如何将普通应用预装为​​不可卸载的系统应用

352 阅读4分钟

将用故事结合代码的方式,详细说明如何将普通应用预装为​​不可卸载的系统应用​​(放入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源码中创建模块:

  1. ​新建目录​​:vendor/musicplanet/
  2. ​放入APK​​:MusicPlanet.apk
  3. ​编写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  # 加入编译清单

编译时发生以下流程:

  1. 编译系统识别MusicPlanet模块;

  2. MusicPlanet.apk复制到 ​out/target/product/your_device/system/priv-app/​;

  3. 系统镜像打包时,此目录被写入system分区只读区域


🔐 ​​第五章:签名验证——特权通行证​

系统启动时,PackageManagerService (PMS)扫描priv-app目录:

  1. ​检查签名​​:用platform公钥验证APK的CERT.RSA文件;

  2. ​权限赋予​​:若签名匹配,自动授予signature级权限(如MODIFY_AUDIO_SETTINGS);

  3. ​安装生效​​:应用被视为系统核心组件,不可卸载

⚠️ ​​签名失败后果​​:
若APK未用platform签名,PMS会拒绝安装,Logcat报错:INSTALL_FAILED_SHARED_LIB_BAD_CERTIFICATE


♻️ ​​第六章:恢复出厂设置的“复活甲”​

用户恢复出厂设置时:

  1. system分区被完整保留​​(只读属性);

  2. data分区被清空​​(用户数据删除);

  3. 重启后,PMS重新扫描system/priv-app,​​“音乐星球”自动恢复​

💡 与/data/app不同:用户卸载data/app的应用后,恢复出厂​​不会恢复​​。


⚖️ ​​关键知识总结:系统应用 vs 普通预装​

​特性​​系统特权应用 (priv-app)​​普通可卸载应用 (data/app)​
​存储路径​/system/priv-app/data/app
​卸载权限​❌ 不可卸载✅ 可卸载
​签名要求​LOCAL_CERTIFICATE := platformLOCAL_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分区);

  • 平台签名是​​信任链的根​​,确保特权不会被恶意应用窃取


💎 ​​总结:系统级预装的核心要素​

  1. ​路径决定权限​​:priv-app = 特权 + 不可卸载;
  2. ​签名决定身份​​:platform签名是通往系统权限的钥匙;
  3. ​编译决定存在​​:通过Android.mkPRODUCT_PACKAGES植入系统镜像;
  4. ​恢复出厂不变​​:system分区的只读性保障核心功能永驻。

🌟 ​​小安的感悟​​:
普通应用成为系统特权应用,如同获得“​​钢铁侠战甲​​”——能力越大,责任越大。
每一步都需精准匹配系统信任链,否则战甲会变成无法启动的铁棺材⚙️🔒。

(注:技术细节基于AOSP源码实现,主要参考PackageManagerServicebuild/make/core中的编译系统逻辑