本篇文章主要以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