浅析Android系统中的Activity启动过程
一、Activity的启动分为三种类型1.根Activity的启动,通常就是程序的MainActivity的启动,这个是通过用户点击桌面程序(Launcher)的App的图标,
从而导致对应的App在一个新的进程中被启动起来
2.在同一个进程启动子Activity
3.在新的进程启动子Activity
对应第一种类型来讲,主要是有如下分析:
首先根ACtivity的启动涉及到三个不同的进程,依次是Launcher所在进程,MainActivity所在进程,ActivityManagerService所在进程。
其中ActivityManagerService是系统关键服务,他是用来管理系统Activity组件的一个服务,优先级特别高。任何app的Activity的活动都需要与它交互。既然涉及到这么多个进程的交互,那么必然涉及到Android系统中的Binder进程通讯。
其次就是Launcher启动MainActivity的过程分析,大致分为6个阶段
p1:当用户点击桌面app的图标时,Launcher(其实就是一个Activity。或者叫做继承自Activity)就获取到App的一些信息(比如,包名,路径等)(这些信息其实是Launcher通过查询PackageManagerService获得的),Launcher拿着这些信息然后去向ActivityManagerService请求一次进程间通信,表示我想要启动某个App的MainActivity。
p1.1
p1.2
p2.ActivityManagerService收到进程间请求后,会做两件事情,第一将刚刚收到的关于启动MainActivity的信息保存下来(这些信息包括ActivityRecord等), 第二向Launcher发送一次进程间通信请求,请求Launcher进入Pause状态,这样有利于Launcher在MainActivity启动起来时,自己可以做一些操作,例如保存状态信息,以便于Launcher后面Resume。
p2
p3.Launcher收到了ActivityManagerService的进程间通信请求后,就会进入到Paused状态,进入到状态后,会立马向ActivityManagerService再次发送一次进程间通信请求,表示我已经进入了Paused状态,你可以放心的去启动MainActivity了。值得注意的是,ActivityManagerSerice有一个超时机制,如果Launcher在指定的时间没有进入Paused状态,即ActivityManagerService没有及时收到Launcher组件的再一次进程间通信请求,ActivityManagerService会认为Launcher无响应。
p3
p4
p5
p6
这里一个6个阶段,共涉及到5次进程间通信,其中Launcher与ActivityManagerService之间进行了3次,ActivityManagerService与MainActivity所在进程之间进行了2次。
其中涉及到的进程间通信请求具体如下:
-----------------------------------------------------------------------------------------------------------------------
id phase detail
-----------------------------------------------------------------------------------------------------------------------
#1 p1: Launcher所在进程 ----START_ACTIVITY_TRANSACTION----> ActivityManagerService所在进程
#2 p2: ActivityManagerService所在进程 ----SCHEDULE_PAUSE_ACTIVITY_TRANSACTION----> Launcher所在进程
#3 p3: Launcher所在进程 ----ACTIVITY_PAUSED_TRANSACTION----> ActivityManagerService所在进程
#4 p5: MainActivity(新建进程) ----ATTACH_APPLICATION_TRANSACTION----> ActivityManagerService
#5 p6: ActivityManagerService所在进程 ----SCHEDULE_LANUCHER_ACTIVITY_TRANSACTION----> MainActivity(新建进程)
-----------------------------------------------------------------------------------------------------------------------
二、对应第二种类型分析如下:
由于在同一个进程中,一个Activity启动另一个Activity,这两个Activity都是运行在同一个进程中的,因此相比于前面分析的第一种类型,就少了ActivityManagerService去新建一个进程和新建进程对ActivityManagerService做一次ATTACH_APPLICATION_TRANSACTION请求这个步骤
值得注意的是,由于MainActivity去启动一个子Activity是在同一个App中进行的并且没有特别指明taskAffinity,因此他们启动后再ActivityManagerService中都是同属于一个Task的,而非不同的Task。
三、对应于第三种类型分析如下:
由于是在同一个App中,但是两个Activity试运行在不同的进程中的,因此相比于第一种类型,有一点相似之处,但是不同的是两个Activity所属于的Task是一样的,因为他们虽然不属于同一个进程,但是他们是属于一个app的,是属于密切联系的一个用户任务,因此理所当然的就应该是在同一task中了。
每一个Activity都是运行在一个Task中的,Task是一个比进程更加高级和抽象的概念,由于Android的App可以拥有多个不同的进程,用Task去描述一系列相关的功能比用进程去描述更加容易理解和描述。一个Task可以包含运行在不同进程中的Activity,因此可以很好的提高Activity的可重用性。(比如你的App想要查看一张照片,那么任何App提供查看照片能力的Activity都可以添加到你的App所在的Task中,虽然他们是运行在不同进程,而且甚至是不同uid中的,但是由于Task的存在,用户丝毫感觉不到是两个App, 这样查看照片的Activity就可以得到复用)
四、总结
这个过程涉及到几个主要的类:
<span style="font-size:18px;">ActivityThread ApplicationThread ActivityManagerService Instrumentation ActivityRecord ProcessRecord TaskRecord ActivityStack ActivityManagerProxy ApplocationThreadProxy</span>
参考文献:
[1]罗升阳.Android系统源代码情景分析[M].北京:电子工业出版社,2012:393-443