鏇存柊鏂囨。

This commit is contained in:
renjianbo
2026-01-16 17:23:12 +08:00
parent 2a5df47056
commit 2c5542037b
3 changed files with 713 additions and 2 deletions

View File

@@ -0,0 +1,710 @@
# PMS常见面试题
---
## 一、PMS基础概念
### Q1: 什么是PMS它的作用是什么
**A:** PMSPackageManagerService是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进程**:启动各类系统服务
- 启动PMSPackageManagerService
- 启动AMSActivityManagerService
- 启动WMSWindowManagerService
- 启动其他系统服务
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解析和签名验证机制
- 了解权限管理原理
- 能够分析安装失败问题
- 了解多用户支持机制