# PMS常见面试题

---

## 一、PMS基础概念

### Q1: 什么是PMS？它的作用是什么？

**A:** PMS（PackageManagerService）是Android系统的核心服务之一，运行在system_server进程中。

**主要作用：**

1. **应用安装管理**：管理应用的安装、卸载、更新
2. **权限管理**：管理应用权限的授予、撤销和检查
3. **组件管理**：管理Activity、Service、BroadcastReceiver、ContentProvider等组件信息
4. **包扫描**：扫描系统和应用目录中的APK文件
5. **签名验证**：验证APK的签名信息，确保应用安全性
6. **多用户管理**：支持多用户环境下的应用隔离和管理

### Q2: PMS在系统启动流程中的位置？

**A:** PMS在系统启动流程中的位置：

1. **Bootloader阶段**：加载Linux内核
2. **Kernel启动**：初始化硬件，启动init进程
3. **Init进程**：解析init.rc，启动Zygote和ServiceManager
4. **Zygote进程**：预加载类和资源，fork出SystemServer进程
5. **SystemServer进程**：启动各类系统服务
   - 启动PMS（PackageManagerService）
   - 启动AMS（ActivityManagerService）
   - 启动WMS（WindowManagerService）
   - 启动其他系统服务
6. **PMS扫描应用**：系统启动时，PMS扫描系统目录和应用目录中的APK文件

### Q3: PMS与其他系统服务的关系？

**A:** PMS与其他系统服务的关系：

1. **PMS与AMS**：AMS需要PMS提供包信息来启动Activity
2. **PMS与Installer**：PMS通过Installer执行实际的APK安装操作
3. **PMS与UserManagerService**：PMS需要UserManagerService管理多用户
4. **PMS与StorageManagerService**：PMS需要StorageManagerService管理存储空间

---

## 二、应用安装流程

### Q4: 请详细描述应用的安装流程？

**A:** 应用安装流程：

**客户端进程：**
1. `PackageInstaller.install()`：用户点击安装或调用安装API
2. `PackageInstaller.Session.commit()`：提交安装会话
3. `PackageInstaller.Session.commit()`：通过Binder调用PMS

**服务端进程（system_server）：**
4. `PackageManagerService.installPackageAsUser()`：PMS接收安装请求
5. `PackageManagerService.createInstallSession()`：创建安装会话
6. `PackageManagerService.writeApkToSession()`：写入APK文件到临时目录
7. `PackageManagerService.commitSession()`：提交安装会话
8. `PackageManagerService.installPackageTracedLI()`：执行安装
9. `PackageParser.parsePackage()`：解析APK文件
   - 解析AndroidManifest.xml
   - 提取四大组件信息
   - 提取权限信息
   - 验证签名
10. `PackageManagerService.scanPackageTracedLI()`：扫描包信息
11. `PackageManagerService.updateSettingsLI()`：更新包设置
12. `PackageManagerService.sendPackageBroadcast()`：发送安装完成广播

**关键步骤：**
- 权限检查：检查安装权限
- APK解析：解析APK的AndroidManifest.xml
- 签名验证：验证APK签名
- 冲突检查：检查包名冲突、版本冲突
- 存储检查：检查存储空间是否足够
- 安装执行：复制APK文件、创建数据目录
- 组件注册：注册Activity、Service等组件
- 权限授予：授予声明的权限

### Q5: APK解析过程是怎样的？

**A:** APK解析过程：

1. **创建PackageParser**
   ```java
   PackageParser parser = new PackageParser();
   ```

2. **解析APK文件**
   ```java
   PackageParser.Package pkg = parser.parsePackage(apkFile, flags);
   ```

3. **解析AndroidManifest.xml**
   - 解析包名、版本号等基本信息
   - 解析四大组件（Activity、Service、BroadcastReceiver、ContentProvider）
   - 解析权限声明
   - 解析Intent Filter
   - 解析资源信息

4. **收集证书信息**
   ```java
   collectCertificates(pkg);
   collectManifestDigest(pkg);
   ```

5. **提取组件信息**
   ```java
   extractActivities(pkg);
   extractServices(pkg);
   extractReceivers(pkg);
   extractProviders(pkg);
   extractPermissions(pkg);
   ```

6. **验证签名**
   - 验证APK签名是否有效
   - 检查签名是否匹配
   - 验证签名证书链

### Q6: 签名验证是如何进行的？

**A:** 签名验证过程：

1. **提取签名信息**
   ```java
   // 从APK中提取签名
   Signature[] signatures = packageInfo.signatures;
   ```

2. **验证签名格式**
   - 检查签名文件是否存在（META-INF/）
   - 验证签名文件格式是否正确

3. **验证签名证书**
   - 验证证书是否有效
   - 验证证书是否过期
   - 验证证书链是否完整

