一句话结论
只有被平台私钥签名的 APK,放到 /system/priv-app/ 下并设置 android:sharedUserId="android.uid.system",才能成为真正的系统应用,获得 READ_PRIVILEGED_PHONE_STATE、MOUNT_UNMOUNT_FILESYSTEMS 等特权权限。
适用场景
- 需要预装到定制设备
- 需要访问普通应用无法申请的特权权限
- ROM 厂商、ODM/OEM 项目、行业终端调试
01. 拿到 platform key 的三个文件
系统签名的核心就是这三个文件,必须和设备 ROM 对应:
| 文件 | 作用 | 常见来源 |
|---|---|---|
platform.x509.pem |
公钥证书 | AOSP 源码 build/target/product/security/ |
platform.pk8 |
私钥 | 同上,或设备厂商提供的 releasekey |
signapk.jar |
AOSP 签名工具 | 源码路径 build/tools/signapk/ |
厂商 ROM 的 key 文件名可能是
releasekey.pk8、releasekey.x509.pem或vendor_xxxx.pk8,必须和设备实际刷入的 ROM 匹配,否则签名无效。
02. 把 APK 重新签名为 platform 签名
2.1 先用 q5.jks 出 v1-only 的 release APK
在 app/build.gradle 的 release 配置里强制 v1 签名:
arduino
android {
signingConfigs {
config {
// q5.jks 配置
storeFile file("q5.jks")
storePassword "xxx"
keyAlias "xxx"
keyPassword "xxx"
v1SigningEnabled true
v2SigningEnabled false
}
}
buildTypes {
release {
signingConfig signingConfigs.config
}
}
}
debug 版本必须保持
v1SigningEnabled true和v2SigningEnabled true都开启,否则adb install在 7.0+ 设备上会失败。
然后在 Android Studio 里:
rust
Build -> Generate Signed APK -> 选择 q5Release flavor
2.2 用 signapk 重新签名
拿到 app\build\outputs\apk\q5\release\q5_xxx_release.apk 后,执行:
arduino
java -jar signapk.jar \
-w \
platform.x509.pem \
platform.pk8 \
app\build\outputs\apk\q5\release\q5_xxx_release.apk \
app-system-signed.apk
signapk.jar默认只生成 v1 签名,正好符合系统应用要求。签完不要再拿 jks 工具二次签名,否则会覆盖 platform 签名。
03. 推送到设备的 /system/priv-app/
bash
adb root
adb remount
# 1) 建包名目录(注意用 applicationId,不是 package)
adb shell mkdir -p /system/priv-app/com.qhsoft.q5
# 2) 推送 APK
adb push app-system-signed.apk /system/priv-app/com.qhsoft.q5/app.apk
# 3) 关键权限设置,这三步很多人漏
adb shell chmod 644 /system/priv-app/com.qhsoft.q5/app.apk
adb shell chown root:root /system/priv-app/com.qhsoft.q5/app.apk
adb shell restorecon /system/priv-app/com.qhsoft.q5/app.apk
# 4) 重启生效
adb reboot
chmod 644、chown root:root、restorecon必须做,否则 SELinux 或文件权限检查会导致系统应用权限不生效。
04. 验证是否真正成为系统应用
4.1 确认是系统应用(userId=1000)
go
adb shell dumpsys package com.qhsoft.q5 | findstr "userId"
期望输出包含 userId=1000。
4.2 确认从 priv-app 路径安装
lua
adb shell pm path com.qhsoft.q5
期望:
bash
/system/priv-app/com.qhsoft.q5/app.apk
4.3 确认特权权限已授权
go
adb shell dumpsys package com.qhsoft.q5 | findstr "READ_PRIVILEGED_PHONE_STATE"
期望:
ini
permission grant=true
配套改动清单
AndroidManifest.xml
ini
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.qhsoft.q5"
android:sharedUserId="android.uid.system">
<application
android:persistent="true"
... />
</manifest>
android:sharedUserId="android.uid.system"是核心,否则即使放到 priv-app 也拿不到系统权限。
app/build.gradle
java
signingConfigs {
config {
storeFile file("q5.jks")
storePassword "xxx"
keyAlias "xxx"
keyPassword "xxx"
v1SigningEnabled true
v2SigningEnabled false
}
}
总结
- 系统应用必须用设备的 platform 私钥签名。
- 签名后的 APK 要放到
/system/priv-app/<applicationId>/app.apk。 - 配置目录权限
644、root:root、restorecon后重启。 AndroidManifest.xml必须声明android:sharedUserId="android.uid.system"。
按这套流程走下来,dumpsys package 看到 userId=1000 和 permission grant=true,就说明系统应用模式已经跑通。