Android Framework(七)WMS-窗口的移除

一般销毁窗口的场景就2种:

  • 1、销毁Activity
  • 2、重启Activity

而且相对addWindow流程来说,窗口移除简单很多。

在这里插入图片描述

应用端处理

应用端的处理都是在 ActivityThread 触发这些事件处理的,不管是销毁还是重启,触发 Window 移除都要执行到 ActivityThread::performDestroyActivity 方法, 从这个方法开发分析 应用端的调用链如下:

ActivityThread::handleDestroyActivity
    ActivityThread::performDestroyActivity       -- onDestroy流程
        Instrumentation::callActivityOnDestroy
            Activity::performDestroy
                Activity::onDestroy
    WindowManagerImpl::removeViewImmediate        -- UI处理
        WindowManagerGlobal::removeView
            WindowManagerGlobal::removeViewLocked
                ViewRootImpl::die
                    ViewRootImpl::doDie
                        ViewRootImpl::dispatchDetachedFromWindow
                            IWindowSession::remove     -- 跨进程到 system_service 进程处理
                        ViewRootImpl::destroyHardwareRenderer
                        ViewRootImpl::destroySurface
                mDyingViews::add
            
    ActivityClient::activityDestroyed            -- system_service 进程处理

首先是ActivityThread处理:

# ActivityThread
    @Override
    public void handleDestroyActivity(ActivityClientRecord r, boolean finishing, int configChanges,
            boolean getNonConfigInstance, String reason) {
        // 1. 主流程 onDestroy
        performDestroyActivity(r, finishing, configChanges, getNonConfigInstance, reason);
        // 视图相关处理
        cleanUpPendingRemoveWindows(r, finishing);
        WindowManager wm = r.activity.getWindowManager();
        View v = r.activity.mDecor;
        if (v != null) {
            if (r.activity.mVisibleFromServer) {
                mNumVisibleActivities--;
            }
            IBinder wtoken = v.getWindowToken();
            if (r.activity.mWindowAdded) {
                if (r.mPreserveWindow) {
                    // ......需要保留Window
                } else {
                    ......
                     // 2. 移除当前视图 (触发WindowManagerGlobal移除)
                    wm.removeViewImmediate(v);
                }
            }
            
            r.activity.mDecor = null;
        }
        ......
        if (finishing) {
            // 3. 通知 SystemService 端
            ActivityClient.getInstance().activityDestroyed(r.token);
        }
        mSomeActivitiesChanged = true;
    }

做了三件事:

  • 1、执行到 Activity 的 onDestroy
  • 2、处理UI相关的移除
  • 3、通知 SystemService 端这个 Activity 已经 Destroy 了,后续该干啥干啥。

这一部分的代码也在 【Activity生命周期之onDestroy】讲过,重复的地方不在解释,本篇关注第二点:UI的移除

# WindowManagerImpl
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

    @Override
    public void removeViewImmediate(View view) {
        mGlobal.removeView(view, true);
    }
# WindowManagerGlobal

    public void removeView(View view, boolean immediate) {
        if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }

        synchronized (mLock) {
            // 从mViews获取到当前View对应的下标
            int index = findViewLocked(view, true);
            // 去出相同下标的ViewRootImpl,再获取ViewRootImpl下的View
            View curView = mRoots.get(index).getView();
            // 主流程
            removeViewLocked(index, immediate);
            if (curView == view) {
                return;
            }
            // 如果2个View不相等,说明代码逻辑出现异常
            throw new IllegalStateException("Calling with view " + view
                    + " but the ViewAncestor is attached to " + curView);
        }
    }

这里主要是做了一些校验,注释都加上了,政策逻辑还是看 removeViewLocked 的执行。

# WindowManagerGlobal
    //  即将销毁的View集合
    private final ArraySet<View> mDyingViews = new ArraySet<View>();

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

        if (root != null) {
            root.getImeFocusController().onWindowDismissed();
        }
        // 主流程
        boolean deferred = root.die(immediate);
        if (view != null) {
            // 这种父节点为null
            view.assignParent(null);
            if (deferred) {
                // 加入延迟销毁的集合
                mDyingViews.add(view);
            }
        }
    }

根据当前的调用链,immediate 传递过来的是 true ,表示立即销毁。

流程来到了 ViewRootImpl

# ViewRootImpl

    /**
     * @param immediate True, do now if not in traversal. False, put on queue and do later.
     * @return True, request has been queued. False, request has been completed.
     */
    boolean die(boolean immediate) {
        ......
        // 如果是立即销毁则执行doDie
        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;
    }

当前只看直接销毁的了,延迟销毁的自行了解。

# ViewRootImpl
    void doDie() {
        // 主线程检查
        checkThread();
        synchronized (this) {
            ......
            if (mAdded) {
                // 1. Window的销毁
                dispatchDetachedFromWindow();
            }
            if (mAdded && !mFirst) {
                // 2. 硬绘处理
                destroyHardwareRenderer();
                ......// 如果此时发现了一些参数改变,比如忽然可见了,则执行 finishDrawing 流程。
                ......// 非场景场景,先忽略 
                // 3. 应用端的Surface销毁处理
                destroySurface();
            }
        }
        ......
    }

