PackageManagerService(PKMS)构造函数分析

220 阅读30分钟

在上一篇文章中,分析了PKMS的启动过程,在启动过程中有一步是通过 new PackageManagerService 创建一个 PackageManagerService 实例,本文就从SystemServer开始,进一步具体分析下PKMS的构造函数。
本文以android 13代码为例进行分析。

1,在frameworks/base/services/java/com/android/server/SystemServer.java中

private SystemServiceManager mSystemServiceManager; // 在run函数中进行初始化,即 mSystemServiceManager = new SystemServiceManager(mSystemContext);

private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {

	t.traceBegin("StartInstaller");
    Installer installer = mSystemServiceManager.startService(Installer.class); // 启动安装器服务,确保在初始化其他服务之前,系统安装器已经完成了必要的初始化工作,比如创建关键目录和设置适当的权限。
    t.traceEnd();
	
	IPackageManager iPackageManager;
    t.traceBegin("StartPackageManagerService");
    try {
		// 调用了Watchdog的实例来暂停对当前线程的监控,避免在PackageManagerService启动过程中因为操作时间过长而被系统认为是无响应(ANR)。"packagemanagermain"是这里用于标识线程的字符串。
        Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain"); 
		
		// 通过调用PackageManagerService.main(...)方法启动PMS
        Pair<PackageManagerService, IPackageManager> pmsPair = PackageManagerService.main(
                mSystemContext, installer, domainVerificationService,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore); 
				
        mPackageManagerService = pmsPair.first; // 将Pair对象的first(即PackageManagerService的实例)保存到mPackageManagerService变量中。
		
        iPackageManager = pmsPair.second; // 将Pair对象的second(即IPackageManager的实现)保存到iPackageManager变量中,用于后续跨进程通信。
    } finally {
        Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain"); // 在PMS启动完毕后,恢复对当前线程的监控。
    }
    
    t.traceEnd();
}

上面的代码中调用了 PackageManagerService.main 函数。

2,在frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java中

public static Pair<PackageManagerService, IPackageManager> main(Context context,
            Installer installer, @NonNull DomainVerificationService domainVerificationService,
            boolean factoryTest, boolean onlyCore) {
	...
	// 创建一个PackageManagerService的实例 m,传入多个参数。
    PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest,PackagePartitions.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG, Build.VERSION.SDK_INT, Build.VERSION.INCREMENTAL);
	...
}

上面的代码中通过 new PackageManagerService 创建了 PKMS对象,下面分析下 PackageManagerService 构造函数。
PackageManagerService 构造函数很复杂,可以根据日志划分为 BOOT_PROGRESS_PMS_START,
BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
BOOT_PROGRESS_PMS_SCAN_END,
BOOT_PROGRESS_PMS_READY 等阶段。

public PackageManagerService(PackageManagerServiceInjector injector, boolean onlyCore,
				boolean factoryTest, final String buildFingerprint, final boolean isEngBuild,
				final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
				...
	// 记录系统启动进度事件,并写入事件日志。
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, SystemClock.uptimeMillis());
	
	// 通过injector获取系统设置(Settings),并将其赋值给成员变量mSettings。这些设置包括用户偏好和系统配置。
	mSettings = injector.getSettings();
	
	mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
					ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
	...
	EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,startTime);
	
	// 获取缓存目录
	mCacheDir = PackageManagerServiceUtils.preparePackageParserCache(
	        mIsEngBuild, mIsUserDebugBuild, mIncrementalVersion);
	
	final int[] userIds = mUserManager.getUserIds();
	// 获取PackageParser2对象
	PackageParser2 packageParser = mInjector.getScanningCachingPackageParser();
	// 扫描系统app
	mOverlayConfig = mInitAppsHelper.initSystemApps(packageParser, packageSettings, userIds,
	        startTime);
	// 系统app以为的app
	mInitAppsHelper.initNonSystemApps(packageParser, userIds, startTime); //调用 initNonSystemApps 函数会走到 BOOT_PROGRESS_PMS_DATA_SCAN_START
	packageParser.close();
	
	EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,SystemClock.uptimeMillis());
	
	mPermissionManager.onStorageVolumeMounted(
	        StorageManager.UUID_PRIVATE_INTERNAL, mIsUpgrade);
	ver.sdkVersion = mSdkVersion;
	
	EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
	        SystemClock.uptimeMillis());
			
	mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr(computer);
	
	mSettings.setPermissionControllerVersion(
	        computer.getPackageInfo(mRequiredPermissionControllerPackage, 0,
	                UserHandle.USER_SYSTEM).getLongVersionCode());
					
	t.traceBegin("GC");
	VMRuntime.getRuntime().requestConcurrentGC();
	t.traceEnd();
		
}

首先看下 BOOT_PROGRESS_PMS_START 阶段。
在 BOOT_PROGRESS_PMS_START 阶段做的基本是基础准备工作,获取了需要的一系列对象和路径,创建了 Settings。

final Settings mSettings;//在PKMS的构造函数中通过 injector.getSettings() 进行赋值,即 mSettings = injector.getSettings();
//通过循环或逐个调用addSharedUserLPw方法,向mSettings(系统设置对象)中添加多个共享用户。每个调用都指定了共享用户的名称、UID(用户标识符)、系统标志和私有特权标志。
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);

下面分析下Settings.java类。

3,在frameworks/base/services/core/java/com/android/server/pm/Settings.java中

public final class Settings implements Watchable, Snappable {
	
	Settings(File dataDir, RuntimePermissionsPersistence runtimePermissionsPersistence,
            LegacyPermissionDataProvider permissionDataProvider,
            @NonNull DomainVerificationManagerInternal domainVerificationManager,
            @NonNull Handler handler,
            @NonNull PackageManagerTracedLock lock)  {
        mPackages = new WatchedArrayMap<>(); // 使用WatchedArrayMap初始化,用于存储应用包信息。
        mPackagesSnapshot  =
                new SnapshotCache.Auto<>(mPackages, mPackages, "Settings.mPackages"); // 基于mPackages创建一个快照缓存,用于高效访问。
        mKernelMapping = new WatchedArrayMap<>(); // 用于存储内核映射信息及其快照。
        mKernelMappingSnapshot =
                new SnapshotCache.Auto<>(mKernelMapping, mKernelMapping, "Settings.mKernelMapping");
        mInstallerPackages = new WatchedArraySet<>(); // 用于存储安装器包信息及其快照。
        mInstallerPackagesSnapshot =
                new SnapshotCache.Auto<>(mInstallerPackages, mInstallerPackages,
                                         "Settings.mInstallerPackages");
        mKeySetManagerService = new KeySetManagerService(mPackages); // 初始化KeySetManagerService,可能用于管理应用签名密钥集。
    
        mHandler = handler;
        mLock = lock;
        mAppIds = new AppIdSettingMap(); // 使用AppIdSettingMap初始化,用于存储应用ID设置。
        mPermissions = new LegacyPermissionSettings(lock); // 使用LegacyPermissionSettings初始化,管理旧版权限设置。
        mRuntimePermissionsPersistence = new RuntimePermissionPersistence(
                runtimePermissionsPersistence, new Consumer<Integer>() {
            @Override
            public void accept(Integer userId) {
                mRuntimePermissionsPersistence.writeStateForUser(userId, mPermissionDataProvider,
                        mPackages, mSharedUsers, mHandler, mLock, /*sync=*/false);
            }
        }); // mRuntimePermissionsPersistence 初始化运行时权限持久化对象,包含一个用户ID的回调,用于写入用户状态。
        mPermissionDataProvider = permissionDataProvider;
    
        mSystemDir = new File(dataDir, "system"); // 初始化系统目录(mSystemDir),并创建目录和设置权限。
        mSystemDir.mkdirs();
        FileUtils.setPermissions(mSystemDir.toString(),
                FileUtils.S_IRWXU|FileUtils.S_IRWXG
                |FileUtils.S_IROTH|FileUtils.S_IXOTH,
                -1, -1);
    	 // 初始化设置文件(mSettingsFilename、mBackupSettingsFilename、mPackageListFilename),并设置mPackageListFilename的权限。
        mSettingsFilename = new File(mSystemDir, "packages.xml");
        mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
        mPackageListFilename = new File(mSystemDir, "packages.list");
        FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);
    
