AOSP15 WMS/AMS系统开发 -窗口动画源码分析

基于 AOSP 15 (Android 15) 源码,分析窗口动画的添加、执行、移除完整流程。


目录

  1. 架构概览
  2. 核心类介绍
  3. 动画添加流程
  4. 动画执行流程
  5. 动画移除流程
  6. 完整时序图
  7. 关键源码位置索引

1. 架构概览

窗口动画系统分为三层:

scss 复制代码
┌──────────────────────────────────────────────────┐
│              应用层 (App Process)                 │
│   RemoteAnimationRunner / View Animation         │
├──────────────────────────────────────────────────┤
│           框架层 (Framework Services)             │
│   AppTransitionController → AppTransition        │
│          → WindowContainer.applyAnimation()      │
│          → SurfaceAnimator.startAnimation()      │
├──────────────────────────────────────────────────┤
│           执行层 (Animation Runner)               │
│   SurfaceAnimationRunner (AnimationThread)       │
│          → ValueAnimator → Transaction.apply()   │
└──────────────────────────────────────────────────┘

核心设计思路:通过 Leash(牵引绳)机制实现动画------创建一个新的 SurfaceControl(Leash),将目标窗口的 Surface 重新挂载到 Leash 上,然后对 Leash 做变换(位移、缩放、透明度等),动画结束后将 Surface 重新挂回原父节点并销毁 Leash。


2. 核心类介绍

2.1 WindowAnimator

路径 : services/core/java/com/android/server/wm/WindowAnimator.java

全局单例,驱动每帧动画更新。通过 Choreographer 注册 FrameCallback,在每个 VSync 信号到来时执行 animate() 方法。

java 复制代码
// WindowAnimator.java
WindowAnimator(final WindowManagerService service) {
    // ...
    mChoreographer = Choreographer.getSfInstance(); // 使用 SurfaceFlinger 的 VSync
    mAnimationFrameCallback = frameTimeNs -> {
        synchronized (mService.mGlobalLock) {
            mAnimationFrameCallbackScheduled = false;
            animate(frameTimeNs); // 核心动画帧回调
        }
    };
}

2.2 SurfaceAnimator

路径 : services/core/java/com/android/server/wm/SurfaceAnimator.java

动画核心控制器,管理 Leash 的创建与销毁,协调动画的启动、取消和完成回调。

每个 WindowContainer 持有一个 SurfaceAnimator 实例。

2.3 SurfaceAnimationRunner

路径 : services/core/java/com/android/server/wm/SurfaceAnimationRunner.java

在不持有 WindowManager 锁的情况下运行动画。在 SurfaceAnimationThread 上使用 ValueAnimator 驱动动画,通过 SurfaceControl.Transaction 应用变换到 Leash。

2.4 AnimationAdapter 接口

路径 : services/core/java/com/android/server/wm/AnimationAdapter.java

动画适配器接口,桥接 SurfaceAnimator 和实际执行动画的组件。主要实现:

  • LocalAnimationAdapter :本地动画,通过 SurfaceAnimationRunner 执行
  • RemoteAnimationController:远程动画,在应用进程中执行(如 Launcher 的动画)

2.5 WindowStateAnimator

路径 : services/core/java/com/android/server/wm/WindowStateAnimator.java

单个窗口(WindowState)的动画和 Surface 状态管理,负责窗口进入/退出动画的应用。

2.6 AppTransitionController

路径 : services/core/java/com/android/server/wm/AppTransitionController.java

检查 App 转场动画是否就绪,解析动画属性,执行可见性变更。是 App 转场动画的入口控制器。


3. 动画添加流程

3.1 触发入口:窗口绘制完成到进入动画

窗口动画的触发起点是窗口绘制完成(Draw 完成),从 WindowStateAnimator.commitFinishDrawingLocked() 开始,完整链路如下:

3.1.1 绘制完成:commitFinishDrawingLocked

当客户端完成一帧绘制后,WMS 调用 finishDrawingLocked() 将 DrawState 从 DRAW_PENDING 推进到 COMMIT_DRAW_PENDING。随后在布局流程中调用 commitFinishDrawingLocked()

java 复制代码
// WindowStateAnimator.java
boolean commitFinishDrawingLocked() {
    // 检查状态必须是 COMMIT_DRAW_PENDING 或 READY_TO_SHOW
    if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
        return false;
    }
    mDrawState = READY_TO_SHOW;

    final ActivityRecord activity = mWin.mActivityRecord;
    // 如果没有 ActivityRecord,或 Activity 允许显示窗口,或是 StartingWindow → 调用 performShow
    if (activity == null || activity.canShowWindows()
            || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
        result = mWin.performShowLocked(); // → 关键跳转点
    }
    return result;
}

