???????接著上篇文章分析锐朴,Android WMS窗口管理,接下來看一下窗口顯示流程:
五.窗口顯示
???????窗口從最初創(chuàng)建到顯示在屏幕上會有五個mDrawState狀態(tài)的變遷蔼囊,分別為:NO_SURFACE焚志、DRAWING_PENDING、COMMIT_DRAW_PENDING畏鼓、READY_TO_SHOW酱酬、HAS_DRAWN;結(jié)合代碼實(shí)現(xiàn)來一起看一下:
1.NO_SURFACE
???????當(dāng)一個窗口剛剛被WMS執(zhí)行addWindow()方法創(chuàng)建的時候云矫,WindowStateAnimator在WindowState的構(gòu)造函數(shù)中一起被創(chuàng)建膳沽,在relayoutWindow之前,窗口是沒有Surface的让禀,所以不可能被顯示出來挑社,此時狀態(tài)就是NO_SURFACE。
2.DRAWING_PENDING
???????客戶端調(diào)用了relayoutWindow()巡揍,這個時候通過WindowManagerServcice的createSurfaceControl()創(chuàng)建了SurfaceControl痛阻,然后為窗口創(chuàng)建了一塊空白的Surface,此時需要客戶端在Surface上作畫腮敌,但由于Surface為空白狀態(tài)阱当,所以還是不能顯示出俏扩;看一下具體的代碼邏輯實(shí)現(xiàn):
2.1.relayoutWindow()
public int relayoutWindow(Session session, IWindow client, int seq,WindowManager.LayoutParams attrs, xx,xx, Surface outSurface) {
............................
...........................
try {
result = createSurfaceControl(outSurface, result, win, winAnimator);
}
.................
.................
}
???????在relayoutWindow()內(nèi)部會執(zhí)行createSurfaceControl(),看一下該方法實(shí)現(xiàn):
2.2.createSurfaceControl()
private int createSurfaceControl(Surface outSurface, int result, WindowState win,
WindowStateAnimator winAnimator) {
................
WindowSurfaceController surfaceController;
try {
surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
if (surfaceController != null) {
surfaceController.getSurface(outSurface);
} else {
outSurface.release();
}
return result;
}
???????在createSurfaceControl()內(nèi)部主要做了兩件事:
???????1.通過WindowStateAnimator的createSurfaceLocked()獲取WindowSurfaceController實(shí)例弊添;
???????2.通過WindowSurfaceController的getSurface()來對outSurface進(jìn)行賦值动猬,該outSurface對應(yīng)ViewRootImpl內(nèi)部的Surface,最終在該surface進(jìn)行繪制顯示表箭;
2.3.createSurfaceLocked()
WindowSurfaceController createSurfaceLocked(int windowType, int ownerUid) {
final WindowState w = mWin;
............................
w.setHasSurface(false);
resetDrawState();
final WindowManager.LayoutParams attrs = w.mAttrs;
if (mService.isSecureLocked(w)) {
flags |= SurfaceControl.SECURE;
}
...............................
try {
......................
mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
attrs.getTitle().toString(),width, height, format, flags, this, windowType, ownerUid);
mSurfaceFormat = format;
w.setHasSurface(true);
}
..................................
mService.openSurfaceTransaction();
try {
mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top, false);
mSurfaceController.setLayerStackInTransaction(getLayerStack());
mSurfaceController.setLayer(mAnimLayer);
} finally {
mService.closeSurfaceTransaction();
}
mLastHidden = true;
return mSurfaceController;
}
???????該方法比較重要,一起看一下主要做了什么事情:
???????1.執(zhí)行setHasSurface(false)钮莲,表示此時還未創(chuàng)建Surface免钻;
???????2.執(zhí)行resetDrawState(),將mDrawState設(shè)置為DRAW_PENDING崔拥,此時狀態(tài)變?yōu)镈RAW_PENDING极舔;
???????3.創(chuàng)建WindowSurfaceController對象,在構(gòu)造方法內(nèi)部會創(chuàng)建SurfaceControl链瓦,每個WindowState對應(yīng)一個SurfaceControl拆魏,SurfaceControl與底層的SurfaceFlinger進(jìn)行交互;
???????4.執(zhí)行setHasSurface(true)慈俯,表示Surface已經(jīng)創(chuàng)建完畢渤刃;
???????5.執(zhí)行setPositionInTransaction()來設(shè)置WindowState顯示的位置;
???????6.執(zhí)行setLayerStackInTransaction()來表示該WindowState顯示在對應(yīng)的LayerStack贴膘,通過SurfaceControll通知到SurfaceFlinger卖子,一個Display對應(yīng)一個LayerStack,即顯示在對應(yīng)的Display上刑峡;
???????7.執(zhí)行setLayer()來設(shè)置WindowState顯示的layer洋闽,通過SurfaceControll通知到SurfaceFlinger,上篇文章講到突梦,對App窗口來說诫舅,mAnimLayer跟mLayer是相同的;
2.4.getSurface()
???????接著上面relayoutWindow()實(shí)現(xiàn)分析宫患,在創(chuàng)建完WindowSurfaceController后刊懈,會執(zhí)行g(shù)etSurface()來獲取要繪制內(nèi)容的Surface;
void getSurface(Surface outSurface) {
outSurface.copyFrom(mSurfaceControl);
}
public void copyFrom(SurfaceControl other) {
.............
long surfaceControlPtr = other.mNativeObject;
long newNativeObject = nativeGetFromSurfaceControl(surfaceControlPtr);
synchronized (mLock) {
if (mNativeObject != 0) {
nativeRelease(mNativeObject);
}
setNativeObjectLocked(newNativeObject);
}
}
???????通過copyFrom()方法可以看到撮奏,將剛才創(chuàng)建的SurfaceControl的信息賦值給要展示的Surface俏讹,由于Surface、SurfaceControl跟底層SurfaceFlinger打交道畜吊,所以直接通過native方法來進(jìn)操作泽疆;
3.COMMIT_DRAW_PENDING
???????在獲取到要繪制的Surface時,ViewRootImpl就通過Canvas在Surface上進(jìn)行繪制玲献,繪制完成之后會調(diào)用Session的finishDrawing()方法殉疼,調(diào)用到WMS的finishDrawingWindow()方法梯浪,看一下實(shí)現(xiàn):
3.1.finishDrawingWindow()
void finishDrawingWindow(Session session, IWindow client) {
try {
synchronized (mWindowMap) {
WindowState win = windowForClientLocked(session, client, false);
if (win != null && win.mWinAnimator.finishDrawingLocked()) {
win.setDisplayLayoutNeeded();
mWindowPlacerLocked.requestTraversal();
}
}
}
}
???????調(diào)用到WindowState的finishDrawingLocked()方法:
3.2.finishDrawingLocked()
boolean finishDrawingLocked() {
....................
if (mDrawState == DRAW_PENDING) {
mDrawState = COMMIT_DRAW_PENDING;
layoutNeeded = true;
}
return layoutNeeded;
}
???????在該方法內(nèi)部將mDrawState設(shè)置為COMMIT_DRAW_PENDING,此時狀態(tài)切換到COMMIT_DRAW_PENDING瓢娜,表示窗口已經(jīng)繪制完成挂洛,正在等待布局系統(tǒng)進(jìn)行提交。
4.READY_TO_SHOW
???????在WMS內(nèi)部的findDrawingWindow()在設(shè)置完狀態(tài)后眠砾,接著執(zhí)行了mWindowPlacerLocked.requestTraversal()來請求刷新窗口虏劲,跟著調(diào)用關(guān)系,最終會調(diào)用到DIsplayContent的applySurfaceChangesTransaction()方法:
4.1.applySurfaceChangesTransaction()
boolean applySurfaceChangesTransaction(boolean recoveringMemory)
.........................
........................
forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
...................
}
private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
...........................
...........................
if (w.mHasSurface) {
final boolean committed = winAnimator.commitFinishDrawingLocked();
.................
}
.............
}
???????在mApplySurfaceChangesTransaction內(nèi)部會遍歷WindowState褒颈,前面在createSurfaceLocked()時柒巫,已經(jīng)將mHasSurface設(shè)為了true,所以此時執(zhí)行commitFinishDrawingLocked():
4.2.commitFinishDrawingLocked()
boolean commitFinishDrawingLocked() {
if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
return false;
}
mDrawState = READY_TO_SHOW;
boolean result = false;
final AppWindowToken atoken = mWin.mAppToken;
if (atoken == null || atoken.allDrawn || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
result = mWin.performShowLocked();
}
return result;
}
???????1.設(shè)置mDrawState = READY_TO_SHOW谷丸,把狀態(tài)切換到READY_TO_SHOW堡掏;
???????2.然后做如下檢查:
??????????a.atoken == null,表示不是App窗口刨疼;
??????????b.atoken.allDrawn泉唁,表示 AppWindowToken 的對應(yīng)的所有窗口都已經(jīng)是 allDrawn,AppWindowToken通常只有一個WindowState揩慕,也可能存在 子窗口的情況亭畜,保證所有的窗口已經(jīng)繪制完成了;
??????????c.mWin.mAttrs.type ==TYPE_APPLICATION_STARTING迎卤,表示該窗口是啟動窗口贱案;
???????3.如果滿足以上任何一個條件就會執(zhí)行 WindowState 的 performShowLocked();
5.HAS_DRAWN
???????前面講到止吐,在滿足條件后宝踪,會執(zhí)行WindowState的performShowLocked(),一起看一下:
5.1.performShowLocked()
boolean performShowLocked() {
......................
final int drawState = mWinAnimator.mDrawState;
if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW)
&& mAttrs.type != TYPE_APPLICATION_STARTING && mAppToken != null) {
mAppToken.onFirstWindowDrawn(this, mWinAnimator);
}
if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplay()) {
return false;
}
logPerformShow("Showing ");
mService.enableScreenIfNeededLocked();
mWinAnimator.applyEnterAnimationLocked();
mWinAnimator.mLastAlpha = -1;
mWinAnimator.mDrawState = HAS_DRAWN;
mService.scheduleAnimationLocked();
if (mHidden) {
mHidden = false;
final DisplayContent displayContent = getDisplayContent();
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = mChildren.get(i);
if (c.mWinAnimator.mSurfaceController != null) {
c.performShowLocked();
if (displayContent != null) {
displayContent.setLayoutNeeded();
}
}
}
}
...................
return true;
}
???????1.窗口要顯示了碍扔,執(zhí)行mAppToken.onFirstWindowDrawn(this, mWinAnimator)來移除STARTING_WINDOW瘩燥;
???????2.執(zhí)行mWinAnimator.applyEnterAnimationLocked(),來加載窗口動畫不同;
???????3.設(shè)置mDrawState = HAS_DRAWN厉膀,此時窗口顯示狀態(tài)更新為HAS_DRWAN;
???????4.執(zhí)行mService.scheduleAnimationLocked()來執(zhí)行窗口動畫二拐;
???????5.如果有子WindowState時服鹅,執(zhí)行子WindowState的performShowLocked()方法來顯示窗口;
6.總結(jié)
???????用一種流程圖總結(jié)一下狀態(tài)的變遷過程:
六.Task動畫
???????Task動畫分為兩種:STARTING_WINDOW_TYPE_SNAPSHOT和STARTING_WINDOW_TYPE_SPLASH_SCREEN百新,發(fā)生在一個Activity啟動伴隨著一次Task的切換企软, 要啟動的窗口還沒有Ready的情況下,為了體現(xiàn)流暢性饭望,顯示的一種窗口仗哨;
???????既然是在啟動的窗口還沒有ready情況下顯示的一種窗口形庭,那么啟動時機(jī)就應(yīng)該比較早,Activity啟動過程就不贅述了厌漂,直接從入口開始萨醒,在ActivityStarter內(nèi)部的startActivityUnchecked()內(nèi)部會調(diào)用以下邏輯:
mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,mOptions)
???????在該方法內(nèi)部,會執(zhí)行:
r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity))
???????跟著調(diào)用邏輯繼續(xù)看:
void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
boolean fromRecents) {
...............................
final boolean shown = mWindowContainerController.addStartingWindow(packageName, theme,
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
allowTaskSnapshot(),
state.ordinal() >= RESUMED.ordinal() && state.ordinal() <= STOPPED.ordinal(),
fromRecents);
if (shown) {
mStartingWindowState = STARTING_WINDOW_SHOWN;
}
}
???????調(diào)用到AppWindowContainerController的addStartingWindow()苇倡,上篇文章中講到富纸,AppWindowContainerController是在創(chuàng)建ActivityRecord時就創(chuàng)建了,看一下addStartingWindow()方法:
public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
synchronized(mWindowMap) {
.....................................
final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
mContainer.getTask().mTaskId, mContainer.getTask().mUserId,
false /* restoreFromDisk */, false /* reducedResolution */);
final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
allowTaskSnapshot, activityCreated, fromRecents, snapshot);
if (type == STARTING_WINDOW_TYPE_SNAPSHOT ) {
return createSnapshot(snapshot);
}
..............................
mContainer.startingData = new SplashScreenStartingData(mService, pkg, theme,
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
mContainer.getMergedOverrideConfiguration(), false);
scheduleAddStartingWindow();
}
return true;
}
???????1.通過getSnapshot()來獲取該TaskRecord對應(yīng)的截圖旨椒;
???????2.根據(jù)getStartingWindowType()來獲取對應(yīng)的啟動type胜嗓;
???????3.應(yīng)用非首次啟動時,會走createSnapshot(snapshot)分支钩乍;首次啟動時,會執(zhí)行SplashScreenStartingData分支怔锌;
???????先從STARTING_WINDOW_TYPE_SPLASH_SCREEN開始看:
1.STARTING_WINDOW_TYPE_SPLASH_SCREEN
???????先創(chuàng)建SplashScreenStartingData對象賦值給mContainer.startingData寥粹,即賦值給AppWindowToken的startingData變量,接著執(zhí)行scheduleAddStartingWindow()來開始staring window埃元,先看一下SplashScreenStartingData:
1.1.SplashScreenStartingData
class SplashScreenStartingData extends StartingData {
.....................
SplashScreenStartingData(WindowManagerService service, String pkg, int theme,
CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
int logo, int windowFlags, Configuration mergedOverrideConfiguration,boolean isForUIMode) {
super(service);
...................
}
@Override
StartingSurface createStartingSurface(AppWindowToken atoken) {
return mService.mPolicy.addSplashScreen(atoken.token, mPkg, mTheme, mCompatInfo,
mNonLocalizedLabel, mLabelRes, mIcon, mLogo, mWindowFlags,
mMergedOverrideConfiguration, atoken.getDisplayContent().getDisplayId(),mIsForUIMode);
}
???????繼承StartingData涝涤,實(shí)現(xiàn)了createStartingSurface()方法來返回StartingSurface;
1.2.scheduleAddStartingWindow()
void scheduleAddStartingWindow() {
mService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
}
???????發(fā)送消息到消息隊列的頭部岛杀,優(yōu)先執(zhí)行阔拳,看一下mAddStartingWindow:
private final Runnable mAddStartingWindow = () -> {
final StartingData startingData;
final AppWindowToken container;
synchronized (mWindowMap) {
if (mContainer == null) {
return;
}
startingData = mContainer.startingData;
container = mContainer;
}
.........................
StartingSurface surface = null;
try {
surface = startingData.createStartingSurface(container);
}
if (surface != null) {
boolean abort = false;
synchronized(mWindowMap) {
............................
container.startingSurface = surface;
.......................
}
}
};
???????1.將mContainer的startingData賦值給startingData變量;
???????2.通過startingData的createStartingSurface()來獲取StartingSurface實(shí)例类嗤,賦值給container的startingSurface變量糊肠;
???????前面已經(jīng)講到,在createStartingSurface()內(nèi)部會執(zhí)行到PhoneWindowManager的addSplashScreen()來獲取StartingSurface對象遗锣;
1.3.addSplashScreen()
public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme,
CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
int logo, int windowFlags, Configuration overrideConfig, int displayId,boolean forUIMode) {
//可以設(shè)置該Flag不讓顯示splash screen;
if (!SHOW_SPLASH_SCREENS) {
return null;
}
WindowManager wm = null;
View view = null;
try {
Context context = mContext;
final Context displayContext = getDisplayContext(context, displayId);
context = displayContext;
.......................................
final PhoneWindow win = new PhoneWindow(context);
win.setIsStartingWindow(true);
............................
win.setType(WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
..................................
final WindowManager.LayoutParams params = win.getAttributes();
params.token = appToken;
...........................
params.setTitle("Splash Screen " + packageName);
if (forUIMode){
addSplashscreenContentForUIMode(win, context);
} else {
addSplashscreenContent(win, context);
}
wm = (WindowManager) context.getSystemService(WINDOW_SERVICE);
view = win.getDecorView();
wm.addView(view, params);
return view.getParent() != null ? new SplashScreenSurface(view, appToken) : null;
}
}
???????1.獲取對應(yīng)Display的Context货裹,來獲取不同的資源;
???????2.創(chuàng)建PhoneWindow實(shí)例win精偿,設(shè)置屬性mIsStartingWindow為true弧圆;
???????3.設(shè)置type為TYPE_APPLICATION_STARTING,跟App窗口是不一樣的笔咽,后續(xù)會根據(jù)該type來進(jìn)行相應(yīng)的邏輯處理搔预;
???????4.將Spashscreen窗口對應(yīng)的appToken設(shè)置為params.token;
???????5.設(shè)置title為"Splash Screen " + packageName叶组;
???????6.addSplashscreenContent()來創(chuàng)建View()拯田,設(shè)備backgroud,并執(zhí)行PhoneWindow.setContentView()來創(chuàng)建DecorView甩十;
???????7.通過WindowManager的addView()來顯示View(SplashScreen)勿锅;
???????8.最后創(chuàng)建SplashScreenSurface對象作為返回值帕膜,為了后面來移除SplashScreen窗口;
class SplashScreenSurface implements StartingSurface {
private final View mView;
private final IBinder mAppToken;
SplashScreenSurface(View view, IBinder appToken) {
mView = view;
mAppToken = appToken;
}
@Override
public void remove() {
final WindowManager wm = mView.getContext().getSystemService(WindowManager.class);
wm.removeView(mView);
}
}
1.4.onFirstWindowDrawn()
???????前面講到溢十,在WindowState執(zhí)行performShowLocked()進(jìn)行最后的顯示時垮刹,如果mAttrs.type != TYPE_APPLICATION_STARTING,即當(dāng)App窗口要顯示時會執(zhí)行mAppToken.onFirstWindowDrawn(this, mWinAnimator)张弛,在該方法內(nèi)部會移除SplashScreen荒典,一起看一下邏輯實(shí)現(xiàn):
void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
firstWindowDrawn = true;
removeDeadWindows();
if (startingWindow != null) {
winAnimator.clearAnimation();
if (getController() != null) {
getController().removeStartingWindow();
}
}
updateReportedVisibilityLocked();
}
???????可以看到,如果AppWindowToken對應(yīng)的startingWindow不為null時吞鸭,會通過AppWindowContainerController的removeStartingWindow()來進(jìn)行移除:
1.5.removeStatingWindow()
public void removeStartingWindow() {
synchronized (mWindowMap) {
final StartingSurface surface;
if (mContainer.startingData != null) {
surface = mContainer.startingSurface;
mContainer.startingData = null;
mContainer.startingSurface = null;
mContainer.startingWindow = null;
mContainer.startingDisplayed = false;
}
............................
mService.mAnimationHandler.post(() -> {
try {
surface.remove();
}
});
}
}
???????從mContainer獲取StartingSurface寺董,執(zhí)行remove(),在內(nèi)部通過removeView()來移除SplashScreen窗口刻剥;
2.STARTING_WINDOW_TYPE_SNAPSHOT
???????從AppWindowContainerController的addStartingWindow()內(nèi)部遮咖,如果返回的type為STARTING_WINDOW_TYPE_SNAPSHOT時,表示TaskRecord已經(jīng)啟動過造虏,用snapshot來作為Task動畫窗口御吞,從createSnapshot()開始:
2.1.createSnapshot()
private boolean createSnapshot(TaskSnapshot snapshot) {
if (snapshot == null) {
return false;
}
mContainer.startingData = new SnapshotStartingData(mService, snapshot);
scheduleAddStartingWindow();
return true;
}
???????創(chuàng)建SnapshotStartingData對象賦值給AppWindowToken的變量startingData,然后執(zhí)行scheduleAddStartingWindow()漓藕;
2.2.SnapshotStartingData
class SnapshotStartingData extends StartingData {
private final WindowManagerService mService;
private final TaskSnapshot mSnapshot;
SnapshotStartingData(WindowManagerService service, TaskSnapshot snapshot) {
super(service);
mService = service;
mSnapshot = snapshot;
}
@Override
StartingSurface createStartingSurface(AppWindowToken atoken) {
return mService.mTaskSnapshotController.createStartingSurface(atoken, mSnapshot);
}
}
???????也是繼承StartingData陶珠,實(shí)現(xiàn)了createStartingSurface()方法內(nèi)部通過TaskSnapshotController的createStartingSurface來獲取StartingSurface;
???????scheduleAddStartingWindow()實(shí)現(xiàn)前面在SplashScreen已經(jīng)分析了享钞,就不贅述了揍诽,直接看TaskSnapshotController的createStartingSurface()方法:
2.3.createStartingSurface()
StartingSurface createStartingSurface(AppWindowToken token,TaskSnapshot snapshot) {
return TaskSnapshotSurface.create(mService, token, snapshot);
}
???????調(diào)用TaskSnapshotSurface的create()方法來返回StartingSurface;
2.4.TaskSnapshotSurface
static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token,
TaskSnapshot snapshot) {
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
final Window window = new Window();
final IWindowSession session = WindowManagerGlobal.getWindowSession();
window.setSession(session);
final Surface surface = new Surface();
......................
int backgroundColor = WHITE;
................
synchronized (service.mWindowMap) {
.............................
layoutParams.type = TYPE_APPLICATION_STARTING;
layoutParams.token = token.token;
layoutParams.setTitle(String.format(TITLE_FORMAT, task.mTaskId))
.........................
}
try {
final int res = session.addToDisplay(window, window.mSeq, layoutParams,
View.VISIBLE, token.getDisplayContent().getDisplayId(), tmpRect, tmpRect, tmpRect, null);
}
final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
surface, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor,
navigationBarColor, sysUiVis, windowFlags, windowPrivateFlags, taskBounds,
currentOrientation);
window.setOuter(snapshotSurface);
try {
session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame,
tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect,
tmpMergedConfiguration, surface);
}
snapshotSurface.setFrames(tmpFrame, tmpContentInsets, tmpStableInsets);
snapshotSurface.drawSnapshot();
return snapshotSurface;
}
???????跟SplashScreen實(shí)現(xiàn)類似也是設(shè)置了type及token栗竖、title暑脆、backgroudColor等參數(shù),直接通過addToDisplay及relayout()狐肢、drawSnapshot()來顯示窗口饵筑,最后返回snapshotSurface;
???????最后在onFirstWindowDrawn()內(nèi)不removeStartingWindow()处坪,調(diào)用mSession.remove(mWindow)來移除snapshot窗口根资;
3.總結(jié)
???????用一張邏輯執(zhí)行流程圖來總結(jié)一下:
七.窗口移除
???????一個應(yīng)用在啟動后,下次再進(jìn)入該應(yīng)用時會特別快同窘,是因?yàn)樯洗螁拥拇翱跊]有刪除玄帕,下次再啟動時不會重新執(zhí)行addWindow(),那么什么時候去移除窗口呢想邦?
???????拿Activity來說裤纹,從當(dāng)前Activity切換到別的Activity時,該Activity對應(yīng)的窗口是不會刪除的,只有當(dāng)該Activity執(zhí)行finish()時鹰椒,比如:主動finish()锡移、back鍵等,此時會執(zhí)行handleDestroyActivity()漆际,從以下三方面來看一下:
1.Activity執(zhí)行finish()開啟
???????當(dāng)Activity執(zhí)行了finish()時淆珊,會對該activity進(jìn)行銷毀,即會執(zhí)行onDestroy()奸汇,直接從ActivityThread的handleDestroy()方法看起:
private void handleDestroyActivity(IBinder token, boolean finishing,
int configChanges, boolean getNonConfigInstance) {
ActivityClientRecord r = performDestroyActivity(token, finishing,configChanges, getNonConfigInstance);
WindowManager wm = r.activity.getWindowManager();
View v = r.activity.mDecor;'
wm.removeViewImmediate(v)
..............
ActivityManager.getService().activityDestroyed(token);
}
???????1.執(zhí)行performDestroyActivity()施符,在該方法內(nèi)部會通過token獲取到ActivityClientRecord,然后執(zhí)行activity的onDestroy()擂找,最后從mActivities內(nèi)部刪除該ActivityClientRecord戳吝,最后返回ActivityClientRecord;
???????2.獲取到WindowManage及Activity對應(yīng)的DecorView贯涎,最后調(diào)用removeViewImmediate()來移除該view听哭;
???????3.最后通知ActivityManagerService執(zhí)行activityDestroyed()進(jìn)行后續(xù)工作;
???????先看一下removeViewImmediate()的執(zhí)行過程:
1.1.removeViewImmediate()
public void removeViewImmediate(View view) {
mGlobal.removeView(view, true);
}
???????調(diào)用到WindowManagerGlobal的removeView():
1.2.removeView()
public void removeView(View view, boolean immediate) {
synchronized (mLock) {
int index = findViewLocked(view, true);
View curView = mRoots.get(index).getView();
removeViewLocked(index, immediate);
if (curView == view) {
return;
}
}
}
private void removeViewLocked(int index, boolean immediate) {
ViewRootImpl root = mRoots.get(index);
View view = root.getView();
....................
boolean deferred = root.die(immediate);
.....................
}
???????通過index找到該view對應(yīng)的ViewRootImpl塘雳,調(diào)用到ViewRootImpl的die()方法陆盘;
1.3.die()
boolean die(boolean immediate) {
if (immediate && !mIsInTraversal) {
doDie();
return false;
}
.................
}
???????在die()內(nèi)調(diào)用了doDie()方法:
1.4.doDie()
void doDie() {
checkThread();
synchronized (this) {
..............
mRemoved = true;
if (mAdded) {
dispatchDetachedFromWindow();
}
if (mAdded && !mFirst) {
destroyHardwareRenderer();
if (mView != null) {
int viewVisibility = mView.getVisibility();
boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
if (mWindowAttributesChanged || viewVisibilityChanged) {
try {
if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
& WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
mWindowSession.finishDrawing(mWindow);
}
}
mSurface.release();
}
}
mAdded = false;
}
WindowManagerGlobal.getInstance().doRemoveView(this);
}
???????1.執(zhí)行dispatchDetachedFromWindow();
???????2.執(zhí)行destroyHardwareRenderer()粉捻,釋放跟繪制渲染相關(guān)的邏輯;
???????3.執(zhí)行WindowManagerGlobal.getInstance().doRemoveView(this)通知WindowManagerGlobal將該ViewRootImpl從mRoots中刪除斑芜;
1.5.dispatchDetachedFromWindow()
void dispatchDetachedFromWindow() {
if (mView != null && mView.mAttachInfo != null) {
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
mView.dispatchDetachedFromWindow();
}
.............
mView.assignParent(null);
mView = null;
mAttachInfo.mRootView = null;
mSurface.release();
.......................
if (mInputEventReceiver != null) {
mInputEventReceiver.dispose();
mInputEventReceiver = null;
}
try {
mWindowSession.remove(mWindow);
}
if (mInputChannel != null) {
mInputChannel.dispose();
mInputChannel = null;
}
mDisplayManager.unregisterDisplayListener(mDisplayListener);
unscheduleTraversals();
}
???????1.通過mView.dispatchDetachedFromWindow()通知Activity執(zhí)行onDetachedFromWindow()肩刃;
???????2.進(jìn)行置空和mSurface.release();
???????3.執(zhí)行mInputEventReceiver.dispose來取消Input事件監(jiān)聽杏头;
???????4.執(zhí)行 mWindowSession.remove(mWindow)來移除window盈包;
???????5.執(zhí)行mInputChannel.dispose()來銷毀Input事件監(jiān)聽通道;
???????6.反注冊mDisplayListener醇王;
???????7.執(zhí)行unscheduleTraversals()來移除消息屏障呢燥,表示不需要處理繪制優(yōu)先消息了;
2.SurfaceFlinger移除對應(yīng)layer
???????前面講到寓娩,執(zhí)行mWindowSession的remove()叛氨,會調(diào)用到WMS的removeWindow(),一步一步執(zhí)行棘伴,最終通知SurfaceFlinger來移除WindowState對應(yīng)的layer寞埠,跟著調(diào)用邏輯一起看一下執(zhí)行過程:
2.1.removeWindow()
void removeWindow(Session session, IWindow client) {
synchronized(mWindowMap) {
WindowState win = windowForClientLocked(session, client, false);
win.removeIfPossible();
}
}
???????通過windowForClientLocked根據(jù)client找到對應(yīng)的WindowState,執(zhí)行removeIfPossible()焊夸,跟著調(diào)用關(guān)系仁连,執(zhí)行到removeImmediately():
2.2.removeImmediately()
void removeImmediately() {
.......................
mPolicy.removeWindowLw(this);
disposeInputChannel();
mWinAnimator.destroyDeferredSurfaceLocked();
mWinAnimator.destroySurfaceLocked();
mSession.windowRemovedLocked();
mService.postWindowRemoveCleanupLocked(this);
}
???????1.執(zhí)行PhoneWindowManager的removeWindowLw(this) 做特殊窗口的處理,比如狀態(tài)欄阱穗、導(dǎo)航欄等饭冬;
???????2.執(zhí)行disposeInputChannel()來移除Input事件監(jiān)聽通道使鹅;
???????3.執(zhí)行mWinAnimator.destroySurfaceLocked()來銷毀Surface,最終會通知到SurfaceFlinger進(jìn)行銷毀昌抠,接下來看患朱;
???????4.執(zhí)行mSession.windowRemovedLocked()來從WMS的mSessions內(nèi)移除該WindowState對應(yīng)的Session;
???????5.執(zhí)行mService.postWindowRemoveCleanupLocked(this)來從WMS的mWindowMap內(nèi)移除該WindowState扰魂;
2.3.destroySurfaceLocked()
void destroyDeferredSurfaceLocked() {
.................
mSurfaceDestroyDeferred = false;
mPendingDestroySurface = null;
}
???????在WindowState執(zhí)行removeImmediately()時麦乞,會先執(zhí)行destroyDeferredSurfaceLocked(),進(jìn)行一些變量的設(shè)置劝评,再執(zhí)行destroySurfaceLocked()姐直,只列出了執(zhí)行的代碼邏輯:
void destroySurfaceLocked() {
.....................
.....................
destroySurface();
mWin.setHasSurface(false);
if (mSurfaceController != null) {
mSurfaceController.setShown(false);
}
mSurfaceController = null;
mDrawState = NO_SURFACE;
}
void destroySurface() {
try {
if (mSurfaceController != null) {
mSurfaceController.destroyInTransaction();
}
} finally {
mWin.setHasSurface(false);
mSurfaceController = null;
mDrawState = NO_SURFACE;
}
}
???????1.執(zhí)行destroySuface()來執(zhí)行SurfaceController的destroyInTransaction();
???????2.設(shè)置WindowState的mHasSurface為false蒋畜;
???????3.將mDrawState設(shè)置為NO_SURFACE声畏;
2.4.destroyInTransaction()
void destroyInTransaction() {
try {
if (mSurfaceControl != null) {
mSurfaceControl.destroy();
} finally {
setShown(false);
mSurfaceControl = null;
}
}
}
???????在destroyInTransaction()執(zhí)行SurfaceControl的destroy():
2.5.destroy()
public void destroy() {
if (mNativeObject != 0) {
nativeDestroy(mNativeObject);
mNativeObject = 0;
}
mCloseGuard.close();
}
???????在destroy()內(nèi)部執(zhí)行nativeDestroy(mNativeObject)通知SurfaceFlinger將該WindowState對應(yīng)的Layer從mCurrentState中移除;
3.WMS管理
???????前面講到姻成,在Activity執(zhí)行完onDestroy()后插龄,會通知AMS執(zhí)行activityDestroyed()方法,一起看一下:
3.1.activityDestroyedLocked()
final void activityDestroyedLocked(IBinder token, String reason) {
try {
ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r != null) {
mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
}
if (isInStackLocked(r) != null) {
if (r.state == ActivityState.DESTROYING) {
cleanUpActivityLocked(r, true, false);
removeActivityFromHistoryLocked(r, reason);
}
}
}
}
3.2.removeActivityFromHistoryLocked()
private void removeActivityFromHistoryLocked(ActivityRecord r, String reason) {
......................................
r.removeWindowContainer();
final TaskRecord task = r.getTask();
final boolean lastActivity = task != null ? task.removeActivity(r) : false;
..........................
if (lastActivity) {
removeTask(task, reason, REMOVE_TASK_MODE_DESTROYING);
}
}
???????只分析跟WMS窗口管理相關(guān)的邏輯:
???????1.調(diào)用ActivityRecord的removeWindowContainer()方法移除該ActivityRecord對應(yīng)的AppWindowToken科展;
???????2.如果是最后的activity均牢,那么會通或removeTask()執(zhí)行到Task.removeWindowContainer()來移除該TaskRecord對應(yīng)的Task;
3.3.removeWindowContainer()
void removeWindowContainer() {
mWindowContainerController.removeContainer(getDisplayId());
mWindowContainerController = null;
}
???????通過AppWindowContainerController的removeContainer()來移除才睹,傳入了displayId參數(shù)徘跪;
3.4.removeContainer()
public void removeContainer(int displayId) {
synchronized(mWindowMap) {
final DisplayContent dc = mRoot.getDisplayContent(displayId);
dc.removeAppToken(mToken.asBinder());
super.removeContainer();
}
}
???????找到displayId對應(yīng)的DisplayContent,琅攘,然后執(zhí)行removeAppToken():
3.5.removeAppToken()
void removeAppToken(IBinder binder) {
final WindowToken token = removeWindowToken(binder);
..........................
final AppWindowToken appToken = token.asAppWindowToken();
...................
appToken.onRemovedFromDisplay();
}
WindowToken removeWindowToken(IBinder binder) {
final WindowToken token = mTokenMap.remove(binder);
if (token != null && token.asAppWindowToken() == null) {
oken.setExiting();
}
return token;
}
???????1.執(zhí)行removeWindowToken()將該AppWindowToken從DisplayContent的mTokenMap中移除垮庐;
???????2.執(zhí)行AppWindowToken的onRemovedFromDisplay()來處理其他邏輯;
3.6.onRemovedFromDisplay()
void onRemovedFromDisplay() {
............................
mRemovingFromDisplay = true;
//從mOpeningApps中移除
mService.mOpeningApps.remove(this);
//從對應(yīng)的snapshot從mCache中移除
mService.mTaskSnapshotController.onAppRemoved(this);
.....................................
//有必要的話坞琴,移除StartingWindow
if (startingData != null && getController() != null) {
getController().removeStartingWindow();
}
...............................
final TaskStack stack = getStack();
.............................
mAppAnimator.clearAnimation();
mAppAnimator.animating = false;
if (stack != null) {
//從TaskStack中的mExitingAppTokens移除
stack.mExitingAppTokens.remove(this);
}
removeIfPossible();
removed = true;
stopFreezingScreen(true, true);
if (mService.mFocusedApp == this) {
mService.mFocusedApp = null;
mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
mService.mInputMonitor.setFocusedAppLw(null);
}
mRemovingFromDisplay = false;
}
???????主要是做了一些清理工作哨查,在看一下removeIfPossible()方法:
3.7.removeIfPossible()
void removeIfPossible() {
mIsExiting = false;
removeAllWindowsIfPossible();
removeImmediately();
}
???????調(diào)用super方法,最終調(diào)用到WindowContainer內(nèi)的removeImmediately()方法:
3.8.removeImmediately()
void removeImmediately() {
while (!mChildren.isEmpty()) {
final WindowContainer child = mChildren.peekLast();
child.removeImmediately();
mChildren.remove(child);
}
if (mParent != null) {
mParent.removeChild(this);
}
if (mController != null) {
setController(null);
}
}
???????AppWindowToken對應(yīng)的mParent為Task剧辐,調(diào)用mParent.removeChild(this)把AppWindowToken從Task中移除寒亥,然后執(zhí)行setController(null)將 AppWindowContainerController置空;
4.總結(jié)
???????1.窗口移除從App端發(fā)起荧关,當(dāng)Activity執(zhí)行destroy()后執(zhí)行wm.removeViewImmediate()開啟护盈;
???????2.通過WindowManagerGlobal-->ViewRootImpl-->Session-->WindowManagerService的removeWindow(),調(diào)用到WindowState的removeImediately()羞酗,接著通過WindowStateAnimator-->WindowSurfaceController的destroyInTransaction()最終調(diào)用到SurfaceControl的destroy()來通知SurfaceFlinger來移除layer腐宋;
???????3.在Acticity執(zhí)行onDestroy()后會通知AMS,來執(zhí)行ActivityRecord的removeWindowContainer()來從DisplayContent、taskStack胸竞、Task刪除對應(yīng)的AppWindowToken欺嗤,并把AppWindowContainerController置空;
???????4.如果該ActivityRecord的TaskRecord的最后一個ActivityRecord卫枝,那么TaskRecord也沒有存在的必要了煎饼,也會跟刪除AppWindowToken邏輯一樣,將TaskRecord對應(yīng)的Task從DisplayContent及TaskStack中刪除校赤,并把TaskWindowContainerController置空卢佣;