Activity启动研究
前言
在工作项目中,需要研究这一部分的源码。在项目完成后,对这个部分做一个总结。
流程图

在安卓中,我们一般使用intent来启动Activity。比如startActivity(new intent)这样的方式。上层我们使用的时候比较简单,但是,仔细研究,向下挖掘,就会复杂一点。流程图如上。我们重点研究ActivityStarter部分。因为核心内容就在Starter中的execute部分。
ActivityStarter研究
java
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
mAmInternal.addCreatorToken(intent, callingPackage);
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final SafeActivityOptions opts = SafeActivityOptions.fromBundle(
bOptions, callingPid, callingUid);
assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityAsUser");
if (isSdkSandboxActivityIntent(mContext, intent)) {
SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
SdkSandboxManagerLocal.class);
sdkSandboxManagerLocal.enforceAllowedToHostSandboxedActivity(
intent, callingUid, callingPackage
);
}
if (Process.isSdkSandboxUid(callingUid)) {
SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
SdkSandboxManagerLocal.class);
if (sdkSandboxManagerLocal == null) {
throw new IllegalStateException("SdkSandboxManagerLocal not found when starting"
+ " an activity from an SDK sandbox uid.");
}
sdkSandboxManagerLocal.enforceAllowedToStartActivity(intent);
}
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
callingPid, callingUid, "startActivityAsUser");
// TODO: Switch to user app stacks here.
// 这里获得ActivityStarter开始启动Activity
// 很明显,这里设置了许多参数,在execute都能看到这些参数的用途
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(opts)
.setUserId(userId)
.execute();
}
看到入口,现在开始研究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() {
// Required for logging ContentOrFileUriEventReported in the finally block.
String callerActivityName = null;
ActivityRecord launchingRecord = null;
try {
// 这里在做执行前的一些准备工作,挖下去,其实就是在设置一个状态值
onExecutionStarted();
/*
.......省略
*/
// 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) {
// 1、这里很重要,这里就开始处理我们传递过来的intent参数了
mRequest.resolveActivity(mSupervisor);
}
/*
....省略....
*/
int res = START_CANCELED;
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();
try {
res = resolveToHeavyWeightSwitcherIfNeeded();
if (res != START_SUCCESS) {
return res;
}
// 2.这里是开始执行request,上面启动失败,就会返回。
res = executeRequest(mRequest);
} finally {
Binder.restoreCallingIdentity(origId);
mRequest.logMessage.append(" result code=").append(res);
Slog.i(TAG, mRequest.logMessage.toString());
mRequest.logMessage.setLength(0);
}
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;
// Only track the launch time of activity that will be resumed.
if (mDoResume || (isStartResultSuccessful(res)
&& mLastStartActivityRecord.getTask().isVisibleRequested())) {
launchingRecord = mLastStartActivityRecord;
}
// If the new record is the one that started, a new activity has created.
final boolean newActivityCreated = mStartActivity == launchingRecord;
// 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, launchingRecord, originalOptions);
if (mRequest.waitResult != null) {
mRequest.waitResult.result = res;
res = waitResultIfNeeded(mRequest.waitResult, mLastStartActivityRecord,
launchingState);
}
// 这里返回启动的结果。如果是SUCCESS,就说明启动成功了
return getExternalResult(res);
}
} finally {
/*
.....省略.....
*/
onExecutionComplete();
}
}
1.resolveActivity
java
/**
* Resolve activity from the given intent for this launch.
*/
void resolveActivity(ActivityTaskSupervisor supervisor) {
/*
这里重点看这个resolveIntent
调用到ResolveIntentHelper.java中的resolveIntentInternal函数,在该函数中,会
使用PackageManagerService来检索对应用户下能够处理这个intent的resolve,这里先不介绍。
*/
resolveInfo = supervisor.resolveIntent(intent, resolvedType, userId,
0 /* matchFlags */,
computeResolveFilterUid(callingUid, realCallingUid, filterCallingUid),
realCallingPid);
if (resolveInfo == null) {
// Special case for profiles: If attempting to launch non-crypto aware app in a
// locked profile or launch an app in a profile that is stopped by quiet mode from
// an unlocked parent, allow it to resolve as user will be sent via confirm
// credentials to unlock the profile.
resolveInfo = resolveIntentForLockedOrStoppedProfiles(supervisor);
}
// Collect information about the target of the Intent.
// 用上面获得的resolveinfo来获取对应的Activity,其实返回就是resolvceinfo中的activityInfo
activityInfo = supervisor.resolveActivity(intent, resolveInfo, startFlags,
profilerInfo);
/*
....省略....
*/
}
2.executeRequest
java
/**
* Executing activity start request and starts the journey of starting an activity. Here
* begins with performing several preliminary checks. The normally activity launch flow will
* go through {@link #startActivityUnchecked} to {@link #startActivityInner}.
*/
private int executeRequest(Request request) {
/*
....省略....
*/
final int userId = aInfo != null && aInfo.applicationInfo != null
? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
final int launchMode = aInfo != null ? aInfo.launchMode : 0;
if (err == ActivityManager.START_SUCCESS) {
/*
以后想要排查activity启动的问题,就可以debug这里这个字段,看看是不是走在这里
*/
request.logMessage.append("START u").append(userId).append(" {")
.append(intent.toShortString(true, true, true, false))
.append("} with ").append(launchModeToString(launchMode))
.append(" from uid ").append(callingUid);
if (callingUid != realCallingUid
&& realCallingUid != Request.DEFAULT_REAL_CALLING_UID) {
request.logMessage.append(" (realCallingUid=").append(realCallingUid).append(")");
}
}
/*
省略
*/
// Only do the create here since startActivityInner can abort. If it doesn't abort,
// the requestStart will be sent in handleStartRequest.
final Transition newTransition = r.mTransitionController.isShellTransitionsEnabled()
? r.mTransitionController.createAndStartCollecting(TRANSIT_OPEN) : null;
// Because startActivity must run immediately, it can get combined with another
// transition meaning it is no-longer independent. This is NOT desirable, but is the
// only option for the time being.
final boolean isIndependent = newTransition != null;
final Transition transition = isIndependent ? newTransition
: mService.getTransitionController().getCollectingTransition();
// 这个函数,内部调用startActivityInner函数
/*官方对startActivityInner的解释
* Start an activity and determine if the activity should be adding to the top of an existing
* task or delivered new intent to an existing activity. Also manipulating the activity task
* onto requested or valid root-task/display.
**/
mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
request.voiceInteractor, startFlags, checkedOptions,
inTask, inTaskFragment, balVerdict, intentGrants, realCallingUid, transition,
isIndependent);
if (request.outActivity != null) {
request.outActivity[0] = mLastStartActivityRecord;
}
return mLastStartActivityResult;
}
写到这里,基本上这个流程就结束了。这些重要函数的内部细节还有很多需要研究的地方。AMS是一个很大服务。梳理好这个流程至少能够让我们思路清晰点。