【Android FrameWork】第四十二天:PMS main函数

Android PMS main函数

在前文对PMS main函数整体逻辑讲解的基础上,本节结合Android 11(API 30) 完整源码(关键片段),逐行拆解main函数及关联核心逻辑,明确每一行代码的作用、依赖关系和设计意图。

PMS main函数完整源码(Android 11)

先贴出main函数的完整源码(含注释),再逐步解析:

java 复制代码
/**
 * PackageManagerService的启动入口,由SystemServer调用
 * @param context SystemServer的SystemContext,系统级上下文
 * @param installer 与installd守护进程通信的代理对象
 * @param factoryTest 是否为工厂测试模式(0=非工厂模式,1=工厂测试,2=工厂测试且无加密)
 * @param onlyCore 是否仅加载核心系统包(用于系统启动早期极简模式)
 * @return 初始化完成的PMS实例
 */
public static PackageManagerService main(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {
    // 1. 确保运行在SystemServer进程(安全校验)
    PackageManagerServiceCompilerMapping.recordServiceStart();
    
    // 2. 创建PMS实例(核心逻辑,构造函数是重点)
    PackageManagerService m = new PackageManagerService(context, installer,
            factoryTest ? FactoryTest.FACTORY_TEST_ON : FactoryTest.FACTORY_TEST_OFF,
            onlyCore);
    
    // 3. 将PMS注册到ServiceManager,对外暴露Binder服务
    ServiceManager.addService(Context.PACKAGE_SERVICE, m);
    
    // 4. 启用系统用户(User 0)的应用包访问权限
    m.enableSystemUserPackages();
    
    // 5. 初始化包验证相关的系统特性(Android 11新增)
    m.getPackageVerificationManager().initialize();
    
    return m;
}

main函数逐行源码解析

1. 进程安全校验:PackageManagerServiceCompilerMapping.recordServiceStart()

java 复制代码
PackageManagerServiceCompilerMapping.recordServiceStart();

作用

  • 这是Android系统的"编译映射"埋点,用于跟踪PMS服务启动的编译/执行状态,属于系统性能监控和调试辅助逻辑;
  • 底层通过CompilerMapping记录服务启动的时间戳、进程信息,便于排查启动耗时、编译优化相关问题;
  • 无业务逻辑影响,仅为系统级监控设计。

2. PMS实例化:核心构造函数调用

java 复制代码
PackageManagerService m = new PackageManagerService(context, installer,
        factoryTest ? FactoryTest.FACTORY_TEST_ON : FactoryTest.FACTORY_TEST_OFF,
        onlyCore);

这是main函数的核心,构造函数是PMS初始化的"主战场"。以下是构造函数的关键源码片段(简化后)及解析:

java 复制代码
/**
 * PMS构造函数,完成核心初始化
 */
public PackageManagerService(Context context, Installer installer, int factoryTest, boolean onlyCore) {
    // ===== 步骤1:基础环境初始化 =====
    mContext = context;
    mFactoryTest = factoryTest;
    mOnlyCore = onlyCore;
    mInstaller = installer; // 注入installd代理,后续apk安装/解压依赖此对象
    
    // 初始化系统目录(核心路径,PMS扫描apk的基础)
    mSystemDir = new File(Environment.getRootDirectory(), "app");
    mVendorDir = new File("/vendor/app");
    mOemDir = new File("/oem/app");
    mDataDir = Environment.getDataDirectory();
    mAppDataDir = new File(mDataDir, "app");
    // 校验目录权限,确保PMS可读写(无权限则抛出异常,SystemServer启动失败)
    enforceDirectoryPermissions();

    // ===== 步骤2:核心模块初始化 =====
    // 权限管理模块(处理应用权限声明、授予、校验)
    mPermissionManager = new PermissionManager(this, mContext);
    // 包安装器(处理apk安装/卸载流程)
    mPackageInstaller = new PackageInstallerService(this);
    // dex优化模块(提升应用启动速度,处理dex2oat)
    mDexManager = new PackageDexOptimizer(this, mInstaller);
    // 内存数据库初始化(存储包信息、组件信息,核心数据结构)
    mPackages = new ArrayMap<String, PackageParser.Package>(); // 包名->Package对象
    mActivities = new ArrayMap<String, ArrayMap<ComponentName, ActivityInfo>>(); // 组件->Activity信息
    mServices = new ArrayMap<String, ArrayMap<ComponentName, ServiceInfo>>(); // 组件->Service信息

    // ===== 步骤3:包扫描(PMS最核心的逻辑) =====
    // 分阶段扫描:先扫描核心系统包,再扫描普通包
    long startTime = SystemClock.uptimeMillis();
    // 扫描/framework目录(核心框架包,如android.jar对应的应用)
    scanDirTracedLI(new File(Environment.getRootDirectory(), "framework"),
            PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_FRAMEWORK,
            scanFlags, 0);
    // 扫描/system/app(系统应用)
    scanDirTracedLI(mSystemDir, PackageParser.PARSE_IS_SYSTEM, scanFlags, 0);
    // 扫描/vendor/app(厂商应用)
    scanDirTracedLI(mVendorDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_VENDOR,
            scanFlags, 0);
    // 仅非"仅核心包"模式下,扫描/data/app(第三方应用)
    if (!mOnlyCore) {
        scanDirTracedLI(mAppDataDir, 0, scanFlags, 0);
    }
    Log.i(TAG, "Scanned " + mPackages.size() + " packages in "
            + (SystemClock.uptimeMillis() - startTime) + "ms");

    // ===== 步骤4:权限初始化与授予 =====
    // 加载系统预置权限(从framework的AndroidManifest.xml)
    mPermissionManager.loadAllPermissions();
    // 为已扫描的应用授予声明的权限(系统应用优先授予)
    grantDefaultPermissions();

    // ===== 步骤5:其他初始化 =====
    // 初始化包名管理(处理包名冲突、别名)
    mPackageNameManager = new PackageNameManagerService(this);
    // 初始化多用户模块
    mUserManager = UserManagerService.getInstance();
}

构造函数核心要点解析

  • 目录初始化mSystemDir/mDataDir等路径是PMS扫描apk的基础,enforceDirectoryPermissions()会校验目录的rwx权限(如/data/app需属于system用户,权限755),无权限则直接崩溃;
  • 内存数据库mPackages是PMS最核心的数据结构,存储所有已扫描应用的完整信息(包名、版本、签名、组件等),后续getPackageInfo()等接口均从这里读取数据;
  • 分阶段扫描 :先扫描核心框架包(确保系统基础功能),再扫描系统应用,最后扫描第三方应用,且onlyCore模式下跳过第三方应用,减少启动耗时;
  • 权限授予grantDefaultPermissions()会根据应用的签名、位置(如/system/app)授予系统权限,普通应用需用户手动授权的权限在此仅记录声明,不授予。

3. 服务注册:ServiceManager.addService()

java 复制代码
ServiceManager.addService(Context.PACKAGE_SERVICE, m);

源码关联Context.PACKAGE_SERVICE的定义是"package",与前文提到的服务名称一致。

java 复制代码
// Context.java中定义
public static final String PACKAGE_SERVICE = "package";

// ServiceManager.java的addService方法
public static void addService(String name, IBinder service) {
    try {
        getIServiceManager().addService(name, service, false, IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT);
    } catch (RemoteException e) {
        Log.e(TAG, "error adding service " + name, e);
    }
}

作用解析

  • getIServiceManager()获取ServiceManager的Binder代理对象(IServiceManager);

  • addService将PMS的Binder对象(PMS继承自IPackageManager.Stub,实现Binder通信)注册到ServiceManager的服务注册表;

  • 第三个参数false表示"非单例"(实际PMS是单例),第四个参数是dump优先级;

  • 注册完成后,其他进程可通过Context.getSystemService(Context.PACKAGE_SERVICE)获取PMS代理,底层逻辑是:

    java 复制代码
    // ContextImpl.java
    @Override
    public Object getSystemService(String name) {
        return SystemServiceRegistry.getSystemService(this, name);
    }
    // SystemServiceRegistry.java
    static {
        registerService(Context.PACKAGE_SERVICE, PackageManager.class,
                new CachedServiceFetcher<PackageManager>() {
                    @Override
                    public PackageManager createService(ContextImpl ctx) {
                        // 获取PMS的Binder代理
                        IPackageManager pm = IPackageManager.Stub.asInterface(
                                ServiceManager.getService(Context.PACKAGE_SERVICE));
                        return new ApplicationPackageManager(ctx, pm);
                    }
                });
    }

4. 系统用户包启用:enableSystemUserPackages()

java 复制代码
m.enableSystemUserPackages();

源码实现(简化)

java 复制代码
void enableSystemUserPackages() {
    // 获取系统用户(User 0)的UserHandle
    UserHandle systemUser = UserHandle.SYSTEM;
    // 为系统用户启用所有已扫描的包
    synchronized (mLock) {
        for (PackageParser.Package pkg : mPackages.values()) {
            // 设置包对系统用户可见
            setPackageVisibleToUser(pkg.packageName, true, systemUser.getIdentifier());
        }
    }
    // 触发系统用户的包信息更新
    mUserManager.onPackagesAvailableForUser(systemUser.getIdentifier());
}

作用

  • Android多用户体系中,应用包默认仅对创建者可见,系统用户(User 0)是基础用户,需确保所有系统包/第三方包对其可见;
  • setPackageVisibleToUser修改包的可见性标记,mUserManager.onPackagesAvailableForUser通知用户管理服务更新包状态。

5. 包验证模块初始化:getPackageVerificationManager().initialize()

java 复制代码
m.getPackageVerificationManager().initialize();

源码实现(简化)

java 复制代码
PackageVerificationManager getPackageVerificationManager() {
    if (mPackageVerificationManager == null) {
        mPackageVerificationManager = new PackageVerificationManager(this);
    }
    return mPackageVerificationManager;
}

// PackageVerificationManager.java
void initialize() {
    // 加载包验证规则(如是否校验第三方apk的签名)
    mVerificationRules = loadVerificationRules();
    // 注册包安装验证的监听器(监听apk安装过程中的验证事件)
    registerVerificationListeners();
}

作用

  • Android 11新增的包验证模块,用于校验apk安装的合法性(如是否为恶意应用、是否符合企业策略);
  • initialize()加载系统预置的验证规则,初始化监听器,确保后续apk安装时触发验证流程。

main函数关联的关键源码设计

1. Binder通信核心:IPackageManager.aidl

PMS能对外提供跨进程服务,核心是实现了IPackageManager.aidl定义的接口,而main函数注册的Binder对象正是该接口的实现:

aidl 复制代码
// IPackageManager.aidl
package android.content.pm;

interface IPackageManager {
    // 获取包信息
    PackageInfo getPackageInfo(String packageName, int flags, int userId);
    // 安装包
    void installPackage(String packagePath, IPackageInstallObserver observer, int flags);
    // 卸载包
    void uninstallPackage(String packageName, IPackageDeleteObserver observer, int flags);
    // 其他核心接口...
}

PMS的继承关系:

java 复制代码
public class PackageManagerService extends IPackageManager.Stub {
    // 实现IPackageManager.aidl中定义的所有接口
    @Override
    public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
        // 从mPackages中读取包信息,返回给调用方
        synchronized (mLock) {
            PackageParser.Package pkg = mPackages.get(packageName);
            if (pkg == null) {
                throw new PackageManager.NameNotFoundException(packageName);
            }
            return generatePackageInfo(pkg, flags, userId);
        }
    }
}

