AMS做了一系列初始化操作之后,会进入AMS.systemReady()方法,Launcher的启动就是由这个方法开始的。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
/**
* Ready. Set. Go!
*/
public void systemReady(final Runnable goingCallback, @NonNull TimingsTraceAndSlog t) {
t.traceBegin("PhaseActivityManagerReady");
mSystemServiceManager.preSystemReady();
synchronized(this) {
......
if (bootingSystemUser) {
t.traceBegin("startHomeOnAllDisplays");
mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");//需要启动界面,肯定要AMS启动完成。
t.traceEnd();
}
......
}
}
mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
可以看到调用了mAtmInternel.startHomeOnAllDisplays()方法来启动launcher。而mAtmInternel是一个ActivityTaskManagerInternal的对象,ActivityTaskManagerInternal是一个抽象类,里面定义了一些抽象方法。这些抽象方法实际上是在ActivityTaskManagerService.java的内部类LocalService.java中实现的。(源码里面一般类似xxxInternal的抽象类,实现类往往是xxxService里面的LocalService)
所以它实际上调用的是ActivityTaskManagerService.java的startHomeOnAllDisplays()方法
frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
final class LocalService extends ActivityTaskManagerInternal {
......
@Override
public boolean startHomeOnAllDisplays(int userId, String reason) {
synchronized (mGlobalLock) {
return mRootWindowContainer.startHomeOnAllDisplays(userId, reason);
}
}
......
}
调用了RootWindowContainer.java里的startHomeOnAllDisplays()方法。
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界面,调用了同文件里的startHomeOnDisplay()方法。
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) {//判断diaplay id是否有效,如果无效,则回退到top焦点显示,或者默认显示
final Task rootTask = getTopDisplayFocusedRootTask();
displayId = rootTask != null ? rootTask.getDisplayId() : DEFAULT_DISPLAY;
}
final DisplayContent display = getDisplayContent(displayId);//获取display信息
return display.reduceOnAllTaskDisplayAreas((taskDisplayArea, result) ->
result | startHomeOnTaskDisplayArea(userId, reason, taskDisplayArea,
allowInstrumenting, fromHomeKey),
false /* initValue */);
}
后面继续调用startHomeOnTaskDisplayArea()方法
frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
boolean startHomeOnTaskDisplayArea(int userId, String reason, TaskDisplayArea taskDisplayArea,
boolean allowInstrumenting, boolean fromHomeKey) {
// Fallback to top focused display area if the provided one is invalid.
if (taskDisplayArea == null) {//如果taskDisplayArea为null,回退到当前顶部焦点显示
final Task rootTask = getTopDisplayFocusedRootTask();
taskDisplayArea = rootTask != null ? rootTask.getDisplayArea()
: getDefaultTaskDisplayArea();
}
Intent homeIntent = null;//要启动的launcher中的home intent
ActivityInfo aInfo = null;//要启动的launcher中的activity info
if (taskDisplayArea == getDefaultTaskDisplayArea()) {//判断传入的taskDisplayArea是否是默认的taskDisplayArea
homeIntent = mService.getHomeIntent();//1.调用了ActivityTaskManagerService里的getHomeIntent()方法获取默认屏幕的home intent
aInfo = resolveHomeActivity(userId, homeIntent);//2.获取home activity的信息
} else if (shouldPlaceSecondaryHomeOnDisplayArea(taskDisplayArea)) {// 如果需要加载第二个屏幕home intent的activity
Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, taskDisplayArea);
aInfo = info.first;
homeIntent = info.second;
}
if (aInfo == null || homeIntent == null) {
return false;
}
if (!canStartHomeOnDisplayArea(aInfo, taskDisplayArea, allowInstrumenting)) {//检查是否允许在屏幕上开始显示home activity
return false;
}
// Updates the home component of the intent.
//设置homeintent的一些属性
homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
// Updates the extra information of the intent.
if (fromHomeKey) {//表示是否是由于按了home按键导致的启动home intent
homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);
if (mWindowManager.getRecentsAnimationController() != null) {
mWindowManager.getRecentsAnimationController().cancelAnimationForHomeStart();
}
}
homeIntent.putExtra(WindowManagerPolicy.EXTRA_START_REASON, reason);
// Update the reason for ANR debugging to verify if the user activity is the one that
// actually launched.
final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(
aInfo.applicationInfo.uid) + ":" + taskDisplayArea.getDisplayId();//获取启动home activity的reason
mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
taskDisplayArea);//3.启动home activity
return true;
}
startHomeOnTaskDisplayArea()方法里主要是设置了一些home intent的属性,封装进homeIntent中,然后通过startHomeActivity()方法来启动对应的activity。首先是通过mService.getHomeIntent()方法获取需要启动的intent信息:
frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
RootWindowContainer(WindowManagerService service) {
super(service);
......
mService = service.mAtmService;
......
}
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
final ActivityTaskManagerService mAtmService;
所以实际上调用的是ActivityTaskManagerService里的getHomeIntent()方法获取需要启动的intent信息,主要是添加一个category为CATEGORY_HOME的Intent,表明是Home Activity
frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
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;
}
getHomeIntent()函数中创建了Intent,并将mTopAction和mTopData传入。mTopAction的值为Intent.ACTION_MAIN,如果系统运行模式不是低级工厂模式则将intent的Category设置为Intent.CATEGORY_HOME。Launcher的Intent对象中添加了Intent.CATEGORY_HOME常量,这个其实是一个launcher的标志,一般系统的启动页面Activity都会在AndroidManifest.xml中配置这个标志。
然后是调用resolveHomeActivity()方法从PKMS中查询Category类型为HOME的Activity。
这里只有系统自带的Launcher应用程序注册了HOME类型的Activity
frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
@VisibleForTesting
ActivityInfo resolveHomeActivity(int userId, Intent homeIntent) {
final int flags = ActivityManagerService.STOCK_PM_FLAGS;
final ComponentName comp = homeIntent.getComponent();
ActivityInfo aInfo = null;
try {
if (comp != null) {
// Factory test.
aInfo = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
} else {//系统正常启动,走该流程
final String resolvedType =
homeIntent.resolveTypeIfNeeded(mService.mContext.getContentResolver());
final ResolveInfo info = AppGlobals.getPackageManager()
.resolveIntent(homeIntent, resolvedType, flags, userId);//查找符合home intent的activities,然后找出最符合的那个activity
if (info != null) {
aInfo = info.activityInfo;
}
}
} catch (RemoteException e) {
// ignore
}
if (aInfo == null) {
Slog.wtf(TAG, "No home screen found for " + homeIntent, new Throwable());
return null;
}
aInfo = new ActivityInfo(aInfo);
aInfo.applicationInfo = mService.getAppInfoForUser(aInfo.applicationInfo, userId);
return aInfo;
}
获取好了需要启动的activity信息之后,通过ActivityStartController里的startHomeActivity()方法来启动对应的activity
frameworks/base/services/core/java/com/android/server/wm/ActivityStartController.java
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();
......
}
ActivityStarter obtainStarter(Intent intent, String reason) {
return mFactory.obtain().setIntent(intent).setReason(reason);
}
在这个方法中主要是传入启动所需的各种参数,然后就是启动了一个异步任务去开始启动activity。可以看到obtainStarter()方法返回了一个ActivityStarter对象,所以调用了ActivityStarter的execute()方法。
frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
int execute() {
try {
......
res = executeRequest(mRequest);
......
}
调用了executeRequest()方法,在这个方法中首先根据Request获取要启动activity的一些属性,检查activity权限、后台启动activity及判断是否可以启动这个activity,然后调用startActivityUnchecked()->startActivityInner()来启动home activity。