关于Android进程或是activity启动流程,近期看到的几个非常不错的学习地址整理如下,以后再回顾就不用再在网上花时间找了:
(1)作者非常牛掰,按照源码流程进行梳理讲解;
(2)更主要是从整体流程上梳理;
(3)(4)是视频,更直观形象的感受到进程或是activity的创建流程。
(1)理解Android进程创建流程:
http://gityuan.com/2016/03/26/app-process-create/
(2)一个APP从启动到主页面展示的流程:
https://lrh1993.gitbooks.io/android_interview_guide/content/android/advance/app-launch.html
(3)Android系统定制和源码开发以及源码编译(附视频):
https://www.jianshu.com/p/46c63dfd5c89
(4)Android开发之Activity那些事儿:
https://segmentfault.com/l/1500000013256867/play
下面来自上述文章中的一些流程上的图片,更方便回忆知识点:
文章(2)中的梳理:
①点击桌面App图标,Launcher进程采用Binder IPC向system_server进程发起startActivity请求;
②system_server进程接收到请求后,向zygote进程发送创建进程的请求;
③Zygote进程fork出新的子进程,即App进程;
④App进程,通过Binder IPC向sytem_server进程发起attachApplication请求;
⑤system_server进程在收到请求后,进行一系列准备工作后,再通过binder IPC向App进程发送scheduleLaunchActivity请求;
⑥App进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程发送LAUNCH_ACTIVITY消息;
⑦主线程在收到Message后,通过发射机制创建目标Activity,并回调Activity.onCreate()等方法。
⑧到此,App便正式启动,开始进入Activity生命周期,执行完onCreate/onStart/onResume方法,UI渲染结束后便可以看到App的主界面。
文章(1)中的梳理:
#进程创建流程
图解:
- App发起进程:当从桌面启动应用,则发起进程便是Launcher所在进程;当从某App内启动远程进程,则发送进程便是该App所在进程。发起进程先通过binder发送消息给system_server进程;
- system_server进程:调用Process.start()方法,通过socket向zygote进程发送创建新进程的请求;
- zygote进程:在执行
ZygoteInit.main()
后便进入runSelectLoop()
循环体内,当有客户端连接时便会执行ZygoteConnection.runOnce()方法,再经过层层调用后fork出新的应用进程; - 新进程:执行handleChildProc方法,最后调用ActivityThread.main()方法。
进程的创建:
copy-on-write原理:写时拷贝是指子进程与父进程的页表都所指向同一个块物理内存,fork过程只拷贝父进程的页表,并标记这些页表是只读的。父子进程共用同一份物理内存,如果父子进程任一方想要修改这块物理内存,那么会触发缺页异常(page fault),Linux收到该中断便会创建新的物理内存,并将两个物理内存标记设置为可写状态,从而父子进程都有各自独立的物理内存。
流程总结:
Process.start()方法是阻塞操作,等待直到进程创建完成并返回相应的新进程pid,才完成该方法。
当App第一次启动时或者启动远程Service,即AndroidManifest.xml文件中定义了process:remote属性时,都需要创建进程。比如当用户点击桌面的某个App图标,桌面本身是一个app(即Launcher App),那么Launcher所在进程便是这次创建新进程的发起进程,该通过binder发送消息给system_server进程,该进程承载着整个java framework的核心服务。system_server进程从Process.start开始,执行创建进程。
上图中,system_server
进程通过socket IPC通道向zygote
进程通信,zygote
在fork出新进程后由于fork调用一次,返回两次,即在zygote进程中调用一次,在zygote进程和子进程中各返回一次,从而能进入子进程来执行代码。该调用流程图的过程:
- system_server进程(
即流程1~3
):通过Process.start()方法发起创建新进程请求,会先收集各种新进程uid、gid、nice-name等相关的参数,然后通过socket通道发送给zygote进程; - zygote进程(
即流程4~12
):接收到system_server进程发送过来的参数后封装成Arguments对象,图中绿色框forkAndSpecialize()方法是进程创建过程中最为核心的一个环节(详见流程6),其具体工作是依次执行下面的3个方法:- preFork():先停止Zygote的4个Daemon子线程(java堆内存整理线程、对线下引用队列线程、析构线程以及监控线程)的运行以及初始化gc堆;
- nativeForkAndSpecialize():调用linux的fork()出新进程,创建Java堆处理的线程池,重置gc性能数据,设置进程的信号处理函数,启动JDWP线程;
- postForkCommon():在启动之前被暂停的4个Daemon子线程。
- 新进程(
即流程13~15
):进入handleChildProc()方法,设置进程名,打开binder驱动,启动新的binder线程;然后设置art虚拟机参数,再反射调用目标类的main()方法,即Activity.main()方法。
再之后的流程,如果是startActivity则将要进入Activity的onCreate/onStart/onResume等生命周期;如果是startService则将要进入Service的onCreate等生命周期。
system_server进程等待zygote返回进程创建完成(ZygoteConnection.handleParentProc), 一旦Zygote.forkAndSpecialize()方法执行完成, 那么分道扬镳, zygote告知system_server进程进程已创建, 而子进程继续执行后续的handleChildProc操作.
Tips: [小节11]RuntimeInit.java的方法nativeZygoteInit()会调用到onZygoteInit(),这个过程中有startThreadPool()创建Binder线程池。也就是说每个进程无论是否包含任何activity等组件,一定至少会包含一个Binder线程。