文章目录
- 前言
- 源码探究
- Activity pause阶段
- 超时的设置
- LAUNCH_TIMEOUT_MSG
- PAUSE_TIMEOUT_MSG
- mHandler的由来
- 超时的触发
- LAUNCH_TIMEOUT_MSG
- PAUSE_TIMEOUT_MSG
- 超时的取消
- Application launch阶段
- 超时的设置
- 超时的触发
- 超时的取消
- Activity launch阶段
- 超时的设置
- 超时的触发
- 超时的取消
- Activity stop阶段
- 超时的设置
- 超时的触发
- 超时的取消
- Activity destroy阶段
- 超时的设置
- 超时的触发
- 超时的取消
- 总结
前言
在Activity启动过程中,ActivityManagerService会与APP进程进行交互,调度APP进程上的Activity的生成和初始化,以及生命周期的逐步切换和回调。
在这期间的调度交互中ActivityManagerService需要知道APP进程端的执行结果来进行下一步操作,因此ActivityManagerService需要一个超时判定机制,来应对APP进程端执行过久或无响应时的情况。
例如,当目标Activity所属进程未启动时,ActivityManagerService需要先请求Zygote创建进程,然后等待进程创建完毕后继续启动目标Activity,那么AMS如何监听进程启动是否太久呢?还有当启动目标Activity前,会先pause当前正显示的Activity,之后才显示目标Activity,那么AMS是否会无限期等待?
源码探究
文中源码基于Android 9.0
ActivityManagerService在调度Activity的各个阶段都需要超时处理,这里按照《Activity启动流程总结-生命周期》中的过程来分阶段看。
Activity pause阶段
Activity启动流程中,首先需要暂停当前正在显示的Activity。
超时的设置
[ActivityStack.java]
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
ActivityRecord resuming, boolean pauseImmediately) {
// ···
ActivityRecord prev = mResumedActivity;
// ···
mPausingActivity = prev;
// ···
if (prev.app != null && prev.app.thread != null) {
try {
// 调度APP进程执行对应Activity的pause行为
mService.getLifecycleManager().scheduleTransaction(prev.app.thread, 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()) {
// 获取Wakelock并设置超时监听
mStackSupervisor.acquireLaunchWakelock();
}
if (mPausingActivity != null) {
// ···
// pauseImmediately默认为false
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) {
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
return false;
}
}
该方法中会设置两个超时,在通过scheduleTransaction方法调度Activity进行pause后,就调用acquireLaunchWakelock和schedulePauseTimeout方法进行超时设置。
LAUNCH_TIMEOUT_MSG
[ActivityStackSupervisor.java]
void acquireLaunchWakelock() {
if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) {
throw new IllegalStateException("Calling must be system uid");
}
mLaunchingActivity.acquire();
if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
// To be safe, don't allow the wake lock to be held for too long.
mHandler.sendEmptyMessageDelayed(LAUNCH_TIMEOUT_MSG, LAUNCH_TIMEOUT);
}
}
可以看出这里是通过mHandler发送延迟消息的方式来进行超时设置,what为LAUNCH_TIMEOUT_MSG,LAUNCH_TIMEOUT为10s。
PAUSE_TIMEOUT_MSG
[ActivityStack.java]
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...");
}
通过mHandler发送延迟消息的方式来进行超时设置,Message的what赋值为PAUSE_TIMEOUT_MSG,obj为需要pause的ActivityRecord,pauseTime为系统启动以来时间。
[ActivityStack.java]
private static final int PAUSE_TIMEOUT = 500;
PAUSE_TIMEOUT表示500ms,留给Activity pause的时间很短,在500ms后就会触发超时。
mHandler的由来
- ActivityStack的mHandler成员在ActivityStack的构造函数中实例化:
[ActivityStack.java]
ActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
int windowingMode, int activityType, boolean onTop) {
mHandler = new ActivityStackHandler(mService.mHandler.getLooper());
}
mHandler实例的类型为ActivityStackHandler(继承自Handler),通过ActivityManagerService的mHandler的成员的Looper创建。
- ActivityStackSupervisor的mHandler成员在构造函数中创建,其实例为ActivityStackSupervisorHandler:
[ActivityStackSupervisor.java]
public ActivityStackSupervisor(ActivityManagerService service, Looper looper) {
mService = service;
mLooper = looper;
mHandler = new ActivityStackSupervisorHandler(looper);
}
- ActivityManagerService的mHandler成员在构造函数中实例化,其实例为创建MainHandler。
构造函数中创建ServiceThread(继承自HandlerThread)并启动,之后将Looper设置给mHandler。通过mHandler发送的消息将运行在ServiceThread中。
[ActivityManagerService.java]
public ActivityManagerService(Context systemContext) {
mHandlerThread = new ServiceThread(TAG,
THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
mHandlerThread.start();
mHandler = new MainHandler(mHandlerThread.getLooper());
}
超时的触发
LAUNCH_TIMEOUT_MSG
进入ActivityStackSupervisorHandler的handleMessage方法的LAUNCH_TIMEOUT_MSG case:
[ActivityStack.java]
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_TIMEOUT_MSG: {
synchronized (mService) {
if (mLaunchingActivity.isHeld()) {
Slog.w(TAG, "Launch timeout has expired, giving up wake lock!");
if (VALIDATE_WAKE_LOCK_CALLER
&& Binder.getCallingUid() != Process.myUid()) {
throw new IllegalStateException("Calling must be system uid");
}
// 释放Wakelock
mLaunchingActivity.release();
}
}
} break;
// ···
}
}
PAUSE_TIMEOUT_MSG
进入ActivityStackHandler的handleMessage方法的PAUSE_TIMEOUT_MSG case:
[ActivityStack.java]
public void handleMessage(Message msg) {
switch (msg.what) {
case PAUSE_TIMEOUT_MSG: {
// 获取pausing的Activity对应的ActivityRecord
ActivityRecord r = (ActivityRecord)msg.obj;
// We don't at this point know if the activity is fullscreen,
// so we need to be conservative and assume it isn't.
Slog.w(TAG, "Activity pause timeout for " + r);
synchronized (mService) {
if (r.app != null) {
mService.logAppTooSlow(r.app, r.pauseTime, "pausing " + r);
}
// 传入token和true
activityPausedLocked(r.appToken, true);
}
} break;
// ···
}
}
当过了500ms的延迟时间后,若触发了PAUSE_TIMEOUT_MSG的消息,将执行activityPausedLocked方法,传入Activity对应的窗口token和true(表示来自超时)。
activityPausedLocked方法在正常的Activity pause后也会调用。
接着进入activityPausedLocked方法:
[ActivityStack.java]
// timeout在超时触发情况下为true,正常pause情况下为false
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) {
// 移除PAUSE_TIMEOUT_MSG消息
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 {
// ···
}
}
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
可以看出该方法中是否timeout的区别仅在日志不同上,即使超时也会继续进行后续的启动Activity的流程。
超时的取消
当APP进程端完成Activity的pause操作后,会调用ActivityManagerService的activityPaused方法,而在该方法中又会通过token查找对应的ActivityStack,调用其activityPausedLocked方法,此时传入的timeout为false,在activityPausedLocked方法中就会移除PAUSE_TIMEOUT_MSG消息。
LAUNCH_TIMEOUT_MSG消息将会在目标Activity启动完成后取消。
Application launch阶段
若待启动的目标Activity所属进程未启动,则AMS会先请求创建进程。
超时的设置
ActivityManagerService中会调用startProcessLocked方法进行请求创建进程:
[ActivityManagerService.java]
private boolean startProcessLocked(String hostingType, String hostingNameStr, String entryPoint,
ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
String seInfo, String requiredAbi, String instructionSet, String invokeWith,
long startTime) {
// ···
// 进一步请求创建进程
final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint,
app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo,
requiredAbi, instructionSet, invokeWith, app.startTime);
synchronized (ActivityManagerService.this) {
// 这个方法中进行超时设置
handleProcessStartedLocked(app, startResult, startSeq);
}
// ···
}
handleProcessStartedLocked方法中又会调用另一个重载方法:
[ActivityManagerService.java]
private boolean handleProcessStartedLocked(ProcessRecord app, int pid, boolean usingWrapper,
long expectedStartSeq, boolean procAttached) {
synchronized (mPidsSelfLocked) {
this.mPidsSelfLocked.put(pid, app);
// procAttached传入为false
if (!procAttached) {
// what为PROC_START_TIMEOUT_MSG
Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
// obj为待启动进程对应的ProcessRecord
msg.obj = app;
// 发送延迟消息
mHandler.sendMessageDelayed(msg, usingWrapper
? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}
}
checkTime(app.startTime, "startProcess: done updating pids map");
return true;
}
这里可以看出是通过ActivityManagerService的mHandler成员发送一个what=PROC_START_TIMEOUT_MSG的10s延迟消息。
[ActivityManagerService.java]
// 20min
static final int PROC_START_TIMEOUT_WITH_WRAPPER = 1200*1000;
// 10s
static final int PROC_START_TIMEOUT = 10*1000;
当有对启动进程过程附加监听时,将设置延迟时间为1200s,例如设置了Valgrind内存监测工具。通常情况下延迟时间为10s。
超时的触发
ActivityManagerService的mHandler是在ActivityManagerService构造函数中初始化,其实例为MainHandler,进入它的handleMessage方法:
[ActivityManagerService.java]
public void handleMessage(Message msg) {
switch (msg.what) {
// ···
case PROC_START_TIMEOUT_MSG: {
ProcessRecord app = (ProcessRecord)msg.obj;
synchronized (ActivityManagerService.this) {
processStartTimedOutLocked(app);
}
} break;
// ···
}
}
在PROC_START_TIMEOUT_MSG case中调用了processStartTimedOutLocked方法:
[ActivityManagerService.java]
private final void processStartTimedOutLocked(ProcessRecord app) {
final int pid = app.pid;
// 标记是否进行清理工作
boolean gone = false;
synchronized (mPidsSelfLocked) {
// mPidsSelfLocked中保存着所有在运行的APP进程信息
ProcessRecord knownApp = mPidsSelfLocked.get(pid);
if (knownApp != null && knownApp.thread == null) {
// 若存在APP进程信息,但是IApplicationThread为空,则需要移除,并标记需要清理
mPidsSelfLocked.remove(pid);
gone = true;
}
}
if (gone) {
Slog.w(TAG, "Process " + app + " failed to attach");
EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, app.userId,
pid, app.uid, app.processName);
removeProcessNameLocked(app.processName, app.uid);
if (mHeavyWeightProcess == app) {
mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
mHeavyWeightProcess.userId, 0));
mHeavyWeightProcess = null;
}
mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
// Take care of any launching providers waiting for this process.
// 处理等待该进程启动的ContentProvider部分
cleanupAppInLaunchingProvidersLocked(app, true);
// Take care of any services that are waiting for the process.
// 处理等待该进程启动的Service部分
mServices.processStartTimedOutLocked(app);
app.kill("start timeout", true);
if (app.isolated) {
mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
}
removeLruProcessLocked(app);
if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
Slog.w(TAG, "Unattached app died before backup, skipping");
mHandler.post(new Runnable() {
@Override
public void run(){
try {
IBackupManager bm = IBackupManager.Stub.asInterface(
ServiceManager.getService(Context.BACKUP_SERVICE));
bm.agentDisconnected(app.info.packageName);
} catch (RemoteException e) {
// Can't happen; the backup manager is local
}
}
});
}
if (isPendingBroadcastProcessLocked(pid)) {
Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
// 跳过等待该进程启动的广播部分
skipPendingBroadcastLocked(pid);
}
} else {
// 否则仅打印一段日志
Slog.w(TAG, "Spurious process start timeout - pid not known for " + app);
}
}
该方法中会对AMS的mPidsSelfLocked成员中保存的ProcessRecord进行检查,若存在对应的ProcessRecord却不存在IApplicationThread,则需要进行清理工作。否则打印一段日志。
APP进程正常启动情况下,会将对应的ProcessRecord保存在mPidsSelfLocked中。
超时的取消
APP进程正常启动后,会通知AMS:
[ActivityThread.java]
private void attach(boolean system, long startSeq) {
final IActivityManager mgr = ActivityManager.getService();
try {
// 通过IActivityManager binder通信接口通知到AMS,最终调用到AMS的attachApplication方法。
// 这里将IApplicationThread和启动序列号传给AMS,用于AMS向APP进程通信和AMS匹配启动的ProcessRecord。
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
在AMS的attachApplication方法中又调用attachApplicationLocked方法:
[ActivityManagerService.java]
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {
// ···
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
// ···
}
在AMS的attachApplicationLocked方法中将移除PROC_START_TIMEOUT_MSG消息。
Activity launch阶段
超时的设置
在ActivityStack的resumeTopActivityInnerLocked方法中,当判断APP进程存在时,将会调度Activity resume事务,并发送超时消息:
[ActivityStack.java]
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
// ···
if (next.app != null && next.app.thread != null) {
// next为将要显示的Activity对应的ActivityRecord
next.completeResumeLocked();
} else {
// ···
}
// ···
}
在ActivityRecord的completeResumeLocked方法中将调用ActivityStackSupervisor的scheduleIdleTimeoutLocked方法:
[ActivityStackSupervisor.java]
void scheduleIdleTimeoutLocked(ActivityRecord next) {
if (DEBUG_IDLE) Slog.d(TAG_IDLE,
"scheduleIdleTimeoutLocked: Callers=" + Debug.getCallers(4));
// 发送IDLE_TIMEOUT_MSG消息
Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG, next);
// IDLE_TIMEOUT值为10s
mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
}
通过mHandler(为ActivityStackSupervisorHandler)发送一个10s的IDLE_TIMEOUT_MSG消息消息。
超时的触发
进入ActivityStackSupervisorHandler的handleMessage方法,看对应的IDLE_TIMEOUT_MSG case:
[ActivityStackSupervisor.java]
public void handleMessage(Message msg) {
switch (msg.what) {
case IDLE_TIMEOUT_MSG: {
if (DEBUG_IDLE) Slog.d(TAG_IDLE,
"handleMessage: IDLE_TIMEOUT_MSG: r=" + msg.obj);
// We don't at this point know if the activity is fullscreen,
// so we need to be conservative and assume it isn't.
// 调用ActivityStackSupervisorHandler的activityIdleInternal方法
activityIdleInternal((ActivityRecord) msg.obj,
true /* processPausingActivities */);
} break;
}
}
最终将调用ActivityStackSupervisor的activityIdleInternalLocked方法。
超时的取消
Activity启动完成后,将调用AMS的activityIdle方法通知启动完成,在activityIdle中又会调用ActivityStackSupervisor的activityIdleInternalLocked方法:
[ActivityStackSupervisor.java]
final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
boolean processPausingActivities, Configuration config) {
ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r != null) {
// ···
// 移除IDLE_TIMEOUT_MSG消息
mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
// ···
}
if (allResumedActivitiesIdle()) {
// ···
if (mLaunchingActivity.isHeld()) {
// 移除IDLE_TIMEOUT_MSG消息
mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
if (VALIDATE_WAKE_LOCK_CALLER &&
Binder.getCallingUid() != Process.myUid()) {
throw new IllegalStateException("Calling must be system uid");
}
// 释放WakeLock
mLaunchingActivity.release();
}
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
}
AMS在收到Activity启动完成通知调用后,就会移除IDLE_TIMEOUT_MSG和LAUNCH_TIMEOUT_MSG消息。
Activity stop阶段
当目标Activity显示后,将处理待执行stop的那些Activity。
超时的设置
停止Activity会调用ActivityStack的stopActivityLocked方法:
[ActivityStack.java]
final void stopActivityLocked(ActivityRecord r) {
// ···
Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r);
// STOP_TIMEOUT为 11 * 1000
mHandler.sendMessageDelayed(msg, STOP_TIMEOUT);
// ···
}
发送11s延迟的STOP_TIMEOUT_MSG消息。
超时的触发
进入ActivityStackHandler的handleMessage方法:
[ActivityStack.java]
public void handleMessage(Message msg) {
switch (msg.what) {
case STOP_TIMEOUT_MSG: {
ActivityRecord r = (ActivityRecord)msg.obj;
// We don't at this point know if the activity is fullscreen,
// so we need to be conservative and assume it isn't.
Slog.w(TAG, "Activity stop timeout for " + r);
synchronized (mService) {
if (r.isInHistory()) {
r.activityStoppedLocked(null /* icicle */,
null /* persistentState */, null /* description */);
}
}
} break;
}
}
即使APP进程端stop Activity超时,AMS也会进行后续的操作。
超时的取消
Activity在stop完成后,会调用AMS的activityStopped方法,在该方法中会查找对应ActivityRecord,调用其activityStoppedLocked方法:
[ActivityRecord.java]
final void activityStoppedLocked(Bundle newIcicle, PersistableBundle newPersistentState,
CharSequence description) {
// ···
stack.mHandler.removeMessages(STOP_TIMEOUT_MSG, this);
// ···
}
在该方法中移除STOP_TIMEOUT_MSG超时消息。
Activity destroy阶段
超时的设置
销毁APP进程中的Activity时会调用ActivityStack的destroyActivityLocked方法:
[ActivityStack.java]
final boolean destroyActivityLocked(ActivityRecord r, boolean removeFromApp, String reason) {
r.setState(DESTROYING,
"destroyActivityLocked. finishing and not skipping destroy");
Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG, r);
// DESTROY_TIMEOUT为 10 * 1000
mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
}
发送10s延迟的DESTROY_TIMEOUT_MSG消息。
超时的触发
进入ActivityStackHandler的handleMessage方法:
[ActivityStack.java]
public void handleMessage(Message msg) {
switch (msg.what) {
case DESTROY_TIMEOUT_MSG: {
ActivityRecord r = (ActivityRecord)msg.obj;
// We don't at this point know if the activity is fullscreen,
// so we need to be conservative and assume it isn't.
Slog.w(TAG, "Activity destroy timeout for " + r);
synchronized (mService) {
// 进行清理和移除相关操作
activityDestroyedLocked(r != null ? r.appToken : null, "destroyTimeout");
}
} break;
}
}
APP进程端destroy Activity如果超时,AMS会进行清理相关操作。
超时的取消
APP进程端destroy Activity完成后会调用AMS的activityDestroyed方法,该方法中最终会调用ActivityStack的activityDestroyedLocked方法:
[ActivityStack.java]
final void activityDestroyedLocked(ActivityRecord record, String reason) {
if (record != null) {
// 移除DESTROY_TIMEOUT_MSG消息
mHandler.removeMessages(DESTROY_TIMEOUT_MSG, record);
}
// 进行清理和移除相关操作 ···
}
AMS收到通知后即会移除DESTROY_TIMEOUT_MSG消息。
总结
AMS在pause Activity时会通过Handler发送LAUNCH_TIMEOUT_MSG(10s)和PAUSE_TIMEOUT_MSG(500ms)超时消息;在launch Application时发送**PROC_START_TIMEOUT_MSG(10s)超时消息;launch Activity时发送IDLE_TIMEOUT_MSG(10s)超时消息;stop Activity时发送STOP_TIMEOUT_MSG(11s)超时消息;destory Activity时发送DESTROY_TIMEOUT_MSG(10s)**超时消息。
当触发超时后,AMS将自动进行后续阶段的操作和清理操作。即使APP进程端处理耗时过久或异常或无响应,AMS也能保证调度过程不会因此出现停滞和混乱。