⼀个APP从启动到主页⾯显⽰经历了哪些过程?(App启动流程,从点击桌⾯开
始)
本⽂以图⽂并茂的形式简单介绍⼀个APP从启动到主页⾯显⽰经历了哪些流程,以及实现的原理。不介绍具体源码,仅仅构建⼀个⼤体框架。
⼀、流程概述
启动流程:
①点击桌⾯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,并回调Create()等⽅法。
⑧到此,App便正式启动,开始进⼊Activity⽣命周期,执⾏完onCreate/onStart/onResume⽅法,UI渲染结束后便可以看到App的主界⾯。
上⾯的⼀些列步骤简单介绍了⼀个APP启动到主页⾯显⽰的过程,可能这些流程中的⼀些术语看的有些懵,什么是Launcher,什么是zygote,什么是applicationThread…..
下⾯我们⼀⼀介绍。
⼆、理论基础
<
zygote意为“受精卵“。Android是基于Linux系统的,⽽在Linux中,所有的进程都是由init进程直接或者是间接fork出来的,zygote进程也不例外。
在Android系统⾥⾯,zygote是⼀个进程的名字。Android是基于Linux System的,当你的⼿机开机的时候,Linux的内核加载完成之后就会启动⼀个叫“init“的进程。在Linux System⾥⾯,所有的进程都是由init进程fork出来的,我们的zygote进程也不例外。
我们都知道,每⼀个App其实都是
● ⼀个单独的dalvik虚拟机
● ⼀个单独的进程
所以当系统⾥⾯的第⼀个zygote进程运⾏之后,在这之后再开启App,就相当于开启⼀个新的进程。⽽为了实现资源共⽤和更快的启动速度,Android系统开启新进程的⽅式,是通过fork第⼀个zygote进程实现的。所以说,除了第⼀个zygote进程,其他应⽤所在的进程都是zygote的⼦进程,这下你明⽩为什么这个进程叫“受精卵”了吧?因为就像是⼀个受精卵⼀样,它能快速的分裂,并且产⽣遗传物质⼀样的细胞!
2.system_server
SystemServer也是⼀个进程,⽽且是由zygote进程fork出来的。
知道了SystemServer的本质,我们对它就不算太陌⽣了,这个进程是Android Framework⾥⾯两⼤⾮常重要的进程之⼀——另外⼀个进程就是上⾯的zygote进程。
为什么说SystemServer⾮常重要呢?因为系统⾥⾯重要的服务都是在这个进程⾥⾯开启的,⽐如
ActivityManagerService、PackageManagerService、WindowManagerService等等。
3.ActivityManagerService
ActivityManagerService,简称AMS,服务端对象,负责系统中所有Activity的⽣命周期。
ActivityManagerService进⾏初始化的时机很明确,就是在SystemServer进程开启的时候,就会初始化ActivityManagerService。
下⾯介绍下Android系统⾥⾯的服务器和客户端的概念。
其实服务器客户端的概念不仅仅存在于Web开发中,在Android的框架设计中,使⽤的也是这⼀种模式。服务器端指的就是所有App共⽤的系统服务,⽐如我们这⾥提到的ActivityManagerService,和前⾯提到的PackageManagerService、WindowManagerService等等,这些基础的系统服务是被所有的App公⽤的,当某个App想实现某个操作的时候,要告诉这些系统服务,⽐如你想打开⼀个App,那么我们知道了包名和MainActivity类名之后就可以打开
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
ComponentName cn = new ComponentName(packageName, className);
intent.setComponent(cn);
startActivity(intent);
但是,我们的App通过调⽤startActivity()并不能直接打开另外⼀个App,这个⽅法会通过⼀系列的调⽤,最后还是告诉AMS说:“我要打开这个App,我知道他的住址和名字,你帮我打开吧!”所以是AMS来通知zygote进程来fork⼀个新进程,来开启我们的⽬标App的。这就像是浏览器想要打开⼀个超链接⼀样,浏览器把⽹页地址发送给服务器,然后还是服务器把需要的资源⽂件发送给客户端的。
知道了Android Framework的客户端服务器架构之后,我们还需要了解⼀件事情,那就是我们的App和AMS(SystemServer进程)还有zygote进程分属于三个独⽴的进程,他们之间如何通信呢?
App与AMS通过Binder进⾏IPC通信,AMS(SystemServer进程)与zygote通过Socket进⾏IPC通信。后⾯具体介绍。
那么AMS有什么⽤呢?在前⾯我们知道了,如果想打开⼀个App的话,需要AMS去通知zygote进程,除此之外,其实所有的Activity的开启、暂停、关闭都需要AMS来控制,所以我们说,AMS负责系统中所有Activity的⽣命周期。
在Android系统中,任何⼀个Activity的启动都是由AMS和应⽤程序进程(主要是ActivityThread)相互配合来完成的。AMS服务统⼀调度系统中所有进程的Activity启动,⽽每个Activity的启动过程则由其所属的进程具体来完成。
4.Launcher
当我们点击⼿机桌⾯上的图标的时候,App就由Launcher开始启动了。但是,你有没有思考过Launcher到底是⼀个什么东西?Launcher本质上也是⼀个应⽤程序,和我们的App⼀样,也是继承⾃Activity
packages/apps/Launcher2/src/com/android/launcher2/Launcher.java
Launcher实现了点击、长按等回调接⼝,来接收⽤户的输⼊。既然是普通的App,那么我们的开发经验在这⾥就仍然适⽤,⽐如,我们点击图标的时候,是怎么开启的应⽤呢?捕捉图标点击事件,然后startActivity()发送对应的Intent请求呗!是的,Launcher也是这么做的,就是这么easy!
5.Instrumentation和ActivityThread
每个Activity都持有Instrumentation对象的⼀个引⽤,但是整个进程只会存在⼀个Instrumentation对象。
Instrumentation这个类⾥⾯的⽅法⼤多数和Application和Activity有关,这个类就是完成对Application和Activity初始化和⽣命周期的⼯具类。Instrumentation这个类很重要,对Activity⽣命周期⽅法的调⽤根本就离不开他,他可以说是⼀个⼤管家。
ActivityThread,依赖于UI线程。App和AMS是通过Binder传递信息的,那么ActivityThread就是专门与AMS的外交⼯作的。
6.ApplicationThread
前⾯我们已经知道了App的启动以及Activity的显⽰都需要AMS的控制,那么我们便需要和服务端的沟通,⽽这个沟通是双向的。
客户端–>服务端
⽽且由于继承了同样的公共接⼝类,ActivityManagerProxy提供了与ActivityManagerService⼀样的函数原型,使⽤户感觉不出Server 是运⾏在本地还是远端,从⽽可以更加⽅便的调⽤这些重要的系统服务。
服务端–>客户端
还是通过Binder通信,不过是换了另外⼀对,换成了ApplicationThread和ApplicationThreadProxy。
他们也都实现了相同的接⼝IApplicationThread
public final class Launcher extends Activity
implements View .OnClickListener , OnLongClickListener , LauncherModel .Callbacks ,
View .OnTouchListener {
}
private class ApplicationThread extends ApplicationThreadNative {}
public abstract class ApplicationThreadNative extends Binder implements IApplicationThread{}
class ApplicationThreadProxy implements IApplicationThread {}
关于Binder通信,可以参考这两篇⽂章理解⼀下:
好了,前⾯罗⾥吧嗦的⼀⼤堆,介绍了⼀堆名词,可能不太清楚,没关系,下⾯结合流程图介绍。
三、启动流程
1.创建进程
①先从Launcher的startActivity()⽅法,通过Binder通信,调⽤ActivityManagerService的startActivity⽅法。
②⼀系列折腾,最后调⽤startProcessLocked()⽅法来创建新的进程。
③该⽅法会通过前⾯讲到的socket通道传递参数给Zygote进程。Zygote孵化⾃⾝。调⽤ZygoteInit.main()⽅法来实例化ActivityThread 对象并最终返回新进程的pid。
④调⽤ActivityThread.main()⽅法,ActivityThread随后依次调⽤Looper.prepareLoop()和Looper.loop()来开启消息循环。开机不显示桌面图标
⽅法调⽤流程图如下:
更直⽩的流程解释:
①App发起进程:当从桌⾯启动应⽤,则发起进程便是Launcher所在进程;当从某App内启动远程进程,则发送进程便是该App所在进程。发起进程先通过binder发送消息给system_server进程;
②system_server进程:调⽤Process.start()⽅法,通过socket向zygote进程发送创建新进程的请求;
③zygote进程:在执⾏ZygoteInit.main()后便进⼊runSelectLoop()循环体内,当有客户端连接时便会执⾏
ZygoteConnection.runOnce()⽅法,再经过层层调⽤后fork出新的应⽤进程;
④新进程:执⾏handleChildProc⽅法,最后调⽤ActivityThread.main()⽅法。
2.绑定Application
上⾯创建进程后,执⾏ActivityThread.main()⽅法,随后调⽤attach()⽅法。
将进程和指定的Application绑定起来。这个是通过上节的ActivityThread对象中调⽤bindApplication()⽅法完成的。该⽅法发送⼀个BIND_APPLICATION的消息到消息队列中, 最终通过handleBindApplication()⽅法处理该消息. 然后调⽤makeApplication()⽅法来加载App的classes到内存中。
⽅法调⽤流程图如下:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论