DrawState 状态流转

复制代码
NO_SURFACE → DRAW_PENDING → COMMIT_DRAW_PENDING → READY_TO_SHOW → HAS_DRAWN
                                                     ↑               ↑
                                               commitFinish     performShow
                                               DrawingLocked    Locked 设置

3.1.2 显示窗口:performShowLocked

performShowLocked() 负责将窗口从"准备好显示"推进到"已显示",并在此处触发进入动画:

java 复制代码
// WindowState.java
boolean performShowLocked() {
    // 检查状态必须是 READY_TO_SHOW
    if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplay()) {
        return false;
    }

    mWmService.enableScreenIfNeededLocked();

    // ★ 触发进入动画 ★
    mWinAnimator.applyEnterAnimationLocked();

    mWinAnimator.mLastAlpha = -1;     // 强制下一帧 prepareSurface 更新 alpha
    mWinAnimator.mDrawState = HAS_DRAWN;
    mWmService.scheduleAnimationLocked(); // 调度动画帧

    // 递归显示子窗口
    for (int i = mChildren.size() - 1; i >= 0; --i) {
        final WindowState c = mChildren.get(i);
        if (c.mWinAnimator.mSurfaceControl != null) {
            c.performShowLocked();
        }
    }
    return true;
}

注意scheduleAnimationLocked() 在此处被调用,确保 WindowAnimator 在下一个 VSync 执行 animate(),驱动动画帧更新。

3.1.3 应用进入动画:applyEnterAnimationLocked

根据窗口是否首次显示,选择 TRANSIT_ENTER(首次进入)或 TRANSIT_SHOW(重新显示)转场类型:

java 复制代码
// WindowStateAnimator.java
void applyEnterAnimationLocked() {
    final int transit;
    if (mEnterAnimationPending) {
        mEnterAnimationPending = false;
        transit = WindowManagerPolicy.TRANSIT_ENTER;  // 首次进入动画
    } else {
        transit = WindowManagerPolicy.TRANSIT_SHOW;   // 重新显示动画
    }

    // 排除三类窗口:
    // 1. TYPE_BASE_APPLICATION --- 应由 ActivityRecord 控制(App Transition)
    // 2. Wallpaper --- 应由 WallpaperController 控制
    // 3. StartingWindow 下的窗口 --- 跳过
    if (mAttrType != TYPE_BASE_APPLICATION && !mWin.mIsWallpaper
            && !(mWin.mActivityRecord != null && mWin.mActivityRecord.hasStartingWindow())) {
        applyAnimationLocked(transit, true /* isEntrance */);
    }

    // 通知无障碍服务窗口转场
    if (mService.mAccessibilityController.hasCallbacks()) {
        mService.mAccessibilityController.onWindowTransition(mWin, transit);
    }
}

为什么排除 TYPE_BASE_APPLICATION 应用主窗口的动画由 AppTransitionController 统一管理(通过 mOpeningApps/mClosingApps),不走 WindowState 级别的进入动画,以保证所有 Activity 窗口动画的协调性。

3.1.4 选择并加载动画:applyAnimationLocked

根据转场类型选择具体的 Animation 资源:

java 复制代码
// WindowStateAnimator.java
boolean applyAnimationLocked(int transit, boolean isEntrance) {
    // 如果已经在运行同类型的动画,不重复应用
    if (mWin.isAnimating() && mAnimationIsEntrance == isEntrance) {
        return true;
    }

    if (mWin.mControllableInsetProvider != null) {
        return false; // Inset 提供者的动画由 Inset 控制目标驱动
    }

    if (mWin.mToken.okToAnimate()) {
        // 步骤 1:通过 DisplayPolicy 选择动画资源 ID
        int anim = mWin.getDisplayContent().getDisplayPolicy().selectAnimation(mWin, transit);
        Animation a = null;

        if (anim != DisplayPolicy.ANIMATION_STYLEABLE) {
            // 系统内置动画,直接加载
            if (anim != DisplayPolicy.ANIMATION_NONE) {
                a = AnimationUtils.loadAnimation(mContext, anim);
            }
        } else {
            // 从窗口的 WindowAnimation style 属性加载
            // transit=ENTER → windowEnterAnimation
            // transit=EXIT  → windowExitAnimation
            // transit=SHOW  → windowShowAnimation
            // transit=HIDE  → windowHideAnimation
            int attr = -1;
            switch (transit) {
                case TRANSIT_ENTER:
                    attr = R.styleable.WindowAnimation_windowEnterAnimation;
                    break;
                case TRANSIT_EXIT:
                    attr = R.styleable.WindowAnimation_windowExitAnimation;
                    break;
                case TRANSIT_SHOW:
                    attr = R.styleable.WindowAnimation_windowShowAnimation;
                    break;
                case TRANSIT_HIDE:
                    attr = R.styleable.WindowAnimation_windowHideAnimation;
                    break;
            }
            if (attr >= 0) {
                a = mWin.getDisplayContent().mAppTransition.loadAnimationAttr(
                        mWin.mAttrs, attr, TRANSIT_OLD_NONE);
            }
        }

        // 步骤 2:启动动画
        if (a != null) {
            mWin.startAnimation(a);    // → 进入 3.2 节
            mAnimationIsEntrance = isEntrance;
        }
    } else {
        mWin.cancelAnimation();        // 不允许动画时直接取消
    }

    return mWin.isAnimating(0, ANIMATION_TYPE_WINDOW_ANIMATION);
}

