1:概述
应用程序在冷启动过程中通常会显示一个预览窗口,接着在显示要启动的activity的窗口,因为activity的窗口显示渲染到屏幕上是需要时间的,特别是在性能比较差的设备上,这样有了预览窗口之后屏幕上看到的可能不是黑屏,增强了用户体验
本文主要是基于android_10.0.0来讲述的
2:StartingWindow添加流程
ActivityStarter.java::startActivity
ActivityStarter.java::startActivityUnchecked
ActivityStack.java::startActivityLocked
我们主要是从startActivityLocked来跟踪
//第一个条件满足,一般我们是从桌面启动应用
if (!isHomeOrRecentsStack() || numActivities() > 0) {
final DisplayContent dc = getDisplay().mDisplayContent;
.......................................
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
dc.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
mStackSupervisor.mNoAnimActivities.add(r);//是否需要启动动画
} else {
...................................省去部分代码
boolean doShow = true;
if (newTask) {
..............................
//桌面启动一般不带有此flag
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
resetTaskIfNeededLocked(r, r);
doShow = topRunningNonDelayedActivityLocked(null) == r;
}
} else if (options != null && options.getAnimationType()
== ActivityOptions.ANIM_SCENE_TRANSITION) {
doShow = false;
}
// mLaunchTaskBehind = options.getLaunchTaskBehind();赋值,桌面启动不带有此参数
if (r.mLaunchTaskBehind) {
r.setVisibility(true);
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
} else if (SHOW_APP_STARTING_PREVIEW && doShow) {//成立doShow=true
TaskRecord prevTask = r.getTaskRecord();
ActivityRecord prev = prevTask.topRunningActivityWithStartingWindowLocked();
if (prev != null) {
// We don't want to reuse the previous starting preview if:
// (1) The current activity is in a different task.
if (prev.getTaskRecord() != prevTask) {
prev = null;
}
// (2) The current activity is already displayed.
else if (prev.nowVisible) {
prev = null;
}
}
//r为ActivityRecord,直接调用showStartingWindow
r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity));
}
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
ActivityOptions.abort(options);
}
我们在这里分析是桌面启动一个应用的情况
2.1:ActivityRecord::showStartingWindow
void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
boolean fromRecents) {
if (mAppWindowToken == null) {
return;
}
if (mTaskOverlay) {
// We don't show starting window for overlay activities.
return;
}
if (pendingOptions != null
&& pendingOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
// Don't show starting window when using shared element transition.
return;
}
final CompatibilityInfo compatInfo =
mAtmService.compatibilityInfoForPackageLocked(info.applicationInfo);
final boolean shown = addStartingWindow(packageName, theme,
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
allowTaskSnapshot(),
mState.ordinal() >= RESUMED.ordinal() && mState.ordinal() <= STOPPED.ordinal(),
fromRecents);
if (shown) {
mStartingWindowState = STARTING_WINDOW_SHOWN;
}
}
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) {
..................................................
if (mAppWindowToken == null) {
Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + appToken);
return false;
}
if (mAppWindowToken.getTask() == null) {//不会为null,AppWindowToken被Task管理
return false;
}
return mAppWindowToken.addStartingWindow(pkg, theme, compatInfo, nonLocalizedLabel,
labelRes, icon, logo, windowFlags, transferFrom, newTask, taskSwitch,
processRunning, allowTaskSnapshot, activityCreated, fromRecents);
}
2.2:AppWindowToken::addStartingWindow
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) {
if (!okToDisplay()) {//还没准备好显示
return false;
}
if (mStartingData != null) {//如果之前已经有启动窗口的数据
return false;
}
final WindowState mainWin = findMainWindow();
if (mainWin != null && mainWin.mWinAnimator.getShown()) {
// App already has a visible window...why would you want a starting window?
return false;
}
final ActivityManager.TaskSnapshot snapshot =
mWmService.mTaskSnapshotController.getSnapshot(
getTask().mTaskId, 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);
}
if (theme != 0) {//主题,对应的activity的主题
AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
com.android.internal.R.styleable.Window,
mWmService.mCurrentUserId);
if (ent == null) {
// Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't
// see that.
return false;
}
final boolean windowIsTranslucent = ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowIsTranslucent, false);
final boolean windowIsFloating = ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowIsFloating, false);
final boolean windowShowWallpaper = ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowShowWallpaper, false);
final boolean windowDisableStarting = ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowDisablePreview, false);
if (windowIsTranslucent) {//如果是半透明
return false;
}
if (windowIsFloating || windowDisableStarting) {//如果是悬浮的或是禁止显示启动窗口
return false;
}
if (windowShowWallpaper) {//显示壁纸
if (getDisplayContent().mWallpaperController
.getWallpaperTarget() == null) {
windowFlags |= FLAG_SHOW_WALLPAPER;
} else {//表示的壁纸窗口已经被其他的目标窗口占用,则不显示
return false;
}
}
}
if (transferStartingWindow(transferFrom)) {
return true;
}
if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
return false;
}
//窗口启动数据
mStartingData = new SplashScreenStartingData(mWmService, pkg,
theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
getMergedOverrideConfiguration());
scheduleAddStartingWindow();//发送消息到android.anim线程对应的消息队列中
return true;
}
2.3:scheduleAddStartingWindow
void scheduleAddStartingWindow() {
if (!mWmService.mAnimationHandler.hasCallbacks(mAddStartingWindow)) {
mWmService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
}//放在消息对应的头部,mAnimationHandler对应的是android.anim线程
}
2.4:Runnable对象mAddStartingWindow
private final Runnable mAddStartingWindow = new Runnable() {
@Override
public void run() {
// Can be accessed without holding the global lock
final StartingData startingData;
synchronized (mWmService.mGlobalLock) {//同步锁
// There can only be one adding request, silly caller!
mWmService.mAnimationHandler.removeCallbacks(this);//消息队列中移除
if (mStartingData == null) {
// Animation has been canceled... do nothing.
return;
}
startingData = mStartingData;
}
WindowManagerPolicy.StartingSurface surface = null;
try {//创建一个surface绘图表面startingData是SplashScreenStartingData
surface = startingData.createStartingSurface(AppWindowToken.this);
} catch (Exception e) {
Slog.w(TAG, "Exception when adding starting window", e);
}
if (surface != null) {
boolean abort = false;
synchronized (mWmService.mGlobalLock) {
// If the window was successfully added, then
// we need to remove it.
if (removed || mStartingData == null) {
startingWindow = null;
mStartingData = null;
abort = true;
} else {
startingSurface = surface;
}
}
if (abort) {
surface.remove();
}
} else if (DEBUG_STARTING_WINDOW) {
Slog.v(TAG, "Surface returned was null: " + AppWindowToken.this);
}
}
};
2.5:SplashScreenStartingData::createStartingSurface
StartingSurface createStartingSurface(AppWindowToken atoken) {
return mService.mPolicy.addSplashScreen(atoken.token, mPkg, mTheme, mCompatInfo,
mNonLocalizedLabel, mLabelRes, mIcon, mLogo, mWindowFlags,
mMergedOverrideConfiguration, atoken.getDisplayContent().getDisplayId());
}
mPolicy数据类型是PhoneWindowManager
2.6:PhoneWindowManager::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) {
if (!SHOW_SPLASH_SCREENS) {
return null;
}
if (packageName == null) {//包名信息
return null;
}
WindowManager wm = null;
View view = null;
try {
Context context = mContext;
// Obtain proper context to launch on the right display.
final Context displayContext = getDisplayContext(context, displayId);
if (displayContext == null) {
// Can't show splash screen on requested display, so skip showing at all.
return null;
}
context = displayContext;
if (theme != context.getThemeResId() || labelRes != 0) {
try {
context = context.createPackageContext(packageName, CONTEXT_RESTRICTED);
context.setTheme(theme);
} catch (PackageManager.NameNotFoundException e) {
// Ignore
}
}
if (overrideConfig != null && !overrideConfig.equals(EMPTY)) {
final Context overrideContext = context.createConfigurationContext(overrideConfig);
overrideContext.setTheme(theme);
final TypedArray typedArray = overrideContext.obtainStyledAttributes(
com.android.internal.R.styleable.Window);
final int resId = typedArray.getResourceId(R.styleable.Window_windowBackground, 0);
if (resId != 0 && overrideContext.getDrawable(resId) != null) {
context = overrideContext;
}
typedArray.recycle();
}
final PhoneWindow win = new PhoneWindow(context);//创建一个PhoneWindow
win.setIsStartingWindow(true);
CharSequence label = context.getResources().getText(labelRes, null);
// Only change the accessibility title if the label is localized
if (label != null) {
win.setTitle(label, true);
} else {
win.setTitle(nonLocalizedLabel, false);
}
//窗口类型
win.setType(
WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
if (displayId == DEFAULT_DISPLAY && mKeyguardOccluded) {
windowFlags |= FLAG_SHOW_WHEN_LOCKED;//锁屏的时候显示
}
}
//窗口flag
win.setFlags(
windowFlags|
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
windowFlags|
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
win.setDefaultIcon(icon);
win.setDefaultLogo(logo);
win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT);
final WindowManager.LayoutParams params = win.getAttributes();
params.token = appToken;//appToken,共有activity的token
params.packageName = packageName;
params.windowAnimations = win.getWindowStyle().getResourceId(
com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
if (!compatInfo.supportsScreen()) {
params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
}
params.setTitle("Splash Screen " + packageName);
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;
} catch (WindowManager.BadTokenException e) {
} catch (RuntimeException e) {
Log.w(TAG, appToken + " failed creating starting window", e);
} finally {
if (view != null && view.getParent() == null) {
Log.w(TAG, "view not successfully added to wm, removing view");
wm.removeViewImmediate(view);
}
}
return null;
}
这个方法主要是创建一个PhoneWindow对象,然后设置一些窗口属性,最后将DecorView添加到窗口管理器
3:启动窗口的移除
我们都知道一个窗口既然被添加到窗口管理器了,那么肯定也有被销毁(移除)的时机,它移除的时机就是被启动的组件已经可见了,那么启动窗口就需要被移除,我们知道窗口只要有内容或是属性发生了变化都会触发更新,其更新都会调到WindowSurfacePlacer::performSurfacePlacement
3.1:performSurfacePlacement
final void performSurfacePlacement(boolean force) {
if (mDeferDepth > 0 && !force) {
return;
}
int loopCount = 6;
do {
mTraversalScheduled = false;
performSurfacePlacementLoop();
mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
loopCount--;
} while (mTraversalScheduled && loopCount > 0);
mService.mRoot.mWallpaperActionPending = false;
}
3.2:performSurfacePlacementLoop
private void performSurfacePlacementLoop() {
if (mInLayout) {
return;
}
// TODO(multi-display):
final DisplayContent defaultDisplay = mService.getDefaultDisplayContentLocked();
if (defaultDisplay.mWaitingForConfig) {
return;
}
if (!mService.mDisplayReady) {
// Not yet initialized, nothing to do.
return;
}
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
mInLayout = true;
boolean recoveringMemory = false;
if (!mService.mForceRemoves.isEmpty()) {
recoveringMemory = true;
// Wait a little bit for things to settle down, and off we go.
while (!mService.mForceRemoves.isEmpty()) {
final WindowState ws = mService.mForceRemoves.remove(0);
Slog.i(TAG, "Force removing: " + ws);
ws.removeImmediately();
}
Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
Object tmp = new Object();
synchronized (tmp) {
try {
tmp.wait(250);
} catch (InterruptedException e) {
}
}
}
try {
//mRoot是RootWindowContainer.java
mService.mRoot.performSurfacePlacement(recoveringMemory);
mInLayout = false;
if (mService.mRoot.isLayoutNeeded()) {
if (++mLayoutRepeatCount < 6) {
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);
}
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
3.3RootWindowContainer::performSurfacePlacement
void performSurfacePlacement(boolean recoveringMemory) {
try {
performSurfacePlacementNoTrace(recoveringMemory);
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
3.4:performSurfacePlacementNoTrace
void performSurfacePlacementNoTrace(boolean recoveringMemory) {
int i;
if (mWmService.mFocusMayChange) {//如果焦点窗口可能改变
mWmService.mFocusMayChange = false;
mWmService.updateFocusedWindowLocked(//更新焦点窗口
UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
}
final int numDisplays = mChildren.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final DisplayContent displayContent = mChildren.get(displayNdx);
displayContent.setExitingTokensHasVisible(false);
}
mHoldScreen = null;
mScreenBrightness = -1;
mUserActivityTimeout = -1;
mObscureApplicationContentOnSecondaryDisplays = false;
mSustainedPerformanceModeCurrent = false;
mWmService.mTransactionSequence++;
// TODO(multi-display): recents animation & wallpaper need support multi-display.
final DisplayContent defaultDisplay = mWmService.getDefaultDisplayContentLocked();
final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
mWmService.openSurfaceTransaction();
try {
//执行/应用surface改变事务
applySurfaceChangesTransaction(recoveringMemory);
} catch (RuntimeException e) {
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
} finally {
//关闭事务
mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
mWmService.mAnimator.executeAfterPrepareSurfacesRunnables();
checkAppTransitionReady(surfacePlacer);//检查app切换是否准备完毕
// Defer starting the recents animation until the wallpaper has drawn
final RecentsAnimationController recentsAnimationController =
mWmService.getRecentsAnimationController();
if (recentsAnimationController != null) {
recentsAnimationController.checkAnimationReady(defaultDisplay.mWallpaperController);
}
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final DisplayContent displayContent = mChildren.get(displayNdx);
if (displayContent.mWallpaperMayChange) {//壁纸窗口层级是否可能改变
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;//重新布局壁纸窗口
}
}
if (mWmService.mFocusMayChange) {
mWmService.mFocusMayChange = false;
mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
false /*updateInputWindows*/);
}
if (isLayoutNeeded()) {//是否需要重新layout
defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
handleResizingWindows();
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.
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();
win.mWinAnimator.destroyPreservedSurfaceLocked();
} while (i > 0);
mWmService.mDestroySurface.clear();
}
// Time to remove any exiting tokens?
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final DisplayContent displayContent = mChildren.get(displayNdx);
displayContent.removeExistingTokensIfPossible();
}
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final DisplayContent displayContent = mChildren.get(displayNdx);
if (displayContent.pendingLayoutChanges != 0) {
displayContent.setLayoutNeeded();
}
}
mWmService.setHoldScreenLocked(mHoldScreen);
if (!mWmService.mDisplayFrozen) {
final int brightness = mScreenBrightness < 0 || mScreenBrightness > 1.0f
? -1 : toBrightnessOverride(mScreenBrightness);
mHandler.obtainMessage(SET_SCREEN_BRIGHTNESS_OVERRIDE, brightness, 0).sendToTarget();
mHandler.obtainMessage(SET_USER_ACTIVITY_TIMEOUT, mUserActivityTimeout).sendToTarget();
}
if (mSustainedPerformanceModeCurrent != mSustainedPerformanceModeEnabled) {
mSustainedPerformanceModeEnabled = mSustainedPerformanceModeCurrent;
mWmService.mPowerManagerInternal.powerHint(
PowerHint.SUSTAINED_PERFORMANCE,
(mSustainedPerformanceModeEnabled ? 1 : 0));
}
if (mUpdateRotation) {
if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
mUpdateRotation = updateRotationUnchecked();
}
if (mWmService.mWaitingForDrawnCallback != null
|| (mOrientationChangeComplete && !isLayoutNeeded()
&& !mUpdateRotation)) {
mWmService.checkDrawnWindowsLocked();
}
final int N = mWmService.mPendingRemove.size();
if (N > 0) {
if (mWmService.mPendingRemoveTmp.length < N) {
mWmService.mPendingRemoveTmp = new WindowState[N + 10];
}
mWmService.mPendingRemove.toArray(mWmService.mPendingRemoveTmp);
mWmService.mPendingRemove.clear();
ArrayList<DisplayContent> displayList = new ArrayList();
for (i = 0; i < N; i++) {
final WindowState w = mWmService.mPendingRemoveTmp[i];
w.removeImmediately();
final DisplayContent displayContent = w.getDisplayContent();
if (displayContent != null && !displayList.contains(displayContent)) {
displayList.add(displayContent);
}
}
for (int j = displayList.size() - 1; j >= 0; --j) {
final DisplayContent dc = displayList.get(j);
dc.assignWindowLayers(true /*setLayoutNeeded*/);
}
}
// Remove all deferred displays stacks, tasks, and activities.
for (int displayNdx = mChildren.size() - 1; displayNdx >= 0; --displayNdx) {
mChildren.get(displayNdx).checkCompleteDeferredRemoval();
}
forAllDisplays(dc -> {
dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
dc.updateSystemGestureExclusion();
dc.updateTouchExcludeRegion();
});
// Check to see if we are now in a state where the screen should
// be enabled, because the window obscured flags have changed.
mWmService.enableScreenIfNeededLocked();//屏幕使能
mWmService.scheduleAnimationLocked();//准备开启动画
}
3.5:applySurfaceChangesTransaction
private void applySurfaceChangesTransaction(boolean recoveringMemory) {
mHoldScreenWindow = null;
mObscuringWindow = null;
// TODO(multi-display): Support these features on secondary screens.
final DisplayContent defaultDc = mWmService.getDefaultDisplayContentLocked();
final DisplayInfo defaultInfo = defaultDc.getDisplayInfo();
final int defaultDw = defaultInfo.logicalWidth;
final int defaultDh = defaultInfo.logicalHeight;
if (mWmService.mWatermark != null) {
mWmService.mWatermark.positionSurface(defaultDw, defaultDh);
}
if (mWmService.mStrictModeFlash != null) {
mWmService.mStrictModeFlash.positionSurface(defaultDw, defaultDh);
}
if (mWmService.mCircularDisplayMask != null) {
mWmService.mCircularDisplayMask.positionSurface(defaultDw, defaultDh,
mWmService.getDefaultDisplayRotation());
}
if (mWmService.mEmulatorDisplayOverlay != null) {
mWmService.mEmulatorDisplayOverlay.positionSurface(defaultDw, defaultDh,
mWmService.getDefaultDisplayRotation());
}
final int count = mChildren.size();
for (int j = 0; j < count; ++j) {
final DisplayContent dc = mChildren.get(j);
dc.applySurfaceChangesTransaction(recoveringMemory);
}
mWmService.mDisplayManagerInternal.performTraversal(mDisplayTransaction);
SurfaceControl.mergeToGlobalTransaction(mDisplayTransaction);
}
3.6:applySurfaceChangesTransaction
void applySurfaceChangesTransaction(boolean recoveringMemory) {
final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
mTmpUpdateAllDrawn.clear();
int repeats = 0;
do {
repeats++;
if (repeats > 6) {
Slog.w(TAG, "Animation repeat aborted after too many iterations");
clearLayoutNeeded();
break;
}
if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
mWallpaperController.adjustWallpaperWindows();//调整壁纸窗口
}
if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
if (updateOrientationFromAppTokens()) {//如果应用要求改变显示方向
setLayoutNeeded();//重新布局
sendNewConfiguration();//设置新的配置
}
}
if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
setLayoutNeeded();
}
// FIRST LOOP: Perform a layout, if needed.
if (repeats < LAYOUT_REPEAT_THRESHOLD) {
performLayout(repeats == 1, false /* updateInputWindows */);
} else {
Slog.w(TAG, "Layout repeat skipped after too many iterations");
}
pendingLayoutChanges = 0;
try {
mDisplayPolicy.beginPostLayoutPolicyLw();
forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
pendingLayoutChanges |= mDisplayPolicy.finishPostLayoutPolicyLw();
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
mInsetsStateController.onPostLayout();
} while (pendingLayoutChanges != 0);
mTmpApplySurfaceChangesTransactionState.reset();
mTmpRecoveringMemory = recoveringMemory;
try {
forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);//重点
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
prepareSurfaces();
mLastHasContent = mTmpApplySurfaceChangesTransactionState.displayHasContent;
mWmService.mDisplayManagerInternal.setDisplayProperties(mDisplayId,
mLastHasContent,
mTmpApplySurfaceChangesTransactionState.preferredRefreshRate,
mTmpApplySurfaceChangesTransactionState.preferredModeId,
true /* inTraversal, must call performTraversalInTrans... below */);
final boolean wallpaperVisible = mWallpaperController.isWallpaperVisible();
if (wallpaperVisible != mLastWallpaperVisible) {
mLastWallpaperVisible = wallpaperVisible;
mWmService.mWallpaperVisibilityListeners.notifyWallpaperVisibilityChanged(this);
}
while (!mTmpUpdateAllDrawn.isEmpty()) {
final AppWindowToken atoken = mTmpUpdateAllDrawn.removeLast();
atoken.updateAllDrawn();
}
}
3.7:mApplySurfaceChangesTransaction
private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
final boolean obscuredChanged = w.mObscured !=
mTmpApplySurfaceChangesTransactionState.obscured;
final RootWindowContainer root = mWmService.mRoot;
// Update effect.
w.mObscured = mTmpApplySurfaceChangesTransactionState.obscured;
if (!mTmpApplySurfaceChangesTransactionState.obscured) {
final boolean isDisplayed = w.isDisplayedLw();
if (isDisplayed && w.isObscuringDisplay()) {
// This window completely covers everything behind it, so we want to leave all
// of them as undimmed (for performance reasons).
root.mObscuringWindow = w;
mTmpApplySurfaceChangesTransactionState.obscured = true;
}
mTmpApplySurfaceChangesTransactionState.displayHasContent |=
root.handleNotObscuredLocked(w,
mTmpApplySurfaceChangesTransactionState.obscured,
mTmpApplySurfaceChangesTransactionState.syswin);
if (w.mHasSurface && isDisplayed) {
final int type = w.mAttrs.type;
if (type == TYPE_SYSTEM_DIALOG || type == TYPE_SYSTEM_ERROR
|| (w.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
mTmpApplySurfaceChangesTransactionState.syswin = true;
}
if (mTmpApplySurfaceChangesTransactionState.preferredRefreshRate == 0
&& w.mAttrs.preferredRefreshRate != 0) {
mTmpApplySurfaceChangesTransactionState.preferredRefreshRate
= w.mAttrs.preferredRefreshRate;
}
final int preferredModeId = getDisplayPolicy().getRefreshRatePolicy()
.getPreferredModeId(w);
if (mTmpApplySurfaceChangesTransactionState.preferredModeId == 0
&& preferredModeId != 0) {
mTmpApplySurfaceChangesTransactionState.preferredModeId = preferredModeId;
}
}
}
if (obscuredChanged && w.isVisibleLw() && mWallpaperController.isWallpaperTarget(w)) {
mWallpaperController.updateWallpaperVisibility();
}
w.handleWindowMovedIfNeeded();
final WindowStateAnimator winAnimator = w.mWinAnimator;
w.resetContentChanged();
if (w.mHasSurface) {
final boolean committed = winAnimator.commitFinishDrawingLocked();
if (isDefaultDisplay && committed) {
if (w.mAttrs.type == TYPE_DREAM) {
pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
}
if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
mWallpaperMayChange = true;
pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
}
}
final AppWindowToken atoken = w.mAppToken;
if (atoken != null) {
atoken.updateLetterboxSurface(w);
final boolean updateAllDrawn = atoken.updateDrawnWindowStates(w);
if (updateAllDrawn && !mTmpUpdateAllDrawn.contains(atoken)) {
mTmpUpdateAllDrawn.add(atoken);
}
}
if (!mLosingFocus.isEmpty() && w.isFocused() && w.isDisplayedLw()) {
mWmService.mH.obtainMessage(REPORT_LOSING_FOCUS, this).sendToTarget();
}
w.updateResizingWindowIfNeeded();
};
3.8: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.canShowWindows()
|| mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
result = mWin.performShowLocked();
}
return result;
}
3.9:performShowLocked
boolean performShowLocked() {
if (isHiddenFromUserLocked()) {
clearPolicyVisibilityFlag(VISIBLE_FOR_USER);
return false;
}
logPerformShow("performShow on ");
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 ");
mWmService.enableScreenIfNeededLocked();//屏幕使能
mWinAnimator.applyEnterAnimationLocked();//执行进入动画
mWinAnimator.mLastAlpha = -1;
mWinAnimator.mDrawState = HAS_DRAWN;
mWmService.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();
}
}
}
}
if (mAttrs.type == TYPE_INPUT_METHOD) {
getDisplayContent().mDividerControllerLocked.resetImeHideRequested();
}
return true;
}
3.10:onFirstWindowDrawn
void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
firstWindowDrawn = true;
// We now have a good window to show, remove dead placeholders
removeDeadWindows();
if (startingWindow != null) {
win.cancelAnimation();//取消动画播放
}
removeStartingWindow();//移除启动窗口
updateReportedVisibilityLocked();//更新上报可见性
}
3.11:removeStartingWindow
void removeStartingWindow() {
if (startingWindow == null) {
if (mStartingData != null) {
mStartingData = null;
}
return;
}
final WindowManagerPolicy.StartingSurface surface;
if (mStartingData != null) {
surface = startingSurface;
mStartingData = null;
startingSurface = null;
startingWindow = null;
startingDisplayed = false;
if (surface == null) {
return;
}
} else {
return;
}
mWmService.mAnimationHandler.post(() -> {
try {
surface.remove();//surface是SplashScreenSurface
} catch (Exception e) {
Slog.w(TAG_WM, "Exception when removing starting window", e);
}
});
}
3.12:remove
@Override
public void remove() {
final WindowManager wm = mView.getContext().getSystemService(WindowManager.class);
wm.removeView(mView);//直接移除DecorView
}
我们从上面可以看到启动窗口的添加和移除是在android.anim线程中完成,添加的逻辑主要是创建一个PhoneWindow,然后将PhoneWindow的DecorView添加到窗口管理器,移除则是直接removeDecorView来完成的