笔友城堡 - 可定义的个人主页

前言

上次Android源码分析开机动画退出(《Android退出开机动画源码分析》),今天就看一下Intent.ACTION_BOOT_COMPLETED广播啥时候发送的。

记录于此,方便自己查阅。

代码分析借助于AI注释

正文

回到上一篇的finishBooting()中。

ActivityManagerService.java

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 {
        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 等)在此阶段完成最后初始化
    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);
            }
        }
        // ==================== 功耗监控 ====================
        // 启动后开始监控异常 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 ====================
        // 通知所有用户、所有应用:系统启动完成
        // 这是第三方应用收到的最重要的启动广播
        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();
}

上面有个关注点,

mUserController.sendBootCompleted(...);

这个是用户相关控制类。

UserController.java

sendBootCompleted()
/**
 * 向指定用户发送启动完成信号。
 *
 * 该方法在用户解锁(unlocked)后被调用,
 * 负责完成用户级初始化,并最终发送 {@link Intent#ACTION_BOOT_COMPLETED} 广播。
 *
 * 本方法直接影响:
 * - 应用首次启动时机
 * - 开机动画结束后的桌面首帧时间
 * - 多用户场景下的应用可见性
 */
/* private */ void sendBootCompleted(UserState uss) {
    final int userId = uss.mHandle.getIdentifier();
    synchronized (mLock) {
        // 防御性校验:防止用户已被移除,避免操作过期对象
        if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) {
            return;
        }
    }

    UserInfo userInfo = getUserInfo(userId);
    if (userInfo == null) {
        return;
    }

    // ==================== FBE 安全校验 ====================
    // 文件级加密(FBE)场景下,用户密钥必须已解锁
    // 否则不能访问用户数据,也不能继续初始化
    if (!StorageManager.isUserKeyUnlocked(userId)) {
        return;
    }
    // 记录用户登录状态(用于最近登录用户、多用户切换等)
    mInjector.getUserManager().onUserLoggedIn(userId);
    // 用户初始化任务:仅执行一次
    Runnable initializeUser =
            () -> mInjector.getUserManager().makeInitialized(userInfo.id);
    // ==================== 用户首次初始化 ====================
    // 某些用户配置(铃声、时区、默认应用)只在首次启动时设置
    if (!userInfo.isInitialized()) {
        Slogf.d(TAG, "Initializing user #" + userId);
        if (userInfo.preCreated) {
            // 预创建用户:直接同步初始化
            initializeUser.run();
        } else if (userId != UserHandle.USER_SYSTEM) {
            // 非系统用户:通过 ACTION_USER_INITIALIZE 通知系统组件
            Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
            mInjector.broadcastIntent(intent, null,
                    new IIntentReceiver.Stub() {
                        @Override
                        public void performReceive(Intent intent, int resultCode,
                                String data, Bundle extras, boolean ordered,
                                boolean sticky, int sendingUser) {
                            // 广播处理完成后,正式标记用户已初始化
                            initializeUser.run();
                        }
                    }, 0, null, null, null, AppOpsManager.OP_NONE,
                    null, true, false, MY_PID, SYSTEM_UID,
                    Binder.getCallingUid(), Binder.getCallingPid(), userId);
        }
    }
    // ==================== 预创建用户特殊处理 ====================
    // 预创建用户仅用于提前加载服务,并非真实可用用户
    // 初始化完成后立即停掉,避免占用资源
    if (userInfo.preCreated) {
        Slogf.i(TAG, "Stopping pre-created user " + userInfo.toFullString());
        stopUser(userInfo.id,
                /* force= */ true,
                /* allowDelayedLocking= */ false,
                /* stopUserCallback= */ null,
                /* keyEvictedCallback= */ null);
        return;
    }

    // ==================== 启动 AppWidget ====================
    // 在 BOOT_COMPLETED 之前启动 widget,
    // 确保桌面组件(时钟、天气等)及时就绪
    // 【Unisoc 优化点】widget 越早启动,桌面首帧越快
    mInjector.startUserWidgets(userId);

    // 通知内部状态机:用户已解锁
    mHandler.obtainMessage(USER_UNLOCKED_MSG, userId, 0).sendToTarget();

    Slogf.i(TAG, "Posting BOOT_COMPLETED user #" + userId);

    // ==================== 系统启动耗时统计 ====================
    // 仅统计系统用户、非 runtime restart、非首次开机/OTA 场景
    if (userId == UserHandle.USER_SYSTEM
            && !mInjector.isRuntimeRestarted()
            && !mInjector.isFirstBootOrUpgrade()) {
        final long elapsedTimeMs = SystemClock.elapsedRealtime();
        FrameworkStatsLog.write(
                FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
                FrameworkStatsLog
                        .BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__FRAMEWORK_BOOT_COMPLETED,
                elapsedTimeMs);
    }

    // ==================== 发送 ACTION_BOOT_COMPLETED ====================
    // 这是应用层能收到的“系统启动完成”最关键信号
    // 直接影响:
    // - 第三方应用启动时机
    // - JobScheduler / AlarmManager 首次运行
    // - 开机自启类应用的执行时间
    final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
    bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
    bootIntent.addFlags(
            Intent.FLAG_RECEIVER_NO_ABORT           // 不允许拦截,保证必达
          | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND // 允许后台应用接收
          | Intent.FLAG_RECEIVER_OFFLOAD);          // Android 13+:广播卸载优化

    final int callingUid = Binder.getCallingUid();
    final int callingPid = Binder.getCallingPid();

    // 【关键顺序保证】
    // Widget 广播通过 FgThread 发送,
    // 为保证 widget → boot_completed 的顺序一致性,
    // BOOT_COMPLETED 也通过 FgThread 发送
    FgThread.getHandler().post(() -> {
        mInjector.broadcastIntent(bootIntent, null,
                new IIntentReceiver.Stub() {
                    @Override
                    public void performReceive(Intent intent, int resultCode, String data,
                            Bundle extras, boolean ordered, boolean sticky, int sendingUser)
                            throws RemoteException {
                        Slogf.i(UserController.TAG,"Finished processing BOOT_COMPLETED for u" + userId);
                        // 标记 AMS 内部状态:BOOT_COMPLETED 已处理完成
                        // 影响后续开机阶段判断、应用启动策略
                        mBootCompleted = true;
                    }
                }, 0, null, null,
                new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
                AppOpsManager.OP_NONE,
                getTemporaryAppAllowlistBroadcastOptions(REASON_BOOT_COMPLETED).toBundle(),
                true, false, MY_PID, SYSTEM_UID,
                callingUid, callingPid, userId);
    });
}

参考文章

  1. AI

  2. Android退出开机动画源码分析

相关文章

笔友城堡 - 可定义的个人主页

暂无评论

评论审核已启用。您的评论可能需要一段时间后才能被显示。

none
暂无评论...