Android 14 开机自启动第三方 APK 全流程踩坑与最终解决方案(含 RescueParty 避坑)

前言

在 Android 14.0 设备定制中,遇到一个开机自启动第三方 APK 的需求:设备开机后自动拉起客制化 APP,且不能因为切换语言、修改字体大小、更换默认壁纸等系统设置而重复启动。通过在launcher中定义自启动app的方法基本上都会遇到修改系统设置时,再次去换起第三方apk的bug

最终在frameworks\base\packages\SystemUI\src\com\android\systemui\SystemUIService.java

服务中添加延迟启动方法修复bug

下面列举了所有试错方案和思路转换,从问题出现 → 多次踩坑 → 崩溃进 Recovery → 最终稳定方案,完整复盘整个实战过程。


一、需求与初始问题

1.1 需求

  • Android 14.0 系统开机自启动第三方客制 APK
  • 重启设备能正常自启
  • 修改语言、字体大小、壁纸等系统设置不重复自启

1.2 最初实现(有问题)

Launcher 的 onCreate 中调用自启动方法:

复制代码
startAppByPackageName(packageName);

1.3 第一个坑:系统设置一修改,APP 就重启

现象:

  • 切换系统语言
  • 修改字体大小 / 显示大小
  • 修改默认壁纸

都会导致:Launcher 进程重启 → 重新走 onCreate → 自启动逻辑再次执行 → APP 被重复拉起

原因:这些操作属于系统全局配置变化,系统会重建 Launcher,并非真正的设备重启。


二、第一轮尝试:各种方案踩坑

2.1 方案 1:通过 ro.boot.id 判断只在真正开机时启动

思路:读取系统属性 ro.boot.id,认为只有冷开机才执行自启。

结果:第一次刷机后根本不自启,属性判断时机不对。

2.2 方案 2:监听开机广播 BOOT_COMPLETED

思路:只在收到开机广播时自启,避开 Launcher 重建。

结果:

  • 修改系统设置不再重复自启 ✔
  • 只有刷机 / 恢复出厂第一次能自启
  • 设备重启后无法自启

三、第二轮尝试:换位置实现自启

既然 Launcher 不行,尝试放到系统更底层

3.1 尝试放到 PhoneWindowManager

  • 开机广播中启动 APP
  • 能解决设置变更不重复自启 ✔
  • 但出现新问题:点击返回键会优先跳回客制 APP

3.2 尝试放到 Activity 的 finish 逻辑

同样出现:页面返回、跳转都会被强行拉回客制 APP,严重影响体验。

3.3 最终放到 SystemUIService

frameworks\base\packages\SystemUI\src\com\android\systemui\SystemUIService.java

SystemUIService.javaonCreate 中直接启动:

复制代码
Intent intent = new Intent();
intent.setComponent(new ComponentName(pkg, cls));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

表面效果很好:

  • 重启能自启 ✔
  • 修改系统设置不重复自启 ✔

但埋下超级大坑

四、致命问题:多次重启 → 直接进 Recovery

4.1 客户反馈现象

  • 正常使用没问题
  • 连续手动重启设备几次
  • 设备直接进入 Recovery 模式
  • 提示:需要清除 data 分区才能进系统

4.2 日志分析(关键)

复制代码
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.android.systemui
java.lang.RuntimeException: Unable to create service com.android.systemui.SystemUIService
Caused by: ActivityNotFoundException

4.3 根本原因(非常重要)

  1. SystemUI 启动时机 早于 PMS 扫描

    • SystemUI 是系统核心服务,启动极早
    • PMS(PackageManagerService)还没扫描完 /system/priv-app
    • 此时启动客制 APP → Activity 不存在
  2. 空指针 / 异常导致 SystemUI 崩溃

  3. 系统触发 RescueParty 机制

    • 核心进程连续崩溃达到阈值
    • Android 判定系统损坏
    • 强制进入 Recovery,要求清 data

这是 Android 系统的自我保护机制

五、最终稳定方案:延迟启动 + 重试机制

5.1 核心思路

  1. 自启动逻辑放在 SystemUIService
  2. 不直接在 onCreate 启动
  3. 使用 Handler 延迟 + 重试,等 PMS 扫描完成
  4. 全 try-catch 保护,绝对不让 SystemUI 崩溃

5.2 最终代码(可直接使用,修改ComponentName里为你自己apk的包名类名)

\frameworks\base\packages\SystemUI\src\com\android\systemui\SystemUIService.java

