核心服务二:PackageManagerService

397 阅读9分钟

Android PMS(Package Manager Service)详细梳理

一、PMS概述

Android PMS,即Package Manager Service,管理和维护安装在设备上的应用程序包(APK文件)。 它不仅确保应用程序的安全性和稳定性,还提供了对应用程序包信息的全面访问和管理功能,是连接用户与应用程序的桥梁。

二、PMS的主要功能

  1. 应用程序的安装、卸载和更新

    • 安装:处理用户发起的安装请求,验证APK文件的签名和完整性,提取并存储元数据信息,最后将应用程序文件放置在系统指定位置(如/data/app/)。
    • 卸载:响应用户的卸载请求,删除应用程序的文件、数据以及相关的元数据信息,并通知其他系统组件进行清理。
    • 更新:执行应用程序的更新流程,包括卸载旧版本、安装新版本,并处理更新过程中的数据迁移等问题。
  2. 应用程序的权限管理

    • 在应用程序安装时,PMS会审核其申请的权限列表,并根据系统的安全策略决定是否授予这些权限。
    • 在应用程序运行时,PMS负责权限的动态检查,确保应用程序只能访问其被授权的资源和功能。
  3. 维护应用程序包清单信息

    • PMS维护一个包含所有已安装应用程序元数据的数据库和XML文件(如AndroidManifest.xml),这些信息对于系统管理和用户交互至关重要。

三、PMS的工作流程

  1. 应用程序的安装流程

    • 用户发起安装请求。
    • PackageInstaller将APK文件发送给PMS。
    • PMS利用PackageParser解析APK文件,提取元数据信息并进行签名验证。
    • 验证通过后,PMS将应用程序文件复制至系统指定目录,并分配UID。
    • 更新内部数据库和XML文件,记录应用程序的元数据信息。
    • 发送安装成功广播,通知系统其他组件。
  2. 应用程序的卸载流程

    • 用户发起卸载请求。
    • PMS删除应用程序文件及相关数据。
    • 从内部数据库和XML文件中移除应用程序的元数据信息。
    • 发送卸载成功广播,通知其他系统组件进行清理。
  3. 权限管理流程

    • 在安装时,PMS根据应用程序的AndroidManifest.xml文件及系统安全策略,授予或拒绝权限请求。
    • 运行时,PMS根据权限等级和应用状态动态管理权限访问。

四、PMS的核心类和模块

  • PackageManagerService(PMS的实现类):提供应用程序包管理的核心逻辑,如安装、卸载、更新和权限管理等。
  • PackageInstaller:负责处理APK文件的安装请求,与PMS协同工作完成安装流程。
  • PackageParser:专门用于解析APK文件,提取其中的元数据信息(如包名、版本号、权限等)。
  • PackageManager:作为对外接口,为其他系统组件和应用程序提供查询和管理应用程序包信息的服务。

五、权限检查异常

PMS(PackageManager Service)在检查APK(Android应用程序包)权限时,可能会抛出多种错误异常,这些异常通常与APK文件的格式、权限声明、签名验证等方面的问题相关。以下是一些常见的错误异常类型:

  1. ParseError(解析错误):

    • 当PMS尝试解析APK文件时,如果APK文件的格式不正确、损坏或缺失必要的部分(如AndroidManifest.xml文件),PMS可能会抛出解析错误。这通常是由于APK文件在传输或存储过程中损坏,或者APK文件本身就不符合Android的规范。
  2. SecurityException(安全异常):

    • 如果APK文件尝试声明或使用它不应该有的权限,或者APK的签名不符合预期(例如,尝试安装一个被篡改的应用),PMS可能会抛出安全异常。这是Android安全机制的一部分,用于防止恶意软件安装到设备上。
  3. PackageManager.NameNotFoundException(包名未找到异常):

    • 当PMS在尝试查询或操作一个不存在的包时,会抛出此异常。例如,如果APK文件尝试通过Intent启动一个不存在的Activity或服务,或者尝试访问一个不存在的包的数据,就可能触发此异常。
  4. BadPackageException(不良包异常):

    • 当APK文件存在某些严重问题,如应用程序ID(application ID)冲突、权限冲突或签名不一致等,PMS可能会抛出此异常。这通常表示APK文件在构建或发布过程中存在问题。
  5. InstallationException(安装异常):

    • 虽然这不是一个直接由PMS抛出的异常,但在APK安装过程中,如果PMS检测到任何问题(如存储空间不足、APK文件损坏、权限问题等),都可能导致安装失败,并可能通过安装器(如PackageInstaller)返回安装异常。

需要注意的是,具体的异常类型和错误信息可能会因Android版本的不同而有所差异。此外,由于Android系统的更新和变化,新的异常类型或错误代码可能会被引入,而旧的则可能不再使用。

六、伪代码示例

由于直接提供Android系统内部(如PackageManagerService, PMS)的完整源码示例可能涉及复杂的系统架构和大量代码,这里我将以一个简化的伪代码或概念性描述来概述PMS的工作流程,特别是应用程序的安装流程。请注意,这并非实际的Android源代码,而是对流程的逻辑抽象。

1、应用程序的安装流程伪代码

// 假设这是PMS的一个简化版本
class PackageManagerService {

