Android V : WindowContainer 本地动画框架

444 阅读6分钟

并不是所有窗口动画都是由或经由 shell-transitions 执行的,有一类窗口动画,称之为local animation(本地动画),是在 WM-Core 侧执行的。例如,窗口的异步旋转,或者窗口的退出动画。

local animation 框架的时序图,如下

sequenceDiagram

调用方 ->> WindowContainer: startAnimation()
WindowContainer ->> SurfaceAnimator: startAnimation()
SurfaceAnimator ->> SurfaceAnimator: createAnimationLeash()
Note right of SurfaceAnimator: 创建 leash,并把 WC surface reparent 到 leash
SurfaceAnimator -->> WindowContainer: onAnimationLeashCreated()
Note over SurfaceAnimator,WindowContainer: WC 保存 leash,还会更新 layer
SurfaceAnimator ->> AnimationAdapter: startAnimation(leash)
AnimationAdapter ->> SurfaceAnimationRunner: startAnimation(AnimationSpec, lesh)
SurfaceAnimationRunner ->> +Choreagrapher: postFrameCallback()
Note right of SurfaceAnimationRunner: 类型为 CALLBACK_ANIMATION
Choreagrapher -->> -SurfaceAnimationRunner: startAnimations()
SurfaceAnimationRunner ->> ValueAnimator: addUpdateListener()
SurfaceAnimationRunner ->> ValueAnimator: addListener()
ValueAnimator -->> SurfaceAnimationRunner: onAnimationUpdate()

activate SurfaceAnimationRunner
rect rgb(191, 223, 255)
SurfaceAnimationRunner ->> +SurfaceAnimationRunner: applyTransformation(mFrameTransaction)
SurfaceAnimationRunner ->> -AnimationSpec: apply()
Note over SurfaceAnimationRunner,AnimationSpec: AnimationSpec 从 Animation 获取 transformation,使用 mFrameTransaction ,利用 transformation 操作 leash
end

rect rgb(200, 150, 255)
SurfaceAnimationRunner ->> +SurfaceAnimationRunner: scheduleApplyTransaction()
SurfaceAnimationRunner ->> -Choreagrapher: postCallback(CALLBACK_TRAVERSAL)
Note over SurfaceAnimationRunner, Choreagrapher: apply mFrameTransaction,即执行对 leash 操作
end
deactivate SurfaceAnimationRunner

ValueAnimator -->> SurfaceAnimationRunner: onAnimationEnd()
SurfaceAnimationRunner -->> SurfaceAnimator: onAnimationFinished()
SurfaceAnimator -->> SurfaceAnimator: reset()
Note right of SurfaceAnimator: WindowContainer 复位,并 remove leash
SurfaceAnimator -->> WindowContainer: onAnimationFinished()
SurfaceAnimator -->> 调用方: onAnimationFinished()

介绍下涉及的几个类

  1. SurfaceAnimator:它是 WindowContainer 的一个成员变量,在 local animation 中,它会创建 leash,并把 WindowContainer surface reparent 到 leash 上,然后把 leash 发送给 AnimationAdapter 去执行动画。
  2. AnimationAdaper: 它是一个动画适配器,它会把数据交给 SurfaceAnimationRunner 去真正的执行动画。它主要持有的数据是 AnimationSpec。
  3. SurfaceAnimationRunner: 它是动画的真正执行者,它使用 ValueAnimator 对 leash 执行动画。更重要的是,执行动画时,它不需要持有 WindowManager lock。
  4. AnimationSpec:从命名可以看出,它保存动画参数,在执行动画时,会先从它获取动画的数据,然后应用到 leash 上。

local animation 是通过 WindowContainer#startAnimation() 开始,如下

// WindowContainer.java

void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
        @AnimationType int type) {
    startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */);
}

void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
        @AnimationType int type,
        @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
    startAnimation(t, anim, hidden, type, animationFinishedCallback,
            null /* adapterAnimationCancelledCallback */, null /* snapshotAnim */);
}

