Android系统启动后,下一步就是启动应用程序。应用程序进程启动是第一步,只有应用程序进程启动了,应用程序才能启动。所以本次问答,会讲解应用程序的进程启动。
问:应用程序的进程是什么?
答:应用程序的进程是Zygote进程的子进程,通过Zygote fork自身创建的。所以应用程序进程会获取Zygote的虚拟机实例,并会创建Binder用于进程间通信,还有消息循环Looper。
问:应用程序进程是怎么启动的?
答:应用程序进程启动主要包含两方面:AMS发送启动请求、Zygote接收请求并创建应用程序进程。
问:AMS是怎么发送启动应用程序进程请求的?
答:这里先给出AMS发送启动应用程序进程请求的时序图,如下图所示。AMS通过start启动应用程序进程,同时设置启动参数用户id(uid)、用户组id(gid)、进程名、主线程名(com.android.ActivityThread),通过connect建立socket的连接,当abi匹配时socket的名称是zygote,不匹配是zygote_secondary。
问:Zygote接收请求并创建应用程序进程的流程?
答:同样先给出Zygote接收请求并创建应用程序进程的时序图,如下图所示。这里的7MethodAndArgsCaller是RuntimeInit抛出的异常,异常被ZygoteInit捕获后,Zygote调用了ActivityThread的main方法。(通过参数Caller的run方法进行的类和方法的对应)
问:Zygote接收请求并创建应用程序进程干了什么?
答:整个过程中,主要的工作是,根据connection连接,获取启动参数,通过参数fork Zygote自身创建应用程序进程实例,根据创建该实例的参数,通过反射的方式,创建ActivityThread的class实例。这样完成了应用程序进程的创建和运行应用程序的主线程ActivityThread。
问:Binder线程池是怎么启动的?
答:首先我们要明白创建线程池是为了通信更高效。入口是在ZygoteInit.zygoteInit()里,通过JNI,适用C语言来创建线程池。通过JNI找到对应的cpp文件,最终通过startThreadPool启动线程池。该线程池有一个bool类型的变量,可以保证该应用程序进程的线程池只创建1次。创建的同时会通过run创建一个线程并加入到线程池。这样线程池就启动了,可以进行进程间通信了。
问:消息循环是怎么创建的?
答:在应用程序进程创建时会通过抛异常的方式清空堆栈信息,并使main方法看起来像入口方法。我们上面说到了,创建应用程序进程时,会通过反射调用ActivityThread的main方法,Looper就是在ActivityThread的main方法通过Loop.prepareMainLooper()创建的。
问:消息循环干了什么?
答:当通过反射创建ActivityThread对象并调用其main方法时,main方法里主要处理消息循环的。这里主要做了,创建一个活动线程(ActivityThread),创建一个Handler(这个Handler是ActivityThread的内部类,继承Handler,以后将会经常用到)。因为消息循环代码是在prepare和loop之间,所以这些是在Looper.prepareMainLoopre和Looper.loop之间完成的。
小结:本讲主要说明应用程序进程创建的相关知识点,主要包括AMS发送创建应用程序进程请求,Zygote接收请求并创建应用程序,创建Binder线程池用于以后进程间通信,创建消息循环Looper,添加至ActivityThread中。