3.2 创建动画适配器并启动:WindowState.startAnimation

WindowState.startAnimation()Animation 对象封装为 LocalAnimationAdapter,然后通过 WindowContainer.startAnimation() 交给 SurfaceAnimator

java 复制代码
// WindowState.java
void startAnimation(Animation anim) {
    if (mControllableInsetProvider != null) return;

    // 初始化 Animation 的尺寸信息
    final DisplayInfo displayInfo = getDisplayInfo();
    anim.initialize(mWindowFrames.mFrame.width(), mWindowFrames.mFrame.height(),
            displayInfo.appWidth, displayInfo.appHeight);
    anim.restrictDuration(MAX_ANIMATION_DURATION);
    anim.scaleCurrentDuration(mWmService.getWindowAnimationScaleLocked());

    // 计算窗口在 Surface 坐标系中的位置
    final Point position = new Point();
    transformFrameToSurfacePosition(mWindowFrames.mFrame.left, mWindowFrames.mFrame.top, position);

    // 创建 LocalAnimationAdapter
    final AnimationAdapter adapter = new LocalAnimationAdapter(
            new WindowAnimationSpec(anim, position, false /* canSkipFirstFrame */,
                    0 /* windowCornerRadius */),
            mWmService.mSurfaceAnimationRunner);

    // 根据是否有 ActivityRecord 选择不同 Transaction
    final Transaction t = mActivityRecord != null
            ? getSyncTransaction() : getPendingTransaction();
    startAnimation(t, adapter);            // → WindowContainer.startAnimation()
    commitPendingTransaction();
}

3.3 WindowContainer.startAnimation → SurfaceAnimator.startAnimation

WindowContainer.startAnimation() 直接委托给 SurfaceAnimator

java 复制代码
// WindowContainer.java
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
        @AnimationType int type, ...) {
    mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback,
            animationCancelledCallback, snapshotAnim, mSurfaceFreezer);
}

3.4 SurfaceAnimator.startAnimation --- Leash 创建

这是动画添加的核心步骤,负责创建 Leash 并启动动画执行:

java 复制代码
// SurfaceAnimator.java
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
        @AnimationType int type, ...) {
    // 1. 取消已有动画(标记为 restarting)
    cancelAnimation(t, true /* restarting */, true /* forwardCancel */);

    // 2. 保存动画引用
    mAnimation = anim;
    mAnimationType = type;

    // 3. 获取目标 Surface
    final SurfaceControl surface = mAnimatable.getSurfaceControl();
    if (surface == null) {
        cancelAnimation();
        return;
    }

    // 4. 创建 Leash(动画牵引 Surface)
    mLeash = createAnimationLeash(mAnimatable, surface, t, type,
            mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(),
            0 /* x */, 0 /* y */, hidden, mService.mTransactionFactory);

    // 5. 通知 Animatable Leash 已创建
    mAnimatable.onAnimationLeashCreated(t, mLeash);

    // 6. 通知 Animatable 即将开始动画
    mAnimatable.onLeashAnimationStarting(t, mLeash);

    // 7. 启动动画(交给 AnimationAdapter 执行)
    mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
}

3.5 Leash 创建细节:createAnimationLeash

