Android 11---窗口销毁流程ViewRootImpl.doDie

本篇文章主要以ViewRootImpl.doDie为入口梳理下窗口的销毁流程, 代码同样基于11.0。

流程图如下:

 

下面来逐步分析:

Step 1.ViewRootImpl.doDie

    void doDie() {
        checkThread();
        if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
        synchronized (this) {
            if (mRemoved) {
                return;
            }
            mRemoved = true;    // Set to true once doDie() has been called.
            if (mAdded) {
                dispatchDetachedFromWindow();
            }

            if (mAdded && !mFirst) {
                destroyHardwareRenderer();

                if (mView != null) {
                    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 {
                            if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
                                    & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                                mWindowSession.finishDrawing(
                                        mWindow, null /* postDrawTransaction */);
                            }
                        } catch (RemoteException e) {
                        }
                    }

                    destroySurface();    // 调用mSurfaceControl,mSurface的release函数,销毁系统端传过来的surface相关实例
                }
            }

            mAdded = false;
        }
        WindowManagerGlobal.getInstance().doRemoveView(this);  
    }

 

Step 2.ViewRootImpl.dispatchDetachedFromWindow

    void dispatchDetachedFromWindow() {
        ......
        try {
            // mWindow:W类对象,static class W extends IWindow.Stub,
            // binder对象的作用一般有两个: 1.在多个进程中标识同一个对象 2.跨进程调用   这里两个作用都用到了
            mWindowSession.remove(mWindow); 
        } catch (RemoteException e) {
        }
        ......
    }

 

Step 3.Session.remove

先介绍下mWindowSession, 该对象是在ViewRootImpl构造函数中调用WindowManagerGlobal.getWindowSession()获取的,而进一步来看,就是调用windowManager.openSession返回一个Session对象。

    public ViewRootImpl(Context context, Display display) {
        this(context, display, WindowManagerGlobal.getWindowSession(),
                false /* useSfChoreographer */);
    }


WindowManagerService.openSession
    @Override
    public IWindowSession openSession(IWindowSessionCallback callback) {
        return new Session(this, callback);
    }
/**
 * This class represents an active client session.  There is generally one
 * Session object per process that is interacting with the window manager.
 */  注释同样很详细了,不解释了
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {}

    @Override
    public void remove(IWindow window) {
        mService.removeWindow(this, window);   // 直接调用WMS的同名函数
    }

 

Step 4.WindowManagerService.removeWindow

    void removeWindow(Session session, IWindow client) {
        synchronized (mGlobalLock) {
            // WindowState win = mWindowMap.get(client);  通过IWindow对象从mWindowMap中获取对应的WindowState对象
            WindowState win = windowForClientLocked(session, client, false);
            if (win != null) {
                win.removeIfPossible();   // 调用WindowState.removeIfPossible函数
                return;
            }

            // Remove embedded window map if the token belongs to an embedded window
            mEmbeddedWindowController.remove(client);
        }
    }

 

Step 5.WindowState.removeIfPossible

    @Override
    void removeIfPossible() {
        super.removeIfPossible();   // WindowContainer中的逻辑就是for循环调用mChildren的同名函数,先删除子节点
        removeIfPossible(false /*keepVisibleDeadWindow*/);
        immediatelyNotifyBlastSync();
    }

 

Step 6.WindowState.removeIfPossible

    private void removeIfPossible(boolean keepVisibleDeadWindow) {
        // It is save to remove the window and destroy the surface because the client 
        // requested removal or some other higher level component said so (e.g. activity manager).
        mWindowRemovalAllowed = true;
        ProtoLog.v(WM_DEBUG_ADD_REMOVE,
                "removeIfPossible: %s callers=%s", this, Debug.getCallers(5));

        final boolean startingWindow = mAttrs.type == TYPE_APPLICATION_STARTING;  // 判断是否是预览窗口
        if (startingWindow) {
            ProtoLog.d(WM_DEBUG_STARTING_WINDOW, "Starting window removed %s", this);
        }

        ProtoLog.v(WM_DEBUG_FOCUS, "Remove client=%x, surfaceController=%s Callers=%s",
                    System.identityHashCode(mClient.asBinder()),
                    mWinAnimator.mSurfaceController,
                    Debug.getCallers(5));


        final long origId = Binder.clearCallingIdentity();

        try {
            disposeInputChannel();

            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
                    "Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b "
                            + "mHasSurface=%b surfaceShowing=%b animating=%b app-animation=%b "
                            + "mWillReplaceWindow=%b mDisplayFrozen=%b callers=%s",
                    this, mWinAnimator.mSurfaceController, mAnimatingExit, mRemoveOnExit,
                    mHasSurface, mWinAnimator.getShown(),
                    isAnimating(TRANSITION | PARENTS),
                    mActivityRecord != null && mActivityRecord.isAnimating(PARENTS | TRANSITION),
                    mWillReplaceWindow,
                    mWmService.mDisplayFrozen, Debug.getCallers(6));

            // Visibility of the removed window. Will be used later to update orientation later on.
            boolean wasVisible = false;

            // First, see if we need to run an animation. If we do, we have to hold off on removing the
            // window until the animation is done. If the display is frozen, just remove immediately,
            // since the animation wouldn't be seen.   判断是否满足执行动画的条件
            if (mHasSurface && mToken.okToAnimate()) {
                if (mWillReplaceWindow) {  // This window will be replaced due to relaunch. 这种情况下保留old window,直到新的显示
                    // This window is going to be replaced. We need to keep it around until the new one
                    // gets added, then we will get rid of this one.
                    ProtoLog.v(WM_DEBUG_ADD_REMOVE,
                            "Preserving %s until the new one is added", this);
                    // TODO: We are overloading mAnimatingExit flag to prevent the window state from
                    // been removed. We probably need another flag to indicate that window removal
                    // should be deffered vs. overloading the flag that says we are playing an exit
                    // animation.
                    mAnimatingExit = true;
                    mReplacingRemoveRequested = true;
                    return;
                }

                // If we are not currently running the exit animation, we need to see about starting one
                wasVisible = isWinVisibleLw();   // Step 7 判断WindowState的可见状态

                if (keepVisibleDeadWindow) {   // 本文这种情况下传进参数为false,仅在WindowState.binderDied可能为true
                    ProtoLog.v(WM_DEBUG_ADD_REMOVE,
                            "Not removing %s because app died while it's visible", this);

                    mAppDied = true;
                    setDisplayLayoutNeeded();
                    mWmService.mWindowPlacerLocked.performSurfacePlacement();

                    // Set up a replacement input channel since the app is now dead.
                    // We need to catch tapping on the dead window to restart the app.
                    openInputChannel(null);
                    getDisplayContent().getInputMonitor().updateInputWindowsLw(true /*force*/);
                    return;
                }

                if (wasVisible) {  // 如果窗口可见,则可能会执行一个退出动画
                    final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE;  // 根据窗口type设置transit

                    // Try starting an animation.  Step 8 尝试开始一个退出动画
                    // WindowStateAnimator对象:WindowState构造函数中创建,一对一,作用:Keep track of animations and surface operations for a single WindowState.
                    if (mWinAnimator.applyAnimationLocked(transit, false)) {
                        mAnimatingExit = true;   // 标识当前正在执行一个退出窗口动画

                        // mAnimatingExit affects canAffectSystemUiFlags(). Run layout such that
                        // any change from that is performed immediately.  哇偶,解释的很棒
                        setDisplayLayoutNeeded();
                        mWmService.requestTrav
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值