Android 应用冷启动窗口(Splash Screen)的创建与销毁流程,涵盖从 ActivityManagerService(AMS)到 WindowManagerService(WMS)的完整交互过程:
一、冷启动窗口的核心作用
冷启动窗口是 Android 在应用冷启动时显示的预览窗口 ,其目的是:
减少用户感知延迟 :在应用进程创建和界面绘制完成前,显示一个临时界面(如 Logo 或主题背景)。
避免白屏/黑屏 :防止用户看到未初始化的空白界面。
兼容性控制 :通过统一的 API 管理启动窗口的生命周期。
二、冷启动窗口的创建流程
- AMS 触发应用启动
当用户点击应用图标时,ActivityManagerService 会通过 startActivity() 启动目标 Activity:
java
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public final int startActivity(...) {
// 调用 startActivityMayWait 处理启动请求
return startActivityMayWait(...);
}
关键逻辑:
如果应用进程未启动,AMS 会调用 startProcessLocked() 请求 Zygote 创建新进程。
在进程创建前,AMS 会通过 WMS 预先创建启动窗口。
- WMS 创建启动窗口
AMS 通过 IWindowManager 接口请求 WMS 创建启动窗口:
java
// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public void addAppToken(...) {
// 创建启动窗口(Splash Screen)
createSplashScreenWindow(appToken, info, windowingMode, requestedOrientation);
}
调用链:
AMS.realStartActivityLocked()
→ WMS.addAppToken()
→ WMS.createSplashScreenWindow()
核心代码:
java
// frameworks/base/services/core/java/com/android/server/wm/SplashScreenWindow.java
private void createSplashScreenWindow(...) {
// 1. 加载应用的主题样式(来自 AndroidManifest.xml)
final int theme = info.resolveThemeResId();
// 2. 创建 SurfaceControl(用于绘制窗口)
mSurfaceControl = new SurfaceControl.Builder()
.setName("Splash Screen")
.setParent(rootSurfaceControl)
.build();
java
// 3. 设置窗口属性(如背景、动画)
java
final WindowState windowState = new WindowState(this, session, client, token, type, displayContent);
windowState.setWindowAnimations(...); // 设置启动动画
windowState.setDimmingEnabled(false); // 禁用暗化效果
}
关键数据结构:
AppWindowToken :AMS 为每个 Activity 分配的令牌(Token),用于标识应用窗口。
SplashScreenWindow :WMS 中管理启动窗口的类,负责窗口的创建和销毁。
- 启动窗口的显示
WMS 将启动窗口添加到 DisplayContent 的窗口层级中。
SurfaceFlinger 将窗口合成到屏幕显示:
java
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::handleTransactionLocked(...) {
// 合成所有窗口并更新屏幕
rebuildLayerStacks();
}
三、冷启动窗口的销毁流程
- 应用进程完成绘制
应用进程启动后,ActivityThread 会执行 handleLaunchActivity():
java
// frameworks/base/core/java/android/app/ActivityThread.java
private void handleLaunchActivity(...) {
// 1. 创建 Context 和 Activity
Activity a = performLaunchActivity(...);
// 2. 执行 Activity.onCreate() 和 setContentView()
a.onCreate(...);
// 3. 报告界面绘制完成
WindowManagerGlobal.getInstance().reportDrawn();
}
核心逻辑:
通过 ViewRootImpl 向 WMS 报告界面已绘制完成:
java
// frameworks/base/core/java/android/view/ViewRootImpl.java
public void reportDrawn() {
mWindowSession.finishDrawing(mWindow);
}
- WMS 销毁启动窗口
WMS 收到 finishDrawing() 请求后,会移除启动窗口:
java
// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public void finishDrawingWindow(WindowState windowState) {
// 1. 移除启动窗口
windowState.removeSplashScreen();
// 2. 通知 AMS 应用已就绪
mActivityManager.notifyAppTransitionFinished();
}
销毁逻辑详解:
移除 SurfaceControl :释放启动窗口占用的图形资源。
触发动画结束 :如果启动窗口有退出动画,WMS 会执行动画并延迟销毁窗口。
更新窗口层级 :重新计算窗口层级(Z-Order),确保主 Activity 窗口显示在前台。
- AMS 清理启动状态
AMS 收到通知后,会清理冷启动标记:
java
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void notifyAppTransitionFinished(...) {
// 清除冷启动窗口标记
app.getWindowProcessController().setHasShownSplashScreen(true);
}
四、冷启动窗口的样式与资源加载
- 主题配置(Android 12+)
从 Android 12 开始,冷启动窗口由 SplashScreen API 控制:
XML
<!-- AndroidManifest.xml -->
<activity
android:theme="@style/AppTheme.SplashScreen">
...
</activity>
样式定义:
XML
<!-- res/values/styles.xml -->
<style name="AppTheme.SplashScreen" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/splash_background</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/splash_icon</item>
<item name="postSplashScreenTheme">@style/AppTheme.NoActionBar</item>
</style>
- 旧版本兼容方案
在 Android 11 及以下版本,冷启动窗口通过 Theme.AppCompat.Light.NoActionBar 等主题模拟实现。
五、代码流程图
用户点击应用图标
↓
AMS.startActivity() → AMS.startProcessLocked()
↓
WMS.createSplashScreenWindow() → 加载主题样式,创建SurfaceControl
↓
SurfaceFlinger 合成窗口 → 显示启动界面
↓
应用进程启动 → ActivityThread.handleLaunchActivity()
↓
ViewRootImpl.reportDrawn() → WMS.finishDrawingWindow()
↓
WMS.removeSplashScreen() → 销毁SurfaceControl,触发动画结束
↓
AMS.notifyAppTransitionFinished() → 清理冷启动状态
六、关键代码路径与调试技巧
- 核心代码路径
模块 文件路径
AMS 启动流程 frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
WMS 窗口管理 frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
启动窗口实现 frameworks/base/services/core/java/com/android/server/wm/SplashScreenWindow.java
应用端绘制完成通知 frameworks/base/core/java/android/view/ViewRootImpl.java
- 调试方法
查看窗口层级 :
adb shell dumpsys window windows | grep -i "splash"
强制关闭冷启动窗口 (测试用途):
adb shell am set-debug-app --wait <package_name>
日志跟踪 :
adb logcat -s "WindowManager" "ActivityManager"
七、Android 12+ 的 Splash Screen API 变化
从 Android 12 开始,冷启动窗口由 SplashScreen 类统一管理:
java
// 应用端代码(Java/Kotlin)
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// 1. 安装 Splash Screen
installSplashScreen()
super.onCreate(savedInstanceState)
// 2. 设置主界面内容
setContentView(R.layout.activity_main)
}
}
新特性:
动画控制 :支持自定义启动动画(如图标旋转)。
延迟关闭 :通过 setKeepOnScreenCondition() 控制窗口关闭时机。
资源隔离 :启动窗口与主界面使用不同的 Theme,避免资源冲突。
八、总结
|----|------------------------|-------------------------------------|
| 阶段 | 核心组件 | 关键操作 |
| 创建 | ActivityManagerService | 请求启动应用进程,触发 WMS 创建冷启动窗口 |
| 创建 | WindowManagerService | 加载应用主题样式,创建 SurfaceControl 并添加到窗口层级 |
| 销毁 | ActivityThread | 完成界面绘制后调用 reportDrawn() 通知 WMS |
| 销毁 | WindowManagerService | 移除冷启动窗口,触发动画结束,释放 Surface 资源 |
| 销毁 | ActivityManagerService | 清理冷启动状态,标记应用为"已就绪" |