前言
继续上篇的app启动,本篇将从zygote接受到消息跟到activity启动。
下一篇将着重分析应用进程加载代码与资源的过程,并分析实现应用壳的加载方案。
ActivityStarter是Android 7.0新加入的类,它是加载Activity的控制类,会收集所有的逻辑来决定如何将Intent和Flags转换为Activity,并将Activity和Task以及Stack相关联。
参考文:
http://duanqz.github.io/2016-10-23-Activity-LaunchProcess-Part2#%E6%A6%82%E8%A7%88
gityuan
时序图
分析
1-zygoteServer.runSelectLoop
这里进入zygote进程
zygoteServer.runSelectLoop
位于frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
|
|
此时Zygote作为服务端不断监听来自AMS的请求。注释详尽……有点javaNIO服务器的常见用法的感觉…..不过runOnce执行一次就把连接丢掉了。
没有连接请求时会进入休眠状态,当有创建新进程的连接请求时,唤醒Zygote进程,创建Socket通道ZygoteConnection,然后执行ZygoteConnection的runOnce()方法。
4-ZygoteConnection.runOnce
frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java
forkAndSpecialize底层调用fork创建进程。
为子:zygoteServer关闭,调用handleChildProc
父:handleParentProc通过socket将pid返回
安全措施主要靠uid判断的
forkAndSpecialize内主要有:初始化gc堆的工作, 将线程转换为long型并保存到token, fork(),设置group、limit、uid。设置信号处理函数
Arguments参数:
|
|
5-handleChildProc
|
|
关闭连接,之后根据parsedArgs.invokeWith的判断决定用什么执行。
有一篇参考:https://blog.csdn.net/Roland_Sun/article/details/45870677
区别先理解为快速启动和通过系统命令app_process启动,需要时再来分析
6-ZygoteInit.zygoteInit
ZygoteInit.zygoteInit
frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
|
|
commonInit:设置默认的未捕捉异常处理方法、设置时区、重置log配置、设置默认的HTTP User-agent格式,用于 HttpURLConnection、设置socket的tag,用于网络流量统计。
nativeZygoteInit:打开/dev/binder驱动设备、启动Binder线程进入service循环,因此每个进程都有Binder通信机制。
7-RuntimeInit.applicationInit
frameworks\base\core\java\com\android\internal\os\RuntimeInit.java
最终抛出Zygote.MethodAndArgsCaller(m, argv)
frameworks\base\core\java\com\android\internal\os\Zygote.java
MethodAndArgsCaller继承Exception类并实现Runnable接口,这里是个有意思的地方,最终这个MethodAndArgsCaller异常会被ZygoteInit的main函数捕获。
java中的函数抛出异常没有被当前函数捕获,当前函数的执行将异常退出,退出该栈。并将这个异常向上传递直到被捕获。
捕获点:
frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
可见在ZygoteInit的main捕获并执行run
这样做的原因是为了保证一个干净的虚拟机栈。该栈最后只剩执行到尾部的ZygoteInit.main之后即可执行ActivityThread.main。
透过这点思考出:java的错误机制只不过使另一种函数返回方式,原理为栈的快速回退。快速回逆的时候可以携带对象参数,并且可以对该参数拦截控制栈回退的位置!
10-ActivityThread.main
捕获执行的run中执行了android.app.ActivityThread.main
frameworks\base\core\java\android\app\ActivityThread.java
|
|
这就是主线程,也就是UI线程。关于Looper需要回顾下android多线程编程:
Looper:每个线程的messagequeue管家,调用loop之后进入循环,发现messagequeue中有消息就取出,传递到Handler中执行。
MessageQueue:存放handler的消息
Message:线程间的消息
Handler:处理、发送消息。
frameworks\base\core\java\android\os\Looper.java
一般线程里looper初始化用prepare里面的sThreadLocal是static final的,说明其线程唯一。底层保证其创建于线程私有空间
在ActivityThread里的prepareMainLooper中还赋值给了sMainLooper,为该类所有,是进程唯一。主线程looper可以被其它线程直接获取
同时创建lopper时会创建与lopper唯一绑定的queue,主线程创建时传入false不允许退出,该对象是属于looper对象的,属于进程空间,可被线程共享,因此用来接收消息。
frameworks\base\core\java\android\os\Handler.java
普通的Handler生成方式:构造Handler时绑定该线程的looper,因此所有线程用该handler发送的消息都到了handler创建的线程的处理looper中。
ActivityThread的Handler生成方式:直接获取一个该对象唯一的H继承Handler,也就是为lopper绑定了一个已经实现的Handler,该对象与activityThread类绑定,static可被全局找到
消息传递的核心是队列,利用了线程共享数据作为消息接发,实现线程通信。
loop
frameworks\base\core\java\android\os\Looper.java
looper所在线程为处理线程,此处轮询queue获取msg调用发送它的handler执行dispatchMessage最后执行handleMessage。
因为handler创建时绑定线程因此发送时只发送给绑定的线程因此受到的线程执行他的处理方法即可。
之后等待AMS的消息………
12-ActivityThread.attach
frameworks\base\core\java\android\app\ActivityThread.java
mAppThread是一个ApplicationThread类型的Binder对象,它的作用是用来进行进程间通信的。其继承于IApplicationThread.Stub
IActivityManager与IApplicationThread用于应用与服务互相交互,一个位于服务一个位于应用。
http://duanqz.github.io/2016-01-29-Activity-IPC
注意ApplicationThread运行于Binder线程。
13-AMS.attachApplication
AMS.attachApplication
frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
|
|
通过Binder.getCallingPid()可以获取Binder接口的调用者所在进程的PID,
用进程的ApplicationThread对象赋值给ProcessRecord.thread变量,
AMS获取启动要启动进程的信息,AMS将要启动的apk信息发给新进程。通过pid确认要发的包,通过IApplicationThread确定进程目标。
将信息传递给应用程序以后,就可以进行调度了。这里通过两个标识来记录调度的情况:badApp标识是否调度失败,默认为false,在依次调度Activity、Service和Broadcast的过程中,根据实际的情况,可能将其调整为true,表示调度失败了。一旦调度失败,则需要杀掉应用进程;didSomething表示确有调度发生。
17-bindApplication
ApplicationThread会在Binder线程中响应这个跨进程调用,进行一些简单的数据封装后,便向主线程抛出一个BIND_APPLICATION消息
又回到新进程的ActivityThread收到Binder消息BIND_APPLICATION调用:
frameworks\base\core\java\android\app\ActivityThread.java
回调onCreat的部分
frameworks\base\core\java\android\app\Instrumentation.java
进程得到AMS传来的运行信息,获取相关资源,得到application,此时成为真正的app进程。
16-mStackSupervisor.attachApplicationLocked
接下来看下他的activity启动
mStackSupervisor.attachApplicationLocked(app)
frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
遍历寻找所有ActivityStack和TaskRecord,对栈顶的ActivityRecord进行操作。这里其实就是需要启动应用进程中还未启动的Activity。
realStartActivityLocked中:
- 将ProcessRecord和ActivityRecord关联。ActivityRecord对象的app属性,就是ProcessRecord类型
- 跨进程调用IApplicationThread.scheduleLaunchActivity(),调度启动Activity。很多参数都会通过这个函数传递到应用进程;其中包括含ActivityRecord的Token
- 调用AS.minimalResumeActivityLocked()来显示Activity。
20-handleLaunchActivity
scheduleLaunchActivity发送LAUNCH_ACTIVITY到ActivityThread.H
frameworks\base\core\java\android\app\ActivityThread.java
- 调用ActivityThread.performLaunchActivity()函数,初始化一个Activity,真正干活的是它
- 调用ActivityThread.handleResumeActivity()来处理Activity进入显示状态时需要完成的操作
在performLaunchActivity中:获取activity参数(注册类名的原因、部分信息也都可以通过PackageManager再向系统进程索取),反射创建activity对象,创建activity的context,回调oncreate、onstart等函数。
在handleResumeActivity中:调用Activity.onResume(),通知系统进程,Activity已经处于Resumed状态
后记
由zygote fork出子进程后,构建activitythrea主线程和applicationThread,前者作为主线程用线程通信looper接受消息处理渲染等操作,后者作为binder线程接受AMS的消息管理应用。