Android ShellTransitions 机制完整分析(by DeepSeekV4Pro)

Android ShellTransitions 机制完整分析


一、系统架构总览

ShellTransitions 是一个三层架构 ,将转场动画的生命周期管理(WMCore)、窗口同步(BLASTSyncEngine)与动画执行(WMShell)完全分离。核心思想是:WMCore管理"发生了什么变化",BLAST保证"窗口准备好了",WMShell负责"怎么动画展示"

1.1 架构分层图

scss 复制代码
┌──────────────────────────────────────────────────────────────────────┐
│                         外部调用者                                     │
│  ┌──────────┐  ┌──────────┐  ┌───────────┐  ┌───────────────────┐  │
│  │Launcher3 │  │ SystemUI │  │ 第三方App  │  │ ActivityStarter   │  │
│  │(手势导航) │  │(锁屏状态栏)│  │(远程动画)  │  │(Activity启动)     │  │
│  └────┬─────┘  └────┬─────┘  └─────┬──────┘  └────────┬──────────┘  │
│       │              │              │                  │              │
│       │   IShellTransitions (AIDL)  │       WindowOrganizerController│
│       └──────────────┼──────────────┘                  │              │
│                      │                                 │              │
└──────────────────────┼─────────────────────────────────┼──────────────┘
                       │                                 │
┌──────────────────────┼─────────────────────────────────┼──────────────┐
│                      │      WMCore Layer (Server)       │              │
│                      ▼                                 ▼              │
│  ┌─────────────────────────────────────────────────────────────────┐ │
│  │                   TransitionController                           │ │
│  │   • 全局转场生命周期管理                                         │ │
│  │   • mCollectingTransition (当前收集中)                            │ │
│  │   • mWaitingTransitions (等待就绪队列)                            │ │
│  │   • mPlayingTransitions (播放中)                                 │ │
│  │   • mQueuedTransitions (排队中)                                  │ │
│  │   • assignTrack() 轨道分配                                       │ │
│  └──────────────────────────┬──────────────────────────────────────┘ │
│                              │                                        │
│  ┌──────────────────────────▼──────────────────────────────────────┐ │
│  │                        Transition                               │ │
│  │   • 状态机: PENDING→COLLECTING→STARTED→PLAYING→FINISHED        │ │
│  │   • mParticipants: 参与者集合                                    │ │
│  │   • mChanges: 每个参与者的 ChangeInfo                            │ │
│  │   • 与 BLASTSyncEngine 协调同步                                  │ │
│  └──────────────────────────┬──────────────────────────────────────┘ │
│                              │                                        │
│  ┌──────────────────────────▼──────────────────────────────────────┐ │
│  │                    BLASTSyncEngine                              │ │
│  │   • SyncGroup: 同步组管理                                        │ │
│  │   • WindowContainer同步状态:                                     │ │
│  │     NONE→WAITING_FOR_DRAW→READY                                  │ │
│  │   • Transaction合并与提交                                        │ │
│  └─────────────────────────────────────────────────────────────────┘ │
│                                                                       │
│  通信接口: ITransitionPlayer (Binder IPC)                             │
└───────────────────────────────────────────────────────────────────────┘
                               │
                               │ ITransitionPlayer.aidl
                               │
┌──────────────────────────────┼───────────────────────────────────────┐
│                              │        WMShell Layer (Client)          │
│  ┌───────────────────────────▼─────────────────────────────────────┐ │
│  │                      Transitions                                 │ │
│  │   (ITransitionPlayer.Stub 实现, 转场播放器)                       │ │
│  │                                                                  │ │
│  │   ┌──────────────────────────────────────────────────────────┐  │ │
│  │   │              生命周期管理                                 │  │ │
│  │   │  mPendingTransitions → READY → (Track队列)                │  │ │
│  │   │  mKnownTransitions (全局状态追踪)                          │  │ │
│  │   │  mReadyDuringSync (SYNC阻塞等待队列)                       │  │ │
│  │   └──────────────────────────────────────────────────────────┘  │ │
│  │                                                                  │ │
│  │   ┌──────────────────────────────────────────────────────────┐  │ │
│  │   │              动画执行                                     │  │ │
│  │   │  setupStartState()  设置初始状态                           │  │ │
│  │   │  setupAnimHierarchy()  建立动画层级                         │  │ │
│  │   │  calculateAnimLayer()  计算Z轴顺序                          │  │ │
│  │   └──────────────────────────────────────────────────────────┘  │ │
│  │                                                                  │ │
│  │   ┌──────────────────────────────────────────────────────────┐  │ │
│  │   │              Handler责任链                                 │  │ │
│  │   │  (高优先级) RemoteTransitionHandler                        │  │ │
│  │   │            KeyguardTransitionHandler                       │  │ │
│  │   │            PipTransitionHandler                            │  │ │
│  │   │            SplitScreenTransitionHandler                    │  │ │
│  │   │  (低优先级) DefaultTransitionHandler (兜底默认)             │  │ │
│  │   └──────────────────────────────────────────────────────────┘  │ │
│  │                                                                  │ │
│  │   ┌──────────────────────────────────────────────────────────┐  │ │
│  │   │             轨道系统                                       │  │ │
│  │   │  Track[0]: mReadyTransitions → mActiveTransition          │  │ │
│  │   │  Track[1]: mReadyTransitions → mActiveTransition          │  │ │
│  │   │  Track[N]: (并行播放)                                      │  │ │
│  │   └──────────────────────────────────────────────────────────┘  │ │
│  └─────────────────────────────────────────────────────────────────┘ │
│                                                                       │
│  ┌─────────────────────────────────────────────────────────────────┐ │
│  │              对外接口: IShellTransitions (AIDL)                   │ │
│  │  registerRemote() / registerRemoteForTakeover()                  │ │
│  │  setHomeTransitionListener() / setFocusTransitionListener()      │ │
│  └─────────────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────────┘

