Android系统起来之后,会启动Launcher的主Activity。
看一下调用链
SystemServer startOtherServices(......)
--> ActivityManagerService systemReady(......)
--> LocalService startHomeOnAllDisplays(......) LocalService是ActivityTaskManagerService 类的内部类
-> RootWindowContainer startHomeOnAllDisplays(......)
-> RootWindowContainer startHomeOnAllDisplays(int userId, String reason, int displayId)
--> RootWindowContainer startHomeOnAllDisplays(int userId, String reason, int displayId, boolean allowInstrumenting, boolean fromHomeKey)
--> DisplayContent reduceOnAllTaskDisplayAreas((taskDisplayArea, result) ->
result | startHomeOnTaskDisplayArea(userId, reason, taskDisplayArea, allowInstrumenting, fromHomeKey),
false /* initValue */)
--> RootWindowContainer startHomeOnTaskDisplayArea(int userId, String reason, TaskDisplayArea taskDisplayArea, boolean allowInstrumenting, boolean fromHomeKey)
--> ActivityStartController. startHomeActivity(......)
--> ActivityStarter execute()
这里直接从RootWindowContainer startHomeOnTaskDisplayArea(int userId, String reason, TaskDisplayArea taskDisplayArea, boolean allowInstrumenting, boolean fromHomeKey)看,代码如下:
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) {
final Task rootTask = getTopDisplayFocusedRootTask();
taskDisplayArea = rootTask != null ? rootTask.getDisplayArea()
: getDefaultTaskDisplayArea();
}
Intent homeIntent = null;
ActivityInfo aInfo = null;
if (taskDisplayArea == getDefaultTaskDisplayArea()) {
homeIntent = mService.getHomeIntent();
aInfo = resolveHomeActivity(userId, homeIntent);
} else if (shouldPlaceSecondaryHomeOnDisplayArea(taskDisplayArea)) {
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)) {
return false;
}
// Updates the home component of the intent.
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) {
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();
mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
taskDisplayArea);
return true;
}
taskDisplayArea是不为null的,它的构建可以参考看一下这篇文章 Android 窗口结构(一) 窗口层级构造。
Android是支持多屏幕的,这里咱们针对单屏幕来说。也即是满足第一个if分支的情况。下面是得到homeIntent,然后通过homeIntent再得到aInfo。
这里mService是ActivityTaskManagerService对象,它的getHomeIntent()得到的Intent对象,action为Intent.ACTION_MAIN,Category为Intent.CATEGORY_HOME。这个是Launcher的主Activity配置。
接着通过resolveHomeActivity(userId, homeIntent)解析该Intent对象,得到对应的Activity信息对象aInfo。这块如果只存在一个Launcher,它就返回对应Launcher主Activity的信息;如果是配置了多个Launcher,它会返回ResolverActivity的信息,如果是这样,等下面启动ResolverActivity时,它会显示一个界面 ,让选择运行哪个Launcher。这里咱们就说一个Launcher的情况。
接下来,它会配置Intent对象的ComponentName。它包括包名和Activity名字。还会加上FLAG_ACTIVITY_NEW_TASK标识,它代表启动一个新的Task。
再接下来就是调用ActivityStartController类对象startHomeActivity()方法去启动Activity。mService.getActivityStartController()是ActivityTaskManagerService对象的成员mActivityStartController,它是ActivityStartController类型。
ActivityStartController类的startHomeActivity方法如下:
java
void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason,
TaskDisplayArea taskDisplayArea) {
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
if (!ActivityRecord.isResolverActivity(aInfo.name)) {
// The resolver activity shouldn't be put in root home task because when the
// foreground is standard type activity, the resolver activity should be put on the
// top of current foreground instead of bring root home task to front.
options.setLaunchActivityType(ACTIVITY_TYPE_HOME);
}
final int displayId = taskDisplayArea.getDisplayId();
options.setLaunchDisplayId(displayId);
options.setLaunchTaskDisplayArea(taskDisplayArea.mRemoteToken
.toWindowContainerToken());
// The home activity will be started later, defer resuming to avoid unnecessary operations
// (e.g. start home recursively) when creating root home task.
mSupervisor.beginDeferResume();
final Task rootHomeTask;
try {
// Make sure root home task exists on display area.
rootHomeTask = taskDisplayArea.getOrCreateRootHomeTask(ON_TOP);
} finally {
mSupervisor.endDeferResume();
}
mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)
.setOutActivity(tmpOutRecord)
.setCallingUid(0)
.setActivityInfo(aInfo)
.setActivityOptions(options.toBundle())
.execute();
mLastHomeActivityStartRecord = tmpOutRecord[0];
if (rootHomeTask.mInResumeTopActivity) {
// If we are in resume section already, home activity will be initialized, but not
// resumed (to avoid recursive resume) and will stay that way until something pokes it
// again. We need to schedule another resume.
mSupervisor.scheduleResumeTopActivities();
}
}
首先设置参数ActivityOptions类型options,先设置窗口模式全屏(WINDOWING_MODE_FULLSCREEN),如果启动的Activity不是ResolverActivity,设置启动Activty类型为ACTIVITY_TYPE_HOME,设置显示屏Id。
taskDisplayArea.mRemoteToken是RemoteToken类型对象,它继承自IWindowContainerToken.Stub,用来实现Binder通信。taskDisplayArea.mRemoteToken.toWindowContainerToken()则是WindowContainerToken(实现Parcelable接口,用来序列化)对象。这里也将它设置到options中。
再接下来就从taskDisplayArea中获取RootHomeTask。因为RootHomeTask的初始化在DisplayContent初始化中,DisplayContent初始化是在RootWindowContainer的setWindowManager(WindowManagerService wm)中,它又在ActivityManagerService的setWindowManager(WindowManagerService wm)中,所以现在它已经创建了。创建的过程参考 Android 窗口结构(二) 添加Home Task。
obtainStarter(intent, "startHomeActivity: " + reason)得到的是ActivityStarter对象,接着会向其设置intent对象,还会调用setCallingUid(0)、setActivityInfo(aInfo)、setActivityOptions(options.toBundle())分别设置调用Uid,启动的Activity信息、设置参数。最后调用ActivityStarter对象的execute()方法,执行。
tmpOutRecord是一个数组,是一个输出参数,所以上述方法调用完毕,之后,将它设置到mLastHomeActivityStartRecord中,作为最后一次启动的Home Activity。
如果rootHomeTask.mInResumeTopActivity为true,代表Home Task已经在执行恢复Activity的操作了,导致现在的Home Activity没有执行resume。所以这里接着调用mSupervisor.scheduleResumeTopActivities()继续执行Home Activity的resume。
下面进入ActivityStarter类中看一下它的execute()方法,如下:
java
/**
* Resolve necessary information according the request parameters provided earlier, and execute
* the request which begin the journey of starting an activity.
* @return The starter result.
*/
int execute() {
try {
// Refuse possible leaked file descriptors
if (mRequest.intent != null && mRequest.intent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
final LaunchingState launchingState;
synchronized (mService.mGlobalLock) {
final ActivityRecord caller = ActivityRecord.forTokenLocked(mRequest.resultTo);
final int callingUid = mRequest.realCallingUid == Request.DEFAULT_REAL_CALLING_UID
? Binder.getCallingUid() : mRequest.realCallingUid;
launchingState = mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(
mRequest.intent, caller, callingUid);
}
// If the caller hasn't already resolved the activity, we're willing
// to do so here. If the caller is already holding the WM lock here,
// and we need to check dynamic Uri permissions, then we're forced
// to assume those permissions are denied to avoid deadlocking.
if (mRequest.activityInfo == null) {
mRequest.resolveActivity(mSupervisor);
}
// Add checkpoint for this shutdown or reboot attempt, so we can record the original
// intent action and package name.
if (mRequest.intent != null) {
String intentAction = mRequest.intent.getAction();
String callingPackage = mRequest.callingPackage;
if (intentAction != null && callingPackage != null
&& (Intent.ACTION_REQUEST_SHUTDOWN.equals(intentAction)
|| Intent.ACTION_SHUTDOWN.equals(intentAction)
|| Intent.ACTION_REBOOT.equals(intentAction))) {
ShutdownCheckPoints.recordCheckPoint(intentAction, callingPackage, null);
}
}
int res;
synchronized (mService.mGlobalLock) {
final boolean globalConfigWillChange = mRequest.globalConfig != null
&& mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0;
final Task rootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
if (rootTask != null) {
rootTask.mConfigWillChange = globalConfigWillChange;
}
ProtoLog.v(WM_DEBUG_CONFIGURATION, "Starting activity when config "
+ "will change = %b", globalConfigWillChange);
final long origId = Binder.clearCallingIdentity();
res = resolveToHeavyWeightSwitcherIfNeeded();
if (res != START_SUCCESS) {
return res;
}
res = executeRequest(mRequest);
Binder.restoreCallingIdentity(origId);
if (globalConfigWillChange) {
// If the caller also wants to switch to a new configuration, do so now.
// This allows a clean switch, as we are waiting for the current activity
// to pause (so we will not destroy it), and have not yet started the
// next activity.
mService.mAmInternal.enforceCallingPermission(
android.Manifest.permission.CHANGE_CONFIGURATION,
"updateConfiguration()");
if (rootTask != null) {
rootTask.mConfigWillChange = false;
}
ProtoLog.v(WM_DEBUG_CONFIGURATION,
"Updating to new configuration after starting activity.");
mService.updateConfigurationLocked(mRequest.globalConfig, null, false);
}
// The original options may have additional info about metrics. The mOptions is not
// used here because it may be cleared in setTargetRootTaskIfNeeded.
final ActivityOptions originalOptions = mRequest.activityOptions != null
? mRequest.activityOptions.getOriginalOptions() : null;
// If the new record is the one that started, a new activity has created.
final boolean newActivityCreated = mStartActivity == mLastStartActivityRecord;
// Notify ActivityMetricsLogger that the activity has launched.
// ActivityMetricsLogger will then wait for the windows to be drawn and populate
// WaitResult.
mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res,
newActivityCreated, mLastStartActivityRecord, originalOptions);
if (mRequest.waitResult != null) {
mRequest.waitResult.result = res;
res = waitResultIfNeeded(mRequest.waitResult, mLastStartActivityRecord,
launchingState);
}
return getExternalResult(res);
}
} finally {
onExecutionComplete();
}
}
如果Intent中含有文件描述符,是会抛出IllegalArgumentException异常的。
mSupervisor.getActivityMetricsLogger()是ActivityMetricsLogger对象,这个类是用来监听Activity启动、过渡、可见性改变、窗口绘制进行回调的。它的notifyActivityLaunching()就是通知Activity启动了。在这里它会记录启动的时间。
如果mRequest.activityInfo == null,会需要解析它,这里前面已经设置它了,不需要解析它。
如果intentAction和调用的包名callingPackage不为null,并且是关机或者重启的请求,会添加检查点。
变量globalConfigWillChange是全局的配置是否发生了变化,是用mRequest.globalConfig(不能为null)和mService.getGlobalConfiguration()进行比较,如果不同即发生了变化。这里因为没有设置mRequest.globalConfig,所以它为null。globalConfigWillChange也为false。
mRootWindowContainer.getTopDisplayFocusedRootTask()里面目前也就只有一个Home Task。所以这里就得到它。
resolveToHeavyWeightSwitcherIfNeeded()是在必要的情况下(需要满足配置特色条件),在请求的进程uid和当前的重量级进程不同的情况下,需要跳转到HeavyWeightSwitcherActivity中去操作处理。目前这个暂时忽略。
executeRequest(mRequest)就是去执行启动Activity的操作。这个可以参考 Android Activity的启动器ActivityStarter入口。其中Home ActivityRecord添加到Task中,也是由它实现的。这里,它主要是由addOrReparentStartingActivity方法实现的。
下面globalConfigWillChange为false,所以不用更新配置。
mStartActivity、mLastStartActivityRecord都是在executeRequest(mRequest)中赋值的,只不过赋值的地方不同。mLastStartActivityRecord是在ActivityRecord对象刚创建的时候设置的,而mStartActivity是在启动Activity时设置的,所以它俩一致,代表Activity创建成功,所以newActivityCreated为true。
接下来就是调用ActivityMetricsLogger对象的notifyActivityLaunched方法,通知Activity已经启动完。
如果设置了mRequest.waitResult,则需要对它进行处理。并将它的处理结果返回给res。
getExternalResult(res)是在res为START_ABORTED时,也返回START_SUCCESS。
onExecutionComplete()主要是处理启动器类ActivityStarter对象的回收。