在 Android 系统定制中,常见一个问题:某个预装应用没有注册 BOOT_COMPLETED 广播接收器,但产品要求它在设备开机后自动启动。
如果无法修改 APK(无源码、签名限制、第三方交付),可以在 Framework 层做兜底拉起。
一、需求背景
目标应用包名:
com.longzhiye.custom
目标效果:
- 系统完成
BOOT_COMPLETED分发后,自动启动该应用 - 仅在系统用户(
USER_SYSTEM)执行,避免多用户重复拉起
二、改动总览
本次修改集中在:
frameworks/base/services/core/java/com/android/server/am/UserController.java
核心改动有 3 个:
- 新增自动拉起配置常量
- 在
BOOT_COMPLETED完成后调度启动逻辑 - 实现应用启动与异常兜底日志
三、关键实现解析
1)新增常量配置
// Longzhiye app package to force-start after boot when APK has no BOOT_COMPLETED receiver.
private static final String BOOT_AUTO_LAUNCH_PACKAGE = "com.longzhiye.custom";
private static final long BOOT_AUTO_LAUNCH_DELAY_MS = 100;
说明:
-
BOOT_AUTO_LAUNCH_PACKAGE:目标包名 -
BOOT_AUTO_LAUNCH_DELAY_MS:延迟执行时间,避免与开机阶段任务抢占时序
2)插入 BOOT_COMPLETED 后触发点
mBootCompleted = true;
scheduleBootAutoLaunchApp(userId);
这一步非常关键:
在系统确认 BOOT_COMPLETED 处理完成后,进入自动拉起流程。
3)仅系统用户执行并延迟启动
private void scheduleBootAutoLaunchApp(@UserIdInt int userId) {
if (userId != UserHandle.USER_SYSTEM) {
return;
}
mHandler.postDelayed(() -> startBootAutoLaunchApp(userId), BOOT_AUTO_LAUNCH_DELAY_MS);
}
设计目的:
- 仅允许
USER_SYSTEM执行,避免多用户重复触发 - 使用
postDelayed让启动动作更平滑,减少开机瞬时冲突
4)启动逻辑与兜底处理
private void startBootAutoLaunchApp(@UserIdInt int userId) {
final Context context = mInjector.getContext();
try {
Intent launchIntent = context.getPackageManager()
.getLaunchIntentForPackage(BOOT_AUTO_LAUNCH_PACKAGE);
if (launchIntent == null) {
launchIntent = new Intent(Intent.ACTION_MAIN);
launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
launchIntent.setPackage(BOOT_AUTO_LAUNCH_PACKAGE);
}
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivityAsUser(launchIntent, UserHandle.of(userId));
Slogf.i(TAG, "Boot auto-launch: started " + BOOT_AUTO_LAUNCH_PACKAGE);
} catch (Exception e) {
Slogf.e(TAG, "Boot auto-launch: failed to start " + BOOT_AUTO_LAUNCH_PACKAGE, e);
}
}
实现要点:
- 优先使用
getLaunchIntentForPackage()获取应用主入口 - 若返回空,回退为
ACTION_MAIN + CATEGORY_LAUNCHER - 添加
FLAG_ACTIVITY_NEW_TASK,满足系统服务上下文启动 Activity 要求 - 使用
startActivityAsUser()指定用户启动 - 全量异常捕获并记录日志,便于排查启动失败原因
四、方案优势
- 不改 APK:适合预装闭源应用
- 改动集中:只改 Framework 单一模块
- 可观测性强:有明确成功/失败日志
- 风险可控:用户过滤 + 延迟调度 + 异常兜底
五、注意事项
- 包名硬编码维护成本高,建议后续改为系统属性或 overlay 配置
- 延迟时间建议按机型调优,必要时可提升至 100ms~1000ms
- 需验证目标应用确实存在可启动 Activity
- 多用户/用户切换场景建议加幂等保护,防止重复拉起
六、验证建议
开机后检查日志:
- 成功:
Boot auto-launch: started com.longzhiye.custom - 失败:
Boot auto-launch: failed to start com.longzhiye.custom