二、BLAST同步机制详解

BLAST (Buffer as LayerSync Transaction) 同步机制是 ShellTransitions 能够在正确时机播放动画的基础保证。它的核心目标是:确保在窗口内容已经绘制完毕之后,才开始播放转场动画

2.1 问题背景

在Android窗口系统中,WM端的状态变更(如配置变化、可见性变化)会触发客户端重绘。如果不等客户端绘制完成就开始动画,会出现两个问题:

  1. 白屏/闪烁:动画开始时窗口还没有新内容
  2. 视觉跳跃:旧内容随着动画变换,新内容突然出现

2.2 核心保证

如果同时对同步状态进行变更和启动同步,那么客户端在观察到同步状态后绘制的第一帧,将被发送到同步的消费者(而非直接发送给SurfaceFlinger)。

2.3 协议定义

BLASTSyncEngine 定义了完整的同步协议:

Server协议
makefile 复制代码
SA: 进入临界区(获取WM锁)
SB: 变更可同步状态,准备任意数量的同步(递增seqId)
SC: 离开临界区(释放WM锁)
SD: 向客户端发送同步状态更新,始终携带当前seqId
SE: 当客户端调用 finishDrawing 时,对所有 seqId ≤ 传递seqId 的同步执行消费者回调
Client协议
makefile 复制代码
CA: 观察状态和seqId变更直到固定帧截止时间,然后执行 performTraversals
CB: 如果seqId在帧截止时递增,配置渲染器将下一次绘制重定向到Transaction,记录当前seqId
CC: 绘制完成后,将包含绘制的Transaction连同记录的seqId发送给WM

2.4 同步状态机

css 复制代码
每个 WindowContainer 都有 mSyncState:

    ┌──────────────────┐
    │  SYNC_STATE_NONE │  (0) 未参与同步
    └────────┬─────────┘
             │ prepareSync() --- 加入SyncGroup
    ┌────────▼─────────┐
    │ SYNC_STATE_READY │  (2) 内容最新,直接可用
    └────────┬─────────┘
             │ resize/relayout --- 发生布局变化
    ┌────────▼──────────────┐
    │ SYNC_STATE_WAITING     │  (1) 等待客户端重绘
    │ _FOR_DRAW              │
    └────────┬───────────────┘
             │ finishDrawing() --- 客户端绘制完成
    ┌────────▼─────────┐
    │ SYNC_STATE_READY │  (2) 回到就绪
    └──────────────────┘

2.5 SyncGroup 生命周期

scss 复制代码
┌──────────────────────────────────────────────────────────────────────┐
│                       SyncGroup 生命周期                               │
│                                                                       │
│  1. 创建                 2. 添加成员                  3. 等待就绪       │
│  prepareSyncSet()      addToSyncSet(wc)             mReady = true     │
│  ┌──────────┐          ┌──────────────┐           ┌──────────┐      │
│  │ SyncGroup│─────────►│ wc.prepareSync│──────────►│ 等待所有  │      │
│  │ (未激活) │          │ 遍历子树      │           │ 成员就绪  │      │
│  └──────────┘          └──────────────┘           └────┬─────┘      │
│                                                        │             │
│  6. 清理               5. 完成                         │             │
│  finishSync()         onTransactionReady()   ◄────────┘             │
│  ┌──────────┐          ┌──────────────┐                             │
│  │ 恢复      │◄────────│ tryFinish()  │                             │
│  │ pendingTr │         │ isSyncFinished│                             │
│  └──────────┘         │ 检查所有成员  │                             │
│                       └──────────────┘                             │
│                                                                       │
│  关键方法:                                                            │
│  • tryFinish(): 检查 mReady && 无依赖 && 所有 rootMembers isSyncFinished│
│  • finishNow(): 合并所有 SyncTransaction → 调用 listener.onTransactionReady│
│  • onSurfacePlacement(): 遍历所有活跃SyncGroup尝试完成                │
└──────────────────────────────────────────────────────────────────────┘

