目录
  1. 1. 一、PKMS 的体系定位
  2. 2. 二、PKMS 启动流程与扫描管线
    1. 2.1. 2.1 SystemServer 中启动 PKMS
    2. 2.2. 2.2 PKMS 构造函数——扫描管线
    3. 2.3. 2.3 scanDirTracedLI——目录扫描
    4. 2.4. 2.4 PackageParser2——APK 解析器
    5. 2.5. 2.5 scanPackageChildLI——深度扫描与登记
  3. 3. 三、APK 安装流程
    1. 3.1. 3.1 安装入口
    2. 3.2. 3.2 安装的执行阶段
    3. 3.3. 3.3 dexopt 触发
  4. 4. 四、Settings 与 packages.xml
    1. 4.1. 4.1 Settings 类
    2. 4.2. 4.2 packages.xml 内容示例
  5. 5. 五、权限管理
    1. 5.1. 5.1 BasePermission 与 PermissionInfo
    2. 5.2. 5.2 权限授予逻辑
  6. 6. 六、组件解析(Component Resolution)
  7. 7. 七、ABI 确定与 Native Library 管理
  8. 8. 八、核心面试题
【吃透源码系列】之PKMS

PackageManagerService(PKMS)是 Android 系统中负责应用包管理的核心服务。从 APK 的扫描解析、安装卸载,到权限管理、组件解析、共享 UID 管理,PKMS 是整个应用生态的底座。本文基于 Android 11 AOSP 源码,深入分析 PKMS 的启动流程、APK 扫描管线、安装流程、权限模型和关键数据结构。

一、PKMS 的体系定位

PKMS 运行在 system_server 进程中,是引导服务(Bootstrap Service)之一,在 SystemServer 的 startBootstrapServices 阶段被创建,早于 AMS 和 WMS。

SystemServer.startBootstrapServices()
└── PMS.main() // 静态工厂方法
└── PKMS(Context) // 构造函数(执行扫描等主要逻辑)
├── Settings // 所有已安装包配置(packages.xml)
├── PackageParser // APK 解析器(Android 11 改为 PackageParser2)
├── PermissionManagerService // 权限管理(Android 11+ 拆分)
└── Installer // installd 守护进程代理

AOSP 核心路径:

  • frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
  • frameworks/base/services/core/java/com/android/server/pm/Settings.java
  • frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java

二、PKMS 启动流程与扫描管线

2.1 SystemServer 中启动 PKMS

// frameworks/base/services/java/com/android/server/SystemServer.java
private void startBootstrapServices() {
// ... AMS 启动之后
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
// PKMS 注册到 ServiceManager
ServiceManager.addService("package", mPackageManagerService);
// 首次启动标记
mFirstBoot = mPackageManagerService.isFirstBoot();
// 获取包管理器的客户端接口
mPackageManager = mSystemContext.getPackageManager();
}

2.2 PKMS 构造函数——扫描管线

PKMS 的构造函数是理解 APK 扫描的核心入口。在 Android 11 中,扫描流程大致分为以下几个阶段:

// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {

// 阶段1:初始化基础组件
mContext = context;
mInstaller = installer; // installd 的代理
mPmsBgHandler = new Handler(BackgroundThread.getHandler().getLooper());

// 阶段2:创建 Settings 对象(持久化配置管理)
mSettings = new Settings(mPmsBgHandler.getLooper());
// 读取 packages.xml 等持久化文件
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, ...);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ...);

// 阶段3:扫描系统 APK
// scanDirTracedLI 是扫描单个目录的核心方法
// 依次扫描以下分区:
// 1) /system/framework (framework-res.apk 等)
// 2) /system/priv-app
// 3) /system/app
// 4) /vendor/app
// 5) /product/app
// 6) /data/app (已安装的第三方应用)

// 阶段3.1:解析 framework-res.apk
File frameworkDir = new File(Environment.getRootDirectory(), "framework");

// 阶段3.2:使用 ParallelPackageParser 多线程解析
// 扫描 /system/priv-app、/system/app 等分区
scanDirTracedLI(systemAppDir, ...);

// 阶段4:处理所有已解析的包
for (PackageSetting ps : mSettings.mPackages.values()) {
// 处理包配置
}

// 阶段5:更新组件解析表
// 如 Activity、Service、BroadcastReceiver 的 IntentFilter 解析
mComponentResolver = new ComponentResolver(activityResolvers, ...);

// 阶段6:更新权限信息
updateAllPermissions(null, true);
}

2.3 scanDirTracedLI——目录扫描

// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private void scanDirTracedLI(File scanDir, int parseFlags, int scanFlags,
long currentTime, PackageParser2 packageParser) {
// 1. 列出目录下所有 APK 文件
final File[] files = scanDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
return;
}

// 2. 使用 ParallelPackageParser 并行解析
try (ParallelPackageParser parallelPackageParser =
new ParallelPackageParser(packageParser, mExecutorService)) {
// 提交所有 APK 文件进行解析
for (File file : files) {
parallelPackageParser.submit(file, parseFlags);
}

// 3. 依次处理每个解析结果
for (ParseResult result; (result = parallelPackageParser.take()) != null; ) {
// 对每个 APK 执行深度扫描
scanPackageChildLI(result.pkg, parseFlags, scanFlags,
currentTime, null /* user */);
}
}
}

2.4 PackageParser2——APK 解析器

Android 11 用 PackageParser2 替代了 PackageParser,核心改进是使用了 TypedKeyValue 和增量解析特性,提升了扫描速度:

// frameworks/base/services/core/java/com/android/server/pm/parsing/PackageParser2.java
public class PackageParser2 {
// 解析 APK 的核心方法
public ParsedPackage parsePackage(File packageFile, int flags)
throws PackageManagerException {
// 1. 获取 ApkLite(轻量级 APK 信息)
ApkLite baseApk = getApkLite(packageFile, flags);

// 2. 解析 AndroidManifest.xml
ParseInput input = mParsingThreadLocal.get().reset();
// parseMonolithicPackage 解析整个包信息:
// - package name, versionCode, versionName
// - uses-permission, uses-feature
// - application (四大组件声明)
// - activity, service, receiver, provider 的 intent-filter
ParsedPackage pkg = parseMonolithicPackage(input, baseApk, flags);

return pkg;
}

// 解析 AndroidManifest XML
private ParsedPackage parseMonolithicPackage(ParseInput input,
ApkLite baseApk, int flags) {
// 读取 AndroidManifest.xml 并转为二进制 XML
// 使用 TypedKeyValue 进行高性能解析
return PackageCacher.parseMonolithicPackage(input,
baseApk.getPath(), baseApk.getSigningDetails(), ...);
}
}

2.5 scanPackageChildLI——深度扫描与登记

// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private PackageSetting scanPackageChildLI(ParsedPackage pkg, ...) {
// 1. 创建或更新 PackageSetting(持久化配置)
PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.getPackageName());
if (pkgSetting == null) {
pkgSetting = mSettings.insertPackageSettingLPw(pkg, ...);
}

// 2. 处理 SharedUserId(如果有)
if (pkg.getSharedUserId() != null) {
SharedUserSetting sharedUser = mSettings.getSharedUserLPw(
pkg.getSharedUserId(), ...);
pkgSetting.setSharedUserSetting(sharedUser);
}

// 3. 验证签名
if (!mSettings.isSignatureMatch(pkgSetting, pkg.getSigningDetails())) {
// 签名不匹配处理...
}

// 4. 确定 ABI(CPU 架构)
String primaryCpuAbi = PackageManagerService.computePrimaryCpuAbi(
pkg.getCpuAbiOverride(), scanFlags);

// 5. 将组件信息注册到 SystemServer 的解析表中
commitReconciledScanResultLocked(reconciledPkg, mUserManager.getUserIds());

return pkgSetting;
}

三、APK 安装流程

3.1 安装入口

APK 安装可以通过多种方式触发:PackageInstaller(系统安装器 UI)、adb install、Google Play 等。所有方式最终都通过 PackageInstallerService 的 Session 机制实现。

// frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java
public class PackageInstallerService extends IPackageInstaller.Stub {
// 创建安装会话
public int createSession(SessionParams params, String installerPackageName, int userId) {
// 生成唯一的 sessionId
final int sessionId = allocateSessionIdLocked();
// 创建临时目录
File stageDir = buildStageDir(params, sessionId);
// 创建 PackageInstallerSession
PackageInstallerSession session = new PackageInstallerSession(
mInternalCallback, mContext, mPm, ...);
mSessions.put(sessionId, session);
return sessionId;
}

// 提交安装
public void commitSession(int sessionId) {
synchronized (mSessions) {
PackageInstallerSession session = mSessions.get(sessionId);
session.commit(PreapprovalDetails.DETAILS_UNKNOWN);
}
}
}

3.2 安装的执行阶段

// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
void installStage(ActiveInstallSession activeInstallSession) {
// 阶段1:复制 APK 到 /data/app 目录
mPendingInstalls.put(activeInstallSession.getSessionId(), ...);

// 阶段2:通过 Handler 在后台线程执行
mHandler.post(() -> {
// 阶段3:调用 processInstallRequests
processInstallRequests(installRequests, ...);
});
}

void processInstallRequests(List<InstallRequest> installRequests, ...) {
// 1. 验证包名、签名
// 2. 复制 native libs 到 /data/app/<pkg>/lib/
// 3. 执行 dexopt(dex2oat)
// - 调用 Installer.dexopt()
// - 生成 oat 文件到 /data/dalvik-cache/
// 4. 创建应用数据目录 /data/data/<pkg>/
// 5. 更新 packages.xml
// 6. 发送 ACTION_PACKAGE_ADDED 广播
// 7. 通知 AMS 更新组件信息
}

3.3 dexopt 触发

// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private void performDexopt(List<PackageSetting> pkgSettings, ...) {
for (PackageSetting pkgSetting : pkgSettings) {
// 调用 InstalleNative 的 dexopt
mInstaller.dexopt(pkgSetting.getPath(),
pkgSetting.getAppId(),
pkgSetting.getPkgName(),
instructionSet,
dexoptNeeded,
null /*outputPath*/,
dexFlags,
compilerFilter, // speed / speed-profile / verify 等
...);
}
}

四、Settings 与 packages.xml

4.1 Settings 类

Settings 是 PKMS 的持久化配置管理类,管理所有已安装包的状态信息,并在重启后从 packages.xml 恢复。

// frameworks/base/services/core/java/com/android/server/pm/Settings.java
final class Settings {
// 所有已安装包的配置
final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>();

// SharedUserId → SharedUserSetting 的映射
final ArrayMap<String, SharedUserSetting> mSharedUsers = new ArrayMap<>();

// 读取 packages.xml
boolean readLPw(@NonNull List<UserInfo> users) {
FileInputStream str = new FileInputStream(mSettingsFilename);
// 使用 XML pull parser 解析 packages.xml
XmlPullParser parser = Xml.newPullParser();
// 逐条恢复 PackageSetting 信息
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
if (type == XmlPullParser.START_TAG) {
String tagName = parser.getName();
if (tagName.equals("package")) {
readPackageLPw(parser);
} else if (tagName.equals("shared-user")) {
readSharedUserLPw(parser);
}
}
}
return true;
}

// 写入 packages.xml
void writeLPr() {
// 序列化所有 PackageSetting 和 SharedUserSetting
}
}

4.2 packages.xml 内容示例

packages.xml 位于 /data/system/packages.xml,记录了每个已安装应用的完整配置信息:

<package name="com.example.app" codePath="/data/app/com.example.app-xxx"
nativeLibraryPath="/data/app/com.example.app-xxx/lib"
primaryCpuAbi="arm64-v8a" userId="10123" ...>
<sigs count="1">
<cert index="0" key="..."/>
</sigs>
<perms>
<item name="android.permission.INTERNET" granted="true" flags="0"/>
</perms>
<proper-signing-keyset identifier="1"/>
</package>

五、权限管理

5.1 BasePermission 与 PermissionInfo

// frameworks/base/services/core/java/com/android/server/pm/permission/Permission.java
final class Permission {
final PermissionInfo info; // 权限元数据(AndroidManifest 中定义)
final int type; // 权限类型:Normal, Dangerous, Signature
boolean mReconciled;

static final int TYPE_MANIFEST = 0;
static final int TYPE_CONFIG = 1;
static final int TYPE_DYNAMIC = 2;
}

// frameworks/base/services/core/java/com/android/server/pm/permission/PermissionRegistry.java
// 维护所有权限的注册表
final class PermissionRegistry {
final ArrayMap<String, Permission> mPermissions = new ArrayMap<>();
final ArrayMap<String, Permission> mTreePermissions = new ArrayMap<>();
}

5.2 权限授予逻辑

// frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
// Android 11+ 权限管理被拆分成独立的 PermissionManagerService
private int grantPermissions(PackageState packageState, ...) {
// 遍历申请的所有权限
for (String permName : allPermissions) {
Permission permission = mPermissionRegistry.getPermission(permName);
if (permission == null) continue;

if (permission.getProtection() == PermissionInfo.PROTECTION_NORMAL) {
// Normal 权限:自动授予
grantPermission(packageState, permName, userId);
} else if (permission.getProtection() == PermissionInfo.PROTECTION_DANGEROUS) {
// Dangerous 权限:需要用户确认(或从备份恢复)
if (hasUserApproval || restoredFromBackup) {
grantPermission(packageState, permName, userId);
}
} else if (permission.getProtection() == PermissionInfo.PROTECTION_SIGNATURE) {
// Signature 权限:签名匹配则自动授予
if (packageState.isSignedWithPlatformKey()) {
grantPermission(packageState, permName, userId);
}
}
}
}

