Files
mkdocs/docs/android面试/系统原理/PMS常见面试题.md
2026-01-16 17:23:12 +08:00

18 KiB
Raw Blame History

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与AMSAMS需要PMS提供包信息来启动Activity
  2. PMS与InstallerPMS通过Installer执行实际的APK安装操作
  3. PMS与UserManagerServicePMS需要UserManagerService管理多用户
  4. PMS与StorageManagerServicePMS需要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
  • 提取四大组件信息
  • 提取权限信息
  • 验证签名
  1. PackageManagerService.scanPackageTracedLI():扫描包信息
  2. PackageManagerService.updateSettingsLI():更新包设置
  3. PackageManagerService.sendPackageBroadcast():发送安装完成广播

关键步骤:

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

Q5: APK解析过程是怎样的

A: APK解析过程

  1. 创建PackageParser

    PackageParser parser = new PackageParser();
    
  2. 解析APK文件

    PackageParser.Package pkg = parser.parsePackage(apkFile, flags);
    
  3. 解析AndroidManifest.xml

    • 解析包名、版本号等基本信息
    • 解析四大组件Activity、Service、BroadcastReceiver、ContentProvider
    • 解析权限声明
    • 解析Intent Filter
    • 解析资源信息
  4. 收集证书信息

    collectCertificates(pkg);
    collectManifestDigest(pkg);
    
  5. 提取组件信息

    extractActivities(pkg);
    extractServices(pkg);
    extractReceivers(pkg);
    extractProviders(pkg);
    extractPermissions(pkg);
    
  6. 验证签名

    • 验证APK签名是否有效
    • 检查签名是否匹配
    • 验证签名证书链

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

A: 签名验证过程:

  1. 提取签名信息

    // 从APK中提取签名
    Signature[] signatures = packageInfo.signatures;
    
  2. 验证签名格式

    • 检查签名文件是否存在META-INF/
    • 验证签名文件格式是否正确
  3. 验证签名证书

    • 验证证书是否有效
    • 验证证书是否过期
    • 验证证书链是否完整
  4. 验证签名匹配

    • 如果是更新安装,验证新签名是否与旧签名匹配
    • 如果是共享UID应用验证签名是否一致
  5. 关键代码位置

    • PackageManagerService.verifySignatures()
    • PackageParser.collectCertificates()
    • PackageManagerService.checkUpgradeKeySetLocked()

三、应用卸载流程

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

A: 应用卸载流程:

  1. 卸载请求

    packageManager.deletePackage(packageName, observer, flags);
    
  2. PMS处理卸载

    PackageManagerService.deletePackageAsUser(packageName, userId, flags);
    
  3. 检查卸载条件

    • 检查应用是否正在运行
    • 检查是否有其他应用依赖
    • 检查卸载权限
  4. 停止应用

    • 停止应用的所有Activity
    • 停止应用的所有Service
    • 取消注册BroadcastReceiver
  5. 删除文件

    • 删除APK文件
    • 删除应用数据目录
    • 删除应用缓存
  6. 更新包信息

    • 从包列表中移除
    • 清理组件注册信息
    • 清理权限信息
  7. 发送卸载广播

    sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, packageName);
    

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

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

  1. 删除应用目录

    // 删除应用数据目录
    /data/data/<package_name>/
    /data/user/<user_id>/<package_name>/
    
  2. 删除APK文件

    // 删除APK文件
    /data/app/<package_name>-<random>/
    
  3. 删除外部存储数据

    // 删除外部存储中的应用数据
    /sdcard/Android/data/<package_name>/
    
  4. 清理数据库

    • 清理包信息数据库
    • 清理权限数据库
    • 清理组件注册信息
  5. 清理缓存

    • 清理系统缓存中的应用信息
    • 清理其他服务中的应用引用

四、权限管理

Q9: PMS如何管理应用权限