java 复制代码
// SurfaceAnimator.java
static SurfaceControl createAnimationLeash(Animatable animatable, SurfaceControl surface,
        Transaction t, @AnimationType int type, int width, int height, ...) {
    // 创建一个新的 EffectLayer 作为 Leash
    final SurfaceControl leash = animatable.makeAnimationLeash()
            .setParent(animatable.getAnimationLeashParent())  // 挂到动画专用父节点
            .setName(surface + " - animation-leash of " + animationTypeToString(type))
            .setHidden(hidden)
            .setEffectLayer()
            .build();

    // 设置初始裁剪区域和位置
    t.setWindowCrop(leash, width, height);
    t.setPosition(leash, x, y);
    t.show(leash);
    t.setAlpha(leash, hidden ? 0 : 1);

    // 关键步骤:将目标 Surface 重新挂载到 Leash 下
    t.reparent(surface, leash);

    return leash;
}

Surface 层级变化

makefile 复制代码
动画前:
  ParentSurface
    └── TargetSurface

动画中:
  AnimationLeashParent
    └── Leash (动画变换作用于此)
          └── TargetSurface

动画后:
  ParentSurface
    └── TargetSurface  (恢复原位)

3.6 补充:App Transition 路径(Activity 级别转场)

上面 3.1~3.5 分析的是窗口级别 的进入动画路径(非 TYPE_BASE_APPLICATION 窗口)。对于应用主窗口,动画由 AppTransitionController 统一管理:

scss 复制代码
AppTransitionController.handleAppTransitionReady()
  ├─ transitionGoodToGo()            检查所有 App 窗口是否就绪
  ├─ getTransitCompatType()          确定转场类型(如 TRANSIT_OLD_ACTIVITY_OPEN)
  ├─ getAnimationTargets()           收集动画目标 WindowContainer
  └─ applyAnimations()
       └─ wc.applyAnimation()
            └─ getAnimationAdapter()     获取 AnimationAdapter
                 ├─ [远程动画] RemoteAnimationController
                 └─ [本地动画] AppTransition.loadAnimation() → WindowAnimationSpec → LocalAnimationAdapter

该路径最终同样走到 WindowContainer.startAnimation()SurfaceAnimator.startAnimation(),与窗口级动画在 Leash 创建和动画执行阶段完全一致。


4. 动画执行流程

4.1 LocalAnimationAdapter.startAnimation

java 复制代码
// LocalAnimationAdapter.java:64
public void startAnimation(SurfaceControl animationLeash, Transaction t,
        @AnimationType int type, OnAnimationFinishedCallback finishCallback) {
    mAnimator.startAnimation(mSpec, animationLeash, t,
            () -> finishCallback.onAnimationFinished(type, this));
}

4.2 SurfaceAnimationRunner.startAnimation

java 复制代码
// SurfaceAnimationRunner.java
void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t,
        Runnable finishCallback) {
    synchronized (mLock) {
        final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash, finishCallback);

        // 加入待启动队列
        mPendingAnimations.put(animationLeash, runningAnim);

        // 通过 Choreographer 在下一帧启动
        if (!mAnimationStartDeferred && mPreProcessingAnimations.isEmpty()) {
            mChoreographer.postFrameCallback(this::startAnimations);
        }

        // 立即应用初始变换(第 0 帧)
        applyTransformation(runningAnim, t, 0 /* currentPlayTime */);
    }
}

4.3 ValueAnimator 驱动逐帧更新

java 复制代码
// SurfaceAnimationRunner.java:281
private void startAnimationLocked(RunningAnimation a) {
    final ValueAnimator anim = mAnimatorFactory.makeAnimator();
    anim.setDuration(a.mAnimSpec.getDuration());

    // 每帧更新回调
    anim.addUpdateListener(animation -> {
        if (!a.mCancelled) {
            long currentPlayTime = anim.getCurrentPlayTime();
            applyTransformation(a, mFrameTransaction, currentPlayTime);
        }
        scheduleApplyTransaction(); // 调度 Transaction 提交
    });

    // 动画结束回调
    anim.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            mRunningAnimations.remove(a.mLeash);
            if (!a.mCancelled) {
                // 在 AnimationThread 上执行完成回调
                mAnimationThreadHandler.post(a.mFinishCallback);
            }
        }
    });

    a.mAnim = anim;
    mRunningAnimations.put(a.mLeash, a);
    anim.start();
}

4.4 逐帧变换应用

java 复制代码
// SurfaceAnimationRunner.java
private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
    a.mAnimSpec.apply(t, a.mLeash, currentPlayTime);
}

// WindowAnimationSpec.java
public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
    tmp.transformation.clear();
    mAnimation.getTransformation(currentPlayTime, tmp.transformation);  // 从 Animation 获取当前变换
    tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
    t.setMatrix(leash, tmp.transformation.getMatrix(), tmp.floats);  // 设置矩阵
    t.setAlpha(leash, tmp.transformation.getAlpha());                 // 设置透明度

    // 设置裁剪区域
    if (tmp.transformation.hasClipRect()) {
        t.setWindowCrop(leash, tmp.transformation.getClipRect());
    }
}

