本文基于 Android 15

一、启动流程

PKMS 是一个负责包管理的系统服务,是在 SystemServer 进程中进行启动的,在开机阶段中 SystemServer 中执行 startOtherService()

1.1 SystemServer.startOtherServices()

t.traceBegin("StartPackageManagerService");
try {
    Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
    mPackageManagerService = PackageManagerService.main( // PKMS 的创建和注册过程
            mSystemContext, installer, domainVerificationService,
            mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF);
} finally {
    Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
}

mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
t.traceEnd();

这里调用 PKMS 的 main 方法来进行 PKMS 的初始化,服务注册,应用扫描、解析和安装等操作

1.1 PKMS.main()

/** Starts PackageManagerService. */
public static PackageManagerService main(Context context,
        Installer installer, @NonNull DomainVerificationService domainVerificationService,
        boolean factoryTest) {

    HandlerThread backgroundThread = new ServiceThread("PackageManagerBg", // 创建 PackageManagerBg 线程
            Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
    backgroundThread.start();
    Handler backgroundHandler = new Handler(backgroundThread.getLooper(),
            BACKGROUND_HANDLER_CALLBACK); // 创建 PackageManagerBg 后台线程的 Handler
    // 先创建 PackageManagerServiceInjector 注入器对象,获取使用的一些对象都可以从里面进行获取,这里使用的是 lambda 表达式
    PackageManagerServiceInjector injector = new PackageManagerServiceInjector(
            ...
            (i, pm) -> new Settings(Environment.getDataDirectory(),
                    RuntimePermissionsPersistence.createInstance(),
                    i.getPermissionManagerServiceInternal(),
                    domainVerificationService, backgroundHandler,
                    lock),
            ...
            (i, pm) -> new PackageDexOptimizer(i.getInstaller(), i.getInstallLock(),
                    i.getContext(), "*dexopt*"),
            (i, pm) -> new DexManager(i.getContext(), i.getPackageDexOptimizer(),
                    i.getDynamicCodeLogger()),
            ...
            (i, pm) -> new PackageParser2(pm.mSeparateProcesses, i.getDisplayMetrics(), // 获取包解析器,重要的
                    new PackageCacher(pm.mCacheDir, pm.mPackageParserCallback),
                    pm.mPackageParserCallback) /* scanningCachingPackageParserProducer */,
            (i, pm) -> new PackageParser2(pm.mSeparateProcesses, i.getDisplayMetrics(), null,
                    pm.mPackageParserCallback) /* scanningPackageParserProducer */,
            (i, pm) -> new PackageParser2(pm.mSeparateProcesses, i.getDisplayMetrics(), null,
                    pm.mPackageParserCallback) /* preparingPackageParserProducer */,
            // Prepare a supplier of package parser for the staging manager to parse apex file
            // during the staging installation.
            (i, pm) -> new PackageInstallerService( // 创建 PackageInstallerService
                    i.getContext(), pm, i::getScanningPackageParser),
            ...);
            
    // 这里才会创建 PKMS 对象
    PackageManagerService m = new PackageManagerService(injector, factoryTest,
            PackagePartitions.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG,
            Build.VERSION.SDK_INT, Build.VERSION.INCREMENTAL); 
    t.traceEnd(); // "create package manager"
    ...
    m.installAllowlistedSystemPackages();
    IPackageManagerImpl iPackageManager = m.new IPackageManagerImpl(); // 获取的是 PackageManagerService 本身,因为这里调用是在 PKMS 的本地进程中
    ServiceManager.addService("package", iPackageManager); // 将 PKMS 注册到 ServiceManager 中,发布服务
    final PackageManagerNative pmn = new PackageManagerNative(m); // 相当于是同时注册两个独立的服务,注册 PackageManagerNative 对象之后,客户端可与 Native 直接通信,不必再传递到 Java 层来
    ServiceManager.addService("package_native", pmn); // 再使用 JNI 初始化 Native 层对应的 PKMS 服务,然后同时发布到 ServiceManager 中进行注册
    // 服务的发布必须进行注册到 ServiceManager 中,客户端才能获取到服务的代理类
    return m;
}
  • 创建并启动 PackageManagerBg 线程

  • 初始化 PackageManagerServiceInjector 注入器对象,再初始化 PackageManagerService 对象

  • 将 PKMS 注册到 ServiceManager 中

  • 将 PKMS 的 Native 对象注册到 ServiceManager 中

创建 PackageManagerBg 线程,后续有一些操作可通过 Handler 投递到该线程进行执行,依赖的初始化是通过 PackageManagerServiceInjector 来进行,将 PKMS 所以来的对象维护在 Injector 中,后续 PKMS 需要使用就直接从注入器中获取

创建 Injector 对象之后,调用 PKMS 的构造方法来进行 PKMS 初始化,其中会进行应用扫描、解析和安装等等一系列繁琐的操作,后文就一直围绕着构造方法中具体的一些重要步骤在讲述

最后会将 PKMS 发布到 ServiceManager 中进行服务的注册,后续其他进程想要使用该服务的使用才能调用到,这是 binder 通信的必要操作

还会通过 JNI 初始化一个 PackageManagerNative 的 Native 层对象,这是 PKMS 在 Native 的对应表示,将其也注册到 ServiceManager 中

1.2 new PackageManagerService()

public PackageManagerService(PackageManagerServiceInjector injector, boolean factoryTest,
        final String partitionsFingerprint, final boolean isEngBuild,
        final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
    ...
    mPendingBroadcasts = new PendingPackageBroadcasts();
    ...
    // PKMS 初始化的第一个阶段 BOOT_PROGRESS_PMS_START
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
            SystemClock.uptimeMillis());

    // 添加 PackageManagerInternal 到 LocalServices 中供 SystemServer 进程内部使用
    LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());
    LocalManagerRegistry.addManager(PackageManagerLocal.class,
            new PackageManagerLocalImpl(this));
    LocalServices.addService(TestUtilityService.class, this);
    mTestUtilityService = LocalServices.getService(TestUtilityService.class);
    mUserManager = injector.getUserManagerService();
    mUserNeedsBadging = new UserNeedsBadgingCache(mUserManager);
    mComponentResolver = injector.getComponentResolver();
    mPermissionManager = injector.getPermissionManagerServiceInternal(); // PermissionManagerService 对象
    mSettings = injector.getSettings(); // 属于 pm 包下的维护着一些配置的 Settings 类
    mIncrementalManager = mInjector.getIncrementalManager();
    mDefaultAppProvider = mInjector.getDefaultAppProvider();
    mLegacyPermissionManager = mInjector.getLegacyPermissionManagerInternal();
    PlatformCompat platformCompat = mInjector.getCompatibility();

    t.traceBegin("addSharedUsers"); // 进行 SharedUserId 的初始化,为系统关键组件添加 SharedUserId
    mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.se", SE_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    mSettings.addSharedUserLPw("android.uid.uwb", UWB_UID,
            ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    final ArrayMap<String, Integer> oemDefinedUids = systemConfig.getOemDefinedUids();
    final int numOemDefinedUids = oemDefinedUids.size();
    for (int i = 0; i < numOemDefinedUids; i++) {
        mSettings.addOemSharedUserLPw(oemDefinedUids.keyAt(i), oemDefinedUids.valueAt(i),
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
    }
        ...
    
        // 这里进行读取历史持久化配置,顺便可以通过是否存在历史持久化配置来判断是否首次开机启动
        mFirstBoot = !mSettings.readLPw(computer, // LPw 表示需要持有锁并且需要执行写操作
                mInjector.getUserManagerInternal().getUsers(
                /* excludePartial= */ true,
                /* excludeDying= */ false,
                /* excludePreCreated= */ false));
        t.traceEnd();

        mPermissionManager.readLegacyPermissionsTEMP(mSettings.mPermissions); // 读取之前的权限信息
        mPermissionManager.readLegacyPermissionStateTEMP(); // 读取了之后存储起来

        if (mFirstBoot) {
            DexOptHelper.requestCopyPreoptedFiles();
        }
        
        // 开始 PKMS 扫描阶段
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
                startTime);
        // 获取 InitAppsHelper 类,负责应用扫描安装
        mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper,
                mInjector.getSystemPartitions());
             
        final int[] userIds = mUserManager.getUserIds();
        // 初始化 PackageParser 对象(包解析器)
        PackageParser2 packageParser = mInjector.getScanningCachingPackageParser();
        // 进行系统应用的扫描安装
        mOverlayConfig = mInitAppsHelper.initSystemApps(packageParser, packageSettings, userIds,
                startTime);
        // 进行三方应用扫描安装
        mInitAppsHelper.initNonSystemApps(packageParser, userIds, startTime);
        packageParser.close();
        
        // PKMS 应用扫描结束
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
                SystemClock.uptimeMillis());
        ...
        // PKMS ready 阶段
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
                SystemClock.uptimeMillis());
        ...
}
  • 进行一些依赖服务的绑定,PackageManagerService 初始化

  • 进行 SharedUserId 的初始化,为系统关键组件添加 SharedUserId

  • 通过 com.android.server.pm.Settings 类来读取持久化配置并保存起来,顺便判断是否手次开机启动

  • 通过 mInitAppsHelper 进行系统应用和三方应用的扫描安装

