前言
前一篇文章《重温ActivityManagerService》重温了AMS,记录了AMS启动过程,与AMS交互的几个重要的类和数据结构。
分析的笔记见:AMS源码分析笔记
此文章主要记录一个应用是如何启动起来的。其中分析启动过程我将以两种不同的启动方式来分析:
- 根Activity的启动流程(进程没有启动的状态)
- 子Activity的启动过程(进程已经启动)
1 图解Acitivity启动过程
凡事由浅入深,一口气带出全过程必然一脸蒙蔽。因此我先放出一张简易版的子Activity的启动过程图。小伙伴们肯定可以看懂一个界面是如何启动起来的。但是该图只能说明大致流程,没有考虑进程还没有启动的情况。
然后看看稍微详细一些的子Activity启动流程图,可以更加详细得明白APP和AMS是如何调度的。
最后看看详细的根Activity的启动流程图,可以全面看清楚一个应用从无到启动完成的过程。后面章节也会详细叙述每个步骤做了什么。
注意:根Activity的23步到24步还做了很多事件,例如AMS通过Socket请求Zygote fork一个子进程等操作没有画入到该流程图中,因为该过程在《Android系统启动流程分析》中有分析到,此处只列出了调用AMS的startProcessLocked()就启动了一个进程,然后调用了ActivityThread的main()方法。
小结:
Launcher组件启动MainActivity组件的过程:
- (1)Launcher组件向AMS发送一个启动MAinActivity组件的进程间通信请求
- (2)AMS首先将要启动的MAinActivity组件信息保存下来,然后再向Launcher组件发送一个进入中止状态的进程间通信请求。
- (3)Launcher组件进入到中止状态之后,就会向AMS发送一个已进入中止状态的进程间通信请求,以便AMS可以继续执行启动MAinActivity组件的操作。
- (4)AMS发现用来运行MAinActivity组件的应用程序进程不存在,因此,他就会先启动一个新的应用程序进程。
- (5)新的应用程序进程启动完成之后,就会向AMS发送一个启动完成的进程间通信请求,以便AMS可以继续执行启动MAinActivity组件的操作。
- (6)AMS将第2步保存下来的MAinActivity组件的信息发送给第4步创建的应用程序进程,以便它可以将MAinActivity组件启动起来。
Ok, let's go! 为了叙述的完整性,我们还是从启动根Activity开始分析,因此启动子Activity绝大多数步骤是沿用启动根Activity的流程。
2.启动根Activity
启动根Activity我们以在Launcher应用中点击Icon开始分析。
2.1 在Launcher进程中完成的操作
在Launcher进程中完成了以下五个步骤的调用,具体实现的功能如下:
- 1.用户调用launcher的startActivitySafely,设置Activity组件启动标志位Intent.FLAG_ACTIVITY_NEW_TASK为1,然后调用父类的startActivity。
- 2.调用startActivityForResult(intent,int),第二个参数为-1,表示不需要知道即将启动的Activity组件的执行结果。
- 3.传递ApplicationThread给AMS,以便AMS告知Launcher可以进入pause状态,mToken对象指向AMS中的ActivityRecord,每一个已经启动的activity都会在AMS中记录一个ActivityRecord,用来记录activity组件运行状态。
- 4.在execStartActivity中通过AMS的代理对象调用AMS的startActivity。
- 5.AMS代理透传信息。
2.2 在ActivityManagerService中完成的操作
从6至12步骤是在AMS中完成的操作,具体实现的功能如下:
- 6.AMS内部有一个activityStack,用来描述一个activity组件堆栈,在该步骤中进一步调用mActivityStack的startActivityMayWait进一步响应进程间通信请求。
- 7.在PMS中解析Intent的内容,以获得要启动activity组件的信息。然后调用startActivityLocked继续启动activity
- 8.每一个应用程序都会使用ProcessRecord对象来描述并且保存在AMS内部。通过传进来的ApplicationThread在AMS中查询到Launcher的ProcessRecord。从mHistory堆栈中获得launcher组件的ActivityRecord。创建一个Mactivity的ActivityRecord。调用startActivityUncheckedLocked启动目标组件
- 9.判断新启动的activity是否要在新任务中启动,在AMS中查询该任务是否已经存在。为MainActivity创建新的任务,并且将该任务加入到AMS的task堆栈中。将目标ActivityRecord保存在mHistory中,并且把MAinActivity放在栈顶,调用resumeTopActivityLocked。
- 10.从栈顶取出activity,判断当前activity是不是被激活的activity,如果是,并且状态是Resumed直接退出,说明已经启动了。判断当前activity是否是上一次被中止的activity组件。由于当前activity是launcher,调用startPausingLocked来通知他进入pause状态。
- 11.向launcher发送一个中止通知,并且在AMS中发送一个中止超时消息,如果Launcher没有在超时时间内返回,那么就认为Launcher没有响应了。
- 12.透传参数给ApplicationThread。
2.3 在Launcher进程中完成的操作
从13至17步骤是在Launcher中完成的操作,具体内容如下:
13.调用ActivityThread的queueOrSendMessage,这个步骤已经在launcher进程中。准备将通知暂停的消息抛到主线程。
14.封装一个message发送到mH主线程。
15.处理activityThread发来的PAUSE_ACTIVITY
-
16.(1)从launcher进程中的mActivities中取出ActivityClientRecord。
(2)调用performUserLeavingActivity向launcher组件发送一个用户离开事件通知,即调用成员函数onUserLeaveHint (3)调用performPauseActivity向Launcher发送中止事件通知,调用成员函数onPause (4)调用QueuedWork类的静态方法waitToFinish()等待完成前面的一些数据写入操作。为了回到Resumed状态时,能够恢复当前的状态信息。 (5)调用handlePauseActivity向AMS发送中止Launcher组件的进程间通信请求。
17.从AMS代理调用activityPaused。
2.4 在ActivityManagerService中完成的操作
从18至23步骤是在AMS中完成的操作,具体实现的功能如下:
- 18.收到launcher已经暂停的通知之后,调用activitystack的activityPaused.
- 19.从mHistory取出launcher的ActivityRecord,从mHandler中移除暂停超时通知。调用completePauseLocked。
- 20.把当前进入mPausingAcitivity取出,如果是空的,表示当前正在进入中止的Activity已经进入了Paused状态。检查当前系统是不是正在进入睡眠或者关闭状态。
- 21.取出栈顶的ActivityRecord,MainActivity的app是空的,所以调用startSpecificActivityLocked将MainActivity的进程启动起来。
- 22.通过activityRecord中的UID和进程名字查找是否存在MAinActivity所在的进程,如果存在则直接通知Activity启动,否则AMS的startProcessLocked来启动MAinActivity应用进程。如果进程已经起来了,那就调用realStartActivityLocked
- 23.(1)通过processName和uid判断ProcessRecord是否存在,如果不存在,调用startProcessLocked启动新进程。
(2)创建新进程用户Id和用户组Id
(3)Process.start方法启动一个新的应用进程
(4)将新创建的ProcessRecord保存在AMS的mPidsSelfLocked中,并且发送一个启动计时Message,如果超时AMS认为进程启动失败,否则AMS就会通知应用启动Maintivity。
2.5 在Launcher进程中完成的操作
24步之前,AMS会调到Zygote, Zygote会fork一个进程出来,然后调用Launcher的ActivityThread.main().
从24至25步骤是在Launcher中完成的操作,具体内容如下:
- 24.此步骤已经进入了新进程Main方法,在Main方法中新建MainLooper,然后new一个ActivityThread,并且调用attach方法,最后Looper循环起来。在ActivityThread中新建一个ApplicationThread,通过AMS代理调用attachApplication。
- 25.新建进程状态透传给AMS。此处将IApplicationThread传递给AMS,AMS之后就可以通过Binder 客户端和新起来的进程通信了。
2.6 在ActivityManagerService中完成的操作
从27至30步骤是在AMS中完成的操作,具体实现的功能如下:
- 27.(1)通过PID在AMS中找到新建的ProcessRecors并且初始化他们。
(2)移除应用启动超时消息
(3)获取栈顶activityRecord,并且判断栈顶的activityRecord和要启动的是不是一致的。如果是一致的,调用activityStack的realStartAcitivityLocked - 28.将ActivityRecord的app值赋成新建的APP,然后将activity组件存入app所描述的进程中。然后在app描述的线程中调用scheduleLauncherActivity来通知新创建的进程启动activityRecord所描述的组件,即MainActivity
- 29.透传activityRecord信息
- 30.此步已经回到了新启动的应用进程。新建一个ActivityClientRecord,将AMS传来的参数对该ActivityClientRecord初始化,并且调用queueOrSendMessage
2.7 在Launcher进程中完成的操作
从31至35步骤是在Launcher中完成的操作,具体内容如下:
- 31.封装一个message向主线程handle一个消息。
- 32.通过ActivityClientRecord的applicationInfo查询新启动应用程序的包信息。然后调用handleLaunchActivity来启动一个新的activity
- 33.调用performLaunchActivity将MainActivity启动起来,并且调用HandleResumeActivity表示当前activity已经处于已激活状态。
- 34.(1)获取componentName,并且用ActivityClientRecord.packageInfo的类加载器加载MainActivity类。
(2)ActivityClientRecord.packageInfo的makeApplication创建一个Application对象。
(3)如果上面加载的MainActivity不是空的。新建一个contextImpl并且用ActivityClientRecord来初始化他。
(4)调用activity.attach来初始化activity
(5)调用mInstrumentation.callActivityOnCreate
(6)将activityClientRecord的token作为关键字,并且将他保存在Activity的mActivity中。token是一个Binder代理,指向AMS中对应activity的ActivityRecrod - 35.onCreate被调用,加载用户界面,已经对用户界面上的控件进行初始化。
2.8 小结
MainActivity组件作为应用程序Activity的根activity,他启动起来就意味着应用程序启动起来了。因此我们可以将一个根Activity的启动过程看做一个Android应用程序的启动过程。
3.启动子Activity
启动子Activity和启动根Activity步骤相似度非常高,只是在startActivityUncheckedLocked中判断是否能通过AcitivityRecord获得到IApplicationThread,如果获取不到就说明进程没有启动,就去先启进程;如果不为空,就直接启动子Activity。
3.1 在Launcher进程中完成的操作
从1至5步骤是在Launcher中完成的操作,具体内容如下:
- 1.设置intent,调用startActivity
- 2.3.4.5.沿用根activity启动的流程,并且目前是在原应用进程中执行。
3.2 在ActivityManagerService中完成的操作
从6至12步骤是在AMS中完成的操作,具体实现的功能如下:
- 6.7.8.沿用根activity流程。从这三步开始在AMS进程中执行。
- 9.判断是否需要创建一个新的任务来启动子activity组件。将新建的activityRecord加入到mHistory中。调用resumeTopActivityLocked
- 10.检查要启动的activity是否已经是当前激活的activity,判断要启动的activity的是否是上次中止的activity。
- 11.发送暂停通知,并且开始计时
- 12.透传暂停通知
3.3 在Launcher进程中完成的操作
从13至17步骤是在Launcher中完成的操作,具体内容如下:
- 13.调用queueOrSendMessage
- 14.封装message并且发送到主线程
- 15.处理暂停事件
- 16.(1)获得前一个组件ActivityClientRecord
(2)向前一个组件发送离开通知,调用onUserLeaveHint
(3)调用前一个组件的中止通知onPause
(4)等待前一个组件将数据写入磁盘 - 17.将前一个组件已经暂停的通知告知AMS
3.4 在ActivityManagerService中完成的操作
从18至25步骤是在AMS中完成的操作,具体实现的功能如下:
- 18.透传已暂停通知给AMS
- 19.暂停计时,设置上一个activity为pause状态
- 20.设置中止中的activity为上一个activity,说明暂停状态已经结束
- 21.取出栈顶的ActivityRecord,SubActivity的app是空的,所以调用startSpecificActivityLocked将SubActivity的进程启动起来。
- 22.查看processRecord是否是空,如果不是空,则调用realStartActivityLocked真正启动一个activity
- 23.将ActivityRecord的app值赋成新建的APP,然后将activity组件存入app所描述的进程中。然后在app描述的线程中调用scheduleLauncherActivity来通知新创建的进程启动activityRecord所描述的组件,即SubActivity
- 24.透传activityRecord信息
- 25.用传来的activityRecord初始化activityClientRecord
3.5 在Launcher进程中完成的操作
从26至30步骤是在Launcher中完成的操作,具体实现的功能如下:
- 26.封装一个message,向主线程发送一个message
- 27.获取APK资源来处理启动activity事件
- 28.调用performLaunchActivity将MainActivity启动起来,并且调用HandleResumeActivity表示当前activity已经处于已激活状态。
- 29.(1)获取componentName,并且用ActivityClientRecord.packageInfo的类加载器加载MainActivity类。
(2)ActivityClientRecord.packageInfo的makeApplication创建一个Application对象。
(3)如果上面加载的MainActivity不是空的。新建一个contextImpl并且用ActivityClientRecord来初始化他。
(4)调用activity.attach来初始化activity
(5)调用mInstrumentation.callActivityOnCreate
(6)将activityClientRecord的token作为关键字,并且将他保存在Activity的mActivity中。token是一个Binder代理,指向AMS中对应activity的ActivityRecrod - 30.onCreate被调用,加载用户界面,已经对用户界面上的控件进行初始化。
3.6 说明
如果子activity设置了android:process属性为另一个进程,启动过程跟MainActivity启动一样,只是不用再新建一个task了,因为子activity的android:taskAffinity和MAinActivity是一样的,MainActivity已经新创建了一个task,可以在同一个task中进程。