4.5 Transaction 提交

java 复制代码
// SurfaceAnimationRunner.java
private void applyTransaction() {
    mFrameTransaction.setAnimationTransaction();           // 标记为动画事务
    mFrameTransaction.setFrameTimelineVsync(mChoreographer.getVsyncId()); // 关联 VSync
    mFrameTransaction.apply();                             // 提交到 SurfaceFlinger
    mApplyScheduled = false;
}

4.6 WindowAnimator.animate() 的角色

WindowAnimator 在每帧 VSync 时执行,负责:

  1. 调用 dc.updateWindowsForAnimator() 更新窗口动画状态
  2. 调用 dc.prepareSurfaces() 准备 Surface
  3. 合并各 DisplayContent 的 pending Transaction
  4. 统一 apply 整个 Transaction
java 复制代码
// WindowAnimator.java
private void animate(long frameTimeNs) {
    scheduleAnimation(); // 预先调度下一帧(持续反压)

    for (int i = 0; i < numDisplays; i++) {
        final DisplayContent dc = root.getChildAt(i);
        dc.updateWindowsForAnimator();  // 更新窗口动画
        dc.prepareSurfaces();           // 准备 Surface
    }

    // 检查是否还有动画在运行
    for (int i = 0; i < numDisplays; i++) {
        if (dc.isAnimating(animationFlags, ANIMATION_TYPE_ALL)) {
            rootAnimating = true;
        }
        mTransaction.merge(dc.getPendingTransaction()); // 合并 Transaction
    }

    mTransaction.apply(); // 统一提交
}

5. 动画移除流程

5.1 正常结束

SurfaceAnimationRunner 中的 ValueAnimator 播放完毕时:

scss 复制代码
ValueAnimator.onAnimationEnd()
  → mAnimationThreadHandler.post(a.mFinishCallback)
    → mInnerAnimationFinishedCallback.onAnimationFinished()

mInnerAnimationFinishedCallback 是在 SurfaceAnimator 构造时创建的:

java 复制代码
// SurfaceAnimator.java
private OnAnimationFinishedCallback getFinishedCallback(...) {
    return (type, anim) -> {
        synchronized (mService.mGlobalLock) {
            if (anim != mAnimation) return; // 动画已被替换,忽略

            final Runnable resetAndInvokeFinish = () -> {
                if (anim != mAnimation) return; // 再次检查
                reset(mAnimatable.getSyncTransaction(), true /* destroyLeash */);
                // 回调通知
                if (staticAnimationFinishedCallback != null) {
                    staticAnimationFinishedCallback.onAnimationFinished(type, anim);
                }
                if (animationFinishCallback != null) {
                    animationFinishCallback.onAnimationFinished(type, anim);
                }
            };

            // 检查是否需要延迟结束
            if (!(mAnimatable.shouldDeferAnimationFinish(resetAndInvokeFinish)
                    || anim.shouldDeferAnimationFinish(resetAndInvokeFinish))) {
                resetAndInvokeFinish.run();
            }
        }
    };
}

5.2 reset --- 清理 Leash

java 复制代码
// SurfaceAnimator.java
private void reset(Transaction t, boolean destroyLeash) {
    mService.mAnimationTransferMap.remove(mAnimation);
    mAnimation = null;
    mSurfaceAnimationFinishedCallback = null;
    mAnimationType = ANIMATION_TYPE_NONE;

    // 清理快照
    if (mSnapshot != null) {
        mSnapshot.cancelAnimation(t, !destroyLeash);
        mSnapshot = null;
    }

    if (mLeash == null) return;

    SurfaceControl leash = mLeash;
    mLeash = null;

    // 移除 Leash,将 Surface 重新挂回原父节点
    final boolean scheduleAnim = removeLeash(t, mAnimatable, leash, destroyLeash);
    mAnimationFinished = false;

    if (scheduleAnim) {
        mService.scheduleAnimationLocked();
    }
}

5.3 removeLeash --- Surface 重新挂载