    	 // 尝试设置内核映射文件目录(mKernelMappingFilename),如果/config/sdcardfs目录存在。
        final File kernelDir = new File("/config/sdcardfs");
        mKernelMappingFilename = kernelDir.exists() ? kernelDir : null;
    
        // Deprecated: Needed for migration
        mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
        mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
    
        mDomainVerificationManager = domainVerificationManager; // 初始化为传入的域验证管理器。
    
        registerObservers(); // 注册观察者以监听设置的变化。
        Watchable.verifyWatchedAttributes(this, mObserver);
    
        mSnapshot = makeCache(); // 调用makeCache()方法创建快照缓存。
    }
}

Settings中保存了安装包信息,主要文件就是 packages.xml,packages-backup.xml,packages.list.
packages.xml文件:PKMS扫描完目标文件夹后会创建该文件,当系统进行程序安装、卸载、更新等操作时均会更新该文件,该文件保存了系统中与package相关的一些信息。
packages.list文件:描述系统中存在的所有非系统自带的APK信息,当这些程序有变动时,PKMS会更新该文件。

接着看下 BOOT_PROGRESS_PMS_SYSTEM_SCAN_START 阶段。
在 BOOT_PROGRESS_PMS_SYSTEM_SCAN_START 阶段重要的是通过 mInitAppsHelper 获取系统apk和其它apk信息。

private final InitAppsHelper mInitAppsHelper; //在构造函数中进行初始化,即 mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper,mInjector.getSystemPartitions()); 

//获取PackageParser2对象
PackageParser2 packageParser = mInjector.getScanningCachingPackageParser();
//扫描系统app
mOverlayConfig = mInitAppsHelper.initSystemApps(packageParser, packageSettings, userIds,
        startTime);
//系统app以为的app
mInitAppsHelper.initNonSystemApps(packageParser, userIds, startTime);
packageParser.close();

上面的代码中调用了 InitAppsHelper 类的 initSystemApps 和 initNonSystemApps 函数。
首先分析下 initSystemApps 函数。

4,在frameworks/base/services/core/java/com/android/server/pm/InitAppsHelper.java中

/**
 * Install apps from system dirs.
 */
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
public OverlayConfig initSystemApps(PackageParser2 packageParser,
        WatchedArrayMap<String, PackageSetting> packageSettings,
        int[] userIds, long startTime) { // 方法的参数定义。PackageParser2 packageParser用于解析APK文件,WatchedArrayMap<String, PackageSetting> packageSettings存储应用的设置信息,int[] userIds是用户ID数组,long startTime记录方法开始执行的时间,用于后续计算执行时间。
    // Prepare apex package info before scanning APKs, this information is needed when
    // scanning apk in apex.
	 // 在扫描APK文件之前,准备Apex包的信息。Apex是Android 10引入的一种模块化系统,允许将系统服务和应用以模块化的形式打包。这里调用mApexManager.scanApexPackagesTraced方法来扫描Apex包,这是因为在扫描Apex中的APK时需要这些信息。
    mApexManager.scanApexPackagesTraced(packageParser, mExecutorService);

	 // 调用scanSystemDirs方法来扫描系统目录中的APK文件。
    scanSystemDirs(packageParser, mExecutorService);
    
    // Parse overlay configuration files to set default enable state, mutability, and
    // priority of system overlays.
    final ArrayMap<String, File> apkInApexPreInstalledPaths = new ArrayMap<>(); //创建一个ArrayMap<String, File>,用于存储APK在Apex中预安装的路径信息。
	 // 遍历所有激活的Apex信息,对于每个Apex模块,获取其中包含的APK包名,并将这些APK的包名和对应的Apex预安装路径存储到apkInApexPreInstalledPaths中。
    for (ApexManager.ActiveApexInfo apexInfo : mApexManager.getActiveApexInfos()) {
        for (String packageName : mApexManager.getApksInApex(apexInfo.apexModuleName)) {
            apkInApexPreInstalledPaths.put(packageName, apexInfo.preInstalledApexPath);
        }
    }
	 //  初始化OverlayConfig实例。这里通过调用OverlayConfig.initializeSystemInstance方法,并传入一个lambda表达式,该表达式遍历所有包,使用包管理器(mPm)为每个包调用一个消费者函数,该函数接受包信息、是否为系统包以及APK在Apex中的预安装路径。
    final OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
            consumer -> mPm.forEachPackage(mPm.snapshotComputer(),
                    pkg -> consumer.accept(pkg, pkg.isSystem(),
                            apkInApexPreInstalledPaths.get(pkg.getPackageName()))));

	 // 如果不是仅处理核心应用(mIsOnlyCoreApps为false),则首先更新存根系统应用列表(updateStubSystemAppsList),然后准备系统应用的清理工作(prepareSystemPackageCleanUp),这可能包括删除或更新一些系统应用。
    if (!mIsOnlyCoreApps) {
        // do this first before mucking with mPackages for the "expecting better" case
        updateStubSystemAppsList(mStubSystemApps);
        mInstallPackageHelper.prepareSystemPackageCleanUp(packageSettings,
                mPossiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
    }

    logSystemAppsScanningTime(startTime);// 使用开始时间startTime记录系统应用扫描的时间,并打印日志。
    return overlayConfig; // 返回OverlayConfig实例。
}

上面的 initSystemApps 方法的参数定义如下:
PackageParser2 packageParser 用于解析APK文件,
WatchedArrayMap<String, PackageSetting> packageSettings 存储应用的设置信息, int[] userIds 是用户ID数组,long startTime记录方法开始执行的时间,用于后续计算执行时间。
上面的代码调用 scanSystemDirs 扫描系统目录中的APK文件。