二、应用扫描

针对构造方法中的应用扫描、解析和安装来进一步详细说明,这也是 PKMS 启动的核心流程

这里就使用系统应用的安装来举例

2.1 InitAppsHelper.initSystemApps()

/**
 * Install apps from system dirs.
 * 安装系统应用
 */
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
public OverlayConfig initSystemApps(PackageParser2 packageParser,
        WatchedArrayMap<String, PackageSetting> packageSettings,
        int[] userIds, long startTime) {
    // 这里先扫描 apex 包,解析为 ApexManager.ScanResult 对象
    final List<ApexManager.ScanResult> apexScanResults = scanApexPackagesTraced(packageParser);
    mApexManager.notifyScanResult(apexScanResults);

    scanSystemDirs(packageParser, mExecutorService);
    ...
    logSystemAppsScanningTime(startTime);
    return overlayConfig;
}
  • 这里 SystemApp 包括 system、system_ext、product、vendor、odm、oem、apex 分区下的/app 和/priv-app 目录下的 apk,也包括 apex 包

  • 先进行 apex 包的扫描

  • 进行系统目录的扫描和应用安装,包括 system、system_ext、product、vendor、odm、oem、apex 分区

  • apex 包启用和 overlay 配置

2.2 InitAppsHelper.scanSystemDirs()