六、组件解析(Component Resolution)

当应用通过 PackageManager.queryIntentActivities() 查询能处理某个 Intent 的 Activity 时,PKMS 通过 ComponentResolver 高效地进行组件匹配。

// frameworks/base/services/core/java/com/android/server/pm/ComponentResolver.java
public class ComponentResolver {
// Activity IntentFilter 注册表
private final ActivityIntentResolver mActivities;
// Service IntentFilter 注册表
private final ServiceIntentResolver mServices;
// BroadcastReceiver IntentFilter 注册表
private final ReceiverIntentResolver mReceivers;
// ContentProvider 注册表
private final ProviderIntentResolver mProviders;

// 查询匹配的 Activity
List<ResolveInfo> queryActivities(Intent intent, String resolvedType,
int flags, int userId) {
// 从 mActivities 中查询所有匹配 intent-filter 的 ActivityInfo
return mActivities.queryIntent(intent, resolvedType, flags, userId);
}
}

根 IntentResolver 的匹配逻辑:

  1. 匹配 Action(如果 Intent 指定了 action)
  2. 匹配 Category(所有 category 都要匹配)
  3. 匹配 Data(URI scheme、host、path、mimeType)
  4. 按优先级排序(priority 值和 preferred)

七、ABI 确定与 Native Library 管理

PKMS 在安装时需要为 APK 确定正确的 CPU ABI,以便在 /data/app/<pkg>/lib/ 下建立正确的 native 库目录。

// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
static String computePrimaryCpuAbi(ScanPackage pkg, int scanFlags) {
// 1. 检查 APK 中是否包含原生库
String[] abis = pkg.getCpuAbis();

// 2. 按照优先级确定最优 ABI
// arm64-v8a > armeabi-v7a > armeabi
// x86_64 > x86
for (String buildAbi : Build.SUPPORTED_ABIS) {
for (String pkgAbi : abis) {
if (buildAbi.equals(pkgAbi)) {
return buildAbi;
}
}
}

// 3. 如果 APK 只提供了 32 位库,设备是 64 位架构
// 使用通过 Build.SUPPORTED_32_BIT_ABIS 中匹配的第一项
return null;
}

八、核心面试题

Q1:PKMS 如何实现应用间共享 UID?它的安全风险是什么?

PKMS 通过 SharedUserSetting 管理共享 UID。当多个 APK 声明相同的 android:sharedUserId 且使用相同的签名时,它们会被分配到相同的 Linux UID,从而可以相互访问对方的文件(/data/data/<pkg>/)。风险显而易见:如果一个共享 UID 的应用存在安全漏洞,同 UID 的所有应用的数据都可能被利用。在 Android 11+ 中,Google 进一步收紧了 sharedUserId 的使用,新应用不推荐使用。

Q2:PKMS 中的 packages.xml 和 packages.list 分别存储什么信息?

packages.xml(位于 /data/system/)存储所有已安装应用的完整元数据:包名、代码路径、native 库路径、签名证书、授予的权限、SharedUserId 信息等。每次应用安装/卸载时更新。
packages.list(位于 /data/system/)以更简洁的格式存储包名和 UID 的映射关系,格式为:<pkgName> <uid> <dataDir>,供快速查询使用。

Q3:Android 11 中 PermissionManagerService 为什么从 PKMS 中独立出来?

主要出于架构解耦和安全性考虑:(1) 权限检查是高频操作,独立成单独服务后可以更好地优化;(2) 分离权限管理代码使得代码边界更清晰,便于安全审计;(3) 为未来的权限模型演进(如 Scoped Storage、One-Time Permissions)提供更灵活的基础。

AOSP 核心路径参考:

  • frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
  • frameworks/base/services/core/java/com/android/server/pm/Settings.java
  • frameworks/base/services/core/java/com/android/server/pm/ComponentResolver.java
  • frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java
  • frameworks/base/services/core/java/com/android/server/pm/parsing/PackageParser2.java
  • frameworks/base/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
  • frameworks/base/services/core/java/com/android/server/pm/permission/PermissionRegistry.java
打赏
  • 微信
  • 支付宝

评论