2.6 BLAST 与 ShellTransitions 的集成

scss 复制代码
Transition.startCollecting()
    │
    ▼
BLASTSyncEngine.startSyncSet(transition, timeout, "Transition")
    │  创建 SyncGroup,Transition 作为 TransactionReadyListener
    ▼
TransitionController.collect(wc)
    │
    ▼
Transition.collect(wc)
    │
    ▼
SyncGroup.addToSync(wc)
    │  wc.prepareSync() → mSyncState = READY
    │  如果发生 resize → mSyncState = WAITING_FOR_DRAW
    ▼
WindowState.finishDrawing(transaction)
    │  客户端绘制完成
    │  mSyncState = READY
    ▼
BLASTSyncEngine.onSurfacePlacement()
    │
    ▼
SyncGroup.tryFinish()
    │  isSyncFinished() 递归检查所有成员
    │  所有成员 READY → finishNow()
    ▼
Transition.onTransactionReady(mergedSyncTransaction)
    │  Transition 获得所有参与者的合并SyncTransaction
    │  调用 Transition.playNow()
    ▼
构建 TransitionInfo → ITransitionPlayer.onTransitionReady()
    ↓
  WMShell 开始动画

2.7 Transaction 排序保证

BLAST同步同时解决了跨进程Transaction的顺序问题:

rust 复制代码
BLASTBufferQueue 的 Transaction 类型:

┌──────────────┬──────────────────────────────────────────────┐
│ 类型          │ 排序保证                                      │
├──────────────┼──────────────────────────────────────────────┤
│ Sync,Sync     │ 委托给 SyncConsumer                          │
│ Sync,NotSync  │ CommitCallback 保证 Sync 先被应用             │
│ NotSync,Sync  │ Barrier: Sync标记最后一帧NotSync barrier     │
│ NotSync,NotSync │ 同线程同队列保证顺序                         │
└──────────────┴──────────────────────────────────────────────┘

三、轨道机制 (Track) 详解

轨道机制是 ShellTransitions 实现并行动画串行动画有序混合的核心设计。

3.1 设计动机

在复杂的多窗口场景中,不同的转场可能涉及完全不同的窗口:

  • 分屏场景:上半屏一个动画,下半屏另一个动画 --- 应该并行
  • 同一Task的连续操作:打开一个Activity,紧接着它又被缩小 --- 应该串行
  • 跨多个轨道的转场:一个转场涉及分屏两边 --- 必须等待所有轨道清空

轨道机制优雅地解决了这个三维调度问题。

3.2 核心数据结构

ini 复制代码
Transitions (WMShell)                     TransitionController (WMCore)
┌──────────────────────────┐            ┌──────────────────────────────┐
│ mTracks: ArrayList<Track>│            │ mPlayingTransitions[]       │
│                          │            │ mTrackCount                 │
│ Track[0]:                │            │                              │
│   mActiveTransition ─────┼────────────┼─ 当前播放的Transition         │
│   mReadyTransitions[]    │            │   .mAnimationTrack = 0       │
│                          │            │                              │
│ Track[1]:                │            │ assignTrack():              │
│   mActiveTransition ─────┼────────────┼─ 与Track[0]独立 → Track[1]   │
│   mReadyTransitions[]    │            │   与Track[0]重叠 → Track[0]   │
│                          │            │   与多个Track重叠 → SYNC     │
│ Track[N] 动态创建        │            │                              │
└──────────────────────────┘            └──────────────────────────────┘

3.3 轨道分配算法 (WMCore: assignTrack)

ini 复制代码
assignTrack(transition, info):
    track = -1
    sync = false
    
    for each playing in mPlayingTransitions:
        if playing == transition: continue
        if getIsIndependent(playing, transition): continue
        
        if track == -1:
            track = playing.mAnimationTrack     // 加入相同轨道
        else if track != playing.mAnimationTrack:
            sync = true                         // 与多轨道重叠!
            break
    
    if sync:
        track = 0                              // 强制归入轨道0
        info.setFlags(FLAG_SYNC)               // 标记同步
    
    if track < 0:
        track = mTrackCount++                  // 新轨道(并行)
    
    return track

3.4 独立性判断 (getIsIndependent)

两个Transition可以并行的条件:

scss 复制代码
Transition A (播放中)                Transition B (新进入)
     │                                     │
     ├─ 目标窗口是 Activity 级别的?  ───────┤ (如Task级别则不可)
     │                                     │
     ├─ 不是 A 的 transient-launch ────────┤ (重叠则不可)
     │    目标?                             │
     │                                     │
     └─ 在不同Display? ────────────────────┤ (不同屏可以并行)

