接著上篇:http://www.itdecent.cn/p/95e8654036a8
2.3 窗口狀態(tài)刷新
當(dāng)應(yīng)用端執(zhí)行measure-layout-draw之后,便會(huì)調(diào)用WMS.finishDrawingWindow,處理Surface的狀態(tài)變更并將Surface show出來。
首先還是看一下該階段的流程圖,對(duì)整個(gè)流程有個(gè)初步的了解。
將整個(gè)流程分為三部分:
1.WMS接受客戶端請(qǐng)求,將mDrawState更新為COMMIT_DRAW_PENDING,并請(qǐng)求窗口布局。
2.mDrawState更新為HAS_DRAW,再次請(qǐng)求窗口布局。
3.執(zhí)行show Surface。
2.3.1 接受客戶端請(qǐng)求
代碼路徑:framework/services/core/java/com/android/server/wm/Session.java
@Override
public void finishDrawing(IWindow window,
@Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
if (DEBUG) Slog.v(TAG_WM, "IWindow finishDrawing called for " + window);
//調(diào)用WMS中的finishDrawingWindow處理
mService.finishDrawingWindow(this, window, postDrawTransaction, seqId);
}
2.3.2 finishDrawingWindow
1.在WMS中根據(jù)客戶端的Binder在mWindowMap中獲取對(duì)應(yīng)的WindowState。
2.調(diào)用WindowState.finishDrawing執(zhí)行mDrawState的狀態(tài)變更。
3.將WindowState.mLayoutNeeded標(biāo)志位置為true。
4.請(qǐng)求進(jìn)行布局刷新。
代碼路徑:framework/services/core/java/com/android/server/wm/WindowManagerService.java
void finishDrawingWindow(Session session, IWindow client,
@Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
if (postDrawTransaction != null) {
postDrawTransaction.sanitize();
}
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
/*1.根據(jù)客戶端的Binder在mWindowMap中獲取對(duì)應(yīng)的WindowState*/
WindowState win = windowForClientLocked(session, client, false);
ProtoLog.d(WM_DEBUG_ADD_REMOVE, "finishDrawingWindow: %s mDrawState=%s",
win, (win != null ? win.mWinAnimator.drawStateToString() : "null"));
/*2.finishDrawing執(zhí)行mDrawState的狀態(tài)更變*/
if (win != null && win.finishDrawing(postDrawTransaction, seqId)) {
if (win.hasWallpaper()) {
win.getDisplayContent().pendingLayoutChanges |=
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
}
/*3.將當(dāng)前WindowState.mLayoutNeeded置為true*/
//該標(biāo)志位是判斷是否進(jìn)行窗口大小尺寸計(jì)算的條件之一
win.setDisplayLayoutNeeded();
/*4.請(qǐng)求進(jìn)行布局刷新*/
mWindowPlacerLocked.requestTraversal();
}
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
1.mDrawState的狀態(tài)更變
在finishDrawingWindow中調(diào)用WindowState的finishDrawing方法
win.finishDrawing(postDrawTransaction, seqId)
這個(gè)方法主要調(diào)用了WindowStateAnimator的finishDrawingLocked進(jìn)行狀態(tài)更變
代碼路徑:framework/services/core/java/com/android/server/wm/WindowState.java
boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction, int syncSeqId) {
......
//調(diào)用WindowStateAnimator.finishDrawingLocked,會(huì)將mDrawState的狀態(tài)更改為COMMIT_DRAW_PENDING
final boolean layoutNeeded =
mWinAnimator.finishDrawingLocked(postDrawTransaction, mClientWasDrawingForSync);
mClientWasDrawingForSync = false;
// We always want to force a traversal after a finish draw for blast sync.
return !skipLayout && (hasSyncHandlers || layoutNeeded);
}
我們繼續(xù)看看WindowStateAnimator中的finishDrawingLocked()方法
首先判斷mDrawState的狀態(tài)是否為DRAW_PENDING,在我們創(chuàng)建SurfaceControl時(shí),會(huì)將mDrawState狀態(tài)更新為DRAW_PENDING。因此接下來將狀態(tài)調(diào)整為COMMIT_DRAW_PENDING。
代碼路徑:framework/services/core/java/com/android/server/wm/WindowStateAnimator.java
boolean finishDrawingLocked(SurfaceControl.Transaction postDrawTransaction,
boolean forceApplyNow) {
......
boolean layoutNeeded = false;
if (mDrawState == DRAW_PENDING) {
......
//如果當(dāng)前狀態(tài)為DRAW_PENDING,則將mDrawState更變?yōu)镃OMMIT_DRAW_PENDING
mDrawState = COMMIT_DRAW_PENDING;
layoutNeeded = true;
}
......
return layoutNeeded;
}
2.請(qǐng)求布局刷新
在finishDrawingWindow中請(qǐng)求布局刷新
mWindowPlacerLocked.requestTraversal();
requestTraversal中主要做了兩件事:
1.首先將遍歷標(biāo)志為mTraversalSchedule置為true。
2.其次發(fā)送handle消息mPerformSurfacePlacement
void requestTraversal() {
//判斷遍歷標(biāo)志mTraversalScheduled是否為true
if (mTraversalScheduled) {
return;
}
// Set as scheduled even the request will be deferred because mDeferredRequests is also
// increased, then the end of deferring will perform the request.
//將遍歷標(biāo)志位置為true
mTraversalScheduled = true;
if (mDeferDepth > 0) {
mDeferredRequests++;
if (DEBUG) Slog.i(TAG, "Defer requestTraversal " + Debug.getCallers(3));
return;
}
//發(fā)送handle消息,處理消息會(huì)調(diào)用mPerformSurfacePlacement
mService.mAnimationHandler.post(mPerformSurfacePlacement);
}
mPerformSurfacePlacement會(huì)新建一個(gè)線程調(diào)用performSurfacePlacement。
performSurfacePlacement方法我們?cè)谥vrelayoutWindow相關(guān)流程的時(shí)候講過,這是執(zhí)行遍歷布局的入口??梢曰乜聪隆?.2.4 計(jì)算窗口大小位置中的“1.處理窗口布局循環(huán)”】
private class Traverser implements Runnable {
@Override
public void run() {
synchronized (mService.mGlobalLock) {
//調(diào)用執(zhí)行performSurfacePlacement
performSurfacePlacement();
}
}
}
private final Traverser mPerformSurfacePlacement = new Traverser();
final void performSurfacePlacement(boolean force) {
//當(dāng)mDeferDepth大于0且force為false時(shí),則將延遲布局請(qǐng)求數(shù)+1,并直接返回
if (mDeferDepth > 0 && !force) {
mDeferredRequests++;
return;
}
//將循環(huán)的最大次數(shù)設(shè)置為6次
int loopCount = 6;
do {
//將該標(biāo)志為設(shè)置為false
mTraversalScheduled = false;
//執(zhí)行窗口布局操作
performSurfacePlacementLoop();
mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
loopCount--;
//只有當(dāng)mTraversalScheduled為true且循環(huán)次數(shù)大于0時(shí),才會(huì)再次循環(huán)執(zhí)行布局
} while (mTraversalScheduled && loopCount > 0);
mService.mRoot.mWallpaperActionPending = false;
}
private void performSurfacePlacementLoop() {
//若當(dāng)前已經(jīng)進(jìn)行布局操作,則無需重復(fù)調(diào)用直接返回
if (mInLayout) {
......
return;
}
......
//將該標(biāo)志位置為true,表示正在處于布局過程中
mInLayout = true;
......
try {
/*1.調(diào)用RootWindowContainer的performSurfacePlacement()方法對(duì)所有窗口執(zhí)行布局操作*/
mService.mRoot.performSurfacePlacement();
mInLayout = false;
if (mService.mRoot.isLayoutNeeded()) {
/*2.若需要布局,且布局次數(shù)小于6次,則需要再次請(qǐng)求布局*/
if (++mLayoutRepeatCount < 6) {
//該方法中會(huì)將mTraversalScheduled標(biāo)志位設(shè)置位true
requestTraversal();
} else {
Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
mLayoutRepeatCount = 0;
}
} else {
mLayoutRepeatCount = 0;
}
if (mService.mWindowsChanged && !mService.mWindowChangeListeners.isEmpty()) {
mService.mH.removeMessages(REPORT_WINDOWS_CHANGE);
mService.mH.sendEmptyMessage(REPORT_WINDOWS_CHANGE);
}
} catch (RuntimeException e) {
mInLayout = false;
Slog.wtf(TAG, "Unhandled exception while laying out windows", e);
}
}
代碼路徑:framework/services/core/java/com/android/server/wm/RootWindowContainer.java
void performSurfacePlacement() {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performSurfacePlacement");
try {
//調(diào)用performSurfacePlacementNoTrace()
performSurfacePlacementNoTrace();
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
// "Something has changed! Let's make it correct now."
// TODO: Super long method that should be broken down...
void performSurfacePlacementNoTrace() {
......
/*1.如果有焦點(diǎn)變化,更新焦點(diǎn)*/
if (mWmService.mFocusMayChange) {
mWmService.mFocusMayChange = false;
mWmService.updateFocusedWindowLocked(
UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
}
......
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
//開啟事務(wù),獲取GlobalTransactionWrapper對(duì)象
mWmService.openSurfaceTransaction();
try {
/*2.執(zhí)行窗口尺寸計(jì)算,surface狀態(tài)變更等操作*/
applySurfaceChangesTransaction();
} catch (RuntimeException e) {
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
} finally {
//關(guān)閉事務(wù),把事務(wù)提交
mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (SHOW_LIGHT_TRANSACTIONS) {
Slog.i(TAG,
"<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
}
}
......
/*3.將Surface狀態(tài)變更為HAS_DRAWN,觸發(fā)App觸發(fā)動(dòng)畫。該過程在“2.3.3mDrawState變更為HAS_DRAW”流程中再詳細(xì)分析*/
checkAppTransitionReady(surfacePlacer);
......
/*4.遍歷所有DisplayContent,如果壁紙有變化,更新壁紙*/
for (int displayNdx = 0; displayNdx < mChildren.size(); ++displayNdx) {
final DisplayContent displayContent = mChildren.get(displayNdx);
//判斷DisplayContent的壁紙是否需要改變
if (displayContent.mWallpaperMayChange) {
ProtoLog.v(WM_DEBUG_WALLPAPER, "Wallpaper may change! Adjusting");
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
if (DEBUG_LAYOUT_REPEATS) {
surfacePlacer.debugLayoutRepeats("WallpaperMayChange",
displayContent.pendingLayoutChanges);
}
}
}
/*5.在此處理焦點(diǎn)變化*/
if (mWmService.mFocusMayChange) {
mWmService.mFocusMayChange = false;
mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
false /*updateInputWindows*/);
}
......
/*6.如果過程中size或者位置變化,則通知客戶端重新relayout*/
handleResizingWindows();
if (mWmService.mDisplayFrozen) {
ProtoLog.v(WM_DEBUG_ORIENTATION,
"With display frozen, orientationChangeComplete=%b",
mOrientationChangeComplete);
}
if (mOrientationChangeComplete) {
if (mWmService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
mWmService.mLastFinishedFreezeSource = mLastWindowFreezeSource;
mWmService.mH.removeMessages(WINDOW_FREEZE_TIMEOUT);
}
mWmService.stopFreezingDisplayLocked();
}
// Destroy the surface of any windows that are no longer visible.
/*7.銷毀不可見的窗口*/
i = mWmService.mDestroySurface.size();
if (i > 0) {
do {
i--;
WindowState win = mWmService.mDestroySurface.get(i);
win.mDestroying = false;
final DisplayContent displayContent = win.getDisplayContent();
if (displayContent.mInputMethodWindow == win) {
displayContent.setInputMethodWindowLocked(null);
}
if (displayContent.mWallpaperController.isWallpaperTarget(win)) {
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
win.destroySurfaceUnchecked();
} while (i > 0);
mWmService.mDestroySurface.clear();
}
......
}
這里我們主要關(guān)注applySurfaceChangesTransaction();和checkAppTransitionReady(surfacePlacer);
- 窗口位置計(jì)算與窗口狀態(tài)刷新流程不同點(diǎn)
可以發(fā)現(xiàn),窗口位置計(jì)算流程與窗口狀態(tài)刷新流程都調(diào)用了performSurfacePlacement,兩次調(diào)用的主要不同點(diǎn)在于:
1.窗口狀態(tài)刷新流程在DisplayContent.applySurfaceChangesTransaction中調(diào)用mApplySurfaceChangesTransaction,處理mDrawState狀態(tài)。
2.窗口狀態(tài)刷新流程在RootWindowContainer.performSurfacePlacementNoTrace中調(diào)用checkAppTransitionReady,處理mDrawState狀態(tài)變更為HAS_DRAWN,觸發(fā)Activity過渡動(dòng)畫。
3.窗口狀態(tài)刷新流程在WindowSurfacePlacementLoop.performSurfacePlacementLoop中會(huì)調(diào)用requestTraversal,請(qǐng)求再次布局。
4.窗口狀態(tài)刷新流程在DisplayContent.applySurfaceChangesTransaction中調(diào)用prepareSurfaces()處理處理surface的位置、大小以及顯示等。
2.3.3 mDrawState變更為HAS_DRAW
1.mApplySurfaceChangesTransaction
RootWindowContainer的applySurfaceChangesTransaction()方法最終會(huì)調(diào)用到DisplayContent中調(diào)用的applySurfaceChangesTransaction()方法,我們接著該方法中的mApplySurfaceChangesTransaction跟蹤。
forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
如果當(dāng)前WindowState存在surfaceControl,則進(jìn)入到WindowStateAnimator進(jìn)行mDrawState的狀態(tài)更變。
代碼路徑:framework/services/core/java/com/android/server/wm/DisplayContent.java
private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
......
//首先判斷當(dāng)前windowState的是否有surfaceControl
if (w.mHasSurface) {
// Take care of the window being ready to display.
//調(diào)用WindowStateAnimator的commitFinishDrawingLocked()方法
final boolean committed = winAnimator.commitFinishDrawingLocked();
......
}
......
};
繼續(xù)看看WindowStateAnimator的commitFinishDrawingLocked()方法
final boolean committed = winAnimator.commitFinishDrawingLocked();
1.對(duì)mDrawState的狀態(tài)進(jìn)行過濾,非COMMIT_DRAW_PENDING和READY_TO_SHOW則直接返回。
2.此時(shí)我們的mDrawState已經(jīng)在“【2.3.2 finishDrawingWindow】”將狀態(tài)更新為COMMIT_DRAW_PENDING,因此此處將其變更為READY_TO_SHOW。
代碼路徑:framework/services/core/java/com/android/server/wm/WindowStateAnimator.java
// This must be called while inside a transaction.
boolean commitFinishDrawingLocked() {
//非COMMIT_DRAW_PENDING和READY_TO_SHOW則直接返回
if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
return false;
}
ProtoLog.i(WM_DEBUG_ANIM, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW %s",
mSurfaceController);
//將狀態(tài)更變?yōu)镽EADY_TO_SHOW
mDrawState = READY_TO_SHOW;
boolean result = false;
final ActivityRecord activity = mWin.mActivityRecord;
//如果ActivityRecord為空,或者canShowWindows()為true,或者窗口類型為啟動(dòng)窗口,則直接進(jìn)入到WindowState.performShowLocked()流程
//進(jìn)入performShowLocked()流程后mDrawState更新HAS_DRAWN
//由于非這三種情況最終也會(huì)調(diào)用到performShowLocked(),因此下面這種情況我們暫不討論
if (activity == null || activity.canShowWindows()
|| mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
result = mWin.performShowLocked();
}
return result;
}
2.checkAppTransitionReady()
這里我們繼續(xù)跟蹤RootWindowContainer.performSurfacePlacementNoTrace()方法中的checkAppTransitionReady()方法
checkAppTransitionReady(surfacePlacer);
該方法會(huì)遍歷所有DisplayContent,處理activity的過濾動(dòng)畫,此處我們只有跟蹤有關(guān)mDrawState狀態(tài)更變的相關(guān)代碼
代碼路徑:framework/services/core/java/com/android/server/wm/RootWindowContainer.java
private void checkAppTransitionReady(WindowSurfacePlacer surfacePlacer) {
// Trace all displays app transition by Z-order for pending layout change.
for (int i = mChildren.size() - 1; i >= 0; --i) {
final DisplayContent curDisplay = mChildren.get(i);
// If we are ready to perform an app transition, check through all of the app tokens
// to be shown and see if they are ready to go.
//檢查所有要顯示的app token,是否已經(jīng)準(zhǔn)備就緒
if (curDisplay.mAppTransition.isReady()) {
// handleAppTransitionReady may modify curDisplay.pendingLayoutChanges.
curDisplay.mAppTransitionController.handleAppTransitionReady();
if (DEBUG_LAYOUT_REPEATS) {
surfacePlacer.debugLayoutRepeats("after handleAppTransitionReady",
curDisplay.pendingLayoutChanges);
}
}
......
}
}
調(diào)用AppTransitionController的handleAppTransitionReady()方法,該方法主要還是在處理activity的過渡動(dòng)畫,但是在應(yīng)用過渡動(dòng)畫時(shí),還做了以下事情
1.分別調(diào)用 handleClosingApps以及handleOpeningApps對(duì)要關(guān)閉的和要打開的Activity進(jìn)行可見性更新。
2.由于activity的可見性變更,將DisplayContent.mLayoutNeeded設(shè)置為true,該標(biāo)志位在DisplayContent.performLayoutNoTrace中用來判斷是否對(duì)當(dāng)前Displaycontent下的所有窗口進(jìn)行刷新。
代碼路徑:framework/services/core/java/com/android/server/wm/AppTransitionController.java
/**
* Handle application transition for given display.
*/
void handleAppTransitionReady() {
......
try {
//應(yīng)用app transition動(dòng)畫
applyAnimations(openingAppsForAnimation, closingAppsForAnimation, transit, animLp,
voiceInteraction);
/*1.1處理closing activity可見性*/
handleClosingApps();
/*1.2處理opening actvity可見性*/
handleOpeningApps();
......
} finally {
mService.mSurfaceAnimationRunner.continueStartingAnimations();
}
......
// This has changed the visibility of windows, so perform
// a new layout to get them all up-to-date.
/*2.由于activity的可見性變更,將DisplayContent.mLayoutNeeded標(biāo)志位置為true*/
mDisplayContent.setLayoutNeeded();
......
}
我們先看看 handleClosingApps()
該方法中主要的作用就是將所有即將close的activity的mVisible標(biāo)志設(shè)置為false。該標(biāo)志位在后續(xù)prepareSurfaces中是判斷是否show surface的條件之一。
private void handleClosingApps() {
final ArraySet<ActivityRecord> closingApps = mDisplayContent.mClosingApps;
final int appsCount = closingApps.size();
for (int i = 0; i < appsCount; i++) {
final ActivityRecord app = closingApps.valueAt(i);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now closing app %s", app);
//設(shè)置activity的可見性,將mVisible設(shè)置為false
app.commitVisibility(false /* visible */, false /* performLayout */);
app.updateReportedVisibilityLocked();
// Force the allDrawn flag, because we want to start
// this guy's animations regardless of whether it's
// gotten drawn.
//強(qiáng)制將allDrawn設(shè)置為true
app.allDrawn = true;
......
}
}
再看看,與handleClosingApps類似,主要處理兩件事情:
1.將所有即將open的activity的mVisible標(biāo)志位設(shè)置為true.
2.調(diào)用ActivityRecord.showAllWindowsLocked(),最終會(huì)調(diào)用到WindowState.performShowLocked() ,處理mDrawState的狀態(tài)變更
private void handleOpeningApps() {
final ArraySet<ActivityRecord> openingApps = mDisplayContent.mOpeningApps;
final int appsCount = openingApps.size();
for (int i = 0; i < appsCount; i++) {
final ActivityRecord app = openingApps.valueAt(i);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now opening app %s", app);
/*1.設(shè)置activity的可見性,將mVisible設(shè)置為true*/
app.commitVisibility(true /* visible */, false /* performLayout */);
......
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
">>> OPEN TRANSACTION handleAppTransitionReady()");
//開啟事務(wù)
mService.openSurfaceTransaction();
try {
/*2.此方法最終會(huì)調(diào)用到WindowState.performShowLocked*/
app.showAllWindowsLocked();
} finally {
//關(guān)閉事務(wù)
mService.closeSurfaceTransaction("handleAppTransitionReady");
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
"<<< CLOSE TRANSACTION handleAppTransitionReady()");
}
......
}
}
app.commitVisibility(true /* visible /, false / performLayout */);
先調(diào)用到ActivityRecord的howAllWindowsLocked()
代碼路徑:framework/services/core/java/com/android/server/wm/ActivityRecord.java
/**
* This must be called while inside a transaction.
*/
void showAllWindowsLocked() {
forAllWindows(windowState -> {
if (DEBUG_VISIBILITY) Slog.v(TAG, "performing show on: " + windowState);
windowState.performShowLocked();
}, false /* traverseTopToBottom */);
}
windowState.performShowLocked();
再調(diào)用到WindowState的performShowLocked()
將mDrawState的狀態(tài)由READY_TO_SHOW變更為HAS_DRAW
代碼路徑:framework/services/core/java/com/android/server/wm/WindowState.java
// This must be called while inside a transaction.
boolean performShowLocked() {
......
//獲取WindowStateAnimator.mDrawState
final int drawState = mWinAnimator.mDrawState;
//這里判斷(drawState 狀態(tài)為HAS_DRAWN 或者READY_TO_SHOW)且ActivityRecord不為空
if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW) && mActivityRecord != null) {
//窗口類型不為啟動(dòng)窗口
if (mAttrs.type != TYPE_APPLICATION_STARTING) {
mActivityRecord.onFirstWindowDrawn(this);
} else {
mActivityRecord.onStartingWindowDrawn();
}
}
//如果當(dāng)前mDrawState的狀態(tài)不為READY_TO_SHOW ,則直接返回
if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplay()) {
return false;
}
......
// Force the show in the next prepareSurfaceLocked() call.
mWinAnimator.mLastAlpha = -1;
ProtoLog.v(WM_DEBUG_ANIM, "performShowLocked: mDrawState=HAS_DRAWN in %s", this);
//設(shè)置mDrawState的狀態(tài)為HAS_DRAWN
mWinAnimator.mDrawState = HAS_DRAWN;
mWmService.scheduleAnimationLocked();
......
return true;
}
3.再次請(qǐng)求布局
回到WindowSurfacePlacer中通過requestTraversals(),再次請(qǐng)求布局,該方法將mTraversalScheduled標(biāo)志位設(shè)置為true的判斷條件有兩個(gè):
1.遍歷所有DisplayContent.mLayoutNeeded標(biāo)志為是否為true。(由于AppTransitionController.handleAppTransitionReady階段已經(jīng)將mLayoutNeeded置為true,因此該條件為真)
2.重復(fù)布局的次數(shù)不能超過6次,該條件也為真。(因?yàn)楫?dāng)前還只是第一次布局)
代碼路徑:framework/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
private void performSurfacePlacementLoop() {
......
try {
......
/*1.遍歷所有DisplayContent.mLayoutNeeded標(biāo)志位是否為true*/
if (mService.mRoot.isLayoutNeeded()) {
/*2.如果需要布局,且布局次數(shù)小于6次,則需要再次請(qǐng)求布局*/
if (++mLayoutRepeatCount < 6) {
//該方法中會(huì)將mTraversalScheduled標(biāo)志位設(shè)置位true
requestTraversal();
} else {
Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
mLayoutRepeatCount = 0;
}
} else {
mLayoutRepeatCount = 0;
}
......
} catch (RuntimeException e) {
......
}
}
接下來進(jìn)入第二次布局循環(huán),其主要目的是為了show surface
2.3.4 show Surface
在第二次循環(huán)中,我們主要關(guān)注DisplayContent中applySurfaceChangesTransaction()方法調(diào)用的prepareSurfaces()
該方法最終會(huì)調(diào)用到根容器WindowContainer,來遍歷所有子容器中的prepareSurfaces。
代碼路徑:framework/services/core/java/com/android/server/wm/DisplayContent.java
@Override
void prepareSurfaces() {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "prepareSurfaces");
try {
//獲取事務(wù)
final Transaction transaction = getPendingTransaction();
//調(diào)用其父類方法
super.prepareSurfaces();
// TODO: Once we totally eliminate global transaction we will pass transaction in here
// rather than merging to global.
SurfaceControl.mergeToGlobalTransaction(transaction);
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
調(diào)用其父類方法super.prepareSurfaces();
DisplayContent的父類為WindowContainer
代碼路徑:framework/services/core/java/com/android/server/wm/WindowContainer.java
void prepareSurfaces() {
// If a leash has been set when the transaction was committed, then the leash reparent has
// been committed.
mCommittedReparentToAnimationLeash = mSurfaceAnimator.hasLeash();
//調(diào)用所有子容器中的prepareSurfaces
for (int i = 0; i < mChildren.size(); i++) {
mChildren.get(i).prepareSurfaces();
}
}
mChildren.get(i).prepareSurfaces();在WindowState.prepareSurfaces中,主要做了兩方面工作。
1.將mWindowFrames中計(jì)算出來的left以及top設(shè)置surface位置,并調(diào)整窗口比例。
2.控制surface的可見性,查看WindowStateAnimator.prepareSurfaceLocked
代碼路徑:framework/services/core/java/com/android/server/wm/WindowState.java
void prepareSurfaces() {
mIsDimming = false;
applyDims();
//實(shí)際調(diào)用的是其父類WindowContainer的方法
/*1.最終調(diào)用自身的updateSurfacePosition()(自身有重寫該方法)計(jì)算surface的位置*/
updateSurfacePositionNonOrganized();
// Send information to SurfaceFlinger about the priority of the current window.
updateFrameRateSelectionPriorityIfNeeded();
//更新窗口比例
updateScaleIfNeeded();
/*2.控制surface的可見性,調(diào)用WindowStateAnimator的prepareSurfaceLocked()方法*/
mWinAnimator.prepareSurfaceLocked(getSyncTransaction());
super.prepareSurfaces();
}
@Override
@VisibleForTesting
void updateSurfacePosition(Transaction t) {
if (mSurfaceControl == null) {
return;
}
......
mSurfacePlacementNeeded = false;
//將mSurfacePosition的left以及top設(shè)置mWindowFrames中計(jì)算出來的left以及top,并根據(jù)parent進(jìn)行偏移
transformFrameToSurfacePosition(mWindowFrames.mFrame.left, mWindowFrames.mFrame.top,
mSurfacePosition);
//根據(jù)壁紙的比例對(duì)SurfacePosition進(jìn)行調(diào)整
if (mWallpaperScale != 1f) {
final Rect bounds = getLastReportedBounds();
Matrix matrix = mTmpMatrix;
matrix.setTranslate(mXOffset, mYOffset);
matrix.postScale(mWallpaperScale, mWallpaperScale, bounds.exactCenterX(),
bounds.exactCenterY());
matrix.getValues(mTmpMatrixArray);
mSurfacePosition.offset(Math.round(mTmpMatrixArray[Matrix.MTRANS_X]),
Math.round(mTmpMatrixArray[Matrix.MTRANS_Y]));
} else {
mSurfacePosition.offset(mXOffset, mYOffset);
}
......
}
mWinAnimator.prepareSurfaceLocked(getSyncTransaction()); 調(diào)用WindowStateAnimator的prepareSurfaceLocked()方法,該則真正的處理觸發(fā)surface show的邏輯。主要分為兩部分。
1.將計(jì)算的alpha應(yīng)用于當(dāng)前surface。
2.判斷是否調(diào)用showSurfaceRobustlyLocked將surface show出來。
代碼路徑:framework/services/core/java/com/android/server/wm/WindowStateAnimator.java
void prepareSurfaceLocked(SurfaceControl.Transaction t) {
final WindowState w = mWin;
//首先判斷是否有SurfaceControl
if (!hasSurface()) {
......
return;
}
//設(shè)置mShowAlpha
computeShownFrameLocked();
//判斷parentWindow是否hidden,或者當(dāng)前窗口是否on-screen
if (w.isParentWindowHidden() || !w.isOnScreen()) {
......
} else if (mLastAlpha != mShownAlpha
|| mLastHidden) {
mLastAlpha = mShownAlpha;
ProtoLog.i(WM_SHOW_TRANSACTIONS,
"SURFACE controller=%s alpha=%f HScale=%f, VScale=%f: %s",
mSurfaceController, mShownAlpha, w.mHScale, w.mVScale, w);
/*1.設(shè)置surface的alpha*/
boolean prepared =
mSurfaceController.prepareToShowInTransaction(t, mShownAlpha);
//如果當(dāng)前狀態(tài)為HAS_DRAWN
if (prepared && mDrawState == HAS_DRAWN) {
if (mLastHidden) {
/*2.觸發(fā)show surface*/
if (showSurfaceRobustlyLocked(t)) {
mAnimator.requestRemovalOfReplacedWindows(w);
//設(shè)置mLastHidden為false
mLastHidden = false;
.......
} else {
w.setOrientationChanging(false);
}
}
}
} else {
if (mWin.isAnimating(TRANSITION | PARENTS)) {
ProtoLog.v(WM_DEBUG_ANIM, "prepareSurface: No changes in animation for %s", this);
}
}
......
}
從上述代碼中可以看出觸發(fā)showSurfaceRobustlyLocked的判斷條件有以下幾點(diǎn):
1.w.isParentWindowHidden判斷其parent的mHidden是否為true,此時(shí)當(dāng)前窗口沒有parent直接返回false
2.w.isOnScreen,判斷當(dāng)前窗口是否在屏幕上,如果該窗口mVisible為true或者在不可見之前正在運(yùn)行動(dòng)畫,判斷為在屏幕上。我們?cè)谏洗尾季值腁ppTransitionController.handleAppTransitionReady階段將當(dāng)前窗口的mVisible置為了true,因此w.isOnScreen返回true。
3.mLastAlpha != mShownAlpha以及mLastHidden滿足其一即可,此處我們分析mLastHidden,該標(biāo)志位在創(chuàng)建SurfaceControl或者h(yuǎn)ide surface時(shí)會(huì)被置為true,因?yàn)楫?dāng)前窗口才剛剛被創(chuàng)建,因此mLastHidden為true。
經(jīng)過以上判斷可以得出我們順利觸發(fā)showSurfaceRobustlyLocked
后面通過WindowStateAnimator將show SurfaceControl的請(qǐng)求傳遞給了WindowSurfaceController
/**
* Have the surface flinger show a surface, robustly dealing with
* error conditions. In particular, if there is not enough memory
* to show the surface, then we will try to get rid of other surfaces
* in order to succeed.
*
* @return Returns true if the surface was successfully shown.
*/
private boolean showSurfaceRobustlyLocked(SurfaceControl.Transaction t) {
//WindowStateAnimator將show SurfaceControl的請(qǐng)求傳遞給了WindowSurfaceController
//調(diào)用WindowSurfaceController的showRobustly方法
boolean shown = mSurfaceController.showRobustly(t);
//如果沒有成功返回false
if (!shown)
return false;
t.merge(mPostDrawTransaction);
return true;
}
在WindowSurfaceController中,首先判斷標(biāo)志位mSurfaceShown,若為true則直接返回;若為false,則將mSurfaceShown置為true,并調(diào)用SurfaceControl.show。至此真正的繪圖已經(jīng)顯示出來,但是否真正的被用戶看見,還需要看其parent是否被show。
代碼路徑:framework/services/core/java/com/android/server/wm/WindowSurfaceController.java
boolean showRobustly(SurfaceControl.Transaction t) {
......
//首先判斷surface是否已經(jīng)shown
if (mSurfaceShown) {
return true;
}
//將mSurfaceShown設(shè)置為true
setShown(true);
//調(diào)用SurfceControl中的show方法,將surface show出來
t.show(mSurfaceControl);
if (mAnimator.mIsWallpaper) {
EventLog.writeEvent(EventLogTags.WM_WALLPAPER_SURFACE,
mAnimator.mWin.getDisplayId(), 1 /* request shown */);
}
return true;
}
從SurfaceControl的創(chuàng)建以及show的流程上看,可以發(fā)現(xiàn)WMS是通過WindowSurfaceController對(duì)SurfaceControl進(jìn)行管理的。
最后我們看一下SurfaceControl中的show方法
代碼路徑:frameworks/base/core/java/android/view/SurfaceControl.java
/**
* Request that a given surface and it's sub-tree be shown.
*
* @param sc The surface to show.
* @return This transaction.
* @hide
*/
@UnsupportedAppUsage
public Transaction show(SurfaceControl sc) {
checkPreconditions(sc);
nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SURFACE_HIDDEN);
return this;
}
2.4 performSurfacePlacement()流程總結(jié)