java 复制代码
// SurfaceAnimator.java
static boolean removeLeash(Transaction t, Animatable animatable, SurfaceControl leash,
        boolean destroy) {
    final SurfaceControl surface = animatable.getSurfaceControl();
    final SurfaceControl parent = animatable.getParentSurfaceControl();
    final SurfaceControl curAnimationLeash = animatable.getAnimationLeash();

    // 判断是否需要重新挂载
    final boolean reparent = surface != null && (curAnimationLeash == null
            || curAnimationLeash.equals(leash));

    if (reparent) {
        // 将 Surface 重新挂回原始父节点
        if (surface.isValid() && parent != null && parent.isValid()) {
            t.reparent(surface, parent);
        }
    }

    // 销毁 Leash
    if (destroy) {
        t.remove(leash);
    }

    // 通知 Animatable Leash 已丢失
    if (reparent) {
        animatable.onAnimationLeashLost(t);
    }

    return scheduleAnim;
}

5.4 主动取消动画

java 复制代码
// SurfaceAnimator.java
private void cancelAnimation(Transaction t, boolean restarting, boolean forwardCancel) {
    final SurfaceControl leash = mLeash;
    final AnimationAdapter animation = mAnimation;

    // 重置内部状态
    reset(t, false);

    if (animation != null) {
        if (forwardCancel) {
            // 通知动画适配器动画被取消
            animation.onAnimationCancelled(leash);
            // SurfaceAnimationRunner 收到后取消 ValueAnimator
        }
        if (!restarting) {
            // 通知外部回调动画结束
            if (mStaticAnimationFinishedCallback != null) {
                mStaticAnimationFinishedCallback.onAnimationFinished(animationType, animation);
            }
        }
    }

    if (forwardCancel) {
        // 取消快照动画
        if (snapshot != null) snapshot.cancelAnimation(t, false);
        // 移除 Leash
        if (leash != null) {
            t.remove(leash);
            mService.scheduleAnimationLocked();
        }
    }
}

5.5 SurfaceAnimationRunner 处理取消

java 复制代码
// SurfaceAnimationRunner.java
void onAnimationCancelled(SurfaceControl leash) {
    synchronized (mLock) {
        // 从待启动队列中移除
        if (mPendingAnimations.containsKey(leash)) {
            mPendingAnimations.remove(leash);
            return;
        }
        // 从预处理队列中移除
        if (mPreProcessingAnimations.containsKey(leash)) {
            mPreProcessingAnimations.remove(leash);
            return;
        }
        // 从运行中队列中移除并取消
        final RunningAnimation anim = mRunningAnimations.get(leash);
        if (anim != null) {
            mRunningAnimations.remove(leash);
            synchronized (mCancelLock) {
                anim.mCancelled = true;
            }
            mSurfaceAnimationHandler.post(() -> {
                anim.mAnim.cancel();       // 取消 ValueAnimator
                applyTransaction();         // 提交最终状态
            });
        }
    }
}

5.6 WindowState 动画结束

对于 WindowState 级别的动画(非 App 转场),结束回调链:

scss 复制代码
SurfaceAnimator.mInnerAnimationFinishedCallback
  → WindowContainer.doAnimationFinished()
    → WindowState.onAnimationFinished()
      → WindowStateAnimator.onAnimationFinished()
        → WindowState.checkPolicyVisibilityChange()
        → WindowState.onExitAnimationDone()
java 复制代码
// WindowStateAnimator.java
void onAnimationFinished() {
    mWin.checkPolicyVisibilityChange();

    // 请求重新布局
    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM;
    if (displayContent.mWallpaperController.isWallpaperTarget(mWin)) {
        displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
    }

    // 更新 Activity 可见性
    if (mWin.mActivityRecord != null) {
        mWin.mActivityRecord.updateReportedVisibilityLocked();
    }
}

6. 完整时序图

6.1 窗口级进入动画完整流程(从 commitFinishDrawingLocked 开始)

scss 复制代码
客户端完成绘制(finishDrawing)
      │
      ▼
WindowStateAnimator.finishDrawingLocked()
      │  mDrawState: DRAW_PENDING → COMMIT_DRAW_PENDING
      │
      ▼
WindowStateAnimator.commitFinishDrawingLocked()
      │  mDrawState: COMMIT_DRAW_PENDING → READY_TO_SHOW
      │  检查是否可以显示(无 ActivityRecord / canShowWindows / StartingWindow)
      │
      ▼
WindowState.performShowLocked()
      │  检查 mDrawState == READY_TO_SHOW && isReadyForDisplay()
      │
      ├─ mWinAnimator.applyEnterAnimationLocked()    ★ 触发进入动画 ★
      ├─ mDrawState = HAS_DRAWN
      ├─ scheduleAnimationLocked()                    调度动画帧
      │
      ▼
