Pause前台显示Activity,Resume目标Activity
Android四大组件源码实现详解系列博客目录:
Android应用进程创建流程大揭秘
Android四大组件之bindService源码实现详解
Android四大组件之Activity启动流程源码实现详解概要
Android四大组件之Activity启动流程源码实现详解(一)
Android四大组件之Activity启动流程源码实现详解(二)
Activity启动流程(三)- Activity Task调度算法复盘分析
Activity启动流程(四)- Pause前台显示Activity,Resume目标Activity
前言
还记得我们在前面博客Android四大组件之Activity启动流程源码实现详解(二)和Activity启动流程(三)- Activity Task调度算法复盘分析中做的艰苦卓越的斗争吗!这场战役之惨烈,战况之持久前所未有!虽然过程是疼苦的,但是战果也是显赫和令人满意的,通过上述战役我们取得了如下的阶段性成果:
- 初始化了Activity启动状态
- 计算了启动launchFlag
- 计算了调用者的ActivityStack
- 检查了是否存在复用的TaskRecord
- 对于存在复用的TaskRecord则进行相应的ActivityStack、TaskRecord的移动(说实话,我也没有真的搞懂,希望这块比较有经验的小伙们能和我一起学习)
- 计算了当前启动Activity所属的TaskRecord
- 把当前启动的Activity放到所属TaskRecord的栈顶
- 并且前面的TaskRecord放到了ActivityStack的栈顶
总而言之经过上述一顿猛虎般的操作,此时要启动的目标Actvity及其对应的task位置以及ActivityStack已经安排妥当,现在可以准备接下来的相关工作了,那么在本篇博客中我们将继续分析system_server对Activity启动请求的处理流程:
- system_server进程通过AMS处理启动Activity请求:
5.Pause前台Activity
6.Resume请求的目标Activity
7.AMS请求zygote进程为目标Activity创建所属进程
注意:本篇的介绍是基于Android 7.xx平台为基础的,其中涉及的代码路径如下:
frameworks/base/services/core/java/com/android/server/am/
--- ActivityManagerService.java
--- ProcessRecord.java
--- ActivityRecord.java
--- ActivityResult.java
--- ActivityStack.java
--- ActivityStackSupervisor.java
--- ActivityStarter.java
--- TaskRecord.java
frameworks/base/services/core/java/com/android/server/pm/
--- PackageManagerService.java
frameworks/base/core/java/android/content/pm/
--- ActivityInfo.java
frameworks/base/core/java/android/app/
--- IActivityManager.java
--- ActivityManagerNative.java (内部包含AMP)
--- ActivityManager.java
--- AppGlobals.java
--- Activity.java
--- ActivityThread.java(内含AT)
--- LoadedApk.java
--- AppGlobals.java
--- Application.java
--- Instrumentation.java
--- IApplicationThread.java
--- ApplicationThreadNative.java (内部包含ATP)
--- ActivityThread.java (内含ApplicationThread)
--- ContextImpl.java
并且在后续的源码分析过程中为了简述方便,会将做如下简述:
- ApplicationThreadProxy简称为ATP
- ActivityManagerProxy简称为AMP
- ActivityManagerService简称为AMS
- ActivityManagerNative简称AMN
- ApplicationThreadNative简称ATN
- PackageManagerService简称为PKMS
- ApplicationThread简称为AT
- ActivityStarter简称为AS,这里不要和ActivityServices搞混淆了
- ActivityStackSupervisor简称为ASS
在正式开始今天博客相关源码分析前,还是先奉上调用的时序图以便小伙们先从整体上有个清晰的概括,然后再从细节开撸!
一.Pause处于Resume状态Actvity以及Resume目标Activity
战斗还没有结束,革命尚未成功仍需努力!让我们带着前面博客Android四大组件之Activity启动流程源码实现详解(二)未完成使命继续前进!
//[ActivityStarter.java]
private int startActivityUnchecked(final ActivityRecord r,
ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession,
IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume,
ActivityOptions options,
TaskRecord inTask) {
...
if (mDoResume) {
if (!mLaunchTaskBehind) {
mService.setFocusedActivityLocked(mStartActivity, "startedActivity");
}
final ActivityRecord topTaskActivity = mStartActivity.task.topRunningActivityLocked();
if (!mTargetStack.isFocusable()//当前的目标Stack被设置成了焦点所以不会走此分支
|| (topTaskActivity != null && topTaskActivity.mTaskOverlay
&& mStartActivity != topTaskActivity)) {
...
} else {
//开始resume,详见章节1.1
mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
mOptions);
}
} else {
mTargetStack.addRecentActivityLocked(mStartActivity);
}
return START_SUCCESS;
...
}
搞了这么久,发起端Activity和目标Actvity的生命周期一个都没有看到,小伙们是不是心里有些慌了! 不急,这不它就来了,让我们先来看看Acitivyt A启动Activty B的正常生命周期调度:
---> Activity A onCreate
---> Activity A onStart
---> Activity A onResume
---> Activity A onPause
---> Activity B onCreate
---> Activity B onStart
---> Activity B onResume
---> Activty A onStop
而我们接下来会沿着上面的主线进行相关的分析,这里我们从A的onPause为起始段开始本篇博客的分析。此时我们将上述场景Activity A启动Activity B带入下面的相关分析中。
1.1 ASS.resumeFocusedStackTopActivityLocked
让我们对ActivityStackSupervisor中的resumeFocusedStackTopActivityLocked继续分析,其中Android中对于Activity的启动主要表现在如下两个方面:
- 第一:AMS对于Activity比较复杂的部分即为Task任务栈和Stack的处理,这部分详见Activity启动流程(三)- Activity Task调度算法复盘分析
- 第二:本章节要重点介绍的resumed相关操作,
并且关于这两部分读者最好参考我前面的博客先假定某种启动模式,然后进行相关的分析,否则很容易陷入代码中而不能自拔。而我们这里的resumeFocusedStackTopActivityLocked其实对应的就是Activity的生命周期。
//[ActivityStackSupervisor.java]
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack,
ActivityRecord target,
ActivityOptions targetOptions) {
if (targetStack != null && isFocusedStack(targetStack)) {
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);//详见章节1.1.1
}
...
}
让我们单刀直入直捣黄龙,接着分析ActivityStack的resumeTopActivityUncheckedLocked方法(不是我不分析,确实是因为没有啥好分析的)。
1.1.1 ActivityStack.resumeTopActivityUncheckedLocked
//[ActivityStack.java]
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
if (mStackSupervisor.inResumeTopActivity) {
// Don't even start recursing.
return false;
}
boolean result = false;
try {
...
result = resumeTopActivityInnerLocked(prev, options);//详见章节1.2
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
return result;
}
这里没有过多可以介绍的,让我们单刀直入直捣黄龙,接着分析其方法resumeTopActivityInnerLocked,在分析这个方法之前小伙们该上厕所的可以上厕所了,喝水的可以喝水了,因为这又是一个重量级的方法。
1.2 ActivityStack.resumeTopActivityInnerLocked
在正式开始分析该方法之前,我们先来看看该方法的入参,方法入参的名字挺奇怪的!
参数类型 | 参数名称 | 参数功能 |
---|---|---|
ActivityRecord | prev | 目标Activity的相关信息 |
ActivityOptions | options | 额外附加信息 |
不知各位小伙们发现没有,在上一个方法中发起调用时,传入的参数名称是target,表示待启动的ActivityRecord,但这里摇身一变,参数名称却是prev,看参数意思是表示之前启动的ActivityRecord,即将要进入Pausing状态的那个Activity,到底意欲几何,是不是谷歌的哥哥搞错了啊?这里小伙们先暂且将该疑问放在一边,待我们后续的源码中一一揭秘。此时我们要重点关注,此时的入参为位目标ActivityRecord,虽然它换了一个马甲叫做prev。
//[ActivityStack.java]
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
if (!mService.mBooting && !mService.mBooted) {
// 如果系统还未启动完毕,那AMS还不能正常工作,所以也不能显示Activity,主要是为防止没有开机启动完成
return false;
}
//此处忽略
ActivityRecord parent = mActivityContainer.mParentActivity;
...
// 当前AS中可能存在一些正处于Intializing状态的ActivityRecord,
// 如果这些ActivityRecord不是位于栈顶,而且正在执行窗口启动动画,
// 那么,就需要取消这些Activity的启动动画。
mStackSupervisor.cancelInitializingActivities();
final ActivityRecord next = topRunningActivityLocked();
//这个变量是表示是否回调Activity中的onUserLeaveHint和onUserInteraction函数
final boolean userLeaving = mStackSupervisor.mUserLeaving;
mStackSupervisor.mUserLeaving = false;
final TaskRecord prevTask = prev != null ? prev.task : null;
if (next == null) { //这个表示如果当前ActivityStack不存在待启动的Activity,那么会启动Launcher桌面
final String reason = "noMoreActivities";
final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack()
? HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
// 当前AS不是全屏显示,则需要将焦点切换到下一个待显示的AS
if (!mFullscreen && adjustFocusToNextFocusableStackLocked(returnTaskType, reason)) {
return mStackSupervisor.resumeFocusedStackTopActivityLocked(
mStackSupervisor.getFocusedStack(), prev, null);
}
ActivityOptions.abort(options);
// 默认情况下,Stack都是占据全屏的,所以,当前Stack如果没有要显示的Activity,则会要求显示桌面
return isOnHomeDisplay() &&
mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, reason);
}
next.delayedResume = false;
//检查要启动的Activity 组件是否等于当前被激活的 Activity 组件,如果等于
//并且处于 RESUMED 状态,直接返回,我们前面演示的启动情况很显然不满足条件
if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
mStackSupervisor.allResumedActivitiesComplete()) {
//当前正在显示的Activity正好就是下一个待显示的Activity,
// 那么,就中断对目标ActivityRecord的调度
mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
ActivityOptions.abort(options);
return false;
}
final TaskRecord nextTask = next.task;
if (prevTask != null && prevTask.stack == this &&
prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {
...
}
// 系统进入休眠状态,当前Stack的栈顶Activity已经处于Paused状态
// 那么,中断待显示Activity的相关调度(有点拗口,学习源码就是这么枯燥的事情)
if (mService.isSleepingOrShuttingDownLocked()
&& mLastPausedActivity == next
&& mStackSupervisor.allPausedActivitiesComplete()) {
mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
ActivityOptions.abort(options);
return false;
}
...
mStackSupervisor.mStoppingActivities.remove(next);
mStackSupervisor.mGoingToSleepActivities.remove(next);
next.sleeping = false;
mStackSupervisor.mWaitingVisibleActivities.remove(next);
// 如果当前ASS中还有ActivityRecord不是处于PAUSED, STOPPED或STOPPING这三个状态之一,
// 那么,需要先等这些ActivityRecord进入停止状态
if (!mStackSupervisor.allPausedActivitiesComplete()) {
return false;
}
分析至此,让我们先缓缓,停下前进的脚步看看我们来时的路!前面的代码片段,主要是做一些初始化和可能的"异常"处理工作。虽然我们待显示的目标ActivityRecord已经位于栈顶,但要真正将其显示到前台来,即执行目标Activity的onCreate/onStart/onResume等状态,这一路有很多障碍和初始化工作还处理,或者说还有很多前提条件需要满足,譬如,系统要休眠时,当前启动目标Activity过程要中断;当前ASS中有Activity正处于Pausing状态时,也需要等相关Activity执行完毕才行。我们可以将上述的相关工作认为是准备阶段!前路漫漫是征途,我将上下而求索!
//[ActivityStack.java]
mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);
final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
//这里是为了演示使用
//ASS.java
boolean pauseBackStacks(boolean userLeaving, boolean resuming, boolean dontWait) {
boolean someActivityPaused = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
if (!isFocusedStack(stack) && stack.mResumedActivity != null) {
someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
dontWait);
}
}
}
return someActivityPaused;
}
//此时要带入真是场景了,此时的mResumedActivity表示目标Stack栈中处于Resume状态的Activity,那么在此场景下就是Activity A,这个因该比较容易理解
if (mResumedActivity != null) {
//当前resumd状态activity不为空,则需要先暂停该Activity
// pause当前栈的activity,即执行Activity的生命周期onPause
pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);//详见章节1.3
}
if (pausing) { //当前有正在pause的Activity,尼玛按照我们场景Activity A启动Activity B,那不是到此就结束了啊,直接返回了,事实就是这样的,尼玛是不是走错片场了,后续你就知道了
if (next.app != null && next.app.thread != null) {
mService.updateLruProcessLocked(next.app, true, null);
}
return true;
}
//检查要启动的Activity 组件是否等于当前被激活的 Activity 组件,如果等于
//并且处于 RESUMED 状态,直接返回,我们前面演示的启动情况很显然不满足条件
else if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
mStackSupervisor.allResumedActivitiesComplete()) {
mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
ActivityOptions.abort(options);
return true;
}
我们在此就此打住,先不往后分析resumeTopActivityInnerLocked的相关逻辑了,实时上启动目标Acitivity第一次进入该方法时也会从此处返回,事实就是这样的,尼玛是不是走错片场了,后续你就知道了。让我们接着后续分析前面章节1.2提出的问题也会解决了,至于此处为啥在此就return也会解决了。
1.3 Pause前台显示的Activity
我们对要显示的目标Activity已经做好入栈工作了,就是放在Stack的栈顶,我们可以通过方法ActivityStack.topRunningActivityLocked可以找到它。然后如果当前要Resume的目标Activity不是之前已经Resume的Activity,那么必须将Pause之前的Activity才行,而这部分的具体工作分两部分完成:
- Pause其他所有已经focus的任务栈的mResumedActivity,调用方法ASS.pauseBackStacks执行
- Pause当前任务栈的mResumedActivity
最后上述两步都会调到核心方法,ActivityStack.startPausingLocked,而这也是我们本章节将要介绍的:
//[ActivityStack.java]
final boolean startPausingLocked(boolean userLeaving,
boolean uiSleeping, //此时传递进来的参数为false
boolean resuming,//此时传递进来的参数为true
boolean dontWait)
{
//判断当前的Stack栈中是否存在正在pausing的Activity
if (mPausingActivity != null) {
if (!mService.isSleepingLocked()) {
completePauseLocked(false);
}
}
//获取当前Stack栈中处于Resume状态的Activity,在我们当前的环境下就是Activity A了
ActivityRecord prev = mResumedActivity;
if (prev == null) {
if (!resuming) {
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
return false;
}
...
// 变更ActivityStack中pauseActivity的记录,此处是重点
mResumedActivity = null;
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.state = ActivityState.PAUSING;
prev.task.touchActiveTime();
clearLaunchTime(prev);
...
// 通知APP执行发起端的pause操作
if (prev.app != null && prev.app.thread != null) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
try {
EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
prev.userId, System.identityHashCode(prev),
prev.shortComponentName);
mService.updateUsageStats(prev, false);
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait);//详见章节1.3.1
} catch (Exception e) {
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
} else {
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
//获取锁,防止休眠
if (!uiSleeping && !mService.isSleepingOrShuttingDownLocked()) {
mStackSupervisor.acquireLaunchWakelock();
}
if (mPausingActivity != null) {
if (!uiSleeping) {
prev.pauseKeyDispatchingLocked();
} else if (DEBUG_PAUSE) {
}
if (dontWait) {
completePauseLocked(false);
return false;
} else {
//这个是经典的ANR埋雷,监控APP是否pause超时,时间只有500ms
Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
msg.obj = prev;
prev.pauseTime = SystemClock.uptimeMillis();
mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
return true;
}
} else {
...
}
}
在正式开始上述的源码分析前,我们先来阐述一个重要的知识点,即在这个调用过程中涉及到两个进程,不妨令发起startActivity的发起进程记为进程Process_A,AMS Service所属进程记为进程Process_B;那么进程Process_A通过Binder机制(采用IActivityManager接口)向进程Process_B发起请求服务,进程Process_B则通过Binder机制(采用IApplicationThread接口)向进程Process_A发起请求服务。也就是说进程Process_A与进程Process_B能相互间主动发起请求,进而完成进程通信,但是这里有一点需要注意IApplicationThread的Binder实体端并没有注册到servicemanager进程中,它是一个依赖于实名Binder的匿名Binder。
这里涉及IApplicationThread很重要,它串联起了AMS对App进程的生命周期及其其它的控制,那么下面直接把其相关的类图展示如下:
这里的IApplicationThread与IActivityManager的Binder通信原理一样,ATP作为Binder通信的客户端,ATN作为Binder通信的服务端,其中ApplicationThread继承ATN类,覆写其中的部分方法。
并且在目标Activity A的进程创建的时候会存在如下的流程关系(这里小伙们可以先记住,后面再理解)
前面分析了一大堆主要想说明如下问题:
- 这里的IApplicationThread和IActivityManager类似,是可以实现Binder跨进程通信的
- 客户端进程可以通过AMP实现和AMS(system_server进程)的通信
- AMS(system_server进程)可以通过ATP和客户端发起进程AT通信
如果小伙们对上述Binder跨进程调用不是很清晰的,可以参见系列博客Android Binder框架实现源码分析,这里就不过多讲述了,总之通过prev.app.thread.schedulePauseActivity实际上调用的就是ApplicationThread的schedulePauseActivity方法中去了,其调用过程可以使用下面的伪代码来表示:
ATP.schedulePauseActivity()--->
BinderProxy.transact() --->
BpBinder.transact()--->
binder驱动传输--->
JavaBBinder.onTransact()--->
ATN.onTransact()--->
ATN.schedulePauseActivity()
1.3.1 AT.schedulePauseActivity处理Pause请求
通过ATP的努力和我们的Binder框架的协助,我们跨越万水千山,完成了system_server所在进程到发起端所在目的端进程调用过程,让我们接着分析看看目的端进程是怎么处理schedulePauseActivity的RPC请求的。我好难啊!
//[ActivityThread.java]
private class ApplicationThread extends ApplicationThreadNative {
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) {
int seq = getLifecycleSeq();
sendMessage(
finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
token,
(userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0),
configChanges,
seq);//详见1.3.2
}
}
巧用ActivityThread的主线程的Handler发送消息,这里我们可以总结一下规律,通常AMS通过ATP发送过来的消息,遵循如下的处理逻辑,如下
scheduleXXX() ---> handleXXX()
1.3.2 H.handleMessage
//ActivityThread.java
private class H extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
...
case PAUSE_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
SomeArgs args = (SomeArgs) msg.obj;
handlePauseActivity((IBinder) args.arg1, false,
(args.argi1 & USER_LEAVING) != 0, args.argi2,
(args.argi1 & DONT_REPORT) != 0, args.argi3);//详见章节1.3.3
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
...
}
}
}
1.3.3 AT.handlePauseActivity
//[ActivityThread.java]
private void handlePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport, int seq) {
//获取需要
ActivityClientRecord r = mActivities.get(token);
if (r != null) {
if (userLeaving) {
performUserLeavingActivity(r);
}
r.activity.mConfigChangeFlags |= configChanges;
//执行Activity的onPause操作
performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");//详见章节1.3.4
if (r.isPreHoneycomb()) {
QueuedWork.waitToFinish();
}
if (!dontReport) {
try {
//通知AMS已经Pause成功了
ActivityManagerNative.getDefault().activityPaused(token);//详见章节1.3.5
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
mSomeActivitiesChanged = true;
}
}
无需多言,直接进入下一关,打怪升级!
1.3.4 AT.performPauseActivity
final Bundle performPauseActivity(IBinder token, boolean finished,
boolean saveState, String reason) {
ActivityClientRecord r = mActivities.get(token);
return r != null ? performPauseActivity(r, finished, saveState, reason) : null;
}
final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
boolean saveState, String reason) {
...
performPauseActivityIfNeeded(r, reason);
...
return !r.activity.mFinished && saveState ? r.state : null;
}
private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {
if (r.paused) {
// You are already paused silly...
return;
}
try {
r.activity.mCalled = false;
mInstrumentation.callActivityOnPause(r.activity);
EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(),
r.activity.getComponentName().getClassName(), reason);
if (!r.activity.mCalled) {
...
}
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
...
}
r.paused = true;
}
还是原来的配方,还是原来的味道,最终通过Instrumentation类回调了Activity实例的onPause方法,如下:
//[Instrumentation.java]
public void callActivityOnPause(Activity activity) {
activity.performPause();
}
见证奇迹的时刻要到了,让我们拭目以待:
//[Activity.java]
final void performPause() {
mDoReportFullyDrawn = false;
mFragments.dispatchPause();
mCalled = false;
onPause();//执行Activity的onPause方法
mResumed = false;
if (!mCalled && getApplicationInfo().targetSdkVersion
>= android.os.Build.VERSION_CODES.GINGERBREAD) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
" did not call through to super.onPause()");
}
mResumed = false;
}
尼玛,太不容易了,终于回调到了ASS中处于Resume状态的Activity的onPause方法,这其中涉及的弯弯绕绕可真多啊。网上有有博主说我们在启动一个Activity的时候最先被执行的是栈顶的Activity的onPause方法,我个人不是很赞同上述说法,应该是目标Activity所属Stack栈存在Resume状态的Activity时会执行其onPause方法,否则执行的就是其它Stack栈中的了。
1.3.5 AMS.activityPaused
继续回到章节1.3.3未完成之实名,在将当前显示的Activity执行onPause之后,在该方法的最后面执行了ActivityManagerNative.getDefault().activityPaused(token);方法,这是应用进程告诉system_server服务进程,当前显示的Activity已经执行完成onPause方法了,通过前面我们的分析,我们知道这句话最终会被ActivityManagerService的activityPaused方法执行了!,其调用流程可以使用如下的伪代码来表述:
AMP.activityPaused(...)--->
BinderProxy.transact(...) --->
BpBinder.transact(...)--->
binder驱动传输--->
JavaBBinder.onTransact(...)--->
AMN.onTransact(..)--->
AMN.activityPaused(...)
//[AMS.java]
public final void activityPaused(IBinder token) {
final long origId = Binder.clearCallingIdentity();
synchronized(this) {
//获取已经pause的Activity所属Stack
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
stack.activityPausedLocked(token, false);
}
}
Binder.restoreCallingIdentity(origId);
}
在activityPaused内部继续调用ActivityStack的activityPausedLocked方法进行下一步的处理,让我们接着分析:
final void activityPausedLocked(IBinder token, boolean timeout) {
final ActivityRecord r = isInStackLocked(token);
if (r != null) {
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
if (mPausingActivity == r) {
completePauseLocked(true);//此处传入的参数为true
return;
} else {
...
}
}
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
接着继续分析completePauseLocked,注意此时传入的参数为true,我们继续分析:
private void completePauseLocked(boolean resumeNext) {
ActivityRecord prev = mPausingActivity;
...
if (resumeNext) {
final ActivityStack topStack = mStackSupervisor.getFocusedStack();
if (!mService.isSleepingOrShuttingDownLocked()) { //会进入此分支,继续章节1.1.1的逻辑
//此时的prev为前台显示已经pause的Activity
mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
} else {
mStackSupervisor.checkReadyForSleepLocked();
ActivityRecord top = topStack.topRunningActivityLocked();
if (top == null || (prev != null && top != prev)) {
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
}
...
}
经过了一系列的逻辑之后,又调用了resumeFocusedStackTopActivityLocked方法,又回到了章节1.1解析的方法中了,此时的传入的prev就是我们已经pause的Activity的了,而不是目标Activiyt了,现在章节1.2最后的谜题可以解决了。感觉resumeFocusedStackTopActivityLocked不是这么简单啊!
1.3.6 Pause前台显示的Activity小结
虽然本人也反对分析源码过程中大量堆砌源码,但是有时候又不得不为之,因为如果不放上源码调用逻辑,整个流程下来就不是很清晰了,这个也木有办法,臣妾也不想啊!好吗,我们来总结一下Pause前台显示的Activity的流程,如果站在进程交互的角度出发,其中Pause前台显示的Activity牵涉到两次的跨进程调用:
-
AMS通过ATP通知前台Activity进行相关的onPause操作
-
前台显示的Activity执行onPause成功之后通过AMP跨进程通知AMS已经成功执行
其中整个Pause前台显示的Activity的流程可以使用如下的伪代码流程来表示,如下:
//AMS端
ActivityStack.startPausingLocked(...) --->
ATP.schedulePauseActivity(...) --->
BinderProxy.transact(...) --->
BpBinder.transact(...) --->
binder驱动传输 --->
//前台显示Activity端
JavaBBinder.onTransact(...) --->
ATN.onTransact(...) --->
ATN.schedulePauseActivity(...) --->
ApplicationThread.schedulePauseActivity(...) --->
ActivityThread.H.handleMessage(...) --->
ActivityThread.handlePauseActivity(...) --->
ActivityThread.performPauseActivity(...) --->
ActiivtyThread.performPauseActivityIfNeeded(...) --->
Instrumentation.callActivityOnPause(...) --->
Activity.performPause(...) --->
Activity.onPause(...) --->
AMP.activityPaused(...)--->
BinderProxy.transact(...) --->
BpBinder.transact(...)--->
binder驱动传输--->
//AMS端
JavaBBinder.onTransact(...)--->
AMN.onTransact(..)--->
AMN.activityPaused(...)
1.4 Resume目标Activity
爱的魔力转圈圈,让我们继续第二轮回,重新开始源码的分析
//[ActivityStackSupervisor.java]
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack,
ActivityRecord target, //此时的target为前台已经处于pause状态的Activity,如果在我们当前的场景下即为Activity A
ActivityOptions targetOptions) {
if (targetStack != null && isFocusedStack(targetStack)) {
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
...
}
继续往下分析此时我想各位应该明白我们在章节1.2的疑问了
//[ActivityStack.java]
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
...
boolean result = false;
try {
...
result = resumeTopActivityInnerLocked(prev, options);
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
return result;
}
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
if (!mService.mBooting && !mService.mBooted) {
// 如果系统还未启动完毕,那AMS还不能正常工作,所以也不能显示Activity,主要是为防止没有开机启动完成
return false;
}
//此处忽略
ActivityRecord parent = mActivityContainer.mParentActivity;
...
// 当前AS中可能存在一些正处于Intializing状态的ActivityRecord,
// 如果这些ActivityRecord不是位于栈顶,而且正在执行窗口启动动画,
// 那么,就需要取消这些Activity的启动动画。
mStackSupervisor.cancelInitializingActivities();
final ActivityRecord next = topRunningActivityLocked();
//这个变量是表示是否回调Activity中的onUserLeaveHint和onUserInteraction函数
final boolean userLeaving = mStackSupervisor.mUserLeaving;
mStackSupervisor.mUserLeaving = false;
final TaskRecord prevTask = prev != null ? prev.task : null;
if (next == null) { //这个表示如果当前ActivityStack不存在待启动的Activity,那么会启动Launcher桌面
final String reason = "noMoreActivities";
final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack()
? HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
// 当前AS不是全屏显示,则需要将焦点切换到下一个待显示的AS
if (!mFullscreen && adjustFocusToNextFocusableStackLocked(returnTaskType, reason)) {
return mStackSupervisor.resumeFocusedStackTopActivityLocked(
mStackSupervisor.getFocusedStack(), prev, null);
}
ActivityOptions.abort(options);
// 默认情况下,Stack都是占据全屏的,所以,当前Stack如果没有要显示的Activity,则会要求显示桌面
return isOnHomeDisplay() &&
mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, reason);
}
next.delayedResume = false;
//检查要启动的Activity 组件是否等于当前被激活的 Activity 组件,如果等于
//并且处于 RESUMED 状态,直接返回,我们前面演示的启动情况很显然不满足条件
if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
mStackSupervisor.allResumedActivitiesComplete()) {
//当前正在显示的Activity正好就是下一个待显示的Activity,
// 那么,就中断对目标ActivityRecord的调度
mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
ActivityOptions.abort(options);
return false;
}
final TaskRecord nextTask = next.task;
if (prevTask != null && prevTask.stack == this &&
prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {
...
}
// 系统进入休眠状态,当前Stack的栈顶Activity已经处于Paused状态
// 那么,中断待显示Activity的相关调度(有点拗口,学习源码就是这么枯燥的事情)
if (mService.isSleepingOrShuttingDownLocked()
&& mLastPausedActivity == next
&& mStackSupervisor.allPausedActivitiesComplete()) {
mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
ActivityOptions.abort(options);
return false;
}
...
mStackSupervisor.mStoppingActivities.remove(next);
mStackSupervisor.mGoingToSleepActivities.remove(next);
next.sleeping = false;
mStackSupervisor.mWaitingVisibleActivities.remove(next);
// 如果当前ASS中还有ActivityRecord不是处于PAUSED, STOPPED或STOPPING这三个状态之一,
// 那么,需要先等这些ActivityRecord进入停止状态
if (!mStackSupervisor.allPausedActivitiesComplete()) {
return false;
}
分析至此,让我们先缓缓,停下前进的脚步看看我们来时的路!前面的代码片段,主要是做一些初始化和可能的"异常"处理工作。虽然我们待显示的目标ActivityRecord已经位于栈顶,但要真正将其显示到前台来,即执行目标Activity的onCreate/onStart/onResume等状态,这一路有很多障碍和初始化工作还处理,或者说还有很多前提条件需要满足,譬如,系统要休眠时,当前启动目标Activity过程要中断;当前ASS中有Activity正处于Pausing状态时,也需要等相关Activity执行完毕才行。我们可以将上述的相关工作认为是准备阶段!前路漫漫是征途,我将上下而求索!
//[ActivityStack.java]
mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);
final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
//此时要带入真是场景了,此时的mResumedActivity表示目标Stack栈中处于Resume状态的Activity,通过前面的分析可以此时没有处于Resume状态的Activty了,所以不会走入此分支
if (mResumedActivity != null) {
....
}
if (pausing) { //也不会进入此分支可以往后续分析了
if (next.app != null && next.app.thread != null) {
mService.updateLruProcessLocked(next.app, true, null);
}
return true;
}
//检查要启动的Activity 组件是否等于当前被激活的 Activity 组件,如果等于
//并且处于 RESUMED 状态,直接返回,我们前面演示的启动情况很显然不满足条件
else if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
mStackSupervisor.allResumedActivitiesComplete()) {
mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
ActivityOptions.abort(options);
return true;
}
在前面章节1.3的最后我们知道当前台Activity被执行pause以后,会回调activityPaused通知AMS,然后AMS会执行completePauseLocked。该函数也会调用resumeTopActivityInnerLocked。这一次,由于所有resumedActivity都已经paused了,所以返回的结果pausing为false,所以可以继续进行目标activity的resume工作。让我们对相关的流程继续分析!
//[ActivityStack.java]
//对已经Pause的Activity继续处理,主要是通知WMS做进一步的处理
if (prev != null && prev != next) {
if (!mStackSupervisor.mWaitingVisibleActivities.contains(prev)
&& next != null && !next.nowVisible) {
mStackSupervisor.mWaitingVisibleActivities.add(prev);
} else {
if (prev.finishing) {
mWindowManager.setAppVisibility(prev.appToken, false);
} else {
}
}
}
try {
// 通过PackageManager修改待启动Package的状态
AppGlobals.getPackageManager().setPackageStoppedState(
next.packageName, false, next.userId);
} catch (RemoteException e1) {
} catch (IllegalArgumentException e) {
}
...
ActivityStack lastStack = mStackSupervisor.getLastStack();
if (next.app != null && next.app.thread != null) { //如果目的端进程已经创建,即要启动的目标Activity所属进程已经存在
...
next.state = ActivityState.RESUMED;
mResumedActivity = next;
next.task.touchActiveTime();
mRecentTasks.addLocked(next.task);
mService.updateLruProcessLocked(next.app, true, null);
updateLRUListLocked(next);
mService.updateOomAdjLocked();
...
try {
...
next.sleeping = false;
mService.showUnsupportedZoomDialogIfNeededLocked(next);
mService.showAskCompatModeDialogLocked(next);
next.app.pendingUiClean = true;
next.app.forceProcessStateUpTo(mService.mTopProcessState);
next.clearOptionsLocked();
//执行目的端Activity的scheduleResumeActivity操作
next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
mService.isNextTransitionForward(), resumeAnimOptions);
...
} catch (Exception e) {
...
}
try {
completeResumeLocked(next);
} catch (Exception e) {
//处理异常
requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,
"resume-exception", true);
return true;
}
} else { //当目标Activity所属进程没有启动的时候,则会创建进程
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
} else {
if (SHOW_APP_STARTING_PREVIEW) {
next.showStartingWindow(null, true);
}
}
//创建目标Activity进程
mStackSupervisor.startSpecificActivityLocked(next, true, true);
}
return true;
}
到这里终于快要告一段落了,此处的逻辑主要分为两个分支:
- 如果要启动的目标Activity所属进程已经创建,则直接通过ATP调用目标进程的ActivityThread执行相关的Activity的onCreate等相关生命周期
- 如果目标Activity所属进程没有创建,则通过startSpecificActivityLocked方法创建目标进程,经过层层调用最后会调用到AMS.attachApplicationLocked, 然后再执行resumeTopActivityInnerLocked继续resume操作这个逻辑我想也是小伙们最关心的, 我们后续从这个地方开撸
1.5 Pause前台显示Activity,Resume目标Activity小结
Pause前台显示Activity,Resume目标Activity到这里就基本完结了,是时候停下前进的脚步回过头来看看了!在上述过程中我们会进行两次resumeTopActivityInnerLocked方法:
- 第一次是将所有resumedActivity进行pause,此时流程不会继续往下进行而是待前台显示的Activity真正执行pause后,然后回调AMS继续第二执行resumeTopActivityInnerLocked相关操作
- 由于此时所有处于Resume状态的Activity已经都被Pause了,所以继续往下执行,此时会判断目标Activity所属进程是否创建,如果创建则直接执行目标Activity的生命周期,如果没有创建则会创建目标Activity所属进程,进而再执行下一步操作
对于上述的整个流程,可以使用下述的图示来表达:
其中红色箭头表示Binder跨进程调用
黄色框表示的是发起端进程
紫色框表示的是AMS所属system_server进程
红色框表示的是目标Activity所属进程
蓝色框表示的前台处于Resume的Activity所属进程
总结
Activity启动流程(四)- Pause前台显示Activity,Resume目标Activity这里就要告一段落了,从前面的分析可以看出来,此时我们已将将需要Pause前台Activity已经Pause,接下来就是专心的来Resume目标Activity了,如果此时是冷启动的目标Activity那么就会先期进行目标Activity目标所属进程的创建,然后接着继续Resume目标Activity,如果是热启动就简单一些了直接执行目标Activity相关的onCretate等相关的操作。好了今天就到这里了,是时候说再见了!希望小伙们能点赞和关注,谢谢!