在“【2.2 窗口位置計(jì)算】”以及“【2.3 窗口狀態(tài)刷新】”部分均調(diào)用了WindowSurfacePlacer.performSurfacePlacement(),實(shí)際上任何窗口屬性變化都會(huì)觸發(fā)該方法,但我們?cè)趐erformSurfacePlacement中只關(guān)注了窗口位置大小計(jì)算以及窗口狀態(tài)變更的相關(guān)流程。此處再對(duì)該流程進(jìn)行簡(jiǎn)單的梳理。
當(dāng)調(diào)用到WindowSurfacePlacer.performSurfacePlacement()時(shí)首先會(huì)執(zhí)行“1”更新所有窗口的大小以及狀態(tài)信息,在執(zhí)行“2”處理是否在此調(diào)用執(zhí)行performSurfacePlacement。
1.1.1:主要調(diào)用computeFrames,計(jì)算窗口的尺寸大小。
1.1.2:主要處理mDrawState的狀態(tài)變更,在commitFinishDrawingLocked中會(huì)將處于DRAW_PENDING狀態(tài)的mDrawState更新為COMMIT_DRAW_PENDING。
1.1.3:主要根據(jù)computerFrames中計(jì)算出來的窗口大小來設(shè)置Surface的位置,并調(diào)用SurfaceControl.show()將窗口show出來。
1.2:將處于COMMIT_DRAW_PENDING狀態(tài)的mDrawState更新為READY_TO_SHOW,并將DisplayContent.mLayoutNeeded設(shè)置為true。在“2”中會(huì)判斷該標(biāo)志位來處理是否再次調(diào)用performSurfacePlacement的操作。
————————————————
版權(quán)聲明:本文為CSDN博主「yi諾千金」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/yimelancholy/article/details/130339779