【Android 13源码分析】StartWindow-SplashScreen-2-移除-window_transition动画

795 阅读7分钟

忽然有一天,我想要做一件事:去代码中去验证那些曾经被“灌输”的理论。

                        -- 服装学院的IT男

本篇为 StartWindow 的第二篇,执行时机是应用窗口要显示了,并且执行了 starting_reveal 动画后就不需要 StartWindow 了,这个时候需要将其移除。

根据 Winscope 看到的信息,移除流程还会触发“window_animation”动画。

1 初步分析触发时机

如何分析StartWindow的移除还是和以前一样可以有2种方式:

    1. 根据ShellStartingWindow的日志然后分析调用链
    1. 从业务逻辑分析
    1. 根据创建leash动画的堆栈开始分析
  1. ShellStartingWindow的日志分析

remove的日志开始是这段

	ShellStartingWindow: Task start finish, remove starting surface for task: 28
	ShellStartingWindow: Removing splash screen window for task: 28

在代码里找到这2句日志是在StartingSurfaceDrawer类下的removeStartingWindow和removeWindowSynced方法里调用的,这一块

TaskOrganizer.mInterface::removeStartingWindow ShellTaskOrganizer::removeStartingWindow StartingSurfaceDrawer::removeStartingWindow StartingSurfaceDrawer::removeWindowSynced

发现这个流程和【starting_reveal动画】前面的是一样的

  1. 业务逻辑分析

从业务逻辑上分析,StartWindow的作用就是在真正的window显示前为了过渡出现的,所以它的remove时间就是在真正Window要显示之前。而真正Window显示的节点就是starting_reveal的动画结束。 移除的第一个对应的日志应该的。

  1. 根据创建leash动画的堆栈开始分析 这个的堆栈如下,
09-29 21:31:03.361 17616 19545 E biubiubiu: SurfaceControl mName: Surface(name=bc9b727 Splash Screen com.google.android.dialer)/@0xf2e673e - animation-leash of window_animation  mCallsiteSurfaceAnimator.createAnimationLeash
09-29 21:31:03.361 17616 19545 E biubiubiu: java.lang.Exception
09-29 21:31:03.361 17616 19545 E biubiubiu: 	at android.view.SurfaceControl.<init>(SurfaceControl.java:1580)
09-29 21:31:03.361 17616 19545 E biubiubiu: 	at android.view.SurfaceControl.<init>(Unknown Source:0)
09-29 21:31:03.361 17616 19545 E biubiubiu: 	at android.view.SurfaceControl$Builder.build(SurfaceControl.java:1240)
09-29 21:31:03.361 17616 19545 E biubiubiu: 	at com.android.server.wm.SurfaceAnimator.createAnimationLeash(SurfaceAnimator.java:472)
09-29 21:31:03.361 17616 19545 E biubiubiu: 	at com.android.server.wm.SurfaceAnimator.startAnimation(SurfaceAnimator.java:184)
09-29 21:31:03.361 17616 19545 E biubiubiu: 	at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2770)
09-29 21:31:03.361 17616 19545 E biubiubiu: 	at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2777)
09-29 21:31:03.361 17616 19545 E biubiubiu: 	at com.android.server.wm.WindowContainer.startAnimation(WindowContainer.java:2783)
09-29 21:31:03.361 17616 19545 E biubiubiu: 	at com.android.server.wm.WindowState.startAnimation(WindowState.java:5377)
09-29 21:31:03.361 17616 19545 E biubiubiu: 	at com.android.server.wm.WindowState.startAnimation(WindowState.java:5353)
09-29 21:31:03.361 17616 19545 E biubiubiu: 	at com.android.server.wm.WindowStateAnimator.applyAnimationLocked(WindowStateAnimator.java:669)
09-29 21:31:03.361 17616 19545 E biubiubiu: 	at com.android.server.wm.WindowManagerService.tryStartExitingAnimation(WindowManagerService.java:2638)
09-29 21:31:03.361 17616 19545 E biubiubiu: 	at com.android.server.wm.WindowManagerService.relayoutWindow(WindowManagerService.java:2441)
09-29 21:31:03.361 17616 19545 E biubiubiu: 	at com.android.server.wm.Session.relayout(Session.java:267)
09-29 21:31:03.361 17616 19545 E biubiubiu: 	at android.view.IWindowSession$Stub.onTransact(IWindowSession.java:729)
09-29 21:31:03.361 17616 19545 E biubiubiu: 	at com.android.server.wm.Session.onTransact(Session.java:181)
09-29 21:31:03.361 17616 19545 E biubiubiu: 	at android.os.Binder.execTransactInternal(Binder.java:1285)
09-29 21:31:03.361 17616 19545 E biubiubiu: 	at android.os.Binder.execTransact(Binder.java:1244)

