第4章 Activity生命周期状态机实现:状态定义、转换条件、超时机制
Activity生命周期状态机是ActivityManagerService(AMS)调度Activity的核心模型。本章定义一套完整的私有状态枚举、合法转换条件以及超时保护机制,供后续定制AMS时直接使用。
4.1 状态定义
AMS内部使用一组离散状态描述Activity的运行时阶段,不同于对外暴露的onCreate/onStart等回调。本章状态枚举从AOSP源码ActivityRecord中提炼,定制场景下可扩展或裁剪。
| 状态名 | 枚举值 | 说明 | 所属进程阶段 |
|---|---|---|---|
| INITIALIZING | 0x01 | ActivityRecord创建后尚未启动 | 应用未创建 |
| STARTED | 0x02 | 已发出启动请求,等待应用进程响应 | 应用进程就绪 |
| RESUMED | 0x03 | Activity可见且获得焦点 | 前台 |
| PAUSING | 0x04 | 正在执行暂停操作(回调onPause) | 退出前台 |
| PAUSED | 0x05 | 暂停完成,Activity不可见 | 后台可见?不可见 |
| STOPPING | 0x06 | 正在执行停止操作(回调onStop) | 不可见 |
| STOPPED | 0x07 | 停止完成,保留状态但不可见 | 后台 |
| DESTROYING | 0x08 | 正在执行销毁操作(回调onDestroy) | 销毁中 |
| DESTROYED | 0x09 | 销毁完成,等待从Record列表移除 | 已结束 |
定制注意: 若需要多窗口或分屏状态,可新增MULTI_WINDOW_PAUSED、PICTURE_IN_PICTURE等状态,但需同步修改转换条件与超时处理。
4.2 状态转换条件
合法转换定义在一张有向状态转换表中。以下为定制AMS中必须遵守的核心规则,不可任意跨状态跳转。
| 当前状态 | 触发事件 | 下一状态 | 条件/备注 |
|---|---|---|---|
| INITIALIZING | attachApplication() | STARTED | 应用进程已绑定 |
| STARTED | activityResumed() | RESUMED | 应用调用onResume完成 |
| RESUMED | schedulePauseActivity() | PAUSING | 新Activity启动或返回Home |
| PAUSING | activityPaused() | PAUSED | 应用onPause回调返回 |
| PAUSED | scheduleStopActivity() | STOPPING | Activity不再可见 |
| STOPPING | activityStopped() | STOPPED | 应用onStop回调返回 |
| STOPPED | scheduleDestroyActivity() | DESTROYING | 需要释放资源 |
| DESTROYING | activityDestroyed() | DESTROYED | 应用onDestroy回调返回 |
| 任意中途状态 | processDied() | DESTROYED | 进程死亡强制结束 |
禁止非法转换: 例如,直接从INITIALIZING跳转到RESUMED,或从PAUSED跳转到RESUMED而不经过STARTED,会导致回调顺序错乱和ANR。所有转换必须经AMS维护的
mState字段校验。4.3 超时机制
为避免应用进程阻塞AMS主线程,每个涉及长耗时回调(onPause、onStop、onDestroy)的状态都配置独立超时值。超时后AMS强制推进状态并发送错误报告。
| 等待回调 | 超时时间(ms) | 超时处理策略 |
|---|---|---|
| activityPaused() | 500 | 强制设为PAUSED,输出ANR警告 |
| activityStopped() | 10000 | 强制设为STOPPED,杀死进程 |
| activityDestroyed() | 10000 | 强制设为DESTROYED,清理Record |
超时计时器实现示例:
// 在AMS主线程Handler中调度
private void scheduleActivityTimeout(ActivityRecord r, int timeoutMs) {
Message msg = mHandler.obtainMessage(HANDLE_ACTIVITY_TIMEOUT, r);
mHandler.sendMessageDelayed(msg, timeoutMs);
}
// 收到超时消息后执行强制转换
private void handleActivityTimeout(ActivityRecord r) {
synchronized (mLock) {
if (r.state == ActivityState.PAUSING) {
r.state = ActivityState.PAUSED;
dispatchActivityPausedLocked(r);
Slog.w(TAG, "Force PAUSED due to timeout for " + r);
}
// 类似处理STOPPING、DESTROYING
}
}
定制调优: 针对低端设备或特定场景(如VR、车机),可以动态调整超时值。建议通过
SystemProperties暴露三个配置项:persist.activity.timeout.pause、persist.activity.timeout.stop、persist.activity.timeout.destroy。4.4 状态机整体结构
4.5 调试与验证
状态机实现完成后,建议通过以下方法验证正确性:
- 日志标记:在每个状态转换点输出
Slog.i(TAG, "Statemachine: " + oldState + " -> " + newState),配合logcat -s ActivityManager:I观察。 - 单元测试:使用Robolectric模拟AMS主线程,注入虚假
ClientTransaction验证转换路径。 - 压力测试:启动大量Activity并快速旋转屏幕,检查是否出现状态滞留或双重回调。
// 验证超时触发日志示例片段
adb logcat -s ActivityManager:I | grep "Timeout\|Force\|state="
// 若看到以下日志说明超时机制生效
ActivityManager: Force PAUSED due to timeout for ActivityRecord{xxx}
ActivityManager: state=PAUSING -> PAUSED (timeout)
常见错误: 超时消息未在
activityPaused()等回调到达时及时移除,导致状态被双重强制转换。务必在回调处理中加入mHandler.removeMessages(HANDLE_ACTIVITY_TIMEOUT, r)清理待执行超时消息。4.6 性能与稳定性优化
- 超时容忍度动态调整:根据设备CPU负载或帧率下降,临时缩短PAUSING超时(如从500ms降到300ms),防止卡顿堆叠。
- 批量状态变更:若同时处理多个Activity,可合并
scheduleActivityTimeout调用,减少Handler消息队列压力。 - 安全锁粒度:状态机操作在
mLock同步块内执行,但超时Handler回调中加锁需谨慎,避免死锁。建议在Handler消息处理中使用synchronized (mLock)时只做最短临界区。
本章定义的状态枚举、转换表、超时配置可直接嵌入AMS源码的ActivityRecord.java和ActivityStack.java中。下一阶段将结合第5章“Activity启动流程同步回调定制”,把状态机与客户端事务调度整合。