1.从launcher恢复activity
2.从当前activity打开另一个acivity
3.从当前activity打开另一个acivity,并在当前activity设置了newTask标记
本系列将分3篇文章,讲述不同情况下activity的启动情况
本文就先分析最简单的情况,也就是第一种情况
下文出现的MainActivity指的是我们自己的应用也就是从LoadingActivity-MainActivity
LaunchActivity指的是回到桌面时候所展现的页面
1.在ams里获取到要启动的activity的activityinfo对象
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
这个 intent是launcher打开activity的默认是new_task和clear_flags
startFlags和profilerInfo都是0,不用管
接下来会调用
final ActivityStack stack = mRootActivityContainer.getTopDisplayFocusedStack();
这里是获取当前正在显示的activityStack(也就是最上层的activitstack)
然后进入以下代码,有些参数是通过mRequest通过建造者模式传过来的
也就是新建了一个activityStarter
final ActivityRecord[] outRecord = new ActivityRecord[1];
int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo,
voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent,
allowBackgroundActivityStart);
下面说下这几个参数的作用
ApplicationThread caller
也就说是调用者的一个binderproxy对象,用来回调调用者的回调方法
这个参数是application级别的,也就是和进程有关的,一个进程就会创建一个对象
private class ApplicationThread extends IApplicationThread.Stub {
private static final String DB_INFO_FORMAT = " %8s %8s %14s %14s %s";
public final void scheduleSleeping(IBinder token, boolean sleeping) {
sendMessage(H.SLEEPING, token, sleeping ? 1 : 0);
}
Intent intent
调用者设置的intent对象在此处是(表示要打开的activity的intent)
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.badtokendemo/.LoadingActivity bnds=[41,258][290,586] }
Intent ephemeralIntent
intent的赋值对象(没多大意义)
String resolvedType
intent.resolveTypeIfNeeded(who.getContentResolver()),
来源于此值,现在没啥作用
ActivityInfo aInfo
存放着启动的activity的info值(包括了此activity在xml里的各种属性)
ResolveInfo rInfo
包含了activityInfo对象,并有些其他的属性
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor
默认都是为null
IBinder resultTo
这个属性很重要,是activityRecord里的一个内部类,用来找到对应的actiivtyRecord(这里的值是launcher的activityrecord)
resultWho
这里默认为null
requestCode
默认也为0
callingPid callingUid
这里传过来的是都是0,后面会取launcher的realCallingPid 和realCallingUid
SafeActivityOptions options
这里是打开activity时传的activityoptions的封装的形式,这里由于是launcher开启的,所以会传过来一些参数
下面几个都是默认的值
boolean ignoreTargetSecurity
为false
boolean componentSpecified
为true
boolean allowPendingRemoteAnimationRegistryLookup
为true
boolean allowBackgroundActivityStart
为false
PendingIntentRecord originatingPendingIntent
为null
boolean ignoreTargetSecurity
为false
ActivityRecord[] outActivity
要打开activity对应的activityRecord
TaskRecord inTask
这里为null
接下来会调用
WindowProcessController callerApp = null;
if (caller != null) {
callerApp = mService.getProcessController(caller);
if (callerApp != null) {
callingPid = callerApp.getPid();
callingUid = callerApp.mInfo.uid;
} else {
Slog.w(TAG, "Unable to find app for caller " + caller
+ " (pid=" + callingPid + ") when starting: "
+ intent.toString());
err = ActivityManager.START_PERMISSION_DENIED;
}
}
这里获取launcher的WindowProcess,然后获得callingPid和callingUid
接下来是根据IBinder对象获取ActivityRecord
ActivityRecord resultRecord = null;
if (resultTo != null) {
sourceRecord = mRootActivityContainer.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;
}
}
}
显然这里sourceRecord是launcher activity对应的record
接下来(launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0这个暂且跳过
launchFlags就是newTask和if need属性
接下来的代码都是判断activity的启动权限是否是后台启动的拦截等,这里不做多讲
然后就是新建打开页面的activityRecord了
ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
mSupervisor, checkedOptions, sourceRecord);
if (outActivity != null) {
outActivity[0] = r;
}
这里说下activityRecord的具体参数吧
appToken 包含了当前的activityrecord和intent
appToken = new Token(this, _intent);
这个intent是传过来的intent,this就是当前的要打开的activityRecord
也就是说通过token就能找到对应的activity
比如a打开b页面,通常要传递a页面的token,是因为这样才能找到a的activityRecord,从而来确定b是依附于哪个activityRecord上(标准情况下)
frontOfTask 是否是task的第一个,默认是false
ActivityState mState 是ActivityRecord的一个成员变量,通过不断的赋值不同的状态来回调
final TaskRecord parent = getTaskRecord();
if (parent != null) {
parent.onActivityStateChanged(this, state, reason);
}
当然现在的activity对应的taskrecord还是null,不会空时会调用onActivityStateChanged方法
stopped = false;判断栈有没有被终止
delayedResume=false 有没有可见,默认是false
finishing = false;
mActivityComponent 对象代表着包名和类名,就是新的activityRecord存放着intent的componentName
if (aInfo.targetActivity == null
|| (aInfo.targetActivity.equals(_intent.getComponent().getClassName())
&& (aInfo.launchMode == LAUNCH_MULTIPLE
|| aInfo.launchMode == LAUNCH_SINGLE_TOP))) {
mActivityComponent = _intent.getComponent();
} else {
mActivityComponent = new ComponentName(aInfo.packageName, aInfo.targetActivity);
}
intent 取的是launch传过来的值,当然如果
taskAffinity 读取的是xml写的值,还有一些processName,theme,logolaunchMode等
resultTo 参数,这个参数后面会用到,来源在于
if (resultTo != null) {
sourceRecord = mRootActivityContainer.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;
}
}
}
当然现在默认是null的,和上面IBinder传过来的result不同,那个是找到sourceRecord的
注意:logolaunchMode是存在activityRecord里的,但是flages没存,存的是launch的intent
在赋值完activityRecord以后
继续调用startActivity方法
private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity, boolean restrictedBgActivity) {
int result = START_CANCELED;
final ActivityStack startedActivityStack;
try {
mService.mWindowManager.deferSurfaceLayout();
result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, outActivity, restrictedBgActivity);
}
这里主要是调用startActivityUnchecked核心方法,也是逻辑非常绕的一段
先来说下他几个参数
第一个r是将要打开的LoadingActivity的activityRecord,注意,此时还没被添加到activityTask里和activityStack里
sourceRecord是launcher的启动的activityRecord
doResume 参数这里传过来的是true
outActivity 数组里第一个就是LoadingActivity的activityRecord
inTask 参数为null 表示有没有指定放入的task
首先会调用setInitialState方法,可以看到,主要是一个赋值的操作
private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
boolean doResume, int startFlags, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
boolean restrictedBgActivity) {
reset(false /* clearRequest */);
可以看到的是一个activityRecord对应一个activityStater
activityStater里的mStartActivity对应的就是要打开的activity
mIntent就是launcher的intent
mCallingUid就是launcher的uid
mLaunchMode 就是xml设置的mode
mLaunchFlags = adjustLaunchFlagsToDocumentMode(
r, LAUNCH_SINGLE_INSTANCE == mLaunchMode,
LAUNCH_SINGLE_TASK == mLaunchMode, mIntent.getFlags());
这里的mLaunchFlags就是intent的launch就是0x10200000
由于是根据DocumentMode调整的,我们这里暂且不论
接下来调用
private void sendNewTaskResultRequestIfNeeded() {
final ActivityStack sourceStack = mStartActivity.resultTo != null
? mStartActivity.resultTo.getActivityStack() : null;
if (sourceStack != null && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
// For whatever reason this activity is being launched into a new task...
// yet the caller has requested a result back. Well, that is pretty messed up,
// so instead immediately send back a cancel and let the new task continue launched
// as normal without a dependency on its originator.
Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
sourceStack.sendActivityResultLocked(-1 /* callingUid */, mStartActivity.resultTo,
mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED,
null /* data */);
mStartActivity.resultTo = null;
}
}
由于我们的resultTo为null,上文说过,所以暂且不论
mDoResume就是一开始赋的值,这里为true
mNotTop 字段
mNotTop = (mLaunchFlags & FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? sourceRecord : null;
和FLAG_ACTIVITY_PREVIOUS_IS_TOP有关,这里为null
inTask对应的taskRecord这里由于没制定也是null
这里第一步是分析完了,主要是给activityStarter赋值,并且修正一些值
现阶段还没有修正过哪个值
接下来调用computeLaunchingTaskFlags
简单来说就是修正一些flag
} 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;
}
由于我们有sourcerecord所以只可能会走这里,如果sourcerecord是singleInstance,则给新的activityStater添加FLAG_ACTIVITY_NEW_TASK
如果是singleTask或者singleInstance的话,就添加newTask
很显然我们的mLunchFlag是包含了newTask
所以都不会走
3.接下来给当前activityRecord赋值mSourceStack
很显然取得也是mSourceRecord的stack
private void computeSourceStack() {
if (mSourceRecord == null) {
mSourceStack = null;
return;
}
if (!mSourceRecord.finishing) {
mSourceStack = mSourceRecord.getActivityStack();
return;
}
4.给intent设置调整后的flags
mIntent.setFlags(mLaunchFlags);
由于没调整过,所以不用处理
5.寻找可重用的activityRecord,这个很重要
private ActivityRecord getReusableIntentActivity() {
// We may want to try to place the new activity in to an existing task. We always
// do this if the target activity is singleTask or singleInstance; we will also do
// this if NEW_TASK has been requested, and there is not an additional qualifier telling
// us to still place it in a new task: multi task, always doc mode, or being asked to
// launch this as a new task behind the current one.
boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
(mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK);
// If bring to front is requested, and no result is requested and we have not been given
// an explicit task to launch in to, and we can find a task that was started with this
// same component, then instead of launching bring that one to the front.
putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
ActivityRecord intentActivity = null;
if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
final TaskRecord task = mRootActivityContainer.anyTaskForId(mOptions.getLaunchTaskId());
intentActivity = task != null ? task.getTopActivity() : null;
} else if (putIntoExistingTask) {
if (LAUNCH_SINGLE_INSTANCE == mLaunchMode) {
// There can be one and only one instance of single instance activity in the
// history, and it is always in its own unique task, so we do a special search.
intentActivity = mRootActivityContainer.findActivity(mIntent, mStartActivity.info,
mStartActivity.isActivityTypeHome());
} else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
// For the launch adjacent case we only want to put the activity in an existing
// task if the activity already exists in the history.
intentActivity = mRootActivityContainer.findActivity(mIntent, mStartActivity.info,
!(LAUNCH_SINGLE_TASK == mLaunchMode));
} else {
// Otherwise find the best task to put the activity in.
intentActivity =
mRootActivityContainer.findTask(mStartActivity, mPreferredDisplayId);
}
}
if (intentActivity != null
&& (mStartActivity.isActivityTypeHome() || intentActivity.isActivityTypeHome())
&& intentActivity.getDisplayId() != mPreferredDisplayId) {
// Do not reuse home activity on other displays.
intentActivity = null;
}
return intentActivity;
}
先判断是否放入现有的任务中
mStartActivity.resultTo这里对应的就是上文的resultRecord,当然这里为null
这里主要调用findTask方法
intentActivity =
mRootActivityContainer.findTask(mStartActivity, mPreferredDisplayId);
核心调用的方法是
void findTaskLocked(ActivityRecord target, FindTaskResult result) {
Intent intent = target.intent;
ActivityInfo info = target.info;
ComponentName cls = intent.getComponent();
if (info.targetActivity != null) {
cls = new ComponentName(info.packageName, info.targetActivity);
}
final int userId = UserHandle.getUserId(info.applicationInfo.uid);
boolean isDocument = intent != null & intent.isDocument();
// If documentData is non-null then it must match the existing task data.
Uri documentData = isDocument ? intent.getData() : null;
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + target + " in " + this);
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
if (task.voiceSession != null) {
// We never match voice sessions; those always run independently.
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": voice session");
continue;
}
if (task.userId != userId) {
// Looking for a different task.
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": different user");
continue;
}
// Overlays should not be considered as the task's logical top activity.
final ActivityRecord r = task.getTopActivity(false /* includeOverlays */);
if (r == null || r.finishing || r.mUserId != userId ||
r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch root " + r);
continue;
}
if (!r.hasCompatibleActivityType(target)) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch activity type");
continue;
}
final Intent taskIntent = task.intent;
final Intent affinityIntent = task.affinityIntent;
final boolean taskIsDocument;
final Uri taskDocumentData;
if (taskIntent != null && taskIntent.isDocument()) {
taskIsDocument = true;
taskDocumentData = taskIntent.getData();
} else if (affinityIntent != null && affinityIntent.isDocument()) {
taskIsDocument = true;
taskDocumentData = affinityIntent.getData();
} else {
taskIsDocument = false;
taskDocumentData = null;
}
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls="
+ (task.realActivity != null ? task.realActivity.flattenToShortString() : "")
+ "/aff=" + r.getTaskRecord().rootAffinity + " to new cls="
+ intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
// TODO Refactor to remove duplications. Check if logic can be simplified.
if (task.realActivity != null && task.realActivity.compareTo(cls) == 0
&& Objects.equals(documentData, taskDocumentData)) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
//dump();
if (DEBUG_TASKS) Slog.d(TAG_TASKS,
"For Intent " + intent + " bringing to top: " + r.intent);
result.mRecord = r;
result.mIdealMatch = true;
break;
} else if (affinityIntent != null && affinityIntent.getComponent() != null &&
affinityIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
//dump();
if (DEBUG_TASKS) Slog.d(TAG_TASKS,
"For Intent " + intent + " bringing to top: " + r.intent);
result.mRecord = r;
result.mIdealMatch = true;
break;
} else if (!isDocument && !taskIsDocument
&& result.mRecord == null && task.rootAffinity != null) {
if (task.rootAffinity.equals(target.taskAffinity)) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
// It is possible for multiple tasks to have the same root affinity especially
// if they are in separate stacks. We save off this candidate, but keep looking
// to see if there is a better candidate.
result.mRecord = r;
result.mIdealMatch = false;
}
} else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
}
}
这里会遍历activityStack,当然现在lunancher对应activityStack先被遍历到,传过去的参数是要打开的activityRecord
简单来说就是从每个activityStack里去寻找匹配的activityRecord
这里先拿到要打开activity的ComponentName,然后去遍历activityStater中的taskRecord去拿到最上面的activityRecord,如果是singleInstance的话就跳过(8.0以后基本上一个activityStack对应了一个taskRecord)
这里要说明的是不但activityRecord属性,taskRecord也有此属性
最后来匹配创建taskRecord的传过来的ComponentName和当前的activityRecord的ComponentName做比较
很明显由于是打开过的taskRecord,所以第二个taskRecord的realactivity符合
所以会走到这里面,所以返回的 result.mRecord也就是taskRecord
result.mRecord = r;
result.mIdealMatch = true;
也就是原来的mainActivity对应的activityRecord
6.当reusedActivity不为null时,也是最重要的逻辑
6.1
final boolean clearTopAndResetStandardLaunchMode =
(mLaunchFlags & (FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED))
== (FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
&& mLaunchMode == LAUNCH_MULTIPLE;
// If mStartActivity does not have a task associated with it, associate it with the
// reused activity's task. Do not do so if we're clearing top and resetting for a
// standard launchMode activity.
if (mStartActivity.getTaskRecord() == null && !clearTopAndResetStandardLaunchMode) {
mStartActivity.setTask(reusedActivity.getTaskRecord());
}
这里clearTopAndResetStandardLaunchMode为false
会走到setTask里,也就是给activity放到taskRecord里
void setTask(TaskRecord task, boolean reparenting) {
// Do nothing if the {@link TaskRecord} is the same as the current {@link getTaskRecord}.
if (task != null && task == getTaskRecord()) {
return;
}
final ActivityStack oldStack = getActivityStack();
final ActivityStack newStack = task != null ? task.getStack() : null;
// Inform old stack (if present) of activity removal and new stack (if set) of activity
// addition.
if (oldStack != newStack) {
if (!reparenting && oldStack != null) {
oldStack.onActivityRemovedFromStack(this);
}
if (newStack != null) {
newStack.onActivityAddedToStack(this);
}
}
this.task = task;
if (!reparenting) {
onParentChanged();
}
}
这里由于不是resume的状态,所以onActivityAddedToStack没啥用,简单来说就是把taskRecord赋值到了这个activityRecord里
接下来是针对singletask的一个条件语句
if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| isDocumentLaunchesIntoExisting(mLaunchFlags)
|| isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
这里我们暂时不分析,下文会分析,重点看下这方法
reusedActivity = setTargetStackAndMoveToFrontIfNeeded(reusedActivity);
从名字上来说是把这个acivityRecord对应的activityStack移到第一个,来看看具体的操作
private ActivityRecord setTargetStackAndMoveToFrontIfNeeded(ActivityRecord intentActivity) {
mTargetStack = intentActivity.getActivityStack();
mTargetStack.mLastPausedActivity = null;
// If the target task is not in the front, then we need to bring it to the front...
// except... well, with SINGLE_TASK_LAUNCH it's not entirely clear. We'd like to have
// the same behavior as if a new instance was being started, which means not bringing it
// to the front if the caller is not itself in the front.
final boolean differentTopTask;
if (mPreferredDisplayId == mTargetStack.mDisplayId) {
final ActivityStack focusStack = mTargetStack.getDisplay().getFocusedStack();
final ActivityRecord curTop = (focusStack == null)
? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
final TaskRecord topTask = curTop != null ? curTop.getTaskRecord() : null;
differentTopTask = topTask != intentActivity.getTaskRecord()
|| (focusStack != null && topTask != focusStack.topTask());
} else {
// The existing task should always be different from those in other displays.
differentTopTask = true;
}
....
这里mTargetStack就是我们的loadingActivity对应的ActivityStack就是targetStack,把这个mLastPausedActivity设为null,而focusStack肯定就是launcher对应的ActivityRecord 接下来去寻找当前activitystack对应的可见的ActivityRecord
ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
final ArrayList activities = task.mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
ActivityRecord r = activities.get(activityNdx);
if (!r.finishing && !r.delayedResume && r != notTop && r.okToShowLocked()) {
return r;
}
}
}
return null;
}
可以看到取到的就是lunchActivity
然后判断
differentTopTask = topTask != intentActivity.getTaskRecord()
|| (focusStack != null && topTask != focusStack.topTask());
MainActivity对应taskRecord是否是launcher的taskRecord一样,很显然是不一样的
所以走了如下的逻辑
if (differentTopTask && !mAvoidMoveToFront) {
mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
if (mSourceRecord == null || (mSourceStack.getTopActivity() != null &&
mSourceStack.getTopActivity().getTaskRecord()
== mSourceRecord.getTaskRecord())) {
// We really do want to push this one into the user's face, right now.
if (mLaunchTaskBehind && mSourceRecord != null) {
intentActivity.setTaskToAffiliateWith(mSourceRecord.getTaskRecord());
}
这里给MainActivity对应的activityRecord设置flag,这个flag也就是launcher启动的标志
然后判断mSourceStack也就是activityStack的taskrecord的topActivity如果是sourceRecord对应的taskrecord,显然这里是符合的
但是mLaunchTaskBehind是false所以不走以下逻辑
final boolean willClearTask =
(mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
if (!willClearTask) {
final ActivityStack launchStack = getLaunchStack(
mStartActivity, mLaunchFlags, mStartActivity.getTaskRecord(), mOptions);
final TaskRecord intentTask = intentActivity.getTaskRecord();
if (launchStack == null || launchStack == mTargetStack) {
// We only want to move to the front, if we aren't going to launch on a
// different stack. If we launch on a different stack, we will put the
// task on top there.
mTargetStack.moveTaskToFrontLocked(intentTask, mNoAnimation, mOptions,
mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
mMovedToFront = true;
} else if (launchStack.inSplitScreenWindowingMode()) {
if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
// If we want to launch adjacent and mTargetStack is not the computed
// launch stack - move task to top of computed stack.
intentTask.reparent(launchStack, ON_TOP,
REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
"launchToSide");
} else {
// TODO: This should be reevaluated in MW v2.
// We choose to move task to front instead of launching it adjacent
// when specific stack was requested explicitly and it appeared to be
// adjacent stack, but FLAG_ACTIVITY_LAUNCH_ADJACENT was not set.
mTargetStack.moveTaskToFrontLocked(intentTask,
mNoAnimation, mOptions, mStartActivity.appTimeTracker,
"bringToFrontInsteadOfAdjacentLaunch");
}
mMovedToFront = launchStack != launchStack.getDisplay()
.getTopStackInWindowingMode(launchStack.getWindowingMode());
} else if (launchStack.mDisplayId != mTargetStack.mDisplayId) {
// Target and computed stacks are on different displays and we've
// found a matching task - move the existing instance to that display and
// move it to front.
intentActivity.getTaskRecord().reparent(launchStack, ON_TOP,
REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
"reparentToDisplay");
mMovedToFront = true;
} else if (launchStack.isActivityTypeHome()
&& !mTargetStack.isActivityTypeHome()) {
// It is possible for the home activity to be in another stack initially.
// For example, the activity may have been initially started with an intent
// which placed it in the fullscreen stack. To ensure the proper handling of
// the activity based on home stack assumptions, we must move it over.
intentActivity.getTaskRecord().reparent(launchStack, ON_TOP,
REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
"reparentingHome");
mMovedToFront = true;
}
mOptions = null;
// We are moving a task to the front, use starting window to hide initial drawn
// delay.
intentActivity.showStartingWindow(null /* prev */, false /* newTask */,
true /* taskSwitch */);
}
重点看下这个逻辑
先获得getLaunchStack,
最终会走到
if (r.getDisplayId() == displayId && r.getTaskRecord() == candidateTask) {
return candidateTask.getStack();
}
这个r是mStartActivity,因为之前已经赋值过taskRecord,所以是返回taskRecord对应的activityStack
然后走到关键的地方
if (!willClearTask) {
final ActivityStack launchStack = getLaunchStack(
mStartActivity, mLaunchFlags, mStartActivity.getTaskRecord(), mOptions);
final TaskRecord intentTask = intentActivity.getTaskRecord();
if (launchStack == null || launchStack == mTargetStack) {
// We only want to move to the front, if we aren't going to launch on a
// different stack. If we launch on a different stack, we will put the
// task on top there.
mTargetStack.moveTaskToFrontLocked(intentTask, mNoAnimation, mOptions,
mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
mMovedToFront = true;
}
由于launchStack等于mTargetStack(就是loadingActivity对应的activityStack)
回调用此activityStack的moveTaskToFrontLocked方法
里面获取到LoadingActivity的activityRecord以后
final ActivityRecord r = topRunningActivityLocked();
if (r != null) {
r.moveFocusableActivityToTop(reason);
}
重点调用了如下方法
/** Move activity with its stack to front and make the stack focused. */
boolean moveFocusableActivityToTop(String reason) {
if (!isFocusable()) {
if (DEBUG_FOCUS) {
Slog.d(TAG_FOCUS, "moveActivityStackToFront: unfocusable activity=" + this);
}
return false;
}
final TaskRecord task = getTaskRecord();
final ActivityStack stack = getActivityStack();
if (stack == null) {
Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: activity="
+ this + " task=" + task);
return false;
}
if (mRootActivityContainer.getTopResumedActivity() == this) {
if (DEBUG_FOCUS) {
Slog.d(TAG_FOCUS, "moveActivityStackToFront: already on top, activity=" + this);
}
return false;
}
if (DEBUG_FOCUS) {
Slog.d(TAG_FOCUS, "moveActivityStackToFront: activity=" + this);
}
stack.moveToFront(reason, task);
// Report top activity change to tracking services and WM
if (mRootActivityContainer.getTopResumedActivity() == this) {
// TODO(b/111361570): Support multiple focused apps in WM
mAtmService.setResumedActivityUncheckLocked(this, reason);
}
return true;
}
重点在于moveTofront方法会调用此方法来排序displayContent中的activityStack的显示顺序
display.positionChildAtTop(this, !movingTask /* includingParents */, reason);
这个方法用来排序把loadingactivity对应的activityStack排序到前面去
然后
if (mRootActivityContainer.getTopResumedActivity() == this) {
// TODO(b/111361570): Support multiple focused apps in WM
mAtmService.setResumedActivityUncheckLocked(this, reason);
}
此时ams里最上面的activityrecord就是此,然后把ams的lastResumeActivity设置成MainActivity
setResumedActivityUncheckLocked() 方法
if (mLastResumedActivity != null && r.mUserId != mLastResumedActivity.mUserId) {
mAmInternal.sendForegroundProfileChanged(r.mUserId);
}
updateResumedAppTrace(r);
mLastResumedActivity = r;
r.getDisplay().setFocusedApp(r, true);
applyUpdateLockStateLocked(r);
applyUpdateVrModeLocked(r);
在设置完成之后
ams会调用一个最重要的方法resumeFocusedStacksTopActivities,此时要打开的activity的栈已经被移到前面了
boolean resumeFocusedStacksTopActivities() {
return resumeFocusedStacksTopActivities(null, null, null);
}
三个参数都是null
boolean resumeFocusedStacksTopActivities(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if (!mStackSupervisor.readyToResume()) {
return false;
}
boolean result = false;
if (targetStack != null && (targetStack.isTopStackOnDisplay()
|| getTopDisplayFocusedStack() == targetStack)) {
result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
boolean resumedOnDisplay = false;
final ActivityDisplay display = mActivityDisplays.get(displayNdx);
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
final ActivityRecord topRunningActivity = stack.topRunningActivityLocked();
if (!stack.isFocusableAndVisible() || topRunningActivity == null) {
continue;
}
if (stack == targetStack) {
// Simply update the result for targetStack because the targetStack had
// already resumed in above. We don't want to resume it again, especially in
// some cases, it would cause a second launch failure if app process was dead.
resumedOnDisplay |= result;
continue;
}
if (display.isTopStack(stack) && topRunningActivity.isState(RESUMED)) {
// Kick off any lingering app transitions form the MoveTaskToFront operation,
// but only consider the top task and stack on that display.
stack.executeAppTransition(targetOptions);
} else {
resumedOnDisplay |= topRunningActivity.makeActiveIfNeeded(target);
}
}
这里由于runnActivity(就是mainActivity)最终会调用makeActiveIfNeeded方法
@GuardedBy("mService")
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
if (mInResumeTopActivity) {
// Don't even start recursing.
return false;
}
boolean result = false;
try {
// Protect against recursion.
mInResumeTopActivity = true;
result = resumeTopActivityInnerLocked(prev, options);
间接调用resumeTopActivityInnerLocked注意这两个参数都是null,并且设置了loadactivity对应的activityStack的mInResumeTopActivity值为true
从而调用mainactivity对应的activityStack的resumeTopActivityInnerLocked
方法,也就是在这方法里MainActivity来resume的
这里看判断这个activitystack里mPausingActivity的对应的activityrecord是否是null
// If we are currently pausing an activity, then don't do anything until that is done.
if (!mRootActivityContainer.allPausedActivitiesComplete()) {
if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
"resumeTopActivityLocked: Skip resume: some activity pausing.");
return false;
}
如果此activityRecord在pause就返回true
接下来就调用pauseBackStacks用来让launch onpause;
boolean pausing = getDisplay().pauseBackStacks(userLeaving, next, false);
这方法判断activitystack对应的resumeActivity属性收否是null,并且不是fosucable
boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming, boolean dontWait) {
boolean someActivityPaused = false;
for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = mStacks.get(stackNdx);
final ActivityRecord resumedActivity = stack.getResumedActivity();
if (resumedActivity != null
&& (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE
|| !stack.isFocusable())) {
if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack +
" mResumedActivity=" + resumedActivity);
someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
dontWait);
}
}
return someActivityPaused;
}
会调用activityStack(此时是launcherActivity)的startPausingLocked方法
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
ActivityRecord resuming, boolean pauseImmediately) {
if (mPausingActivity != null) {
Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity
+ " state=" + mPausingActivity.getState());
if (!shouldSleepActivities()) {
// Avoid recursion among check for sleep and complete pause during sleeping.
// Because activity will be paused immediately after resume, just let pause
// be completed by the order of activity paused from clients.
completePauseLocked(false, resuming);
}
}
ActivityRecord prev = mResumedActivity;
if (prev == null) {
if (resuming == null) {
Slog.wtf(TAG, "Trying to pause when nothing is resumed");
mRootActivityContainer.resumeFocusedStacksTopActivities();
}
return false;
}
if (prev == resuming) {
Slog.wtf(TAG, "Trying to pause activity that is in process of being resumed");
return false;
}
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSING: " + prev);
else if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Start pausing: " + prev);
mPausingActivity = prev;
mLastPausedActivity = prev;
mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0 ? prev : null;
prev.setState(PAUSING, "startPausingLocked");
prev.getTaskRecord().touchActiveTime();
clearLaunchTime(prev);
mService.updateCpuStats();
if (prev.attachedToProcess()) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
try {
EventLogTags.writeAmPauseActivity(prev.mUserId, System.identityHashCode(prev),
prev.shortComponentName, "userLeaving=" + userLeaving);
mService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
prev.configChangeFlags, pauseImmediately));
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
Slog.w(TAG, "Exception thrown during pause", e);
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
} else {
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
// If we are not going to sleep, we want to ensure the device is
// awake until the next activity is started.
if (!uiSleeping && !mService.isSleepingOrShuttingDownLocked()) {
mStackSupervisor.acquireLaunchWakelock();
}
if (mPausingActivity != null) {
// Have the window manager pause its key dispatching until the new
// activity has started. If we're pausing the activity just because
// the screen is being turned off and the UI is sleeping, don't interrupt
// key dispatch; the same activity will pick it up again on wakeup.
if (!uiSleeping) {
prev.pauseKeyDispatchingLocked();
} else if (DEBUG_PAUSE) {
Slog.v(TAG_PAUSE, "Key dispatch not paused for screen off");
}
if (pauseImmediately) {
// If the caller said they don't want to wait for the pause, then complete
// the pause now.
completePauseLocked(false, resuming);
return false;
} else {
schedulePauseTimeout(prev);
return true;
}
} else {
// This activity failed to schedule the
// pause, so just treat it as being paused now.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next.");
if (resuming == null) {
mRootActivityContainer.resumeFocusedStacksTopActivities();
}
return false;
}
}
由于这里是launcherActivity的activityStack,所以他的mPauseing为null
而正在mResumedActivity就是launcheractivity了,然后把mPausingActivity和
mLastPausedActivity赋值为launcheractivity
然后这里
prev.setState(PAUSING, "startPausingLocked");
把activityrecord的状态设置成pausing
void setState(ActivityState state, String reason) {
if (DEBUG_STATES) Slog.v(TAG_STATES, "State movement: " + this + " from:" + getState()
+ " to:" + state + " reason:" + reason);
if (state == mState) {
// No need to do anything if state doesn't change.
if (DEBUG_STATES) Slog.v(TAG_STATES, "State unchanged from:" + state);
return;
}
mState = state;
final TaskRecord parent = getTaskRecord();
if (parent != null) {
parent.onActivityStateChanged(this, state, reason);
}
会间接调用onActivityStateChanged方法
void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) {
if (record == mResumedActivity && state != RESUMED) {
setResumedActivity(null, reason + " - onActivityStateChanged");
}
if (state == RESUMED) {
if (DEBUG_STACK) Slog.v(TAG_STACK, "set resumed activity to:" + record + " reason:"
+ reason);
setResumedActivity(record, reason + " - onActivityStateChanged");
if (record == mRootActivityContainer.getTopResumedActivity()) {
// TODO(b/111361570): Support multiple focused apps in WM
mService.setResumedActivityUncheckLocked(record, reason);
}
mStackSupervisor.mRecentTasks.add(record.getTaskRecord());
}
}
这里由于状态是onpause所以不走如下逻辑,但是把这个activitystask的resume状态取消了
接下来判断进程是否存在
if (prev.attachedToProcess()) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
try {
EventLogTags.writeAmPauseActivity(prev.mUserId, System.identityHashCode(prev),
prev.shortComponentName, "userLeaving=" + userLeaving);
mService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
prev.configChangeFlags, pauseImmediately));
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
Slog.w(TAG, "Exception thrown during pause", e);
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
} else {
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
这里当有activityrecord所在进程存在的情况下会让此activity进行onpause的操作
if (mResumedActivity != null) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Pausing " + mResumedActivity);
pausing |= startPausingLocked(userLeaving, false, next, false);
}
if (pausing && !resumeWhilePausing) {
if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES,
"resumeTopActivityLocked: Skip resume: need to start pausing");
// At this point we want to put the upcoming activity's process
// at the top of the LRU list, since we know we will be needing it
// very soon and it would be a waste to let it get killed if it
// happens to be sitting towards the end.
if (next.attachedToProcess()) {
next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
true /* activityChange */, false /* updateOomAdj */);
}
if (lastResumed != null) {
lastResumed.setWillCloseOrEnterPip(true);
}
return true;
} else if (mResumedActivity == next && next.isState(RESUMED)
&& display.allResumedActivitiesComplete()) {
// It is possible for the activity to be resumed when we paused back stacks above if the
// next activity doesn't have to wait for pause to complete.
// So, nothing else to-do except:
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options);
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Top activity resumed (dontWaitForPause) " + next);
return true;
}
这里回到了Mainactivity的activityrecord里,由于mResumedActivity还没有赋值,mResumedActivity还是原来的activitystack里,虽然已经执行了onpause操作
这里返回的pausing就是mPausingActivity正在pause的标示符,
这里是返回的true.然后更新process的优先级
if (next.attachedToProcess()) {
next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
true /* activityChange */, false /* updateOomAdj */);
}
这里的next指的就是mainActivity的record
这里总结一下:
1.先循环找到最顶层的activityStack对应的activityRecord,然后调用其makeActiveIfNeeded方法
判断是focusable但不是resume状态的
2.然后根据mResume的状态去pause activityStack是resume但不是在最上层的activityStack对应的activityRecord
至此moveTaskToFrontLocked算是走完了,可见非常的绕,当然这只是一种case
最后走到了
if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
return mTargetStack.resetTaskIfNeededLocked(intentActivity, mStartActivity);
}
由于从launcher启动会带上这个参数,来看下这个参数实际的含义
这里这个属性其实和这三个设置的有关,由于默认没设置,就没有
final int flags = target.info.flags;
final boolean finishOnTaskLaunch =
(flags & ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
final boolean allowTaskReparenting =
(flags & ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
final boolean clearWhenTaskReset =
(target.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
再来看下setTaskFromIntentActivity方法,传过来的是MainActivity
if (reusedActivity != null) {
setTaskFromIntentActivity(reusedActivity);
这个方法主要对singleTask和FLAG_ACTIVITY_SINGLE_TOP做的处理
最后如果此mStartActivity没有被加到task中
if (!mAddingToTask && mReuseTask == null) {
// We didn't do anything... but it was needed (a.k.a., client don't use that
// intent!) And for paranoia, make sure we have correctly resumed the top activity.
resumeTargetStackIfNeeded();
if (outActivity != null && outActivity.length > 0) {
// The reusedActivity could be finishing, for example of starting an
// activity with FLAG_ACTIVITY_CLEAR_TOP flag. In that case, return the
// top running activity in the task instead.
outActivity[0] = reusedActivity.finishing
? reusedActivity.getTaskRecord().getTopActivity() : reusedActivity;
}
return mMovedToFront ? START_TASK_TO_FRONT : START_DELIVERED_TO_TOP;
}
这里会间接调用resumeFocusedStacksTopActivities方法,上文已经调用过了,但是参数mTargetStack代表了MainActivity
boolean resumeFocusedStacksTopActivities(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if (!mStackSupervisor.readyToResume()) {
return false;
}
boolean result = false;
if (targetStack != null && (targetStack.isTopStackOnDisplay()
|| getTopDisplayFocusedStack() == targetStack)) {
result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
....
这里targetStack很明显就是我们MainActivity对应的task
此时看到了又循环了此方法,但是由于我们的pausing标记
if (!mRootActivityContainer.allPausedActivitiesComplete()) {
if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
"resumeTopActivityLocked: Skip resume: some activity pausing.");
return false;
}
这里很明显会走到这个if里面,返回false,也就是不会在走进去了
当然后面由于状态是pausing的状态,所以是返回false
当然后面的makeActiveIfNeeded也是因为是pause状态所以没有执行resumeTopActivityUncheckedLocked方法
boolean makeActiveIfNeeded(ActivityRecord activeActivity) {
if (shouldResumeActivity(activeActivity)) {
if (DEBUG_VISIBILITY) {
Slog.v("TAG_VISIBILITY", "Resume visible activity, " + this);
}
return getActivityStack().resumeTopActivityUncheckedLocked(activeActivity /* prev */,
null /* options */);
}
显然过程已经执行完了,接下来执行
if (outActivity != null && outActivity.length > 0) {
// The reusedActivity could be finishing, for example of starting an
// activity with FLAG_ACTIVITY_CLEAR_TOP flag. In that case, return the
// top running activity in the task instead.
outActivity[0] = reusedActivity.finishing
? reusedActivity.getTaskRecord().getTopActivity() : reusedActivity;
}
还记得上文么,outActivity是startActivity也就是LoadingActivityRecord
,现在变成了我们原来的的MainActivity
好吧,我们的startactivityunchecked方法终于执行完了
try {
mService.mWindowManager.deferSurfaceLayout();
result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, outActivity, restrictedBgActivity);
} finally {
final ActivityStack currentStack = r.getActivityStack();
startedActivityStack = currentStack != null ? currentStack : mTargetStack;
if (ActivityManager.isStartResultSuccessful(result)) {
if (startedActivityStack != null) {
// If there is no state change (e.g. a resumed activity is reparented to
// top of another display) to trigger a visibility/configuration checking,
// we have to update the configuration for changing to different display.
final ActivityRecord currentTop =
startedActivityStack.topRunningActivityLocked();
if (currentTop != null && currentTop.shouldUpdateConfigForDisplayChanged()) {
mRootActivityContainer.ensureVisibilityAndConfig(
currentTop, currentTop.getDisplayId(),
true /* markFrozenIfConfigChanged */, false /* deferResume */);
}
}
} else {
// If we are not able to proceed, disassociate the activity from the task.
// Leaving an activity in an incomplete state can lead to issues, such as
// performing operations without a window container.
final ActivityStack stack = mStartActivity.getActivityStack();
if (stack != null) {
stack.finishActivityLocked(mStartActivity, RESULT_CANCELED,
null /* intentResultData */, "startActivity", true /* oomAdj */);
}
// Stack should also be detached from display and be removed if it's empty.
if (startedActivityStack != null && startedActivityStack.isAttached()
&& startedActivityStack.numActivities() == 0
&& !startedActivityStack.isActivityTypeHome()) {
startedActivityStack.remove();
}
}
mService.mWindowManager.continueSurfaceLayout();
}
postStartActivityProcessing(r, result, startedActivityStack);
return result;
}
接下来看下后续的流程
这里currentTop很明显不为null的,然后后面的逻辑是分屏的逻辑,这里暂且不论
然后通知wms去刷新屏幕的操作
mService.mWindowManager.continueSurfaceLayout();
wms去刷新SurfaceLayout();本文也不做多的详细解释
然后回到最初的地方也就是startActivityMayWait方法
会调用日志打印的地方来打印日志
mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outRecord[0]);
最后通过activityStater来重新更新mLastStarter的操作
分析了一圈我们只分析出来了会调用我们onPause方法,那此时界面根本没显示,啥时候调用onResume方法呢?
其实在我们客户端调用完onPause之后
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, pendingActions,
"PAUSE_ACTIVITY_ITEM");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@Override
public int getTargetState() {
return ON_PAUSE;
}
@Override
public void postExecute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
if (mDontReport) {
return;
}
try {
// TODO(lifecycler): Use interface callback instead of AMS.
ActivityTaskManager.getService().activityPaused(token);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
会调用postExecute,也就是执行完onPause的操作,可以看到会调用activityPaused方法
这里说下ams的处理超时的机制,如果从ams端到客户端onPause的时间大于500毫秒,注意,这里就只有ipc通讯的时间,并不包括你客户端执行onPause时间(因为客户端是通过handler调用你自己的onpause方法的)
这段代码在activityStack里面,这个代码和正常返回的代码是竞争同一把锁的,这里要注意下
/**
* Schedule a pause timeout in case the app doesn't respond. We don't give it much time because
* this directly impacts the responsiveness seen by the user.
*/
private void schedulePauseTimeout(ActivityRecord r) {
final Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
msg.obj = r;
r.pauseTime = SystemClock.uptimeMillis();
mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Waiting for pause to complete...");
}
那来看下activityPaused方法
@Override
public final void activityPaused(IBinder token) {
final long origId = Binder.clearCallingIdentity();
synchronized (mGlobalLock) {
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
stack.activityPausedLocked(token, false);
}
}
Binder.restoreCallingIdentity(origId);
}
这里根据token来找到activityRecord,然后找到activityStack
然后进入到activityPausedLocked方法里
final void activityPausedLocked(IBinder token, boolean timeout) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE,
"Activity paused: token=" + token + ", timeout=" + timeout);
final ActivityRecord r = isInStackLocked(token);
if (r != null) {
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
if (mPausingActivity == r) {
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSED: " + r
+ (timeout ? " (due to timeout)" : " (pause complete)"));
mService.mWindowManager.deferSurfaceLayout();
try {
completePauseLocked(true /* resumeNext */, null /* resumingActivity */);
} finally {
mService.mWindowManager.continueSurfaceLayout();
}
return;
} else {
EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
r.mUserId, System.identityHashCode(r), r.shortComponentName,
mPausingActivity != null
? mPausingActivity.shortComponentName : "(none)");
if (r.isState(PAUSING)) {
r.setState(PAUSED, "activityPausedLocked");
if (r.finishing) {
if (DEBUG_PAUSE) Slog.v(TAG,
"Executing finish of failed to pause activity: " + r);
finishCurrentActivityLocked(r, FINISH_AFTER_VISIBLE, false,
"activityPausedLocked");
}
}
}
}
mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
}
也就是launcheractivity的activitystack方法,这里前面说过
lunaunch的stack的mPausingActivity就已经被赋值过了,所以是等于的,会进入completePauseLocked里面
private void completePauseLocked(boolean resumeNext, ActivityRecord resuming) {
ActivityRecord prev = mPausingActivity;
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev);
if (prev != null) {
prev.setWillCloseOrEnterPip(false);
final boolean wasStopping = prev.isState(STOPPING);
prev.setState(PAUSED, "completePausedLocked");
if (prev.finishing) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false,
"completePausedLocked");
} else if (prev.hasProcess()) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
+ " wasStopping=" + wasStopping + " visible=" + prev.visible);
if (prev.deferRelaunchUntilPaused) {
// Complete the deferred relaunch that was waiting for pause to complete.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev);
prev.relaunchActivityLocked(false /* andResume */,
prev.preserveWindowOnDeferredRelaunch);
} else if (wasStopping) {
// We are also stopping, the stop request must have gone soon after the pause.
// We can't clobber it, because the stop confirmation will not be handled.
// We don't need to schedule another stop, we only need to let it happen.
prev.setState(STOPPING, "completePausedLocked");
} else if (!prev.visible || shouldSleepOrShutDownActivities()) {
// Clear out any deferred client hide we might currently have.
prev.setDeferHidingClient(false);
// If we were visible then resumeTopActivities will release resources before
// stopping.
addToStopping(prev, true /* scheduleIdle */, false /* idleDelayed */,
"completePauseLocked");
}
} else {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "App died during pause, not stopping: " + prev);
prev = null;
}
// It is possible the activity was freezing the screen before it was paused.
// In that case go ahead and remove the freeze this activity has on the screen
// since it is no longer visible.
if (prev != null) {
prev.stopFreezingScreenLocked(true /*force*/);
}
mPausingActivity = null;
}
if (resumeNext) {
final ActivityStack topStack = mRootActivityContainer.getTopDisplayFocusedStack();
if (!topStack.shouldSleepOrShutDownActivities()) {
mRootActivityContainer.resumeFocusedStacksTopActivities(topStack, prev, null);
} else {
checkReadyForSleep();
ActivityRecord top = topStack.topRunningActivityLocked();
if (top == null || (prev != null && top != prev)) {
// If there are no more activities available to run, do resume anyway to start
// something. Also if the top activity on the stack is not the just paused
// activity, we need to go ahead and resume it to ensure we complete an
// in-flight app switch.
mRootActivityContainer.resumeFocusedStacksTopActivities();
}
}
}
if (prev != null) {
prev.resumeKeyDispatchingLocked();
if (prev.hasProcess() && prev.cpuTimeAtResume > 0) {
final long diff = prev.app.getCpuTime() - prev.cpuTimeAtResume;
if (diff > 0) {
final Runnable r = PooledLambda.obtainRunnable(
ActivityManagerInternal::updateForegroundTimeIfOnBattery,
mService.mAmInternal, prev.info.packageName,
prev.info.applicationInfo.uid,
diff);
mService.mH.post(r);
}
}
prev.cpuTimeAtResume = 0; // reset it
}
// Notify when the task stack has changed, but only if visibilities changed (not just
// focus). Also if there is an active pinned stack - we always want to notify it about
// task stack changes, because its positioning may depend on it.
if (mStackSupervisor.mAppVisibilitiesChangedSinceLastPause
|| (getDisplay() != null && getDisplay().hasPinnedStack())) {
mService.getTaskChangeNotificationController().notifyTaskStackChanged();
mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
}
mRootActivityContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS);
}
这里分为两部分,一开始是把launch的activity的状态设置成paused的状态,然后判断有没有重启的标志
是的话就重启,这应该和屏幕旋转有关,以后有时间在分析
else if (prev.hasProcess()) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
+ " wasStopping=" + wasStopping + " visible=" + prev.visible);
if (prev.deferRelaunchUntilPaused) {
// Complete the deferred relaunch that was waiting for pause to complete.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev);
prev.relaunchActivityLocked(false /* andResume */,
prev.preserveWindowOnDeferredRelaunch);
也就是relaunchActivityLocked方法
第二部分有调用了resumeFocusedStacksTopActivities方法,可见这是一个核心方法
很明显
if (!mRootActivityContainer.allPausedActivitiesComplete()) {
if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
"resumeTopActivityLocked: Skip resume: some activity pausing.");
return false;
}
由于刚刚的状态改了,把pausing状态改成了paused了,当然不走这里了,然后进行到第二部分
final ActivityStack lastFocusedStack = display.getLastFocusedStack();
if (lastFocusedStack != null && lastFocusedStack != this) {
// So, why aren't we using prev here??? See the param comment on the method. prev doesn't
// represent the last resumed activity. However, the last focus stack does if it isn't null.
lastResumed = lastFocusedStack.mResumedActivity;
if (userLeaving && inMultiWindowMode() && lastFocusedStack.shouldBeVisible(next)) {
// The user isn't leaving if this stack is the multi-window mode and the last
// focused stack should still be visible.
if(DEBUG_USER_LEAVING) Slog.i(TAG_USER_LEAVING, "Overriding userLeaving to false"
+ " next=" + next + " lastResumed=" + lastResumed);
userLeaving = false;
}
lastResumedCanPip = lastResumed != null && lastResumed.checkEnterPictureInPictureState(
"resumeTopActivity", userLeaving /* beforeStopping */);
}
这里是拿到上一个有焦点的activitystack,然后判断是否等于现在的
activityStack,这里很明显不是,当然由于此前,resume状态被重置过了,所以lastResumed也为null
接下来pause的判断
boolean pausing = getDisplay().pauseBackStacks(userLeaving, next, false);
if (mResumedActivity != null) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Pausing " + mResumedActivity);
pausing |= startPausingLocked(userLeaving, false, next, false);
}
if (pausing && !resumeWhilePausing) {
if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES,
"resumeTopActivityLocked: Skip resume: need to start pausing");
// At this point we want to put the upcoming activity's process
// at the top of the LRU list, since we know we will be needing it
// very soon and it would be a waste to let it get killed if it
// happens to be sitting towards the end.
if (next.attachedToProcess()) {
next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
true /* activityChange */, false /* updateOomAdj */);
}
if (lastResumed != null) {
lastResumed.setWillCloseOrEnterPip(true);
}
return true;
} else if (mResumedActivity == next && next.isState(RESUMED)
&& display.allResumedActivitiesComplete()) {
// It is possible for the activity to be resumed when we paused back stacks above if the
// next activity doesn't have to wait for pause to complete.
// So, nothing else to-do except:
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options);
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Top activity resumed (dontWaitForPause) " + next);
return true;
}
由于mResumeActivity都为null
所以也不会走到onpause里面,然后就开始更改Mainactivity的状态了
if (next.attachedToProcess()) {
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next
+ " stopped=" + next.stopped + " visible=" + next.visible);
// If the previous activity is translucent, force a visibility update of
// the next activity, so that it's added to WM's opening app list, and
// transition animation can be set up properly.
// For example, pressing Home button with a translucent activity in focus.
// Launcher is already visible in this case. If we don't add it to opening
// apps, maybeUpdateTransitToWallpaper() will fail to identify this as a
// TRANSIT_WALLPAPER_OPEN animation, and run some funny animation.
final boolean lastActivityTranslucent = lastFocusedStack != null
&& (lastFocusedStack.inMultiWindowMode()
|| (lastFocusedStack.mLastPausedActivity != null
&& !lastFocusedStack.mLastPausedActivity.fullscreen));
// This activity is now becoming visible.
if (!next.visible || next.stopped || lastActivityTranslucent) {
next.setVisibility(true);
}
// schedule launch ticks to collect information about slow apps.
next.startLaunchTickingLocked();
ActivityRecord lastResumedActivity =
lastFocusedStack == null ? null : lastFocusedStack.mResumedActivity;
final ActivityState lastState = next.getState();
mService.updateCpuStats();
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next
+ " (in existing)");
next.setState(RESUMED, "resumeTopActivityInnerLocked");
也就是说从这里开始activityStack对应的mResumedActivity是MainActivity,然后会间接调用到onActivityStateChanged方法里
void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) {
if (record == mResumedActivity && state != RESUMED) {
setResumedActivity(null, reason + " - onActivityStateChanged");
}
if (state == RESUMED) {
if (DEBUG_STACK) Slog.v(TAG_STACK, "set resumed activity to:" + record + " reason:"
+ reason);
setResumedActivity(record, reason + " - onActivityStateChanged");
if (record == mRootActivityContainer.getTopResumedActivity()) {
// TODO(b/111361570): Support multiple focused apps in WM
mService.setResumedActivityUncheckLocked(record, reason);
}
mStackSupervisor.mRecentTasks.add(record.getTaskRecord());
}
}
这里主要作用是增加Recentask的taskRecord,然后把ams里的mLastResumedActivity设置为mainactivity对应的record
然后会调用远端的onResume方法
next.sleeping = false;
mService.getAppWarningsLocked().onResumeActivity(next);
next.app.setPendingUiCleanAndForceProcessStateUpTo(mService.mTopProcessState);
next.clearOptionsLocked();
transaction.setLifecycleStateRequest(
ResumeActivityItem.obtain(next.app.getReportedProcState(),
getDisplay().mDisplayContent.isNextTransitionForward()));
mService.getLifecycleManager().scheduleTransaction(transaction);
然后会调用ams这里的activityResumed方法,也就差不多了,最后还有一个疑问就是onStop方法在哪里调用的
其实在客户端也就是actiivtyThread中
在处理onResume之后
r.nextIdle = mNewActivities;
mNewActivities = r;
if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r);
Looper.myQueue().addIdleHandler(new Idler());
}
会有一个idler的handler,从而调用远程的activityIdle方法
if (a.activity != null && !a.activity.mFinished) {
try {
am.activityIdle(a.token, a.createdConfig, stopProfiling);
a.createdConfig = null;
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
最终会调用到launcher对应的activityStack的stopActivityLocked方法,来进行stop操作
final void stopActivityLocked(ActivityRecord r) {
if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Stopping: " + r);
if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
if (!r.finishing) {
if (!shouldSleepActivities()) {
if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + r);
if (requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
"stop-no-history", false)) {
// If {@link requestFinishActivityLocked} returns {@code true},
// {@link adjustFocusedActivityStack} would have been already called.
r.resumeKeyDispatchingLocked();
return;
}
} else {
if (DEBUG_STATES) Slog.d(TAG_STATES, "Not finishing noHistory " + r
+ " on stop because we're just sleeping");
}
}
}
if (r.attachedToProcess()) {
adjustFocusedActivityStack(r, "stopActivity");
r.resumeKeyDispatchingLocked();
try {
r.stopped = false;
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to STOPPING: " + r + " (stop requested)");
r.setState(STOPPING, "stopActivityLocked");
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Stopping visible=" + r.visible + " for " + r);
if (!r.visible) {
r.setVisible(false);
}
EventLogTags.writeAmStopActivity(
r.mUserId, System.identityHashCode(r), r.shortComponentName);
mService.getLifecycleManager().scheduleTransaction(r.app.getThread(), r.appToken,
StopActivityItem.obtain(r.visible, r.configChangeFlags));
if (shouldSleepOrShutDownActivities()) {
r.setSleeping(true);
}
Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r);
mHandler.sendMessageDelayed(msg, STOP_TIMEOUT);
} catch (Exception e) {
// Maybe just ignore exceptions here... if the process
// has crashed, our death notification will clean things
// up.
Slog.w(TAG, "Exception thrown during pause", e);
// Just in case, assume it to be stopped.
r.stopped = true;
if (DEBUG_STATES) Slog.v(TAG_STATES, "Stop failed; moving to STOPPED: " + r);
r.setState(STOPPED, "stopActivityLocked");
if (r.deferRelaunchUntilPaused) {
destroyActivityLocked(r, true, "stop-except");
}
}
}
}