Android 系统 APK 分区存放剖析-你的apk应该放在哪里?

一、概述

在 Android 系统中,APK 的存放路径远不止 /system/app 这一个。从 Android 早期到现在,随着系统架构的演进(尤其是 Project Treble 之后),APK 的存放路径被划分成了多个不同的分区目录。不同分区的 APK 在卸载行为权限获取机制签名要求等方面都有本质区别。

本文基于 AOSP 15 源码设备的实际编译产物,对 Android 系统中所有 APK 存放路径做一个完整的梳理和对比。

在这里插入图片描述


二、所有分区路径总览

以下是从你的 AOSP 15 编译产物中列出的所有 APK 存放分区及其实际内容(以 target/product/grus 为例):

在这里插入图片描述

三、各分区详解

3.1 /data/app —— 第三方应用

这是最普遍的第三方应用路径。通过 Google Play 或其他应用商店安装、或者用户手动 adb install 的 APK,都存放在这里。

  • 可卸载:用户可以随时卸载
  • 签名:无特殊要求,开发者自签名即可
  • 权限:只能使用 normaldangerous 保护级别的权限
  • 实际路径:每个 app 一个子目录,如 /data/app/com.example.app-xxxxxxxx/
  • 编译产物中不存在:因为它是运行时动态安装的,编译产物不会预置

3.2 /system/app —— 系统内置应用

这是 Android 内置的系统级应用路径,与 /data/app 不同,这里的应用不能被普通用户卸载

  • 可卸载:普通用户不可卸载(需要 root 或系统级操作)
  • 签名无强制要求,可以是 platform 签名、shared 签名、media 签名、甚至是第三方自定义签名
  • 权限:可以声明 normaldangerous 级别权限,但对于 signature|privileged 保护级别的权限默认无法获得(需满足额外条件,见后文)
  • 编译产物举例
system/app/BasicDreams/            # 屏保
system/app/BluetoothMidiService/   # 蓝牙MIDI服务
system/app/CaptivePortalLogin/     # WiFi 登录门户
system/app/CertInstaller/          # 证书安装器
system/app/KeyChain/               # 密钥链
system/app/PrintSpooler/           # 打印服务
system/app/Stk/                    # SIM工具包
system/app/EasterEgg/              # Android彩蛋
  • Build 配置示例(Soong / Android.bp)
android_app {
    name: "BasicDreams",
    platform_apis: true,
    certificate: "platform",  // 签名自选
    // 没设 privileged: true,所以进 system/app
}

3.3 /system/priv-app —— 系统特权应用

priv-app 是 Android 4.4(KitKat)引入的概念,在后续版本中不断增强。它与 system/app 最核心的区别在于:

priv-app 中的 APK 有"资格"申请 signature|privileged 保护级别的系统权限,但前提是必须在对应的 privapp-permissions.xml 文件中显式声明。

  • 可卸载:普通用户不可卸载
  • 签名:同 system/app,无强制要求
  • 权限门槛:放置于 priv-app 只是获得了一张"门票",真正获得权限还需要第二步——白名单声明(见第四章)
  • 编译产物举例
system/priv-app/CalendarProvider/         # 日历提供者
system/priv-app/ContactsProvider/         # 联系人提供者
system/priv-app/CredentialManager/        # 凭证管理
system/priv-app/DocumentsUI/              # 文件选择器
system/priv-app/DownloadProvider/         # 下载管理器
system/priv-app/ExternalStorageProvider/  # 外部存储提供者
system/priv-app/FusedLocation/            # 融合定位
system/priv-app/IntentResolver/           # Intent解析器
  • Build 配置示例(Soong)
android_app {
    name: "CalendarProvider",
    platform_apis: true,
    certificate: "platform",
    privileged: true,   // <-- 这行决定进 system/priv-app
}
  • 传统 Makefile 配置(Android.mk)
LOCAL_PRIVILEGED_MODULE := true

3.4 /vendor/app/vendor/priv-app —— 硬件厂商分区(Project Treble)

Android 8.0 引入 Project Treble,将**硬件相关代码(HAL 实现、SoC 驱动配套 app)**从 system 分区中分离出来,形成 vendor 分区。

  • 目的:让 system 分区可以独立升级(Generic System Image, GSI),不受硬件厂商定制影响
  • 存放内容:与硬件/SoC 紧耦合的 APK,如运营商网络相关(CneApp、IWlanService)、Qualcomm 配套服务等
  • 可卸载:不可卸载
  • 编译产物举例
vendor/app/CneApp/          # 连接引擎(Qualcomm)
vendor/app/IWlanService/    # IWLAN服务
vendor/app/TimeService/     # 时间服务
vendor/app/CACertService/   # CA证书服务
  • Build 配置示例(Soong)
android_app {
    name: "CneApp",
    proprietary: true,      // vendor 分区
    certificate: "platform",
    ...
}
  • 传统 Makefile 配置
LOCAL_VENDOR_MODULE := true

3.5 /product/app/product/priv-app —— 产品分区(Android 9+)

Android 9 引入 Product 分区,用于存放OEM 厂商定制的产品级应用。这些应用不是 AOSP 原生的,也不是硬件绑定的,而属于 OEM 的差异化定制(相机 App、时钟、短信等)。

  • 目的:更精细的模块化,让 OEM 的定制内容也可以单独构建和升级
  • 编译产物举例