/**
 * First part of init dir scanning
 */
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"}) // @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})注解表明,这个方法在执行时必须持有mPm.mInstallLock和mPm.mLock这两个锁的至少一个,以确保线程安全和数据一致性。
private void scanSystemDirs(PackageParser2 packageParser, ExecutorService executorService) { // 参数:PackageParser2实例用于解析APK文件,ExecutorService用于异步执行任务。
	 // 创建了一个指向系统框架目录的File对象。
    File frameworkDir = new File(Environment.getRootDirectory(), "framework");

    // Collect vendor/product/system_ext overlay packages. (Do this before scanning
    // any apps.)
    // For security and version matching reason, only consider overlay packages if they
    // reside in the right directory.
	 // 循环(从mDirsToScanAsSystem列表的末尾开始)处理的是被视为系统级的覆盖包(overlay packages),这些包可能来自vendor、product或system_ext分区。这些覆盖包在扫描任何应用之前被处理,以确保安全性和版本匹配。
    for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
        final ScanPartition partition = mDirsToScanAsSystem.get(i);
        if (partition.getOverlayFolder() == null) {
            continue;
        }
        scanDirTracedLI(partition.getOverlayFolder(), /* frameworkSplits= */ null,
                mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
                packageParser, executorService);
    }

	 // 使用 scanDirTracedLI 方法扫描框架目录,特别指定了SCAN_NO_DEX和SCAN_AS_PRIVILEGED标志,意味着这些APK不包含DEX文件(可能已经被预先优化),并且被视为特权应用。
    scanDirTracedLI(frameworkDir, null,
            mSystemParseFlags,
            mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED,
            packageParser, executorService);
	 // 如果系统包管理器(mPm)的mPackages映射中不包含键为"android"的条目,则抛出IllegalStateException异常。这确保了Android框架包被成功加载。
    if (!mPm.mPackages.containsKey("android")) {
        throw new IllegalStateException(
                "Failed to load frameworks package; check log for warnings");
    }

	 // 再次遍历 mDirsToScanAsSystem 列表,这次处理的是私有应用目录和普通应用目录。对于私有应用目录,使用SCAN_AS_PRIVILEGED标志;对于所有目录,都应用了分区特定的扫描标志。
    for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
        final ScanPartition partition = mDirsToScanAsSystem.get(i);
        if (partition.getPrivAppFolder() != null) {
            scanDirTracedLI(partition.getPrivAppFolder(), /* frameworkSplits= */ null,
                    mSystemParseFlags,
                    mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag,
                    packageParser, executorService);
        }
        scanDirTracedLI(partition.getAppFolder(), /* frameworkSplits= */ null,
                mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
                packageParser, executorService);
    }
}

上面的函数 scanSystemDirs 扫描系统目录以加载和解析系统级别的APK(Android应用程序包)。
这个方法是在Android的包管理器(PackageManager)的上下文中执行的,用于在系统启动时或特定情况下加载和验证系统应用。 scanSystemDirs方法是Android系统启动过程中的一个关键步骤,负责加载和解析系统级别的APK,包括框架包、覆盖包、私有应用和普通应用。
上面的代码中调用了 scanDirTracedLI 函数扫描框架目录。

private final InstallPackageHelper mInstallPackageHelper; // mInstallPackageHelper 通过 InitAppsHelper 构造函数通过传入的参数进行赋值。

@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
private void scanDirTracedLI(File scanDir, List<File> frameworkSplits,
        int parseFlags, int scanFlags,
        PackageParser2 packageParser, ExecutorService executorService) {
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
    try {
		 // 如果scanFlags中包含SCAN_AS_APK_IN_APEX标志(表示正在扫描位于APEX模块中的APK文件),则将PARSE_APK_IN_APEX标志添加到parseFlags中。这是为了在处理APEX模块中的APK文件时,能够检查其maxSdkVersion属性。
        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方法,它是实际执行APK文件安装和解析的地方。该方法接收扫描目录、框架拆分文件列表、解析标志、扫描标志、PackageParser2实例和ExecutorService作为参数。
        mInstallPackageHelper.installPackagesFromDir(scanDir, frameworkSplits, parseFlags,
                scanFlags, packageParser, executorService);
                
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}

上面的函数 scanDirTracedLI 扫描指定的目录(scanDir),以加载和解析其中的APK(Android应用程序包)文件,它通过适当的锁机制确保线程安全,使用性能追踪帮助开发者优化系统性能,并支持对APEX模块中APK文件的特殊处理。
上面的函数 scanDirTracedLI 中通过 mInstallPackageHelper 调用 installPackagesFromDir 函数。

5,在frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java中

@GuardedBy({"mPm.mInstallLock", "mPm.mLock"}) // 注解表明,在调用此方法时,必须持有mPm.mInstallLock或mPm.mLock这两个锁之一,以确保线程安全。
public void installPackagesFromDir(File scanDir, List<File> frameworkSplits, int parseFlags,
        int scanFlags, PackageParser2 packageParser,
        ExecutorService executorService) {
	  // 获取指定目录下的所有文件和子目录。
    final File[] files = scanDir.listFiles();
    if (ArrayUtils.isEmpty(files)) {
        Log.d(TAG, "No files in app dir " + scanDir);
        return;
    }

    if (DEBUG_PACKAGE_SCANNING) {
        Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags
                + " flags=0x" + Integer.toHexString(parseFlags));
    }
	  // 创建一个ParallelPackageParser实例,用于并行解析APK文件。该实例接收PackageParser2、ExecutorService和框架拆分文件列表作为参数。
    ParallelPackageParser parallelPackageParser =
            new ParallelPackageParser(packageParser, executorService, frameworkSplits);

    // 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;
        }
		  // 如果满足条件,并且设置了SCAN_DROP_CACHE标志,则删除该文件的缓存结果。
        if ((scanFlags & SCAN_DROP_CACHE) != 0) {
            final PackageCacher cacher = new PackageCacher(mPm.getCacheDir());
            Log.w(TAG, "Dropping cache of " + file.getAbsolutePath());
            cacher.cleanCachedResult(file);
        }
		// 将文件提交给ParallelPackageParser进行解析。
        parallelPackageParser.submit(file, parseFlags);
		
        fileCount++;
    }
	
	// Process results one by one
    for (; fileCount > 0; fileCount--) { // 使用循环从ParallelPackageParser中获取解析结果。
        ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
        Throwable throwable = parseResult.throwable;
        int errorCode = PackageManager.INSTALL_SUCCEEDED;
        String errorMsg = null;
    
        if (throwable == null) { // 如果解析成功(没有抛出异常)
            // TODO(b/194319951): move lower in the scan chain
            // Static shared libraries have synthetic package names
            if (parseResult.parsedPackage.isStaticSharedLibrary()) { // 检查解析的包是否为静态共享库,并相应地重命名。
                PackageManagerService.renameStaticSharedLibraryPackage(
                        parseResult.parsedPackage);
            }
            try {
                addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
                        null);
            } catch (PackageManagerException e) {
                errorCode = e.error;
                errorMsg = "Failed to scan " + parseResult.scanFile + ": " + e.getMessage();
                Slog.w(TAG, errorMsg);
            }
        } else if (throwable instanceof PackageManagerException) { // 如果解析过程中抛出了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);
        }
    
    	  // 如果设置了SCAN_AS_APK_IN_APEX标志,并且解析失败,则向APEX管理器报告错误。
        if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0 && errorCode != INSTALL_SUCCEEDED) {
            mApexManager.reportErrorWithApkInApex(scanDir.getAbsolutePath(), errorMsg);
        }
		// Delete invalid userdata apps
        // 如果没有设置SCAN_AS_SYSTEM标志,并且解析失败,则记录警告日志,并删除无效的应用代码路径。
        if ((scanFlags & SCAN_AS_SYSTEM) == 0
                && errorCode != PackageManager.INSTALL_SUCCEEDED) {
            logCriticalInfo(Log.WARN,
                    "Deleting invalid package at " + parseResult.scanFile);
            mRemovePackageHelper.removeCodePathLI(parseResult.scanFile);
        }
	}
}

上面的函数 installPackagesFromDir 从指定的目录(scanDir)中安装和解析APK文件,是Android系统包管理器服务中用于从指定目录中安装和解析APK文件的关键方法。 它通过并行解析提高了效率,并通过适当的锁机制确保了线程安全。同时,它还支持对APEX模块中APK文件的特殊处理,并能够删除无效的用户数据应用。
上面的代码中通过 ParallelPackageParser 的 submit 提交安装任务,take获取任务结果。

6,在frameworks/base/services/core/java/com/android/server/pm/ParallelPackageParser.java中