这一块是从 relayoutWindow 开始的,在 system_server 进程执行,是动画的主要调用链,但是需要找到什么时候触发的,才是 StartWindow 移除的真正触发点

综上第一第二点,StartWindow的移除触发是在【starting_reveal动画】结束的时候开始的,然后会触发一次relayoutWindow,进而执行动画

2 SystemUI进程移除StartWidow

StartingSurfaceDrawer::removeWindowInner WindowManagerGlobal::removeView WindowManagerGlobal::removeViewLocked ViewRootImpl::die ViewRootImpl::doDie ViewRootImpl::relayoutWindow IWindowSession::relayout --后续由system_server执行

这段前面的逻辑去【starting_reveal动画】看,当前直接从StartingSurfaceDrawer::removeWindowInner开始分析

# StartingSurfaceDrawer
    private void removeWindowInner(View decorView, boolean hideView) {
        if (mSysuiProxy != null) {
            mSysuiProxy.requestTopUi(false, TAG);
        }
        if (hideView) {
            // 设置GONE,这里的decorView就是startWindow的decorView
            decorView.setVisibility(View.GONE);
        }
        // 触发remove,第二个参数为false
        mWindowManagerGlobal.removeView(decorView, false /* immediate */);
    }
# WindowManagerGlobal
    public void removeView(View view, boolean immediate) {
        if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }

        synchronized (mLock) {
            int index = findViewLocked(view, true);
            View curView = mRoots.get(index).getView();
            removeViewLocked(index, immediate);
            if (curView == view) {
                return;
            }

            throw new IllegalStateException("Calling with view " + view
                    + " but the ViewAncestor is attached to " + curView);
        }
    }

    private void removeViewLocked(int index, boolean immediate) {
        ViewRootImpl root = mRoots.get(index);
        View view = root.getView();

        if (root != null) {
            root.getImeFocusController().onWindowDismissed();
        }
        // 调用ViewRootImpl::die 移除
        boolean deferred = root.die(immediate);
        if (view != null) {
            view.assignParent(null);
            if (deferred) {
                // 加入需要移除的集合
                mDyingViews.add(view);
            }
        }
    }
# ViewRootImpl
    boolean die(boolean immediate) {
        if (ViewDebugManager.DEBUG_LIFECYCLE) {
            Log.v(mTag, "die: immediate = " + immediate + ", mIsInTraversal = " + mIsInTraversal
                    + ",mIsDrawing = " + mIsDrawing + ",this = " + this, new Throwable());
        }

        // Make sure we do execute immediately if we are in the middle of a traversal or the damage
        // done by dispatchDetachedFromWindow will cause havoc on return.
        //immediate为false左右不走这
        if (immediate && !mIsInTraversal) {
            doDie();
            return false;
        }

        if (!mIsDrawing) {
            destroyHardwareRenderer();
        } else {
            Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
                    "  window=" + this + ", title=" + mWindowAttributes.getTitle());
        }
        // 发送消息
        mHandler.sendEmptyMessage(MSG_DIE);
        return true;
    }
    private void handleMessageImpl(Message msg) {
        ......
        case MSG_DIE: {
            doDie();
        }
        ......
    }

