上次有跟踪过Android的Launcher启动和startActivity的源码分析(看文末链接,部分内容比较旧了),这次简单记录一下Android开机动画退出的源码分析。
因为Launcher启动完成且空闲后会通知系统退出开机动画。
借力AI分析源码,很准的,只要自己了解跳转流程。
正文
进入正题。
我们知道Launcher就是作为第一个可跟用户交互的App,第一次开机后先启动进程,然后启动Activity,我们知道,当我们可见Activity时是onResume()阶段。
ActivityThread.java
frameworks\base\core\java\android\app\ActivityThread.javahandleResumeActivity()
@Override public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest, boolean isForward, String reason) { //略 if (r.window == null && !a.mFinished && willBeVisible) { r.window = r.activity.getWindow(); View decor = r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); ViewManager wm = a.getWindowManager(); WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; if (r.mPreserveWindow) { a.mWindowAdded = true; r.mPreserveWindow = false; ViewRootImpl impl = decor.getViewRootImpl(); if (impl != null) { impl.notifyChildRebuilt(); } } if (a.mVisibleFromClient) { if (!a.mWindowAdded) { a.mWindowAdded = true; //添加decor wm.addView(decor, l); } else { a.onWindowAttributesChanged(l); } } } else if (!willBeVisible) { r.hideForNow = true; } //略 r.nextIdle = mNewActivities; //这里赋值,不为null,下面Idler中要用 mNewActivities = r; //【关注点】 //1. 创建Idler对象 //2. 添加到消息队列中 Looper.myQueue().addIdleHandler(new Idler()); }
从上面可以知道
decor添加到wm
Looper.myQueue().addIdleHandler(new Idler())
第二个比较重要,添加一个Idler对象。
Idler
private class Idler implements MessageQueue.IdleHandler { @Override public final boolean queueIdle() { //上面赋值了,不为null ActivityClientRecord a = mNewActivities; //略 if (a != null) { mNewActivities = null; final ActivityClient ac = ActivityClient.getInstance(); ActivityClientRecord prev; do { if (a.activity != null && !a.activity.mFinished) { //进入这里,调用ActivityClient中的activityIdle ac.activityIdle(a.token, a.createdConfig, stopProfiling); a.createdConfig = null; } prev = a; a = a.nextIdle; prev.nextIdle = null; } while (a != null); } if (stopProfiling) { mProfiler.stopProfiling(); } return false; } }
Idler实现于MessageQueue.IdleHandler,实现了queueIdle方法。
public static interface IdleHandler { boolean queueIdle(); }
把Idler对象添加到消息队列中,然后会执行MessageQueue.next() ,这里只看部分
@UnsupportedAppUsage Message next() { //略 for (;;) { for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler boolean keep = false; try { //这里调用了queueIdle() keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf(TAG, "IdleHandler threw exception", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } //略 } }
ActivityClient.java
frameworks\base\core\java\android\app\ActivityClient.javaactivityIdle()
/** Reports the main thread is idle after the activity is resumed. */ public void activityIdle(IBinder token, Configuration config, boolean stopProfiling) { try { getActivityClientController().activityIdle(token, config, stopProfiling); } catch (RemoteException e) { e.rethrowFromSystemServer(); } }
看getActivityClientController()返回值
getActivityClientController()
private static IActivityClientController getActivityClientController() { final IActivityClientController controller = INTERFACE_SINGLETON.mKnownInstance; return controller != null ? controller : INTERFACE_SINGLETON.get(); }
返回ActivityClientController的对象。
具体细节这里不展开
ActivityClientController.java
frameworks\base\services\core\java\com\android\server\wm\ActivityClientController.java
activityIdle()
@Override
public void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityIdle");
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r == null) {
return;
}
//这里
mTaskSupervisor.activityIdleInternal(r, false /* fromTimeout */,
false /* processPausingActivities */, config);
//略
}
} finally {
//略
}
}mTaskSupervisor是ActivityTaskSupervisor对象
private final ActivityTaskSupervisor mTaskSupervisor;
ActivityTaskSupervisor.java
frameworks\base\services\core\java\com\android\server\wm\ActivityTaskSupervisor.java
activityIdleInternal()
void activityIdleInternal(ActivityRecord r, boolean fromTimeout,
boolean processPausingActivities, Configuration config) {
if (r != null) {
mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
//略
// 标记该 Activity 已进入空闲状态
r.idle = true;
// 判断条件:系统正在启动 & 所有 Resumed Activity 均已空闲 || 超时兜底
if ((mService.isBooting() && mRootWindowContainer.allResumedActivitiesIdle())
|| fromTimeout) {
checkFinishBootingLocked();
}
r.mRelaunchReason = RELAUNCH_REASON_NONE;
}
//略
}checkFinishBootingLocked()
/**
* Called when all resumed tasks/root-tasks are idle.
*/
@GuardedBy("mService")
private void checkFinishBootingLocked() {
final boolean booting = mService.isBooting();
boolean enableScreen = false;
mService.setBooting(false);
if (!mService.isBooted()) {
mService.setBooted(true);
enableScreen = true;
}
//enableScreen为true,满足条件
if (booting || enableScreen为true,满足条件) {
//重点
mService.postFinishBooting(booting, enableScreen);
}
}重点关注postFinishBooting
final ActivityTaskManagerService mService;
ActivityTaskManagerService.java
frameworks\base\services\core\java\com\android\server\wm\ActivityTaskManagerService.java
void postFinishBooting(boolean finishBooting, boolean enableScreen) {
mH.post(() -> {
if (finishBooting) {
//ActivityManagerInternal mAmInternal;
mAmInternal.finishBooting();
}
if (enableScreen) {
//final ActivityTaskManagerInternal mInternal;
mInternal.enableScreenAfterBoot(isBooted());
}
});
}下面分别介绍一下mAmInternal和mInternal
ActivityManagerInternal mAmInternal; mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
ActivityManagerInternal是一个抽象类,其实现是ActivityManagerService.java中的LocalService
public final class LocalService extends ActivityManagerInternal
implements ActivityManagerLocal {
//略
@Override
public void finishBooting() {
//调用ActivityManagerService中的
ActivityManagerService.this.finishBooting();
}
//略
}下面看
final ActivityTaskManagerInternal mInternal; mInternal = new LocalService();
其LocalService为ActivityTaskManagerService.java中的
final class LocalService extends ActivityTaskManagerInternal {
//略
@Override
public void enableScreenAfterBoot(boolean booted) {
writeBootProgressEnableScreen(SystemClock.uptimeMillis());
mWindowManager.enableScreenAfterBoot();
synchronized (mGlobalLock) {
updateEventDispatchingLocked(booted);
}
}
//略
}一个一个看,先看mAmInternal然后mInternal
ActivityManagerService.java
frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
根据上面
ActivityManagerService.this.finishBooting();
直接看finishBooting()
finishBooting()
/**
* 系统启动流程的最终阶段:
* 当开机动画结束、系统核心服务就绪后,AMS 在此完成启动收尾工作。
*
* 主要职责:
* 1. 等待 boot animation 真正完成
* 2. 通知 ART / Zygote 启动完成
* 3. 注册关键广播监听
* 4. 通知 StorageManager / SystemServiceManager
* 5. 启动被挂起的进程
* 6. 设置 boot_completed 系统属性
* 7. 发送 BOOT_COMPLETED 相关广播
*/
final void finishBooting() {
synchronized (this) {
// 如果开机动画还没结束,先标记“需要补调用 finishBooting”
// 等动画结束后再真正执行后续逻辑
if (!mBootAnimationComplete) {
mCallFinishBooting = true;
t.traceEnd();
return;
}
// 动画已完成,清除标记
mCallFinishBooting = false;
}
// ==================== 通知运行时 ====================
// 告诉 Zygote 和系统 Server 的 ART 虚拟机:系统启动完成
// 用于触发 JIT 编译、堆整理、预加载优化等
ZYGOTE_PROCESS.bootCompleted();
VMRuntime.bootCompleted();
// ==================== 注册包重启查询广播 ====================
// 用于判断某个 package 是否可以被安全地 force-stop
// 例如:ANR / 低内存清理前做安全检查
IntentFilter pkgFilter = new IntentFilter();
pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
pkgFilter.addDataScheme("package");
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String[] pkgs = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
if (pkgs != null) {
for (String pkg : pkgs) {
synchronized (ActivityManagerService.this) {
// 如果包可以被 force-stop,则返回 OK
if (forceStopPackageLocked(pkg, -1, false, false, false, false, false,
0, "query restart")) {
setResultCode(Activity.RESULT_OK);
return;
}
}
}
}
}
}, pkgFilter);
// ==================== 存储 Checkpoint 提交 ====================
// 用于 FBE(文件级加密)或 A/B 更新后的数据一致性保障
try {
Slog.i(TAG, "About to commit checkpoint");
IStorageManager storageManager = InstallLocationUtils.getStorageManager();
storageManager.commitChanges();
} catch (Exception e) {
// 如果提交失败,直接重启设备以保证数据安全
PowerManager pm = (PowerManager)
mInjector.getContext().getSystemService(Context.POWER_SERVICE);
pm.reboot("Checkpoint commit failed");
}
// ==================== 通知所有 SystemService ====================
// 触发 PHASE_BOOT_COMPLETED
// 各服务(WMS / PMS / PKMS 等)在此阶段完成最后初始化
Slog.w(TAG, "finishBooting PHASE_BOOT_COMPLETED : ");
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_BOOT_COMPLETED);
synchronized (this) {
// ==================== 启动被挂起的进程 ====================
// 某些进程在启动早期被放入 mProcessesOnHold
// 现在统一批量启动
final int NP = mProcessesOnHold.size();
if (NP > 0) {
ArrayList<ProcessRecord> procs = new ArrayList<>(mProcessesOnHold);
for (int ip = 0; ip < NP; ip++) {
if (DEBUG_PROCESSES) {
Slog.v(TAG_PROCESSES, "Starting process on hold: " + procs.get(ip));
}
mProcessList.startProcessLocked(
procs.get(ip),
new HostingRecord(HostingRecord.HOSTING_TYPE_ON_HOLD),
ZYGOTE_POLICY_FLAG_BATCH_LAUNCH);
}
}
// 工厂测试模式(低级)下,启动流程到此为止
if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
return;
}
// ==================== 功耗监控 ====================
// 启动后开始监控异常 WakeLock 使用
Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_POWER_USE_MSG);
mHandler.sendMessageDelayed(nmsg, mConstants.POWER_CHECK_INTERVAL);
// ==================== Userspace Reboot 处理 ====================
// 如果是用户空间重启,记录成功事件
if (InitProperties.userspace_reboot_in_progress().orElse(false)) {
UserspaceRebootLogger.noteUserspaceRebootSuccess();
}
// ==================== 设置 boot_completed 属性 ====================
// sys.boot_completed = 1 是系统启动完成的“黄金标志”
// init / native 进程都会监听这个属性
SystemProperties.set("sys.boot_completed", "1");
// dev.bootcomplete = 1 用于更早阶段的服务判断
if (!"trigger_restart_min_framework".equals(VoldProperties.decrypt().orElse(""))
|| "".equals(VoldProperties.encrypt_progress().orElse(""))) {
SystemProperties.set("dev.bootcomplete", "1");
}
// ==================== 发送 BOOT_COMPLETED ====================
// 通知所有用户、所有应用:系统启动完成
// 这是第三方应用收到的最重要的启动广播
Slog.v(TAG, "--------sendBootCompleted----1------ ");
mUserController.sendBootCompleted(
new IIntentReceiver.Stub() {
@Override
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered,
boolean sticky, int sendingUser) {
synchronized (mProcLock) {
// 广播发送后,立即收集一次所有进程的 PSS 信息
mAppProfiler.requestPssAllProcsLPr(
SystemClock.uptimeMillis(), true, false);
}
}
});
// 记录 userspace reboot 相关指标
maybeLogUserspaceRebootEvent();
// 启动用户 profile(多用户场景)
mUserController.scheduleStartProfiles();
}
// ==================== 控制台 / MTE 警告 ====================
// 如果 UART console 开启,发出安全提醒
showConsoleNotificationIfActive();
showMteOverrideNotificationIfActive();
t.traceEnd();
}通知zygote、VMRuntime、mSystemServiceManager等开机完成
设置sys.boot_completed为1,表示开机完成
发送ACTION_BOOT_COMPLETED
这里重点就是设置开机完成以及设置开机完成属性为1,然后通知开机完成广播。
继续回调上面mInternal的调用。
ActivityTaskManagerService.java
mInternal就是ActivityTaskManagerService.java中的LocalService。
LocalService.enableScreenAfterBoot()
/**
* ActivityTaskManagerService 对外暴露的本地服务实现(LocalService),
* 供 SystemServer 或其他同一进程内的组件调用。
*
* 此类继承自 ActivityTaskManagerInternal,
* 是 ATMS 与 WMS / AMS 等系统服务交互的重要桥梁。
*/
final class LocalService extends ActivityTaskManagerInternal {
// ... 省略其他实现 ...
/**
* 系统启动完成后,通知 ATMS 启用屏幕。
*
* 该方法通常由 SystemServer 在启动流程末尾调用,
* 是“系统已启动完成”的关键信号之一。
*
* @param booted 当前系统是否已处于 boot completed 状态
*/
@Override
public void enableScreenAfterBoot(boolean booted) {
// ==================== Boot Timing ====================
// 记录“点亮屏幕”这一关键启动节点的时间戳
// 用于:
// - dumpsys bootinfo
// - 开机性能分析
// - 对比 system_server 各阶段耗时
writeBootProgressEnableScreen(SystemClock.uptimeMillis());
// ==================== 核心调用 ====================
// 委托 WindowManagerService 执行真正的亮屏逻辑:
// - 停止开机动画
// - 通知 SurfaceFlinger
// - 启用输入分发
// - 触发 performEnableScreen()
mWindowManager.enableScreenAfterBoot();
// ==================== 事件分发控制 ====================
// 根据系统启动状态,更新窗口输入事件的派发策略
// 例如:
// - 启动未完成时屏蔽用户输入
// - 启动完成后恢复正常触摸 / 按键响应
synchronized (mGlobalLock) {
updateEventDispatchingLocked(booted);
}
}
// ... 省略其他实现 ...
}这里主要看
mWindowManager.enableScreenAfterBoot();
WindowManagerService.java
enableScreenAfterBoot()
/**
* 系统启动完成后,由 WMS 调用,用于最终点亮屏幕并完成启动收尾工作。
* 该方法通常由 performEnableScreen() 触发,
* 是 WindowManagerPolicy(PhoneWindowManager)介入启动流程的关键入口。
*/
public void enableScreenAfterBoot() {
synchronized (mGlobalLock) {
// ==================== 调试日志 ====================
// 打印当前启动状态,并附带调用栈,便于排查开机卡屏 / 黑屏问题
ProtoLog.i(WM_DEBUG_BOOT, "enableScreenAfterBoot: mDisplayEnabled=%b "
+ "mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. "
+ "%s",
mDisplayEnabled, mForceDisplayEnabled, mShowingBootMessages, mSystemBooted,
new RuntimeException("here").fillInStackTrace());
// ========== Unisoc 厂商定制逻辑(bug2400846)==========
// 强制提前退出开机动画,避免动画阻塞亮屏
SystemProperties.set("service.bootanim.exit", "1");
mBootAnimationStopped = true;
// 强制认为显示已可用,跳过部分等待逻辑
mForceDisplayEnabled = true;
// ===================================================
// 如果系统已经标记为启动完成,直接返回,避免重复执行
if (mSystemBooted) {
return;
}
// 标记系统正式启动完成
mSystemBooted = true;
// 隐藏开机阶段显示的文字(如 "Android"、进度条等)
hideBootMessagesLocked();
// ===== 兜底保护机制 =====
// 如果屏幕在 30 秒内仍未正常点亮,
// 通过 Handler 强制触发亮屏流程,防止系统“假死”
mH.sendEmptyMessageDelayed(H.BOOT_TIMEOUT, 30 * 1000);
}
// ==================== 通知 Policy ====================
// 让 PhoneWindowManager 知道系统已经启动完成
// 典型行为包括:
// - 允许锁屏显示
// - 允许唤醒设备
// - 允许接收用户输入
mPolicy.systemBooted();
Slog.w(TAG, "enableScreenAfterBoot");
// ==================== 真正点亮屏幕 ====================
// 执行最终的屏幕启用流程:
// - 停止开机动画
// - 通知 SurfaceFlinger
// - 启用输入分发
// - 通知 AMS bootAnimationComplete
performEnableScreen();
}这里再关注一下performEnableScreen()
performEnableScreen()
/**
* 点亮屏幕 & 结束开机动画。
* 这是 WindowManagerService 启动流程中最重要的收尾函数之一。
* 必须确保所有系统窗口绘制完成、开机动画结束,才能正式启用屏幕和输入。
*/
private void performEnableScreen() {
synchronized (mGlobalLock) {
// 屏幕已经点亮过,直接返回(防止重复执行)
if (mDisplayEnabled) {
return;
}
// 系统尚未完全启动,且没有显示过开机提示信息,还不能亮屏
if (!mSystemBooted && !mShowingBootMessages) {
return;
}
// =====================================================
// 关键前提:等待所有系统窗口绘制完成
// 防止出现“桌面先出、状态栏后出”或黑屏问题
// =====================================================
if (!mForceDisplayEnabled) {
// 第一次进入,记录等待开始时间
if (mBootWaitForWindowsStartTime < 0) {
mBootWaitForWindowsStartTime = SystemClock.elapsedRealtime();
}
// 遍历所有 RootWindowContainer 的子节点
// 若存在需要等待的系统装饰窗口(如 SystemUI、导航栏、状态栏),
// 则继续等待,暂不亮屏
for (int i = mRoot.getChildCount() - 1; i >= 0; i--) {
if (mRoot.getChildAt(i).shouldWaitForSystemDecorWindowsOnBoot()) {
return;
}
}
// 统计等待窗口绘制的时间
long waitTime = SystemClock.elapsedRealtime() - mBootWaitForWindowsStartTime;
mBootWaitForWindowsStartTime = -1;
if (waitTime > 10) {
ProtoLog.i(WM_DEBUG_BOOT,
"performEnableScreen: Waited %dms for all windows to be drawn",
waitTime);
}
}
// =====================================================
// 停止开机动画(bootanimation)
// 早期版本是直接 kill 进程,现在通过设置 property 通知其优雅退出
// =====================================================
if (!mBootAnimationStopped) {
Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
// 通知 bootanimation 进程退出
SystemProperties.set("service.bootanim.exit", "1");
mBootAnimationStopped = true;
}
// ========== Unisoc 私有逻辑 ==========
// 回收 LK(Little Kernel)阶段动画占用的资源
Slog.w(TAG, "setprop sys.native.bootanimation to 1");
SystemProperties.set("sys.native.bootanimation", "1");
// 确保开机动画真的已经结束,否则继续等待
if (!mForceDisplayEnabled && !checkBootAnimationCompleteLocked()) {
ProtoLog.i(WM_DEBUG_BOOT, "performEnableScreen: Waiting for anim complete");
return;
}
// =====================================================
// 通知 SurfaceFlinger:系统启动完成(BOOT_FINISHED)
// SurfaceFlinger 收到后会切到正常合成模式
// =====================================================
try {
IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
if (surfaceFlinger != null) {
ProtoLog.i(WM_ERROR, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
Parcel data = Parcel.obtain();
data.writeInterfaceToken("android.ui.ISurfaceComposer");
// FIRST_CALL_TRANSACTION == BOOT_FINISHED
surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, data, null, 0);
data.recycle();
}
} catch (RemoteException ex) {
ProtoLog.e(WM_ERROR, "Boot completed: SurfaceFlinger is dead!");
}
// 记录开机动画结束时间点(用于性能分析)
EventLogTags.writeWmBootAnimationDone(SystemClock.uptimeMillis());
Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
// ==================== 正式点亮屏幕 ====================
mDisplayEnabled = true;
ProtoLog.i(WM_DEBUG_SCREEN_ON, "******************** ENABLING SCREEN!");
// 启用输入事件分发(触摸、按键等)
mInputManagerCallback.setEventDispatchingLw(mEventDispatchingEnabled);
}
// =========================================================
// 通知 ActivityManagerService:开机动画已完成
// AMS 会进一步触发 ACTION_BOOT_COMPLETED
// =========================================================
try {
Slog.w(TAG, " performEnableScreen bootAnimationComplete");
mActivityManager.bootAnimationComplete();
} catch (RemoteException e) {
// AMS 可能已死,忽略异常
}
// Policy(PhoneWindowManager)处理亮屏后的逻辑
// 如锁屏显示、唤醒行为等
mPolicy.enableScreenAfterBoot();
// 确保最后一次请求的方向(横竖屏)已生效
updateRotationUnchecked(false, false);
}至此,开机动画退出,显示了Launcher界面。
参考文字
AI
《》
《》
《》
《