public void submit(File scanFile, int parseFlags) {
	 // 使用mExecutorService.submit()方法提交一个任务到线程池mExecutorService中执行。mExecutorService是一个执行服务的实例,用于管理线程池。
    mExecutorService.submit(() -> {
		 // 在提交的任务中,首先创建一个ParseResult实例pr,用于存储解析结果。
        ParseResult pr = new ParseResult();
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" + scanFile + "]");
        try {
            pr.scanFile = scanFile;
			
		// 调用 parsePackage(scanFile, parseFlags)方法解析文件,将解析结果赋值给pr.parsedPackage。
            pr.parsedPackage = parsePackage(scanFile, parseFlags);
			
        } catch (Throwable e) {
            pr.throwable = e;
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
        try {
			 // 将解析结果pr放入mQueue队列中。mQueue可能是一个用于存储解析结果的阻塞队列。
            mQueue.put(pr);
        } catch (InterruptedException e) {
		// 如果在将结果放入队列时线程被中断(InterruptedException),则重新设置当前线程的中断状态(Thread.currentThread().interrupt()),并记录被中断的线程名称到mInterruptedInThread变量中。
		// 这一步骤是为了确保如果主线程在等待解析完成时被中断,它不会无限期地等待下去。
            Thread.currentThread().interrupt();
            // Propagate result to callers of take().
            // This is helpful to prevent main thread from getting stuck waiting on
            // ParallelPackageParser to finish in case of interruption
            mInterruptedInThread = Thread.currentThread().getName();
        }
    });
}

上面的 submit 函数代码在后台线程中异步解析一个文件,并将解析结果放入一个队列中,以便后续处理。如果在解析或结果放入队列的过程中发生异常或线程被中断,它也有相应的处理逻辑来确保系统的稳定性和响应性。
下面看下 take 函数。

public ParseResult take() {
    try {
		// 检查mInterruptedInThread变量是否为null。如果mInterruptedInThread不为null,说明之前在某个线程中解析文件并放入队列mQueue的过程中,该线程被中断了,并且中断的线程名称被记录在了mInterruptedInThread中。
		// 此时,方法会抛出一个InterruptedException,并附带一个消息,指出在哪个线程中发生了中断。
        if (mInterruptedInThread != null) {
            throw new InterruptedException("Interrupted in " + mInterruptedInThread);
        }
		// 如果mInterruptedInThread为null,则继续执行,从mQueue队列中取出一个ParseResult对象并返回。这里使用了mQueue.take()方法,该方法会阻塞当前线程,直到队列中有元素可取。
        return mQueue.take();
    } catch (InterruptedException e) {
        // We cannot recover from interrupt here
		// 如果在从队列取元素的过程中当前线程被中断(InterruptedException),则捕获这个异常。
		// 在catch块中,首先重新设置当前线程的中断状态(Thread.currentThread().interrupt()),因为Java中的中断状态在抛出InterruptedException后会被清除。
		// 然后,抛出一个新的IllegalStateException,并将原始的InterruptedException作为原因传递给它。这里的注释// We cannot recover from interrupt here表明,在这个方法内部,从中断中恢复是不可能的,因此选择抛出异常来处理这种情况。
         Thread.currentThread().interrupt();
         throw new IllegalStateException(e);
     }
}

上面的 take 函数代码用于从某个阻塞队列mQueue中获取一个ParseResult对象。这个take方法的设计表明,它期望在调用之前或调用过程中,没有其他线程会修改mInterruptedInThread变量的值(除非是通过中断机制)。 此外,由于InterruptedException是一个受检异常(checked exception),调用take方法的代码需要处理这个异常,或者声明它自己的方法也抛出这个异常。 在实际应用中,这种设计可能用于确保在并发环境下,当某个操作被中断时,能够及时地通知调用者,并且调用者可以根据中断信息做出适当的响应,比如重试操作、放弃操作或者进行其他清理工作。

上面的 submit 和 take 是通过一个 BlockingQueue 实现解析和获取任务,解析是 parsePackage 函数实现的。

private final PackageParser2 mPackageParser; // 在 ParallelPackageParser 构造函数中被传入的参数赋值

@VisibleForTesting
protected ParsedPackage parsePackage(File scanFile, int parseFlags)
        throws PackageManagerException {
    return mPackageParser.parsePackage(scanFile, parseFlags, true, mFrameworkSplits);
}

上面的代码通过 PackageParser2 类对象 mPackageParser 调用 parsePackage 函数。

7,在frameworks/base/services/core/java/com/java/com/android/server/pm/parsing/PackageParser2.java中

private ParsingPackageUtils parsingUtils; // 在该类的构造函数中通过new创建新对象,即 parsingUtils = new ParsingPackageUtils(onlyCoreApps, separateProcesses, displayMetrics,splitPermissions, callback); 

@AnyThread // @AnyThread表明这个方法可以在任何线程上调用,即它不是线程受限的。
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches,
        List<File> frameworkSplits) throws PackageManagerException {
	 // 如果useCaches为true且mCacher不为null,则尝试从缓存中获取解析结果。如果找到了缓存的结果,则直接返回它。
    if (useCaches && mCacher != null) {
        ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags);
        if (parsed != null) {
            return parsed;
        }
    }

	 // 如果启用了日志记录(LOG_PARSE_TIMINGS为true),则记录解析开始的时间。
    long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
	 // 获取一个ParseInput对象,并重置它
    ParseInput input = mSharedResult.get().reset();
	
	 // 调用parsingUtils.parsePackage方法来解析包文件。这个方法返回一个ParseResult<ParsingPackage>对象,其中包含了解析的结果或错误信息。
    ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags,
            frameworkSplits);
			
	 // 如果解析结果表示发生了错误(result.isError()为true),则抛出一个PackageManagerException异常,包含错误代码、错误消息和异常对象。
    if (result.isError()) {
        throw new PackageManagerException(result.getErrorCode(), result.getErrorMessage(),
                result.getException());
    }

	 // 从解析结果中获取ParsedPackage对象。
    ParsedPackage parsed = (ParsedPackage) result.getResult().hideAsParsed();

    long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
	 // 如果启用了缓存且mCacher不为null,则将解析结果缓存起来。
    if (mCacher != null) {
        mCacher.cacheResult(packageFile, flags, parsed);
    }
	 // 如果启用了日志记录,则计算解析和缓存更新的时间,并根据设定的阈值(LOG_PARSE_TIMINGS_THRESHOLD_MS)决定是否打印日志信息。
    if (LOG_PARSE_TIMINGS) {
        parseTime = cacheTime - parseTime;
        cacheTime = SystemClock.uptimeMillis() - cacheTime;
        if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {
            Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime
                    + "ms, update_cache=" + cacheTime + " ms");
        }
    }
	 // 返回解析得到的ParsedPackage对象。
    return parsed;
}

上面的代码中调用 parsingUtils.parsePackage 函数,parsingUtils 是 ParsingPackageUtils 类对象。

8,在frameworks/base/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java中

public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile, int flags,
        List<File> frameworkSplits) {
    if (((flags & PARSE_FRAMEWORK_RES_SPLITS) != 0)
            && frameworkSplits.size() > 0
            && packageFile.getAbsolutePath().endsWith("/framework-res.apk")) {
        return parseClusterPackage(input, packageFile, frameworkSplits, flags);
    } else if (packageFile.isDirectory()) {
        return parseClusterPackage(input, packageFile, /* frameworkSplits= */null, flags);
    } else {
        return parseMonolithicPackage(input, packageFile, flags);
    }
}

