Framework学习(六)应用程序进程启动过程(1),腾讯面试经验汇总

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
img

正文

//1

ProcessRecord app = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid, true);

r.task.stack.setLaunchTime®;

if (app != null && app.thread != null) {

try {

if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0 || !“android”.equals(r.info.packageName)) {

app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode, mService.mProcessStats);

}

realStartActivityLocked(r, app, andResume, checkConfig); //2

return;

} catch (RemoteException e) {

Slog.w(TAG, "Exception when starting activity " + r.intent.getComponent().flattenToShortString(), e);

}

}

//3

mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, “activity”, r.intent.getComponent(), false, false, true);

}

final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) {

if (uid == Process.SYSTEM_UID) {

// The system gets to run in any process. If there are multiple

// processes with the same uid, just pick the first (this

// should never happen).

SparseArray procs = mProcessNames.getMap().get(processName);

if (procs == null) return null;

}

}

AMS启动应用程序时,会检查这个应用程序需要的应用程序进程是否存在。

注释1处获取当前Activity所在的进程的ProcessRecord,如果进程已经启动了,会执行注释2处的代码。否则执行注释3的代码,通过调用startProcessLocked函数来向Zygote进程发送请求。

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

ActivityManagerService#startProcessLocked()

private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {

try {

try {

final int userId = UserHandle.getUserId(app.uid);

AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);

} catch (RemoteException e) {

throw e.rethrowAsRuntimeException();

}

int uid = app.uid; //1

int[] gids = null;

int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;

if (!app.isolated) {

//2

if (ArrayUtils.isEmpty(permGids)) {

gids = new int[2];

} else {

gids = new int[permGids.length + 2];

System.arraycopy(permGids, 0, gids, 2, permGids.length);

}

gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));

gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid));

}

if (entryPoint == null) entryPoint = “android.app.ActivityThread”; //3

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " + app.processName);

checkTime(startTime, “startProcess: asking zygote to start proc”);

//4

Process.ProcessStartResult startResult = Process.start(entryPoint, app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet, app.info.dataDir, entryPointArgs);

} catch (RuntimeException e) {

}

}

}

注释1处的代码创建应用程序进程的用户ID。

注释2处对用户组ID:gids进行创建和赋值。

注释3处如果entryPoint 为null则赋为”android.app.ActivityThread”。

注释4处调用Process的start函数,将此前得到的应用程序进程用户ID、用户组ID和entryPoint 传进去。

frameworks/base/core/java/android/os/Process.java

Process#start()

public static final ProcessStartResult start(final String processClass,

final String niceName,

int uid, int gid, int[] gids,

int debugFlags, int mountExternal,

int targetSdkVersion,

String seInfo,

String abi,

String instructionSet,

String appDataDir,

String[] zygoteArgs) {

try {

//1

return startViaZygote(processClass, niceName, uid, gid, gids, debugFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, zygoteArgs);

} catch (ZygoteStartFailedEx ex) {

Log.e(LOG_TAG, “Starting VM process through Zygote failed”);

throw new RuntimeException(“Starting VM process through Zygote failed”, ex);

}

}

Process#startViaZygote()

private static ProcessStartResult startViaZygote(final String processClass,

final String niceName,

final int uid, final int gid,

final int[] gids,

int debugFlags, int mountExternal,

int targetSdkVersion,

String seInfo,

String abi,

String instructionSet,

String appDataDir,

String[] extraArgs)

throws ZygoteStartFailedEx {

synchronized(Process.class) {

//1

ArrayList argsForZygote = new ArrayList();

argsForZygote.add(“–runtime-args”);

argsForZygote.add(“–setuid=” + uid);

argsForZygote.add(“–setgid=” + gid);

if (gids != null && gids.length > 0) {

StringBuilder sb = new StringBuilder();

sb.append(“–setgroups=”);

int sz = gids.length;

for (int i = 0; i < sz; i++) {

if (i != 0) {

sb.append(‘,’);

}

sb.append(gids[i]);

}

argsForZygote.add(sb.toString());

}

argsForZygote.add(processClass);

if (extraArgs != null) {

for (String arg : extraArgs) {

argsForZygote.add(arg);

}

}

return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);

}

}