复制代码
// 放在 SystemUIService 的 onCreate 中

        // Bind the dump service so we can dump extra info during a bug report
        startServiceAsUser(
                new Intent(getApplicationContext(), SystemUIAuxiliaryDumpService.class),
                UserHandle.SYSTEM);
  //czq Start Amicus MainActivity with delay and retry mechanism
        mMainHandler.postDelayed(new Runnable() {
            private int mRetryCount = 0;
            private static final int MAX_RETRY_COUNT = 5;
            private static final long RETRY_DELAY_MS = 3000; // 3秒重试一次

            @Override
            public void run() {
                try {
                    Slog.e(SystemUIApplication.TAG, "Attempting to start Amicus MainActivity (retry " + mRetryCount + ")");
                    Intent intent = new Intent();
                    intent.setComponent(new ComponentName("com.xxx.xxx", "com.xxx.xxx.MainActivity"));
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);
                    Slog.e(SystemUIApplication.TAG, "Successfully started Amicus MainActivity");
                } catch (ActivityNotFoundException e) {
                    Slog.e(SystemUIApplication.TAG, "start com.butterfly.amicus.MainActivity fail:target Activity does not exist", e);
                    if (mRetryCount < MAX_RETRY_COUNT) {
                        mRetryCount++;
                        Slog.e(SystemUIApplication.TAG, "Retrying to start Amicus MainActivity in " + RETRY_DELAY_MS + "ms (attempt " + mRetryCount + "/" + MAX_RETRY_COUNT + ")");
                        mMainHandler.postDelayed(this, RETRY_DELAY_MS);
                    } else {
                        Slog.e(SystemUIApplication.TAG, "Max retry count reached. Giving up on starting Amicus MainActivity");
                    }
                } catch (Exception e) {
                    Slog.e(SystemUIApplication.TAG, "start com.butterfly.amicus.MainActivity fail ", e);
                }
            }
        }, 5000); //czq end 初始延迟5秒,给系统足够的启动时间

5.3 为什么这样写能解决所有问题

  1. 延迟 5s 启动给 PMS 足够时间扫描 priv-app

  2. 重试机制第一次找不到就等 3s 再试,最多试 5 次

  3. 全面异常捕获绝对不抛出异常 → SystemUI 不崩溃 → 不触发 RescueParty

  4. 放在 SystemUI不受 Launcher 重建影响 → 修改语言 / 壁纸 / 字体都不会重复自启


六、最终效果(全部满足)

  • ✅ 设备重启 → 正常自启
  • ✅ 刷机第一次开机 → 正常自启
  • ✅ 恢复出厂 → 正常自启
  • ✅ 切换语言、字体大小、壁纸 → 不重复自启
  • ✅ 多次重启设备 → 不会进 Recovery
  • ✅ SystemUI 稳定不崩溃、不异常

七、实战总结(非常关键)

  1. 不要在 Launcher onCreate 做开机自启系统设置变更会重建 Launcher,导致重复自启。

  2. 不要在核心服务 onCreate 直接启动第三方 APPPMS 还没扫描完,会报 Activity 不存在。

  3. SystemUI 绝对不能崩溃崩溃多了直接触发 RescueParty 进 Recovery。

  4. 开机自启最稳方案SystemUIService + 延迟 + 重试 + 全 try-catch

八、常用抓包日志命令

复制代码
adb logcat -v time SystemUI:E *:S

adb logcat -v time *:E | findstr /i "systemui fatal androidruntime caused by"
相关推荐
AI人工智能+1 小时前
CNN+CRNN+NER:如何实现食品经营许可证秒级结构化信息提取?
深度学习·ocr·食品经营许可证识别
轩情吖2 小时前
MySQL库的操作
android·数据库·mysql·oracle·字符集·数据库操作·编码集
当战神遇到编程2 小时前
LinkedList深入讲解
java·intellij-idea
kylezhao20192 小时前
C#中的反射是什么?详细讲解以及在工控上位机中如何应用
java·开发语言
张三_02262 小时前
Java并发:我用修仙小说讲AQS
java
what丶k2 小时前
【微服务】Spring AI 使用详解:让微服务无缝集成 AI 能力
java·后端·ai编程
骑猪上高速z2 小时前
Easy Desensitize:Java 高性能脱敏引擎的试用与实测
java
工业甲酰苯胺2 小时前
一文学习 Spring AOP 源码全过程
java·学习·spring
知我Deja_Vu2 小时前
详解 Lists.newArrayList() 的作用
java·开发语言