上面的代码中,函数 parsePackage 接收四个参数:
一个ParseInput对象input用于存储解析过程中需要的数据,一个File对象packageFile指向要解析的包文件或目录,一个整数flags用于提供解析时的选项或标志,以及一个List对象frameworkSplits包含框架资源分割文件的列表。
在if条件中,如果flags中包含了PARSE_FRAMEWORK_RES_SPLITS标志,且frameworkSplits列表不为空,并且packageFile的路径以/framework-res.apk结尾,那么调用parseClusterPackage方法来解析一个包含框架资源分割的包。
在else if 条件中,如果packageFile是一个目录(而不是文件),则也调用parseClusterPackage方法来解析,但此时不传入框架资源分割文件列表(传入null)。
如果上述条件都不满足,那么调用parseMonolithicPackage方法来解析一个单体包(即,不是包含框架资源分割的包,也不是一个目录)。 是一个单独的一个apk就使用 parseMonolithicPackage 进行解析。
下面看下 parseMonolithicPackage 函数。

private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
        int flags) {
    final ParseResult<PackageLite> liteResult =
            ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, flags); // 先通过parseMonolithicPackageLite初步解析这个apk,会解析出minSdkVersion,versionCode等基本信息。
    if (liteResult.isError()) {
        return input.error(liteResult);
    }

    final PackageLite lite = liteResult.getResult();
	 // 如果mOnlyCoreApps标志为true且APK不是核心应用(lite.isCoreApp()返回false),则返回一个包含错误信息的ParseResult<ParsingPackage>对象,错误信息指出只允许核心应用。
    if (mOnlyCoreApps && !lite.isCoreApp()) {
        return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
                "Not a coreApp: " + apkFile);
    }

	 // 创建一个SplitAssetLoader对象,用于加载APK中的资源。这里使用的是DefaultSplitAssetLoader实现,并传入了PackageLite对象和解析标志。
    final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
    try {
		 // 调用parseBaseApk方法解析APK文件,该方法接收ParseInput、APK文件、APK文件的规范路径、资源加载器和解析标志作为参数,并返回一个ParseResult<ParsingPackage>对象。
        final ParseResult<ParsingPackage> result = parseBaseApk(input,
                apkFile,
                apkFile.getCanonicalPath(),
                assetLoader, flags);
		 // 如果解析过程中发生错误,则使用input.error(result)方法返回一个包含错误信息的ParseResult<ParsingPackage>对象。
        if (result.isError()) {
            return input.error(result);
        }

		 // 如果解析成功,则使用input.success(result.getResult().setUse32BitAbi(lite.isUse32bitAbi()))方法返回一个包含解析成功的ParsingPackage对象的ParseResult<ParsingPackage>对象,并设置32位ABI的使用情况。
        return input.success(result.getResult()
                .setUse32BitAbi(lite.isUse32bitAbi()));
    } catch (IOException e) {
        return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                "Failed to get path: " + apkFile, e);
    } finally {
        IoUtils.closeQuietly(assetLoader);
    }
}

上面的代码中先通过 parseMonolithicPackageLite 初步解析这个apk,得到PackageLite,然后调用 parseBaseApk 进一步解析apk.
首先分析下 parseMonolithicPackageLite 函数。

9,在frameworks/base/core/java/android/content/pm/parsing/ApkLiteParseUtils.java中

/**
 * Parse lightweight details about a single APK files.
 */
public static ParseResult<PackageLite> parseMonolithicPackageLite(ParseInput input,
        File packageFile, int flags) {
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
    try {
		 // 调用parseApkLite方法解析APK文件,该方法返回一个ParseResult<ApkLite>对象。ApkLite是一个包含APK基本信息(如路径、目标SDK版本等)的简化对象。
        final ParseResult<ApkLite> result = parseApkLite(input, packageFile, flags);
		 // 检查parseApkLite方法的返回结果是否为错误。如果是,使用input.error(result)方法将错误信息封装在ParseResult<PackageLite>对象中并返回。
        if (result.isError()) {
            return input.error(result);
        }

        final ApkLite baseApk = result.getResult(); // 获取ApkLite对象
        final String packagePath = packageFile.getAbsolutePath(); // 获取APK文件的绝对路径。
		 // 使用input.success方法返回一个包含成功解析结果的ParseResult<PackageLite>对象。
		 // 这个PackageLite对象通过构造器初始化,包含了APK文件的路径、ApkLite对象的路径、ApkLite对象本身,以及一些关于APK分割(splits)的信息(这里全部为null,表示这是一个整体APK,没有分割)。此外,还包含了目标SDK版本。
        return input.success(
                new PackageLite(packagePath, baseApk.getPath(), baseApk, null /* splitNames */,
                        null /* isFeatureSplits */, null /* usesSplitNames */,
                        null /* configForSplit */, null /* splitApkPaths */,
                        null /* splitRevisionCodes */, baseApk.getTargetSdkVersion(),
                        null /* requiredSplitTypes */, null /* splitTypes */));
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}

上面的代码中,静态方法 parseMonolithicPackageLite 它接受三个参数:
ParseInput input(解析输入),File packageFile(APK文件),和int flags(解析标志)。
该方法返回一个ParseResult类型的对象,这个对象包含了解析结果,可能是成功的结果(PackageLite对象)或错误信息。 整体而言,上面的函数解析一个整体的APK文件,并将其基本信息封装在一个PackageLite对象中返回。如果解析过程中出现错误,将返回错误信息。此外,代码还包含了性能追踪的逻辑,帮助开发者监控方法的执行效率。
下面分析下 parseBaseApk 函数。

10,在frameworks/base/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java中

private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
        String codePath, SplitAssetLoader assetLoader, int flags) {
	 // 通过apkFile.getAbsolutePath()获取APK文件的绝对路径。
    final String apkPath = apkFile.getAbsolutePath();

    String volumeUuid = null;
	 // 检查是否位于扩展存储:如果APK路径以MNT_EXPAND(一个表示扩展存储挂载点的常量)开头,则提取并保存卷UUID。
	 // MNT_EXPAND 是一个常量,即 public static final String MNT_EXPAND = "/mnt/expand/";
    if (apkPath.startsWith(MNT_EXPAND)) {
        final int end = apkPath.indexOf('/', MNT_EXPAND.length());
        volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
    }

    if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);

    final AssetManager assets;
    try {
		 // 从assetLoader获取基础资源管理器。如果失败,则根据异常类型返回相应的错误码和错误信息。
        assets = assetLoader.getBaseAssetManager();
    } catch (IllegalArgumentException e) {
        return input.error(e.getCause() instanceof IOException ? INSTALL_FAILED_INVALID_APK
                : INSTALL_PARSE_FAILED_NOT_APK, e.getMessage(), e);
    }
	 // 使用资源管理器查找APK路径对应的cookie。如果未找到,则返回解析失败错误。
    final int cookie = assets.findCookieForPath(apkPath);
    if (cookie == 0) {
        return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                "Failed adding asset path: " + apkPath);
    }

	 // 使用找到的cookie打开APK中的AndroidManifest.xml文件,并创建一个资源对象用于解析。
	 // ANDROID_MANIFEST_FILENAME 是一个常量,即 public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
    try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
            ANDROID_MANIFEST_FILENAME)) {
        final Resources res = new Resources(assets, mDisplayMetrics, null);

		 // 调用重载函数 parseBaseApk 解析APK文件,包括其manifest文件和其他资源。
        ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
                parser, flags);
		 // 如果解析结果包含错误,则返回错误信息和错误位置。
        if (result.isError()) {
            return input.error(result.getErrorCode(),
                    apkPath + " (at " + parser.getPositionDescription() + "): "
                            + result.getErrorMessage());
        }
		
		final ParsingPackage pkg = result.getResult();
		
        if (assets.containsAllocatedTable()) {
            final ParseResult<?> deferResult = input.deferError(
                    "Targeting R+ (version " + Build.VERSION_CODES.R + " and above) requires"
                            + " the resources.arsc of installed APKs to be stored uncompressed"
                            + " and aligned on a 4-byte boundary",
                    DeferredError.RESOURCES_ARSC_COMPRESSED);
            if (deferResult.isError()) {
                return input.error(INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED,
                        deferResult.getErrorMessage());
            }
        }
        
        // 从assetLoader获取APK资源对象,并检查是否定义了可覆盖的资源。
        ApkAssets apkAssets = assetLoader.getBaseApkAssets();
        boolean definesOverlayable = false;
        try {
            definesOverlayable = apkAssets.definesOverlayable();
        } catch (IOException ignored) {
            // Will fail if there's no packages in the ApkAssets, which can be treated as false
        }
        
        // 如果APK定义了可覆盖的资源,则遍历所有包名和对应的可覆盖资源映射,将这些信息添加到解析的包对象中。
        if (definesOverlayable) {
            SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers();
            int size = packageNames.size();
            for (int index = 0; index < size; index++) {
                String packageName = packageNames.valueAt(index);
                Map<String, String> overlayableToActor = assets.getOverlayableMap(packageName);
                if (overlayableToActor != null && !overlayableToActor.isEmpty()) {
                    for (String overlayable : overlayableToActor.keySet()) {
                        pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable));
                    }
                }
            }
        }
        
        pkg.setVolumeUuid(volumeUuid);
        
        // 如果指定了收集证书信息的标志位,则尝试获取签名详细信息。如果失败,则返回错误。
        if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
            final ParseResult<SigningDetails> ret =
                    getSigningDetails(input, pkg, false /*skipVerify*/);
            if (ret.isError()) {
                return input.error(ret);
            }
            pkg.setSigningDetails(ret.getResult());
        } else {
            pkg.setSigningDetails(SigningDetails.UNKNOWN);
        }
		// 返回包含解析后的包对象的成功结果
		return input.success(pkg);
	} catch (Exception e) {
        return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                "Failed to read manifest from " + apkPath, e);
    }
}