注释1处创建了字符串列表argsForZygote ,并将启动应用进程的启动参数保存在argsForZygote中,例如uid、gid等,这里需要注意processClass = android.app.ActivityThread,后文会用到。

注释2会调用zygoteSendArgsAndGetResult函数,需要注意的是,zygoteSendArgsAndGetResult函数中第一个参数中调用了openZygoteSocketIfNeeded函数,而第二个参数是保存应用进程的启动参数的argsForZygote。

Process#zygoteSendArgsAndGetResult()

private static ProcessStartResult zygoteSendArgsAndGetResult(ZygoteState zygoteState, ArrayList args) throws ZygoteStartFailedEx {

try {

// Throw early if any of the arguments are malformed. This means we can

// avoid writing a partial response to the zygote.

int sz = args.size();

for (int i = 0; i < sz; i++) {

if (args.get(i).indexOf(‘\n’) >= 0) {

throw new ZygoteStartFailedEx(“embedded newlines not allowed”);

}

}

final BufferedWriter writer = zygoteState.writer;

final DataInputStream inputStream = zygoteState.inputStream;

writer.write(Integer.toString(args.size()));

writer.newLine();

for (int i = 0; i < sz; i++) {

String arg = args.get(i);

writer.write(arg);

writer.newLine();

}

writer.flush();

// Should there be a timeout on this?

ProcessStartResult result = new ProcessStartResult();

result.pid = inputStream.readInt();

result.usingWrapper = inputStream.readBoolean();

if (result.pid < 0) {

throw new ZygoteStartFailedEx(“fork() failed”);

}

return result;

} catch (IOException ex) {

zygoteState.close();

throw new ZygoteStartFailedEx(ex);

}

}

zygoteSendArgsAndGetResult函数主要做的就是将传入的应用进程的启动参数argsForZygote写入到ZygoteState中,结合上文我们知道ZygoteState其实是由openZygoteSocketIfNeeded函数返回的,那么我们接着来看openZygoteSocketIfNeeded函数。

Process#openZygoteSocketIfNeeded()

private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {

if (primaryZygoteState == null || primaryZygoteState.isClosed()) {

try {

primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET); //1

} catch (IOException ioe) {

throw new ZygoteStartFailedEx(“Error connecting to primary zygote”, ioe);

}

}

if (primaryZygoteState.matches(abi)) {

return primaryZygoteState;

}

// The primary zygote didn’t match. Try the secondary.

if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {

try {

secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET); //2

} catch (IOException ioe) {

throw new ZygoteStartFailedEx(“Error connecting to secondary zygote”, ioe);

}

}

if (secondaryZygoteState.matches(abi)) {

return secondaryZygoteState;

}

throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);

}

在之前讲Zygote进程启动过程时我们得知,在Zygote的main函数中会创建name为“zygote”的Server端Socket。

注释1处会调用ZygoteState的connect函数与名称为ZYGOTE_SOCKET的Socket建立连接,这里ZYGOTE_SOCKET的值为“zygote”。

注释2处如果连接name为“zygote”的Socket返回的primaryZygoteState与当前的abi不匹配,则会连接name为“zygote_secondary”的Socket。这两个Socket区别就是:name为”zygote”的Socket是运行在64位Zygote进程中的,而name为“zygote_secondary”的Socket则运行在32位Zygote进程中。既然应用程序进程是通过Zygote进程fock产生的,当要连接Zygote中的Socket时,也需要保证位数的一致。

接收请求并创建应用程序进程


Socket进行连接成功并匹配abi后会返回ZygoteState类型对象,我们在分析zygoteSendArgsAndGetResult函数中讲过,会将应用进程的启动参数argsForZygote写入到ZygoteState中,这样Zygote进程就会收到一个创建新的应用程序进程的请求,我们回到ZygoteInit的main函数。

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

ZygoteInit#main()

