18 KiB
PMS常见面试题
一、PMS基础概念
Q1: 什么是PMS?它的作用是什么?
A: PMS(PackageManagerService)是Android系统的核心服务之一,运行在system_server进程中。
主要作用:
- 应用安装管理:管理应用的安装、卸载、更新
- 权限管理:管理应用权限的授予、撤销和检查
- 组件管理:管理Activity、Service、BroadcastReceiver、ContentProvider等组件信息
- 包扫描:扫描系统和应用目录中的APK文件
- 签名验证:验证APK的签名信息,确保应用安全性
- 多用户管理:支持多用户环境下的应用隔离和管理
Q2: PMS在系统启动流程中的位置?
A: PMS在系统启动流程中的位置:
- Bootloader阶段:加载Linux内核
- Kernel启动:初始化硬件,启动init进程
- Init进程:解析init.rc,启动Zygote和ServiceManager
- Zygote进程:预加载类和资源,fork出SystemServer进程
- SystemServer进程:启动各类系统服务
- 启动PMS(PackageManagerService)
- 启动AMS(ActivityManagerService)
- 启动WMS(WindowManagerService)
- 启动其他系统服务
- PMS扫描应用:系统启动时,PMS扫描系统目录和应用目录中的APK文件
Q3: PMS与其他系统服务的关系?
A: PMS与其他系统服务的关系:
- PMS与AMS:AMS需要PMS提供包信息来启动Activity
- PMS与Installer:PMS通过Installer执行实际的APK安装操作
- PMS与UserManagerService:PMS需要UserManagerService管理多用户
- PMS与StorageManagerService:PMS需要StorageManagerService管理存储空间
二、应用安装流程
Q4: 请详细描述应用的安装流程?
A: 应用安装流程:
客户端进程:
PackageInstaller.install():用户点击安装或调用安装APIPackageInstaller.Session.commit():提交安装会话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
- 提取四大组件信息
- 提取权限信息
- 验证签名
PackageManagerService.scanPackageTracedLI():扫描包信息PackageManagerService.updateSettingsLI():更新包设置PackageManagerService.sendPackageBroadcast():发送安装完成广播
关键步骤:
- 权限检查:检查安装权限
- APK解析:解析APK的AndroidManifest.xml
- 签名验证:验证APK签名
- 冲突检查:检查包名冲突、版本冲突
- 存储检查:检查存储空间是否足够
- 安装执行:复制APK文件、创建数据目录
- 组件注册:注册Activity、Service等组件
- 权限授予:授予声明的权限
Q5: APK解析过程是怎样的?
A: APK解析过程:
-
创建PackageParser
PackageParser parser = new PackageParser(); -
解析APK文件
PackageParser.Package pkg = parser.parsePackage(apkFile, flags); -
解析AndroidManifest.xml
- 解析包名、版本号等基本信息
- 解析四大组件(Activity、Service、BroadcastReceiver、ContentProvider)
- 解析权限声明
- 解析Intent Filter
- 解析资源信息
-
收集证书信息
collectCertificates(pkg); collectManifestDigest(pkg); -
提取组件信息
extractActivities(pkg); extractServices(pkg); extractReceivers(pkg); extractProviders(pkg); extractPermissions(pkg); -
验证签名
- 验证APK签名是否有效
- 检查签名是否匹配
- 验证签名证书链
Q6: 签名验证是如何进行的?
A: 签名验证过程:
-
提取签名信息
// 从APK中提取签名 Signature[] signatures = packageInfo.signatures; -
验证签名格式
- 检查签名文件是否存在(META-INF/)
- 验证签名文件格式是否正确
-
验证签名证书
- 验证证书是否有效
- 验证证书是否过期
- 验证证书链是否完整
-
验证签名匹配
- 如果是更新安装,验证新签名是否与旧签名匹配
- 如果是共享UID应用,验证签名是否一致
-
关键代码位置
PackageManagerService.verifySignatures()PackageParser.collectCertificates()PackageManagerService.checkUpgradeKeySetLocked()
三、应用卸载流程
Q7: 应用卸载流程是怎样的?
A: 应用卸载流程:
-
卸载请求
packageManager.deletePackage(packageName, observer, flags); -
PMS处理卸载
PackageManagerService.deletePackageAsUser(packageName, userId, flags); -
检查卸载条件
- 检查应用是否正在运行
- 检查是否有其他应用依赖
- 检查卸载权限
-
停止应用
- 停止应用的所有Activity
- 停止应用的所有Service
- 取消注册BroadcastReceiver
-
删除文件
- 删除APK文件
- 删除应用数据目录
- 删除应用缓存
-
更新包信息
- 从包列表中移除
- 清理组件注册信息
- 清理权限信息
-
发送卸载广播
sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, packageName);
Q8: 卸载时如何清理应用数据?
A: 卸载时清理应用数据:
-
删除应用目录
// 删除应用数据目录 /data/data/<package_name>/ /data/user/<user_id>/<package_name>/ -
删除APK文件
// 删除APK文件 /data/app/<package_name>-<random>/ -
删除外部存储数据
// 删除外部存储中的应用数据 /sdcard/Android/data/<package_name>/ -
清理数据库
- 清理包信息数据库
- 清理权限数据库
- 清理组件注册信息
-
清理缓存
- 清理系统缓存中的应用信息
- 清理其他服务中的应用引用
四、权限管理
Q9: PMS如何管理应用权限?
A: PMS权限管理机制:
-
权限声明
- 应用在AndroidManifest.xml中声明权限
- PMS解析时提取权限信息
-
权限授予
// 授予权限 packageManager.grantRuntimePermission(packageName, permission, userHandle); -
权限检查
// 检查权限 int result = packageManager.checkPermission(permission, packageName); if (result == PackageManager.PERMISSION_GRANTED) { // 权限已授予 } -
权限撤销
// 撤销权限 packageManager.revokeRuntimePermission(packageName, permission, userHandle); -
权限存储
- 权限授予状态存储在
/data/system/users/<user_id>/runtime-permissions.xml - 系统启动时加载权限状态
- 权限授予状态存储在
Q10: 运行时权限和安装时权限的区别?
A: 运行时权限和安装时权限的区别:
安装时权限(Normal Permissions):
- 在应用安装时自动授予
- 不需要用户确认
- 通常是低风险权限
- 例如:网络访问、振动等
运行时权限(Dangerous Permissions):
- 需要运行时动态申请
- 需要用户确认
- 通常是高风险权限
- 例如:相机、位置、存储等
权限分类:
// 权限保护级别
PROTECTION_NORMAL // 普通权限,安装时授予
PROTECTION_DANGEROUS // 危险权限,运行时申请
PROTECTION_SIGNATURE // 签名权限,同签名应用自动授予
PROTECTION_SIGNATURE_OR_SYSTEM // 签名或系统权限
五、包扫描机制
Q11: PMS如何扫描应用?
A: PMS包扫描机制:
-
系统目录扫描
/system/app/:系统应用目录/system/priv-app/:系统特权应用目录/vendor/app/:厂商应用目录/oem/app/:OEM应用目录
-
用户目录扫描
/data/app/:用户安装的应用目录/data/app-private/:私有应用目录
-
扫描流程
// 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); } } -
增量扫描
- 只扫描新增或修改的APK
- 使用文件时间戳判断是否需要重新扫描
- 优化启动速度
Q12: 系统启动时PMS如何扫描应用?
A: 系统启动时PMS扫描流程:
-
扫描系统应用
// 扫描系统目录 scanDirTracedLI(new File("/system/app"), ...); scanDirTracedLI(new File("/system/priv-app"), ...); scanDirTracedLI(new File("/vendor/app"), ...); -
扫描用户应用
// 扫描用户安装目录 scanDirTracedLI(new File("/data/app"), ...); -
并行扫描优化
- 使用多线程并行扫描不同目录
- 提高扫描速度
-
延迟扫描
- 非关键目录延迟扫描
- 优先扫描系统应用
- 用户应用可以延迟扫描
六、多用户管理
Q13: PMS如何支持多用户?
A: PMS多用户支持:
-
用户包状态管理
// 每个用户有独立的包状态 final SparseArray<PackageSetting> mSettingsByUser = new SparseArray<>(); -
用户数据目录
- 主用户:
/data/data/<package_name>/ - 其他用户:
/data/user/<user_id>/<package_name>/
- 主用户:
-
用户包安装
// 为用户安装包 installPackageAsUser(packageName, userId); -
用户包卸载
// 删除用户包 removePackageAsUser(packageName, userId); -
用户权限管理
- 每个用户有独立的权限授予状态
- 权限存储在
/data/system/users/<user_id>/runtime-permissions.xml
Q14: 多用户下应用数据如何隔离?
A: 多用户数据隔离机制:
-
数据目录隔离
// 主用户(user_id = 0) /data/data/<package_name>/ // 其他用户 /data/user/<user_id>/<package_name>/ -
包状态隔离
- 每个用户有独立的PackageSetting
- 包启用/禁用状态独立管理
-
权限隔离
- 每个用户有独立的权限授予状态
- 权限授予不影响其他用户
-
组件隔离
- Activity、Service等组件按用户隔离
- 不同用户看到不同的应用列表
七、组件管理
Q15: PMS如何管理Activity组件?
A: PMS管理Activity组件:
-
组件注册
// 解析AndroidManifest.xml时注册Activity extractActivities(package); -
组件查询
// 查询Activity ResolveInfo resolveInfo = packageManager.resolveActivity(intent, flags); List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, flags); -
组件信息存储
- Activity信息存储在PackageParser.Package中
- Intent Filter信息用于匹配Activity
-
组件启用/禁用
// 启用/禁用组件 packageManager.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
Q16: Intent匹配是如何工作的?
A: Intent匹配机制:
-
Intent Filter解析
- PMS解析AndroidManifest.xml中的Intent Filter
- 提取action、category、data等信息
-
Intent匹配
// Intent匹配 List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent, flags); -
匹配规则
- Action匹配:Intent的action必须在Intent Filter中声明
- Category匹配:Intent的所有category都必须在Intent Filter中
- Data匹配:Intent的data必须匹配Intent Filter的data规则
-
匹配优先级
- 精确匹配优先
- 系统应用优先
- 按优先级排序
八、PMS源码分析
Q17: PMS的关键类有哪些?
A: PMS的关键类:
-
PackageManagerService
- PMS的主类,系统服务的实现
- 管理所有包的安装、卸载、更新
-
PackageParser
- 解析APK文件
- 提取包信息和组件信息
-
PackageSettings
- 存储包的安装信息和设置
- 管理包的启用/禁用状态
-
Installer
- 执行实际的APK安装操作
- 管理APK文件的复制和删除
-
PackageInstaller
- 应用层使用的安装接口
- 管理安装会话
Q18: PMS的关键方法有哪些?
A: PMS的关键方法:
安装相关:
installPackageAsUser():安装应用installPackageTracedLI():执行安装scanPackageTracedLI():扫描包信息
卸载相关:
deletePackageAsUser():卸载应用removePackage():移除包
权限相关:
grantRuntimePermission():授予权限revokeRuntimePermission():撤销权限checkPermission():检查权限
查询相关:
getPackageInfo():获取包信息getApplicationInfo():获取应用信息queryIntentActivities():查询ActivityresolveActivity():解析Activity
九、性能优化
Q19: 如何优化PMS的启动速度?
A: PMS启动速度优化:
-
延迟扫描
- 非关键目录延迟扫描
- 优先扫描系统应用
- 用户应用可以延迟扫描
-
并行扫描
- 使用多线程并行扫描不同目录
- 提高扫描速度
-
增量扫描
- 只扫描新增或修改的APK
- 使用文件时间戳判断
-
缓存机制
- 缓存已解析的包信息
- 减少重复解析
-
优化解析
- 优化PackageParser解析速度
- 减少不必要的解析操作
Q20: 如何优化应用安装速度?
A: 应用安装速度优化:
-
优化APK解析
- 只解析必要的信息
- 延迟解析非关键信息
-
优化文件操作
- 使用异步IO
- 批量操作减少IO次数
-
优化签名验证
- 缓存签名信息
- 优化签名验证算法
-
优化数据库操作
- 批量更新数据库
- 使用事务减少数据库操作
十、问题排查
Q21: 如何排查应用安装失败的问题?
A: 应用安装失败排查:
-
查看日志
adb logcat | grep -i "package" adb logcat | grep -i "install" -
检查包信息
adb shell dumpsys package <package_name> -
检查安装会话
adb shell dumpsys package sessions -
常见原因
- 签名验证失败
- 存储空间不足
- 包名冲突
- 版本冲突
- 权限不足
Q22: 如何排查权限问题?
A: 权限问题排查:
-
查看权限状态
adb shell dumpsys package permissions -
查看应用权限
adb shell dumpsys package <package_name> | grep -i permission -
检查权限授予状态
int result = packageManager.checkPermission(permission, packageName); -
常见问题
- 权限未声明
- 权限未授予
- 权限被撤销
- 权限保护级别不匹配
十一、高级问题
Q23: 静默安装是如何实现的?
A: 静默安装实现:
-
系统权限要求
- 需要系统签名
- 需要INSTALL_PACKAGES权限
-
使用PackageInstaller
PackageInstaller.Session session = packageInstaller.openSession(sessionId); session.write("app.apk", 0, -1, inputStream); session.commit(createIntentSender()); -
直接调用PMS
// 需要系统权限 IPackageManager pm = ActivityManager.getService().getPackageManager(); pm.installPackageAsUser(packageUri, observer, flags, installerPackageName, userId); -
注意事项
- 静默安装需要系统权限
- 普通应用无法实现静默安装
- 需要用户授权或系统签名
Q24: 应用更新安装的流程?
A: 应用更新安装流程:
-
版本检查
- 检查新版本号是否大于旧版本
- 检查签名是否匹配
-
停止旧应用
- 停止所有Activity
- 停止所有Service
- 取消注册BroadcastReceiver
-
备份数据
- 备份应用数据
- 备份SharedPreferences
-
安装新版本
- 安装新APK
- 保留应用数据
-
恢复数据
- 恢复应用数据
- 恢复SharedPreferences
-
启动新版本
- 注册新组件
- 发送更新广播
总结
PMS是Android系统的核心服务,负责管理应用的安装、卸载、权限管理等。
关键知识点:
- PMS的职责和架构
- 应用安装流程(APK解析、签名验证、安装执行)
- 应用卸载流程(停止应用、删除文件、清理数据)
- 权限管理机制(权限声明、授予、检查、撤销)
- 包扫描机制(系统目录扫描、用户目录扫描)
- 多用户支持(数据隔离、权限隔离)
- 组件管理(Activity、Service等组件注册和查询)
- PMS源码关键类和方法
- 性能优化和问题排查
面试重点:
- 深入理解应用安装流程
- 掌握APK解析和签名验证机制
- 了解权限管理原理
- 能够分析安装失败问题
- 了解多用户支持机制