这周在看Android源码,感觉就像看到了汪洋大海一样,不知所措,于是就决定带着问题去查看Android源码,于是就产生了本篇博客,本篇只对主要流程进行分析,细枝末节的会忽略
Android源码启动模式分析
首先是Activity类,实现了context接口中的startActivity()方法
android->app->Activity.java
/*参数说明
intent:启动意图
options:启动附加项,具体可以去Android developer上查看,可以实现多种启动动画
requestCode:请求码,当请求码为负数时,请求码不起作用,因此可以看到当我们使用
startActivity时,会传入-1
*/
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null)
}
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
...
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
...
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
...
} else {
...
}
}
通过源码我们可以看到,无论是通过startActivity还是通过startActivityForResult,它走到的结果都是startActivityForResult中,随后通过实例调用Instrumentation类中的execStartActivity方法
android->app->Instrumentation.java
/*参数说明
who:who在英文中是谁的意思,因此我们很容易知道这个参数代表的是启动者的context
contextThread:启动者的context的主线程
token:token我们都知道,其实就是一个标识而已,不过需要注意的是这个参数可能为空
target:标识哪个fragment正在启动,并且接收result
intent:这个就不必介绍了
request:同上
*/
@UnsupportedAppUsage
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, String target,
Intent intent, int requestCode, Bundle options) {
...
try {
...
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getOpPackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), token, target,
requestCode, 0, null, options);
...
} catch (RemoteException e) {
...
}
return null;
}
这个没什么好说的,接下来我们看看ActivityTaskManager中的getService()方法,
/** @hide */
public static IActivityTaskManager getService() {
return IActivityTaskManagerSingleton.get();
}
@UnsupportedAppUsage(trackingBug = 129726065)
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
new Singleton<IActivityTaskManager>() {
@Override
protected IActivityTaskManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
return IActivityTaskManager.Stub.asInterface(b);
}
};
我们可以着重看一看这一部分代码,首先通过单例模式,获取IActivityTaskManager的一个实例,IActivityTaskManager则是通过Binder获取系统进程ActivityTaskManagerService类的代理,这一块不懂的可以看一看Android的IPC机制,也就是从这时候开始,我们从应用进程转到了系统进程,然后通过在Instrumentation类中的execStartActivity方法中,通过获取到的ATMS的代理来调用ATMS中的startActivity方法.,接着我们来看看ATMS中的startActivity方法
com->android->server->wm->ActivityTaskManagerService.java
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions) {
return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
@Override
public int startActivityAsUser(IApplicationThread caller, String callingPackage,
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions, int userId) {
return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
true /*validateIncomingUser*/);
}
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) {
...
// TODO: Switch to user app stacks here.
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setUserId(userId)
.execute();
}
ActivityStartController getActivityStartController() {
return mActivityStartController;
}
这个方法比较简单,就是一系列的重载,然后通过getActivityStartController()方法获取activitystartContrtller的实例,然后通过实例调用obstanStarter()方法,
com->android->server->wm->ActivityStartController
/**
* @return A starter to configure and execute starting an activity. It is valid until after
* {@link ActivityStarter#execute} is invoked. At that point, the starter should be
* considered invalid and no longer modified or used.
*/
ActivityStarter obtainStarter(Intent intent, String reason) {
return mFactory.obtain().setIntent(intent).setReason(reason);
}
这个方法比较简单,通过工厂模式获得ActivityStarter的一个实例,然后再使用建造者模式,通过这个实例,设置一系列参数,最后调用ActivityStarter方法,这个方法就是我们今天的主角,我们好好看一看这个类中有什么
/**
* Controller for interpreting how and then launching an activity.
*
* This class collects all the logic for determining how an intent and flags should be turned into
* an activity and associated task and root task.
*翻译成中文就是这个类是用来解释如何启动活动,然后启动活动的,这个类会收集用于确定
*意图和标志应如何转换的所有逻辑
*/
class ActivityStarter {
/*
* Request details provided through setter methods. Should be reset after {@link #execute()}
* to avoid unnecessarily retaining parameters. Note that the request is ignored when
* {@link #startResolvedActivity} is invoked directly.
*/
@VisibleForTesting
Request mRequest = new Request(); //上一步所有set的信息都保存在这里
/**
* 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 {
...
int res;
synchronized (mService.mGlobalLock) {
...
res = executeRequest(mRequest);
...
return getExternalResult(res);
}
} finally {
onExecutionComplete();
}
}
private int executeRequest(Request request) {
...
final ActivityRecord r = new ActivityRecord.Builder(mService)
.setCaller(callerApp)
.setLaunchedFromPid(callingPid)
.setLaunchedFromUid(callingUid)
.setLaunchedFromPackage(callingPackage)
.setLaunchedFromFeature(callingFeatureId)
.setIntent(intent)
.setResolvedType(resolvedType)
.setActivityInfo(aInfo)
.setConfiguration(mService.getGlobalConfiguration())
.setResultTo(resultRecord)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setComponentSpecified(request.componentSpecified)
.setRootVoiceInteraction(voiceSession != null)
.setActivityOptions(checkedOptions)
.setSourceRecord(sourceRecord)
.build();
mLastStartActivityRecord = r;
...
mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
request.voiceInteractor, startFlags, true /* doResume */, checkedOptions,
inTask, inTaskFragment, restrictedBgActivity, intentGrants);
...
return mLastStartActivityResult;
}
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
TaskFragment inTaskFragment, boolean restrictedBgActivity,
NeededUriGrants intentGrants) {
int result = START_CANCELED;
...
try {
...
result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, inTaskFragment, restrictedBgActivity,
intentGrants);
...
} finally {
...
}
...
return result;
}
/**
* 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.
*
* Note: This method should only be called from {@link #startActivityUnchecked}.
*/翻译就是这个方法时用来实现不同启动模式的
// TODO(b/152429287): Make it easier to exercise code paths through startActivityInner
@VisibleForTesting
int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
TaskFragment inTaskFragment, boolean restrictedBgActivity,
NeededUriGrants intentGrants) {
setInitialState(r, options, inTask, inTaskFragment, doResume, startFlags, sourceRecord,
voiceSession, voiceInteractor, restrictedBgActivity);
computeLaunchingTaskFlags();
computeSourceRootTask();
mIntent.setFlags(mLaunchFlags);
// Get top task at beginning because the order may be changed when reusing existing task.
final Task prevTopTask = mPreferredTaskDisplayArea.getFocusedRootTask();
final Task reusedTask = getReusableTask();
// If requested, freeze the task list
if (mOptions != null && mOptions.freezeRecentTasksReordering()
&& mSupervisor.mRecentTasks.isCallerRecents(r.launchedFromUid)
&& !mSupervisor.mRecentTasks.isFreezeTaskListReorderingSet()) {
mFrozeTaskList = true;
mSupervisor.mRecentTasks.setFreezeTaskListReordering();
}
// Compute if there is an existing task that should be used for.
final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
final boolean newTask = targetTask == null;
mTargetTask = targetTask;
computeLaunchParams(r, sourceRecord, targetTask);
// Check if starting activity on given task or on a new task is allowed.
int startResult = isAllowedToStart(r, newTask, targetTask);
if (startResult != START_SUCCESS) {
return startResult;
}
final ActivityRecord targetTaskTop = newTask
? null : targetTask.getTopNonFinishingActivity();
if (targetTaskTop != null) {
// Recycle the target task for this launch.
startResult = recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants);
if (startResult != START_SUCCESS) {
return startResult;
}
} else {
mAddingToTask = true;
}
// 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.
final Task topRootTask = mPreferredTaskDisplayArea.getFocusedRootTask();
if (topRootTask != null) {
startResult = deliverToCurrentTopIfNeeded(topRootTask, intentGrants);
if (startResult != START_SUCCESS) {
return startResult;
}
}
if (mTargetRootTask == null) {
mTargetRootTask = getLaunchRootTask(mStartActivity, mLaunchFlags, targetTask, mOptions);
}
if (newTask) {
final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.getTask() : null;
setNewTask(taskToAffiliate);
} else if (mAddingToTask) {
addOrReparentStartingActivity(targetTask, "adding to task");
}
if (!mAvoidMoveToFront && mDoResume) {
mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask);
if (!mTargetRootTask.isTopRootTaskInDisplayArea() && mService.mInternal.isDreaming()) {
// Launching underneath dream activity (fullscreen, always-on-top). Run the launch-
// -behind transition so the Activity gets created and starts in visible state.
mLaunchTaskBehind = true;
r.mLaunchTaskBehind = true;
}
}
mService.mUgmInternal.grantUriPermissionUncheckedFromIntent(intentGrants,
mStartActivity.getUriPermissionsLocked());
if (mStartActivity.resultTo != null && mStartActivity.resultTo.info != null) {
// we need to resolve resultTo to a uid as grantImplicitAccess deals explicitly in UIDs
final PackageManagerInternal pmInternal =
mService.getPackageManagerInternalLocked();
final int resultToUid = pmInternal.getPackageUid(
mStartActivity.resultTo.info.packageName, 0 /* flags */,
mStartActivity.mUserId);
pmInternal.grantImplicitAccess(mStartActivity.mUserId, mIntent,
UserHandle.getAppId(mStartActivity.info.applicationInfo.uid) /*recipient*/,
resultToUid /*visible*/, true /*direct*/);
}
final Task startedTask = mStartActivity.getTask();
if (newTask) {
EventLogTags.writeWmCreateTask(mStartActivity.mUserId, startedTask.mTaskId);
}
mStartActivity.logStartActivity(EventLogTags.WM_CREATE_ACTIVITY, startedTask);
mStartActivity.getTaskFragment().clearLastPausedActivity();
mRootWindowContainer.startPowerModeLaunchIfNeeded(
false /* forceSend */, mStartActivity);
final boolean isTaskSwitch = startedTask != prevTopTask && !startedTask.isEmbedded();
mTargetRootTask.startActivityLocked(mStartActivity,
topRootTask != null ? topRootTask.getTopNonFinishingActivity() : null, newTask,
isTaskSwitch, mOptions, sourceRecord);
if (mDoResume) {
final ActivityRecord topTaskActivity = startedTask.topRunningActivityLocked();
if (!mTargetRootTask.isTopActivityFocusable()
|| (topTaskActivity != null && topTaskActivity.isTaskOverlay()
&& mStartActivity != topTaskActivity)) {
// If the activity is not focusable, we can't resume it, but still would like to
// make sure it becomes visible as it starts (this will also trigger entry
// animation). An example of this are PIP activities.
// Also, we don't want to resume activities in a task that currently has an overlay
// as the starting activity just needs to be in the visible paused state until the
// over is removed.
// Passing {@code null} as the start parameter ensures all activities are made
// visible.
mTargetRootTask.ensureActivitiesVisible(null /* starting */,
0 /* configChanges */, !PRESERVE_WINDOWS);
// Go ahead and tell window manager to execute app transition for this activity
// since the app transition will not be triggered through the resume channel.
mTargetRootTask.mDisplayContent.executeAppTransition();
} else {
// If the target root-task was not previously focusable (previous top running
// activity on that root-task was not visible) then any prior calls to move the
// root-task to the will not update the focused root-task. If starting the new
// activity now allows the task root-task to be focusable, then ensure that we
// now update the focused root-task accordingly.
if (mTargetRootTask.isTopActivityFocusable()
&& !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) {
mTargetRootTask.moveToFront("startActivityInner");
}
mRootWindowContainer.resumeFocusedTasksTopActivities(
mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
}
}
mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetRootTask);
// Update the recent tasks list immediately when the activity starts
mSupervisor.mRecentTasks.add(startedTask);
mSupervisor.handleNonResizableTaskIfNeeded(startedTask,
mPreferredWindowingMode, mPreferredTaskDisplayArea, mTargetRootTask);
return START_SUCCESS;
}
}
这里其实就是一系列的链式调用,最终我们来看看computeLaunchTaskFlags()这个方法,
private void computeLaunchingTaskFlags() {
// 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.
//如果呼叫者不是来自另一个活动,而是给了我们一个明确的任务
//tips:在系统进程中,activity会被转化为ActivityRecord
//他们希望我们启动新的活动,然后让我们看看如何做到这一点。
//参数解释:mSourceRecord 目标的ActivityRecord
// mInTask: 指定Task
if (mSourceRecord == null && mInTask != null && mInTask.getRootTask() != null) {
final Intent baseIntent = mInTask.getBaseIntent();
final ActivityRecord root = mInTask.getRootActivity();
if (baseIntent == null) {
ActivityOptions.abort(mOptions);
throw new IllegalArgumentException("Launching into task without base intent: "
+ mInTask);
}
// If this task is empty, then we are adding the first activity -- it
// determines the root, and must be launching as a NEW_TASK.
//如果此任务为空,那么我们将添加第一个活动——
//并且必须作为NEW_TASK启动。
//如果启动模式为SINGLE_INSTANCE 或SINGLE_TASK
if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
if (!baseIntent.getComponent().equals(mStartActivity.intent.getComponent())) {
ActivityOptions.abort(mOptions);
throw new IllegalArgumentException("Trying to launch singleInstance/Task "
+ mStartActivity + " into different task " + mInTask);
}
if (root != null) {
ActivityOptions.abort(mOptions);
throw new IllegalArgumentException("Caller with mInTask " + mInTask
+ " has root " + root + " but target is singleInstance/Task");
}
}
// If task is empty, then adopt the interesting intent launch flags in to the
// activity being started.
//如果task为空,则采用有用的launch flags 去启动activity
//如果根activity为null
if (root == null) {
final int flagsOfInterest = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK
| FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS;
mLaunchFlags = (mLaunchFlags & ~flagsOfInterest)
| (baseIntent.getFlags() & flagsOfInterest);
mIntent.setFlags(mLaunchFlags);
mInTask.setIntent(mStartActivity);
mAddingToTask = true;
// If the task is not empty and the caller is asking to start it as the root of
// a new task, then we don't actually want to start this on the task. We will
// bring the task to the front, and possibly give it a new intent.
//判断是否为FLAG_ACTIVITY_NEW_TASK
} else if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
mAddingToTask = false;
} else {
mAddingToTask = true;
}
mReuseTask = mInTask;
} else {
mInTask = null;
// Launch ResolverActivity in the source task, so that it stays in the task bounds
// when in freeform workspace.
// Also put noDisplay activities in the source task. These by itself can be placed
// in any task/root-task, however it could launch other activities like
// ResolverActivity, and we want those to stay in the original task.
if ((mStartActivity.isResolverOrDelegateActivity() || mStartActivity.noDisplay)
&& mSourceRecord != null && mSourceRecord.inFreeformWindowingMode()) {
mAddingToTask = true;
}
}
//如果没有指定TASK
if (mInTask == null) {
//如果目标ActivityRecord为空
if (mSourceRecord == null) {
// This activity is not being started from another... in this
// case we -always- start a new task.
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {
Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
"Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
//如果目标activityRecord启动模式为Launch_single_instance
} else if (mSourceRecord.launchMode == 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.
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
} else if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
// The activity being started is a single instance... it always
// gets launched into its own task.
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
}
}
private void computeSourceRootTask() {
if (mSourceRecord == null) {
mSourceRootTask = null;
return;
}
if (!mSourceRecord.finishing) {
mSourceRootTask = mSourceRecord.getRootTask();
return;
}
// If the source is finishing, we can't further count it as our source. This is because the
// task it is associated with may now be empty and on its way out, so we don't want to
// blindly throw it in to that task. Instead we will take the NEW_TASK flow and try to find
// a task for it. But save the task information so it can be used when creating the new task.
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
Slog.w(TAG, "startActivity called from finishing " + mSourceRecord
+ "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
mNewTaskInfo = mSourceRecord.info;
// It is not guaranteed that the source record will have a task associated with it. For,
// example, if this method is being called for processing a pending activity launch, it
// is possible that the activity has been removed from the task after the launch was
// enqueued.
final Task sourceTask = mSourceRecord.getTask();
mNewTaskIntent = sourceTask != null ? sourceTask.intent : null;
}
mSourceRecord = null;
mSourceRootTask = null;
}
这个方法是本文的重点,难点是弄清参数的意思,基本上就能看懂