上面的函数代码用于解析APK文件的基础信息,是Android应用安装过程中解析APK文件的关键部分,它负责读取APK的manifest文件和其他资源,并构建一个ParsingPackage对象,该对象包含了应用的基本信息和资源。
上面的函数 parseBaseApk 调用另一个重载的 parseBaseApk 函数。

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

	 // 调用ApkLiteParseUtils.parsePackageSplitNames 方法解析APK的分割名称和包名。如果解析出错,则通过input.error方法返回错误结果。
    ParseResult<Pair<String, String>> packageSplitResult =
            ApkLiteParseUtils.parsePackageSplitNames(input, parser);
    if (packageSplitResult.isError()) {
        return input.error(packageSplitResult);
    }

	 // 从解析结果中获取包名和分割名称。
    Pair<String, String> packageSplit = packageSplitResult.getResult();
    pkgName = packageSplit.first;
    splitName = packageSplit.second;

	 // 检查分割名称是否不为空。如果是,说明期望的是一个基础APK,但找到的是一个分割APK,因此通过input.error方法返回错误结果,错误码为INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME。
    if (!TextUtils.isEmpty(splitName)) {
        return input.error(
                PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
                "Expected base APK, but found split " + splitName
        );
    }

	 // 通过资源对象res和解析器parser获取AndroidManifest.xml文件中定义的属性数组TypedArray。
    final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
    try {
		 // 从AndroidManifest.xml中读取coreApp属性,该属性标记应用是否为系统核心应用。
        final boolean isCoreApp = parser.getAttributeBooleanValue(null /*namespace*/,
                "coreApp",false);
				
		 // 调用回调方法mCallback.startParsingPackage 开始解析包,该方法接收包名、APK路径、代码路径、属性数组和是否为核心应用等参数,返回一个ParsingPackage对象。
        final ParsingPackage pkg = mCallback.startParsingPackage(
                pkgName, apkPath, codePath, manifestArray, isCoreApp);
				
		 // 调用parseBaseApkTags方法继续解析APK的基本标签,如应用权限、组件声明等。如果解析出错,则返回错误结果。
        final ParseResult<ParsingPackage> result =
                parseBaseApkTags(input, pkg, manifestArray, res, parser, flags);
        if (result.isError()) {
            return result;
        }

		 // 如果解析成功,则通过input.success方法返回成功结果,包含解析后的ParsingPackage对象。
        return input.success(pkg);
    } finally {
        manifestArray.recycle();
    }
}

上面的代码函数 parseBaseApk 负责解析一个APK文件的基础信息,包括包名、是否为分割APK、是否为系统核心应用等,并继续解析APK中的基本标签。如果在解析过程中遇到任何错误,会返回相应的错误结果。
上面的函数调用了 parseBaseApkTags 函数进一步解析AndroidManifest中的各个标签。

private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg,
        TypedArray sa, Resources res, XmlResourceParser parser, int flags)
        throws XmlPullParserException, IOException {
	 // 调用parseSharedUser方法解析<manifest>标签中的<shared-user>子标签。如果解析出错,则直接返回错误结果。
    ParseResult<ParsingPackage> sharedUserResult = parseSharedUser(input, pkg, sa);
    if (sharedUserResult.isError()) {
        return sharedUserResult;
    }

	 // 从TypedArray sa中读取并设置APK包的安装位置、目标沙箱版本,以及是否支持外部存储等属性。
	 // PARSE_DEFAULT_INSTALL_LOCATION是一个整型常量,即 public static final int PARSE_DEFAULT_INSTALL_LOCATION = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
    pkg.setInstallLocation(anInteger(PARSE_DEFAULT_INSTALL_LOCATION,
            R.styleable.AndroidManifest_installLocation, sa))
            .setTargetSandboxVersion(anInteger(PARSE_DEFAULT_TARGET_SANDBOX,
                    R.styleable.AndroidManifest_targetSandboxVersion, sa))
            /* Set the global "on SD card" flag */
            .setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0);

    boolean foundApp = false;
    final int depth = parser.getDepth();
    int type;
	 // 使用 XmlResourceParser parser遍历AndroidManifest.xml文档。在遍历过程中,忽略非START_TAG类型的节点,并对每个START_TAG节点进行处理。
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
            && (type != XmlPullParser.END_TAG
            || parser.getDepth() > depth)) {
        if (type != XmlPullParser.START_TAG) {
            continue;
        }

        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 标签
            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 { // 尚未处理过<application>标签,则调用 parseBaseApplication 方法解析<application>标签。
                foundApp = true;
                result = parseBaseApplication(input, pkg, res, parser, flags);
            }
        } else { // 对于非<application>标签,调用 parseBaseApkTag 方法进行处理。
            result = parseBaseApkTag(tagName, input, pkg, res, parser, flags);
        }

        if (result.isError()) {
            return input.error(result);
        }
    }
	
	if (!foundApp && ArrayUtils.size(pkg.getInstrumentations()) == 0) {
        ParseResult<?> deferResult = input.deferError(
                "<manifest> does not contain an <application> or <instrumentation>",
                DeferredError.MISSING_APP_TAG);
        if (deferResult.isError()) {
            return input.error(deferResult);
        }
    }
    
    // 检查APK包中的<attribution>标签组合是否有效。如果无效,则报告错误。
    if (!ParsedAttributionUtils.isCombinationValid(pkg.getAttributions())) {
        return input.error(
                INSTALL_PARSE_FAILED_BAD_MANIFEST,
                "Combination <attribution> tags are not valid"
        );
    }
    
    // 检查APK包中是否声明了重复的权限,但具有不同的属性值。如果是,则报告错误。
    if (ParsedPermissionUtils.declareDuplicatePermission(pkg)) {
        return input.error(
                INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                "Found duplicate permission with a different attribute value."
        );
    }
    
    // 调用convertCompatPermissions和convertSplitPermissions方法处理权限的兼容性转换和分割权限的处理。
    convertCompatPermissions(pkg);
    
    convertSplitPermissions(pkg);
    
    // At this point we can check if an application is not supporting densities and hence
    // cannot be windowed / resized. Note that an SDK version of 0 is common for
    // pre-Doughnut applications.
    if (pkg.getTargetSdkVersion() < DONUT
            || (!pkg.isSupportsSmallScreens()
            && !pkg.isSupportsNormalScreens()
            && !pkg.isSupportsLargeScreens()
            && !pkg.isSupportsExtraLargeScreens()
            && !pkg.isResizeable()
            && !pkg.isAnyDensity())) {
        adjustPackageToBeUnresizeableAndUnpipable(pkg);
    }
    
    return input.success(pkg);
}