这里通过Handler发送消息,对于这个消息的处理也是只执行了doDie()方法,所以直接看这个方法就好了

# ViewRootImpl
    void doDie() {
        ......
                if (mView != null) {
                    // 前面设置为GONE了
                    int viewVisibility = mView.getVisibility();
                    boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
                    if (mWindowAttributesChanged || viewVisibilityChanged) {
                        // If layout params have been changed, first give them
                        // to the window manager to make sure it has the correct
                        // animation info.
                        try {
                            // 重点* 调用relayoutWindow
                            if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
                                    & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                                mWindowSession.finishDrawing(
                                    mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE);
                            }
                        } catch (RemoteException e) {
                            Log.e(mTag, "RemoteException when finish draw window " + mWindow
                                    + " in " + this, e);
                        }
                    }

                    destroySurface();
                }
        ......
    }

这段方法主要就是调用了relayoutWindow,参数viewVisibility是 GONE

# ViewRootImpl
    private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
            boolean insetsPending) throws RemoteException {
                ......
                relayoutResult = mWindowSession.relayout(mWindow, params,
                        requestedWidth, requestedHeight, viewVisibility,
                        insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
                        mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
                        mTempControls, mRelayoutBundle);
                ......
        }

上面的这段逻辑,主要就是将startWindow进行了移除,然后通知WMS,执行一次relayout,后面就会触发startWindow的移除动画了。 至于怎么最终确认是这次SystemUI进程调用的relayout触发的呢? 在2编加上log或者直接debug都可以确认。

3 system_server 进程执行移除StartWindow动画

这块的堆栈在前面总结了,是某次relayoutWindow触发的,也跟过代码确认了是在starting_reveal动画结束后触发的startWindow移除,然后执行了一次relayoutWindow,然后调用到 system_server 进程触发这小节后续的逻辑

3.1 window_animation 动画图层的创建

整理调用链:

Session::relayout
    WindowManagerService::relayoutWindow
        WindowManagerService::tryStartExitingAnimation
            WindowStateAnimator::applyAnimationLocked
                DisplayPolicy::selectAnimation     --选择动画资源
                WindowState::startAnimation
                    WindowState::startAnimation
                        WindowContainer::startAnimation
                            WindowContainer::startAnimation
                                SurfaceAnimator::startAnimation
                                    SurfaceAnimator::createAnimationLeash  -- 创建leash图层
                                    LocalAnimationAdapter::startAnimation  -- 开始动画(本地动画) -- 各个adapter 分歧
                                        SurfaceAnimationRunner::startAnimation
                                            LocalAnimationAdapter::startAnimation
                                                LocalAnimationAdapter::startAnimations
                                                    LocalAnimationAdapter::startPendingAnimationsLocked
                                                        LocalAnimationAdapter::startAnimationLocked
                                                            LocalAnimationAdapter::scheduleApplyTransaction  --update每次执行
                                                                SurfaceAnimationRunner.mApplyTransactionRunnable::run
                                                                    SurfaceAnimationRunner::applyTransaction  --执行Transaction的apply
                                                            RunningAnimation.mFinishCallback::run    --onAnimationEnd执行

开始撸代码:

# WindowManagerService
    private boolean tryStartExitingAnimation(WindowState win, WindowStateAnimator winAnimator,
            boolean focusMayChange) {
                // 本来是退出 退出类型,然后发现当前是StartWindow的退出,则改为TRANSIT_PREVIEW_DONE
                int transit = WindowManagerPolicy.TRANSIT_EXIT;
                if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
                    transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
                }
                String reason = null;
                if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
                    reason = "applyAnimation";
                    focusMayChange = true;
                    win.mAnimatingExit = true;
                } else ......//省略其他case
                ......
                if (reason != null) {
                    // 打印日志
                    ProtoLog.d(WM_DEBUG_ANIM, "Set animatingExit: reason=startExitingAnimation/%s win=%s",
                            reason, win);
                }
                ......
            }
