
1. 理解/system/product/priv-app目录的特殊性在Android系统中/system/product/priv-app目录是一个具有特殊权限的应用存放位置。与普通的/system/app目录不同这里的应用会被自动授予PRIVILEGED权限这意味着它们可以访问普通应用无法获取的系统级API和权限。这个目录通常用于存放设备制造商预装的核心应用如系统设置、拨号器等关键组件。priv-app目录下的APK需要满足几个关键条件必须包含privileged权限声明需要正确的签名通常使用平台签名必须包含在系统的白名单中注意从Android 10开始Google加强了分区限制/system分区变为只读。因此现代方案更多使用动态分区如/product分区来存放这类预装应用。2. 预装APK的准备工作2.1 APK的权限配置要使APK能够预装到priv-app目录首先需要在AndroidManifest.xml中添加特权声明manifest xmlns:androidhttp://schemas.android.com/apk/res/android packagecom.example.myapp !-- 关键声明 -- privileged-permission android:nameandroid.permission.CONTROL_DEVICE/ !-- 其他配置 -- ... /manifest2.2 签名要求priv-app下的APK必须使用平台签名密钥签名。通常这是由设备制造商持有的密钥。开发阶段可以使用测试密钥# 使用AOSP测试密钥签名 java -jar signapk.jar platform.x509.pem platform.pk8 app-debug.apk app-signed.apk2.3 白名单配置在AOSP源码中需要将应用包名添加到/etc/permissions/privapp-permissions-[device].xmlpermissions privapp-permissions packagecom.example.myapp permission nameandroid.permission.CONTROL_DEVICE/ /privapp-permissions /permissions3. 使用Android.bp构建系统集成3.1 创建Android.bp文件在AOSP源码树中为你的APK创建构建定义文件android_app { name: MyPrivApp, srcs: [src/**/*.java], resource_dirs: [res], // 关键配置 privileged: true, product_specific: true, certificate: platform, static_libs: [androidx.appcompat_appcompat], manifest: AndroidManifest.xml, }3.2 产品特定配置在设备的产品定义文件如device/[vendor]/[device]/[product].mk中添加PRODUCT_PACKAGES MyPrivApp PRODUCT_PRIVILEGED_MODULES MyPrivApp3.3 目录结构规范APK在源码树中的推荐存放位置vendor/[vendor]/[device]/prebuilts/priv-app/MyPrivApp/ ├── Android.bp ├── AndroidManifest.xml ├── res/ └── src/4. 手动部署方案无需编译整个系统4.1 准备工作获取已签名的APK文件确保设备已解锁bootloader获取root权限临时或永久4.2 部署步骤# 重新挂载/system为可读写 adb root adb remount # 推送APK到目标目录 adb push MyPrivApp.apk /system/product/priv-app/MyPrivApp/ # 创建必要的目录结构 adb shell mkdir -p /system/product/priv-app/MyPrivApp/oat/arm64 # 设置正确权限 adb shell chmod 755 /system/product/priv-app/MyPrivApp adb shell chmod 644 /system/product/priv-app/MyPrivApp/MyPrivApp.apk # 重启设备 adb reboot4.3 验证安装设备重启后检查adb shell pm list packages | grep myapp adb shell dumpsys package com.example.myapp | grep flags应看到flagsPRIVILEGED的标记。5. 常见问题排查5.1 应用未出现在应用列表中可能原因签名不匹配必须使用平台签名缺少privapp-permissions配置SELinux策略限制检查日志adb logcat | grep -E PackageManager|MyPrivApp5.2 权限被拒绝典型错误java.lang.SecurityException: Package com.example.myapp has not requested permission android.permission.CONTROL_DEVICE解决方案确认APK的AndroidManifest.xml已声明权限检查privapp-permissions.xml是否包含该权限授权验证APK是否确实安装到了priv-app目录5.3 系统升级后应用消失这是因为/system分区在OTA升级时会被完全覆盖。持久化方案将APK放入/product分区如果设备支持使用动态分区方案创建刷机脚本在升级后自动恢复6. 高级技巧与优化6.1 多架构支持对于包含native库的APK需要处理多ABI支持android_app { name: MyPrivApp, // ...其他配置 compile_multilib: both, native_shared_libs: [mynative], }6.2 资源覆盖机制priv-app可以覆盖系统默认资源在APK的res/values/中定义!-- 覆盖系统默认主题 -- style nameTheme.DeviceDefault parentandroid:style/Theme.DeviceDefault item nameandroid:colorPrimarycolor/my_primary/item /style6.3 版本兼容处理在Android.bp中使用特定版本配置target: { android: { min_sdk_version: 29, max_sdk_version: 33, }, },7. 替代方案比较7.1 不同预装目录对比目录权限级别可卸载更新机制适用场景/system/priv-appPRIVILEGED不可需系统更新核心系统应用/system/app普通不可需系统更新基础系统应用/product/priv-appPRIVILEGED不可需产品分区更新厂商定制应用/vendor/app普通不可需vendor分区更新硬件相关应用/data/app普通可动态更新用户应用7.2 动态加载方案对于需要频繁更新的特权应用可以考虑将核心功能拆分为特权APK普通APK特权APK只提供权限代理业务逻辑放在可动态更新的普通APK中实现示例// 在特权APK中 public class PermissionProxy extends Binder { Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) { verifyCallingPackage(com.example.myapp.normal); // 执行特权操作 } }8. 安全最佳实践最小权限原则只请求必要的privileged权限签名保护严格保管平台签名密钥输入验证对所有跨进程调用进行验证定期审计检查privapp-permissions配置隔离设计将特权组件与非特权组件分离审计脚本示例# 检查所有特权应用的权限使用情况 adb shell pm list packages -f -U | grep priv-app | while read line; do pkg${line##*} echo $pkg adb shell dumpsys package $pkg | grep -A 10 requested permissions done9. 实际案例预装系统设置插件假设我们要预装一个自定义的系统设置插件创建Android.bpandroid_app { name: CustomSettings, srcs: [src/**/*.java], resource_dirs: [res], manifest: AndroidManifest.xml, privileged: true, product_specific: true, certificate: platform, static_libs: [ androidx.preference_preference, SettingsLib ], }在系统设置中添加入口!-- in res/xml/settings_headers.xml -- header android:idid/custom_settings android:titlestring/custom_settings_title android:fragmentcom.example.customsettings.CustomFragment /添加权限配置!-- etc/permissions/privapp-permissions-device.xml -- privapp-permissions packagecom.example.customsettings permission nameandroid.permission.WRITE_SECURE_SETTINGS/ permission nameandroid.permission.CONTROL_DEVICE/ /privapp-permissions10. 调试技巧10.1 日志过滤专用logcat过滤器adb logcat -v threadtime -s CustomSettings:I \ ActivityManager:I PackageManager:I *:S10.2 运行时检查验证特权状态public boolean isPrivileged() { try { ApplicationInfo ai getPackageManager() .getApplicationInfo(getPackageName(), 0); return (ai.privateFlags ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) ! 0; } catch (PackageManager.NameNotFoundException e) { return false; } }10.3 资源覆盖调试检查当前资源值adb shell cmd overlay list adb shell cmd overlay dump package11. 性能优化建议延迟加载将非关键初始化放在后台线程模块化设计使用动态功能模块(DFM)资源优化使用WebP格式图片压缩资源ProGuard规则确保核心代码不被混淆示例ProGuard配置-keep class com.example.myapp.** { *; } -keepclassmembers class * extends android.app.Service { public *; }12. 兼容性处理12.1 多版本适配在Android.bp中使用条件编译target: { android: { cflags: [ -DANDROID_VERSION ctx.config().get(Platform_sdk_version), ], }, },12.2 备用方案当特权功能不可用时提供降级方案public void performPrivilegedAction() { try { // 尝试特权API SystemProperties.set(custom.property, value); } catch (SecurityException e) { // 降级处理 SharedPreferences prefs getSharedPreferences(fallback, MODE_PRIVATE); prefs.edit().putString(property, value).apply(); } }13. 测试验证方案13.1 单元测试特权应用的特殊测试配置android_test { name: MyPrivAppTests, srcs: [test/**/*.java], test_suites: [general-tests], test_config: AndroidTest.xml, privileged: true, }13.2 自动化测试使用uiautomator测试特权功能RunWith(AndroidJUnit4.class) public class PrivilegedTest { Test public void testSystemPropertyAccess() { UiDevice device UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); device.executeShellCommand(setprop debug.myapp 1); // 验证特权操作 } }14. 版本更新策略14.1 无缝更新方案保留数据目录结构/system/product/priv-app/MyPrivApp/ ├── apk/ │ └── MyPrivApp.apk # 实际APK └── lib/ # Native库使用符号链接ln -sf /system/product/priv-app/MyPrivApp/apk/MyPrivApp.apk /system/product/priv-app/MyPrivApp.apk14.2 A/B更新支持在Android.bp中启用android_app { name: MyPrivApp, // ...其他配置 use_vendor: true, overrides: [other_priv_app], }15. 厂商定制扩展15.1 设备特定功能通过系统属性交互public class DeviceSpecificUtils { public static void enableFeature(boolean enable) { SystemProperties.set(vendor.myapp.feature.enable, enable ? 1 : 0); } }15.2 硬件抽象层集成JNI层示例// native-lib.cpp extern C JNIEXPORT void JNICALL Java_com_example_myapp_DeviceController_setHardwareMode( JNIEnv* env, jobject obj, jint mode) { vendor::hardware::control::V1_0::IControl::getService() -setMode(static_castint32_t(mode)); }16. 性能监控与调优16.1 启动时间优化测量应用启动时间adb shell am start-activity -W -n com.example.myapp/.MainActivity16.2 内存分析获取内存快照adb shell dumpsys meminfo com.example.myapp16.3 电池消耗监控检查唤醒锁adb shell dumpsys power | grep -i wake17. 用户数据管理17.1 数据迁移方案处理系统升级时的数据保留public class DataMigrationHelper { public static void migrateIfNeeded(Context context) { SharedPreferences oldPrefs context.getSharedPreferences( prefs, Context.MODE_PRIVATE); if (!oldPrefs.getBoolean(migrated, false)) { // 执行迁移 ContentResolver resolver context.getContentResolver(); // ...迁移逻辑 oldPrefs.edit().putBoolean(migrated, true).apply(); } } }17.2 备份恢复策略实现自动备份!-- AndroidManifest.xml -- application android:allowBackuptrue android:fullBackupContentxml/backup_rules ... /application18. 多用户支持18.1 用户感知处理检查当前用户类型UserManager um (UserManager) context.getSystemService(Context.USER_SERVICE); if (um.isSystemUser()) { // 系统用户特有逻辑 }18.2 跨用户数据共享使用ContentProvider跨用户共享// 在Manifest中声明 provider android:name.MyProvider android:authoritiescom.example.myapp.provider android:exportedtrue android:multiprocesstrue android:process:provider /19. 安全更新策略19.1 热修复方案通过特权应用加载补丁public class PatchLoader { public static void loadPatch(Context context, File patch) { try { DexClassLoader loader new DexClassLoader( patch.getAbsolutePath(), context.getCodeCacheDir().getAbsolutePath(), null, context.getClassLoader()); Class? clazz loader.loadClass(com.example.patch.Fix); // 应用补丁 } catch (Exception e) { Log.e(Patch, Failed to load patch, e); } } }19.2 证书轮换机制处理签名证书变更private boolean verifySignature(Context context) { PackageManager pm context.getPackageManager(); PackageInfo info pm.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES); Signature[] sigs info.signatures; // 验证签名是否在允许列表中 }20. 厂商协作建议接口标准化定义清晰的API边界兼容性测试套件提供CTS扩展测试文档规范详细记录特权接口版本协商建立版本兼容矩阵安全评审定期进行代码审计厂商接口示例/** * hide * vendor */ public interface IVendorFeature { /** 需要权限: vendor.permission.FEATURE_CONTROL */ void enableFeature(String feature, boolean enable); }