继续看Window的移除逻辑

# ViewRootImpl
    final IWindowSession mWindowSession;
    void dispatchDetachedFromWindow() {
        ......
        destroyHardwareRenderer();
        ......
        destroySurface();
        try {
            // 触发 system_service 端移除对应的Window
            mWindowSession.remove(mWindow);
        } catch (RemoteException e) {
            Log.e(mTag, "RemoteException remove window " + mWindow + " in " + this, e);
        }
        ......
    }

system_service 端处理

后续的逻辑就由 system_service 处理,客户端最后调用的是 Session::remove 这一块的调用链如下:

Session::remove
    WindowManagerService::removeWindow
        WindowState::removeIfPossible
            WindowContainer::removeIfPossible
            WindowState::removeIfPossible
                WindowState::removeImmediately
                    WindowStateAnimator::destroySurfaceLocked
                        WindowStateAnimator::destroySurface  -- 销毁Surface
                            WindowSurfaceController::destroy
                            SurfaceControl.Transaction::remove
                        WindowState::setHasSurface           -- 设置窗口没有Surface
                        NO_SURFACE                           --设置窗口状态
                WindowContainer::removeImmediately
                    WindowStateAnimator::setSurfaceControl
                    mParent::removeChild

# Session 
    final WindowManagerService mService;

    @Override
    public void remove(IWindow window) {
        mService.removeWindow(this, window);
    }

所以还是由 WindowManagerService 来处理:

# WindowManagerService

    void removeWindow(Session session, IWindow client) {
        synchronized (mGlobalLock) {
            // 拿到对应的WindowState
            WindowState win = windowForClientLocked(session, client, false);
            if (win != null) {
                // 主流程
                win.removeIfPossible();
                return;
            }
            // Remove embedded window map if the token belongs to an embedded window
            mEmbeddedWindowController.remove(client);
        }
    }


这里的代码也很简单,找到需要移除的 WindowState ,然后执行 removeIfPossible

# WindowState

    @Override
    void removeIfPossible() {
        // 1. 调用父类方法,如果有孩子,则执行每个孩子的移除
        super.removeIfPossible();
        // 2. 主流程
        removeIfPossible(false /*keepVisibleDeadWindow*/);
    }

后面会出现多个 removeIfPossible ,需要注意执行是哪个类,还有是否有参数

先看一下调用父类的无参方法,然后再调用自己的方法,传递了 false

WindowContainer::removeIfPossible

刚刚看到的 WindowState::removeIfPossible 也是 Override ,说明这个方法是父类定义的, 也就是在 WindowContainer 下。
父类方法的定义很简单, 就是遍历需要移除的这个容器下的孩子,然后对孩子也执行一下 WindowContainer::removeIfPossible 。
这个其实就是一个递归:执行 removeIfPossible 方法移除容器A的时候,需要先把容器A下面的孩子容器都执行一遍 removeIfPossible方法。

# WindowContainer

    void removeIfPossible() {
        for (int i = mChildren.size() - 1; i >= 0; --i) {
            final WindowContainer wc = mChildren.get(i);
            wc.removeIfPossible();
        }
    }

孩子容器对这个方法有不同的重写,不过当前分析的还是 WindowState 的内容,继续看后续流程

WindowState::removeIfPossible

现在看的是 WindowStata 刚刚调用自己内部带参数的 removeIfPossible 方法。

# WindowState
    private void removeIfPossible(boolean keepVisibleDeadWindow) {
        mWindowRemovalAllowed = true;
        // 关键日志,有堆栈
        ProtoLog.v(WM_DEBUG_ADD_REMOVE,
                "removeIfPossible: %s callers=%s", this, Debug.getCallers(5));
        ......
        // 焦点日志
        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();
            mOnBackInvokedCallbackInfo = null;
            // app 事务的日志
            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));
            ......
            // 主流程
            removeImmediately();
            ......
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

这里有2个关键的 ProtoLog ,一个是窗口相关,一个是App 事务相关需要注意。 既然当前分析的窗口移除,所以看一下窗口相关的日志打印:

V WindowManager: removeIfPossible: Window{93e12cf u0 com.android.systemui/com.android.systemui.settings.brightness.BrightnessDialog} callers=com.android.server.wm.WindowState.removeIfPossible:2563 com.android.server.wm.WindowManagerService.removeWindow:2077 com.android.server.wm.Session.remove:229 android.view.IWindowSession$Stub.onTransact:693 com.android.server.wm.Session.onTransact:181 

这个日志在分析问题的时候也是很重要的,而且还会打印堆栈。

除了日志外,就是执行 WindowState::removeImmediately