product/app/Aperture/       # 相机(LineageOS)
product/app/DeskClock/      # 时钟
product/app/Gallery2/       # 图库
product/app/LatinIME/       # 输入法
product/app/Jelly/          # 浏览器
product/app/messaging/      # 短信
product/app/Recorder/       # 录音机
product/priv-app/Contacts/  # 联系人
product/priv-app/Dialer/    # 拨号器
product/priv-app/SettingsIntelligence/  # 设置建议
  • Build 配置示例(Soong)
android_app {
    name: "Dialer",
    product_specific: true,
    privileged: true,
    certificate: "platform",
    ...
}

3.6 /system_ext/app/system_ext/priv-app —— 系统扩展分区(Android 10/11+)

Android 10/11 引入 SystemExt 分区。这是为了解决一个尴尬的问题:很多 AOSP 核心应用(如 Settings、SystemUI、Launcher3、Telecom)既不能放在 product 分区(因为它们是 AOSP 原生组件,不是 OEM 定制),又不宜留在 system 分区(为了更好的模块化)。

  • 定位:存放"扩展 AOSP 功能"的组件,介于 system 和 product 之间
  • 编译产物举例(在 grus 上这是最丰富的 priv-app 目录)
system_ext/app/AccessibilityMenu/   # 无障碍菜单
system_ext/app/IFAAService/         # IFAA生物识别服务
system_ext/app/QtiTelephonyService/ # QTI电话服务
system_ext/app/WAPPushManager/      # WAP推送管理

system_ext/priv-app/Settings/       # <-- 设置!已从 system/priv-app 迁移
system_ext/priv-app/SystemUI/       # <-- 系统UI!
system_ext/priv-app/TrebuchetQuickStep/  # Launcher
system_ext/priv-app/ThemePicker/    # 主题选择器
system_ext/priv-app/CarrierConfig/  # 运营商配置
system_ext/priv-app/Seedvault/      # 备份
system_ext/priv-app/Updater/        # 系统更新
system_ext/priv-app/AudioFX/        # 音效
system_ext/priv-app/StorageManager/ # 存储管理
  • Build 配置示例(Settings APK)
android_app {
    name: "Settings",
    platform_apis: true,
    certificate: "platform",
    system_ext_specific: true,   // <-- 指定进 system_ext
    privileged: true,            // <-- 指定进 priv-app 子目录
    required: [
        "privapp_whitelist_com.android.settings",
        "settings-platform-compat-config",
    ],
    ...
}

关键代码位于 packages/apps/Settings/Android.bp:158-159

system_ext_specific: true,
privileged: true,

3.7 /odm/app/odm/priv-app —— ODM 分区

ODM(Original Design Manufacturer)分区是为原始设计制造商准备的。ODM 通常是设计并代工手机的工厂(如闻泰、华勤),它们在 OEM 品牌(如小米)的基础上做二次定制。

  • 使用场景:ODM 厂商需要加入自己的特定应用,但又不想和 OEM(product)或 SoC(vendor)混在一起

确认你的apk安装在哪

在开发过程中有时候需要知道某个app具体apk放在在哪个分区,那么这个时候只需要知道packageName就可以了。

相关命令:

先确认报名,这里先打开要确认app的Activity

然后使用
adb shell am stack list命令


 adb shell am stack list
 
RootTask id=1 bounds=[0,0][1080,2340] displayId=0 userId=0
 configuration={1.0 ?mcc0mnc [en_US] ldltr sw393dp w393dp h851dp 440dpi nrml long hdr widecg port night finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 0 - 1080, 2340) mMaxBounds=Rect(0, 0 - 1080, 2340) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mActivityType=home mAlwaysOnTop=undefined mRotation=ROTATION_0} as.3 s.28 fontWeightAdjustment=0}
  taskId=54: com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher bounds=[0,0][1080,2340] userId=0 visible=true topActivity=ComponentInfo{com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher}

RootTask id=2 bounds=[0,0][1080,2340] displayId=0 userId=0
 configuration={1.0 ?mcc0mnc [en_US] ldltr sw393dp w393dp h851dp 440dpi nrml long hdr widecg port night finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 0 - 1080, 2340) mMaxBounds=Rect(0, 0 - 1080, 2340) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} as.3 s.28 fontWeightAdjustment=0}
  taskId=3: unknown bounds=[0,0][1080,2340] userId=0 visible=false
  taskId=4: unknown bounds=[0,2340][1080,3510] userId=0 visible=false

可以看到launcher包名是com.android.launcher3。

那么接下来在看看包名对应的apk目录:

这里可以使用adb shell dumpsys package com.android.launcher3方式输出所有这个包名的pms相关信息

test@test:~/wmtrace$ adb shell  dumpsys package  com.android.launcher3 | grep path
      overlay paths:
      legacy overlay paths:
    path: /system_ext/priv-app/TrebuchetQuickStep/TrebuchetQuickStep.apk

可以确认apk路径位于
/system_ext/priv-app/TrebuchetQuickStep/TrebuchetQuickStep.apk。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值