void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
        @AnimationType int type,
        @Nullable OnAnimationFinishedCallback animationFinishedCallback,
        @Nullable Runnable animationCancelledCallback,
        @Nullable AnimationAdapter snapshotAnim) {
    ProtoLog.v(WM_DEBUG_ANIM, "Starting animation on %s: type=%d, anim=%s",
            this, type, anim);

    // 交给 SurfaceAnimator 执行下一步动画
    mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback,
            animationCancelledCallback, snapshotAnim, mSurfaceFreezer);
}

这三个方法,根据情况,调用任意一个即可开启动画。最终它会把动画交 WindowContainer 的成员变量 SurfaceAnimator mSurfaceAnimator 去执行下一步动画,如下

// SurfaceAnimator.java

void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
        @AnimationType int type,
        @Nullable OnAnimationFinishedCallback animationFinishedCallback,
        @Nullable Runnable animationCancelledCallback,
        @Nullable AnimationAdapter snapshotAnim, @Nullable SurfaceFreezer freezer) {
    cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
    mAnimation = anim;
    mAnimationType = type;
    mSurfaceAnimationFinishedCallback = animationFinishedCallback;
    mAnimationCancelledCallback = animationCancelledCallback;
    
    // mAnimatable 就是 WindowContainer
    final SurfaceControl surface = mAnimatable.getSurfaceControl();
    
    if (surface == null) {
        // ...
    }

    // 1. 获取 leash
    // freezer 就是 WindowContainer 的成员变量 mSurfaceFreezer
    mLeash = freezer != null ? freezer.takeLeashForAnimation() : null;
    if (mLeash == null) {
        // freezer 没有 leashg,就创建毅哥
        mLeash = createAnimationLeash(mAnimatable, surface, t, type,
                mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), 0 /* x */,
                0 /* y */, hidden, mService.mTransactionFactory);
                
        // 2. 通知 WindowContainer leash 创建完成
        mAnimatable.onAnimationLeashCreated(t, mLeash);
    }

    mAnimatable.onLeashAnimationStarting(t, mLeash);
    if (mAnimationStartDelayed) {
        ProtoLog.i(WM_DEBUG_ANIM, "Animation start delayed for %s", mAnimatable);
        return;
    }
    
    // 3. 把 leash 交给 AnimationAdapter 去执行动画
    mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
    
    // ...
}

从整体看,SurfaceAnimator 获取 leash 后,把 leash 交给 AnimationAdapter 去执行动画。

一般来说,leash 都是创建出来的,但是也可能从 WindowContainer#mSurfaceFreezer 中获取。这里看下创建 leash 的过程,如下

// SurfaceAnimator.java

static SurfaceControl createAnimationLeash(Animatable animatable, SurfaceControl surface,
        Transaction t, @AnimationType int type, int width, int height, int x, int y,
        boolean hidden, Supplier<Transaction> transactionFactory) {
    ProtoLog.i(WM_DEBUG_ANIM, "Reparenting to leash for %s", animatable);
    
    final SurfaceControl.Builder builder = animatable.makeAnimationLeash() // 创建 leash
            .setParent(animatable.getAnimationLeashParent()) // 设置 parent surface
            .setName(surface + " - animation-leash of " + animationTypeToString(type))
            .setHidden(hidden) 
            .setEffectLayer()
            .setCallsite("SurfaceAnimator.createAnimationLeash");
    final SurfaceControl leash = builder.build();
    t.setWindowCrop(leash, width, height);
    t.setPosition(leash, x, y);
    t.show(leash);
    t.setAlpha(leash, hidden ? 0 : 1);

    t.reparent(surface, leash); // 把 WindowContainer surface reparent 到 leash 上
    return leash;
}

创建 leash 时,它一般是挂载到 WindowContainer 的 parent 之下,并且会把 WindowContainer surface reparent 到 leash 上。为何要创建 leash,因为动画操作的是 leash surface,而不是 WindowContainer surface。

