Launcher启动流程

基于Android U

SystemServer进程在启动的过程中会启动PackageManagerService,PackageManagerService启动后会将系统中的应用程序安装完成。先前已经启动的AMS会将Launcher启动起来。时序图如下:

启动Launcher的入口为AMS的systemReady()方法,它在SystemServer的startOtherServices()方法中被调用。

1
2
3
4
5
6
7
8
9
10
11
12
/frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
...
mActivityManagerService.systemReady(() -> {
Slog.i(TAG, "Making services ready");
t.traceBegin("StartActivityManagerReadyPhase");
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_ACTIVITY_MANAGER_READY);
t.traceEnd();
...
}, t);
...
}

ActivityManagerService#systemReady

1
2
3
4
5
6
7
8
9
10
11
12
13
14
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void systemReady(final Runnable goingCallback, @NonNull TimingsTraceAndSlog t) {
...
synchronized (this) {
...
boolean isBootingSystemUser = currentUserId == UserHandle.USER_SYSTEM;
if (isBootingSystemUser && !UserManager.isHeadlessSystemUserMode()) {
t.traceBegin("startHomeOnAllDisplays");
mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
t.traceEnd();
}
...
}
}

mAtmInternal.startHomeOnAllDisplays最终调用了RootWindowContainer.startHomeOnAllDisplays()。

1
2
3
4
5
6
7
8
9
/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
boolean startHomeOnAllDisplays(int userId, String reason) {
boolean homeStarted = false;
for (int i = getChildCount() - 1; i >= 0; i--) {
final int displayId = getChildAt(i).mDisplayId;
homeStarted |= startHomeOnDisplay(userId, reason, displayId);
}
return homeStarted;
}

在每个display上显示对应的Home界面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
boolean startHomeOnDisplay(int userId, String reason, int displayId) {
return startHomeOnDisplay(userId, reason, displayId, false /* allowInstrumenting */, false /* fromHomeKey */);
}

boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting, boolean fromHomeKey) {
// Fallback to top focused display or default display if the displayId is invalid.
if (displayId == INVALID_DISPLAY) {
final Task rootTask = getTopDisplayFocusedRootTask();
displayId = rootTask != null ? rootTask.getDisplayId() : DEFAULT_DISPLAY;
}

final DisplayContent display = getDisplayContent(displayId);
return display.reduceOnAllTaskDisplayAreas((taskDisplayArea, result) ->
result | startHomeOnTaskDisplayArea(userId, reason, taskDisplayArea, allowInstrumenting, fromHomeKey), false /* initValue */);
}

调用startHomeOnTaskDisplayArea()启动每个显示区域(DisplayArea)的Home界面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
boolean startHomeOnTaskDisplayArea(int userId, String reason, TaskDisplayArea taskDisplayArea, boolean allowInstrumenting, boolean fromHomeKey) {
...

Intent homeIntent = null;
ActivityInfo aInfo = null;
if (taskDisplayArea == getDefaultTaskDisplayArea()
|| mWmService.shouldPlacePrimaryHomeOnDisplay(
taskDisplayArea.getDisplayId(), userId)) {
homeIntent = mService.getHomeIntent();
aInfo = resolveHomeActivity(userId, homeIntent);
} else if (shouldPlaceSecondaryHomeOnDisplayArea(taskDisplayArea)) {
Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, taskDisplayArea);
aInfo = info.first;
homeIntent = info.second;
}
...

mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason, taskDisplayArea);
return true;
}

判断传入的TaskDisplayArea是否是默认的TaskDisplayArea。如果是,mService.getHomeIntent()获取对应的Intent,这就是传统的Launcher的启动意图。

在getHomeIntent()方法中创建了Intent,并将mTopAction和mTopData传入。mTopAction的值为Intent.ACTION_MAIN,并且如果系统运行模式不是低级工厂模式,则将Intent的Category设置为Intent.CATEGORY_HOME,最后返回该Intent。

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
/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
/**
* 这里主要是获取Launcher的Activity对应的Intent对象以及对应的ActivityInfo
*/
Intent getHomeIntent() {
Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
intent.setComponent(mTopComponent);
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
intent.addCategory(Intent.CATEGORY_HOME);
}
return intent;
}

/frameworks/base/services/core/java/com/android/server/wm/ActivityStartController.java
/**
* 这里主要是进行了一通设置后,调用了ActivityStarter对象的execute方法
*/
void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason,
TaskDisplayArea taskDisplayArea) {
...
mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)
.setOutActivity(tmpOutRecord)
.setCallingUid(0)
.setActivityInfo(aInfo)
.setActivityOptions(options.toBundle())
.execute();
...
}

startHomeActivity()启动的应用程序就是Launcher,因为Launcher的AndroidManifest.xml文件中的intent-filter标签匹配了Action为Intent.ACTION_MAIN,Category为Intent.CATEGORY_HOME。

execute()处理Activity启动请求的接口,executeRequest()执行一系列权限检查,对于合法的请求才继续。

1
2
3
4
5
/frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
int execute() {
...
res = executeRequest(mRequest);
}

后面的步骤和《根Activity的启动过程》相同。


Launcher启动流程
https://citrus-maxima.github.io/2024/03/10/Launcher启动流程/
作者
柚子树
发布于
2024年3月10日
许可协议