接着上篇://www.greatytc.com/p/95e8654036a8
2.3 窗口状态刷新
当应用端执行measure-layout-draw之后,便会调用WMS.finishDrawingWindow,处理Surface的状态变更并将Surface show出来。
首先还是看一下该阶段的流程图,对整个流程有个初步的了解。
将整个流程分为三部分:
1.WMS接受客户端请求,将mDrawState更新为COMMIT_DRAW_PENDING,并请求窗口布局。
2.mDrawState更新为HAS_DRAW,再次请求窗口布局。
3.执行show Surface。
2.3.1 接受客户端请求
代码路径: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);
//调用WMS中的finishDrawingWindow处理
mService.finishDrawingWindow(this, window, postDrawTransaction, seqId);
}
2.3.2 finishDrawingWindow
1.在WMS中根据客户端的Binder在mWindowMap中获取对应的WindowState。
2.调用WindowState.finishDrawing执行mDrawState的状态变更。
3.将WindowState.mLayoutNeeded标志位置为true。
4.请求进行布局刷新。
代码路径: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.根据客户端的Binder在mWindowMap中获取对应的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执行mDrawState的状态更变*/
if (win != null && win.finishDrawing(postDrawTransaction, seqId)) {
if (win.hasWallpaper()) {
win.getDisplayContent().pendingLayoutChanges |=
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
}
/*3.将当前WindowState.mLayoutNeeded置为true*/
//该标志位是判断是否进行窗口大小尺寸计算的条件之一
win.setDisplayLayoutNeeded();
/*4.请求进行布局刷新*/
mWindowPlacerLocked.requestTraversal();
}
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
1.mDrawState的状态更变
在finishDrawingWindow中调用WindowState的finishDrawing方法
win.finishDrawing(postDrawTransaction, seqId)
这个方法主要调用了WindowStateAnimator的finishDrawingLocked进行状态更变
代码路径:framework/services/core/java/com/android/server/wm/WindowState.java
boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction, int syncSeqId) {
......
//调用WindowStateAnimator.finishDrawingLocked,会将mDrawState的状态更改为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);
}
我们继续看看WindowStateAnimator中的finishDrawingLocked()方法
首先判断mDrawState的状态是否为DRAW_PENDING,在我们创建SurfaceControl时,会将mDrawState状态更新为DRAW_PENDING。因此接下来将状态调整为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) {
......
//如果当前状态为DRAW_PENDING,则将mDrawState更变为COMMIT_DRAW_PENDING
mDrawState = COMMIT_DRAW_PENDING;
layoutNeeded = true;
}
......
return layoutNeeded;
}
2.请求布局刷新
在finishDrawingWindow中请求布局刷新
mWindowPlacerLocked.requestTraversal();
requestTraversal中主要做了两件事:
1.首先将遍历标志为mTraversalSchedule置为true。
2.其次发送handle消息mPerformSurfacePlacement
void requestTraversal() {
//判断遍历标志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.
//将遍历标志位置为true
mTraversalScheduled = true;
if (mDeferDepth > 0) {
mDeferredRequests++;
if (DEBUG) Slog.i(TAG, "Defer requestTraversal " + Debug.getCallers(3));
return;
}
//发送handle消息,处理消息会调用mPerformSurfacePlacement
mService.mAnimationHandler.post(mPerformSurfacePlacement);
}
mPerformSurfacePlacement会新建一个线程调用performSurfacePlacement。
performSurfacePlacement方法我们在讲relayoutWindow相关流程的时候讲过,这是执行遍历布局的入口。可以回看下【2.2.4 计算窗口大小位置中的“1.处理窗口布局循环”】
private class Traverser implements Runnable {
@Override
public void run() {
synchronized (mService.mGlobalLock) {
//调用执行performSurfacePlacement
performSurfacePlacement();
}
}
}
private final Traverser mPerformSurfacePlacement = new Traverser();
final void performSurfacePlacement(boolean force) {
//当mDeferDepth大于0且force为false时,则将延迟布局请求数+1,并直接返回
if (mDeferDepth > 0 && !force) {
mDeferredRequests++;
return;
}
//将循环的最大次数设置为6次
int loopCount = 6;
do {
//将该标志为设置为false
mTraversalScheduled = false;
//执行窗口布局操作
performSurfacePlacementLoop();
mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
loopCount--;
//只有当mTraversalScheduled为true且循环次数大于0时,才会再次循环执行布局
} while (mTraversalScheduled && loopCount > 0);
mService.mRoot.mWallpaperActionPending = false;
}
private void performSurfacePlacementLoop() {
//若当前已经进行布局操作,则无需重复调用直接返回
if (mInLayout) {
......
return;
}
......
//将该标志位置为true,表示正在处于布局过程中
mInLayout = true;
......
try {
/*1.调用RootWindowContainer的performSurfacePlacement()方法对所有窗口执行布局操作*/
mService.mRoot.performSurfacePlacement();
mInLayout = false;
if (mService.mRoot.isLayoutNeeded()) {
/*2.若需要布局,且布局次数小于6次,则需要再次请求布局*/
if (++mLayoutRepeatCount < 6) {
//该方法中会将mTraversalScheduled标志位设置位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 {
//调用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.如果有焦点变化,更新焦点*/
if (mWmService.mFocusMayChange) {
mWmService.mFocusMayChange = false;
mWmService.updateFocusedWindowLocked(
UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
}
......
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
//开启事务,获取GlobalTransactionWrapper对象
mWmService.openSurfaceTransaction();
try {
/*2.执行窗口尺寸计算,surface状态变更等操作*/
applySurfaceChangesTransaction();
} catch (RuntimeException e) {
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
} finally {
//关闭事务,把事务提交
mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (SHOW_LIGHT_TRANSACTIONS) {
Slog.i(TAG,
"<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
}
}
......
/*3.将Surface状态变更为HAS_DRAWN,触发App触发动画。该过程在“2.3.3mDrawState变更为HAS_DRAW”流程中再详细分析*/
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.在此处理焦点变化*/
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();
}
......
}
这里我们主要关注applySurfaceChangesTransaction();和checkAppTransitionReady(surfacePlacer);
- 窗口位置计算与窗口状态刷新流程不同点
可以发现,窗口位置计算流程与窗口状态刷新流程都调用了performSurfacePlacement,两次调用的主要不同点在于:
1.窗口状态刷新流程在DisplayContent.applySurfaceChangesTransaction中调用mApplySurfaceChangesTransaction,处理mDrawState状态。
2.窗口状态刷新流程在RootWindowContainer.performSurfacePlacementNoTrace中调用checkAppTransitionReady,处理mDrawState状态变更为HAS_DRAWN,触发Activity过渡动画。
3.窗口状态刷新流程在WindowSurfacePlacementLoop.performSurfacePlacementLoop中会调用requestTraversal,请求再次布局。
4.窗口状态刷新流程在DisplayContent.applySurfaceChangesTransaction中调用prepareSurfaces()处理处理surface的位置、大小以及显示等。
2.3.3 mDrawState变更为HAS_DRAW
1.mApplySurfaceChangesTransaction
RootWindowContainer的applySurfaceChangesTransaction()方法最终会调用到DisplayContent中调用的applySurfaceChangesTransaction()方法,我们接着该方法中的mApplySurfaceChangesTransaction跟踪。
forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
如果当前WindowState存在surfaceControl,则进入到WindowStateAnimator进行mDrawState的状态更变。
代码路径:framework/services/core/java/com/android/server/wm/DisplayContent.java
private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
......
//首先判断当前windowState的是否有surfaceControl
if (w.mHasSurface) {
// Take care of the window being ready to display.
//调用WindowStateAnimator的commitFinishDrawingLocked()方法
final boolean committed = winAnimator.commitFinishDrawingLocked();
......
}
......
};
继续看看WindowStateAnimator的commitFinishDrawingLocked()方法
final boolean committed = winAnimator.commitFinishDrawingLocked();
1.对mDrawState的状态进行过滤,非COMMIT_DRAW_PENDING和READY_TO_SHOW则直接返回。
2.此时我们的mDrawState已经在“【2.3.2 finishDrawingWindow】”将状态更新为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);
//将状态更变为READY_TO_SHOW
mDrawState = READY_TO_SHOW;
boolean result = false;
final ActivityRecord activity = mWin.mActivityRecord;
//如果ActivityRecord为空,或者canShowWindows()为true,或者窗口类型为启动窗口,则直接进入到WindowState.performShowLocked()流程
//进入performShowLocked()流程后mDrawState更新HAS_DRAWN
//由于非这三种情况最终也会调用到performShowLocked(),因此下面这种情况我们暂不讨论
if (activity == null || activity.canShowWindows()
|| mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
result = mWin.performShowLocked();
}
return result;
}
2.checkAppTransitionReady()
这里我们继续跟踪RootWindowContainer.performSurfacePlacementNoTrace()方法中的checkAppTransitionReady()方法
checkAppTransitionReady(surfacePlacer);
该方法会遍历所有DisplayContent,处理activity的过滤动画,此处我们只有跟踪有关mDrawState状态更变的相关代码
代码路径: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,是否已经准备就绪
if (curDisplay.mAppTransition.isReady()) {
// handleAppTransitionReady may modify curDisplay.pendingLayoutChanges.
curDisplay.mAppTransitionController.handleAppTransitionReady();
if (DEBUG_LAYOUT_REPEATS) {
surfacePlacer.debugLayoutRepeats("after handleAppTransitionReady",
curDisplay.pendingLayoutChanges);
}
}
......
}
}
调用AppTransitionController的handleAppTransitionReady()方法,该方法主要还是在处理activity的过渡动画,但是在应用过渡动画时,还做了以下事情
1.分别调用 handleClosingApps以及handleOpeningApps对要关闭的和要打开的Activity进行可见性更新。
2.由于activity的可见性变更,将DisplayContent.mLayoutNeeded设置为true,该标志位在DisplayContent.performLayoutNoTrace中用来判断是否对当前Displaycontent下的所有窗口进行刷新。
代码路径:framework/services/core/java/com/android/server/wm/AppTransitionController.java
/**
* Handle application transition for given display.
*/
void handleAppTransitionReady() {
......
try {
//应用app transition动画
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标志位置为true*/
mDisplayContent.setLayoutNeeded();
......
}
我们先看看 handleClosingApps()
该方法中主要的作用就是将所有即将close的activity的mVisible标志设置为false。该标志位在后续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);
//设置activity的可见性,将mVisible设置为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.
//强制将allDrawn设置为true
app.allDrawn = true;
......
}
}
再看看,与handleClosingApps类似,主要处理两件事情:
1.将所有即将open的activity的mVisible标志位设置为true.
2.调用ActivityRecord.showAllWindowsLocked(),最终会调用到WindowState.performShowLocked() ,处理mDrawState的状态变更
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.设置activity的可见性,将mVisible设置为true*/
app.commitVisibility(true /* visible */, false /* performLayout */);
......
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
">>> OPEN TRANSACTION handleAppTransitionReady()");
//开启事务
mService.openSurfaceTransaction();
try {
/*2.此方法最终会调用到WindowState.performShowLocked*/
app.showAllWindowsLocked();
} finally {
//关闭事务
mService.closeSurfaceTransaction("handleAppTransitionReady");
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
"<<< CLOSE TRANSACTION handleAppTransitionReady()");
}
......
}
}
app.commitVisibility(true /* visible /, false / performLayout */);
先调用到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();
再调用到WindowState的performShowLocked()
将mDrawState的状态由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 状态为HAS_DRAWN 或者READY_TO_SHOW)且ActivityRecord不为空
if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW) && mActivityRecord != null) {
//窗口类型不为启动窗口
if (mAttrs.type != TYPE_APPLICATION_STARTING) {
mActivityRecord.onFirstWindowDrawn(this);
} else {
mActivityRecord.onStartingWindowDrawn();
}
}
//如果当前mDrawState的状态不为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);
//设置mDrawState的状态为HAS_DRAWN
mWinAnimator.mDrawState = HAS_DRAWN;
mWmService.scheduleAnimationLocked();
......
return true;
}
3.再次请求布局
回到WindowSurfacePlacer中通过requestTraversals(),再次请求布局,该方法将mTraversalScheduled标志位设置为true的判断条件有两个:
1.遍历所有DisplayContent.mLayoutNeeded标志为是否为true。(由于AppTransitionController.handleAppTransitionReady阶段已经将mLayoutNeeded置为true,因此该条件为真)
2.重复布局的次数不能超过6次,该条件也为真。(因为当前还只是第一次布局)
代码路径:framework/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
private void performSurfacePlacementLoop() {
......
try {
......
/*1.遍历所有DisplayContent.mLayoutNeeded标志位是否为true*/
if (mService.mRoot.isLayoutNeeded()) {
/*2.如果需要布局,且布局次数小于6次,则需要再次请求布局*/
if (++mLayoutRepeatCount < 6) {
//该方法中会将mTraversalScheduled标志位设置位true
requestTraversal();
} else {
Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
mLayoutRepeatCount = 0;
}
} else {
mLayoutRepeatCount = 0;
}
......
} catch (RuntimeException e) {
......
}
}
接下来进入第二次布局循环,其主要目的是为了show surface
2.3.4 show Surface
在第二次循环中,我们主要关注DisplayContent中applySurfaceChangesTransaction()方法调用的prepareSurfaces()
该方法最终会调用到根容器WindowContainer,来遍历所有子容器中的prepareSurfaces。
代码路径:framework/services/core/java/com/android/server/wm/DisplayContent.java
@Override
void prepareSurfaces() {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "prepareSurfaces");
try {
//获取事务
final Transaction transaction = getPendingTransaction();
//调用其父类方法
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);
}
}
调用其父类方法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();
//调用所有子容器中的prepareSurfaces
for (int i = 0; i < mChildren.size(); i++) {
mChildren.get(i).prepareSurfaces();
}
}
mChildren.get(i).prepareSurfaces();在WindowState.prepareSurfaces中,主要做了两方面工作。
1.将mWindowFrames中计算出来的left以及top设置surface位置,并调整窗口比例。
2.控制surface的可见性,查看WindowStateAnimator.prepareSurfaceLocked
代码路径:framework/services/core/java/com/android/server/wm/WindowState.java
void prepareSurfaces() {
mIsDimming = false;
applyDims();
//实际调用的是其父类WindowContainer的方法
/*1.最终调用自身的updateSurfacePosition()(自身有重写该方法)计算surface的位置*/
updateSurfacePositionNonOrganized();
// Send information to SurfaceFlinger about the priority of the current window.
updateFrameRateSelectionPriorityIfNeeded();
//更新窗口比例
updateScaleIfNeeded();
/*2.控制surface的可见性,调用WindowStateAnimator的prepareSurfaceLocked()方法*/
mWinAnimator.prepareSurfaceLocked(getSyncTransaction());
super.prepareSurfaces();
}
@Override
@VisibleForTesting
void updateSurfacePosition(Transaction t) {
if (mSurfaceControl == null) {
return;
}
......
mSurfacePlacementNeeded = false;
//将mSurfacePosition的left以及top设置mWindowFrames中计算出来的left以及top,并根据parent进行偏移
transformFrameToSurfacePosition(mWindowFrames.mFrame.left, mWindowFrames.mFrame.top,
mSurfacePosition);
//根据壁纸的比例对SurfacePosition进行调整
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()); 调用WindowStateAnimator的prepareSurfaceLocked()方法,该则真正的处理触发surface show的逻辑。主要分为两部分。
1.将计算的alpha应用于当前surface。
2.判断是否调用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;
}
//设置mShowAlpha
computeShownFrameLocked();
//判断parentWindow是否hidden,或者当前窗口是否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.设置surface的alpha*/
boolean prepared =
mSurfaceController.prepareToShowInTransaction(t, mShownAlpha);
//如果当前状态为HAS_DRAWN
if (prepared && mDrawState == HAS_DRAWN) {
if (mLastHidden) {
/*2.触发show surface*/
if (showSurfaceRobustlyLocked(t)) {
mAnimator.requestRemovalOfReplacedWindows(w);
//设置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);
}
}
......
}
从上述代码中可以看出触发showSurfaceRobustlyLocked的判断条件有以下几点:
1.w.isParentWindowHidden判断其parent的mHidden是否为true,此时当前窗口没有parent直接返回false
2.w.isOnScreen,判断当前窗口是否在屏幕上,如果该窗口mVisible为true或者在不可见之前正在运行动画,判断为在屏幕上。我们在上次布局的AppTransitionController.handleAppTransitionReady阶段将当前窗口的mVisible置为了true,因此w.isOnScreen返回true。
3.mLastAlpha != mShownAlpha以及mLastHidden满足其一即可,此处我们分析mLastHidden,该标志位在创建SurfaceControl或者hide surface时会被置为true,因为当前窗口才刚刚被创建,因此mLastHidden为true。
经过以上判断可以得出我们顺利触发showSurfaceRobustlyLocked
后面通过WindowStateAnimator将show SurfaceControl的请求传递给了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的请求传递给了WindowSurfaceController
//调用WindowSurfaceController的showRobustly方法
boolean shown = mSurfaceController.showRobustly(t);
//如果没有成功返回false
if (!shown)
return false;
t.merge(mPostDrawTransaction);
return true;
}
在WindowSurfaceController中,首先判断标志位mSurfaceShown,若为true则直接返回;若为false,则将mSurfaceShown置为true,并调用SurfaceControl.show。至此真正的绘图已经显示出来,但是否真正的被用户看见,还需要看其parent是否被show。
代码路径:framework/services/core/java/com/android/server/wm/WindowSurfaceController.java
boolean showRobustly(SurfaceControl.Transaction t) {
......
//首先判断surface是否已经shown
if (mSurfaceShown) {
return true;
}
//将mSurfaceShown设置为true
setShown(true);
//调用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的创建以及show的流程上看,可以发现WMS是通过WindowSurfaceController对SurfaceControl进行管理的。
最后我们看一下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()流程总结
在“【2.2 窗口位置计算】”以及“【2.3 窗口状态刷新】”部分均调用了WindowSurfacePlacer.performSurfacePlacement(),实际上任何窗口属性变化都会触发该方法,但我们在performSurfacePlacement中只关注了窗口位置大小计算以及窗口状态变更的相关流程。此处再对该流程进行简单的梳理。
当调用到WindowSurfacePlacer.performSurfacePlacement()时首先会执行“1”更新所有窗口的大小以及状态信息,在执行“2”处理是否在此调用执行performSurfacePlacement。
1.1.1:主要调用computeFrames,计算窗口的尺寸大小。
1.1.2:主要处理mDrawState的状态变更,在commitFinishDrawingLocked中会将处于DRAW_PENDING状态的mDrawState更新为COMMIT_DRAW_PENDING。
1.1.3:主要根据computerFrames中计算出来的窗口大小来设置Surface的位置,并调用SurfaceControl.show()将窗口show出来。
1.2:将处于COMMIT_DRAW_PENDING状态的mDrawState更新为READY_TO_SHOW,并将DisplayContent.mLayoutNeeded设置为true。在“2”中会判断该标志位来处理是否再次调用performSurfacePlacement的操作。
————————————————
版权声明:本文为CSDN博主「yi诺千金」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yimelancholy/article/details/130339779