4. **验证签名匹配**
   - 如果是更新安装，验证新签名是否与旧签名匹配
   - 如果是共享UID应用，验证签名是否一致

5. **关键代码位置**
   - `PackageManagerService.verifySignatures()`
   - `PackageParser.collectCertificates()`
   - `PackageManagerService.checkUpgradeKeySetLocked()`

---

## 三、应用卸载流程

### Q7: 应用卸载流程是怎样的？

**A:** 应用卸载流程：

1. **卸载请求**
   ```java
   packageManager.deletePackage(packageName, observer, flags);
   ```

2. **PMS处理卸载**
   ```java
   PackageManagerService.deletePackageAsUser(packageName, userId, flags);
   ```

3. **检查卸载条件**
   - 检查应用是否正在运行
   - 检查是否有其他应用依赖
   - 检查卸载权限

4. **停止应用**
   - 停止应用的所有Activity
   - 停止应用的所有Service
   - 取消注册BroadcastReceiver

5. **删除文件**
   - 删除APK文件
   - 删除应用数据目录
   - 删除应用缓存

6. **更新包信息**
   - 从包列表中移除
   - 清理组件注册信息
   - 清理权限信息

7. **发送卸载广播**
   ```java
   sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, packageName);
   ```

### Q8: 卸载时如何清理应用数据？

**A:** 卸载时清理应用数据：

1. **删除应用目录**
   ```java
   // 删除应用数据目录
   /data/data/<package_name>/
   /data/user/<user_id>/<package_name>/
   ```

2. **删除APK文件**
   ```java
   // 删除APK文件
   /data/app/<package_name>-<random>/
   ```

3. **删除外部存储数据**
   ```java
   // 删除外部存储中的应用数据
   /sdcard/Android/data/<package_name>/
   ```

4. **清理数据库**
   - 清理包信息数据库
   - 清理权限数据库
   - 清理组件注册信息

5. **清理缓存**
   - 清理系统缓存中的应用信息
   - 清理其他服务中的应用引用

---

## 四、权限管理

### Q9: PMS如何管理应用权限？

**A:** PMS权限管理机制：

1. **权限声明**
   - 应用在AndroidManifest.xml中声明权限
   - PMS解析时提取权限信息

2. **权限授予**
   ```java
   // 授予权限
   packageManager.grantRuntimePermission(packageName, permission, userHandle);
   ```

3. **权限检查**
   ```java
   // 检查权限
   int result = packageManager.checkPermission(permission, packageName);
   if (result == PackageManager.PERMISSION_GRANTED) {
       // 权限已授予
   }
   ```

4. **权限撤销**
   ```java
   // 撤销权限
   packageManager.revokeRuntimePermission(packageName, permission, userHandle);
   ```

5. **权限存储**
   - 权限授予状态存储在`/data/system/users/<user_id>/runtime-permissions.xml`
   - 系统启动时加载权限状态

### Q10: 运行时权限和安装时权限的区别？

**A:** 运行时权限和安装时权限的区别：

**安装时权限（Normal Permissions）：**
- 在应用安装时自动授予
- 不需要用户确认
- 通常是低风险权限
- 例如：网络访问、振动等

**运行时权限（Dangerous Permissions）：**
- 需要运行时动态申请
- 需要用户确认
- 通常是高风险权限
- 例如：相机、位置、存储等

**权限分类：**
```java
// 权限保护级别
PROTECTION_NORMAL          // 普通权限，安装时授予
PROTECTION_DANGEROUS       // 危险权限，运行时申请
PROTECTION_SIGNATURE       // 签名权限，同签名应用自动授予
PROTECTION_SIGNATURE_OR_SYSTEM  // 签名或系统权限
```

---

## 五、包扫描机制

### Q11: PMS如何扫描应用？

**A:** PMS包扫描机制：

1. **系统目录扫描**
   - `/system/app/`：系统应用目录
   - `/system/priv-app/`：系统特权应用目录
   - `/vendor/app/`：厂商应用目录
   - `/oem/app/`：OEM应用目录

2. **用户目录扫描**
   - `/data/app/`：用户安装的应用目录
   - `/data/app-private/`：私有应用目录

3. **扫描流程**
   ```java
   // PMS扫描流程
   void scanDirTracedLI(File scanDir, int parseFlags, int scanFlags) {
       // 1. 遍历目录中的APK文件
       File[] files = scanDir.listFiles();
       
       // 2. 解析每个APK
       for (File file : files) {
           PackageParser.Package pkg = parsePackage(file, parseFlags);
           
           // 3. 扫描包信息
           scanPackageTracedLI(pkg, parseFlags, scanFlags);
       }
   }
   ```

