完全基于AOSP 16源码,我们从头开始,把窗口动画的每一个关键步骤和涉及的源码都讲清楚。我会尽量用简单的话来解释,让你能跟着代码一步步看明白整个流程。
📝 窗口动画触发入口:WindowManagerService 的 applyAnimationLocked
窗口动画的启动通常由窗口状态的改变触发,比如一个新的Activity启动、一个窗口被添加或移除。这些操作最终都会调用到 WindowManagerService (WMS) 的 applyAnimationLocked 方法。
源码位置: frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
boolean applyAnimationLocked(WindowState win, int transit, boolean isEntrance) {
// 1. 根据窗口类型(如Activity, Dialog)和切换类型(如打开、关闭)加载对应的动画资源
Animation a = loadAnimation(win, transit, isEntrance);
if (a != null) {
// 2. 如果成功加载了动画,就调用窗口的WindowStateAnimator来启动这个动画
win.mWinAnimator.setAnimation(a);
return true;
}
return false;
}
这个方法就像动画的“发令枪”,它决定要不要播放动画,以及播放哪个动画。
🗺️ 核心数据结构与容器
在深入动画细节前,我们先了解WMS中几个关键的“容器”和数据结构,它们构成了动画系统的基础设施。
@startuml
!theme plain
title WMS核心数据结构与容器关系
class WindowManagerService {
+ mAnimator: WindowAnimator
+ mWindowMap: HashMap<IBinder, WindowState>
+ mRoot: RootWindowContainer
}
class RootWindowContainer {
+ mChildren: WindowList<WindowContainer>
+ getWindowContainer(): WindowContainer
}
class WindowContainer {
+ mChildren: WindowList<WindowContainer>
+ mSurfaceAnimator: SurfaceAnimator
}
class WindowToken {
+ mChildren: WindowList<WindowContainer>
}
class WindowState {
+ mWinAnimator: WindowStateAnimator
+ mSurfaceControl: SurfaceControl
+ mToken: WindowToken
}
class WindowStateAnimator {
+ mSurfaceControl: SurfaceControl
+ mSurfaceAnimator: SurfaceAnimator
}
class SurfaceAnimator {
+ mLeash: SurfaceControl
+ mAnimation: Animation
}
WindowManagerService *-- WindowAnimator
WindowManagerService *-- RootWindowContainer
RootWindowContainer "1" *-- "0..*" WindowContainer
WindowContainer <|-- WindowToken
WindowContainer <|-- WindowState
WindowToken *-- "0..*" WindowState
WindowState *-- WindowStateAnimator
WindowStateAnimator *-- SurfaceAnimator
note right of RootWindowContainer
"WMS 管理所有窗口的根容器,其子节点是 DisplayContent。
通过它,WMS能遍历所有窗口。"
end note
note right of WindowContainer
"一个抽象基类,代表窗口层次结构中的一个节点。
它实现了窗口层级管理、动画、Surface管理等功能。"
end note
note right of WindowToken
"一个逻辑分组容器,代表一组窗口的令牌,
例如一个Activity或一个Toast。"
end note
note right of WindowState
"代表一个具体的应用窗口,如Dialog、Activity界面。
它包含了窗口的所有属性。"
end note
@enduml
· WindowAnimator: 它是动画子系统的“总管家”,负责驱动所有窗口的动画更新。 · RootWindowContainer: WMS管理所有窗口的“根容器”,从这里可以找到屏幕上的任何窗口。 · WindowContainer: 一个抽象的“容器基类”,窗口层级中的每个节点(如Display、Task、Activity)都继承自它。它提供了统一的动画和Surface管理能力。 · WindowToken: 一个“令牌”容器,用于逻辑上分组管理窗口,比如一个Activity下的所有弹窗。 · WindowState: 代表一个真实的“窗口”,包含了窗口的所有属性,如位置、大小、可见性等。 · WindowStateAnimator: WindowState的“专属动画师”,负责管理这个特定窗口的Surface和动画状态。 · SurfaceAnimator: 真正的“动画执行者”,它负责创建Leash图层、持有Animation对象,并在每一帧更新图层的属性。
⚙️ 关键类深度剖析
- WindowAnimator - 动画总管
源码位置: frameworks/base/services/core/java/com/android/server/wm/WindowAnimator.java
WindowAnimator的主要工作是 animate() 方法,它被周期性调用以驱动动画进度。
void animate(long frameTimeNs) {
synchronized (mService.mGlobalLock) {
// 1. 遍历所有正在播放动画的窗口
for (int i = 0; i < mWinAnimatorLists.size(); i++) {
WindowStateAnimator winAnimator = mWinAnimatorLists.get(i);
// 2. 推动单个窗口动画前进一帧
winAnimator.stepAnimationLocked(frameTimeNs);
}
}
// 3. 通知WindowSurfacePlacer,是时候将更新后的窗口位置/属性应用到Surface了
mWindowPlacer.performSurfacePlacement();
}
它就像一个“指挥家”,遍历所有需要更新的“乐手”(WindowStateAnimator),并最终将结果“谱写”到屏幕上。
- WindowStateAnimator - 窗口动画师
源码位置: frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java
WindowStateAnimator 是 WindowState 的成员,它管理着一个特定窗口的Surface,并负责执行动画。
class WindowStateAnimator {
SurfaceControl mSurfaceControl; // 指向应用绘制的Surface
final SurfaceAnimator mSurfaceAnimator; // 真正的动画执行器
// ... 其他成员
void setAnimation(Animation anim) {
// 将动画设置给SurfaceAnimator去执行
mSurfaceAnimator.startAnimation(anim);
}
void stepAnimationLocked(long currentTime) {
// 此方法最终会调用到 SurfaceAnimator.onAnimationUpdate()
mSurfaceAnimator.onAnimationUpdate(currentTime);
}
}
它就像一个“助理”,将动画任务委托给更专业的 SurfaceAnimator 去执行。
- SurfaceAnimator - 动画执行器与Leash机制
源码位置: frameworks/base/services/core/java/com/android/server/wm/SurfaceAnimator.java
这是动画系统的核心,它负责创建Leash图层、持有Animation对象并计算每一帧的变换。
Leash图层是理解窗口动画的关键。AOSP的设计是:当需要对一个窗口做动画时,会创建一个新的、透明的图层,将原窗口的Surface“拴”在这个新图层上,然后只对这个新图层做变换。
public class SurfaceAnimator {
private SurfaceControl mLeash; // 动画用的“缰绳”图层
private Animation mAnimation; // 动画对象
void startAnimation(Animation anim) {
// 1. 创建Leash图层
mLeash = createAnimationLeash(...);
// 2. 将原窗口Surface挂载到Leash下
Transaction t = new Transaction();
t.reparent(mSurfaceControl, mLeash);
t.apply();
// 3. 持有动画对象并开始
mAnimation = anim;
mAnimation.start();
}
void onAnimationUpdate(long currentTime) {
// 1. 计算当前时间点的变换矩阵
Transformation transform = new Transformation();
boolean more = mAnimation.getTransformation(currentTime, transform);
// 2. 将变换应用到Leash图层
Transaction t = new Transaction();
t.setMatrix(mLeash, transform.getMatrix());
t.setAlpha(mLeash, transform.getAlpha());
t.apply();
// 3. 如果动画还没结束,继续请求下一帧
if (more) {
scheduleAnimation();
} else {
// 4. 动画结束,销毁Leash,恢复原状
onAnimationEnd();
}
}
}
Leash机制的精妙之处在于:
· 隔离性:动画的变换只影响Leash,不影响窗口本身的Surface属性,避免了状态污染。 · 灵活性:可以实现复杂的变换,如旋转、缩放、透明度变化,而无需修改应用本身的绘制逻辑。
- Animation - 变换的定义者
源码位置: frameworks/base/core/java/android/view/animation/Animation.java
Animation 是一个抽象类,定义了动画的“剧本”。它的 getTransformation 方法是核心。
public boolean getTransformation(long currentTime, Transformation outTransformation) {
// 1. 计算当前时间在动画总时长中的“进度” (0.0 ~ 1.0)
float normalizedTime = calculateNormalizedTime(currentTime);
// 2. 通过插值器(Interpolator)对进度进行“加工”,实现加速、减速等效果
float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
// 3. 应用变换。子类如 TranslateAnimation, ScaleAnimation 会在这里计算具体的矩阵
applyTransformation(interpolatedTime, outTransformation);
// 4. 返回是否还有更多帧需要播放
return !mEnded;
}
💻 源码级启动流程详解
现在我们把所有点串起来,看一个完整的动画是如何启动的。
@startuml
!theme plain
title 窗口动画启动流程-源码级详解
participant "WindowManagerService" as WMS
participant "WindowState" as WS
participant "WindowStateAnimator" as WSA
participant "SurfaceAnimator" as SA
participant "SurfaceControl.Transaction" as SC_Transaction
participant "SurfaceFlinger" as SF
WMS -> WMS: applyAnimationLocked()
note right: 根据窗口类型和切换类型\n加载Animation资源
WMS -> WS: 获取WindowState
WMS -> WSA: setAnimation(anim)
WSA -> SA: startAnimation(anim)
note right: 将动画委托给SurfaceAnimator执行
SA -> SA: createAnimationLeash()
note right: 创建一个新的、透明的\n"animation-leash of ..."图层
SA -> SC_Transaction: reparent(mSurfaceControl, mLeash)
note right: 将窗口Surface挂载到Leash下
SC_Transaction -> SF
SA -> SA: mAnimation.start()
note right: 初始化动画开始时间
SA -> SA: scheduleAnimation()
note right: 向Choreographer注册CALLBACK_ANIMATION
@enduml
⏳ 源码级执行与驱动流程详解
动画一旦启动,就需要在每一帧更新,这就是Choreographer的舞台。
@startuml
!theme plain
title 窗口动画执行流程-源码级详解
participant "硬件VSync" as VSYNC
participant "Choreographer" as Choreo
participant "WindowAnimator" as WA
participant "WindowStateAnimator" as WSA
participant "SurfaceAnimator" as SA
participant "Animation" as Anim
participant "SurfaceControl.Transaction" as SC_Transaction
participant "SurfaceFlinger" as SF
loop 每 16.7ms (60fps)
VSYNC -> Choreo: onVsync()
Choreo -> Choreo: doFrame()
note right: 处理CALLBACK_ANIMATION类型的回调
Choreo -> WA: animate()
note right: WMS的动画总入口
WA -> WA: 遍历所有WindowStateAnimator
WA -> WSA: stepAnimationLocked()
WSA -> SA: onAnimationUpdate()
SA -> Anim: getTransformation()
note right: 根据当前时间和插值器\n计算变换矩阵和Alpha值
Anim --> SA: 返回Transformation
SA -> SC_Transaction: setMatrix(mLeash, matrix)
SA -> SC_Transaction: setAlpha(mLeash, alpha)
note right: 将变换应用到Leash图层
SC_Transaction -> SF: commit()
SA -> SA: scheduleAnimation()
note right: 如果动画未结束,请求下一帧
Choreo -> Choreo: 处理CALLBACK_TRAVERSAL
note right: 绘制完成
Choreo -> SF: 最终的合成与送显
end
@enduml
🧩 SurfaceFlinger 的合成与送显
动画执行的最终环节,是SurfaceFlinger的合成与显示。SurfaceFlinger是Android系统的“画家”,负责将所有窗口的图层合成最终的画面。
· 接收Transaction: WMS通过SurfaceControl.Transaction将每一帧对Leash图层的更新(位置、透明度等)打包,通过Binder跨进程发送给SurfaceFlinger。 · 合成: SurfaceFlinger收到Transaction后,会在下一个VSync信号到来时,按照Z轴顺序(Z-order)将包括Leash在内的所有可见图层合成一张完整的图像。 · 送显: 最后,SurfaceFlinger将合成好的图像数据提交给硬件显示驱动,呈现在屏幕上。
💎 总结:窗口动画的生命周期
通过以上分析,我们可以清晰地梳理出Android窗口动画的完整生命周期:
- 触发: 一个窗口状态变化(如打开Activity),WMS的 applyAnimationLocked() 被调用,加载对应的 Animation 资源。
- 准备: 动画被委托给 SurfaceAnimator,它创建一个 Leash 图层,并将原窗口 Surface 挂载其下。
- 注册: SurfaceAnimator 向 Choreographer 注册一个 CALLBACK_ANIMATION 回调,准备接收下一帧的VSync信号。
- 驱动: 每16.7ms,硬件VSync信号到达,Choreographer 的 doFrame() 方法被执行,触发 CALLBACK_ANIMATION 类型的回调。
- 更新: 回调链路 WindowAnimator.animate() -> WindowStateAnimator.stepAnimationLocked() -> SurfaceAnimator.onAnimationUpdate() 被执行。
- 计算: SurfaceAnimator 调用 Animation.getTransformation(),根据当前时间和插值器计算出当前帧的变换矩阵(平移、缩放、旋转等)和透明度。
- 应用: SurfaceAnimator 通过 SurfaceControl.Transaction 将计算出的变换应用到 Leash 图层。
- 合成: SurfaceFlinger 在下一个VSync周期中,将应用了新变换的 Leash 图层与其他图层合成。
- 显示: 合成后的画面被送到屏幕,用户看到动画的一帧。
- 结束: 循环步骤4-9,直到 Animation 返回 more = false。SurfaceAnimator 销毁 Leash 图层,将原窗口 Surface 放回原位,动画结束。