具体规则:

  • Recents转场 + Recents转场 → 必须串行(自己不能和自己并行)
  • Recents转场 + 非Recents转场 → 检查窗口是否重叠
  • Activity级 + 不重叠 → 可以并行
  • Task级 → 目前不允许并行

3.5 Shell端轨道执行

ini 复制代码
每个 Track 内部:

    ┌─────────────────────────────────────────────────────┐
    │               Track 工作流程                         │
    │                                                     │
    │  mReadyTransitions: [T3, T2, T1]  (FIFO队列)       │
    │                                                     │
    │  processReadyQueue():                                │
    │    ┌─ mActiveTransition == null?                     │
    │    │   YES → T1出队 → 设为mActiveTransition          │
    │    │       → playTransition(T1)                      │
    │    │       → 尝试合并 T2 → T1 (如成功则T2 = MERGED)  │
    │    │       → 尝试合并 T3 → T1 ...                    │
    │    │                                                 │
    │    │   NO → mergeAnimation(T1, mActiveTransition)    │
    │    │       → 成功: T1被合并, 从队列移除              │
    │    │       → 失败: T1留在队列等待                    │
    │    │                                                 │
    │  onFinish():                                         │
    │    → mActiveTransition = null                        │
    │    → processReadyQueue() (启动下一个)                 │
    └─────────────────────────────────────────────────────┘

多个 Track 之间:

    Track[0]: T0_active → T0_ready1 → T0_ready2  (串行)
    Track[1]: T1_active → T1_ready1              (串行, 与Track[0]并行)
    
    FLAG_SYNC 转场到达时:
    → 所有Track必须排空
    → mReadyDuringSync 收集被阻塞的转场
    → 所有Track idle后释放

3.6 SYNC 机制

当转场与多个活跃轨道重叠时:

scss 复制代码
1. 转场被标记 FLAG_SYNC,加入 mReadyDuringSync 队首
2. 对每个活跃轨道调用 finishForSync():
   ┌─ 向正在播放的动画 merge 一个虚拟 SLEEP 转场(信号)
   ┌─ 设置 120ms 超时
   ┌─ 超时后强制 terminate 仍未完成的动画
   ┌─ 重复直到该轨道 idle
3. 所有轨道 idle 后,mReadyDuringSync 中的转场被释放执行

四、Merge 机制详解

Merge机制允许新到达的转场无缝合并到正在播放的动画中,优化了连续操作的视觉体验。

4.1 触发时机

css 复制代码
时刻线:
    Track[0]: [T1_active ~~~~~~ 播放中 ~~~~~~→]
    
    此时 T2 到达 (ready状态)
    
    processReadyQueue(Track[0]):
        检测到 mActiveTransition(T1) != null
        → 调用 T1.mHandler.mergeAnimation(T2, ..., T1_token, callback)

4.2 Handler的三种策略

css 复制代码
┌──────────────────────────────────────────────────────────────────┐
│                    Merge 三种响应策略                              │
│                                                                   │
│  策略1: 拒绝 (No-op)                                              │
│  ─────────────────                                               │
│  mergeAnimation() 不做任何操作                                     │
│  → T2 留在 track.mReadyTransitions 等待                           │
│  → T1 完成后 T2 独立播放                                          │
│  适用: 转场类型不兼容 (如 PiP打开 vs 全屏关闭)                      │
│                                                                   │
│  策略2: 接受并合并 (Accept & Merge)                               │
│  ───────────────────────────────                                 │
│  mergeAnimation() 内部调用 finishCallback                          │
│  → T2 的 Change 合并到 T1 的 ActiveTransition.mMerged[]           │
│  → T2 的 startTransaction 和 finishTransaction 被纳入 T1          │
│  → T1 结束时一起 apply                                            │
│  适用: 同一窗口的连续变化 (如 打开Activity → Activity变换)          │
│                                                                   │
│  策略3: 终止当前并覆盖 (End & Replace)                             │
│  ──────────────────────────────────                               │
│  mergeAnimation() 先终止 T1 的动画 (anim.end())                   │
│  → 然后 T2 作为新的播放开始                                        │
│  DefaultTransitionHandler 采用此策略                               │
│  适用: 后来的转场完全取代之前的 (如 用户快速连续操作)               │
└──────────────────────────────────────────────────────────────────┘

4.3 DefaultTransitionHandler 的 Merge 实现

scss 复制代码
DefaultTransitionHandler.mergeAnimation():
    
    1. 找到 mergeTarget(被合并目标) 的 Animator 列表
       ArrayList<Animator> animators = mAnimations.get(mergeTarget)
    
    2. 对所有正在运行的 Animator 调用 anim.end()
       → 强制动画跳到最终状态
    
    3. 返回 (不调用 finishCallback)
    
    效果:
    - 旧动画被截断到最终状态
    - 新转场作为独立动画在 processReadyQueue 中播放
    - 新转场的 startTransaction 包含修正后的状态