# WindowStateAnimator
    boolean applyAnimationLocked(int transit, boolean isEntrance) {
        ......
        if (mWin.mToken.okToAnimate()) {
            // 重点*1 根据transit选择动画资源
            int anim = mWin.getDisplayContent().getDisplayPolicy().selectAnimation(mWin, transit);
            int attr = -1;
            Animation a = null;
            //remove startWindow走这
            if (anim != DisplayPolicy.ANIMATION_STYLEABLE) {
                if (anim != DisplayPolicy.ANIMATION_NONE) {
                    Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WSA#loadAnimation");
                    a = AnimationUtils.loadAnimation(mContext, anim);
                    Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
                }
            } else {
                // 其他情况
                switch (transit) {
                    case WindowManagerPolicy.TRANSIT_ENTER:
                        attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
                        break;
                    case WindowManagerPolicy.TRANSIT_EXIT:
                        attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
                        break;
                    case WindowManagerPolicy.TRANSIT_SHOW:
                        attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
                        break;
                    case WindowManagerPolicy.TRANSIT_HIDE:
                        attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
                        break;
                }
                if (attr >= 0) {
                    a = mWin.getDisplayContent().mAppTransition.loadAnimationAttr(
                            mWin.mAttrs, attr, TRANSIT_OLD_NONE);
                }
            }
            // 重点*2 输出关键日志
            if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) {
                ProtoLog.v(WM_DEBUG_ANIM, "applyAnimation: win=%s"
                        + " anim=%d attr=0x%x a=%s transit=%d type=%d isEntrance=%b Callers %s",
                        this, anim, attr, a, transit, mAttrType, isEntrance, Debug.getCallers(20));
            }
            if (a != null) {
                Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WSA#startAnimation");
                // 重点*3  开始动画
                mWin.startAnimation(a);
                Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
                mAnimationIsEntrance = isEntrance;
            }
        } ......
        ......

    }

3.2 动画资源和日志

看方法前面选择动画资源的部分

# DisplayPolicy
    int selectAnimation(WindowState win, int transit) {
        // 打印日志
        ProtoLog.i(WM_DEBUG_ANIM, "selectAnimation in %s: transit=%d", win, transit);
        ......// 忽略其他case
        //  当前逻辑在这
        if (transit == TRANSIT_PREVIEW_DONE) {
            if (win.hasAppShownWindows()) {
                if (win.isActivityTypeHome()) {
                    // Dismiss the starting window as soon as possible to avoid the crossfade out
                    // with old content because home is easier to have different UI states.
                    return ANIMATION_NONE;
                }
                // 打印退出 startWindow
                ProtoLog.i(WM_DEBUG_ANIM, "**** STARTING EXIT");
                // 返回退出的动画资源
                return R.anim.app_starting_exit;
            }
        }
        return ANIMATION_STYLEABLE;
    }

对应的动画资源如下:

# R.anim.app_starting_exit
<alpha
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:detachWallpaper="true"
    android:interpolator="@interpolator/linear"
    android:fromAlpha="1.0"
    android:toAlpha="0.0"
    android:duration="150" />

