Android系统Shell过渡动画流程解析
摘要:本文详细分析了从Activity启动到Shell动画执行的完整流程。关键节点包括:1) ActivityStarter创建并收集Transition;2) 通过TransitionController将Transition请求发送到wm/shell进程;3) Shell端接收请求并执行动画;4) 动画完成后通知WMS使Activity进入RESUMED状态。流程涉及跨进程通信(通过ITransitionPlayer接口),并对比了传统过渡与Shell过渡的区别。核心控制点在TransitionController的requestStartTransition方法,该方法通过Binder调用将TransitionToken传递给Shell进程,触发后续动画执行。整个过程体现了Android窗口管理系统与Shell组件的协同工作机制。
启动动画到 wm/shell 的完整流程
┌─────────────────────────────────────────────────────────────────────────────┐
│ Activity 启动 → Shell动画 流程 │
└─────────────────────────────────────────────────────────────────────────────┘
1️⃣ [ActivityStarter.executeRequest] Line ~1510
│
│ 创建Transition并开始收集
▼
Transition newTransition = r.mTransitionController.createAndStartCollecting(TRANSIT_OPEN)
│
│ 如果Shell Transitions启用,创建Transition
│
▼
2️⃣ [ActivityStarter.startActivityInner] Line 1875
│
│ 执行启动逻辑,Activity被添加到Task
│
▼
3️⃣ [ActivityStarter.handleStartResult] Line 1732
│
│ 核心:发送Transition到Shell
▼
if (isIndependentLaunch && transition != null) {
transitionController.requestStartTransition(transition, ...);
}
│
│ ◄── 这里!Transition被发送到Shell!
│
▼
4️⃣ [TransitionController.requestStartTransition] Line 805
│
│ 获取Shell的ITransitionPlayer代理
▼
mTransitionPlayers.getLast().mPlayer.requestStartTransition(
transition.getToken(), // Transition token
request); // TransitionRequestInfo
│
│ ◄── 跨进程Binder调用到 wm/shell 进程
│
▼
5️⃣ [Shell端 - ITransitionPlayer stub]
│
│ Shell接收Transition请求
▼
TransitionPlaybackController 或 ShellTransitionPlayback
│
│ 执行动画
▼
6️⃣ 动画完成 ──→ 通知WMS ──→ Activity变成RESUMED
创建Transition - ActivityStarter.java:1511-1512
final Transition newTransition = r.mTransitionController.isShellTransitionsEnabled()
? r.mTransitionController.createAndStartCollecting(TRANSIT_OPEN) : null;
触发条件 :只有当 isShellTransitionsEnabled() 返回 true 时才使用 Shell Transitions
发送到Shell - ActivityStarter.java:1838-1842
if (isIndependentLaunch && transition != null) {
transitionController.requestStartTransition(transition,
mTargetTask == null ? started.getTask() : mTargetTask,
remoteTransition, null /* displayChange */);
}
触发条件 :
-
isIndependentLaunch - 独立启动(不是从属启动)
-
transition != null - Transition存在
Shell接收Transition - TransitionController.java:858-859
mTransitionPlayers.getLast().mPlayer.requestStartTransition(
transition.getToken(), request);
mTransitionPlayers 是 Shell 进程注册的 ITransitionPlayer 代理列表
完整时序图
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ App进程 │ │ system_server│ │ wm/shell │ │ SurfaceFlinger│
│ │ │ │ │ 进程 │ │ │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │ │
│ startActivity() │ │ │
│───────────────────▶│ │ │
│ │ │ │
│ │ createAndStartCollecting(TRANSIT_OPEN) │
│ │──────────┐ │ │
│ │ │ │ │
│ │◀─────────┘ │ │
│ │ │ │
│ │ startActivityInner()│ │
│ │ 添加Activity到Task│ │
│ │ │ │
│ │ requestStartTransition() │
│ │───────────────────▶│ │
│ │ │ │
│ │ │ 收到TransitionToken│
│ │ │──────────┐ │
│ │ │ │ │
│ │ │◀─────────┘ │
│ │ │ │
│ │ │ 执行动画... │
│ │ │───────────────────▶│
│ │ │ │
│ │ │ 动画显示 │
│ │ │ │
│ │◀───────────────────│ 动画完成 │
│◀──────────────────│ onAnimationDone │ │
│ │ │ │
│ Activity RESUMED │ │ │
│ │ │ │
Shell Transitions 架构
┌─────────────────────────────────────────────────────────────────────────┐
│ Shell Transitions 架构 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ system_server (WMS) │ wm/shell 进程 │
│ ┌─────────────────────────┐ │ ┌─────────────────────────┐ │
│ │ TransitionController │ │ │ TransitionPlayback │ │
│ │ │ │ │ Controller │ │
│ │ • mTransitionPlayers │─────┼───▶│ • requestStartTransition│ │
│ │ • mCollectingTransition│ │ │ • playAnimation │ │
│ │ • mPlayingTransitions │ │ │ • onAnimationDone │ │
│ └─────────────────────────┘ │ └─────────────────────────┘ │
│ │ │ │
│ ┌─────────────────────────┐ │ ▼ │
│ │ Transition │ │ ┌─────────────────────────┐ │
│ │ │ │ │ ShellTransitionModel │ │
│ │ • mToken (IBinder) │ │ │ │ │
│ │ • mType (TRANSIT_OPEN) │ │ │ • WallpaperCanvas │ │
│ │ • mSyncId │ │ │ • RemoteAnimationRunner│ │
│ └─────────────────────────┘ │ └─────────────────────────┘ │
│ │ │ │
└───────────────────────────────────┼──────────────┼──────────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────┐
│ SurfaceFlinger │
│ │
│ 接收各层Surface, │
│ 合成并输出到显示屏幕 │
└─────────────────────────────────────┘
系统级开关 - WindowManagerService.java:450
public static final boolean sEnableShellTransitions = getShellTransitEnabled();
Activity级别开关 - ActivityOptions
// 通过ActivityOptions设置自定义动画
options.setRemoteTransition(remoteTransition);
// 或者使用自定义Transition
options.setTransitionOwners(remoteTransition);
Legacy vs Shell 对比

实际动画执行点
当你点击桌面图标启动一个App时:
1. Launcher Activity 发起 startActivity()
│
▼
2. ActivityStarter 创建 TRANSIT_OPEN 类型的 Transition
│
▼
3. handleStartResult() 调用 requestStartTransition()
│
▼
4. Binder 调用到 wm/shell 的 ITransitionPlayer
│
▼
5. Shell 端的 TransitionPlaybackController 执行:
├── 计算动画参数(起始位置、结束位置、时长)
├── 创建动画Surface
├── 控制Surface显示/隐藏/变换
└── 完成后通知WMS
│
▼
6. 动画结束 → Activity变成RESUMED状态