4.4 Transitions 层的 Merge 清理

scss 复制代码
Transitions.onMerged(playingToken, mergedToken):
    
    playing = mKnownTransitions.get(playingToken)
    merged = mKnownTransitions.get(mergedToken)
    
    1. 验证: 同一轨道, merged 在队列中
    2. 从 track.mReadyTransitions 中移除 merged
    3. 将 merged 加入 playing.mMerged[]
    4. 如果 merged 未被abort:
       merged.mHandler.onTransitionConsumed(merged.mToken, false, ...)
    5. 通知所有 TransitionObserver.onTransitionMerged()
    6. 继续 processReadyQueue() (尝试合并下一个)

4.5 结束时的 Merge 回放

scss 复制代码
Transitions.onFinish(token, wct):
    
    active = mKnownTransitions.get(token)
    
    // 收集所有被合并转场的 Transaction
    fullFinish = active.mFinishT
    for each merged in active.mMerged:
        fullFinish.merge(merged.mStartT)    // StartT: 无操作则跳过
        fullFinish.merge(merged.mFinishT)
    
    // 一次性 apply 所有变更
    fullFinish.apply()
    
    // 逐个通知 WMCore 转场结束
    mOrganizer.finishTransition(active.mToken, wct)
    for each merged in active.mMerged:
        mOrganizer.finishTransition(merged.mToken, null)
        releaseSurfaces(merged.mInfo)

五、完整流程序列图

5.1 主流程

scss 复制代码
┌─────────┐  ┌──────────────┐  ┌──────────┐  ┌───────────────┐  ┌───────────┐  ┌─────────────┐
│ 调用方   │  │TransitionCtrl│  │Transition│  │BLASTSyncEngine│  │Transitions│  │Transition   │
│          │  │              │  │          │  │               │  │(WMShell)  │  │Handler      │
└────┬─────┘  └──────┬───────┘  └────┬─────┘  └───────┬───────┘  └─────┬─────┘  └──────┬──────┘
     │               │               │                 │                │               │
     │ createTrans() │               │                 │                │               │
     │──────────────►│               │                 │                │               │
     │               │ new Transition│                 │                │               │
     │               │──────────────►│                 │                │               │
     │               │               │                 │                │               │
     │               │moveToCollect()│                 │                │               │
     │               │──────────────►│ STATE=COLLECTING│                │               │
     │               │               │                 │                │               │
     │               │requestStart() │                 │                │               │
     │               │──────────────►│ build RequestInfo│               │               │
     │               │               │─────────────────────────────────►               │
     │               │               │    IPC: requestStartTransition  │               │
     │               │               │                 │                │               │
     │               │               │                 │     创建       │               │
     │               │               │                 │ ActiveTransition│              │
     │               │               │                 │                │               │
     │               │               │                 │dispatchRequest │               │
     │               │               │                 │───────────────►│ handleRequest │
     │               │               │                 │                │ (返回WCT)     │
     │               │               │                 │◄───────────────│               │
     │               │               │                 │                │               │
     │               │               │◄─────────────────────────────────│               │
     │               │               │    IPC: startTransition(token,wct)               │
     │               │               │                 │                │               │
     │               │               │                 │ mPendingTrans. │               │
     │               │               │                 │ .add(0,active) │               │
     │               │               │                 │                │               │
     ════════════════ 阶段2: 参与者收集 ════════════════                 │               │
     │               │               │                 │                │               │
     │ collect(wc)   │               │                 │                │               │
     │──────────────►│               │                 │                │               │
     │               │collect(wc)    │                 │                │               │
     │               │──────────────►│ addToSync(wc)   │                │               │
     │               │               │────────────────►│                │               │
     │               │               │                 │ wc.prepareSync │               │
     │               │               │                 │ STATE=READY    │               │
     │               │               │                 │                │               │
     │               │               │    resize → STATE=WAITING_FOR_DRAW              │
     │               │               │                 │                │               │
     │               │               │  finishDrawing  │                │               │
     │               │               │◄────────────────│                │               │
     │               │               │ STATE=READY     │                │               │
     │               │               │                 │                │               │
     ════════════════ 阶段3: 就绪通知 ════════════════                   │               │
     │               │               │                 │                │               │
     │               │               │onSurfacePlacement()              │               │
     │               │               │◄────────────────│                │               │
     │               │               │ tryFinish()     │                │               │
     │               │               │────────────────►│                │               │
     │               │               │                 │                │               │
     │               │               │onTransactionReady(mergedT)       │               │
     │               │               │◄────────────────│                │               │
     │               │               │                 │                │               │
     │               │               │ playNow()       │                │               │
     │               │               │ build TransitionInfo              │               │
     │               │               │ assignTrack()   │                │               │
     │               │◄──────────────│                 │                │               │
     │               │               │                 │                │               │
     │               │               │─────────────────────────────────►│               │
     │               │               │  IPC: onTransitionReady          │               │
     │               │               │                 │                │               │
     ════════════════ 阶段4: 动画执行 ════════════════                   │               │
     │               │               │                 │                │               │
     │               │               │                 │PENDING→READY   │               │
     │               │               │                 │dispatchReady() │               │
     │               │               │                 │                │               │
     │               │               │                 │setupStartState │               │
     │               │               │                 │                │               │
     │               │               │                 │加入Track队列    │               │
     │               │               │                 │                │               │
     │               │               │                 │processReadyQ() │               │
     │               │               │                 │                │               │
     │               │               │                 │setupAnimHierarchy()            │
     │               │               │                 │ (reparent+Z序) │               │
     │               │               │                 │                │               │
     │               │               │                 │dispatchTransition()             │
     │               │               │                 │───────────────────────────────►│
     │               │               │                 │           startAnimation()      │
     │               │               │                 │                │               │
     │               │               │                 │ startT.apply() │               │
     │               │               │                 │────────────────► SF            │
     │               │               │                 │                │               │
     ════════════════ 阶段5: 动画结束 ════════════════                   │               │
     │               │               │                 │                │               │
     │               │               │                 │finishCallback  │               │
     │               │               │                 │◄───────────────│               │
     │               │               │                 │                │               │
     │               │               │                 │onFinish()      │               │
     │               │               │                 │                │               │
     │               │               │                 │merge all finishT               │
     │               │               │                 │fullFinish.apply()              │
     │               │               │                 │────────────────► SF            │
     │               │               │                 │                │               │
     │               │               │◄─────────────────────────────────│               │
     │               │               │  IPC: finishTransition(token,wct)                │
     │               │               │                 │                │               │
     │               │               │finishTransition │                │               │
     │               │◄──────────────│                 │                │               │
     │               │               │                 │                │               │
     │               │               │validateStates() │                │               │
     │               │               │                 │                │               │
     │               │               │                 │processReadyQ() │               │
     │               │               │                 │(下一个转场)     │               │