获得 leash 后,会通知 WindowContainer,WindowContainer 会保存 leash,并重新更新 layer,如下

// WindowContainer.java

public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
    mLastLayer = -1;
    
    // 保存 leash
    mAnimationLeash = leash;
    
    // 通过 parent 重新更新 layer
    reassignLayer(t);

    // Leash is now responsible for position, so set our position to 0.
    resetSurfacePositionForAnimationLeash(t);
}

最后,把 leash 传递给 AnimationAdapter 去执行下一步动画。对于 local animation 来说,AnimationAdapter 是 LocalAnimationAdapter,如下

// LocalAnimationAdapter.java

public void startAnimation(SurfaceControl animationLeash, Transaction t,
        @AnimationType int type, @NonNull OnAnimationFinishedCallback finishCallback) {
    
    // 交给 SurfaceAnimationRunner 去真正执行动画
    mAnimator.startAnimation(mSpec, animationLeash, t,
            () -> finishCallback.onAnimationFinished(type, this));
}

LocalAnimationAdapter 只是一个适配器,它把数据交给 SurfaceAnimationRunner 去执行动画。

// SurfaceAnimationRunner.java

void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t,
        Runnable finishCallback) {
    synchronized (mLock) {
        // RunningAnimation 就是一个数据包装类
        final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash,
                finishCallback);
        
        // 一般没有 edge extension
        boolean requiresEdgeExtension = requiresEdgeExtension(a);

        if (requiresEdgeExtension) {
            // ...
        }

        if (!requiresEdgeExtension) {
            // mPendingAnimations 保存即将执行的动画
            mPendingAnimations.put(animationLeash, runningAnim);
            
            if (!mAnimationStartDeferred && mPreProcessingAnimations.isEmpty()) {
                // 请求 Vsync 信号,执行 startAnimations()
                mChoreographer.postFrameCallback(this::startAnimations);
            }
        }

        // Some animations (e.g. move animations) require the initial transform to be
        // applied immediately.
        applyTransformation(runningAnim, t, 0 /* currentPlayTime */);
    }
}


private void startAnimations(long frameTimeNanos) {
    synchronized (mLock) {
        if (!mPreProcessingAnimations.isEmpty()) {

        }
        startPendingAnimationsLocked();
    }
    mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0);
}


private void startPendingAnimationsLocked() {
    for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
        startAnimationLocked(mPendingAnimations.valueAt(i));
    }
    mPendingAnimations.clear();
}


private void startAnimationLocked(RunningAnimation a) {
    // 创建 ValueAnimator
    final ValueAnimator anim = mAnimatorFactory.makeAnimator();

    // Animation length is already expected to be scaled.
    anim.overrideDurationScale(1.0f);
    anim.setDuration(a.mAnimSpec.getDuration());
    
    // 监听动画每一帧
    anim.addUpdateListener(animation -> {
        synchronized (mCancelLock) {
            if (!a.mCancelled) {
                final long duration = anim.getDuration();
                long currentPlayTime = anim.getCurrentPlayTime();
                if (currentPlayTime > duration) {
                    currentPlayTime = duration;
                }
                
                // 从动画中获取数据,并操作 leash,这些操作保存到 mFrameTransaction
                applyTransformation(a, mFrameTransaction, currentPlayTime);
            }
        }

        // 执行 mFrameTransaction
        // Transaction will be applied in the commit phase.
        scheduleApplyTransaction();
    });

    anim.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationStart(Animator animation) {
            synchronized (mCancelLock) {
                if (!a.mCancelled) {
                    // TODO: change this back to use show instead of alpha when b/138459974 is
                    // fixed.
                    mFrameTransaction.setAlpha(a.mLeash, 1);
                }
            }
        }

        // 动画执行完成
        @Override
        public void onAnimationEnd(Animator animation) {
            synchronized (mLock) {
                mRunningAnimations.remove(a.mLeash);
                synchronized (mCancelLock) {
                    if (!a.mCancelled) {
                        mAnimationThreadHandler.post(a.mFinishCallback);
                    }
                }
            }
        }
    });
    a.mAnim = anim;
    mRunningAnimations.put(a.mLeash, a);

    // 启动 ValueAnimator
    anim.start();
    
    if (a.mAnimSpec.canSkipFirstFrame()) {
        // If we can skip the first frame, we start one frame later.
        anim.setCurrentPlayTime(mChoreographer.getFrameIntervalNanos() / NANOS_PER_MS);
    }

    // Immediately start the animation by manually applying an animation frame. Otherwise, the
    // start time would only be set in the next frame, leading to a delay.
    anim.doAnimationFrame(mChoreographer.getFrameTime());
}

