文章目录
- 应用端处理
- 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个事做处理。