2. installd通信:Installer类

main函数传入的Installer对象是PMS与底层installd守护进程通信的桥梁,installd负责apk的解压、文件权限修改、dex优化等底层操作:

java 复制代码
// Installer.java核心方法
public class Installer {
    // 创建应用数据目录
    public int createDataDir(String pkgname, int uid, int gid) {
        return execute("create_data_dir", pkgname, String.valueOf(uid), String.valueOf(gid));
    }
    // 解压apk文件
    public int extract(String src, String dst) {
        return execute("extract", src, dst);
    }
    // 底层通过socket与installd通信,execute方法发送指令
    private int execute(String... args) {
        // 建立socket连接,发送指令,接收返回值
    }
}

PMS在安装apk时,会调用mInstaller.createDataDir()创建应用数据目录,再调用extract()解压apk,所有底层文件操作均通过Installer完成,这也是main函数注入Installer的核心原因------解耦PMS与底层文件操作。

源码层面的关键优化点

从源码中可看出Android对PMS启动性能的优化设计:

1. 分阶段扫描+异步扫描

java 复制代码
// 构造函数中,核心包扫描同步执行,第三方包异步执行(Android 11优化)
if (!mOnlyCore) {
    // 异步扫描/data/app,避免阻塞SystemServer主线程
    mHandler.post(() -> scanDirTracedLI(mAppDataDir, 0, scanFlags, 0));
}