/**
 * First part of init dir scanning
 */
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
private void scanSystemDirs(PackageParser2 packageParser, ExecutorService executorService) {
    File frameworkDir = new File(Environment.getRootDirectory(), "framework"); // /system/framework 目录
   
    // mDirsToScanAsSystem 包括 system、system_ext、product、vendor、odm、oem 分区以及包括 apex 包所在的分区(如 apex)
    for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
        final ScanPartition partition = mDirsToScanAsSystem.get(i);
        if (partition.getOverlayFolder() == null) {
            continue;
        }
        scanDirTracedLI(partition.getOverlayFolder(), // 这里先扫描每个分区中 overlay 包并进行安装
                mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
                packageParser, executorService, partition.apexInfo);
    }

    scanDirTracedLI(frameworkDir, // 扫描/system/framework/目录并进行安装
            mSystemParseFlags, mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED,
            packageParser, executorService, null);
    if (!mPm.mPackages.containsKey("android")) {
        throw new IllegalStateException(
                "Failed to load frameworks package; check log for warnings");
    }

    for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
        final ScanPartition partition = mDirsToScanAsSystem.get(i);
        if (partition.getPrivAppFolder() != null) { // 扫描每个系统分区中的/priv-app 目录并安装
            scanDirTracedLI(partition.getPrivAppFolder(),
                    mSystemParseFlags,
                    mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag,
                    packageParser, executorService, partition.apexInfo);
        }
        scanDirTracedLI(partition.getAppFolder(), // 扫描每个系统分区中的/app 目录并安装
                mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
                packageParser, executorService, partition.apexInfo);
    }
}
  • 遍历扫描系统分区中(system、system_ext、product、vendor、odm、oem、apex)的 overlay 包并安装

  • 扫描/system/framework/目录

  • 遍历扫描系统分区中的/priv-app 目录安装包并安装

  • 遍历扫描系统分区中的/app 目录安装包并安装