# WindowState
    final WindowStateAnimator mWinAnimator;
    @Override
    void removeImmediately() {
        ......
        // 重点* 1. 移除 surface
        mWinAnimator.destroySurfaceLocked(getSyncTransaction());
        // 重点* 2. 父类 
        super.removeImmediately();
        ......
        // 获取到当前屏幕
        final DisplayContent dc = getDisplayContent();
        ......
        // 移除
        dc.getDisplayPolicy().removeWindowLw(this);
        ......
    }

这里有2个逻辑:
1、移除 buff 类型的 Surface
2、容器自身相关处理

移除 Surface,设置窗口状态

WindowStateAnimator 是控制动画和窗口状态的,先看一下 WindowStateAnimator::destroySurfaceLocked 做了什么,这个方法传递了事务进去,看来是要做 Surface 操作了。

# WindowStateAnimator
    WindowSurfaceController mSurfaceController;

    void destroySurfaceLocked(SurfaceControl.Transaction t) {
        ......
        mWin.mHidden = true;
        try {
            ......
            // Surface 销毁日志
            ProtoLog.i(WM_SHOW_SURFACE_ALLOC, "SURFACE DESTROY: %s. %s",
                    mWin, new RuntimeException().fillInStackTrace());
            // 1. 销毁Surface
            destroySurface(t);
            // Don't hide wallpaper if we're deferring the surface destroy
            // because of a surface change.
            mWallpaperControllerLocked.hideWallpapers(mWin);
        } ......

        // 2. 设置当前窗口没有Surface (mHasSurface = false)
        mWin.setHasSurface(false);
        if (mSurfaceController != null) {
            mSurfaceController.setShown(false);
        }
        // 3. 将当前窗口的Surface置空
        mSurfaceController = null;
        // 设置状态为 NO_SURFACE
        mDrawState = NO_SURFACE;
    }

标记了3个点,后面2个比较简单,只看销毁 Surface 的处理

# WindowStateAnimator
    WindowSurfaceController mSurfaceController;

    void destroySurfaceLocked(SurfaceControl.Transaction t) {
        ......
        mWin.mHidden = true;
        try {
            ......
            // Surface 销毁日志
            ProtoLog.i(WM_SHOW_SURFACE_ALLOC, "SURFACE DESTROY: %s. %s",
                    mWin, new RuntimeException().fillInStackTrace());
            // 1. 销毁Surface
            destroySurface(t);
            // Don't hide wallpaper if we're deferring the surface destroy
            // because of a surface change.
            mWallpaperControllerLocked.hideWallpapers(mWin);
        } ......

        // 2. 设置当前窗口没有Surface (mHasSurface = false)
        mWin.setHasSurface(false);
        if (mSurfaceController != null) {
            mSurfaceController.setShown(false);
        }
        // 3. 将当前窗口的Surface置空
        mSurfaceController = null;
        // 设置状态为 NO_SURFACE
        mDrawState = NO_SURFACE;
    }

WindowStateAnimator::destroySurfaceLocked 方法主要就是移除 Surface ,然后把 WindowState 的状态设置成 NO_SURFACE 。

容器自身相关处理

再看 父类 WindowContainer::removeImmediately 的处理

# WindowContainer

    void removeImmediately() {
        // 1、 解冻处理,确保事务正常的执行
        final DisplayContent dc = getDisplayContent();
        if (dc != null) {
            mSurfaceFreezer.unfreeze(getSyncTransaction());
        }
        // 2. 遍历孩子,调用孩子的 removeImmediately (这是一个递归了)
        while (!mChildren.isEmpty()) {
            final E child = mChildren.peekLast();
            // 2.1 递归执行孩子的removeImmediately方法
            child.removeImmediately();
            // Need to do this after calling remove on the child because the child might try to
            // remove/detach itself from its parent which will cause an exception if we remove
            // it before calling remove on the child.
            // 2.2 移除孩子
            if (mChildren.remove(child)) {
                onChildRemoved(child);
            }
        }

        if (mSurfaceControl != null) {
            // 3. 容器本身的 Surface 相关处理
            getSyncTransaction().remove(mSurfaceControl);
            setSurfaceControl(null);
            mLastSurfacePosition.set(0, 0);
            mLastDeltaRotation = Surface.ROTATION_0;
            // 触发动画
            scheduleAnimation();
        }
        if (mOverlayHost != null) {
            mOverlayHost.release();
            mOverlayHost = null;
        }

        // This must happen after updating the surface so that sync transactions can be handled
        // properly.
        if (mParent != null) {
            // 4. 把自己从父容器中移除
            mParent.removeChild(this);
        }
        //  5. 移除监听
        for (int i = mListeners.size() - 1; i >= 0; --i) {
            mListeners.get(i).onRemoved();
        }
    }

可以看到这里又处理了一下 Surface 相关,区别是 2.2.1 处理的是 buff类型的 Surface ,这里处理的是 WindowState 的 Surface 。

主要就是做了2件事:

  • 1、容器的移除处理
  • 2、容器 Surface 的置空(移除)

system_service 端的流程不算复杂, 基本上就是围绕着移除容器和移除 Surface 这2个事做处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值