A: PMS权限管理机制

  1. 权限声明

    • 应用在AndroidManifest.xml中声明权限
    • PMS解析时提取权限信息
  2. 权限授予

    // 授予权限
    packageManager.grantRuntimePermission(packageName, permission, userHandle);
    
  3. 权限检查

    // 检查权限
    int result = packageManager.checkPermission(permission, packageName);
    if (result == PackageManager.PERMISSION_GRANTED) {
        // 权限已授予
    }
    
  4. 权限撤销

    // 撤销权限
    packageManager.revokeRuntimePermission(packageName, permission, userHandle);
    
  5. 权限存储

    • 权限授予状态存储在/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包扫描机制

  1. 系统目录扫描

    • /system/app/:系统应用目录
    • /system/priv-app/:系统特权应用目录
    • /vendor/app/:厂商应用目录
    • /oem/app/OEM应用目录
  2. 用户目录扫描

    • /data/app/:用户安装的应用目录
    • /data/app-private/:私有应用目录
  3. 扫描流程

    // 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. 扫描系统应用

    // 扫描系统目录
    scanDirTracedLI(new File("/system/app"), ...);
    scanDirTracedLI(new File("/system/priv-app"), ...);
    scanDirTracedLI(new File("/vendor/app"), ...);
    
  2. 扫描用户应用

    // 扫描用户安装目录
    scanDirTracedLI(new File("/data/app"), ...);
    
  3. 并行扫描优化

    • 使用多线程并行扫描不同目录
    • 提高扫描速度
  4. 延迟扫描

    • 非关键目录延迟扫描
    • 优先扫描系统应用
    • 用户应用可以延迟扫描

六、多用户管理

Q13: PMS如何支持多用户

A: PMS多用户支持

  1. 用户包状态管理

    // 每个用户有独立的包状态
    final SparseArray<PackageSetting> mSettingsByUser = new SparseArray<>();
    
  2. 用户数据目录

    • 主用户:/data/data/<package_name>/
    • 其他用户:/data/user/<user_id>/<package_name>/
  3. 用户包安装

    // 为用户安装包
    installPackageAsUser(packageName, userId);
    
  4. 用户包卸载

    // 删除用户包
    removePackageAsUser(packageName, userId);
    
  5. 用户权限管理

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

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

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

  1. 数据目录隔离

    // 主用户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. 组件注册

    // 解析AndroidManifest.xml时注册Activity
    extractActivities(package);
    
  2. 组件查询

    // 查询Activity
    ResolveInfo resolveInfo = packageManager.resolveActivity(intent, flags);
    List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, flags);
    
  3. 组件信息存储

    • Activity信息存储在PackageParser.Package中
    • Intent Filter信息用于匹配Activity
  4. 组件启用/禁用

    // 启用/禁用组件
    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匹配

    // 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. 查看日志

    adb logcat | grep -i "package"
    adb logcat | grep -i "install"
    
  2. 检查包信息

    adb shell dumpsys package <package_name>
    
  3. 检查安装会话

    adb shell dumpsys package sessions
    
  4. 常见原因

    • 签名验证失败
    • 存储空间不足
    • 包名冲突
    • 版本冲突
    • 权限不足

Q22: 如何排查权限问题?

A: 权限问题排查:

  1. 查看权限状态

    adb shell dumpsys package permissions
    
  2. 查看应用权限

    adb shell dumpsys package <package_name> | grep -i permission
    
  3. 检查权限授予状态

    int result = packageManager.checkPermission(permission, packageName);
    
  4. 常见问题

    • 权限未声明
    • 权限未授予
    • 权限被撤销
    • 权限保护级别不匹配

十一、高级问题

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

A: 静默安装实现:

  1. 系统权限要求

    • 需要系统签名
    • 需要INSTALL_PACKAGES权限
  2. 使用PackageInstaller

    PackageInstaller.Session session = packageInstaller.openSession(sessionId);
    session.write("app.apk", 0, -1, inputStream);
    session.commit(createIntentSender());
    
  3. 直接调用PMS

    // 需要系统权限
    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解析和签名验证机制
  • 了解权限管理原理
  • 能够分析安装失败问题
  • 了解多用户支持机制