SurfaceAnimationRunner 就是通过一个 ValueAnimator 动画来操作 leash,从而形成动画。当 ValueAnimator 有 update event 到来时,首先根据 Animation 数据来操作 leash,如下

// SurfaceAnimationRunner.java

// t 为 SurfaceAnimationRunnber#mFrameTransaction
// currentPlayTime 为动画执行的时间点
private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
    a.mAnimSpec.apply(t, a.mLeash, currentPlayTime);
}

SurfaceAnimationRunner 交给 AnimationSpec 来操作 leash,以 WindowAnimationSpec 为例

// WindowAnimationSpec.java

public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
    final TmpValues tmp = mThreadLocalTmps.get();
    tmp.transformation.clear();
    
    // 根据时间 currentPlayTime,从动画 mAnimation 获取数据,保存到 tmp.transformation
    mAnimation.getTransformation(currentPlayTime, tmp.transformation);
    tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
    
    // 根据 tmp.transformation,对 leash 进行 rotate、translate、scale、alpha 操作
    // 这些操作都保存到 t 中,也就是 SurfaceAnimationRunnber#mFrameTransaction
    t.setMatrix(leash, tmp.transformation.getMatrix(), tmp.floats);
    t.setAlpha(leash, tmp.transformation.getAlpha());

    // ...
}

SurfaceAnimationRunnber 把 leash 的操作保存到 SurfaceAnimationRunnber#mFrameTransaction 后,然后需要 apply mFrameTransaction ,如下

// SurfaceAnimationRunnber.java

private void scheduleApplyTransaction() {
    if (!mApplyScheduled) {
        // 请求 Vsync 信号,执行 applyTransaction()
        mChoreographer.postCallback(CALLBACK_TRAVERSAL, mApplyTransactionRunnable,
                null /* token */);
        mApplyScheduled = true;
    }
}

private void applyTransaction() {
    mFrameTransaction.setAnimationTransaction();
    mFrameTransaction.setFrameTimelineVsync(mChoreographer.getVsyncId());
    // apply mFrameTransaction
    mFrameTransaction.apply();
    mApplyScheduled = false;
}

apply mFrameTransaction 就是对 leash 执行操作,因为就看到了 local animation 动画。

当 ValueAnimator 执行完成后,会执行 SurfaceAnimator 的传入的回调

// SurfaceAnimator.java

SurfaceAnimator(Animatable animatable,
        @Nullable OnAnimationFinishedCallback staticAnimationFinishedCallback,
        WindowManagerService service) {
   
    // 这个就是动画完成的回调
    mInnerAnimationFinishedCallback = getFinishedCallback(staticAnimationFinishedCallback);
}