这个默认的退出动画很简单,就是150毫秒内透明度变化,然后去根据winscope这段的动画对比了一下,确实只有透明度的变化 这部分的日志输出如下: 比较长因为还打印了调用链:

	Line 1605: 09-29 21:31:02.632 17616 17644 V WindowManager: applyAnimation: win=WindowStateAnimator{d909ec3 Splash Screen com.google.android.dialer} anim=0 attr=0x0 a=null transit=1 type=3 isEntrance=true Callers com.android.server.wm.WindowStateAnimator.applyEnterAnimationLocked:597 com.android.server.wm.WindowState.performShowLocked:4721 com.android.server.wm.ActivityRecord.lambda$showAllWindowsLocked$16:6566 com.android.server.wm.ActivityRecord$$ExternalSyntheticLambda4.accept:2 com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply:2642 com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply:2632 com.android.server.wm.WindowState.applyInOrderWithImeWindows:4980 com.android.server.wm.WindowState.forAllWindows:4820 com.android.server.wm.WindowContainer.forAllWindows:1636 com.android.server.wm.WindowContainer.forAllWindows:1646 com.android.server.wm.ActivityRecord.showAllWindowsLocked:6564 com.android.server.wm.AppTransitionController.handleOpeningApps:1075 com.android.server.wm.AppTransitionController.handleAppTransitionReady:287 com.android.server.wm.RootWindowContainer.checkAppTransitionReady:981 com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace:846 com.android.server.wm.RootWindowContainer.performSurfacePlacement:788 com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop:178 com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement:126 com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement:115 com.android.server.wm.WindowSurfacePlacer$Traverser.run:57 


	Line 6054: 09-29 21:31:03.359 17616 19545 V WindowManager: applyAnimation: win=WindowStateAnimator{d909ec3 Splash Screen com.google.android.dialer} anim=17432595 attr=0xffffffffffffffff a=android.view.animation.AlphaAnimation@2a31554 transit=5 type=3 isEntrance=false Callers com.android.server.wm.WindowManagerService.tryStartExitingAnimation:2638 com.android.server.wm.WindowManagerService.relayoutWindow:2441 com.android.server.wm.Session.relayout:267 android.view.IWindowSession$Stub.onTransact:729 com.android.server.wm.Session.onTransact:181 android.os.Binder.execTransactInternal:1285 android.os.Binder.execTransact:1244 <bottom of call stack> <bottom of call stack> <bottom of call stack> <bottom of call stack> <bottom of call stack> <bottom of call stack> <bottom of call stack> <bottom of call stack> <bottom of call stack> <bottom of call stack> <bottom of call stack> <bottom of call stack> <bottom of call stack> 

第一个应该是add流程,但是anim和a都没有实际的值,所以不会有后续动画图层的创建,第二个为remove,是有对应的动画的。

# WindowState
    void startAnimation(Animation anim) {

        // If we are an inset provider, all our animations are driven by the inset client.
        if (mControllableInsetProvider != null) {
            return;
        }

        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());
        // 重点* 这里创建的是本地动画的的adapter(LocalAnimationAdapter),注意第一个是WindowAnimationSpec对应
        //第二个参数runer 是WMS的成员变量
        final AnimationAdapter adapter = new LocalAnimationAdapter(
                new WindowAnimationSpec(anim, mSurfacePosition, false /* canSkipFirstFrame */,
                        0 /* windowCornerRadius */),
                mWmService.mSurfaceAnimationRunner);
        // 带上adapter开始动画
        startAnimation(getPendingTransaction(), adapter);
        commitPendingTransaction();
    }

    private void startAnimation(Transaction t, AnimationAdapter adapter) {
        // 然后就调用父类的方法了,注意type为 ANIMATION_TYPE_WINDOW_ANIMATION
        startAnimation(t, adapter, mWinAnimator.mLastHidden, ANIMATION_TYPE_WINDOW_ANIMATION);
    }

这里注意到,当前动画的是 window_animation ,用到的 Adapter 是 LocalAnimationAdapter,也就是常说的本地动画,在 system_server 进程执行的。而之前分析的 app_transition 是 RemoteAnimationAdapter(远端动画),在launcher进程执行的。

# WindowState
    void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
            @AnimationType int type) {
        // 注意最后一个参数为null
        startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */);
    }

    void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
            @AnimationType int type,
            @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
        // 最后一个参数为null
        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) {
        // 打印log
        ProtoLog.v(WM_DEBUG_ANIM, "Starting animation on %s: type=%d, anim=%s",
                this, type, anim);

        // TODO: This should use isVisible() but because isVisible has a really weird meaning at
        // the moment this doesn't work for all animatable window containers.
        // 倒数第二个参数传过来是null
        mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback,
                animationCancelledCallback, snapshotAnim, mSurfaceFreezer);
    }

