在学习Android app开发的时候,最先要学习的就是关于Activity的启动方式,Task和Back Stack的知识。因此在学习framework如何管理启动的activity之前,有必要回顾一下。
Google官方文档里有这么一篇文档《Understand Tasks and Back Stack》https://developer.android.com/guide/components/activities/tasks-and-back-stack
在这篇文章的开头就给task和Back Stack下了定义:
For example, an email app might have one activity to show a list of new messages. When the user selects a message, a new activity opens to view that message. This new activity is added to the back stack. If the user presses the Back button, that new activity is finished and popped off the stack.
Figure 1. A representation of how each new activity in a task adds an item to the back stack. When the user presses the Back button, the current activity is destroyed and the previous activity resumes.
When the current activity starts another, the new activity is pushed on the top of the stack and takes focus. The previous activity remains in the stack, but is stopped. When an activity stops, the system retains the current state of its user interface. When the user presses the Back button, the current activity is popped from the top of the stack (the activity is destroyed) and the previous activity resumes (the previous state of its UI is restored). Activities in the stack are never rearranged, only pushed and popped from the stack—pushed onto the stack when started by the current activity and popped off when the user leaves it using the Back button. As such, the back stack operates as a “last in, first out” object structure. Figure 1 visualizes this behavior with a timeline showing the progress between activities along with the current back stack at each point in time.
A task is a cohesive unit that can move to the “background” when users begin a new task or go to the Home screen, via the Home button. While in the background, all the activities in the task are stopped, but the back stack for the task remains intact—the task has simply lost focus while another task takes place, as shown in figure 2. A task can then return to the “foreground” so users can pick up where they left off. Suppose, for example, that the current task (Task A) has three activities in its stack—two under the current activity. The user presses the Home button, then starts a new app from the app launcher. When the Home screen appears, Task A goes into the background. When the new app starts, the system starts a task for that app (Task B) with its own stack of activities. After interacting with that app, the user returns Home again and selects the app that originally started Task A. Now, Task A comes to the foreground—all three activities in its stack are intact and the activity at the top of the stack resumes. At this point, the user can also switch back to Task B by going Home and selecting the app icon that started that task (or by selecting the app’s task from the Recents screen).
Figure 2. Two tasks: Task B receives user interaction in the foreground, while Task A is in the background, waiting to be resumed.
英文task的意思是“任务,工作”。所以,可以从用户使用场景来理解Google设计task的目的:
例如:接着上面说过的那个例子:用户打开email应用程序查看电子邮件。当查阅某一封邮件详情时,会启动一个新的activity来显示。
这时候用户对当前字体大小不满意。点击email这个应用设置进入设置页,email的设置直接启动了系统Settings的字体设置页面。
这个时候有三个activity:
这三个页面是一件事情或一份工作,用来完成用户的查看邮件和设置字符的任务。所以,当用户点back 键时,回退到email详情页是最合理的。
当用户想干中别的事情,比如听音乐,这又会是一个新的task任务,关于听音乐应用的页面都会在这个task里。
这时候就有两个task:
当用户再次点击email应用程序时,查看邮件task里的所有activity就会整体切到前台。听音乐task里的所有activity就会整体切到后台。
由于Activity的启动方式有很多,增加了分析问题的复杂度,因此我们只考虑启动方式为standard和 Intent flags为FLAG_ACTIVITY_NEW_TASK的情况。
It is a the default mode. The system creates a new instance of the activity in the task from which it was started and routes the intent to it. The activity can be instantiated multiple times, each instance can belong to different tasks, and one task can have multiple instances.
上面Figure 1 就展示的standard的启动方式。
另外还要注意standard的启动方式在一个task里一个Activity可以被实例化多次。如下图:
Figure 3. A single activity is instantiated multiple times.
When starting an activity, you can modify the default association of an activity to its task by including flags in the intent that you deliver to startActivity().
FLAG_ACTIVITY_NEW_TASK:Start the activity in a new task. If a task is already running for the activity you are now starting, that task is brought to the foreground with its last state restored and the activity receives the new intent in onNewIntent().
我写了一个demo,程序里实现了三个Activity:
启动流程是:
这个流程中framework是怎么设计实现的呢?我们先看看adb dumpsys activity的信息:
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
Stack #29: type=standard mode=fullscreen
isSleeping=false
mBounds=Rect(0, 0 - 0, 0)
mResumedActivity: ActivityRecord{b9474dc u0 com.android.settings/.Settings$NetworkDashboardActivity t29}
* Task{7f8f9e5 #29 visible=true type=standard mode=fullscreen translucent=false A=1000:com.android.settings U=0 StackId=29 sz=1}
mBounds=Rect(0, 0 - 0, 0)
mMinWidth=-1 mMinHeight=-1
userId=0 effectiveUid=1000 mCallingUid=u0a201 mUserSetupComplete=true mCallingPackage=com.tblenovo.wufl2.startactivitydemo mCallingFeatureId=null
affinity=1000:com.android.settings
intent={act=android.settings.WIRELESS_SETTINGS flg=0x10000000 cmp=com.android.settings/.Settings$NetworkDashboardActivity}
mActivityComponent=com.android.settings/.Settings$NetworkDashboardActivity
autoRemoveRecents=false isPersistable=true activityType=1
rootWasReset=false mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
Activities=[ActivityRecord{b9474dc u0 com.android.settings/.Settings$NetworkDashboardActivity t29}]
askedCompatMode=false inRecents=true isAvailable=true
mRootProcess=ProcessRecord{66202c8 23153:com.android.settings/1000}
taskId=29 stackId=29
mHasBeenVisible=true
mResizeMode=RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION mSupportsPictureInPicture=false isResizeable=true
lastActiveTime=102874561 (inactive for 0s)
Hist #0: ActivityRecord{b9474dc u0 com.android.settings/.Settings$NetworkDashboardActivity t29}
Intent { act=android.settings.WIRELESS_SETTINGS flg=0x10000000 cmp=com.android.settings/.Settings$NetworkDashboardActivity }
ProcessRecord{66202c8 23153:com.android.settings/1000}
Stack #28: type=standard mode=fullscreen
isSleeping=false
mBounds=Rect(0, 0 - 0, 0)
* Task{19ea3e1 #28 visible=false type=standard mode=fullscreen translucent=true A=10201:com.tblenovo.wufl2.startactivitydemo U=0 StackId=28 sz=4}
mBounds=Rect(0, 0 - 0, 0)
mMinWidth=-1 mMinHeight=-1
userId=0 effectiveUid=u0a201 mCallingUid=u0a67 mUserSetupComplete=true mCallingPackage=com.tblenovo.launcher mCallingFeatureId=null
affinity=10201:com.tblenovo.wufl2.startactivitydemo
intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.tblenovo.wufl2.startactivitydemo/.MainActivity}
mActivityComponent=com.tblenovo.wufl2.startactivitydemo/.MainActivity
autoRemoveRecents=false isPersistable=true activityType=1
rootWasReset=true mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
Activities=[ActivityRecord{fcb430 u0 com.tblenovo.wufl2.startactivitydemo/.MainActivity t28}, ActivityRecord{46b0e08 u0 com.tblenovo.wufl2.startactivitydemo/.ActivityA t28}, ActivityRecord{71d295a u0 com.tblenovo.wufl2.startactivitydemo/.ActivityB t28}, ActivityRecord{1dcb3ae u0 com.tblenovo.wufl2.startactivitydemo/.ActivityA t28}]
askedCompatMode=false inRecents=true isAvailable=true
mRootProcess=ProcessRecord{c21db8c 23079:com.tblenovo.wufl2.startactivitydemo/u0a201}
taskId=28 stackId=28
mHasBeenVisible=true
mResizeMode=RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION mSupportsPictureInPicture=false isResizeable=true
lastActiveTime=102813374 (inactive for 61s)
Hist #3: ActivityRecord{1dcb3ae u0 com.tblenovo.wufl2.startactivitydemo/.ActivityA t28}
Intent { cmp=com.tblenovo.wufl2.startactivitydemo/.ActivityA }
Hist #2: ActivityRecord{71d295a u0 com.tblenovo.wufl2.startactivitydemo/.ActivityB t28}
Intent { cmp=com.tblenovo.wufl2.startactivitydemo/.ActivityB }
ProcessRecord{c21db8c 23079:com.tblenovo.wufl2.startactivitydemo/u0a201}
Hist #1: ActivityRecord{46b0e08 u0 com.tblenovo.wufl2.startactivitydemo/.ActivityA t28}
Intent { cmp=com.tblenovo.wufl2.startactivitydemo/.ActivityA }
ProcessRecord{c21db8c 23079:com.tblenovo.wufl2.startactivitydemo/u0a201}
Hist #0: ActivityRecord{fcb430 u0 com.tblenovo.wufl2.startactivitydemo/.MainActivity t28}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.tblenovo.wufl2.startactivitydemo/.MainActivity bnds=[12,690][368,979] }
ProcessRecord{c21db8c 23079:com.tblenovo.wufl2.startactivitydemo/u0a201}
从上面的adb dumpsys activity信息中可以解析出下面几个关键信息:
Activities=[
ActivityRecord{b9474dc u0 com.android.settings/.Settings$NetworkDashboardActivity t29}]
Activities=[
ActivityRecord{fcb430 u0 com.tblenovo.wufl2.startactivitydemo/.MainActivity t28},
ActivityRecord{46b0e08 u0 com.tblenovo.wufl2.startactivitydemo/.ActivityA t28},
ActivityRecord{71d295a u0 com.tblenovo.wufl2.startactivitydemo/.ActivityB t28},
ActivityRecord{1dcb3ae u0 com.tblenovo.wufl2.startactivitydemo/.ActivityA t28}]
ProcessRecord{c21db8c 23079:com.tblenovo.wufl2.startactivitydemo/u0a201}
ProcessRecord{66202c8 23153:com.android.settings/1000}
下面我们就看一看framework是怎么让上面的demo工作起来的。
####3.1.1 单编模块
如果要分析framework的相关源码,最好的方法就是加log。能单独编译framework模块,然后adb push到真机上是最快速的。
调度ActivityManagerService相关的功能,通常会修改下面两个目录:
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,new RuntimeException(“here”).fillInStackTrace());
startActivity(new Intent(ActivityA.this,ActivityB.class));的流程从Activity.jav开始。
Activity.java
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback,
AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
}
...
}
}
从上面的代码可以看出,流程从Activity.java的startActivityForResult()方法调到了Instrumentation.java的execStartActivity()方法。
Instrumentation.java
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
try {
intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getBasePackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), token,
target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
从上面的代码可以看出,流程从Instrumentation.java的execStartActivity()调到了ActivityTaskManagerService.java的startActivity()方法。
ActivityTaskManagerService.java
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) {
assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityAsUser");
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
// 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();
}
在这个流程中,要注意Activity.java的mToken,传到Instrumentation.java的token,然后到了ActivityTaskManagerService.java传给了resultTo。
以上面的ActivityA启动ActivityB(startActivity(new Intent(ActivityA.this,ActivityB.class)); )为例,通过加log发现这个resultTo就是
resultTo=Token{fa0eb6d ActivityRecord
{28da3a2 u0 com.tblenovo.wufl2.startactivitydemo/.ActivityA t102}}。
也就是说在ActivityA启动ActivityB这种情况下,token是ActivityA它自己。从resultTo的命名就能猜到用于返回结果。
上面流程相关类有
咱们来想想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 stack.
*/
mRequest数据的准备:
1.在这个流程中set了很多参数:
ActivityStarter.java
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();
2.有execute()方法:
ActivityStarter.java
int execute() {
// 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);//code snippet 1
}
}
ActivityStarter.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) {
if (err == ActivityManager.START_SUCCESS) {
Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
+ "} from uid " + callingUid);
}
}
ActivityStarter.java的execute()里有executeRequest,这时开始执行request请求。
这块就是adb logcat里的那行ActivityTaskManager: START u0 {cmp=com.tblenovo.wufl2.startactivitydemo/.ActivityA} from uid 10201的执行的地方。
再接着看:
/**
* 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) {
ActivityInfo aInfo = request.activityInfo;//code snippet 2
ResolveInfo rInfo = request.resolveInfo;
String resultWho = request.resultWho;//code snippet 3
Task inTask = request.inTask;
ActivityRecord sourceRecord = null;//code snippet 4
ActivityRecord resultRecord = null;
//code snippet 5
if (resultTo != null) {
sourceRecord = mRootWindowContainer.isInAnyStack(resultTo);
if (DEBUG_RESULTS) {
Slog.v(TAG_RESULTS, "Will send result to " + resultTo + " " + sourceRecord);
}
if (sourceRecord != null) {
if (requestCode >= 0 && !sourceRecord.finishing) {
resultRecord = sourceRecord;
}
}
}
//code snippet 6
final ActivityRecord r = new ActivityRecord(mService,callerApp, callingPid, callingUid,
callingPackage, callingFeatureId, intent, resolvedType, aInfo,
mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode,
request.componentSpecified, voiceSession != null, mSupervisor, checkedOptions,
sourceRecord);
//code snippet 7
mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,
restrictedBgActivity, intentGrants);
}
从分析上面的executeRequest()方法可以知道,ActivityStarter类的设计的作用还有:
接着code snippet 7分析。
/**
* Start an activity while most of preliminary checks has been done and caller has been
* confirmed that holds necessary permissions to do so.
* Here also ensures that the starting activity is removed if the start wasn't successful.
*/
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
boolean restrictedBgActivity, NeededUriGrants intentGrants) {
int result = START_CANCELED;
final ActivityStack startedActivityStack;
try {
mService.deferWindowLayout();
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
//code snippet 8
result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
startedActivityStack = handleStartResult(r, result);
mService.continueWindowLayout();
}
postStartActivityProcessing(r, result, startedActivityStack);
return result;
}
startActivityUnchecked()方法比较简单,直接看code snippet8 调了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 stack/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,
boolean restrictedBgActivity, NeededUriGrants intentGrants) {
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor, restrictedBgActivity);
computeLaunchingTaskFlags();
computeSourceStack();//code snippet 9
mIntent.setFlags(mLaunchFlags);
final Task reusedTask = getReusableTask();//code snippet 10
}
着重看一下code snippet 9和code snippet 10的作用:
在code snippet 9中computeSourceStack()方法,初始化了mSourceStack,它是一个ActivityTask。
private void computeSourceStack() {
if (mSourceRecord == null) {
mSourceStack = null;
return;
}
if (!mSourceRecord.finishing) {//code snippet 11
mSourceStack = 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;
mSourceStack = null;
}
以ActivitA启动ActivityB为例,逻辑在code snippet 11就return了。说明当前ActivityB的source Task就是sourceRecord的task,即ActivityA所在的task。
以ActivitA启动ActivityB为例(startActivity(new Intent(ActivityA.this,ActivityB.class));),通过加log,getReusableTask()返回值是null. 即reusedTask为null。
在startActivityInner()方法继续向下分析,会看到computeTargetTask()和computeLaunchParams两个方法。
startActivityInner():
// Compute if there is an existing task that should be used for.
final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();//code snippet 12
final boolean newTask = targetTask == null;
mTargetTask = targetTask;
computeLaunchParams(r, sourceRecord, targetTask);//code snippet 13
由于reusedTask为null(以ActivitA启动ActivityB为例),下面先看一下code snippet 12 computeTargetTask():
private Task computeTargetTask() {
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
// A new task should be created instead of using existing one.
return null;
} else if (mSourceRecord != null) {//code snippet 13
return mSourceRecord.getTask();
} else if (mInTask != null) {
return mInTask;
} else {
final ActivityStack stack = getLaunchStack(mStartActivity, mLaunchFlags,
null /* task */, mOptions);
final ActivityRecord top = stack.getTopNonFinishingActivity();
if (top != null) {
return top.getTask();
} else {
// Remove the stack if no activity in the stack.
stack.removeIfPossible();
}
}
return null;
}
以ActivitA启动ActivityB为例,resultTo不为null,mSourceRecord不为Null,因此会走到code snippet 13的逻辑,即return sourceRecord的task,也就是说返回ActivitA的task. 即targetTask为ActivitA的task。
确定被启动Activity的Task
startActivityInner()方法的code snippet 13处调用了computeLaunchParams()
private void computeLaunchParams(ActivityRecord r, ActivityRecord sourceRecord,
Task targetTask) {
final ActivityStack sourceStack = mSourceStack != null ? mSourceStack
: mRootWindowContainer.getTopDisplayFocusedStack();
if (sourceStack != null && sourceStack.inSplitScreenWindowingMode()
&& (mOptions == null
|| mOptions.getLaunchWindowingMode() == WINDOWING_MODE_UNDEFINED)) {
int windowingMode =
targetTask != null ? targetTask.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
if (sourceStack.inSplitScreenPrimaryWindowingMode()) {
windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
} else if (sourceStack.inSplitScreenSecondaryWindowingMode()) {
windowingMode = WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
}
}
if (mOptions == null) {
mOptions = ActivityOptions.makeBasic();
}
mOptions.setLaunchWindowingMode(windowingMode);
}
//code snippet 14
mSupervisor.getLaunchParamsController().calculate(targetTask, r.info.windowLayout, r,
sourceRecord, mOptions, PHASE_BOUNDS, mLaunchParams);
mPreferredTaskDisplayArea = mLaunchParams.hasPreferredTaskDisplayArea()
? mLaunchParams.mPreferredTaskDisplayArea
: mRootWindowContainer.getDefaultTaskDisplayArea();
mPreferredWindowingMode = mLaunchParams.mWindowingMode;//code snippet 14
}
从方法名computeLaunchParams就能算到这是初始化启动的参数,从方法的内容看主要是在初始化mPreferredWindowingMode,即WindowMode。以ActivitA启动ActivityB为例,WindowMode等于0,WINDOWING_MODE_UNDEFINED。
看一下windowmode的定义,在WindowConfiguration.java里
/**
* Class that contains windowing configuration/state for other objects that contain windows directly
* or indirectly. E.g. Activities, Task, Displays, ...
* The test class is {@link com.android.server.wm.WindowConfigurationTests} which must be kept
* up-to-date and ran anytime changes are made to this class.
* @hide
*/
@TestApi
public class WindowConfiguration implements Parcelable, Comparable {
/** Windowing mode is currently not defined. */
public static final int WINDOWING_MODE_UNDEFINED = 0;
/** Occupies the full area of the screen or the parent container. */
public static final int WINDOWING_MODE_FULLSCREEN = 1;
/** Always on-top (always visible). of other siblings in its parent container. */
public static final int WINDOWING_MODE_PINNED = 2;
/** The primary container driving the screen to be in split-screen mode. */
// TODO: Remove once split-screen is migrated to wm-shell.
public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3;
/**
* The containers adjacent to the {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} container in
* split-screen mode.
* NOTE: Containers launched with the windowing mode with APIs like
* {@link ActivityOptions#setLaunchWindowingMode(int)} will be launched in
* {@link #WINDOWING_MODE_FULLSCREEN} if the display isn't currently in split-screen windowing
* mode
* @see #WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY
*/
// TODO: Remove once split-screen is migrated to wm-shell.
public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4;
/**
* Alias for {@link #WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} that makes it clear that the usage
* points for APIs like {@link ActivityOptions#setLaunchWindowingMode(int)} that the container
* will launch into fullscreen or split-screen secondary depending on if the device is currently
* in fullscreen mode or split-screen mode.
*/
// TODO: Remove once split-screen is migrated to wm-shell.
public static final int WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY =
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
/** Can be freely resized within its parent container. */
// TODO: Remove once freeform is migrated to wm-shell.
public static final int WINDOWING_MODE_FREEFORM = 5;
/** Generic multi-window with no presentation attribution from the window manager. */
public static final int WINDOWING_MODE_MULTI_WINDOW = 6;
确定被启动Activity的window mode.
接着上面的逻辑,继续向下看:
startActivityInner():
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;
}
从recycleTask方法的注释学到了什么?
recycleTask():
/**
* Prepare the target task to be reused for this launch, which including:
* - Position the target task on valid stack on preferred display.
* - Comply to the specified activity launch flags
* - Determine whether need to add a new activity on top or just brought the task to front.
*/
以ActivitA启动ActivityB为例(startActivity(new Intent(ActivityA.this,ActivityB.class));),recycleTask()的流程:
recycleTask():
int recycleTask(Task targetTask, ActivityRecord targetTaskTop, Task reusedTask,
NeededUriGrants intentGrants) {
// Should not recycle task which is from a different user, just adding the starting
// activity to the task.
if (targetTask.mUserId != mStartActivity.mUserId) {
mTargetStack = targetTask.getStack();
mAddingToTask = true;
return START_SUCCESS;
}
...
/**
* Figure out which task and activity to bring to front when we have found an existing matching
* activity record in history. May also clear the task if needed.
* @param intentActivity Existing matching activity.
* @return {@link ActivityRecord} brought to front.
*/
setTargetStackIfNeeded(targetTaskTop);//code snippet 15
...
if (mAddingToTask) {
return START_SUCCESS;//code snippet 16
}
确定被启动Activity的targetStack, targetStack是一个ActivityStack.
以ActivitA启动ActivityB为例(startActivity(new Intent(ActivityA.this,ActivityB.class));),
startActivityInner():
if (newTask) {
final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.getTask() : null;
setNewTask(taskToAffiliate);
if (mService.getLockTaskController().isLockTaskModeViolation(
mStartActivity.getTask())) {
Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
} else if (mAddingToTask) {
addOrReparentStartingActivity(targetTask, "adding to task");
}
因为newTask为false,mAddingToTask为true,因此逻辑会走到addOrReparentStartingActivity()方法里。
addOrReparentStartingActivity():
private void addOrReparentStartingActivity(Task parent, String reason) {
if (mStartActivity.getTask() == null || mStartActivity.getTask() == parent) {//code snippet 17
parent.addChild(mStartActivity);
} else {
mStartActivity.reparent(parent, parent.getChildCount() /* top */, reason);
}
}
由于mStartActivity(ActivityB)的task等于targetTask(ActivityA所在的task),因此在code snippet 17就把mStartActivity加到了targetTask里了。
把要启动的activity加到属于自己的task里。
流程来到了下面的代码段:
startActivityInner():
if (!mAvoidMoveToFront && mDoResume) {
mTargetStack.getStack().moveToFront("reuseOrNewTask", targetTask);
}
以ActivitA启动ActivityB为例(startActivity(new Intent(ActivityA.this,ActivityB.class));),ActivityStack.moveToFront()执行到的逻辑主要有:
ActivityStack.moveToFront():
void moveToFront(String reason, Task task) {
if (!isAttached()) {
return;
}
final TaskDisplayArea taskDisplayArea = getDisplayArea();
if (isRootTask()) {
taskDisplayArea.positionStackAtTop(this, false /* includingParents */, reason);//code snippet 17
}
if (task == null) {
task = this;
}
task.getParent().positionChildAt(POSITION_TOP, task, true /* includingParents */);//code snippet 18
}
把要启动的Activity所在的Task设置在显示区域和WindowContainer的最上层
TODO WindowContainer是什么?在之后慢慢学习
接着看,下面的流程:
startActivityInner():
mTargetStack.startActivityLocked(mStartActivity, topStack.getTopNonFinishingActivity(),
newTask, mKeepCurTransition, mOptions);
以ActivitA启动ActivityB为例(startActivity(new Intent(ActivityA.this,ActivityB.class));), ActivityStack.startActivityLocked的主要流程如下:
ActivityStack.startActivityLocked():
void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
boolean newTask, boolean keepCurTransition, ActivityOptions options) {
Task rTask = r.getTask();
final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
final boolean isOrhasTask = rTask == this || hasChild(rTask);
Task task = null;
task = activityTask;
// Slot the activity into the history stack and proceed
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
new RuntimeException("here").fillInStackTrace());
task.positionChildAtTop(r);//code snippet 19
// The transition animation and starting window are not needed if {@code allowMoveToFront}
// is false, because the activity won't be visible.
if ((!isHomeOrRecentsStack() || hasActivity()) && allowMoveToFront) {
final DisplayContent dc = getDisplay().mDisplayContent;
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: starting " + r);
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
dc.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
mStackSupervisor.mNoAnimActivities.add(r);
} else {
int transit = TRANSIT_ACTIVITY_OPEN;
//code snippet 20
dc.prepareAppTransition(transit, keepCurTransition);
mStackSupervisor.mNoAnimActivities.remove(r);
}
boolean doShow = true;
if (r.mLaunchTaskBehind) {// r.mLaunchTaskBehind= false
// Don't do a starting window for mLaunchTaskBehind. More importantly make sure we
// tell WindowManager that r is visible even though it is at the back of the stack.
r.setVisibility(true);
ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
// Go ahead to execute app transition for this activity since the app transition
// will not be triggered through the resume channel.
getDisplay().mDisplayContent.executeAppTransition();
} else if (SHOW_APP_STARTING_PREVIEW && doShow) {// true
// Figure out if we are transitioning from another activity that is
// "has the same starting icon" as the next one. This allows the
// window manager to keep the previous window it had previously
// created, if it still had one.
Task prevTask = r.getTask();
ActivityRecord prev = prevTask.topActivityWithStartingWindow();
if (prev != null) {
// We don't want to reuse the previous starting preview if:
// (1) The current activity is in a different task.
if (prev.getTask() != prevTask) {
prev = null;
}
// (2) The current activity is already displayed.
else if (prev.nowVisible) {
prev = null;
}
}
//code snippet 21
r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity));
}
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
ActivityOptions.abort(options);
}
}
流程先分析到这里,之后的流程是Activity的Pause和Resume,我会单独再分析。