public static void main(String argv[]) {

try {

String socketName = “zygote”;

/*注册Zygote用的Socket/

registerZygoteSocket(socketName); //1

//预加载类和资源

preload(); //2

//启动SystemServer进程

if (startSystemServer) {

startSystemServer(abiList, socketName); //3

}

//监听socket,启动新的应用进程

runSelectLoop(abiList); //4

closeServerSocket();

} catch (MethodAndArgsCaller caller) {

//通过反射调用SystemServer#main()

caller.run();

} catch (RuntimeException ex) {

Log.e(TAG, “Zygote died with exception”, ex);

closeServerSocket();

throw ex;

}

}

注释1处通过registerZygoteSocket函数来创建一个Server端的Socket,这个name为”zygote”的Socket用来等待AMS来请求Zygote来创建新的应用程序进程。

注释2处用来预加载类和资源。

注释3处用来启动SystemServer进程,这样系统的关键服务也会由SystemServer进程启动起来。

注释4处调用runSelectLoop函数来等待AMS的请求。

ZygoteInit#runSelectLoop()

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {

ArrayList fds = new ArrayList();

ArrayList peers = new ArrayList();

fds.add(sServerSocket.getFileDescriptor()); //1

peers.add(null);

while (true) {

StructPollfd[] pollFds = new StructPollfd[fds.size()];

for (int i = 0; i < pollFds.length; ++i) { //2

pollFds[i] = new StructPollfd();

pollFds[i].fd = fds.get(i);

pollFds[i].events = (short) POLLIN;

}

try {

Os.poll(pollFds, -1);

} catch (ErrnoException ex) {

throw new RuntimeException(“poll failed”, ex);

}

for (int i = pollFds.length - 1; i >= 0; --i) { //3

if ((pollFds[i].revents & POLLIN) == 0) {

continue;

}

if (i == 0) {

ZygoteConnection newPeer = acceptCommandPeer(abiList); //4

peers.add(newPeer);

fds.add(newPeer.getFileDesciptor());

} else {

boolean done = peers.get(i).runOnce(); //5

if (done) {

peers.remove(i);

fds.remove(i);

}

}

}

}

}

private static ZygoteConnection acceptCommandPeer(String abiList) {

try {

return new ZygoteConnection(sServerSocket.accept(), abiList);

} catch (IOException ex) {

}

}

注释1处中的sServerSocket就是我们在registerZygoteSocket函数中创建的服务端Socket,调用sServerSocket.getFileDescriptor()用来获得该Socket的fd字段的值并添加到fd列表fds中。接下来无限循环用来等待AMS请求Zygote进程创建新的应用程序进程。

注释2处通过遍历将fds存储的信息转移到pollFds数组中。

注释3处对pollFds进行遍历。

注释4如果i==0则说明服务端Socket与客户端连接上,也就是当前Zygote进程与AMS建立了连接,则通过acceptCommandPeer函数得到ZygoteConnection类并添加到Socket连接列表peers中,接着将该ZygoteConnection的fd添加到fd列表fds中,以便可以接收到AMS发送过来的请求。

注释5如果i的值大于0,则说明AMS向Zygote进程发送了一个创建应用进程的请求,则调用ZygoteConnection的runOnce函数来创建一个新的应用程序进程。并在成功创建后将这个连接从Socket连接列表peers和fd列表fds中清除。

frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

ZygoteConnection#runOnce()

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {

String args[];

Arguments parsedArgs = null;

FileDescriptor[] descriptors;

try {

args = readArgumentList(); //1

descriptors = mSocket.getAncillaryFileDescriptors();

} catch (IOException ex) {

Log.w(TAG, "IOException on command socket " + ex.getMessage());

closeSocket();

return true;

}

try {

parsedArgs = new Arguments(args);//2

//3

pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,

parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,

parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,

parsedArgs.appDataDir);

} catch (ErrnoException ex) {

}

try {

//4

if (pid == 0) {

// in child

IoUtils.closeQuietly(serverPipeFd);

serverPipeFd = null;

handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

return true;

} else {

// in parent…pid of < 0 means failure

IoUtils.closeQuietly(childPipeFd);

childPipeFd = null;

return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);

}

} finally {

IoUtils.closeQuietly(childPipeFd);

IoUtils.closeQuietly(serverPipeFd);

}

}

注释1处调用readArgumentList函数来获取应用程序进程的启动参数。注释2处将readArgumentList函数返回的字符串封装到Arguments对象parsedArgs中。

注释3处调用Zygote的forkAndSpecialize函数来创建应用程序进程,参数为parsedArgs中存储的应用进程启动参数,返回值为pid。

注释4处forkAndSpecialize函数主要是通过fork当前进程来创建一个子进程的,如果pid等于0,则说明是在新创建的子进程中执行的,就会调用handleChildProc函数来启动这个子进程也就是应用程序进程。

ZygoteConnection#handleChildProc()

private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)

throws ZygoteInit.MethodAndArgsCaller {

//1

if (parsedArgs.invokeWith != null) {

WrapperInit.execApplication(parsedArgs.invokeWith,

parsedArgs.niceName, parsedArgs.targetSdkVersion,

VMRuntime.getCurrentInstructionSet(),

pipeFd, parsedArgs.remainingArgs);

} else {

RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,

parsedArgs.remainingArgs, null /* classLoader */);

}

}

}