5.2 Merge 流程

less 复制代码
Track[0] 状态:
    mActiveTransition = T1 (正在播放)
    mReadyTransitions = [T2, T3]  (等待队列)

════════════ T2 Merge 尝试 ════════════

processReadyQueue(Track[0]):
    
    T2 = track.mReadyTransitions.get(0)   // 队首
    
    T2.mAborted? → NO → 进入 Merge 流程
    
    T1.mHandler.mergeAnimation(
        T2.mToken,       // 新转场
        T2.mInfo,        // 新转场信息
        T2.mStartT,      // 新转场的start Transaction
        T2.mFinishT,     // 新转场的finish Transaction
        T1.mToken,       // 合并目标
        callback         // 成功回调 → onMerged(T1_token, T2_token)
    )
    
    分支A: Merge 失败 (handler 不调用 callback)
    ─────────────────────────────────────
    T2 留在 mReadyTransitions
    等待 T1 结束后独立播放
    

    分支B: Merge 成功 (handler 调用 callback)
    ─────────────────────────────────────
    
    onMerged(T1_token, T2_token):
    
        1. 从 track.mReadyTransitions 移除 T2
        2. T2 加入 T1.mMerged[]
        3. T2.mHandler.onTransitionConsumed(T2_token, false, T2.mFinishT)
        4. 通知 TransitionObservers
        
        继续尝试合并 T3:
            processReadyQueue() → T3 成为新的队首
            → mergeAnimation(T3, T1_token, callback)

六、状态机总览

6.1 WMCore端 Transition 状态

ini 复制代码
                    ┌──────────────────────────────┐
                    │     STATE_PENDING = -1        │
                    │     已创建,未开始收集          │
                    └────────────┬─────────────────┘
                                 │ moveToCollecting()
                    ┌────────────▼─────────────────┐
                    │    STATE_COLLECTING = 0       │
                    │    正在收集中 (可并行收集)       │
                    └────────────┬─────────────────┘
                                 │ startCollecting(timeout)
                    ┌────────────▼─────────────────┐
                    │     STATE_STARTED = 1         │
                    │  正式启动,等待参与者就绪        │
                    │  BLASTSync 确保窗口绘制完成     │
                    └────────────┬─────────────────┘
                                 │ playNow()
                    ┌────────────▼─────────────────┐
                    │     STATE_PLAYING = 2         │
                    │  动画播放中 (在WMShell执行)      │
                    └────────────┬─────────────────┘
                                 │ finishTransition()
                    ┌────────────▼─────────────────┐
                    │    STATE_FINISHED = 4         │
                    │       转场完成                 │
                    └──────────────────────────────┘
                    
                    任意阶段 → STATE_ABORT = 3 (中止)