private OnAnimationFinishedCallback getFinishedCallback(
        @Nullable OnAnimationFinishedCallback staticAnimationFinishedCallback) {
    return (type, anim) -> {
        synchronized (mService.mGlobalLock) {
            final SurfaceAnimator target = mService.mAnimationTransferMap.remove(anim);
            if (target != null) {
                target.mInnerAnimationFinishedCallback.onAnimationFinished(type, anim);
                return;
            }

            if (anim != mAnimation) {
                return;
            }
            
            
            final Runnable resetAndInvokeFinish = () -> {
                // We need to check again if the animation has been replaced with a new
                // animation because the animatable may defer to finish.
                if (anim != mAnimation) {
                    return;
                }

                // 这是调用 WindowContainer#startAnimation() 传入的回调
                final OnAnimationFinishedCallback animationFinishCallback =
                        mSurfaceAnimationFinishedCallback;

                // 重置: 把 WindowContainer surface 复位,移除 leash
                reset(mAnimatable.getSyncTransaction(), true /* destroyLeash */);

                // 通知 WindowContainer 动画执行完成
                if (staticAnimationFinishedCallback != null) {
                    staticAnimationFinishedCallback.onAnimationFinished(type, anim);
                }

                // 执行 WindowContainer#startAnimation() 传入的回调
                if (animationFinishCallback != null) {
                    animationFinishCallback.onAnimationFinished(type, anim);
                }
            };
            
            // 如果不推迟动画结束,就直接执行 resetAndInvokeFinish
            if (!(mAnimatable.shouldDeferAnimationFinish(resetAndInvokeFinish)
                    || anim.shouldDeferAnimationFinish(resetAndInvokeFinish))) {
                resetAndInvokeFinish.run();
            }
            mAnimationFinished = true;
        }
    };
}

动画结束,只要不被推迟结束,就会先执行 reset,另外还会通知 WindowContainer 和发起方,动画完成。

reset 其实就是对 WindowContainer surface 进行复位,因为在执行动画时,它被 reparent 到 leash。另外,还会移除 leash,如下

// SurfaceAnimator.java

private void reset(Transaction t, boolean destroyLeash) {
    mService.mAnimationTransferMap.remove(mAnimation);
    mAnimation = null;
    mSurfaceAnimationFinishedCallback = null;
    mAnimationType = ANIMATION_TYPE_NONE;
    final SurfaceFreezer.Snapshot snapshot = mSnapshot;
    mSnapshot = null;
    if (snapshot != null) {
        // Reset the mSnapshot reference before calling the callback to prevent circular reset.
        snapshot.cancelAnimation(t, !destroyLeash);
    }
    if (mLeash == null) {
        return;
    }
    SurfaceControl leash = mLeash;
    mLeash = null;
    
    
    final boolean scheduleAnim = removeLeash(t, mAnimatable, leash, destroyLeash);
    mAnimationFinished = false;
    
    // 所有的操作,都是保存到 t 这个 Transaction 中,这里调用动画线程来 apply 这个 transaction
    if (scheduleAnim) {
        mService.scheduleAnimationLocked();
    }
}


static boolean removeLeash(Transaction t, Animatable animatable, @NonNull SurfaceControl leash,
        boolean destroy) {
    boolean scheduleAnim = false;
    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) {
        ProtoLog.i(WM_DEBUG_ANIM, "Reparenting to original parent: %s for %s",
                parent, animatable);
        // We shouldn't really need these isValid checks but we do
        // b/130364451
        if (surface.isValid() && parent != null && parent.isValid()) {
            // 把 WindowContainer surface reparent 到原本的 parent surface 上
            t.reparent(surface, parent);
            scheduleAnim = true;
        }
    }
    if (destroy) {
        // 移除 leash
        t.remove(leash);
        scheduleAnim = true;
    }

    if (reparent) {
        // 通知  WindowContainer leash 被移除,WindowContainer 会重新更新 layer 和 surface position
        animatable.onAnimationLeashLost(t);
        scheduleAnim = true;
    }
    return scheduleAnim;
}

通知 WindowContainer 和调用方,动画执行完成,需要根据实际情况来分析,这里就不做代码展示。

到此,local animation 就结束了,如果想消化本篇文章,读者需要根据实际情况,进行实际分析,以做到融会贯通。