这一段的日志打印:

10-08 16:46:47.272  1529  1558 V WindowManager: Starting animation on Window{7d416db u0 Splash Screen com.google.android.dialer}: type=16, anim=com.android.server.wm.LocalAnimationAdapter@856484c

后面就是和之前app_transition动画一样调用到SurfaceAnimator了,这个方法和之前的还是一个的,创建动画图层,然后执行adapter的startAnimation。

# SurfaceAnimator

    private AnimationAdapter mAnimation;

    void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
            @AnimationType int type,
            @Nullable OnAnimationFinishedCallback animationFinishedCallback,
            @Nullable Runnable animationCancelledCallback,
            @Nullable AnimationAdapter snapshotAnim, @Nullable SurfaceFreezer freezer) {
                ......
                if (mLeash == null) {
                    mLeash = createAnimationLeash(mAnimatable, surface, t, type,
                            mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), 0 /* x */,
                            0 /* y */, hidden, mService.mTransactionFactory);
                    mAnimatable.onAnimationLeashCreated(t, mLeash);
                }
                mAnimatable.onLeashAnimationStarting(t, mLeash);
                if (mAnimationStartDelayed) {
                    ProtoLog.i(WM_DEBUG_ANIM, "Animation start delayed for %s", mAnimatable);
                    return;
                }
                mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
                ......
            }

创建动画图层之前看过了,区别是这次的type是前面传过来的ANIMATION_TYPE_WINDOW_ANIMATION,所以返回的类型就是"window_animation"。 然后下面的mAnimation前面也看到是LocalAnimationAdapter,和之前的也不一样。

4 开始remove动画

# LocalAnimationAdapter
    private final SurfaceAnimationRunner mAnimator;

    @Override
    public void startAnimation(SurfaceControl animationLeash, Transaction t,
            @AnimationType int type, @NonNull OnAnimationFinishedCallback finishCallback) {
        mAnimator.startAnimation(mSpec, animationLeash, t,
                () -> finishCallback.onAnimationFinished(type, this));
    }

mAnimator是在构建 LocalAnimationAdapter 时候传递的,根据前面的传参是在WMS中的成员变量mSurfaceAnimationRunner,而这个变量是在构造WMS的时候创建的,new的一个SurfaceAnimationRunner

# SurfaceAnimationRunner
    // 一个等待做动画的集合
    final ArrayMap<SurfaceControl, RunningAnimation> mPendingAnimations = new ArrayMap<>();
    final ArrayMap<SurfaceControl, RunningAnimation> mPreProcessingAnimations = new ArrayMap<>();

    void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t,
            Runnable finishCallback) {
        synchronized (mLock) {
            ......
            // 创建RunningAnimation对象
            final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash,
                    finishCallback);
            ......
                // 放入集合
                mPreProcessingAnimations.put(animationLeash, runningAnim);
            ......
            synchronized (mLock) {
                ......
                // 将动画的leash图层和刚创建的runningAnim放入集合中
                mPendingAnimations.put(animationLeash, runningAnim);
                if (!mAnimationStartDeferred && mPreProcessingAnimations.isEmpty()) {
                    // 下一帧执行startAnimations
                    mChoreographer.postFrameCallback(this::startAnimations);
                }
            }
        }
    }

    private void startAnimations(long frameTimeNanos) {
        synchronized (mLock) {
            if (!mPreProcessingAnimations.isEmpty()) {
                // We only want to start running animations once all mPreProcessingAnimations have
                // been processed to ensure preprocessed animations start in sync.
                // NOTE: This means we might delay running animations that require preprocessing if
                // new animations that also require preprocessing are requested before the previous
                // ones have finished (see b/227449117).
                return;
            }
            // 开始动画
            startPendingAnimationsLocked();
        }
        mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0);
    }

    @GuardedBy("mLock")
    private void startPendingAnimationsLocked() {
        // 将mPendingAnimations所有的数据拿出来开始动画
        for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
            startAnimationLocked(mPendingAnimations.valueAt(i));
        }
        mPendingAnimations.clear();
    }

