目录
前言
在Android世界的起源 — Zygote我们讲了Android系统的启动过程,了解了Zygote进程的作用,其中最重要的作用就是孵化应用进程,那我们本节就来详细讲讲Zygote是如何孵化应用进程的
注意:本文采用的是API28(Android 9)来进行源码分析
两种启动进程的方式
在上文中我们说了一个结论:
每个应用进程不仅有自己的数据资源和需要执行的代码,还需要用到Android框架中通用的资源和代码,由于这些资源和代码是大部分应用都需要调用到的,并且比较重量级,所以安卓把它们都放在Zygote进程的空间中,而应用进程又是继承于Zygote进程,所以当应用需要的时候就直接到里面去找就行了
是不是会有人有点好奇,应用进程为什么能拿到Zygote进程中的资源呢?进程中的这种“继承”关系(注意这里说的不是java中的继承,只是一个比喻)是如何设计的呢?接下来我们来看一下进程的启动方式
首先创建进程都是通过fork()函数,fork() 函数是一次执行,两次返回。说的更严谨一点是 两个进程对用一个程序的两次执行。当 pid == 0 时,说明现在处于子进程,当 pid > 0 时,说明处于父进程
fork()进程后,接下来会分为两种类型的子进程启动方式
第一种:
pid_t pid = fork();
if(pid == 0){
//child process
}else{
//parent process
}
通过这种方式创建的子进程,默认继承了父进程的所有资源,这就是应用进程的启动方式
第二种:
pid_t pid = fork();
if(pid == 0){
//child process
execve(path,argv,env);
}else{
//parent process
}
这种方式在子进程中调用了execve(path,argv,env)函数,会去加载另一个可执行程序,那么子进程所继承的资源都会被清除,这就是Zygote进程的启动方式
path:可执行程序的路径
argvs:附带的参数
env:环境变量
应用进程的启动时机
在应用层当中,我们可以通过startActivity()启动我们应用内部的页面,也可以按照约定的协议跳转到其他的应用的Activity,当我们的应用启动了其他应用的Activity时(不仅仅是Activity,启动四大组件都是同样的道理),也就意味着这个Activity所对应的应用进程也启动了。实际上startActivity()内部并没有直接启动进程的逻辑,Android系统也没有给我们的应用层中暴露启动进程相关的接口,那么这个新的进程是如何被启动的呢?
我们来看一下调用startActivity()后经历了哪些过程:(代码这里就省略了,有兴趣的可以自己跟一下代码)
第一部分:当前进程与ASM进程建立Binder通信,发起startActivity请求
-
Activity#startActivity() -
Activity#startActivityForResult() -
Instrumentation#execStartActivity() -
Instrumentation#execStartActivitiesAsUser() -
ActivityManager.getService().startActivities(),getService()会返回IActivityManager,IActivityManager实际上就是跨进程通信AIDL中的Client持有的Server句柄,也就是说,Client可以通过IActivityManager接口向Server发送请求,而这里的Server就是ActivityServiceManager,因为它继承了IActivityManager.Stub
第二部分:ASM处理startActivity请求,通过Socket向Zygote进程请求创建应用进程
ActivityServiceManager#startActivities()ActivityStarter#execute()ActivityStarter#startActivityMayWait()ActivityStarter#startActivity()ActivityStarter#startActivityUnchecked()ActivityStackSupervisor#resumeFocusedStackTopActivityLocked()ActivityStack#resumeTopActivityUncheckedLocked()ActivityStack#resumeTopActivityInnerLocked()ActivityStackSupervisor#startSpecificActivityLocked()
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
getLaunchTimeTracker().setLaunchTime(r);
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.longVersionCode,
mService.mProcessStats);
}
//启动组件,return
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
}
//进程没有启动,去启动进程
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}
-
ActivityManagerService#startProcessLocked(),四种启动组件的方式,startActivity、startService、sendBroadcast、ContentResolver.query,都会执行到这个方法,这就是AMS请求创建进程的入口 ActivityManagerService#startProcessProcess.start()ZygoteProcess#start()ZygoteProcess#startViaZygote()-
ZygoteProcess.openZygoteSocketIfNeeded(),打开本地Socket,AMS作为Client -
ZygoteProcess.zygoteSendArgsAndGetResult(),通过Socket向Zygote进程发送一个参数列表,然后就进入阻塞状态,直到远程Socket服务端返回新创建的进程pid
第三部分:Zygote处理Socket请求,创建子进程并反射调用ActivityThread
在Android世界的起源 — Zygote中我们分析了ZygoteInit.main()函数,这里面会创建一个ZygoteServer,并调用ZygoteServer#runSelectLoop来死循环监听Socket的Client(AMS)发来的消息
ZygoteServer#runSelectLoopZygoteConnection#processOneCommand()Zygote.forkAndSpecialize()
Runnable processOneCommand(ZygoteServer zygoteServer) {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
//....
//fork进程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
parsedArgs.instructionSet, parsedArgs.appDataDir);
try {
if (pid == 0) {
//子进程执行
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
//进入子进程流程
//parsedArgs.startClass就是ActivityThread类,是前面AMS通过Socket发送过来的
return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.startChildZygote);
} else {
//父进程执行
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, descriptors, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
ZygoteInite.zygoteInit()RuntimeInit.applicationInit()-
RuntimeInit.findStaticMain(),反射调用ActivityThread
第四部分:进入ActivityThread
ActivityThread,本身不是一个线程,但它管理着应用进程中主线程的执行,在ActivityManager请求时调度和执行Activity,Service,Broadcast和其它操作
ActivityThread.main()
public static void main(String[] args) {
......
//创建主线程的Looper
Looper.prepareMainLooper();
//关联AMS
ActivityThread thread = new ActivityThread();
thread.attach(false);
//初始化主线程Handler
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// 进行主线程消息循环
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
至此,进程创建完毕,并且也有了主线程,剩下的便是启动Activity和关联context等初始化操作了
总结
本文主要为了重点讲解应用进程的创建过程,所以过程中一些细节代码就没有罗列出来,如果对更多的细节感兴趣,这里推荐两篇我觉得写得还不错的文章
https://blog.csdn.net/qq_30993595/article/details/82747738
https://blog.csdn.net/luoshengyang/article/details/6689748











网友评论