4. **增量扫描**
   - 只扫描新增或修改的APK
   - 使用文件时间戳判断是否需要重新扫描
   - 优化启动速度

### Q12: 系统启动时PMS如何扫描应用？

**A:** 系统启动时PMS扫描流程：

1. **扫描系统应用**
   ```java
   // 扫描系统目录
   scanDirTracedLI(new File("/system/app"), ...);
   scanDirTracedLI(new File("/system/priv-app"), ...);
   scanDirTracedLI(new File("/vendor/app"), ...);
   ```

2. **扫描用户应用**
   ```java
   // 扫描用户安装目录
   scanDirTracedLI(new File("/data/app"), ...);
   ```

3. **并行扫描优化**
   - 使用多线程并行扫描不同目录
   - 提高扫描速度

4. **延迟扫描**
   - 非关键目录延迟扫描
   - 优先扫描系统应用
   - 用户应用可以延迟扫描

---

## 六、多用户管理

### Q13: PMS如何支持多用户？

**A:** PMS多用户支持：

1. **用户包状态管理**
   ```java
   // 每个用户有独立的包状态
   final SparseArray<PackageSetting> mSettingsByUser = new SparseArray<>();
   ```

2. **用户数据目录**
   - 主用户：`/data/data/<package_name>/`
   - 其他用户：`/data/user/<user_id>/<package_name>/`

3. **用户包安装**
   ```java
   // 为用户安装包
   installPackageAsUser(packageName, userId);
   ```

4. **用户包卸载**
   ```java
   // 删除用户包
   removePackageAsUser(packageName, userId);
   ```

5. **用户权限管理**
   - 每个用户有独立的权限授予状态
   - 权限存储在`/data/system/users/<user_id>/runtime-permissions.xml`

### Q14: 多用户下应用数据如何隔离？

**A:** 多用户数据隔离机制：

1. **数据目录隔离**
   ```java
   // 主用户（user_id = 0）
   /data/data/<package_name>/
   
   // 其他用户
   /data/user/<user_id>/<package_name>/
   ```

2. **包状态隔离**
   - 每个用户有独立的PackageSetting
   - 包启用/禁用状态独立管理

3. **权限隔离**
   - 每个用户有独立的权限授予状态
   - 权限授予不影响其他用户

4. **组件隔离**
   - Activity、Service等组件按用户隔离
   - 不同用户看到不同的应用列表

---

## 七、组件管理

### Q15: PMS如何管理Activity组件？

**A:** PMS管理Activity组件：

1. **组件注册**
   ```java
   // 解析AndroidManifest.xml时注册Activity
   extractActivities(package);
   ```

2. **组件查询**
   ```java
   // 查询Activity
   ResolveInfo resolveInfo = packageManager.resolveActivity(intent, flags);
   List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, flags);
   ```

3. **组件信息存储**
   - Activity信息存储在PackageParser.Package中
   - Intent Filter信息用于匹配Activity

4. **组件启用/禁用**
   ```java
   // 启用/禁用组件
   packageManager.setComponentEnabledSetting(componentName,
       PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
       PackageManager.DONT_KILL_APP);
   ```

### Q16: Intent匹配是如何工作的？

**A:** Intent匹配机制：

1. **Intent Filter解析**
   - PMS解析AndroidManifest.xml中的Intent Filter
   - 提取action、category、data等信息

2. **Intent匹配**
   ```java
   // Intent匹配
   List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent, flags);
   ```

3. **匹配规则**
   - Action匹配：Intent的action必须在Intent Filter中声明
   - Category匹配：Intent的所有category都必须在Intent Filter中
   - Data匹配：Intent的data必须匹配Intent Filter的data规则

4. **匹配优先级**
   - 精确匹配优先
   - 系统应用优先
   - 按优先级排序

---

## 八、PMS源码分析

### Q17: PMS的关键类有哪些？

**A:** PMS的关键类：

1. **PackageManagerService**
   - PMS的主类，系统服务的实现
   - 管理所有包的安装、卸载、更新

2. **PackageParser**
   - 解析APK文件
   - 提取包信息和组件信息

3. **PackageSettings**
   - 存储包的安装信息和设置
   - 管理包的启用/禁用状态

4. **Installer**
   - 执行实际的APK安装操作
   - 管理APK文件的复制和删除

5. **PackageInstaller**
   - 应用层使用的安装接口
   - 管理安装会话

### Q18: PMS的关键方法有哪些？

**A:** PMS的关键方法：

**安装相关：**
- `installPackageAsUser()`：安装应用
- `installPackageTracedLI()`：执行安装
- `scanPackageTracedLI()`：扫描包信息

**卸载相关：**
- `deletePackageAsUser()`：卸载应用
- `removePackage()`：移除包