2.3 InitAppsHelper.scanDirTracedLI()

@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
private void scanDirTracedLI(File scanDir, int parseFlags, int scanFlags,
        PackageParser2 packageParser, ExecutorService executorService,
        @Nullable ApexManager.ActiveApexInfo apexInfo) {
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
    try {
        if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
            // when scanning apk in apexes, we want to check the maxSdkVersion
            parseFlags |= PARSE_APK_IN_APEX;
        }
        mInstallPackageHelper.installPackagesFromDir(scanDir, parseFlags,
                scanFlags, packageParser, executorService, apexInfo);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}

参数:
扫描路径:scanDir

包解析器:packageParser

packageParser(包解析器)会进行 apk 的解析,apk 包的基本信息获取,包名、版本号和证书等等,解析 AndroidManifest.xml 中的各个标签,、等标签,解析标签,四大组件的解析,最后封装为 Parsedpackage 类来表示解析结果

2.4 InstallPackageHelper.installPackagesFromDir()

@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
public void installPackagesFromDir(File scanDir, int parseFlags,
        int scanFlags, PackageParser2 packageParser, ExecutorService executorService,
        @Nullable ApexManager.ActiveApexInfo apexInfo) {
    final File[] files = scanDir.listFiles(); // 获取待安装目录下的所有文件

    // 并行解析器(多线程)
    ParallelPackageParser parallelPackageParser =
            new ParallelPackageParser(packageParser, executorService);

    // Submit files for parsing in parallel
    int fileCount = 0;
    for (File file : files) {
        final boolean isPackage = (isApkFile(file) || file.isDirectory())
                && !PackageInstallerService.isStageName(file.getName());
        if (!isPackage) {
            // Ignore entries which are not packages
            continue;
        }
        ...
        parallelPackageParser.submit(file, parseFlags); // 提交该 apk 给解析器,调用 PackageParser2.parsePackage()进行解析
        fileCount++;
    }

    // Process results one by one 开始依次解析
    for (; fileCount > 0; fileCount--) {
        // 这里一次处理解析后的结果
        ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
        Throwable throwable = parseResult.throwable;
        int errorCode = PackageManager.INSTALL_SUCCEEDED;
        String errorMsg = null;

        if (throwable == null) {
            try {
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "addForInitLI");
                addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
                        new UserHandle(UserHandle.USER_SYSTEM), apexInfo);
            } catch (PackageManagerException e) {
                errorCode = e.error;
                errorMsg = "Failed to scan " + parseResult.scanFile + ": " + e.getMessage();
                Slog.w(TAG, errorMsg);
            } finally {
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
        } else if (throwable instanceof PackageManagerException) {
            PackageManagerException e = (PackageManagerException) throwable;
            errorCode = e.error;
            errorMsg = "Failed to parse " + parseResult.scanFile + ": " + e.getMessage();
            Slog.w(TAG, errorMsg);
        } else {
            throw new IllegalStateException("Unexpected exception occurred while parsing "
                    + parseResult.scanFile, throwable);
        }

        if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0 && errorCode != INSTALL_SUCCEEDED) {
            mApexManager.reportErrorWithApkInApex(scanDir.getAbsolutePath(), errorMsg);
        }

        // Delete invalid userdata apps 解析出错将会删除 app
        if ((scanFlags & SCAN_AS_SYSTEM) == 0
                && errorCode != PackageManager.INSTALL_SUCCEEDED) {
            logCriticalInfo(Log.WARN,
                    "Deleting invalid package at " + parseResult.scanFile);
            mRemovePackageHelper.removeCodePath(parseResult.scanFile);
        }
    }
}