WindowStateAnimator.applyEnterAnimationLocked()
      │
      ├─ 确定转场类型: TRANSIT_ENTER(首次)或 TRANSIT_SHOW(重新显示)
      ├─ 排除 TYPE_BASE_APPLICATION / Wallpaper / StartingWindow 下的窗口
      │
      ▼
WindowStateAnimator.applyAnimationLocked(transit, isEntrance=true)
      │
      ├─ okToAnimate() 检查是否可以动画
      ├─ selectAnimation() 或 loadAnimationAttr() 加载 Animation 资源
      │   ├─ TRANSIT_ENTER → WindowAnimation_windowEnterAnimation
      │   └─ TRANSIT_SHOW  → WindowAnimation_windowShowAnimation
      │
      ▼ (a != null)
WindowState.startAnimation(a)
      │
      ├─ anim.initialize() / restrictDuration() / scaleCurrentDuration()
      ├─ new WindowAnimationSpec(anim, position, ...)
      ├─ new LocalAnimationAdapter(spec, mSurfaceAnimationRunner)
      │
      ▼
WindowContainer.startAnimation(t, adapter)
      │
      ▼
SurfaceAnimator.startAnimation()
      │
      ├─ cancelAnimation(restarting=true)  取消已有动画
      ├─ createAnimationLeash()            创建 Leash
      │     └─ t.reparent(surface, leash)  Surface 挂到 Leash 下
      ├─ onAnimationLeashCreated()         通知 Leash 创建
      ├─ onLeashAnimationStarting()        通知动画即将开始
      │
      ▼
AnimationAdapter.startAnimation(leash, t, type, finishCallback)
      │
      ▼ [LocalAnimationAdapter]
SurfaceAnimationRunner.startAnimation()
      │
      ├─ new RunningAnimation(spec, leash, finishCallback)
      ├─ mPendingAnimations.put(leash, runningAnim)
      ├─ mChoreographer.postFrameCallback(startAnimations)
      ▼ [下一帧 VSync]
startAnimations()
      │
      ▼
startAnimationLocked()
      │
      ├─ new ValueAnimator(duration)
      ├─ anim.addUpdateListener(→ applyTransformation())
      ├─ anim.addListener(→ onAnimationEnd → finishCallback)
      ├─ mRunningAnimations.put(leash, a)
      ├─ anim.start()
      │
      ▼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
      │    [每帧循环]               │
      ▼                            │
applyTransformation()              │
  ├─ spec.apply(t, leash, time)    │
  │   ├─ t.setMatrix()             │
  │   ├─ t.setAlpha()              │
  │   └─ t.setWindowCrop()         │
  └─ scheduleApplyTransaction()    │
      └─ applyTransaction()        │
          └─ t.apply()             │
               │                   │
               ▼                   │
         SurfaceFlinger 合成        │
               │                   │
      ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┘
      │
      ▼ [动画播放完毕]
ValueAnimator.onAnimationEnd()
      │
      ▼
mFinishCallback (→ mInnerAnimationFinishedCallback)
      │
      ▼
SurfaceAnimator 内部完成回调
      │
      ├─ shouldDeferAnimationFinish() 检查是否延迟结束
      │
      ▼
reset(syncTransaction, destroyLeash=true)
      │
      ├─ mAnimation = null
      ├─ mLeash = null
      │
      ▼
removeLeash()
      │
      ├─ t.reparent(surface, parent)  Surface 挂回原父节点
      ├─ t.remove(leash)              销毁 Leash
      ├─ animatable.onAnimationLeashLost(t)
      │
      ▼
staticAnimationFinishedCallback.onAnimationFinished()
      │
      ▼
WindowContainer.doAnimationFinished()
      │
      ▼
ActivityRecord/WindowState.onAnimationFinished()
      │
      ├─ 更新可见性
      ├─ 请求重新布局
      └─ 通知上层动画完成

6.2 远程动画流程

scss 复制代码
AppTransitionController.handleAppTransitionReady()
      │
      ▼
WindowContainer.getAnimationAdapter()
      │
      ├─ controller != null (RemoteAnimationController)
      │
      ▼
RemoteAnimationController.createRemoteAnimationRecord()
      │
      ▼
SurfaceAnimator.startAnimation()
      ├─ 创建 Leash
      └─ mAnimation.startAnimation(leash, t, type, finishCallback)
            │
            ▼ [RemoteAnimationAdapter]
RemoteAnimationController.onStartAnimation()
      │
      ├─ 构建 RemoteAnimationTarget[] (包含 leash)
      ├─ 跨进程调用 mRemoteAnimationAdapter.getRunner().onStartAnimation()
      │
      ▼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
      │   [应用进程]                      │
      ▼                                  │
