接着之前的StartingWindow显示流程,现在来介绍StartingWindow的销毁流程。
在View的绘制流程中会调用frameworks/base/core/java/android/view/ViewRootImpl.java的performTraversals方法:
private void performTraversals() {
......
// Remember if we must report the next draw.
if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
reportNextDraw();
}
......
}
private void reportNextDraw() {
if (mReportNextDraw == false) {
drawPending();
}
mReportNextDraw = true;
}
/**
* Delay notifying WM of draw finished until
* a balanced call to pendingDrawFinished.
*/
void drawPending() {
mDrawsNeededToReport++;
}
因为是第一次relayout,因此会调用ViewRootImpl的reportNextDraw方法,将mReportNextDraw设为true。然后在ViewRootImpl的performDraw方法中:
private void performDraw() {
......
boolean reportNextDraw = mReportNextDraw; // Capture the original value
if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
ArrayList<Runnable> commitCallbacks = mAttachInfo.mTreeObserver
.captureFrameCommitCallbacks();
final boolean needFrameCompleteCallback = mNextDrawUseBLASTSyncTransaction ||
(commitCallbacks != null && commitCallbacks.size() > 0) ||
mReportNextDraw;
usingAsyncReport = mReportNextDraw;
if (needFrameCompleteCallback) {
final Handler handler = mAttachInfo.mHandler;
mAttachInfo.mThreadedRenderer.setFrameCompleteCallback((long frameNr) -> {
finishBLASTSync(!mSendNextFrameToWm);
handler.postAtFrontOfQueue(() -> {
if (reportNextDraw) {
// TODO: Use the frame number
pendingDrawFinished();
}
......
});});
}
}
......
}
因为mReportNextDraw为true,会调用mAttachInfo.mThreadedRenderer.setFrameCompleteCallback设置一个帧完成时的回调,在回调中会调用ViewRootImpl的pendingDrawFinished方法:
void pendingDrawFinished() {
if (mDrawsNeededToReport == 0) {
throw new RuntimeException("Unbalanced drawPending/pendingDrawFinished calls");
}
mDrawsNeededToReport--;
if (mDrawsNeededToReport == 0) {
reportDrawFinished();
}
}
private void reportDrawFinished() {
try {
mDrawsNeededToReport = 0;
mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction);
} catch (RemoteException e) {
// Have fun!
}
}
最终会调用了ViewRootImpl的reportDrawFinished方法,在其中通过binder调用了frameworks/base/services/core/java/com/android/server/wm/Session.java的finishDrawing方法:
@Override
public void finishDrawing(IWindow window,
@Nullable SurfaceControl.Transaction postDrawTransaction) {
if (DEBUG) Slog.v(TAG_WM, "IWindow finishDrawing called for " + window);
mService.finishDrawingWindow(this, window, postDrawTransaction);
}
调用了frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java的finishDrawingWindow方法:
void finishDrawingWindow(Session session, IWindow client,
@Nullable SurfaceControl.Transaction postDrawTransaction) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
WindowState win = windowForClientLocked(session, client, false);
ProtoLog.d(WM_DEBUG_ADD_REMOVE, "finishDrawingWindow: %s mDrawState=%s",
win, (win != null ? win.mWinAnimator.drawStateToString() : "null"));
if (win != null && win.finishDrawing(postDrawTransaction)) {
if ((win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
win.getDisplayContent().pendingLayoutChanges |=
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
}
win.setDisplayLayoutNeeded();
mWindowPlacerLocked.requestTraversal();
}
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
接下来进入窗口布局流程,会调用frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java的mApplySurfaceChangesTransaction方法:
private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
......
final boolean committed = winAnimator.commitFinishDrawingLocked();
......
};
调用了frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java的commitFinishDrawingLocked方法:
// This must be called while inside a transaction.
boolean commitFinishDrawingLocked() {
if (DEBUG_STARTING_WINDOW_VERBOSE &&
mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
Slog.i(TAG, "commitFinishDrawingLocked: " + mWin + " cur mDrawState="
+ drawStateToString());
}
if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
return false;
}
if (DEBUG_ANIM) {
Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurfaceController);
}
mDrawState = READY_TO_SHOW;
boolean result = false;
final ActivityRecord activity = mWin.mActivityRecord;
if (activity == null || activity.canShowWindows()
|| mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
result = mWin.performShowLocked();
}
return result;
}
调用了frameworks/base/services/core/java/com/android/server/wm/WindowState.java的performShowLocked方法:
// This must be called while inside a transaction.
boolean performShowLocked() {
......
final int drawState = mWinAnimator.mDrawState;
if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW) && mActivityRecord != null) {
if (mAttrs.type != TYPE_APPLICATION_STARTING) {
mActivityRecord.onFirstWindowDrawn(this, mWinAnimator);
} else {
mActivityRecord.onStartingWindowDrawn();
}
}
......
}
调用了frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java的onFirstWindowDrawn方法:
void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
firstWindowDrawn = true;
// We now have a good window to show, remove dead placeholders
removeDeadWindows();
if (startingWindow != null) {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Finish starting %s"
+ ": first real window is shown, no animation", win.mToken);
// If this initial window is animating, stop it -- we will do an animation to reveal
// it from behind the starting window, so there is no need for it to also be doing its
// own stuff.
win.cancelAnimation();
}
removeStartingWindow();
updateReportedVisibilityLocked();
}
调用了ActivityRecord的removeStartingWindow方法:
void removeStartingWindow() {
......
final WindowManagerPolicy.StartingSurface surface;
if (mStartingData != null) {
surface = startingSurface;
mStartingData = null;
startingSurface = null;
startingWindow = null;
startingDisplayed = false;
if (surface == null) {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
"startingWindow was set but startingSurface==null, couldn't "
+ "remove");
return;
}
} else {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
"Tried to remove starting window but startingWindow was null: %s",
this);
return;
}
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Schedule remove starting %s startingWindow=%s"
+ " startingView=%s Callers=%s",
this, startingWindow, startingSurface, Debug.getCallers(5));
// Use the same thread to remove the window as we used to add it, as otherwise we end up
// with things in the view hierarchy being called from different threads.
mWmService.mAnimationHandler.post(() -> {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Removing startingView=%s", surface);
try {
surface.remove();
} catch (Exception e) {
Slog.w(TAG_WM, "Exception when removing starting window", e);
}
});
}
如果之前创建的是TaskSnapshotSurface,则调用了其remove方法:
@Override
public void remove() {
......
try {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Removing snapshot surface");
mSession.remove(mWindow);
} catch (RemoteException e) {
// Local call.
}
}
通过mSession.remove将显示窗口移除。
回到ActivityRecord的removeStartingWindow方法中,如果之前创建的是SplashScreenSurface,则调用其remove方法:
@Override
public void remove() {
if (DEBUG_SPLASH_SCREEN) Slog.v(TAG, "Removing splash screen window for " + mAppToken + ": "
+ this + " Callers=" + Debug.getCallers(4));
final WindowManager wm = mView.getContext().getSystemService(WindowManager.class);
wm.removeView(mView);
}
通过wm.removeView将显示窗口移除。
总结
不管是哪种StartingWindow都是在Activity的窗口绘制了第一帧后消失。
本文详细介绍了Android系统中StartingWindow从Activity的第一个窗口绘制完成后开始到销毁的整个流程,涉及ViewRootImpl、WindowStateAnimator等多个核心组件。
79

被折叠的 条评论
为什么被折叠?