上面的代码中 parseBaseApkTags 接收一个ParseInput对象(用于报告解析过程中的错误和成功结果)、一个ParsingPackage对象(代表正在解析的APK包)、一个TypedArray对象(包含从AndroidManifest.xml中解析出的属性)、 一个Resources对象(用于访问资源)、一个XmlResourceParser对象(用于解析XML文档),以及一个int类型的flags(用于控制解析行为)。该方法可能抛出XmlPullParserException和IOException。
上面的函数代码中,如果是 application 标签,则调用 parseBaseApplication 函数,因为四大组件都在这个application标签下面。
下面分析下 parseBaseApplication 函数。

private ParseResult<ParsingPackage> parseBaseApplication(ParseInput input,
        ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
        throws XmlPullParserException, IOException {
    final String pkgName = pkg.getPackageName();
    int targetSdk = pkg.getTargetSdkVersion();

	  // 使用res.obtainAttributes(parser, R.styleable.AndroidManifestApplication)获取<application>标签的属性数组(TypedArray sa)。
    TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication);
    try {
        // TODO(b/135203078): Remove this and force unit tests to mock an empty manifest
        // This case can only happen in unit tests where we sometimes need to create fakes
        // of various package parser data structures.
        if (sa == null) { // 如果sa为空,表示<application>标签不包含任何属性,此时会返回一个错误信息。
            return input.error("<application> does not contain any attributes");
        }

		  // 从属性数组中获取应用名称(name)。
        String name = sa.getNonConfigurationString(R.styleable.AndroidManifestApplication_name,
                0);
        if (name != null) {
			  // 如果名称不为空,构建完整的类名(outInfoName),并检查这个名称是否有效。
            String packageName = pkg.getPackageName();
            String outInfoName = ParsingUtils.buildClassName(packageName, name);
            if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) {
                return input.error("<application> invalid android:name");
            } else if (outInfoName == null) {
                return input.error("Empty class name in package " + packageName);
            }
			  // 将解析出的类名设置到pkg对象中。
            pkg.setClassName(outInfoName);
        }
		
		// 从属性数组中获取标签(label)的值。
        TypedValue labelValue = sa.peekValue(R.styleable.AndroidManifestApplication_label);
        if (labelValue != null) {
            pkg.setLabelRes(labelValue.resourceId); // 如果标签值不为空,首先设置标签的资源ID(labelValue.resourceId)。
            if (labelValue.resourceId == 0) { // 如果资源ID为0(表示没有指定资源ID),则使用标签的字符串值(labelValue.coerceToString()),并标记为非本地化标签。
                pkg.setNonLocalizedLabel(labelValue.coerceToString());
            }
        }
        
        // 调用parseBaseAppBasicFlags(pkg, sa)方法,进一步解析<application>标签中的基本标志(如是否允许调试等)。
        parseBaseAppBasicFlags(pkg, sa);
        
        // 使用nonConfigString方法从属性数组sa中获取manageSpaceActivity的值。
        String manageSpaceActivity = nonConfigString(Configuration.NATIVE_CONFIG_VERSION,
                R.styleable.AndroidManifestApplication_manageSpaceActivity, sa);
        // 如果manageSpaceActivity不为空,使用ParsingUtils.buildClassName方法结合包名pkgName和manageSpaceActivity的值来构建完整的类名manageSpaceActivityName。
        if (manageSpaceActivity != null) {
            String manageSpaceActivityName = ParsingUtils.buildClassName(pkgName,
                    manageSpaceActivity);
        
            if (manageSpaceActivityName == null) { // 如果构建的类名为空,则返回一个错误信息,指出包名中缺少类名。
                return input.error("Empty class name in package " + pkgName);
            }
        
          // 如果类名有效,将其设置到pkg对象的manageSpaceActivityName属性中。
            pkg.setManageSpaceActivityName(manageSpaceActivityName);
        }
		
		// 使用ComponentParseUtils.buildProcessName方法构建应用的进程名称。
        // 这个方法接受多个参数,包括包名pkgName、一个可能为空的默认进程名defProc(在这里传入null)、应用名pname、一些标志位flags、一个表示是否分离进程的布尔值mSeparateProcesses,以及解析输入input。
        ParseResult<String> processNameResult = ComponentParseUtils.buildProcessName(
                pkgName, null /*defProc*/, pname, flags, mSeparateProcesses, input);
        if (processNameResult.isError()) {
            return input.error(processNameResult);
        }
        
        // 调用processNameResult.getResult()获取进程名称。
        String processName = processNameResult.getResult();
        // 将获取到的进程名称设置到pkg对象的processName属性中。
        pkg.setProcessName(processName);
        
        if (pkg.isCantSaveState()) {
            // A heavy-weight application can not be in a custom process.
            // We can do direct compare because we intern all strings.
            if (processName != null && !processName.equals(pkgName)) {
                return input.error(
                        "cantSaveState applications can not use custom processes");
            }
        }
        
        String classLoaderName = pkg.getClassLoaderName();
        if (classLoaderName != null
                && !ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
            return input.error("Invalid class loader name: " + classLoaderName);
        }
		} finally {
		    sa.recycle();
		}
		
		boolean hasActivityOrder = false;
        boolean hasReceiverOrder = false;
        boolean hasServiceOrder = false;
        final int depth = parser.getDepth();
        int type;
        // 使用XmlPullParser解析AndroidManifest.xml文件。循环遍历XML文档,直到到达文档末尾或当前标签的深度小于初始深度(表示已经退出了<manifest>标签)。
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG
                || parser.getDepth() > depth)) {
            if (type != XmlPullParser.START_TAG) {
                continue;
            }
        
            final ParseResult result;
            String tagName = parser.getName();
            boolean isActivity = false;
          // 对于每个开始标签(START_TAG),根据标签名(tagName)执行不同的操作。
            switch (tagName) {
        	  // 当遇到<activity>标签时,解析为ParsedActivity对象,并根据isActivity标志将其添加到活动的列表或接收器的列表中
        	  // (注意,由于代码中的fall-through,<activity>标签实际上也会进入<receiver>的代码块,但isActivity会被设置为true,因此它会被正确地添加到活动的列表中)。
                case "activity":
                    isActivity = true;
                    // fall-through
        	  // 当遇到<receiver>标签时(由于fall-through,这里也处理<activity>之后的情况),解析为ParsedActivity对象(这里使用相同的解析器是因为接收器和活动在AndroidManifest.xml中有许多共同的属性),但将其添加到接收器的列表中。
			  case "receiver":
                  ParseResult<ParsedActivity> activityResult =
                          ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg,
                                  res, parser, flags, sUseRoundIcon, null /*defaultSplitName*/,
                                  input);
              
                  if (activityResult.isSuccess()) {
                      ParsedActivity activity = activityResult.getResult();
                      if (isActivity) {
                          hasActivityOrder |= (activity.getOrder() != 0);
                          pkg.addActivity(activity);
                      } else {
                          hasReceiverOrder |= (activity.getOrder() != 0);
                          pkg.addReceiver(activity);
                      }
                  }
              
                  result = activityResult;
                  break;
              // 当遇到<service>标签时,解析为ParsedService对象,并添加到服务的列表中。
              case "service":
                  ParseResult<ParsedService> serviceResult =
                          ParsedServiceUtils.parseService(mSeparateProcesses, pkg, res, parser,
                                  flags, sUseRoundIcon, null /*defaultSplitName*/,
                                  input);
                  if (serviceResult.isSuccess()) {
                      ParsedService service = serviceResult.getResult();
                      hasServiceOrder |= (service.getOrder() != 0);
                      pkg.addService(service);
                  }
              
                  result = serviceResult;
                  break;
              // 当遇到<provider>标签时,解析为ParsedProvider对象,并添加到内容提供者的列表中。
			  case "provider":
                  ParseResult<ParsedProvider> providerResult =
                          ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser,
                                  flags, sUseRoundIcon, null /*defaultSplitName*/,
                                  input);
                  if (providerResult.isSuccess()) {
                      pkg.addProvider(providerResult.getResult());
                  }
              
                  result = providerResult;
                  break;
              // 当遇到<activity-alias>标签时,解析为ParsedActivity对象(因为活动别名在功能上类似于活动),并添加到活动的列表中。
              case "activity-alias":
                  activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res,
                          parser, sUseRoundIcon, null /*defaultSplitName*/,
                          input);
                  if (activityResult.isSuccess()) {
                      ParsedActivity activity = activityResult.getResult();
                      hasActivityOrder |= (activity.getOrder() != 0);
                      pkg.addActivity(activity);
                  }
              
                  result = activityResult;
                  break;
              // 当遇到<apex-system-service>标签时,解析为ParsedApexSystemService对象,并添加到Apex系统服务的列表中。
              case "apex-system-service":
                  ParseResult<ParsedApexSystemService> systemServiceResult =
                          ParsedApexSystemServiceUtils.parseApexSystemService(res,
                                  parser, input);
                  if (systemServiceResult.isSuccess()) {
                      ParsedApexSystemService systemService =
                              systemServiceResult.getResult();
                      pkg.addApexSystemService(systemService);
                  }
              
                  result = systemServiceResult;
                  break;
			  default:
                  result = parseBaseAppChildTag(input, tagName, pkg, res, parser, flags);
                  break;
			}
			if (result.isError()) {
                return input.error(result);
            }
            // 如果应用包含的组件数量超过了最大限制(通过hasTooManyComponents(pkg)检查),则返回错误信息。
            if (hasTooManyComponents(pkg)) {
                return input.error(MAX_NUM_COMPONENTS_ERR_MSG);
            }
		} // 当XML文档解析完毕时,循环结束。此时,pkg对象已经包含了应用的所有组件信息。
		
		// 检查应用程序包的静态共享库名称和SDK库名称是否都为空
        if (TextUtils.isEmpty(pkg.getStaticSharedLibName()) && TextUtils.isEmpty(
                pkg.getSdkLibName())) {
            // Add a hidden app detail activity to normal apps which forwards user to App Details
            // page.
            ParseResult<ParsedActivity> a = generateAppDetailsHiddenActivity(input, pkg);
            if (a.isError()) {
                // Error should be impossible here, as the only failure case as of SDK R is a
                // string validation error on a constant ":app_details" string passed in by the
                // parsing code itself. For this reason, this is just a hard failure instead of
                // deferred.
                return input.error(a);
            }
        
            pkg.addActivity(a.getResult());
        }
        
        // 根据hasActivityOrder、hasReceiverOrder和hasServiceOrder的值,分别调用pkg.sortActivities()、pkg.sortReceivers()和pkg.sortServices()对活动、接收器和服务进行排序。
        if (hasActivityOrder) {
            pkg.sortActivities();
        }
        if (hasReceiverOrder) {
            pkg.sortReceivers();
        }
        if (hasServiceOrder) {
            pkg.sortServices();
        }
		// Must be run after the entire {@link ApplicationInfo} has been fully processed and after
        // every activity info has had a chance to set it from its attributes.
        setMaxAspectRatio(pkg);
        setMinAspectRatio(pkg);
        setSupportsSizeChanges(pkg);
        
        pkg.setHasDomainUrls(hasDomainURLs(pkg));
        
        return input.success(pkg);
	}

