前言
在我们开始之前,希望您能最好已经满足以下条件:
1、有一份编译后的Android源码(亲自动手实践才会有更深入的理解)
2、对Binder机制有一定的了解
本文启动流程分析基于Android 5.1的源码。为什么是5.1的源码呢?因为手边编译完的代码只有这个版本…另外,用什么版本的源码并不重要,大体的流程并无本质上的区别,仅仅是实现细节的调整,找一个你熟悉的版本就好。
1、启动时序图
作为一个轻微强迫症的人,整理的时序图,相信大家按图索骥,一定能搞明白整个启动流程:
说明:为了让大家更清楚的理解整个过程,将时序图中划分为三个部分:Launcher进程、System进程、App进程,其中有涉及共用的类以L / A进行区分表示跟哪个进程有关,便于理解。
2、关键类说明
整个启动流程因为会涉及到多次Binder通信,这里先简要说明一下几个类的用途,方便大家理解整个交互流程:
1、ActivityManagerService:AMS是Android中最核心的服务之一,主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,其职责与操作系统中的进程管理和调度模块相类似,因此它在Android中非常重要,它本身也是一个Binder的实现类。
2、Instrumentation:顾名思义,它用来监控应用程序和系统的交互。
3、ActivityThread:应用的入口类,系统通过调用main函数,开启消息循环队列。ActivityThread所在线程被称为应用的主线程(UI线程)。
4、ApplicationThread:ApplicationThread提供Binder通讯接口,AMS则通过代理调用此App进程的本地方法。
5、ActivityManagerProxy:AMS服务在当前进程的代理类,负责与AMS通信。
6、ApplicationThreadProxy:ApplicationThread在AMS服务中的代理类,负责与ApplicationThread通信。
3、流程分析
首先交代下整个流程分析的场景:用户点击Launcher上的应用图标到该应用主界面启动展示在用户眼前。
这整个过程涉及到跨进程通信,所以我们将其划分为时序图中所展示三个进程:Launcher进程、System进程、App进程。为了不贴过长的代码又能说清楚进程间交互的流程,这里简述几个重要的交互点。
从时序图上大家也可以看到调用链相当长,对应的代码量也比较大,而且时序图只是分析了这个一个场景下的流程。道阻且长,行则将至!
3.1 Launcher响应用户点击,通知AMS
Launcher做为应用的入口,还是有必要交代一下的,我们来看看Launcher的代码片段,Launcher使用的是packages/apps/Launcher3的的源码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
public
class
Launcher
extends
Activity
implements
View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener {
...
/**
* Launches the intent referred by the clicked shortcut.
*
* @param v The view representing the clicked shortcut.
*/
public
void
onClick(View v) {
// Make sure that rogue clicks don't get through while allapps is launching, or after the
// view has detached (it's possible for this to happen if the view is removed mid touch).
if
(v.getWindowToken() ==
null
) {
return
;
}
...
Object tag = v.getTag();
if
(tag
instanceof
ShortcutInfo) {
onClickAppShortcut(v);
}
else
if
(tag
instanceof
FolderInfo) {
...
}
else
if
(v == mAllAppsButton) {
onClickAllAppsButton(v);
}
else
if
(tag
instanceof
AppInfo) {
startAppShortcutOrInfoActivity(v);
}
else
if
(tag
instanceof
LauncherAppWidgetInfo) {
...
}
}
private
void
startAppShortcutOrInfoActivity(View v) {
...
boolean
success = startActivitySafely(v, intent, tag);
...
}
boolean
startActivitySafely(View v, Intent intent, Object tag) {
...
try
{
success = startActivity(v, intent, tag);
}
catch
(ActivityNotFoundException e) {
...
}
return
success;
}
boolean
startActivity(View v, Intent intent, Object tag) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try
{
...
if
(user ==
null
|| user.equals(UserHandleCompat.myUserHandle())) {
// Could be launching some bookkeeping activity
startActivity(intent, optsBundle);
}
else
{
...
}
return
true
;
}
catch
(SecurityException e) {
...
}
return
false
;
}
}
|
通过starActicity辗转调用到Activity:startActivityForResult
而后则调用至Instrumentation:execStartActivity
,代码片段如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public
class
Instrumentation {
...
public
ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent,
int
requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
...
try
{
...
int
result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target !=
null
? target.mEmbeddedID :
null
,
requestCode,
0
,
null
, options);
...
}
catch
(RemoteException e) {
}
return
null
;
}
...
}
|
这里的ActivityManagerNative.getDefault
返回ActivityManagerService
的远程接口,即ActivityManagerProxy
接口,有人可能会问了为什么会是ActivityManagerProxy
,这就涉及到Binder通信了,这里不再展开。通过Binder驱动程序,ActivityManagerProxy
与AMS服务通信,则实现了跨进程到System进程。
3.2 AMS响应Launcher进程请求
从上面的流程我们知道,此时AMS应该处理Launcher进程发来的请求,请参看时序图及源码,此时我们来看ActivityStackSupervisor:startActivityUncheckedLocked
方法,目测这个方法已经超过600行代码,来看一些关键代码片段:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
public
final
class
ActivityStackSupervisor
implements
DisplayListener {
...
final
int
startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int
startFlags,
boolean
doResume, Bundle options, TaskRecord inTask) {
final
Intent intent = r.intent;
final
int
callingUid = r.launchedFromUid;
...
final
boolean
launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
final
boolean
launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;
final
boolean
launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;
int
launchFlags = intent.getFlags();
...
// We'll invoke onUserLeaving before onPause only if the launching
// activity did not explicitly state that this is an automated launch.
mUserLeaving = (launchFlags & Intent.FLAG_ACTIVITY_NO_USER_ACTION) ==
0
;
...
ActivityRecord notTop =
(launchFlags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) !=
0
? r :
null
;
// If the onlyIfNeeded flag is set, then we can do this if the activity
// being launched is the same as the one making the call... or, as
// a special case, if we do not know the caller then we count the
// current top activity as the caller.
if
((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) !=
0
) {
...
}
...
// If the caller is not coming from another activity, but has given us an
// explicit task into which they would like us to launch the new activity,
// then let's see about doing that.
if
(sourceRecord ==
null
&& inTask !=
null
&& inTask.stack !=
null
) {
final
Intent baseIntent = inTask.getBaseIntent();
final
ActivityRecord root = inTask.getRootActivity();
...
// If this task is empty, then we are adding the first activity -- it
// determines the root, and must be launching as a NEW_TASK.
if
(launchSingleInstance || launchSingleTask) {
...
}
...
}
...
if
(inTask ==
null
) {
if
(sourceRecord ==
null
) {
// This activity is not being started from another... in this
// case we -always- start a new task.
if
((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) ==
0
&& inTask ==
null
) {
Slog.w(TAG,
"startActivity called from non-Activity context; forcing "
+
"Intent.FLAG_ACTIVITY_NEW_TASK for: "
+ intent);
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}
}
else
if
(sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
// The original activity who is starting us is running as a single
// instance... this new activity it is starting must go on its
// own task.
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}
else
if
(launchSingleInstance || launchSingleTask) {
// The activity being started is a single instance... it always
// gets launched into its own task.
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}
}
...
// We may want to try to place the new activity in to an existing task. We always
// do this if the target activity is singleTask or singleInstance; we will also do
// this if NEW_TASK has been requested, and there is not an additional qualifier telling
// us to still place it in a new task: multi task, always doc mode, or being asked to
// launch this as a new task behind the current one.
if
(((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) !=
0
&&
(launchFlags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) ==
0
)
|| launchSingleInstance || launchSingleTask) {
// If bring to front is requested, and no result is requested and we have not
// been given an explicit task to launch in to, and
// we can find a task that was started with this same
// component, then instead of launching bring that one to the front.
if
(inTask ==
null
&& r.resultTo ==
null
) {
// See if there is a task to bring to the front. If this is
// a SINGLE_INSTANCE activity, there can be one and only one
// instance of it in the history, and it is always in its own
// unique task, so we do a special search.
ActivityRecord intentActivity = !launchSingleInstance ?
findTaskLocked(r) : findActivityLocked(intent, r.info);
if
(intentActivity !=
null
) {
...
}
}
}
...
if
(r.packageName !=
null
) {
// If the activity being launched is the same as the one currently
// at the top, then we need to check if it should only be launched
// once.
ActivityStack topStack = getFocusedStack();
ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
if
(top !=
null
&& r.resultTo ==
null
) {
if
(top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
...
}
}
}
else
{
...
}
boolean
newTask =
false
;
boolean
keepCurTransition =
false
;
TaskRecord taskToAffiliate = launchTaskBehind && sourceRecord !=
null
?
sourceRecord.task :
null
;
// Should this be considered a new task?
if
(r.resultTo ==
null
&& inTask ==
null
&& !addingToTask
&& (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) !=
0
) {
...
if
(reuseTask ==
null
) {
r.setTask(targetStack.createTaskRecord(getNextTaskId(),
newTaskInfo !=
null
? newTaskInfo : r.info,
newTaskIntent !=
null
? newTaskIntent : intent,
voiceSession, voiceInteractor, !launchTaskBehind
/* toTop */
),
taskToAffiliate);
...
}
else
{
r.setTask(reuseTask, taskToAffiliate);
}
...
}
else
if
(sourceRecord !=
null
) {
}
else
if
(!addingToTask &&
(launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) !=
0
) {
}
else
if
(inTask !=
null
){
}
else
{
}
...
targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
...
return
ActivityManager.START_SUCCESS;
}
...
}
|
函数经过intent的标志值设置,通过findTaskLocked
函数来查找存不存这样的Task,这里返回的结果是null,即intentActivity
为null,因此,需要创建一个新的Task来启动这个Activity
。现在处理堆栈顶端的Activity
是Launcher
,与我们即将要启动的MainActivity
不是同一个Activity
,创建了一个新的Task里面来启动这个Activity
。
经过栈顶检测,则需要将Launcher推入Paused状态,才可以启动新的Activity
。后续则调用至ActivityStack:startPausingLocked
,我们来看一下这个函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
final
class
ActivityStack {
...
final
boolean
startPausingLocked(
boolean
userLeaving,
boolean
uiSleeping,
boolean
resuming,
boolean
dontWait) {
if
(mPausingActivity !=
null
) {
...
}
ActivityRecord prev = mResumedActivity;
if
(prev ==
null
) {
...
}
...
mResumedActivity =
null
;
mPausingActivity = prev;
mLastPausedActivity = prev;
mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) !=
0
|| (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) !=
0
? prev :
null
;
prev.state = ActivityState.PAUSING;
...
if
(prev.app !=
null
&& prev.app.thread !=
null
) {
try
{
...
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait);
}
catch
(Exception e) {
...
}
}
else
{
...
}
...
}
...
}
|
这里的prev.app.thread
是一个ApplicationThread
对象的远程接口,通过调用这个远程接口的schedulePauseActivity
来通知Launcher进入Paused状态。至此,AMS对Launcher的请求已经响应,这是我们发现又通过Binder通信回调至Launcher进程。
3.3 Launcher进程挂起Launcher,再次通知AMS
这个流程相对会简单一些,我们来看ActivityThread
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public
final
class
ActivityThread {
...
private
void
handlePauseActivity(IBinder token,
boolean
finished,
boolean
userLeaving,
int
configChanges,
boolean
dontReport) {
ActivityClientRecord r = mActivities.get(token);
if
(r !=
null
) {
...
performPauseActivity(token, finished, r.isPreHoneycomb());
// Make sure any pending writes are now committed.
if
(r.isPreHoneycomb()) {
QueuedWork.waitToFinish();
}
// Tell the activity manager we have paused.
if
(!dontReport) {
try
{
ActivityManagerNative.getDefault().activityPaused(token);
}
catch
(RemoteException ex) {
}
}
...
}
}
...
}
|
这部分Launcher的ActivityThread
处理页面Paused并且再次通过ActivityManagerProxy
通知AMS。
3.4 AMS创建新的进程
创建新进程的时候,AMS会保存一个ProcessRecord
信息,如果应用程序中的AndroidManifest.xml配置文件中,我们没有指定Application标签的process属性,系统就会默认使用package的名称。每一个应用程序都有自己的uid,因此,这里uid + process的组合就可以为每一个应用程序创建一个ProcessRecord
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public
final
class
ActivityManagerService
extends
ActivityManagerNative
implements
Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
...
private
final
void
startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
...
try
{
|