2. 包信息缓存

PMS会将mPackages中的包信息序列化到/data/system/packages.xml/data/system/packages.list,下次启动时直接加载缓存,无需重新扫描:

java 复制代码
// 构造函数中加载缓存
private void loadPackageInfoCache() {
    File packagesXml = new File(mDataDir, "system/packages.xml");
    if (packagesXml.exists()) {
        // 解析packages.xml,恢复mPackages数据
        parsePackagesXml(packagesXml);
    }
}

3. 懒加载

部分非核心模块(如mPackageVerificationManager)采用懒加载模式,仅在首次调用时初始化,减少启动时的内存占用和耗时。

总结

PMS的main函数虽代码量少,但串联了实例化、服务注册、模块初始化三大核心环节,其背后的源码设计体现了Android系统服务的核心思想:

  1. 分层设计 :PMS上层处理业务逻辑(包管理、权限),底层通过Installer依赖installd处理文件操作,通过Binder依赖ServiceManager处理跨进程通信;
  2. 性能优先:分阶段扫描、异步执行、缓存复用等设计,均为减少SystemServer启动耗时;
  3. 安全校验:目录权限校验、签名校验、进程校验,确保PMS运行的安全性;
  4. 可扩展性 :通过依赖注入(ContextInstaller)和模块化设计(权限管理、包安装器、dex优化),便于后续功能扩展。
相关推荐
BoomHe3 小时前
Android LMK(Low Memory Killer)机制
android
时光呀时光慢慢走3 小时前
MAUI 开发安卓 MQTT 客户端:实现远程控制 (完整源码 + 避坑指南)
android·物联网·mqtt·c#
成都大菠萝3 小时前
2-2-44 快速掌握Kotlin-函数类型操作
android
有位神秘人4 小时前
Android中获取设备里面的音频文件
android
2501_915918415 小时前
使用 HBuilder 上架 iOS 应用时常见的问题与应对方式
android·ios·小程序·https·uni-app·iphone·webview
farewell-Calm5 小时前
01_Android快速入门
android
helloCat5 小时前
记录CI/CD自动化上传AppGallery遇到的坑
android·前端·api
WordPress学习笔记6 小时前
wordpress根据页面别名获取该页面的链接
android·wordpress
2501_916007476 小时前
iOS 崩溃日志的分析方法,将崩溃日志与运行过程结合分析
android·ios·小程序·https·uni-app·iphone·webview