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

devtools/2024/9/21 7:03:46/

文章目录

  • 应用端处理
  • system_service 端处理
    • WindowContainer::removeIfPossible
    • WindowState::removeIfPossible
      • 移除 Surface,设置窗口状态
      • 容器自身相关处理

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

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

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

在这里插入图片描述

应用端处理

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

ActivityThread::handleDestroyActivityActivityThread::performDestroyActivity       -- onDestroy流程Instrumentation::callActivityOnDestroyActivity::performDestroyActivity::onDestroyWindowManagerImpl::removeViewImmediate        -- UI处理WindowManagerGlobal::removeViewWindowManagerGlobal::removeViewLockedViewRootImpl::dieViewRootImpl::doDieViewRootImpl::dispatchDetachedFromWindowIWindowSession::remove     -- 跨进程到 system_service 进程处理ViewRootImpl::destroyHardwareRendererViewRootImpl::destroySurfacemDyingViews::addActivityClient::activityDestroyed            -- system_service 进程处理

首先是ActivityThread处理:

# ActivityThread@Overridepublic void handleDestroyActivity(ActivityClientRecord r, boolean finishing, int configChanges,boolean getNonConfigInstance, String reason) {// 1. 主流程 onDestroyperformDestroyActivity(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的移除

# WindowManagerImplprivate final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();@Overridepublic void removeViewImmediate(View view) {mGlobal.removeView(view, true);}
# WindowManagerGlobalpublic 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下的ViewView 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和ViewViewRootImpl root = mRoots.get(index);View view = root.getView();if (root != null) {root.getImeFocusController().onWindowDismissed();}// 主流程boolean deferred = root.die(immediate);if (view != null) {// 这种父节点为nullview.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) {......// 如果是立即销毁则执行doDieif (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;}

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

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

继续看Window的移除逻辑

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

system_service 端处理

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

Session::removeWindowManagerService::removeWindowWindowState::removeIfPossibleWindowContainer::removeIfPossibleWindowState::removeIfPossibleWindowState::removeImmediatelyWindowStateAnimator::destroySurfaceLockedWindowStateAnimator::destroySurface  -- 销毁SurfaceWindowSurfaceController::destroySurfaceControl.Transaction::removeWindowState::setHasSurface           -- 设置窗口没有SurfaceNO_SURFACE                           --设置窗口状态WindowContainer::removeImmediatelyWindowStateAnimator::setSurfaceControlmParent::removeChild
# Session final WindowManagerService mService;@Overridepublic void remove(IWindow window) {mService.removeWindow(this, window);}

所以还是由 WindowManagerService 来处理:

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

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

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

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

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

WindowContainer::removeIfPossible

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

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

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

WindowState::removeIfPossible

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

# WindowStateprivate 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

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

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

移除 Surface,设置窗口状态

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

# WindowStateAnimatorWindowSurfaceController 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. 销毁SurfacedestroySurface(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_SURFACEmDrawState = NO_SURFACE;}

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

# WindowStateAnimatorWindowSurfaceController 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. 销毁SurfacedestroySurface(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_SURFACEmDrawState = NO_SURFACE;}

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

容器自身相关处理

再看 父类 WindowContainer::removeImmediately 的处理

# WindowContainervoid 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个事做处理。


http://www.ppmy.cn/devtools/114864.html

相关文章

8585 栈的应用——进制转换

### 思路 1. **初始化栈**&#xff1a;创建一个空栈用于存储转换后的八进制数的每一位。 2. **十进制转八进制**&#xff1a;将十进制数不断除以8&#xff0c;并将余数依次入栈&#xff0c;直到商为0。 3. **输出八进制数**&#xff1a;将栈中的元素依次出栈并打印&#xff0c;…

Linux top命令详解与重点内容说明

文章目录 重点说明基本信息进程(任务)信息cpu占用信息%Cpu(s)内存信息交换内存信息每列含义说明交互命令多窗口模式颜色配置命令参数 重点说明 top命令非常强大&#xff0c;也非常复杂&#xff0c;很难面面俱到&#xff0c;也没有必要&#xff0c;这篇文章的目的是介绍重点&am…

C# 访问Access存取图片

图片存入ole字段&#xff0c;看有的代码是获取图片的字节数组转换为base64字符串&#xff0c;存入数据库&#xff1b;显示图片是把base64字符串转换为字节数组再显示&#xff1b;直接存字节数组可能还好一点&#xff1b; 插入的时候用带参数的sql写法比较好&#xff1b;用拼接…

Linux学习day02

Linux 软件包管理器 yum 什么是软件包 在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安 装程序)放在一个服务器上, 通过包管理器可以很方便…

【python设计模式4】结构型模式1

目录 适配器模式 桥模式 适配器模式 将一个类的接口转换成客户希望的另外一个接口&#xff0c;适配器使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。实现适配器的两种方式&#xff0c;类适配器使用多继承&#xff0c;对象适配器使用组合。组合就是一个类中放入另…

蓝桥杯-基于STM32G432RBT6的LCD进阶(LCD界面切换以及高亮显示界面)

目录 一、页面切换内容详解 1.逻辑解释 2.代码详解 code.c&#xff08;内含详细讲解&#xff09; code.h main.c 3.效果图片展示 ​编辑 二、页面选项高亮内容详解 1.逻辑解释 2.读入数据 FIRST.第一种高亮类型 code.c&#xff08;内含代码详解&#xff09; code.…

flutter中常见的跨组件通讯方式

在 Flutter 开发中&#xff0c;事件管理和组件间通信是非常重要的。EventBus 和 NotificationListener 是两种常用的模式&#xff0c;它们各自有不同的使用场景和优势劣势。本文将对这两者进行比较分析&#xff0c;并提供代码示例。 在 Flutter 开发中&#xff0c;事件管理和组…

【JS】垃圾回收机制与内存泄漏

垃圾回收机制与内存泄漏 内存泄漏是指在程序运行过程中&#xff0c;某些不再需要使用的内存没有被正确释放&#xff0c;导致这些内存资源无法再被系统重新使用。随着程序的持续运行&#xff0c;内存泄漏会不断消耗可用内存&#xff0c;最终可能导致内存不足、系统变慢&#xf…