阅读本文大约需要花费1小时。
文章的内容主要还是从源码进行分析,虽然又臭又长,但是如果想要学习Android系统源码,这是必要走的路,没有捷径。
相对于碎片学习,我更倾向于静下心来花费1个小时认真的学习一段内容。
专注于Android系统级源码分析,Android的平台设计,欢迎关注我,谢谢!
上一节我们讲完了Launcher的启动流程,这一节来看看应用进程的创建过程以及Zygote的fork流程。
系列文章:
1.概述
上一节我们学习了Launcher的启动流程。这一节来介绍下应用进程的创建过程以及Zygote Fork的过程。
点击桌面图标启动应用概述:
在上一节Launcher的启动中我们知道了,手机的桌面其实就是Launcher进程,里面的应用图标都是Launcher通过ListView进行展示。
那么我们点击一个桌面图标,比如微信,这个应用是如何启动的呢,这一节我们从系统级的源码来一步步的进行分析。
在分析之前,我们简单区分一下进程和线程的概念。
在Android中通过Logcat抓取log时,存在PID和TID两个概念。
PID:Process ID,进程ID
TID: Thread ID,线程ID
每个Android都是一个进程,每个进程有一个或多个线程
进程:
是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位。
当我们点击某个应用的图标时,必须创建一个进程,该进程是由Zygote fork出来的,进程具有独立的资源空间,用于承载App上运行的各种Activity/Service等组件。
线程:
是进程的一个执行单元,是进程内科调度实体。比进程更小的独立运行的基本单位。线程也被称为轻量级进程。
每个应用有多个线程,例如UI展示属于UI主线程,一些通信过程属于独立线程,通常JAVA中使用new Thread().start()来创建一个新的线程。
该线程并没有自己独立的地址空间,而是与其所在进程之间资源共享。
进程线程的区别
- 地址空间:同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间。
- 资源拥有:同一进程内的线程共享本进程的资源,但是进程之间的资源是独立的。
- 一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。
- 进程切换时,消耗的资源大,效率高。所以涉及到频繁的切换时,使用线程要好于进程。同样如果要求同时进行并且又要共享某些变量的并发操作,只能用线程不能用进程。
- 执行过程:每个独立的进程有一个程序运行的入口、顺序执行序列和程序入口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
- 线程是处理器调度的基本单位,但是进程不是。
- 两者均可并发执行。
2.核心源码
3.架构
App发起进程:点击一个桌面应用(例如微信),Launcher 加载应用, LauncherActivity收到触发事件,组装Intent,通过binder发送消息给SystemServer进程,调用Activity的startActivity()来启动进程,启动Activity时,受ActivityManagerService-AMS的服务控制,AMS属于SystemServer进程,因此SystemServer进行会通过Process 来向Zygote发送一个Socket。
Zygote有一个无限循环,一直在等待Socket请求,收到SystemServer发来新的Socket请求后,Zygote调用系统的fork函数来孵化一个新的进程,比如这里的微信。
再把启动的入口交给ActivityThread,进入微信的进程中,进行详细的UI展示。
3.1 进程创建图
从点击Launcher中的图标,到启动Activity,再到Zygote Fork操作,最终进入新的进行进行UI绘制。
3.2 Zygote Fork图
Zygote调用系统的fork()函数,孵化出一个新的进程,fork()采用copy-on-write机制,有些类如果不做改变,甚至都不用复制,子进程可以和父进程共享这部分数据,从而省去不少内存的占用。
图片来源Gityuan
4.源码分析
应用的启动共分以下四个步骤完成:
- 点击桌面的图标,Launcher调用系统的startActivity进行启动Activity,此时的动作在Launcher进程中
- ATM\\AMS 进行Activity的处理,组装message,通过socket发送给Socket
- Zygote收到SystemServer发来的消息,进行消息拆分,再调用系统的fork()函数,进行进行孵化操作。
- 进入ActivityThread的main(),完成最终应用进程的的onCreate操作
接下来我们根据这四个步骤来进行详细的源码分析.
4.1 第一阶段,点击桌面图标,触发点击事件
触发Launcher listview的点击事件 onListItemClick()
说明:桌面图标按照5*5或者6*6的方式进行排列,这其实是Launcher进程展示的ListView,每个应用图标填入其中,点击图标进入Launcher的点击事件处理
源码:
4.1.1 [Activity.java]
startActivity()
说明:这里比较简单,调用
startActivityForResult()
源码:
4.1.2 [Activity.java]
startActivityForResult()
说明:不难发现,不论有没有父Activity,最终都交给了 Instrumentation 来开启
源码:
4.1.3 [Instrumentation.java]
execStartActivity()
说明:Binder 调用 ActivityTaskManagerService-ATM 来启动 Activity
源码:
从下面代码可以看到,IActivityTaskManager其实获得的是activity_task对应服务的Binder对象,
即是ActivityTaskManagerService-ATM
4.2 第二阶段:ATM\\AMS 进行Activity的处理
调用栈如下:
4.2.1 [ActivityTaskManagerService.java]
startActivity()
说明: 这里很简单,直接调用startActivityAsUser()
源码:
4.2.2 [ActivityTaskManagerService.java]
startActivityAsUser()
说明:获取 ActivityStarter 对象,最终调用ActivityStarter的execute()
源码:
4.2.3 [ActivityStarter.java] execute()
说明:根据[4.2.2]中调用了setMayWait,因此这里的mRequest.mayWait为true
源码:
4.2.4 [ActivityStarter.java]
startActivityMayWait()
说明:调用startActivity()来启动Activity
源码:
4.2.5 [ActivityStarter.java]
startActivity()
说明:延时布局,然后通过startActivityUnchecked()来处理启动标记 flag ,要启动的
4.2.6 [RootActivityContainer.java]
resumeFocusedStacksTopActivities()
说明:获取栈顶的Activity,恢复它
源码:
4.2.7 [ActivityStackSupervisor.java]
startSpecificActivityLocked()
说明: 发布消息以启动进程,以避免在ATM锁保持的情况下调用AMS时可能出现死锁,最终调用到ATM的startProcess()
源码:
4.2.8 [ActivityManagerService.java]
startProcess()
说明: 一路调用Process start(),最终到ZygoteProcess的
attemptUsapSendArgsAndGetResult(),用来fork一个新的Launcher的进程
源码:
调用栈如下:
4.2.9 [ZygoteProcess.java]
attemptZygoteSendArgsAndGetResult()
说明:通过Socket连接Zygote进程,把之前组装的msg发给Zygote,其中processClass ="android.app.ActivityThread",通过Zygote进程来Fork出一个新的进程,
并执行 "android.app.ActivityThread"的main方法
源码:
4.3 第三阶段 Zygote Fork 应用进程
说明:Zygote的启动过程我们前面有详细讲到过。
SystemServer的AMS服务向启动Home Activity发起一个fork请求,Zygote进程通过Linux的fork函数,孵化出一个新的进程。
由于Zygote进程在启动时会创建Java虚拟机,因此通过fork而创建的Launcher程序进程可以在内部获取一个Java虚拟机的实例拷贝。
fork采用copy-on-write机制,有些类如果不做改变,甚至都不用复制,子进程可以和父进程共享这部分数据,从而省去不少内存的占用。
调用栈如下:
4.3.1 [ZygoteInit.java] main()
说明:Zygote先fork出SystemServer进程,接着进入循环等待,用来接收Socket发来的消息,用来fork出其他应用进程,比如Launcher
源码:
4.3.2 [ZygoteConnection.java]
processOneCommand()
说明:通过 forkAndSpecialize()来fork出Launcher的子进程,并执行handleChildProc,进入子进程的处理
源码:
4.3.3 [Zygote.java] forkAndSpecialize
说明:主要是调用dalvik中ZygoteHooks的preFrok进行预处理,再调用postForkCommon进行完成的进程fork
源码:
4.3.3.1 [ZygoteHooks.java] preFork()
说明:Zygote进程有4个Daemon子线程分别是
HeapTaskDaemon、
ReferenceQueueDaemon、
FinalizerDaemon、
FinalizerWatchdogDaemon
preFork()预处理主要是先停止4个子线程,等待所有的子线程结束,最后完成gc堆的初始化工作
Zygote子线程如下图所示:
源码:
4.3.3.2 [Daemons.java] stop()
说明:此处守护线程Stop方式是先调用目标线程interrrupt()方法,然后再调用目标线程join()方法,等待线程执行完成
停止4个子线程,分别是:Java堆整理线程;引用队列线程;析构线程;析构监控线程
源码:
4.3.3.3 [ZygoteHooks.java]
waitUntilAllThreadsStopped()
说明:等待所有子线程结束
源码:
4.3.4 [ZygoteHooks.java]
nativePreFork()
通过JNI最终调用的是以下方法:
[dalvik_system_ZygoteHooks.cc] ZygoteHooks_nativePreFork()
说明:进行堆的一些预处理
源码:
4.3.4.1 [runtime.cpp] PreZygoteFork()
说明:堆的初始化工作,属于虚拟机的范畴,想理解的可以深挖一下
源码:
4.3.5 [Zygote.java]
nativeForkAndSpecialize()
通过JNI最终调用的是以下方法:
[com_android_internal_os_Zygote.cpp] com_android_internal_os_Zygote_nativeForkAndSpecialize
说明: fork 子进程
源码:
4.3.5.1 [com_android_internal_os_Zygote.cpp]
ForkCommon()
说明:调用系统的fork()进行 应用进程的孵化操作,采用copy-on-write的机制,使得应用进程与Zygote共享部分数据,减少内存的占用
源码:
4.3.5.2 [com_android_internal_os_Zygote.cpp]
SpecializeCommon()
说明:进行进程的一些资源处理,selinux权限处理,并调用Zygote的callPostForkChildHooks()
源码:
4.3.5.3 [Zygote.java]
callPostForkChildHooks()
说明:JAVA堆线程的一些处理
源码:
创建JAVA的线程池,设置信号处理,启动JDWP线程
4.3.6 [ZygoteHooks.java] postForkCommon()
说明:在fork新进程后,启动Zygote的4个Daemon线程,java堆整理,引用队列,以及析构线程。
源码:
启动Zygote的4个新的子线程
4.3.7 [ZygoteConnection.java]
handleChildProc()
说明:进行子进程的操作,最终获得需要执行的ActivityThread的main()
源码:
zygoteInit 进行一些环境的初始化、启动Binder进程等操作
把之前传来的"android.app.ActivityThread" 传递给findStaticMain
通过反射,拿到ActivityThread的main()方法
把反射得来的ActivityThread main()入口返回给ZygoteInit的main,通过caller.run()进行调用
至此,Zygote fork进程的操作全部完成,下一步进入JAVA世界,进行真正的Activity的启动流程。
4.4 第四阶段 进入应用进程,启动Activity的onCreate()
调用栈如下:
4.4.1 [ActivityThread.java] main()
说明: 主线程处理, 创建ActivityThread对象,调用attach进行处理,最终进入Looper循环
源码:
调用ActivityThread的attach进行处理
4.4.2 [ActivityManagerService.java]
attachApplication()
说明:清除一些无用的记录,最终调用ActivityStackSupervisor.java的 realStartActivityLocked(),进行Activity的启动
源码:
4.4.3 [ActivityStackSupervisor.java]
realStartActivityLocked()
说明:真正准备去启动Activity,通过clientTransaction.addCallback把LaunchActivityItem的obtain作为回调参数加进去,再调用
ClientLifecycleManager.scheduleTransaction()得到LaunchActivityItem的execute()方法进行最终的执行
参考上面的第四阶段的调用栈流程:
源码:
4.4.4 [TransactionExecutor.java] execute()
说明:执行之前realStartActivityLocked()中的
clientTransaction.addCallback
调用栈:
源码:
4.4.5 [ActivityThread.java]
handleLaunchActivity()
说明:主要干了两件事,第一件:初始化WindowManagerGlobal;第二件:调用performLaunchActivity方法
源码:
4.4.6 [ActivityThread.java]
performLaunchActivity()
说明:获取ComponentName、Context,反射创建Activity,设置Activity的一些内容,比如主题等;
最终调用callActivityOnCreate()来执行Activity的onCreate()方法
源码:
callActivityOnCreate先执行activity onCreate的预处理,再去调用Activity的onCreate,最终完成Create创建后的内容处理
performCreate()主要调用Activity的onCreate()
至此,看到了我们最熟悉的Activity的onCreate(),应用启动的启动完成,应用程序被真正的调用起来。
5.总结
通过上面一系列的流程,我们理解了应用进程的创建流程,以及Zygote fork这些应用进程的流程。
主要分为4步完成:
- 点击桌面的图标,Launcher调用系统的startActivity进行启动Activity,此时的动作在Launcher进程中
- 通过Binder向SystemServer进行发送消息,让ATM\\AMS 进行Activity的处理,组装message,通过socket发送给Socket,此时动作在SystemServer进程中
- Zygote收到SystemServer发来的消息,进行消息拆分,再调用系统的fork()函数,进行进行孵化操作,此时动作在Zygote进程中
- 进入ActivityThread的main(),完成最终应用进程的的onCreate操作,该步动作处于新创建的应用进程中
閱讀更多 IngresGe 的文章