    // 安装应用程序
    void installApp(File apkFile) {
        // 1. 用户发起安装请求,这里简化为直接调用此方法

        // 2. PackageInstaller将APK文件发送给PMS(这里简化为直接传递)

        // 3. PMS利用PackageParser解析APK文件
        PackageParser parser = new PackageParser();
        PackageInfo packageInfo = parser.parsePackage(apkFile);

        // 4. 提取元数据信息并进行签名验证
        if (!verifySignature(packageInfo)) {
            // 签名验证失败,处理错误
            return;
        }

        // 5. 将应用程序文件复制至系统指定目录,并分配UID
        File destDir = new File("/data/app/");
        File appFile = new File(destDir, packageInfo.packageName + ".apk");
        copyFile(apkFile, appFile);
        int uid = allocateUid();

        // 6. 更新内部数据库和XML文件
        updateDatabase(packageInfo, uid);
        updateXml(packageInfo);

        // 7. 发送安装成功广播
        sendBroadcast(new Intent(Intent.ACTION_PACKAGE_ADDED).putExtra("packageName", packageInfo.packageName));
    }

    // 签名验证方法(伪实现)
    private boolean verifySignature(PackageInfo packageInfo) {
        // 实际实现会复杂得多,包括读取APK的签名信息等
        return true; // 假设总是验证成功
    }

    // 分配UID的伪实现
    private int allocateUid() {
        // 真实环境中,这将是一个更复杂的逻辑,确保UID的唯一性
        return 12345; // 假设分配的UID
    }

    // 复制文件的伪实现
    private void copyFile(File src, File dest) {
        // 真实环境中,这里会使用文件IO操作
    }

    // 更新数据库的伪实现
    private void updateDatabase(PackageInfo packageInfo, int uid) {
        // 这里会更新PMS维护的数据库
    }

    // 更新XML文件的伪实现
    private void updateXml(PackageInfo packageInfo) {
        // 这里会更新PMS维护的XML文件(如AndroidManifest.xml的汇总)
    }

    // 发送广播的伪实现
    private void sendBroadcast(Intent intent) {
        // 真实环境中,这将调用Context的sendBroadcast方法
    }
}

2、应用程序的卸载流程伪代码

// 假设这是PMS中的一个方法
public void uninstallApplication(String packageName) {
    // 用户发起卸载请求,这里直接模拟请求处理
    // 1. 删除应用程序文件及相关数据
    deleteApplicationFiles(packageName);
    
    // 2. 从内部数据库和XML文件中移除应用程序的元数据信息
    removeFromDatabaseAndXml(packageName);
    
    // 3. 发送卸载成功广播,通知其他系统组件进行清理
    sendBroadcast(new Intent(Intent.ACTION_PACKAGE_REMOVED, Uri.parse("package:" + packageName)));
}

// 模拟删除应用程序文件及相关数据的方法
private void deleteApplicationFiles(String packageName) {
    // 实现细节:删除文件、数据库记录等
    System.out.println("Deleting files and data for package: " + packageName);
}

// 模拟从数据库和XML文件中移除应用程序元数据的方法
private void removeFromDatabaseAndXml(String packageName) {
    // 实现细节:更新数据库和XML文件
    System.out.println("Removing metadata from database and XML for package: " + packageName);
}

// 模拟发送广播的方法
private void sendBroadcast(Intent intent) {
    // 在Android中,实际会调用Context的sendBroadcast方法
    System.out.println("Sending broadcast: " + intent.getAction());
}

3、权限管理流程伪代码

权限管理流程涉及安装时和运行时两个阶段,这里分别给出伪代码示例。

安装时权限授予/拒绝伪代码

// 假设这是PMS中处理安装请求时的方法
public void handleInstall(PackageInfo packageInfo) {
    // ... 其他安装流程 ...
    
    // 权限处理
    List<String> requestedPermissions = packageInfo.requestedPermissions;
    List<String> grantedPermissions = new ArrayList<>();
    
    for (String permission : requestedPermissions) {
        if (isPermissionGranted(permission, packageInfo)) {
            grantedPermissions.add(permission);
        }
    }
    
    // 假设这里有一个方法来更新包信息中的权限列表
    updatePackagePermissions(packageInfo, grantedPermissions);
    
    // ... 其他安装流程 ...
}

// 假设这是检查权限是否应该被授予的方法
private boolean isPermissionGranted(String permission, PackageInfo packageInfo) {
    // 实现细节:根据系统安全策略判断
    // 这里简单模拟总是授予权限
    return true; // 或者基于某些逻辑返回true或false
}

// 假设这是更新包信息中权限列表的方法
private void updatePackagePermissions(PackageInfo packageInfo, List<String> grantedPermissions) {
    // 实现细节:更新packageInfo中的权限列表
    // 这里只是模拟
    System.out.println("Granted permissions for package: " + packageInfo.packageName + " = " + grantedPermissions);
}

运行时权限管理伪代码

运行时权限管理通常涉及到应用程序的Context或Activity等组件与系统的交互,但在这里我们主要关注PMS的逻辑。

// 假设PMS中有一个方法来检查运行时权限
public boolean checkRuntimePermission(String packageName, String permission) {
    // 实现细节:检查当前应用的状态和权限等级
    // 这里简单模拟总是允许
    return true; // 或者基于某些逻辑返回true或false
}

// 注意:在实际Android系统中,运行时权限检查通常不是由PMS直接完成的,
// 而是由应用程序通过Context的checkSelfPermission等方法进行。
// 这里只是为了展示PMS在权限管理流程中的角色而提供的伪代码。

请注意,这些伪代码只是为了说明PMS在卸载和权限管理流程中的大致逻辑,并不是Android系统内部实际的代码实现。在真实的Android系统中,这些功能由复杂的系统服务和框架代码支持。