RemoteAnimationRunner.onStartAnimation() │
      │                                  │
      ├─ 操作 leash 的 Transaction        │
      ├─ 完成后调用                        │
      │   finishCallback.onAnimationFinished()
      │                                  │
      ▼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┘
      │
      ▼ [回到系统进程]
SurfaceAnimator 内部完成回调
      │
      ▼
reset() → removeLeash() (与本地动画相同)

7. 关键源码位置索引

路径 职责
WindowAnimator services/wm/WindowAnimator.java 全局动画帧驱动
SurfaceAnimator services/wm/SurfaceAnimator.java Leash 管理与动画生命周期
SurfaceAnimationRunner services/wm/SurfaceAnimationRunner.java 无锁动画执行(ValueAnimator)
LocalAnimationAdapter services/wm/LocalAnimationAdapter.java 本地动画适配器
AnimationAdapter services/wm/AnimationAdapter.java 动画适配器接口
WindowAnimationSpec services/wm/WindowAnimationSpec.java 窗口动画规格(变换计算)
AppTransitionController services/wm/AppTransitionController.java App 转场控制器
AppTransition services/wm/AppTransition.java 转场动画状态管理
RemoteAnimationController services/wm/RemoteAnimationController.java 远程动画控制器
WindowStateAnimator services/wm/WindowStateAnimator.java 单窗口动画状态
WindowContainer services/wm/WindowContainer.java 动画目标容器基类
SurfaceAnimationThread services/wm/SurfaceAnimationThread.java 动画专用线程
AnimationThread server/AnimationThread.java 系统动画线程

所有路径基于 frameworks/base/services/core/java/com/android/server/wm/


8. 动画类型

SurfaceAnimator 定义了以下动画类型(位掩码):

类型 说明
ANIMATION_TYPE_NONE 0 无动画
ANIMATION_TYPE_APP_TRANSITION 1 App 转场动画
ANIMATION_TYPE_SCREEN_ROTATION 2 屏幕旋转动画
ANIMATION_TYPE_DIMMER 4 调光动画
ANIMATION_TYPE_RECENTS 8 最近任务动画
ANIMATION_TYPE_WINDOW_ANIMATION 16 窗口动画(非 Activity)
ANIMATION_TYPE_INSETS_CONTROL 32 插入控制动画
ANIMATION_TYPE_TOKEN_TRANSFORM 64 Token 变换动画
ANIMATION_TYPE_STARTING_REVEAL 128 启动窗口揭显动画
ANIMATION_TYPE_PREDICT_BACK 256 预测返回手势动画

9. 总结

动画添加:3 步走

  1. 选择动画 --- AppTransitionController 确定转场类型,AppTransition 加载具体 Animation
  2. 创建 Leash --- SurfaceAnimator.startAnimation() 创建 Leash 并将 Surface 重新挂载
  3. 启动执行 --- SurfaceAnimationRunner 通过 ValueAnimator 逐帧驱动变换

动画执行:逐帧循环

  1. ValueAnimator 每帧触发 addUpdateListener
  2. WindowAnimationSpec.apply() 计算 Matrix/Alpha/Crop 并写入 Transaction
  3. applyTransaction() 提交到 SurfaceFlinger

动画移除:2 条路径

  1. 正常结束 --- ValueAnimator.onAnimationEnd()finishCallbackreset()removeLeash()
  2. 主动取消 --- cancelAnimation()animation.onAnimationCancelled()reset()removeLeash()

核心清理逻辑统一在 removeLeash() 中:将 Surface 重新挂回原父节点,销毁 Leash,通知 onAnimationLeashLost()

相关推荐
程序员陆业聪7 小时前
Shadow核心原理:壳子Activity与代理机制的精妙设计
android
plainGeekDev8 小时前
Android 开发者再不转Kotlin,真的来不及了
android·kotlin
赏金术士8 小时前
第五章:数据层—网络请求与Repository
android·kotlin·compose
初雪云8 小时前
让安卓发版再简单一点,体验一键自动化发布
android·运维·自动化
jushi89999 小时前
抖音APP抖音助手增强版 内置逗音小手 支持无水印下载/音频提取/去广告等功能
android·智能手机·音视频
plainGeekDev9 小时前
Android 专家岗 Kotlin 面试题:能答出这些,说明你对语言设计有自己的理解
android·kotlin
plainGeekDev9 小时前
Android 资深岗 Kotlin 面试题:只会用协程不够,你得懂它为什么这么设计
android·kotlin
StarShip9 小时前
第一阶段:应用层视图绘制
android