1.前言
我们在了解了四大组件之后,有必要去了解下进程是如何启动的,毕竟,进程是一个很重要的感念。我们知道,我们可以在配置文件中,通过process属性指定进程。在ams中,如果组件需要运行在一个新的进程中,这时候就会去新建进程。让我们看下代码。
|
|
- 其中entryPoint是进程的运行入口
2.Process#start
在start方法中,会调用startViaZygote方法。
|
|
在经过一系列参数设置之后,会调用zygoteSendArgsAndGetResult方法,这里需要两个参数,一个是ZygoteState,通过openZygoteSocketIfNeeded函数返回,另一个就是启动配置。接下来就看下openZygoteSocketIfNeeded干了什么?
3.Process#openZygoteSocketIfNeeded
|
|
这个方法会根据需要是否开启和zygote进程的socket通道,去做操作。在这里能看到两种不同的,这里是因为android5.0开始,支持64位编译,上面分别对应32和64,这里就不说多了。这里通过ZygoteState的connect方法,去链接到在zygote进程中的server端。
4. Process#zygoteSendArgsAndGetResult
|
|
在这个方法中,向socke通道写入进程启动参数,等待socket server相应并返回,读取返回结果。
那么,现在我们就需要这里socket服务端的处理。因为这里没有分析zygote进程的启动,所以讲起来比较麻烦,直接告诉大家,其socket服务端实现在ZygoteInit中,在mian方法中,会调用registerZygoteSocket方法去启动socket server。在然后会调用runSelectLoop方法,去等待socket客户端的连接。
5. ZygoteInit#runSelectLoop
|
|
首先会通过Os.poll等待事件的到来,这里应该是用的poll模型,然后处理,当i=0的时候,为socket请求连接的事件,这时会调用acceptCommandPeer与客户端建立一个连接,然后加入监听数组,等待参数的到来,一旦i!=0,则为参数到来,那么,就调用runOnce去处理参数。完成之后,移除连接、移除监听。
6.ZygoteConnection#runOnce
|
|
- readArgumentList读区启动参数
- 构造Arguments,在这个的构造函数中,会调用parseArgs去解析参数
- 随后进行参数检查和配置
- 调用Zygote.forkAndSpecialize进行fork进程,返回进程id
7.Zygote#forkAndSpecialize
|
|
- VM_HOOKS是ZygoteHooks
在preFork中,会中断HeapTaskDaemon、ReferenceQueueDaemon、FinalizerDaemon、FinalizerWatchdogDaemon,这四个守护线程。并调用nativePreFork在native层做一些fork之前的操作。其对应实现在daivik_system_ZygoteHocks.cc文件中,函数对应表如下
1234static JNINativeMethod gMethods[] = {NATIVE_METHOD(ZygoteHooks, nativePreFork, "()J"),NATIVE_METHOD(ZygoteHooks, nativePostForkChild, "(JILjava/lang/String;)V"),};然后调用nativeForkAndSpecialize去fork进程,对应实现在com_android_internal_os_Zygote.cpp中。
- 调用VM_HOOKS的postForkCommon,去启动先前中断的几个线程。
8. nativePreFork
|
|
这里会调用runtime、runtime中调用heap,最终调用heap的PreZygoteFork方法。去做一些初始化操作,本人太渣,看不太懂。略
9. nativeForkAndSpecialize
在com_android_internal_os_Zygote_nativeForkAndSpecialize方法中,会调用ForkAndSpecializeCommon。
|
|
- 设置子进程的signal信号处理函数 SetSigChldHandler函数
- fork进程,fork函数
- pid为0,进入子进程
- DetachDescriptors 关闭清理文件描述符
- SetGids 设置group
- SetRLimits 设置资源限制
- 进行其他的初始化设置
- CallStaticVoidMethod,调用ZygotecallPostForkChildHooks方法。这里又会调用nativePostForkChild。
- …
- 父进程分支,啥也不做
- 返回pid
当这些都执行完之后,回到ZygoteConnection的runonce方法,进行后续操作
|
|
我们重点看handleChildProc。
10.ZygoteConnection#handleChildProc
在这个方法中,有如下代码。
|
|
大部分情况下,invokeWith为null,所以我们看下面的分支。
11.RuntimeInit.zygoteInit
|
|
- 重定向log输出
- commonInit,进行通用的一些设置如时区。
- zygote初始化
- 应用初始化
12.nativeZygoteInit
该函数的实现在AndroidRuntime.cpp中,
|
|
这里onZygoteInit在app_main.cpp中,这里就不多说了。
13.RuntimeInit.applicationInit
|
|
这里设置一些参数,并且调用invokeStaticMain,从名字上来看,就知道是调用静态main方法,也就是我们指定的进程入口ActivityThread的main方法。
|
|
注意看最后一行代码的注释,因为我们之前经过了复杂的调用,堆栈信息比较多了,这里通过抛异常处理来清理调用栈。最后调用如下代码。
|
|
就这样我们的应用进程就启动起来了。当然,启动应用程序也是这个流程,简单说下吧:
在点击luncher上的图标,会通过startactivity启动我们的程序,但是,这时候没有进程,通过上面这些繁琐的流程启动之后,在启动activity,这样,应用程序也启动起来了。