三、应用解析

3.1 PackageParser2.parsePackage()

@AnyThread
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
        throws PackageParserException {
    ...
    // 下面调用工具类 ParsingPackageUtils.parsePackage 进行解析
    ParseResult<ParsingPackage> result = mParsingUtils.parsePackage(input, packageFile, flags);
    if (result.isError()) {
        throw new PackageParserException(result.getErrorCode(), result.getErrorMessage(),
                result.getException());
    }
    ...
    ParsedPackage parsed = (ParsedPackage) result.getResult().hideAsParsed();
    ...
    return parsed; // 返回解析结果
}

3.2 ParsingPackageUtils.parsePackage()

public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile, int flags) {
    if (packageFile.isDirectory()) {
        return parseClusterPackage(input, packageFile,  flags); // 如果是目录,这是一个 apk 集群
    } else {
        return parseMonolithicPackage(input, packageFile, flags); // 是单个文件,解析 Monolithic 单个 package
    }
}

分为两种情况,apk 分包和单包的情况
**分包:**parseClusterPacakge,扫描目录下面所有 apk,合并清单文件,代码、资源和权限信息,最终生成一个完整的 ParsingPackage 对象

**单包:**parseMonolithicPackage,直接解析这个 apk,生成 ParsingPackage 对象

3.3 ParsingPackageUtils.parseClusterPackage()

private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
      int flags) {
    ...
    // 先进行最基础的信息解析(轻量级信息)
    final ParseResult<PackageLite> liteResult =
          ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, liteParseFlags);
    ...
    try {
        final File baseApk = new File(lite.getBaseApkPath());
        // parseBaseApk,进行最主要的解析步骤
        final ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,
                lite.getPath(), assetLoader, flags, shouldSkipComponents);
                
        ParsingPackage pkg = result.getResult();

        return input.success(pkg); // 返回 ParsingPackage 解析结果
    } catch (IllegalArgumentException e) {
        ...
    }
}

解析分包的情况

3.4 ParsingPackageUtils.parseMonolithicPackage()

private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
        int flags) {
    ...
    // 也是先进行轻量级的解析,解析一些包的基本信息
    final ParseResult<PackageLite> liteResult =
            ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, liteParseFlags);
    ...
    try {
        // 重要的步骤,进行主要的解析
        final ParseResult<ParsingPackage> result = parseBaseApk(input,
                apkFile,
                apkFile.getCanonicalPath(),
                assetLoader, flags, shouldSkipComponents);
        return input.success(result.getResult()
                .set32BitAbiPreferred(lite.isUse32bitAbi()));
    } catch (IOException e) {
        ...
    }
}

解析单包的情况

3.3 ParsingPackageUtils.parseBaseApk()

private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
        String codePath, SplitAssetLoader assetLoader, int flags,
        boolean shouldSkipComponents) {
    ...
    // 获取 xml 解析器来解析 AndroidManifest.xml 文件,这是应用解析最重要的步骤
    try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
            ANDROID_MANIFEST_FILENAME)) {
        final Resources res = new Resources(assets, mDisplayMetrics, null);
        ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
                parser, flags, shouldSkipComponents);
        ...
        return input.success(pkg);
}

3.4 ParsingPackageUtils.parseBaseApk()

