很多开发者之所以觉得开机拉起慢,是因为采用了"等系统发 BOOT_COMPLETED 广播,App 再接收广播调 startActivity"的常规做法(由于广播排队,往往要等开机后 5~10 秒)。
要达到极致最快(开机动画结束的第 1 秒界面就已就绪),利用 persistent="true" 结合特权 Service / Direct Boot 才是最快、最优雅的官方正道。
第一步:APK 端配置(零多余代码,天然常驻)
在 APK 的 AndroidManifest.xml 中配置:
xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.remote.control"
android:sharedUserId="android.uid.system"> <!-- 建议绑定 system uid,获得最高系统权限 -->
<application
android:name=".RemoteApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:directBootAware="true" <!-- 支持 Direct Boot,在用户解锁前即完成初始化 -->
android:persistent="true"> <!-- 核心:标记为系统级常驻保活应用 -->
<activity
android:name=".ui.MainActivity"
android:exported="true"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
极速启动核心:在 Application.onCreate() 中主动拉起主界面
因为标记了 persistent="true",系统开机阶段会自动创建 Application 进程 。在 Application 初始化的第一时间直接拉起 MainActivity,完全不需要任何 Receiver,也不需要等待任何开机广播!
kotlin
package com.remote.control
import android.app.Application
import android.content.Intent
import android.util.Log
import com.remote.control.ui.MainActivity
class RemoteApplication : Application() {
override fun onCreate() {
super.onCreate()
Log.i("RemoteApp", "Persistent Process Started by SystemServer. Auto-launching UI...")
// 系统拉起本进程后,直接将主界面推向前台
val intent = Intent(this, MainActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_CLEAR_TOP or
Intent.FLAG_ACTIVITY_SINGLE_TOP)
}
startActivity(intent)
}
}
第二步:系统源码预置配置(AOSP 端)
1. 编写 Android.bp
将现成的 RemoteControl.apk 放入 vendor/<vendor>/packages/apps/RemoteControl/:
blueprint
android_app_import {
name: "RemoteControl",
apk: "RemoteControl.apk",
privileged: true, // 安装到 /system/priv-app/ 成为特权 App
certificate: "platform", // 必须使用系统平台签名(persistent 应用必须是 platform 签名或系统应用)
extract_jni: true,
dex_preopt: {
enabled: false,
},
required: ["privapp-permissions-remote.xml"],
}
prebuilt_etc {
name: "privapp-permissions-remote.xml",
sub_dir: "permissions",
src: "privapp-permissions-remote.xml",
filename_from_src: true,
}
2. 特权权限白名单 privapp-permissions-remote.xml
xml
<?xml version="1.0" encoding="utf-8"?>
<permissions>
<privapp-permissions package="com.remote.control">
<!-- 允许作为系统后台持续运行 -->
<permission name="android.permission.RECEIVE_BOOT_COMPLETED"/>
</privapp-permissions>
</permissions>
3. 将模块打包进编译文件 (device.mk)
makefile
PRODUCT_PACKAGES += \
RemoteControl \
privapp-permissions-remote.xml
三、 为什么这是最优、最快、最稳定的解决方案?
| 机制维度 | 传统普通方案(广播拉起) | 本方案(persistent="true" + Direct Boot) |
|---|---|---|
| 拉起时机 | 开机流程走完 → 发送 BOOT_COMPLETED → 接收广播 → 启动进程 → 启动 Activity(总耗时:开机后 5~10 秒) |
SystemServer 启动直接 fork 进程 → Application.onCreate() 秒级直启 Activity(总耗时:开机动画结束前已在后台就绪,0 秒直达) |
| 保活能力 | 易被系统 LMK 机制杀掉,需写 JobScheduler/双进程守护等 Hack 手段 | 系统内核级保活(OOM_ADJ = -800) ,系统永远不杀;若发生 Native Crash,AMS 自动重新拉起 |
| 退出行为 | 容易陷入防退出和正常退出的逻辑死结 | 用户点 Home 键可正常退出到原生桌面;退到后台后进程依然常驻、视频通信/机器狗指令长连接不中断 |
| 代码量 | 需写 Receiver、Watchdog、各种保活 Service | 零多余代码 ,仅依赖 Android 原生架构提供的 persistent 机制 |
核心结论
android:persistent="true" + 在 Application.onCreate() 中拉起 UI,是 Android 系统级定制设备(如车载中控、大疆遥控器、特种工业屏)最标准、性能最高、代码量最少的黄金实践。
问题:如果原生 Launcher 和 定制App 在开机时几乎同时被拉起:
- 如果定制App先调用 startActivity,随后系统 ATMS 又拉起了 Launcher3,那么 Launcher3 可能会把具微遥控的主界面覆盖在下方(退回后台) !
- 用户开机后看到的依然是原生桌面,需要用户自己去点图标,破坏了"开机 100% 自动置顶前台"的体验。
解决:Framework 层定制代码
修改 ActivityTaskManagerService.java(或 RootWindowContainer.java)。为了避免开机瞬间系统 I/O 拥堵,加入安全的排队调度:
- 源码路径:frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
scala
package com.android.server.wm;
import android.content.ComponentName;
import android.content.Intent;
import android.os.UserHandle;
import android.util.Slog;
public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
private static final String TAG_KIOSK = "ATMS_KioskBoot";
private static final String TARGET_PKG = "com.remote.control";
private static final String TARGET_CLS = "com.remote.control.ui.MainActivity";
/**
* 在桌面启动完成后,由系统直接派发特权 APP 置顶
*/
void startHomeOnAllDisplays(String reason) {
super.startHomeOnAllDisplays(reason);
// 利用 Handler 异步排队,确保底层的 Home Task 完成了初始事务
mH.post(() -> {
try {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(new ComponentName(TARGET_PKG, TARGET_CLS));
// 关键 Flags:
// 1. FLAG_ACTIVITY_NEW_TASK: 系统 Context 启动外部 App 必须携带
// 2. FLAG_ACTIVITY_RESET_TASK_IF_NEEDED: 保持/重置任务栈
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
// 针对 Android 16 多用户安全机制,明确指定启动到当前前台用户 (UserHandle.USER_CURRENT)
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
Slog.i(TAG_KIOSK, "Successfully launched " + TARGET_PKG + " on top of Launcher.");
} catch (Exception e) {
Slog.e(TAG_KIOSK, "Failed to auto-start " + TARGET_PKG, e);
}
});
}
}

-
时序与稳定性:
- 开机后,原生 Launcher 在最底层待命。
- 定制APP自动在最前台呈现(耗时随开机动画结束直接秒出)。
- 用户按 Home 键或 Back 键逐级返回,可以正常退出并看到原生桌面。
- 随时点击桌面图标可再次进入定制APP。