下面就是动画真正执行的地方了

# SurfaceAnimationRunner

    private void startAnimationLocked(RunningAnimation a) {
        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;
                    }
                    // 根据当时进度构建参数放到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.
                        // 动画开始将leash的Alpha设置为1, 看上面的注释是为了修复出现的bug
                        mFrameTransaction.setAlpha(a.mLeash, 1);
                    }
                }
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                synchronized (mLock) {
                    mRunningAnimations.remove(a.mLeash);
                    synchronized (mCancelLock) {
                        if (!a.mCancelled) {
                            // 动画结束的回调
                            // Post on other thread that we can push final state without jank.
                            mAnimationThreadHandler.post(a.mFinishCallback);
                        }
                    }
                }
            }
        });
        a.mAnim = anim;
        mRunningAnimations.put(a.mLeash, a);
        // 开始执行
        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());
    }

这段代码稍微有点长度,但是跟主流程的话,根据之前对远端动画的分析,主要关注动画的update是怎么处理的就好,还有最终是在哪里将Transformation执行apply。

4.1 动画的update处理

# SurfaceAnimationRunner
    private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
        // 这里的mSpec是构建LocalAnimationAdapter的第一个参数,所以就是WindowAnimationSpec
        a.mAnimSpec.apply(t, a.mLeash, currentPlayTime);
    }
// 下面的方法比较长,主要是根据当前动画的进度,然后计算出参数设置到Transaction中
# WindowAnimationSpec
    @Override
    public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
        final TmpValues tmp = mThreadLocalTmps.get();
        tmp.transformation.clear();
        mAnimation.getTransformation(currentPlayTime, tmp.transformation);
        tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
        t.setMatrix(leash, tmp.transformation.getMatrix(), tmp.floats);
        t.setAlpha(leash, tmp.transformation.getAlpha());

        boolean cropSet = false;
        if (mRootTaskClipMode == ROOT_TASK_CLIP_NONE) {
            if (tmp.transformation.hasClipRect()) {
                final Rect clipRect = tmp.transformation.getClipRect();
                accountForExtension(tmp.transformation, clipRect);
                t.setWindowCrop(leash, clipRect);
                cropSet = true;
            }
        } else {
            mTmpRect.set(mRootTaskBounds);
            if (tmp.transformation.hasClipRect()) {
                mTmpRect.intersect(tmp.transformation.getClipRect());
            }
            accountForExtension(tmp.transformation, mTmpRect);
            t.setWindowCrop(leash, mTmpRect);
            cropSet = true;
        }

        // We can only apply rounded corner if a crop is set, as otherwise the value is meaningless,
        // since it doesn't have anything it's relative to.
        if (cropSet && mAnimation.hasRoundedCorners() && mWindowCornerRadius > 0) {
            t.setCornerRadius(leash, mWindowCornerRadius);
        }
    }

然后就要看看是哪里对Transaction进行apply的。

4.1.1 对动画的事务Transaction进行apply

# SurfaceAnimationRunner
    private final Runnable mApplyTransactionRunnable = this::applyTransaction;

    private void scheduleApplyTransaction() {
        if (!mApplyScheduled) {
            // 下一帧执行mApplyTransactionRunnable
            mChoreographer.postCallback(CALLBACK_TRAVERSAL, mApplyTransactionRunnable,
                    null /* token */);
            mApplyScheduled = true;
        }
    }

下一帧要执行的mApplyTransactionRunnable其实就是执行当前类的方法applyTransaction。

# SurfaceAnimationRunner
    private void applyTransaction() {
        mFrameTransaction.setAnimationTransaction();
        mFrameTransaction.setFrameTimelineVsync(mChoreographer.getVsyncId());
        // 重点* 最终执行apply
        mFrameTransaction.apply();
        mApplyScheduled = false;
    }

至此,startWindow退出动画结束。