文章目录
一般销毁窗口的场景就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个事做处理。