将用故事结合代码的方式,详细说明如何将普通应用预装为不可卸载的系统应用(放入system/priv-app目录)。故事主角是手机厂商工程师小安,任务是预装音乐应用“音乐星球”作为系统核心功能。
📖 第一章:突如其来的系统级需求
产品经理急匆匆找到小安:“这次‘音乐星球’要作为手机的核心功能,必须预装且用户不能卸载!还要能访问系统音频设置!”
小安立刻意识到:这需要将普通应用升级为系统特权应用,需放入 /system/priv-app 目录,并使用平台签名赋予高权限
⚙️ 第二章:特权应用的秘密基地——priv-app
小安翻阅AOSP文档发现:
-
system/app:普通系统应用(如计算器),权限中等,不可卸载; -
system/priv-app:特权系统应用(如设置、SystemUI),可申请signature级权限,不可卸载。 他决定将“音乐星球”放入 priv-app,并修改其代码申请系统权限:
<!-- AndroidManifest.xml 中声明特权权限 -->
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
🔧 第三章:源码整合——Android.mk的魔法
小安在AOSP源码中创建模块:
- 新建目录:
vendor/musicplanet/ - 放入APK:
MusicPlanet.apk - 编写
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := MusicPlanet
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := platform # 关键!使用系统平台签名
LOCAL_PRIVILEGED_MODULE := true # 关键!标记为特权应用
LOCAL_MODULE_PATH := $(TARGET_OUT)/priv-app # 指定priv-app目录
include $(BUILD_PREBUILT)
为何用
platform签名?
系统特权应用必须使用与ROM相同的密钥签名(platform),否则权限校验会失败
🔄 第四章:编译系统的接力赛
在设备配置文件device.mk中激活模块:
PRODUCT_PACKAGES += MusicPlanet # 加入编译清单
编译时发生以下流程:
-
编译系统识别
MusicPlanet模块; -
将
MusicPlanet.apk复制到 out/target/product/your_device/system/priv-app/; -
系统镜像打包时,此目录被写入
system分区只读区域
🔐 第五章:签名验证——特权通行证
系统启动时,PackageManagerService (PMS)扫描priv-app目录:
-
检查签名:用
platform公钥验证APK的CERT.RSA文件; -
权限赋予:若签名匹配,自动授予
signature级权限(如MODIFY_AUDIO_SETTINGS); -
安装生效:应用被视为系统核心组件,不可卸载
⚠️ 签名失败后果:
若APK未用platform签名,PMS会拒绝安装,Logcat报错:INSTALL_FAILED_SHARED_LIB_BAD_CERTIFICATE。
♻️ 第六章:恢复出厂设置的“复活甲”
用户恢复出厂设置时:
-
system分区被完整保留(只读属性); -
data分区被清空(用户数据删除); -
重启后,PMS重新扫描
system/priv-app,“音乐星球”自动恢复
💡 与
/data/app不同:用户卸载data/app的应用后,恢复出厂不会恢复。
⚖️ 关键知识总结:系统应用 vs 普通预装
| 特性 | 系统特权应用 (priv-app) | 普通可卸载应用 (data/app) |
|---|---|---|
| 存储路径 | /system/priv-app | /data/app |
| 卸载权限 | ❌ 不可卸载 | ✅ 可卸载 |
| 签名要求 | LOCAL_CERTIFICATE := platform | LOCAL_CERTIFICATE := PRESIGNED |
| 权限级别 | 可申请signature级系统权限 | 仅普通权限 |
| 恢复出厂后状态 | ✅ 自动恢复 | ❌ 不恢复(除非预置到preinstall目录) |
📜 第七章:代码中的安全哲学
小安在代码中看到PMS的验证逻辑:
// PackageManagerService.java
private void scanPackageTracedLI(...) {
if (isPrivileged) {
// 检查签名是否匹配platform公钥
if (!verifySignatures(pkg, platformPublicKey)) {
throw new PackageManagerException("Invalid signature for priv-app");
}
}
}
安全逻辑:
-
特权应用必须与系统同生共死(绑定
system分区); -
平台签名是信任链的根,确保特权不会被恶意应用窃取
💎 总结:系统级预装的核心要素
- 路径决定权限:
priv-app= 特权 + 不可卸载; - 签名决定身份:
platform签名是通往系统权限的钥匙; - 编译决定存在:通过
Android.mk和PRODUCT_PACKAGES植入系统镜像; - 恢复出厂不变:
system分区的只读性保障核心功能永驻。
🌟 小安的感悟:
普通应用成为系统特权应用,如同获得“钢铁侠战甲”——能力越大,责任越大。
每一步都需精准匹配系统信任链,否则战甲会变成无法启动的铁棺材⚙️🔒。
(注:技术细节基于AOSP源码实现,主要参考PackageManagerService及build/make/core中的编译系统逻辑