6.2 WMShell端 ActiveTransition 流转

scss 复制代码
┌─────────────────────────────────────────────────────────────────┐
│                     ActiveTransition 生命周期                     │
│                                                                  │
│  requestStartTransition()                                        │
│         │                                                        │
│         ▼                                                        │
│  ┌─────────────┐                                                 │
│  │   PENDING   │  mPendingTransitions                            │
│  │  (等待就绪)  │                                                 │
│  └──────┬──────┘                                                 │
│         │ onTransitionReady()                                    │
│         ▼                                                        │
│  ┌─────────────┐                                                 │
│  │   READY     │  track.mReadyTransitions                        │
│  │  (就绪排队)  │                                                 │
│  └──┬──────┬───┘                                                 │
│     │      │                                                     │
│     │      └────────── mergeAnimation() ──────┐                  │
│     │ processReadyQueue()                     │                  │
│     ▼                                         ▼                  │
│  ┌─────────────┐                      ┌──────────────┐          │
│  │   ACTIVE    │                      │   MERGED     │          │
│  │ (动画播放中)│◄─────────────────────│ (被合并)     │          │
│  └──────┬──────┘   merged[]           └──────────────┘          │
│         │                                                        │
│         │ onFinish() (finishCallback)                             │
│         ▼                                                        │
│  ┌─────────────┐                                                 │
│  │   完成      │  apply finishT → finishTransition IPC           │
│  │   清理      │  释放 surfaces → 启动队列下一个                   │
│  └─────────────┘                                                 │
│                                                                  │
│  特殊情况: onAbort() → 跳过动画, 直接走完成流程                     │
│            SYNC标志 → 进入 mReadyDuringSync 等待所有轨道排空      │
└─────────────────────────────────────────────────────────────────┘

七、动画层级计算

7.1 Z轴分割线算法

erlang 复制代码
calculateAnimLayer(change, index, numChanges, transitType):
    
    zSplitLine = numChanges + 1    // 分割线
    
    ┌─────────────────────────────────────────┐
    │  分割线以上 (动画层)  z > zSplitLine     │
    │  ┌───────────────────────────────────┐  │
    │  │  OPEN / TO_FRONT (打开类型转场)    │  │
    │  │  CLOSE / TO_BACK (关闭类型转场)    │  │
    │  │  CHANGE (打开类型转场)             │  │
    │  └───────────────────────────────────┘  │
    ├─────────────────────────────────────────┤
    │  分割线以下 (静态层)  z < zSplitLine     │
    │  ┌───────────────────────────────────┐  │
    │  │  OPEN / TO_FRONT (关闭类型转场)    │  │
    │  │  CLOSE / TO_BACK (打开类型转场)    │  │
    │  │  CHANGE (关闭类型 / 仅排序)         │  │
    │  └───────────────────────────────────┘  │
    └─────────────────────────────────────────┘
    
    具体 z 值 = zSplitLine + offset (上) 或 zSplitLine - offset (下)

7.2 动画层级树构建

ini 复制代码
setupAnimHierarchy(info, startT, finishT):
    
    原始层级:                    动画层级(reparent后):
    
    DisplayContent               Root(leash)
    ├── Task A                   ├── Change[0] (OPEN, layer=high)
    ├── Task B          ──►      ├── Change[1] (CLOSE, layer=mid)
    ├── Wallpaper                 ├── Change[2] (CHANGE, layer=low)
    └── ...                       └── ...
    
    关键操作:
    1. 所有参与窗口的leash被reparent到Root leash
    2. 通过setLayer强制设定Z序
    3. 非独立的子窗口不参与reparent(跟随父窗口)
    4. Display级别的leash仅在非order-only变化时reparent

八、Handler 责任链

erlang 复制代码
mHandlers (ArrayList) --- 顺序从低到高:

┌──────────────────────────────────────────────────────────────────┐
│  Index 0: DefaultTransitionHandler      [最低优先级, 兜底]       │
│           • handleRequest() → null (不干预请求阶段)              │
│           • startAnimation() → 执行XML/Custom动画               │
│           • mergeAnimation() → anim.end() 终止旧动画             │
│           • 支持的动画类型: 所有                                   │
├──────────────────────────────────────────────────────────────────┤
│  Index 1: RemoteTransitionHandler        [远程动画管理]           │
│           • 维护 TransitionFilter → RemoteTransition 映射         │
│           • 匹配时委托给App进程执行动画                           │
│           • 支持 takeover (动画接管)                              │
├──────────────────────────────────────────────────────────────────┤
│  Index 2+: (可选, 按添加顺序)                                    │
│           KeyguardTransitionHandler    [锁屏转场]                 │
│           PipTransitionHandler         [画中画转场]               │
│           SplitScreenTransitionHandler [分屏转场]                 │
│           DesktopModeTransitionHandler [桌面模式转场]             │
│           ...更多自定义Handler...                                 │
└──────────────────────────────────────────────────────────────────┘

