接着ATMS启动Activity流程中frameworks/base/services/core/java/com/android/server/wm/ActivityStack.java的startActivityLocked方法中调用了frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java的showStartingWindow方法:
void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch) {
......
final boolean shown = addStartingWindow(packageName, theme,
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
allowTaskSnapshot(),
mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal());
if (shown) {
mStartingWindowState = STARTING_WINDOW_SHOWN;
}
}
调用了ActivityRecord的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) {
......
final ActivityManager.TaskSnapshot snapshot =
mWmService.mTaskSnapshotController.getSnapshot(task.mTaskId, task.mUserId,
false /* restoreFromDisk */, false /* isLowResolution */);
final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
allowTaskSnapshot, activityCreated, snapshot);
if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
......
return createSnapshot(snapshot);
}
......
// There is no existing starting window, and we don't want to create a splash screen, so
// that's it!
if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
return false;
}
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SplashScreenStartingData");
mStartingData = new SplashScreenStartingData(mWmService, pkg,
theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
getMergedOverrideConfiguration());
scheduleAddStartingWindow();
return true;
}
这里的type主要有两种情况,分别是STARTING_WINDOW_TYPE_SNAPSHOT和STARTING_WINDOW_TYPE_SPLASH_SCREEN。
如果是STARTING_WINDOW_TYPE_SNAPSHOT,则调用了ActivityRecord的createSnapshot方法:
private boolean createSnapshot(ActivityManager.TaskSnapshot snapshot) {
......
mStartingData = new SnapshotStartingData(mWmService, snapshot);
scheduleAddStartingWindow();
return true;
}
创建了SnapshotStartingData对象mStartingData,最后调用了ActivityRecord的scheduleAddStartingWindow方法。
回到ActivityRecord的addStartingWindow方法中,如果是STARTING_WINDOW_TYPE_SPLASH_SCREEN,则创建了SplashScreenStartingData对象mStartingData,最后也调用了ActivityRecord的scheduleAddStartingWindow方法:
void scheduleAddStartingWindow() {
// Note: we really want to do sendMessageAtFrontOfQueue() because we
// want to process the message ASAP, before any other queued
// messages.
if (!mWmService.mAnimationHandler.hasCallbacks(mAddStartingWindow)) {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Enqueueing ADD_STARTING");
mWmService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
}
}
通过mWmService.mAnimationHandler.postAtFrontOfQueue切换到动画线程调用了ActivityRecord的成员变量mAddStartingWindow的run方法:
private class AddStartingWindow implements Runnable {
@Override
public void run() {
......
WindowManagerPolicy.StartingSurface surface = null;
try {
surface = startingData.createStartingSurface(ActivityRecord.this);
} catch (Exception e) {
Slog.w(TAG, "Exception when adding starting window", e);
}
......
}
}
这里调用了之前创建的startingData的createStartingSurface方法,如果是SnapshotStartingData,则调用了frameworks/base/services/core/java/com/android/server/wm/SnapshotStartingData.java的createStartingSurface方法:
@Override
StartingSurface createStartingSurface(ActivityRecord activity) {
return mService.mTaskSnapshotController.createStartingSurface(activity, mSnapshot);
}
调用了frameworks/base/services/core/java/com/android/server/wm/TaskSnapshotController.java的createStartingSurface方法:
/**
* Creates a starting surface for {@param token} with {@param snapshot}. DO NOT HOLD THE WINDOW
* MANAGER LOCK WHEN CALLING THIS METHOD!
*/
StartingSurface createStartingSurface(ActivityRecord activity,
TaskSnapshot snapshot) {
return TaskSnapshotSurface.create(mService, activity, snapshot);
}
调用了frameworks/base/services/core/java/com/android/server/wm/TaskSnapshotSurface.java的create方法:
static TaskSnapshotSurface create(WindowManagerService service, ActivityRecord activity,
TaskSnapshot snapshot) {
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
final Window window = new Window();
final IWindowSession session = WindowManagerGlobal.getWindowSession();
window.setSession(session);
final SurfaceControl surfaceControl = new SurfaceControl();
......
try {
final int res = session.addToDisplay(window, window.mSeq, layoutParams,
View.GONE, activity.getDisplayContent().getDisplayId(), tmpFrame, tmpRect,
tmpRect, tmpCutout, null, mTmpInsetsState, mTempControls);
if (res < 0) {
Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
return null;
}
} catch (RemoteException e) {
// Local call.
}
final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, sysUiVis,
windowFlags, windowPrivateFlags, taskBounds, currentOrientation, activityType,
insetsState);
window.setOuter(snapshotSurface);
try {
session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1,
tmpFrame, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect,
tmpCutout, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
mTempControls, sTmpSurfaceSize, sTmpSurfaceControl);
} catch (RemoteException e) {
// Local call.
}
final Rect systemBarInsets = getSystemBarInsets(tmpFrame, insetsState);
snapshotSurface.setFrames(tmpFrame, systemBarInsets);
snapshotSurface.drawSnapshot();
return snapshotSurface;
}
通过session.addToDisplay创建了显示窗口(此流程具体见View的添加流程),并创建了TaskSnapshotSurface对象,存放了显示窗口相关信息。
回到ActivityRecord的成员变量mAddStartingWindow的run方法中,如果startingData是SplashScreenStartingData,则调用了frameworks/base/services/core/java/com/android/server/wm/SplashScreenStartingData.java的createStartingSurface方法:
@Override
StartingSurface createStartingSurface(ActivityRecord activity) {
return mService.mPolicy.addSplashScreen(activity.token, mPkg, mTheme, mCompatInfo,
mNonLocalizedLabel, mLabelRes, mIcon, mLogo, mWindowFlags,
mMergedOverrideConfiguration, activity.getDisplayContent().getDisplayId());
}
调用了frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java的addSplashScreen方法:
/** {@inheritDoc} */
@Override
public StartingSurface addSplashScreen(IBinder appToken, int userId, String packageName,
int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
int icon, int logo, int windowFlags, Configuration overrideConfig, int displayId) {
......
WindowManager wm = null;
View view = null;
try {
......
final PhoneWindow win = new PhoneWindow(context);
win.setIsStartingWindow(true);
......
params.setTitle("Splash Screen " + packageName);
addSplashscreenContent(win, context);
wm = (WindowManager) context.getSystemService(WINDOW_SERVICE);
view = win.getDecorView();
if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "Adding splash screen window for "
+ packageName + " / " + appToken + ": " + (view.getParent() != null ? view : null));
wm.addView(view, params);
// Only return the view if it was successfully added to the
// window manager... which we can tell by it having a parent.
return view.getParent() != null ? new SplashScreenSurface(view, appToken) : null;
} catch (WindowManager.BadTokenException e) {
// ignore
Log.w(TAG, appToken + " already running, starting window not displayed. " +
e.getMessage());
} catch (RuntimeException e) {
// don't crash if something else bad happens, for example a
// failure loading resources because we are loading from an app
// on external storage that has been unmounted.
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;
}
通过wm.addView创建显示窗口(此流程具体见View的添加流程),并创建了SplashScreenSurface对象,存放了显示窗口相关信息。
StartingWindow后面是怎样销毁的见StartingWindow销毁流程。
总结
1 StartingWindow分为2种,分别是STARTING_WINDOW_TYPE_SNAPSHOT和STARTING_WINDOW_TYPE_SPLASH_SCREEN。
2 STARTING_WINDOW_TYPE_SNAPSHOT一般显示的是Activity之前的一张截图,如果Activity是secure的,则会显示的内容根据其theme绘制。
3 STARTING_WINDOW_TYPE_SPLASH_SCREEN显示的内容根据Activity的theme绘制。
本文详细解析了Android系统中StartingWindow的工作机制,包括STARTING_WINDOW_TYPE_SNAPSHOT与STARTING_WINDOW_TYPE_SPLASH_SCREEN两种类型的区别及实现流程。通过跟踪源码,介绍了不同类型的StartingWindow如何创建、显示以及涉及的主要类和方法。
2026

被折叠的 条评论
为什么被折叠?