**权限相关：**
- `grantRuntimePermission()`：授予权限
- `revokeRuntimePermission()`：撤销权限
- `checkPermission()`：检查权限

**查询相关：**
- `getPackageInfo()`：获取包信息
- `getApplicationInfo()`：获取应用信息
- `queryIntentActivities()`：查询Activity
- `resolveActivity()`：解析Activity

---

## 九、性能优化

### Q19: 如何优化PMS的启动速度？

**A:** PMS启动速度优化：

1. **延迟扫描**
   - 非关键目录延迟扫描
   - 优先扫描系统应用
   - 用户应用可以延迟扫描

2. **并行扫描**
   - 使用多线程并行扫描不同目录
   - 提高扫描速度

3. **增量扫描**
   - 只扫描新增或修改的APK
   - 使用文件时间戳判断

4. **缓存机制**
   - 缓存已解析的包信息
   - 减少重复解析

5. **优化解析**
   - 优化PackageParser解析速度
   - 减少不必要的解析操作

### Q20: 如何优化应用安装速度？

**A:** 应用安装速度优化：

1. **优化APK解析**
   - 只解析必要的信息
   - 延迟解析非关键信息

2. **优化文件操作**
   - 使用异步IO
   - 批量操作减少IO次数

3. **优化签名验证**
   - 缓存签名信息
   - 优化签名验证算法

4. **优化数据库操作**
   - 批量更新数据库
   - 使用事务减少数据库操作

---

## 十、问题排查

### Q21: 如何排查应用安装失败的问题？

**A:** 应用安装失败排查：

1. **查看日志**
   ```bash
   adb logcat | grep -i "package"
   adb logcat | grep -i "install"
   ```

2. **检查包信息**
   ```bash
   adb shell dumpsys package <package_name>
   ```

3. **检查安装会话**
   ```bash
   adb shell dumpsys package sessions
   ```

4. **常见原因**
   - 签名验证失败
   - 存储空间不足
   - 包名冲突
   - 版本冲突
   - 权限不足

### Q22: 如何排查权限问题？

**A:** 权限问题排查：

1. **查看权限状态**
   ```bash
   adb shell dumpsys package permissions
   ```

2. **查看应用权限**
   ```bash
   adb shell dumpsys package <package_name> | grep -i permission
   ```

3. **检查权限授予状态**
   ```java
   int result = packageManager.checkPermission(permission, packageName);
   ```

4. **常见问题**
   - 权限未声明
   - 权限未授予
   - 权限被撤销
   - 权限保护级别不匹配

---

## 十一、高级问题

### Q23: 静默安装是如何实现的？

**A:** 静默安装实现：

1. **系统权限要求**
   - 需要系统签名
   - 需要INSTALL_PACKAGES权限

2. **使用PackageInstaller**
   ```java
   PackageInstaller.Session session = packageInstaller.openSession(sessionId);
   session.write("app.apk", 0, -1, inputStream);
   session.commit(createIntentSender());
   ```

3. **直接调用PMS**
   ```java
   // 需要系统权限
   IPackageManager pm = ActivityManager.getService().getPackageManager();
   pm.installPackageAsUser(packageUri, observer, flags, installerPackageName, userId);
   ```

4. **注意事项**
   - 静默安装需要系统权限
   - 普通应用无法实现静默安装
   - 需要用户授权或系统签名

### Q24: 应用更新安装的流程？

**A:** 应用更新安装流程：

1. **版本检查**
   - 检查新版本号是否大于旧版本
   - 检查签名是否匹配

2. **停止旧应用**
   - 停止所有Activity
   - 停止所有Service
   - 取消注册BroadcastReceiver

3. **备份数据**
   - 备份应用数据
   - 备份SharedPreferences

4. **安装新版本**
   - 安装新APK
   - 保留应用数据

5. **恢复数据**
   - 恢复应用数据
   - 恢复SharedPreferences

6. **启动新版本**
   - 注册新组件
   - 发送更新广播

---

## 总结

PMS是Android系统的核心服务，负责管理应用的安装、卸载、权限管理等。

**关键知识点：**
1. PMS的职责和架构
2. 应用安装流程（APK解析、签名验证、安装执行）
3. 应用卸载流程（停止应用、删除文件、清理数据）
4. 权限管理机制（权限声明、授予、检查、撤销）
5. 包扫描机制（系统目录扫描、用户目录扫描）
6. 多用户支持（数据隔离、权限隔离）
7. 组件管理（Activity、Service等组件注册和查询）
8. PMS源码关键类和方法
9. 性能优化和问题排查

**面试重点：**
- 深入理解应用安装流程
- 掌握APK解析和签名验证机制
- 了解权限管理原理
- 能够分析安装失败问题
- 了解多用户支持机制