dispatchTransition() 遍历逻辑:
    for i = mHandlers.size()-1 down to 0:    // 从高优先级到低
        consumed = handler.startAnimation(...)
        if consumed: return handler
    
    throw IllegalStateException    // 不应发生 (Default总是兜底)

九、关键类型总结

9.1 转场类型 (TransitionType)

类型 说明
TRANSIT_OPEN 新窗口打开
TRANSIT_CLOSE 窗口关闭
TRANSIT_TO_FRONT 窗口移到前面
TRANSIT_TO_BACK 窗口移到后面
TRANSIT_CHANGE 窗口变化(resize等)
TRANSIT_SLEEP 休眠(触发强制同步)
TRANSIT_KEYGUARD_OCCLUDE 锁屏遮挡
Shell自定义类型 PIP/分屏/最大化/最小化/桌面模式等

9.2 Change Mode (参与者变化模式)

Mode 含义
TRANSIT_OPEN 窗口从不可见变为可见
TRANSIT_CLOSE 窗口从可见变为不可见
TRANSIT_TO_FRONT 窗口提升到前面
TRANSIT_TO_BACK 窗口降低到后面
TRANSIT_CHANGE 窗口内容/边界变化

9.3 关键 Flag

Flag 含义
FLAG_SYNC 需要等待所有轨道清空
FLAG_IS_DISPLAY 参与者是Display级别
FLAG_IS_WALLPAPER 参与者是壁纸
FLAG_IS_OCCLUDED 窗口被其他窗口遮挡
FLAG_NO_ANIMATION 不为此窗口播放动画
FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT 接收StartingWindow转移
FLAG_MOVED_TO_TOP 窗口移动到顶层
FLAG_IS_NON_APP_WINDOW 非App窗口(系统窗口)

十、性能与调试

10.1 超时保护

超时类型 时长 说明
收集超时 (DEFAULT) 5000ms 参与者收集的总时间
收集超时 (CHANGE) 2000ms CHANGE类转场预期更快
Sync强制超时 120ms Sleep/Sync信号后每轨最大等待
BLAST Timeout BLAST_TIMEOUT_DURATION CommitCallback超时

10.2 性能提升机制

  • 并行动画:通过Track机制支持多轨道同时播放
  • 并行收集:当前收集完成后等待阶段,下一个转场可以开始收集
  • 动画加速:Sleep转场可强制加速所有动画到最终状态
  • Surface释放:动画结束后立即释放动画Surface(节省GPU内存)
  • 进程优先级:远程动画执行期间提升动画进程优先级
  • Snapshot暂停:动画期间暂停Task快照持久化(降低IO竞争)

10.3 Tracing支持

  • Perfetto : shell_transition.proto 定义trace事件
  • ProtoLog : WM_SHELL_TRANSITIONS 组,日志点在关键方法入口
  • InteractionJankMonitor: 追踪任务间转场的CUJ延迟
  • TransitionMetrics: 记录转场各阶段的时间消耗

10.4 Debug属性

属性 作用
persist.wm.debug.shell_transitions 启用Shell转场
persist.wm.debug.shell_transit_rotate 使用Shell转场处理旋转
persist.wm.debug.shell_transit_blast 切换BLAST同步方法
persist.wm.debug.start_shell_transition 打印转场启动堆栈
persist.wm.debug.finish_shell_transition 打印转场完成堆栈
相关推荐
事后不诸葛9 小时前
安卓init.rc解析
android·framework
徒手猫9 小时前
myslq 中json 格式的数据如何获取某个属性
android·json
2401_827560209 小时前
【电脑和手机系统】解锁bl后刷LineageOS与Magisk各模块的安装(七)
android·linux·智能手机
超人也会哭️呀10 小时前
ES 混合检索(文本+向量)中的条件处理陷阱——当权限过滤遇到关键词查询
android·大数据·elasticsearch
zuowei288910 小时前
Laravel10.x重磅升级:8大新特性解析
android
imuliuliang11 小时前
Laravel4.x核心特性全解析
android
草莓熊Lotso13 小时前
【Linux系统加餐】从原理到封装:基于建造者模式实现System V信号量工业级C++封装
android·linux·运维·服务器·网络·c++·建造者模式
程序员煊子18 小时前
用 Cursor 从零搭一个 Compose 本地记账 App:实战记录与源码解析
android·kotlin·compose·cursor
alexhilton20 小时前
面向Android开发者的Google I/O 2026
android·kotlin·android jetpack