注释1处由于parsedArgs.invokeWith属性默认为null,最后调用RuntimeInit.zygoteInit函数。

frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

RuntimeInit#zygoteInit()

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)

throws ZygoteInit.MethodAndArgsCaller {

if (DEBUG) Slog.d(TAG, “RuntimeInit: Starting application from zygote”);

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “RuntimeInit”);

redirectLogStreams();

commonInit();

nativeZygoteInit(); //1

applicationInit(targetSdkVersion, argv, classLoader); //2

}

注释1处会在新创建的应用程序进程中创建Binder线程池。

注释2处调用了applicationInit函数。

RuntimeInit#applicationInit()

最后附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总)

面试成功其实是必然的,因为我做足了充分的准备工作,包括刷题啊,看一些Android核心的知识点,看一些面试的博客吸取大家面试的一些经验,下面这份PDF是我翻阅了差不多1个月左右一些Android大博主的博客从他们那里取其精华去其糟泊所整理出来的一些Android的核心知识点, 全部都是精华中的精华,我能面试到现在资深开发人员跟我整理的这本Android核心知识点有密不可分的关系,在这里本着共赢的心态分享给各位朋友。

这份PDF囊括了JVM,Java集合,Java多线程并发,Java基础,生命周期,微服务, 进程,Parcelable 接口,IPC,屏幕适配,线程异步,ART,架构,Jetpack,NDK开发,计算机网络基础,类加载器,Android 开源库源码分析,设计模式汇总,Gradle 知识点汇总…

由于篇幅有限,就不做过多的介绍,大家请自行脑补

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

cationInit()**

最后附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总)

[外链图片转存中…(img-P5PFin80-1713473364754)]

面试成功其实是必然的,因为我做足了充分的准备工作,包括刷题啊,看一些Android核心的知识点,看一些面试的博客吸取大家面试的一些经验,下面这份PDF是我翻阅了差不多1个月左右一些Android大博主的博客从他们那里取其精华去其糟泊所整理出来的一些Android的核心知识点, 全部都是精华中的精华,我能面试到现在资深开发人员跟我整理的这本Android核心知识点有密不可分的关系,在这里本着共赢的心态分享给各位朋友。
[外链图片转存中…(img-pzV6Mcff-1713473364755)]

这份PDF囊括了JVM,Java集合,Java多线程并发,Java基础,生命周期,微服务, 进程,Parcelable 接口,IPC,屏幕适配,线程异步,ART,架构,Jetpack,NDK开发,计算机网络基础,类加载器,Android 开源库源码分析,设计模式汇总,Gradle 知识点汇总…

由于篇幅有限,就不做过多的介绍,大家请自行脑补

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-eCP8k4Eh-1713473364755)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 26
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值