private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
        String codePath, Resources res, XmlResourceParser parser, int flags,
        boolean shouldSkipComponents)
        throws XmlPullParserException, IOException {
    final String splitName;
    final String pkgName;

    ParseResult<Pair<String, String>> packageSplitResult =
            ApkLiteParseUtils.parsePackageSplitNames(input, parser);

    Pair<String, String> packageSplit = packageSplitResult.getResult();
    pkgName = packageSplit.first;
    splitName = packageSplit.second;
    
    try {
        final boolean isCoreApp = parser.getAttributeBooleanValue(null /*namespace*/,
                "coreApp", false); // 是否是 core app
        final ParsingPackage pkg = mCallback.startParsingPackage(
                pkgName, apkPath, codePath, manifestArray, isCoreApp);
        // 这里进行 AndroidManifest.xml 中标签的解析
        final ParseResult<ParsingPackage> result =
                parseBaseApkTags(input, pkg, manifestArray, res, parser, flags,
                        shouldSkipComponents);
        return input.success(pkg);
        ...
}

重要的步骤,牢记 parseBaseApk 进行 AndroidManifest.xml 的解析

3.5 ParsingPackageUtils.parseBaseApkTags()

private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg,
        TypedArray sa, Resources res, XmlResourceParser parser, int flags,
        boolean shouldSkipComponents) throws XmlPullParserException, IOException {
    // 解析 sharedUserId 属性
    ParseResult<ParsingPackage> sharedUserResult = parseSharedUser(input, pkg, sa);
    
    final boolean updatableSystem = parser.getAttributeBooleanValue(null /*namespace*/,
            "updatableSystem", true); // 是否为可更新的系统应用
    final String emergencyInstaller = parser.getAttributeValue(null /*namespace*/,
            "emergencyInstaller"); // 指定的紧急安装器
    ...
    boolean foundApp = false;
    final int depth = parser.getDepth();
    int type;
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
            && (type != XmlPullParser.END_TAG
            || parser.getDepth() > depth)) {

        String tagName = parser.getName();
        final ParseResult result;

        // <application> has special logic, so it's handled outside the general method
        if (TAG_APPLICATION.equals(tagName)) { // 解析<application>标签,因为 application 有特殊的逻辑,所以单独拿出来
            if (foundApp) {
                if (RIGID_PARSER) {
                    result = input.error("<manifest> has more than one <application>");
                } else {
                    Slog.w(TAG, "<manifest> has more than one <application>");
                    result = input.success(null);
                }
            } else {
                foundApp = true;
                // 解析<applicaiton 标签>,会进行四大组件的解析
                result = parseBaseApplication(input, pkg, res, parser, flags,
                        shouldSkipComponents);
            }
        } else {
            result = parseBaseApkTag(tagName, input, pkg, res, parser, flags);
        }
    }
    return validateBaseApkTags(input, pkg, flags);
}

在这里解析的解析,解析四大组件标签

3.6 ParsingPackageUtils.parseBaseApplication()

private ParseResult<ParsingPackage> parseBaseApplication(ParseInput input,
        ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags,
        boolean shouldSkipComponents) throws XmlPullParserException, IOException {
        ...
        ParseResult<String> taskAffinityResult = ComponentParseUtils.buildTaskAffinityName(
                pkgName, pkgName, taskAffinity, input);

        pkg.setTaskAffinity(taskAffinityResult.getResult());
        ...
    // 下面解析四大组件
    boolean hasActivityOrder = false;
    boolean hasReceiverOrder = false;
    boolean hasServiceOrder = false;
    final int depth = parser.getDepth();
    int type;
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
            && (type != XmlPullParser.END_TAG
            || parser.getDepth() > depth)) {
        ...
        switch (tagName) {
            case "activity":
                ...
            case "receiver":
                ...
            case "service":
                ...
            case "provider":
                ...
            case "activity-alias":
                ...
            case "apex-system-service":
                ...
            default:
                ...
        }
    return input.success(pkg);
}

解析四大组件,最后将解析结果保存到解析结果 ParsingPacakge 对象里面去

3.6 ParsingPackageUtils.parseBaseApkTag()

private ParseResult parseBaseApkTag(String tag, ParseInput input,
        ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
        throws IOException, XmlPullParserException {
    switch (tag) {
        case TAG_OVERLAY:
            return parseOverlay(input, pkg, res, parser);
        case TAG_KEY_SETS:
            return parseKeySets(input, pkg, res, parser);
        case "feature": // TODO moltmann: Remove
        case TAG_ATTRIBUTION:
            return parseAttribution(input, pkg, res, parser);
        case TAG_PERMISSION_GROUP:
            return parsePermissionGroup(input, pkg, res, parser);
        case TAG_PERMISSION:
            return parsePermission(input, pkg, res, parser, flags);
        case TAG_PERMISSION_TREE:
            return parsePermissionTree(input, pkg, res, parser);
        case TAG_USES_PERMISSION:
        case TAG_USES_PERMISSION_SDK_M:
        case TAG_USES_PERMISSION_SDK_23:
            return parseUsesPermission(input, pkg, res, parser);
        case TAG_USES_CONFIGURATION:
            return parseUsesConfiguration(input, pkg, res, parser);
        case TAG_USES_FEATURE:
            return parseUsesFeature(input, pkg, res, parser);
        case TAG_FEATURE_GROUP:
            return parseFeatureGroup(input, pkg, res, parser);
        case TAG_USES_SDK:
            return parseUsesSdk(input, pkg, res, parser, flags);
        case TAG_SUPPORT_SCREENS:
            return parseSupportScreens(input, pkg, res, parser);
        case TAG_PROTECTED_BROADCAST:
            return parseProtectedBroadcast(input, pkg, res, parser);
        case TAG_INSTRUMENTATION:
            return parseInstrumentation(input, pkg, res, parser);
        case TAG_ORIGINAL_PACKAGE:
            return parseOriginalPackage(input, pkg, res, parser);
        case TAG_ADOPT_PERMISSIONS:
            return parseAdoptPermissions(input, pkg, res, parser);
        case TAG_USES_GL_TEXTURE:
        case TAG_COMPATIBLE_SCREENS:
        case TAG_SUPPORTS_INPUT:
        case TAG_EAT_COMMENT:
            // Just skip this tag
            XmlUtils.skipCurrentTag(parser);
            return input.success(pkg);
        case TAG_RESTRICT_UPDATE:
            return parseRestrictUpdateHash(flags, input, pkg, res, parser);
        case TAG_INSTALL_CONSTRAINTS:
            return parseInstallConstraints(input, pkg, res, parser,
                    mCallback.getInstallConstraintsAllowlist());
        case TAG_QUERIES:
            return parseQueries(input, pkg, res, parser);
        default:
            return ParsingUtils.unknownTag("<manifest>", pkg, parser, input);
    }
}

四、应用安装

4.1 InstallPackageHelper.addForInitLI()

private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
        @ParsingPackageUtils.ParseFlags int parseFlags,
        @PackageManagerService.ScanFlags int scanFlags,
        @Nullable UserHandle user, @Nullable ApexManager.ActiveApexInfo activeApexInfo)
        throws PackageManagerException {
    PackageSetting disabledPkgSetting;
    synchronized (mPm.mLock) {
    ...
    // 解析后的结果
    final Pair<ScanResult, Boolean> scanResultPair = scanPackageForInitLI(
            parsedPackage, parseFlags, scanFlags, user);
    final ScanResult scanResult = scanResultPair.first;
    boolean shouldHideSystemApp = scanResultPair.second;
    // 构建一个安装请求 InstallRequest 对象
    final InstallRequest installRequest = new InstallRequest(
            parsedPackage, parseFlags, scanFlags, user, scanResult, disabledPkgSetting);

    synchronized (mPm.mLock) {
            ...
            commitReconciledScanResultLocked(reconcileResult.get(0),
                    mPm.mUserManager.getUserIds());
    }
    return scanResult.mPkgSetting.getPkg();
}

对于单独的一个 ParsedPackage 解析结果对象,会为其构建一个 InstallRequest 安装请求对象,进行安装

4.2 InstallPackageHelper.commitReconciledScanResultLocked()

/**
 * Commits the package scan and modifies system state.
 * <p><em>WARNING:</em> The method may throw an exception in the middle
 * of committing the package, leaving the system in an inconsistent state.
 * This needs to be fixed so, once we get to this point, no errors are
 * possible and the system is not left in an inconsistent state.
 */
@GuardedBy("mPm.mLock")
private AndroidPackage commitReconciledScanResultLocked(
        @NonNull ReconciledPackage reconciledPkg, int[] allUsers) {
    final InstallRequest request = reconciledPkg.mInstallRequest;
    // TODO(b/135203078): Move this even further away
    ParsedPackage parsedPackage = request.getParsedPackage();
    ...
    // Modify state for the given package setting 最后将
    commitPackageSettings(pkg, pkgSetting, oldPkgSetting, reconciledPkg);
    ...
    return pkg;
}

  • 取出 ReconciledPackage 对象中的 InstallRequest 对象和 parsedPackage 对象

  • commitPackageSettings() 将应用包信息写入到 Settings 中(PKMS 的核心配置管理类),并且会将应用包信息持久化到/data/system/packages.xml 中,是通过 Settings 类完成内存更新和持久化触发

4.3 InstallPackageHelper.commitPackageSettings()

/**
 * Adds a scanned package to the system. When this method is finished, the package will
 * be available for query, resolution, etc...
 * 添加扫描后的 package 到系统中,这个方法结束后,package 就可以被查询、解析等等,应用就安装完成了
 */
private void commitPackageSettings(@NonNull AndroidPackage pkg,
        @NonNull PackageSetting pkgSetting, @Nullable PackageSetting oldPkgSetting,
        ReconciledPackage reconciledPkg) {
    ...
    synchronized (mPm.mLock) {
        // We don't expect installation to fail beyond this point
        // Add the new setting to mSettings
        mPm.mSettings.insertPackageSettingLPw(pkgSetting, pkg); // 这里将 package 信息写入到 pkms 的配置管理类 Settings 中
        // Add the new setting to mPackages
        mPm.mPackages.put(pkg.getPackageName(), pkg);
        
        final List<String> protectedBroadcasts = pkg.getProtectedBroadcasts();
        if (!protectedBroadcasts.isEmpty()) {
            synchronized (mPm.mProtectedBroadcasts) {
                mPm.mProtectedBroadcasts.addAll(protectedBroadcasts); // 进行受保护广播的添加
            }
        }
        // 触发 PermissionManagerService 的回调方法来进行权限的更新
        mPm.mPermissionManager.onPackageAdded(pkgSetting,
                (scanFlags & SCAN_AS_INSTANT_APP) != 0, oldPkg);
    }
    ...
}
  • 最终进行 package 信息更新到 mSettings(PKMS 的核心配置管理类)中

  • 触发 PermissionManagerService 的 onPackageAdded 的回调,进行权限更新

五、总结

到此,PKMS 的开机启动流程就完成了,主要做了以下步骤:

  1. 服务初始化:在 SystemServer 中进行启动,进行 PackageManagerService 的初始化,注册 AIDL 服务到 ServiceManager 中,供夸进程调用

  2. mSettings(PKMS 中核心配置管理类)读取文件系统中的持久化文件(如/data/system/packages.xml),来加载和恢复 PKMS 的配置和应用包信息到内存中,还可以判断是否是第一次启动

  3. 应用扫描:扫描分区(system、system_ext、product、vendor、odm、oem 和 apex 等分区)中的 apex 或 apk 包,读取进行解析应用包

  4. 分别解析系统应用和三方应用,进行应用 apk 的解析,解析包名、版本号、签名等等,解析 AndroidManifest.xml 中的各个标签,、等标签,解析标签,四大组件的解析,最后封装为 Parsedpackage 类来表示解析结果

  5. 应用安装,依次遍历处理后的结果,创建 InstallRequest 对象,交给 InstallPackageHelper 进行应用安装,将 package 的信息保存到(内存)mSettings 中,并触发 mSettings 来持久化写入文件中,最后触发 PermissionManagerService 的回调来进行应用权限信息的更新

PKMS 的核心价值:管理应用全生命周期(安装、更新、卸载、查询),保障应用安装的安全性、系统的稳定性,以及跨进程应用交互的可行性

流程图

在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