上面的代码解析标签,根据标签的不同调用不同的解析函数。

上面分析了InitAppHelper类中的 initSystemApps 函数,下面看下 initNonSystemApps 函数。

11,在frameworks/base/services/core/java/com/android/server/pm/InitAppsHelper.java中

@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
public void initNonSystemApps(PackageParser2 packageParser, @NonNull int[] userIds,
        long startTime) {
    if (!mIsOnlyCoreApps) { // 这行代码检查一个布尔变量mIsOnlyCoreApps。如果它的值为false(即不是仅核心应用),则执行大括号内的代码。
		 // 记录一个事件日志,表示开始扫描PMS(包管理器服务)数据。
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                SystemClock.uptimeMillis());
		 // 调用scanDirTracedLI方法来扫描应用安装目录。这个方法可能涉及到并发执行,因为它使用了mExecutorService。
        scanDirTracedLI(mPm.getAppInstallDir(), /* frameworkSplits= */ null, 0,
                mScanFlags | SCAN_REQUIRE_KNOWN,
                packageParser, mExecutorService);
    }

	 // 关闭执行服务mExecutorService,并返回等待执行的任务列表。
    List<Runnable> unfinishedTasks = mExecutorService.shutdownNow();
	 // 检查是否有未完成的任务
    if (!unfinishedTasks.isEmpty()) {
        throw new IllegalStateException("Not all tasks finished before calling close: "
                + unfinishedTasks);
    }
    if (!mIsOnlyCoreApps) {
	      // 调用fixSystemPackages方法来修复系统包。
        fixSystemPackages(userIds);
	      // 记录非系统应用扫描的耗时。
        logNonSystemAppScanningTime(startTime);
    }
    mExpectingBetter.clear();
	 // 调用pruneRenamedPackagesLPw方法来修剪重命名的包。
    mPm.mSettings.pruneRenamedPackagesLPw();
}

在上面的代码中,有一个 BOOT_PROGRESS_PMS_DATA_SCAN_START 的事件日志记录。

上面分析了BOOT_PROGRESS_PMS_SYSTEM_SCAN_START 和 BOOT_PROGRESS_PMS_DATA_SCAN_START,在PKMS的构造函数中比较复杂的部分已经分析过了,对于下面的 BOOT_PROGRESS_PMS_SCAN_END 和 BOOT_PROGRESS_PMS_READY 在第二步已做了基本分析。 至此,PKMS的构造函数的执行分析完毕。