本文轉(zhuǎn)載自:Android R WindowManagerService模塊(3) Window的relayout過程
本文基于Android 11.0源碼分析
前言
??在Window的添加過程中,主要添加窗口時(shí)的WindowManagerService#addWindow()方法進(jìn)行了主要總結(jié)师枣,通過WindowManagerService#addWindow()方法起惕,system_server中創(chuàng)建了一個(gè)對(duì)應(yīng)的窗口管理對(duì)象,并且放置到了適合的容器中。這篇文章中將對(duì)之后窗口的relayout過程進(jìn)行總結(jié)挂捻。
1.requestLayout過程
??回到添加窗口流程中的ViewRootImpl#setView()方法中吃挑,在調(diào)用mWindowSession#addToDisplayAsUser()方法之前,先是調(diào)用了requestLayout()方法羊初,并最終通過Chreographer對(duì)象設(shè)置了一個(gè)VSync監(jiān)聽:
// frameworks/base/core/java/android/view/ViewRootImpl.java
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 設(shè)置一個(gè)同步屏障
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 設(shè)置VSync監(jiān)聽
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
當(dāng)收到VSync信號(hào)后滨溉,mTraversalRunnable線程的run方法:
//frameworks/base/core/java/android/view/ViewRootImpl.java
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
執(zhí)行doTraversal()方法進(jìn)行遍歷操作:
//frameworks/base/core/java/android/view/ViewRootImpl.java
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
在performTraversals方法中執(zhí)行relayoutWindow()方法,通過IWindowSession接口實(shí)例向WMS發(fā)起布局請(qǐng)求:
//frameworks/base/core/java/android/view/ViewRootImpl.java
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
(int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
mTmpFrame, mTmpRect, mTmpRect, mTmpRect, mPendingBackDropFrame,
mPendingDisplayCutout, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
mTempControls, mSurfaceSize, mBlastSurfaceControl);
......
return relayoutResult;
}
這里Session.java的relayout()方法,之后將進(jìn)入WMS#relayoutWindow()方法中晦攒,在這個(gè)方法中進(jìn)行布局工作。下面詳細(xì)來看這個(gè)方法脯颜。
//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
/**
* @param session IWindowSession對(duì)象,用于ViewRootImpl向WMS發(fā)起交互
* @param client IWindow對(duì)象伐脖,代表客戶端的Window热幔,用于WMS向ViewRootImpl發(fā)起交互
* @param seq 請(qǐng)求序列
* @param attrs 窗口各種參數(shù)和屬性
* @param requestedWidth 客戶端請(qǐng)求窗口的寬
* @param requestedHeight 客戶端請(qǐng)求窗口的高
* @param viewVisibility View的可見性
* @param flags 標(biāo)記
* @param frameNumber
* @param outFrame 返回給ViewRootImpl的窗口框架
* @param outContentInsets
* @param outVisibleInsets
* @param outStableInsets
* @param outBackdropFrame
* @param outCutout
* @param mergedConfiguration
* @param outSurfaceControl 返回給ViewRootImpl的Surface管理對(duì)象
* @param outInsetsState
* @param outActiveControls
* @param outSurfaceSize
* @param outBLASTSurfaceControl
* @return
*/
public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewVisibility, int flags,
long frameNumber, Rect outFrame, Rect outContentInsets,
Rect outVisibleInsets, Rect outStableInsets, Rect outBackdropFrame,
DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
SurfaceControl outBLASTSurfaceControl) {
......
boolean configChanged;
synchronized (mGlobalLock) {
// 獲取WindowState、DisplayContent讼庇、DisplayPolicy绎巨、WindowStateAnimator對(duì)象
final WindowState win = windowForClientLocked(session, client, false);
final DisplayContent displayContent = win.getDisplayContent();
final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
WindowStateAnimator winAnimator = win.mWinAnimator;
// 給WindowState設(shè)置來自應(yīng)用請(qǐng)求的窗口大小
if (viewVisibility != View.GONE) {
win.setRequestedSize(requestedWidth, requestedHeight);
}
// 設(shè)置Frame number
win.setFrameNumber(frameNumber);
final DisplayContent dc = win.getDisplayContent();
// 如果此時(shí)沒有執(zhí)行Configuration的更新,試圖結(jié)束銜接動(dòng)畫
if (!dc.mWaitingForConfig) {
win.finishSeamlessRotation(false /* timeout */);
}
// 用來標(biāo)記屬性是否發(fā)生變化
int attrChanges = 0;
int flagChanges = 0;
int privateFlagChanges = 0;
int privflagChanges = 0;
if (attrs != null) {
// 調(diào)整特殊類型的Window#attrs屬性
displayPolicy.adjustWindowParamsLw(win, attrs, pid, uid);
// 針對(duì)壁紙窗口調(diào)整Window#attrs屬性
win.mToken.adjustWindowParams(win, attrs);
// 調(diào)整mSystemUiVisibility屬性蠕啄,控制status bar的顯示
if (seq == win.mSeq) {
int systemUiVisibility = attrs.systemUiVisibility
| attrs.subtreeSystemUiVisibility;
......
}
win.mSystemUiVisibility = systemUiVisibility;
}
// PRIVATE_FLAG_PRESERVE_GEOMETRY將忽略新x场勤、y、width歼跟、height值和媳,使用舊值
if ((attrs.privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY)
!= 0) {
attrs.x = win.mAttrs.x;
attrs.y = win.mAttrs.y;
attrs.width = win.mAttrs.width;
attrs.height = win.mAttrs.height;
}
// 確定flag是否發(fā)生變化
flagChanges = win.mAttrs.flags ^ attrs.flags;
privateFlagChanges = win.mAttrs.privateFlags ^ attrs.privateFlags;
attrChanges = win.mAttrs.copyFrom(attrs);
// 根據(jù)flag是否發(fā)生變化做出對(duì)應(yīng)響應(yīng),略....
.......
}
// 根據(jù)應(yīng)用請(qǐng)求設(shè)置寬高哈街,獲取窗口縮放比例
win.setWindowScale(win.mRequestedWidth, win.mRequestedHeight);
// 窗口此時(shí)的可見狀態(tài)
final int oldVisibility = win.mViewVisibility;
// 窗口是否要由不可見狀態(tài)轉(zhuǎn)變?yōu)榭梢姞顟B(tài)
final boolean becameVisible =
(oldVisibility == View.INVISIBLE || oldVisibility == View.GONE)
&& viewVisibility == View.VISIBLE;
// 是否需要移除IME窗口
boolean imMayMove = (flagChanges & (FLAG_ALT_FOCUSABLE_IM | FLAG_NOT_FOCUSABLE)) != 0
|| becameVisible;
// 確定是否需要更新focus狀態(tài)留瞳,第一次執(zhí)行relayout時(shí),mRelayoutCalled為false
boolean focusMayChange = win.mViewVisibility != viewVisibility
|| ((flagChanges & FLAG_NOT_FOCUSABLE) != 0)
|| (!win.mRelayoutCalled);
// 如果窗口可見性發(fā)生變化骚秦,且該窗口允許顯示在壁紙之上她倘,則對(duì)壁紙窗口進(jìn)行處理
boolean wallpaperMayMove = win.mViewVisibility != viewVisibility
&& (win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
wallpaperMayMove |= (flagChanges & FLAG_SHOW_WALLPAPER) != 0;
win.mRelayoutCalled = true; // 設(shè)置WindowState#mRelayoutCalled為true
win.mInRelayout = true; // 設(shè)置WindowState#mInRelayout為true,表示在relayout過程中作箍,relayout完畢后硬梁,重置為false
// 更新窗口的可見性
win.setViewVisibility(viewVisibility);
// 通知DisplayContent,需要進(jìn)行重新布局
win.setDisplayLayoutNeeded();
// 表示是否在等待設(shè)置Inset
win.mGivenInsetsPending = (flags & WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
// 如果窗口可見胞得,進(jìn)行重新布局
final boolean shouldRelayout = viewVisibility == View.VISIBLE &&
(win.mActivityRecord == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
|| win.mActivityRecord.isClientVisible());
// 執(zhí)行一遍刷新操作
mWindowPlacerLocked.performSurfacePlacement(true /* force */);
// 是否需要進(jìn)行relayout操作
if (shouldRelayout) {
// 布局
result = win.relayoutVisibleWindow(result, attrChanges);
try {
// 創(chuàng)建Surface
result = createSurfaceControl(outSurfaceControl, outBLASTSurfaceControl,
result, win, winAnimator);
} catch (Exception e) {
return 0;
}
// 如果是第一次relayout操作荧止,需要focusMayChange
if ((result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
focusMayChange = true;
}
// 輸入法窗口的特殊處理
if (win.mAttrs.type == TYPE_INPUT_METHOD
&& displayContent.mInputMethodWindow == null) {
displayContent.setInputMethodWindowLocked(win);
imMayMove = true;
}
} else {
......
}
// 更新FocusWindow
if (focusMayChange) {
if (updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/)) {
imMayMove = false;
}
}
// 是否首次更新
boolean toBeDisplayed = (result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0;
// 更新屏幕顯示方向
configChanged = displayContent.updateOrientation();
// 對(duì)壁紙窗口的特殊處理,更新偏移量
if (toBeDisplayed && win.mIsWallpaper) {
displayContent.mWallpaperController.updateWallpaperOffset(win, false /* sync */);
}
if (win.mActivityRecord != null) {
win.mActivityRecord.updateReportedVisibilityLocked();
}
......
// 更新mergedConfiguration對(duì)象
if (shouldRelayout) {
win.getMergedConfiguration(mergedConfiguration);
} else {
win.getLastReportedMergedConfiguration(mergedConfiguration);
}
// 設(shè)置各種Inset和DisplayCutout
win.getCompatFrame(outFrame);
win.getInsetsForRelayout(outContentInsets, outVisibleInsets,
outStableInsets);
outCutout.set(win.getWmDisplayCutout().getDisplayCutout());
outBackdropFrame.set(win.getBackdropFrame(win.getFrameLw()));
outInsetsState.set(win.getInsetsState(), win.isClientLocal());
// 更新relayout標(biāo)記,表示可接受touch事件
result |= mInTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0;
win.mInRelayout = false; // 重置為false牧愁,表示relayout過程完成
// configuration發(fā)生變化時(shí)递宅,更新全局Configuration
if (configChanged) {
displayContent.sendNewConfiguration();
}
// 設(shè)置outSurfaceSize
if (winAnimator.mSurfaceController != null) {
outSurfaceSize.set(winAnimator.mSurfaceController.getWidth(),
winAnimator.mSurfaceController.getHeight());
}
getInsetsSourceControls(win, outActiveControls);
}
return result;
}
在進(jìn)入這個(gè)方法后,首先通過IWindow對(duì)象獲取了對(duì)應(yīng)的WindowState對(duì)象淋昭,之后將以WindowState為主體進(jìn)行各種操作翔忽。這個(gè)方法很長盏檐,但主要有以下幾個(gè)步驟:
WindowState#setRequestedSize()設(shè)置WindowState寬高胡野;
DisplayPolicy#adjustWindowParamsLw()調(diào)整窗口屬性硫豆;
WindowState#setWindowScale()設(shè)置縮放比例熊响;
WindowState#setViewVisibility()更新可見性屬性;
WindowState#relayoutVisibleWindow()處理FLAG_TURN_SCREEN_ON標(biāo)記秸弛;
WMS#createSurfaceControl()創(chuàng)建Surface递览;
WMS#updateFocusedWindowLocked()更新焦點(diǎn)窗口;
設(shè)置MergedConfiguration對(duì)象返回客戶端纯趋;
設(shè)置windowFrame和Inset返回客戶端吵冒。
2.relayoutWindow逐步分析
??上一小節(jié)分析requestLayout()過程中痹栖,最終會(huì)調(diào)用到WMS的relayoutWindow()方法揪阿,該方法中有很多的處理過程,下面對(duì)這些步驟進(jìn)行分析總結(jié)吴裤。
2.1 WindowState#setRequestedSize()設(shè)置WindowState寬高
??通過WindowState#setRequestedSize()方法麦牺,設(shè)置WindowState對(duì)象mRequestedWidth和mRequestedHeight屬性剖膳,這兩屬性表示來自應(yīng)用請(qǐng)求設(shè)置的寬高:
//frameworks/base/services/core/java/com/android/server/wm/WindowState.java
void setRequestedSize(int requestedWidth, int requestedHeight) {
if ((mRequestedWidth != requestedWidth || mRequestedHeight != requestedHeight)) {
mLayoutNeeded = true;
mRequestedWidth = requestedWidth;
mRequestedHeight = requestedHeight;
}
}
2.2 DisplayPolicy#adjustWindowParamsLw()調(diào)整窗口屬性
??接下來吱晒,會(huì)根據(jù)系統(tǒng)當(dāng)前條件枕荞,對(duì)客戶端傳入的布局參數(shù)進(jìn)行調(diào)整躏精,主要通過DisplayPolicy#adjustWindowParamsLw(win, attrs, pid, uid)調(diào)整矗烛,對(duì)于壁紙這類特殊窗口瞭吃,會(huì)通過WallpaperWindowToken#adjustWindowParams()方法進(jìn)行調(diào)整歪架。如果調(diào)整后的布局參數(shù)發(fā)生了變化霹陡,則進(jìn)行相關(guān)狀態(tài)的處理烹棉。這部分代碼略過浆洗。
2.3 WindowState#setWindowScale()設(shè)置縮放比例
??通過WindowState#setWindowScale()方法伏社,設(shè)置WindowState對(duì)象mHScale和mVScale屬性,這兩屬性表示窗口在橫豎方向的縮放比例:
//frameworks/base/services/core/java/com/android/server/wm/WindowState.java
void setWindowScale(int requestedWidth, int requestedHeight) {
final boolean scaledWindow = (mAttrs.flags & FLAG_SCALED) != 0;
if (scaledWindow) {
mHScale = (mAttrs.width != requestedWidth) ?
(mAttrs.width / (fl性oat)requestedWidth) : 1.0f;
mVScale = (mAttrs.height != requestedHeight) ?
(mAttrs.height / (float)requestedHeight) : 1.0f;
} else {
mHScale = mVScale = 1;
}
}
可以看到凯沪,只有對(duì)在布局參數(shù)中設(shè)置了FLAG_SCALED標(biāo)記的窗口妨马,才會(huì)計(jì)算縮放比例杀赢,否則都是1脂崔。
2.4 WindowState#setViewVisibility()更新可見性
??通過WindowState#setViewVisibility()方法砌左,設(shè)置WindowState對(duì)象mViewVisibility屬性,該屬性表示該Window的可見性:
// frameworks/base/services/core/java/com/android/server/wm/WindowState.java
void setViewVisibility(int viewVisibility) {
mViewVisibility = viewVisibility;
......
}
mViewVisibility有三個(gè)值屁擅,均來自于APP端的View:
View.VISIBLE:表示該窗口可見派歌;
View.INVISIBLE:表示該窗口不可見胶果,但仍然占據(jù)空間早抠,其Surface依然存在蕊连;
View.GONE:表示該窗口不可見咪奖,并且不再占據(jù)空間酱床,其Surface也被銷毀扇谣。
2.5 WindowState#relayoutVisibleWindow()處理FLAG_TURN_SCREEN_ON
//frameworks/base/services/core/java/com/android/server/wm/WindowState.java
int relayoutVisibleWindow(int result, int attrChanges) {
// 是否可見
final boolean wasVisible = isVisibleLw();
// 如果不可見罐寨,表示第一次進(jìn)行relayout
result |= (!wasVisible || !isDrawnLw()) ? RELAYOUT_RES_FIRST_TIME : 0;
// 是否執(zhí)行退出動(dòng)畫
if (mAnimatingExit) {
....
}
// 是否在銷毀Surface列表中鸯绿,等待被Destory
if (mDestroying) {
mDestroying = false;
mWmService.mDestroySurface.remove(this);
}
if (!wasVisible) {
// 表示即將執(zhí)行進(jìn)入動(dòng)畫
mWinAnimator.mEnterAnimationPending = true;
}
// 最近一次可見時(shí)的屏幕方向
mLastVisibleLayoutRotation = getDisplayContent().getRotation();
// 表示開始執(zhí)行進(jìn)入動(dòng)畫
mWinAnimator.mEnteringAnimation = true;
try {
prepareWindowToDisplayDuringRelayout(wasVisible);
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
// 當(dāng)布局參數(shù)中像素格式發(fā)生變化后的處理
if ((attrChanges & FORMAT_CHANGED) != 0) {
.....
}
// 當(dāng)拖拽發(fā)生resize時(shí)
if (isDragResizeChanged()) {
......
}
......
return result;
}
在這個(gè)方法中毒返,調(diào)用prepareWindowToDisplayDuringRelayout()方法拧簸,針對(duì)亮屏flag進(jìn)行處理:
//frameworks/base/services/core/java/com/android/server/wm/WindowState.java
void prepareWindowToDisplayDuringRelayout(boolean wasVisible) {
// 是否帶有點(diǎn)亮屏幕的標(biāo)記
final boolean hasTurnScreenOnFlag = (mAttrs.flags & FLAG_TURN_SCREEN_ON) != 0
|| (mActivityRecord != null && mActivityRecord.canTurnScreenOn());
if (hasTurnScreenOnFlag) {
......
if (allowTheaterMode && canTurnScreenOn
&& (mWmService.mAtmInternal.isDreaming()
|| !mPowerManagerWrapper.isInteractive())) {
// 觸發(fā)亮屏
mPowerManagerWrapper.wakeUp(SystemClock.uptimeMillis(),
PowerManager.WAKE_REASON_APPLICATION, "android.server.wm:SCREEN_ON_FLAG");
}
if (mActivityRecord != null) {
mActivityRecord.setCurrentLaunchCanTurnScreenOn(false);
}
}
if (wasVisible) {
return;
}
......
}
以上方法中盆赤,如果布局參數(shù)或?qū)?yīng)的ActivityRecord中攜帶有亮屏相關(guān)flag牺六,則進(jìn)行亮屏兔乞。窗口中通過FLAG_TURN_SCREEN_ON進(jìn)行亮屏庸追,就是在這里觸發(fā)的淡溯。
2.6 WMS#createSurfaceControl()創(chuàng)建Surface
??在客戶端ViewRootImpl中咱娶,有一個(gè)Surface對(duì)象膘侮,它是這個(gè)ViewRootImpl中View顯示內(nèi)容的最終呈現(xiàn)者琼了。但它在創(chuàng)建時(shí)雕薪,僅僅是一個(gè)空殼敬尺,沒有任何內(nèi)容镜会。在relayout()時(shí)惑惶,ViewRootImpl將SurfaceControl對(duì)象傳遞給了WMS修赞,WMS中會(huì)創(chuàng)建一個(gè)SurfaceControl對(duì)象,并將它復(fù)制給傳入的SurfaceControl鱼填,最終ViewRootImpl從SurfaceControl中獲取內(nèi)容:
//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
private int createSurfaceControl(SurfaceControl outSurfaceControl,
SurfaceControl outBLASTSurfaceControl, int result,
WindowState win, WindowStateAnimator winAnimator) {
// 此時(shí)該WindowState還沒有對(duì)應(yīng)Surface
if (!win.mHasSurface) {
result |= RELAYOUT_RES_SURFACE_CHANGED;
}
WindowSurfaceController surfaceController;
try {
// 創(chuàng)建一個(gè)WindowSurfaceController對(duì)象
surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);
} finally {
}
if (surfaceController != null) {
// 將WindowSurfaceController中的mSurfaceControl復(fù)制給outSurfaceControl
surfaceController.getSurfaceControl(outSurfaceControl);
surfaceController.getBLASTSurfaceControl(outBLASTSurfaceControl);
}
return result;
}
以上方法中:
首先給result變量設(shè)置RELAYOUT_RES_SURFACE_CHANGED標(biāo)記愤惰,表示relayout過程的第二個(gè)階段宦言;
然后通過WindowStateAnimator#createSurfaceLocked()創(chuàng)建了WindowSurfaceController對(duì)象奠旺;
最后通過WindowSurfaceController將內(nèi)部SurfaceControl拷貝給了outSurfaceControl响疚,outSurfaceControl將返回給客戶端的ViewRootImpl忿晕。
??WindowStateAnimator對(duì)象的作用是執(zhí)行和管理WindowState動(dòng)畫和Surface操作践盼,而WindowSurfaceController就是為WindowStateAnimator對(duì)象管理SurfaceControl對(duì)象咕幻。
??創(chuàng)建WindowSurfaceController對(duì)象如下:
//frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java
WindowSurfaceController createSurfaceLocked(int windowType, int ownerUid) {
final WindowState w = mWin;
// 如果已經(jīng)存在肄程,直接返回
if (mSurfaceController != null) {
return mSurfaceController;
}
// 設(shè)置WindowState#mHasSurface屬性為false绷耍,表示沒有Surface
w.setHasSurface(false);
// 重置繪制狀態(tài)
resetDrawState();
//
int flags = SurfaceControl.HIDDEN;
final WindowManager.LayoutParams attrs = w.mAttrs;
// 計(jì)算Surface區(qū)域大小褂始,relayout時(shí)崎苗,由于沒有填充Frame胆数,因此獲取區(qū)域?yàn)?
calculateSurfaceBounds(w, attrs, mTmpSize);
try {
......
// 創(chuàng)建WindowSurfaceController對(duì)象
mSurfaceController = new WindowSurfaceController(attrs.getTitle().toString(), width,
height, format, flags, this, windowType, ownerUid);
mSurfaceFormat = format;
// 設(shè)置WindowState#mHasSurface屬性為false必尼,表示沒有Surface
w.setHasSurface(true);
} catch (OutOfResourcesException e) {
}
mLastHidden = true;
return mSurfaceController;
}
在創(chuàng)建WindowSurfaceController對(duì)象時(shí)判莉,將會(huì)創(chuàng)建對(duì)應(yīng)的SurfaceControl對(duì)象:
//frameworks/base/services/core/java/com/android/server/wm/WindowSurfaceController.java
WindowSurfaceController(String name, int w, int h, int format,
int flags, WindowStateAnimator animator, int windowType, int ownerUid) {
mAnimator = animator; // WindowStateAnimator對(duì)象
mSurfaceW = w; // Surface的寬券盅,創(chuàng)建時(shí)為1, 在setBufferSizeInTransaction()中會(huì)設(shè)置具體值
mSurfaceH = h; // Surface的高锰镀,創(chuàng)建時(shí)為1
title = name; // 窗口名
mService = animator.mService; // WMS對(duì)象
final WindowState win = animator.mWin; // WindowState對(duì)象
mWindowType = windowType; // Window類型
mWindowSession = win.mSession; // IWindowSession對(duì)象
mTmpTransaction = mService.mTransactionFactory.get();
// 創(chuàng)建SurfaceControl
final SurfaceControl.Builder b = win.makeSurface()
.setParent(win.getSurfaceControl())
.setName(name)
.setBufferSize(w, h)
.setFormat(format)
.setFlags(flags)
.setMetadata(METADATA_WINDOW_TYPE, windowType)
.setMetadata(METADATA_OWNER_UID, ownerUid)
.setCallsite("WindowSurfaceController");
mSurfaceControl = b.build();
}
創(chuàng)建完成WindowSurfaceController對(duì)象后泳炉, 通過WindowState#setHasSurface()將WindowState#mHasSurface屬性設(shè)置為true胡桃,表示該WindowState已經(jīng)擁有了Surface翠胰。
2.7 WMS#updateFocusedWindowLocked()更新焦點(diǎn)窗口
??接下來之景,會(huì)通過WMS#updateFocusedWindowLocked()方法锻狗,進(jìn)行焦點(diǎn)窗口的更新轻纪。
//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
boolean changed = mRoot.updateFocusedWindowLocked(mode, updateInputWindows);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
return changed;
}
這里就是直接調(diào)用RootWindowContainer#updateFocusedWindowLocked():
//frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
mTopFocusedAppByProcess.clear();
boolean changed = false;
int topFocusedDisplayId = INVALID_DISPLAY;
for (int i = mChildren.size() - 1; i >= 0; --i) {
final DisplayContent dc = mChildren.get(i);
changed |= dc.updateFocusedWindowLocked(mode, updateInputWindows, topFocusedDisplayId);
final WindowState newFocus = dc.mCurrentFocus;
if (newFocus != null) {
final int pidOfNewFocus = newFocus.mSession.mPid;
if (mTopFocusedAppByProcess.get(pidOfNewFocus) == null) {
mTopFocusedAppByProcess.put(pidOfNewFocus, newFocus.mActivityRecord);
}
if (topFocusedDisplayId == INVALID_DISPLAY) {
topFocusedDisplayId = dc.getDisplayId();
}
} else if (topFocusedDisplayId == INVALID_DISPLAY && dc.mFocusedApp != null) {
// The top-most display that has a focused app should still be the top focused
// display even when the app window is not ready yet (process not attached or
// window not added yet).
topFocusedDisplayId = dc.getDisplayId();
}
}
if (topFocusedDisplayId == INVALID_DISPLAY) {
topFocusedDisplayId = DEFAULT_DISPLAY;
}
if (mTopFocusedDisplayId != topFocusedDisplayId) {
mTopFocusedDisplayId = topFocusedDisplayId;
mWmService.mInputManager.setFocusedDisplay(topFocusedDisplayId);
mWmService.mPolicy.setTopFocusedDisplay(topFocusedDisplayId);
ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "New topFocusedDisplayId=%d",
topFocusedDisplayId);
}
return changed;
}
updateFocusedWindowLocked()獲取輪詢RootWindowContainer容器中的對(duì)象潦嘶,然后通過對(duì)象的DisplayContent去更新焦點(diǎn)窗口掂僵。
//frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows,
int topFocusedDisplayId) {
// 查找當(dāng)前焦點(diǎn)窗口
WindowState newFocus = findFocusedWindowIfNeeded(topFocusedDisplayId);
// 判斷查找的結(jié)果和當(dāng)前的焦點(diǎn)窗口是否一樣
if (mCurrentFocus == newFocus) {
return false;
}
boolean imWindowChanged = false;
// 輸入法窗口
final WindowState imWindow = mInputMethodWindow;
if (imWindow != null) {
final WindowState prevTarget = mInputMethodTarget;
final WindowState newTarget = computeImeTarget(true /* updateImeTarget*/);
imWindowChanged = prevTarget != newTarget;
if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS
&& mode != UPDATE_FOCUS_WILL_PLACE_SURFACES) {
assignWindowLayers(false /* setLayoutNeeded */);
}
}
if (imWindowChanged) {
mWmService.mWindowsChanged = true;
setLayoutNeeded();
newFocus = findFocusedWindowIfNeeded(topFocusedDisplayId);
}
// 焦點(diǎn)窗口變化處理
if (mCurrentFocus != newFocus) {
mWmService.mH.obtainMessage(REPORT_FOCUS_CHANGE, this).sendToTarget();
}
ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Changing focus from %s to %s displayId=%d Callers=%s",
mCurrentFocus, newFocus, getDisplayId(), Debug.getCallers(4));
final WindowState oldFocus = mCurrentFocus;
mCurrentFocus = newFocus;
mLosingFocus.remove(newFocus);
if (newFocus != null) {
mWinAddedSinceNullFocus.clear();
mWinRemovedSinceNullFocus.clear();
if (newFocus.canReceiveKeys()) {
// Displaying a window implicitly causes dispatching to be unpaused.
// This is to protect against bugs if someone pauses dispatching but
// forgets to resume.
newFocus.mToken.paused = false;
}
}
// 通知焦點(diǎn)窗口變化了
onWindowFocusChanged(oldFocus, newFocus);
int focusChanged = getDisplayPolicy().focusChangedLw(oldFocus, newFocus);
if (imWindowChanged && oldFocus != mInputMethodWindow) {
// Focus of the input method window changed. Perform layout if needed.
if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
performLayout(true /*initial*/, updateInputWindows);
focusChanged &= ~FINISH_LAYOUT_REDO_LAYOUT;
} else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
// Client will do the layout, but we need to assign layers
// for handleNewWindowLocked() below.
assignWindowLayers(false /* setLayoutNeeded */);
}
}
if ((focusChanged & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
// The change in focus caused us to need to do a layout. Okay.
setLayoutNeeded();
if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
performLayout(true /*initial*/, updateInputWindows);
} else if (mode == UPDATE_FOCUS_REMOVING_FOCUS) {
mWmService.mRoot.performSurfacePlacement();
}
}
if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
// If we defer assigning layers, then the caller is responsible for doing this part.
getInputMonitor().setInputFocusLw(newFocus, updateInputWindows);
}
adjustForImeIfNeeded();
// We may need to schedule some toast windows to be removed. The toasts for an app that
// does not have input focus are removed within a timeout to prevent apps to redress
// other apps' UI.
scheduleToastWindowsTimeoutIfNeededLocked(oldFocus, newFocus);
if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM;
}
return true;
}
最后通過onWindowFocusChanged()去通知其他模塊焦點(diǎn)窗口變化了眯漩。
2.8 設(shè)置MergedConfiguration對(duì)象給客戶端
??接下來更新MergedConfiguration對(duì)象赦抖,MergedConfiguration是全局Configuration對(duì)象和override Configurationu對(duì)象的包裝類摹芙,實(shí)現(xiàn)了Parcelable對(duì)象,因此可以用來進(jìn)程間傳遞交胚,它的主要作用就是WMS向ViewRootImpl同步Configuration蝴簇。在relayoutWindow()時(shí)熬词,會(huì)將當(dāng)前global configuration 和override configuration給到MergedConfiguration吸重,并創(chuàng)建出一個(gè)新的Configuration對(duì)象:
//frameworks/base/services/core/java/com/android/server/wm/WindowState.java
void getMergedConfiguration(MergedConfiguration outConfiguration) {
// 獲取全局Configuration對(duì)象
final Configuration globaluConfig = getProcessGlobalConfiguration();
// 獲取覆蓋Configuration對(duì)象
final Configuration overrideConfig = getMergedOverrideConfiguration();
// 設(shè)置給MergedConfiguration
outConfiguration.setConfiguration(globalConfig, overrideConfig);
}
2.9 設(shè)置windowFrame和Inset給客戶端
?? WMS中的WindowFrame類颜矿,其中攜帶了一些影響窗口如何進(jìn)行布局的Rect對(duì)象骑疆,比較重要的一些Rect對(duì)象有:
mDisplayFrame:來自于DisplayFrame#mUnrestricted屬性,表示此窗口所在的ActivityStack的整個(gè)屏幕區(qū)域箍铭,一般等于邏輯屏大姓┗稹柄瑰;
mParentFrame:來自于mDisplayFrame教沾,輸入法授翻、壁紙等特殊窗口除外堪唐,多數(shù)情況下淮菠,等于mDisplayFrame荤堪;
mContainingFrame:對(duì)于full-screen類型窗口來說澄阳,等于mParentFrame碎赢。
??這些Rect在DisplayPolicy#layoutWindowLw()方法中對(duì)它們進(jìn)行了設(shè)置肮塞,具體流程在Surface的placement流程中說明。
??這里會(huì)將WindowFrame#mCompatFrame以及其他幾個(gè)Rect對(duì)象設(shè)置給ViewRootImpl中傳入的變量蕊唐,從而輸出給ViewRootImpl:
//frameworks/base/services/core/java/com/android/server/wm/WindowState.java
void getCompatFrame(Rect outFrame) {
outFrame.set(mWindowFrames.mCompatFrame);
}
void getInsetsForRelayout(Rect outContentInsets, Rect outVisibleInsets,
Rect outStableInsets) {
outContentInsets.set(mWindowFrames.mContentInsets);
outVisibleInsets.set(mWindowFrames.mVisibleInsets);
outStableInsets.set(mWindowFrames.mStableInsets);
mLastRelayoutContentInsets.set(mWindowFrames.mContentInsets);
}
3.總結(jié)
通過relayout操作替梨,更新對(duì)應(yīng)WindowState的大小、可見性等相關(guān)屬性弓熏;
在第一次relayout時(shí)挽鞠,就會(huì)創(chuàng)建一個(gè)Surface信认,并對(duì)Surface進(jìn)行大小等屬性的設(shè)置嫁赏,返回給客戶端潦蝇,作為View顯示內(nèi)容的載體深寥;
創(chuàng)建Surface時(shí)则酝,通過WindowStateAnimator中的WindowSurfaceController進(jìn)行創(chuàng)建堤魁。
??Surface創(chuàng)建好之后妥泉,返回給可客戶端盲链,客戶端會(huì)將具體內(nèi)容的畫在Surface上刽沾,并在完成后通知WMS侧漓。WMS中將通過WindowSurfacePlacer#performSurfacePlacement()方法布蔗,最終將Surface送給SurfaceFlinger,完成顯示顿乒。
??以上整個(gè)過程時(shí)序圖如下: