PKMS(3)处理扫描结果并保存数据

PKMS(3)处理扫描结果并保存数据

Android小彩虹2021-07-19 13:37:41120A+A-

前面一篇文章,分析了APK的解析工作,它把解析的结果保存到了PackageParser.Package中,可谓是波澜不惊。

PKMS接下来会处理这个扫描结果,并把处理的结果保存到PKMS的数据结构中,这个过程可谓是惊涛骇浪,让我们直面它。

承接前文的代码如下

    private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
        final File[] files = scanDir.listFiles();
        if (ArrayUtils.isEmpty(files)) {
            Log.d(TAG, "No files in app dir " + scanDir);
            return;
        }

        try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
                mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
                mParallelPackageParserCallback)) {
            // 1. 提交解析APK任务
            int fileCount = 0;
            for (File file : files) {
                final boolean isPackage = (isApkFile(file) || file.isDirectory())
                        && !PackageInstallerService.isStageName(file.getName());
                if (!isPackage) {
                    continue;
                }
                parallelPackageParser.submit(file, parseFlags);
                fileCount++;
            }

            // 2. 处理扫描结果
            for (; fileCount > 0; fileCount--) {
                // 阻塞式地获取扫描的结果
                ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
                Throwable throwable = parseResult.throwable;
                int errorCode = PackageManager.INSTALL_SUCCEEDED;

                if (throwable == null) {
                    // 这个是针对<static-library>标签生成的静态库
                    // 针对静态库,包名要重要命名,格式为packageName_version
                    if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) {
                        renameStaticSharedLibraryPackage(parseResult.pkg);
                    }
                    try {
                        scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
                                currentTime, null);
                    } catch (PackageManagerException e) {
                        errorCode = e.error;
                        Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
                    }
                }// ...
            }
        }
    }

前面的文章分析了第一步,也就是扫描APK。扫描的结果保存到了BlockingQueue<ParseResult> mQueue中。

第二步,在主线程中,从这个 BlockingQueue 中阻塞式的获取结果,然后通过scanPackageChildLI()逐一处理结果并保存数据,让我们开始吧!

    private PackageParser.Package scanPackageChildLI(PackageParser.Package pkg, final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException {
        // scanFlags没有设置SCAN_CHECK_ONLY
        if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
            // 这个是针对<package>标签的,但是在user版本无效
            if (pkg.childPackages != null && pkg.childPackages.size() > 0) {
                scanFlags |= SCAN_CHECK_ONLY;
            }
        } else {
            scanFlags &= ~SCAN_CHECK_ONLY;
        }

        // Scan the parent
        PackageParser.Package scannedPkg = addForInitLI(pkg, parseFlags,
                scanFlags, currentTime, user);

        // Scan the children
        // user版本没有child package功能,因此这里不讨论
        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
        for (int i = 0; i < childCount; i++) {
            PackageParser.Package childPackage = pkg.childPackages.get(i);
            addForInitLI(childPackage, parseFlags, scanFlags,
                    currentTime, user);
        }

        // scanFlags没有设置SCAN_CHECK_ONLY
        if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
            return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
        }

        return scannedPkg;
    }

从整体看,这个函数主要关心的是child package功能,但是这个功能在user版本无效,具体细节可以参考第二篇文章中关于处理<package>标签的代码。

除了child package功能,接下来的任务都交给了 addForInitLI() 函数

一个函数只负责一个功能,这就是设计模式中的单一职责原则。可见,分析源码也是思考和学习的过程。

    private PackageParser.Package addForInitLI(PackageParser.Package pkg, @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException {
        // 以下这些变量都是关于系统升级的,不在本文的讨论范围
        final boolean scanSystemPartition = (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0;
        final String renamedPkgName;
        final PackageSetting disabledPkgSetting;
        final boolean isSystemPkgUpdated;
        final boolean pkgAlreadyExists;
        PackageSetting pkgSetting;

        pkg.setApplicationVolumeUuid(pkg.volumeUuid);
        pkg.setApplicationInfoCodePath(pkg.codePath);
        pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
        pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
        pkg.setApplicationInfoResourcePath(pkg.codePath);
        pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
        pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);

        synchronized (mPackages) {
            // .... 省略关于系统升级的代码

            // 这段代码隐藏在系统升级的代码中,但是它会影响后面的代码
            // 因为最后一个参数为true,它表示如果sharedUserId不是之前保存的共享用户的ID,那么会重新创建一个SharedUserSetting
            // 并且appId是从Process.FIRST_APPLICATION_UID开始。
            // 非系统app使用sharedUserId,通常是为了共享保存的数据,例如SharedPreference,或者一些保存的文件
            final SharedUserSetting sharedUserSetting = (pkg.mSharedUserId != null)
                    ? mSettings.getSharedUserLPw(pkg.mSharedUserId,
                            0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true)
                    : null;
            // ... 省略关于系统升级的代码 
        }

        final boolean newPkgChangedPaths =
                pkgAlreadyExists && !pkgSetting.codePathString.equals(pkg.codePath);
        final boolean newPkgVersionGreater =
                pkgAlreadyExists && pkg.getLongVersionCode() > pkgSetting.versionCode;
        final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated
                && newPkgChangedPaths && newPkgVersionGreater;
        if (isSystemPkgBetter) {
            // .... 省略关于手动安装app的代码
        }

        if (scanSystemPartition && isSystemPkgUpdated && !isSystemPkgBetter) {
            throw new PackageManagerException(Log.WARN, "Package " + pkg.packageName + " at "
                    + pkg.codePath + " ignored: updated version " + pkgSetting.versionCode
                    + " better than this " + pkg.getLongVersionCode());
        }


        // 验证签名,首次开机不需要,系统升级才需要
        final boolean forceCollect = (mIsUpgrade && scanSystemPartition)
                || PackageManagerServiceUtils.isApkVerificationForced(disabledPkgSetting);
        final boolean skipVerify = scanSystemPartition
                || (forceCollect && canSkipForcedPackageVerification(pkg));
        collectCertificatesLI(pkgSetting, pkg, forceCollect, skipVerify);

        // Reset profile if the application version is changed
        maybeClearProfilesForUpgradesLI(pkgSetting, pkg);

        boolean shouldHideSystemApp = false;
        if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists
                && !pkgSetting.isSystem()) {
            // ...
        }

        // 1. 再次扫描
        final ScanResult scanResult = scanPackageNewLI(pkg, parseFlags, scanFlags
                | SCAN_UPDATE_SIGNATURE, currentTime, user);
        if (scanResult.success) {
            synchronized (mPackages) {
                boolean appIdCreated = false;
                try {
                    final String pkgName = scanResult.pkgSetting.name;
                    // 2. 如果是安装APK,会重新调整扫描结果,并返回调整后的结果ReconciledPackage
                    final Map<String, ReconciledPackage> reconcileResult = reconcilePackagesLocked(
                            new ReconcileRequest(
                                    Collections.singletonMap(pkgName, scanResult),
                                    mSharedLibraries,
                                    mPackages,
                                    Collections.singletonMap(
                                            pkgName, getSettingsVersionForPackage(pkg)),
                                    Collections.singletonMap(pkgName,
                                            getSharedLibLatestVersionSetting(scanResult))),
                            mSettings.mKeySetManagerService);
                    // 用于检测appId是否已经创建
                    // appIdCreated的作用是,当扫描出现异常,清理这个appId
                    appIdCreated = optimisticallyRegisterAppId(scanResult);
                    // 3. 把数据提交到PKMS内部的数据结构中
                    commitReconciledScanResultLocked(reconcileResult.get(pkgName));
                } catch (PackageManagerException e) {
                    if (appIdCreated) {
                        cleanUpAppIdCreation(scanResult);
                    }
                    throw e;
                }
            }
        }

        // 关于系统升级的代码
        if (shouldHideSystemApp) {
            // ...
        }
        return scanResult.pkgSetting.pkg;
    }

除去了系统升级相关的代码,我把这个函数分为了三步。

首先第一步,对APK的解析结果进行再次扫描。再次扫描的目的其实是为了创建PackageSetting,其实它与PackageParser.Package类似,只不过它们保存的位置不同。

第二步,主要是与安装APK相关,并调整再次扫描的结果,但是我们无法跳过,因为第三步会把这次的调整结果进行提交到PKMS。

对结果再扫描

首先我来分析第二步,对结果的再扫描,调用的是scanPackageNewLI()函数

    private ScanResult scanPackageNewLI(@NonNull PackageParser.Package pkg, final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException {
        // 如下这段代码都是关于系统升级的,在首次开机时,值都为null
        final String renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
        final String realPkgName = getRealPackageName(pkg, renamedPkgName);
        if (realPkgName != null) {
            ensurePackageRenamed(pkg, renamedPkgName);
        }
        final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName);
        final PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.packageName);
        final PackageSetting disabledPkgSetting =
                mSettings.getDisabledSystemPkgLPr(pkg.packageName);


        // 1. 调整扫描的flag
        // 注意,参数pkgSetting, disabledPkgSetting在首次开机时,都为null
        scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, pkg);
        synchronized (mPackages) {
            // 2. 主要是根据扫描标记位,为pkg添加一些标记位
            // 例如扫描的系统APK,添加ApplicationInfo.FLAG_SYSTEM标记
            applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
            
            // 验证目前解析的信息是否正确
            assertPackageIsValid(pkg, parseFlags, scanFlags);

            // 获取SharedUserSetting
            SharedUserSetting sharedUserSetting = null;
            if (pkg.mSharedUserId != null) {
                // 注意最后一个参数为true,它表示如果指定的sharedUserId不存在,就创建新的SharedUserSetting
                // 其实,前面已经针对这种情况进行处理了,最后一个参数即使为false,也能正确获取到SharedUserSetting
                // 不得不说,源码针对sharedUserId的处理,好像并不是太好
                sharedUserSetting = mSettings.getSharedUserLPw(
                        pkg.mSharedUserId, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/);
            }
            
            // 注意,对于非系统升级,第三个参数到第七个参数都为null
            // 第十个参数表示是否为frameworks-res.apk
            final ScanRequest request = new ScanRequest(pkg, sharedUserSetting,
                    pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
                    originalPkgSetting, realPkgName, parseFlags, scanFlags,
                    (pkg == mPlatformPackage), user);

            // 3. 使用刚才创建的请求继续扫描
            return scanPackageOnlyLI(request, mFactoryTest, currentTime);
        }
    }

从整体看,这一步是封装了一个ScanRequest请求,然后继续扫描。不过,在继续扫描前,还有一些重要的事情要处理,如下

  1. 调用adjustScanFlags()对扫描标志位(scan flag)进行一些调整。
  2. 调用applyPolicy(),在PackageParser.Package.applicationInfo中保存一些标志位。
  3. 创建扫描请求ScanRequest,并调用scanPackageOnlyLI()来完成扫描工作。

调整扫描标记位

首先来看下adjustScanFlags()对扫描标志位的调整

    private @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags, PackageSetting pkgSetting, PackageSetting disabledPkgSetting, UserHandle user, PackageParser.Package pkg) {
        // 首次开机,值为null
        final PackageSetting systemPkgSetting =
                (scanFlags & SCAN_NEW_INSTALL) != 0 && disabledPkgSetting == null
                        && pkgSetting != null && pkgSetting.isSystem()
                        ? pkgSetting
                        : disabledPkgSetting;
        if (systemPkgSetting != null)  {
            // ...
        }
        if (pkgSetting != null) {
            // ...
        }

        // scanFlags & SCAN_AS_VENDOR) != 0 ,如果成立,表示扫描的是vendor分区和odm分区(并不包括odem分区)
        // 比较新的Android版本,ro.vndk.version属性值是大于28的,我的项目是29
        final boolean skipVendorPrivilegeScan = ((scanFlags & SCAN_AS_VENDOR) != 0)
                && SystemProperties.getInt("ro.vndk.version", 28) < 28; 
        if (((scanFlags & SCAN_AS_PRIVILEGED) == 0) // 不是 priv-app 目录下的系统app
                && !pkg.isPrivileged() // 不是特权app
                && (pkg.mSharedUserId != null) // 设置了sharedUserId
                && !skipVendorPrivilegeScan) { // skipVendorPrivilegeScan为false,表示不是vendor或odm分区下的app
            SharedUserSetting sharedUserSetting = null;
            try {
                // 获取共享用户的信息
                // 注意,前面已经针对非系统app使用sharedUserId创建了SharedUserSetting对象并保存了,所以在这里,
                // 即使最后一个参数为false,也能获取到正确的SharedUserSetting
                sharedUserSetting = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, false);
            } catch (PackageManagerException ignore) {}
            // 只有在PKMS构造函数中保存的共享用户,才是特权用户
            if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) {
                synchronized (mPackages) {
                    // 获取frameworks-res.apk的 PackageSetting
                    PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
                    // 比较签名
                    if ((compareSignatures(platformPkgSetting.signatures.mSigningDetails.signatures,
                                pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH)) {
                        // 签名相同,设置 SCAN_AS_PRIVILEGED 这个扫描 flag,也就是说把这个app当作特权app进行扫描
                        scanFlags |= SCAN_AS_PRIVILEGED;
                    }
                }
            }
        }

        return scanFlags;
    }

除去系统升级的代码,剩下的代码处理的是,把非特权app当作特权app来扫描的特殊情况,具体条件如下

  1. 不是vendor分区和odem分区下的APK。例如是product分区,system分区。
  2. 扫描的不是priv-app目录下APK。不在这个目录下的APK,在开始扫描时,不是当作特权APK来扫描的。
  3. 使用了sharedUserId属性,并且这个属性的值是系统保存的共享用户,例如android.uid.system。
  4. 该APK与framework-res.apk的签名相同。

满足了这些条件后,就会给扫描标志位scanFlags,添加一个SCAN_AS_PRIVILEGED标记位。

添加扫描标记

applyPolicy()主要根据扫描标记位,在APK的扫描结果(PackageParser.Package)中保存一些标记信息。

    private static void applyPolicy(PackageParser.Package pkg, final @ParseFlags int parseFlags, final @ScanFlags int scanFlags, PackageParser.Package platformPkg) {
        // 代表扫描的是在系统APK
        if ((scanFlags & SCAN_AS_SYSTEM) != 0) {
            // 我们可以通过ApplicationInfo.FLAG_SYSTEM判断APK是否是系统APK
            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
            // 如果<application>设置directBootAware属性为true,那么四大组件也要相应设置为true
            if (pkg.applicationInfo.isDirectBootAware()) {
                for (PackageParser.Service s : pkg.services) {
                    s.info.encryptionAware = s.info.directBootAware = true;
                }
                for (PackageParser.Provider p : pkg.providers) {
                    p.info.encryptionAware = p.info.directBootAware = true;
                }
                for (PackageParser.Activity a : pkg.activities) {
                    a.info.encryptionAware = a.info.directBootAware = true;
                }
                for (PackageParser.Activity r : pkg.receivers) {
                    r.info.encryptionAware = r.info.directBootAware = true;
                }
            }
            // 处理这样一个情况
            // 1. APk以-stub.apk结尾,例如hello-stub.apk
            // 2. 在当前目录的hello子目录下,存在.gz结尾的压缩包
            // 本文暂且不讨论这种情况
            if (compressedFileExists(pkg.codePath)) {
                pkg.isStub = true;
            }
        } else { // 非系统app要做以下处理
            // 不能使用coreApp属性
            pkg.coreApp = false;
            // 不能使用persistent属性
            pkg.applicationInfo.flags &=
                    ~ApplicationInfo.FLAG_PERSISTENT;
            // 不能使用defaultToDeviceProtectedStorage属性
            pkg.applicationInfo.privateFlags &=
                    ~ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
            // 不能使用directBootAware属性
            pkg.applicationInfo.privateFlags &=
                    ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
            // 权限优先级设置为0
            if (pkg.permissionGroups != null && pkg.permissionGroups.size() > 0) {
                for (int i = pkg.permissionGroups.size() - 1; i >= 0; --i) {
                    pkg.permissionGroups.get(i).info.priority = 0;
                }
            }
        }

        // 处理不是priv-app目录下app
        if ((scanFlags & SCAN_AS_PRIVILEGED) == 0) {
            // 可以看到,不是特权应用,不能使用<protect-broadcast>标签
            pkg.protectedBroadcasts = null;

            // 不是特权app, 对于设置了singleUser属性的receiver, service, provider,它们的exported属性必须为false
            // ignore export request for single user receivers
            if (pkg.receivers != null) {
                for (int i = pkg.receivers.size() - 1; i >= 0; --i) {
                    final PackageParser.Activity receiver = pkg.receivers.get(i);
                    if ((receiver.info.flags & ActivityInfo.FLAG_SINGLE_USER) != 0) {
                        receiver.info.exported = false;
                    }
                }
            }
            // ignore export request for single user services
            if (pkg.services != null) {
                for (int i = pkg.services.size() - 1; i >= 0; --i) {
                    final PackageParser.Service service = pkg.services.get(i);
                    if ((service.info.flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
                        service.info.exported = false;
                    }
                }
            }
            // ignore export request for single user providers
            if (pkg.providers != null) {
                for (int i = pkg.providers.size() - 1; i >= 0; --i) {
                    final PackageParser.Provider provider = pkg.providers.get(i);
                    if ((provider.info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0) {
                        provider.info.exported = false;
                    }
                }
            }
        }

        // 如果扫描是特权app,添加一个flag
        // 注意,刚才在调整策略的函数中,针对一个特殊情况下的APK也当作特权APP
        if ((scanFlags & SCAN_AS_PRIVILEGED) != 0) {
            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
        }
        
        // 下面是对app处在的分区进行标记
        if ((scanFlags & SCAN_AS_OEM) != 0) {
            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_OEM;
        }
        if ((scanFlags & SCAN_AS_VENDOR) != 0) {
            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR;
        }
        if ((scanFlags & SCAN_AS_PRODUCT) != 0) {
            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT;
        }
        if ((scanFlags & SCAN_AS_PRODUCT_SERVICES) != 0) {
            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES;
        }
        if ((scanFlags & SCAN_AS_ODM) != 0) {
            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ODM;
        }

        // frameworks-res.apk 或 与其签名相同的APK都标记为系统签名
        if (PLATFORM_PACKAGE_NAME.equals(pkg.packageName) ||
                (platformPkg != null && compareSignatures(
                        platformPkg.mSigningDetails.signatures,
                        pkg.mSigningDetails.signatures) == PackageManager.SIGNATURE_MATCH)) {
            // 原来可以使用这个来检测APK是否是系统签名
            pkg.applicationInfo.privateFlags |=
                ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY;
        }

        // 不是系统app,不能使用如下标签 
        if (!isSystemApp(pkg)) {
            // Only system apps can use these features.
            // 如下两个变量是针对<original-package>标签
            pkg.mOriginalPackages = null;
            pkg.mRealPackage = null;
            // <adopt-permission>标签
            pkg.mAdoptPermissions = null;
        }


        // 这个是处理库的向后兼容问题
        PackageBackwardCompatibility.modifySharedLibraries(pkg);
    }

这个函数大部分代码是根据扫描标记位,调整ApplicationInfo的flags和privateFlags变量。例如,如果扫描的是系统app,那么为ApplictionInfo.flags添加一个ApplicationInfo.FLAG_SYSTEM。如果扫描的是特权app,那么为ApplicationInfo.privateFlags添加ApplicationInfo.PRIVATE_FLAG_PRIVILEGED。如果是系统签名,那么为ApplicationInfo.privateFlags添加ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY。

扫描

根据前面的分析可知,scanPackageNewLI()做了刚才描述的一些准备工作后,就创建了一个包装类ScanRequest,然后调用scanPackageOnlyLI()继续扫描


    private static @NonNull ScanResult scanPackageOnlyLI(@NonNull ScanRequest request, boolean isUnderFactoryTest, long currentTime) throws PackageManagerException {
        final PackageParser.Package pkg = request.pkg;
        final @ParseFlags int parseFlags = request.parseFlags;
        final @ScanFlags int scanFlags = request.scanFlags;
        final SharedUserSetting sharedUserSetting = request.sharedUserSetting;
        final UserHandle user = request.user;
        final boolean isPlatformPackage = request.isPlatformPackage;

        // 如下几个变量是与系统升级相关,目前讨论的是首次开机,这些值为null
        PackageSetting pkgSetting = request.pkgSetting;
        final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
        final PackageSetting originalPkgSetting = request.originalPkgSetting;
        final String realPkgName = request.realPkgName;

        List<String> changedAbiCodePath = null;

        // Initialize package source and resource directories
        final File scanFile = new File(pkg.codePath);
        final File destCodeFile = new File(pkg.applicationInfo.getCodePath());
        final File destResourceFile = new File(pkg.applicationInfo.getResourcePath());

        String primaryCpuAbiFromSettings = null;
        String secondaryCpuAbiFromSettings = null;
        // 首先开机 ,needToDeriveAbi值为true
        boolean needToDeriveAbi = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0;
        if (!needToDeriveAbi) {
            // ...
        }

        if (pkgSetting != null && pkgSetting.sharedUser != sharedUserSetting) {
            // ...
        }
        
        // <uses-static-library>标签的内容
        // 把app使用的静态库,转换为数组
        String[] usesStaticLibraries = null;
        if (pkg.usesStaticLibraries != null) {
            usesStaticLibraries = new String[pkg.usesStaticLibraries.size()];
            pkg.usesStaticLibraries.toArray(usesStaticLibraries);
        }
        
        // 首次开机pkgSettings为null,因此createNewPackage为true,表示重新创建PackageSettings
        final boolean createNewPackage = (pkgSetting == null);
        if (createNewPackage) {
            final String parentPackageName = (pkg.parentPackage != null)
                    ? pkg.parentPackage.packageName : null;
            final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
            final boolean virtualPreload = (scanFlags & SCAN_AS_VIRTUAL_PRELOAD) != 0;
            // 1. 创建PackageSetting
            pkgSetting = Settings.createNewSetting(pkg.packageName, originalPkgSetting,
                    disabledPkgSetting, realPkgName, sharedUserSetting, destCodeFile,
                    destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,
                    pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi,
                    pkg.mVersionCode, pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
                    user, true /*allowInstall*/, instantApp, virtualPreload,
                    parentPackageName, pkg.getChildPackageNames(),
                    UserManagerService.getInstance(), usesStaticLibraries,
                    pkg.usesStaticLibrariesVersions);
        } else {
            // ...
        }

        if (createNewPackage && originalPkgSetting != null) {
            // ...
        }        
        

        // 传入的user为null,因此这里的userId值为USER_SYSTEM
        final int userId = (user == null ? UserHandle.USER_SYSTEM : user.getIdentifier());
        if (!createNewPackage) {
           // ...
        }
        
        if (disabledPkgSetting != null
                || (0 != (scanFlags & SCAN_NEW_INSTALL)
                && pkgSetting != null && pkgSetting.isSystem())) {
            // ...
        }

        // ... 省略一段关于保存selinux的代码

        // 注意:PackageParser.Package.mExtras保存了PackageSetting
        pkg.mExtras = pkgSetting;

        // 如果指定了process属性,那么进程名就是它的值,否则为包名的值
        pkg.applicationInfo.processName = fixProcessName(
                pkg.applicationInfo.packageName,
                pkg.applicationInfo.processName);

        if (!isPlatformPackage) {
            // 做一些关于用户初始化事情
            pkg.applicationInfo.initForUser(UserHandle.USER_SYSTEM);
        }

        // ... 省略一段关于cpu abi和native lib处理代码

        if (isUnderFactoryTest && pkg.requestedPermissions.contains(
                android.Manifest.permission.FACTORY_TEST)) {
            // ...
        }

        if (isSystemApp(pkg)) {
            pkgSetting.isOrphaned = true;
        }

        // ... 省略一段关于保存安装和最后更新时间的代码

        // PackageSetting.pkg 保存了 PackageParser.Package
        pkgSetting.pkg = pkg;

        // 更新PackageSetting中的信息
        pkgSetting.pkgFlags = pkg.applicationInfo.flags;
        if (pkg.getLongVersionCode() != pkgSetting.versionCode) {
            pkgSetting.versionCode = pkg.getLongVersionCode();
        }
        final String volumeUuid = pkg.applicationInfo.volumeUuid;
        if (!Objects.equals(volumeUuid, pkgSetting.volumeUuid)) {
            pkgSetting.volumeUuid = volumeUuid;
        }

        // 2. 获取静态库和动态库信息
        // 这是针对<static-library>标签
        SharedLibraryInfo staticSharedLibraryInfo = null;
        if (!TextUtils.isEmpty(pkg.staticSharedLibName)) {
            staticSharedLibraryInfo = SharedLibraryInfo.createForStatic(pkg);
        }
        // 这是针对<library>标签
        List<SharedLibraryInfo> dynamicSharedLibraryInfos = null;
        if (!ArrayUtils.isEmpty(pkg.libraryNames)) {
            dynamicSharedLibraryInfos = new ArrayList<>(pkg.libraryNames.size());
            for (String name : pkg.libraryNames) {
                dynamicSharedLibraryInfos.add(SharedLibraryInfo.createForDynamic(pkg, name));
            }
        }

        // 3. 返回扫描结果
        // 第一个参数表示扫描的请求
        // 第二个参数表示扫描是否成功
        // 第三个参数表示扫描创建的PackageSetting(针对首次开机)
        // 第四个参数,在首次开机,值为null
        // 第五个参数,表示返回的PacakgeSetting是否是从已经存在的PacakgeSetting中创建的
        // 第六、七个参数,表示静态库和动态库信息
        return new ScanResult(request, true, pkgSetting, changedAbiCodePath,
                !createNewPackage /* existingSettingCopied */, staticSharedLibraryInfo,
                dynamicSharedLibraryInfos);
    }

这个代码有300多行,但是从最后的返回结果其实就可以知道它做了哪些事,这里列举一些主要的事情

  1. 创建PackageSetting。
  2. 更新PackageSetting和PackageParser.Package信息,并通过成员变量相互引用。
  3. 获取静态库和动态库的信息。

创建PackageSetting本没有什么特别,但是这里有个appId的事情,你可能会感兴趣,我们来看下

    static @NonNull PackageSetting createNewSetting(String pkgName, PackageSetting originalPkg, PackageSetting disabledPkg, String realPkgName, SharedUserSetting sharedUser, File codePath, File resourcePath, String legacyNativeLibraryPath, String primaryCpuAbi, String secondaryCpuAbi, long versionCode, int pkgFlags, int pkgPrivateFlags, UserHandle installUser, boolean allowInstall, boolean instantApp, boolean virtualPreload, String parentPkgName, List<String> childPkgNames, UserManagerService userManager, String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) {
        final PackageSetting pkgSetting;
        if (originalPkg != null) {
            // ...
        } else {
            // 创建PackageSetting
            pkgSetting = new PackageSetting(pkgName, realPkgName, codePath, resourcePath,
                    legacyNativeLibraryPath, primaryCpuAbi, secondaryCpuAbi,
                    null /*cpuAbiOverrideString*/, versionCode, pkgFlags, pkgPrivateFlags,
                    parentPkgName, childPkgNames, 0 /*sharedUserId*/, usesStaticLibraries,
                    usesStaticLibrariesVersions);
            pkgSetting.setTimeStamp(codePath.lastModified());
            pkgSetting.sharedUser = sharedUser;
            if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
                // 处理不是系统app的情况,主要是初始化关于多用户的信息
            }
            if (sharedUser != null) {
                // 设置appId
                // 从这里可以看出SharedUserSetting中的userId变量,其实指的就是appId,源码的这个命名是真的混乱!!!
                pkgSetting.appId = sharedUser.userId;
            } else {
                // Clone the setting here for disabled system packages
                if (disabledPkg != null) {
                    // ...
                }
            }
        }
        return pkgSetting;
    }

从设置appId的那一行代码可以看出,如果多个APK的sharedUserId是同一个值,那么这些APK进程的appId值是相同的。

如果sharedUserId的值是系统共享用户,例如android.uid.system,那么appId的值是从1000开始,理论上讲,最大只能是9999。例如 android.uid.system 对应的 appId 的值是 Process.SYSTEM_UID,值为1000。

而如果sharedUserId的值不是系统用户呢,例如多个APK同时使用sharedUserId,把值设置为com.uid.test,那么appId是从 Process.FIRST_APPLICATION_UID(值为10000) 开始的的,最大为 Process.LAST_APPLICATION_UID (值为19999)。

到此,对解析出的APK结果进行再扫描的过程已经分析完毕,这个过程大致上是先创建一个ScanRequest请求,处理请求后返回一个ScanResult结果。

调整扫描结果

现在我们已经分析完了scanPackageNewLI()再次扫描的过程,现在要分析的代码如下

    private PackageParser.Package addForInitLI(PackageParser.Package pkg, @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException {
        // ....


        // 省略系统升级的代码...

        // 1. 再次扫描,返回扫描结果
        final ScanResult scanResult = scanPackageNewLI(pkg, parseFlags, scanFlags
                | SCAN_UPDATE_SIGNATURE, currentTime, user);
        if (scanResult.success) {
            synchronized (mPackages) {
                boolean appIdCreated = false;
                try {
                    final String pkgName = scanResult.pkgSetting.name;
                    // 2. 如果是安装APK,会调整再次扫描的结果,返回一个调整后的结果ReconfiledPackage
                    final Map<String, ReconciledPackage> reconcileResult = reconcilePackagesLocked(
                            new ReconcileRequest(
                                    Collections.singletonMap(pkgName, scanResult),
                                    mSharedLibraries,
                                    mPackages,
                                    Collections.singletonMap(
                                            pkgName, getSettingsVersionForPackage(pkg)),
                                    Collections.singletonMap(pkgName,
                                            getSharedLibLatestVersionSetting(scanResult))),
                            mSettings.mKeySetManagerService);
                    // 用于检测appId是否已经创建
                    // appIdCreated的作用是,当扫描出现异常,清理这个appId
                    appIdCreated = optimisticallyRegisterAppId(scanResult);
                    // 3. 把最终的结果进行提交
                    commitReconciledScanResultLocked(reconcileResult.get(pkgName));
                } catch (PackageManagerException e) {
                    // ...
                }
            }
        }

        // ...

        return scanResult.pkgSetting.pkg;
    }

第一步已经分析完了,它返回一个ScanResult对象表示扫描的结果。现在来分析第二步,其实第二步是与安装APK相关,但是这一步又无法跳过,因为第三步提交的数据就是第二步返回的结果,所以我们勉为其难地来看下吧。

    private static Map<String, ReconciledPackage> reconcilePackagesLocked( final ReconcileRequest request, KeySetManagerService ksms) throws ReconcileFailure {
        // scannedPackages表示当前再次扫描的结果的Map,key为pkgName,value为再次扫描结果
        final Map<String, ScanResult> scannedPackages = request.scannedPackages;

        // 用于返回的调整的结果
        final Map<String, ReconciledPackage> result = new ArrayMap<>(scannedPackages.size());

        // combinedPackages用于保存已经扫描过的APK信息,和正在扫描的APK信息
        final ArrayMap<String, PackageParser.Package> combinedPackages =
                new ArrayMap<>(request.allPackages.size() + scannedPackages.size());
        // 复制已经保存到PKMS中的APK信息
        combinedPackages.putAll(request.allPackages);

        final Map<String, LongSparseArray<SharedLibraryInfo>> incomingSharedLibraries =
                new ArrayMap<>();

        // 这里其实只会循环一次
        for (String installPackageName : scannedPackages.keySet()) {
            // 代表再次扫描的结果
            final ScanResult scanResult = scannedPackages.get(installPackageName);

            // 添加到刚才创建的combinedPackages中
            combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.pkg);

            // 获取动态库或者静态库的信息
            // 这一段是处理<static-library>和<library>,它表明当前APK是一个库,它会把库的信息放到incomingSharedLibraries中
            final List<SharedLibraryInfo> allowedSharedLibInfos =
                    getAllowedSharedLibInfos(scanResult, request.sharedLibrarySource);
            final SharedLibraryInfo staticLib = scanResult.staticSharedLibraryInfo;
            if (allowedSharedLibInfos != null) {
                for (SharedLibraryInfo info : allowedSharedLibInfos) {
                    // 把库信息加入到incomingSharedLibraries中
                    if (!addSharedLibraryToPackageVersionMap(incomingSharedLibraries, info)) {
                        throw new ReconcileFailure("Static Shared Library " + staticLib.getName()
                                + " is being installed twice in this set!");
                    }
                }
            }

            // ... 省略关于安装app的代码

            // 对再次扫描的结果ScanResult的一次包装
            // 其中加入了很多安装APK的一些参数,这些参数在首次开机流程中都是null
            // 而在首次开机中,有用的参数为allowedSharedLibInfos,这代表APK是一个库
            result.put(installPackageName,
                    new ReconciledPackage(request, installArgs, scanResult.pkgSetting,
                            res, request.preparedPackages.get(installPackageName), scanResult,
                            deletePackageAction, allowedSharedLibInfos, signingDetails,
                            sharedUserSignaturesChanged, removeAppKeySetData));
        }

        for (String installPackageName : scannedPackages.keySet()) {
            final ScanResult scanResult = scannedPackages.get(installPackageName);
            // 系统app是不需要这一步处理的,因为在扫描完成后,会更新库的信息
            if ((scanResult.request.scanFlags & SCAN_BOOTING) != 0
                    || (scanResult.request.parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
                continue;
            }
            try {
                // 对于非系统app的安装,并且使用了<uses-library>或<uses-static-library>,那么获取库的信息
                result.get(installPackageName).collectedSharedLibraryInfos =
                        collectSharedLibraryInfos(scanResult.request.pkg, combinedPackages,
                                request.sharedLibrarySource, incomingSharedLibraries);

            } catch (PackageManagerException e) {
                throw new ReconcileFailure(e.error, e.getMessage());
            }
        }

        return result;
    }

这个函数主要就是处理APK安装,从返回的结果可以看出,对于首次开机,有用的代码就是提取了的 <static-library><library> 标签的信息到allowedSharedLibInfos中,然后包装成一个ReconciledPackage,最后返回一个Map<String, ReconciledPackage> result

提交数据

现在已经分析完了调整扫描结果的过程,现在让我们来看下还剩下什么没有分析了

    private PackageParser.Package addForInitLI(PackageParser.Package pkg, @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException {
        // ....


        // 省略系统升级的代码...

        // 1. 再次扫描,返回扫描结果
        final ScanResult scanResult = scanPackageNewLI(pkg, parseFlags, scanFlags
                | SCAN_UPDATE_SIGNATURE, currentTime, user);
        if (scanResult.success) {
            synchronized (mPackages) {
                boolean appIdCreated = false;
                try {
                    final String pkgName = scanResult.pkgSetting.name;
                    // 2. 如果是安装APK,会调整再次扫描的结果,返回一个调整后的结果ReconfiledPackage
                    final Map<String, ReconciledPackage> reconcileResult = reconcilePackagesLocked(
                            new ReconcileRequest(
                                    Collections.singletonMap(pkgName, scanResult),
                                    mSharedLibraries,
                                    mPackages,
                                    Collections.singletonMap(
                                            pkgName, getSettingsVersionForPackage(pkg)),
                                    Collections.singletonMap(pkgName,
                                            getSharedLibLatestVersionSetting(scanResult))),
                            mSettings.mKeySetManagerService);
                    // 用于检测appId是否已经创建
                    // appIdCreated的作用是,当扫描出现异常,清理这个appId
                    appIdCreated = optimisticallyRegisterAppId(scanResult);
                    // 3. 把最终的结果进行提交
                    commitReconciledScanResultLocked(reconcileResult.get(pkgName));
                } catch (PackageManagerException e) {
                    // ...
                }
            }
        }

        // ...

        return scanResult.pkgSetting.pkg;
    }

现在已经到了第三步,提交结果了。

    private void commitReconciledScanResultLocked(@NonNull ReconciledPackage reconciledPkg) {
        final ScanResult result = reconciledPkg.scanResult;
        final ScanRequest request = result.request;
        final PackageParser.Package pkg = request.pkg;
        final @ParseFlags int parseFlags = request.parseFlags;
        final @ScanFlags int scanFlags = request.scanFlags;
        final UserHandle user = request.user;
        final List<String> changedAbiCodePath = result.changedAbiCodePath;

        // 这个指向当前创建的PackageSetting
        final PackageSetting pkgSetting;

        // 对于首次开机,下面的这些变量都是null
        final PackageParser.Package oldPkg = request.oldPkg;
        final PackageSetting oldPkgSetting = request.oldPkgSetting;
        final PackageSetting originalPkgSetting = request.originalPkgSetting;
        final String realPkgName = request.realPkgName;

        // 对于首次开机,request.pkgSetting是null
        if (request.pkgSetting != null && request.pkgSetting.sharedUser != null
                && request.pkgSetting.sharedUser != result.pkgSetting.sharedUser) {
            // shared user changed, remove from old shared user
            request.pkgSetting.sharedUser.removePackage(request.pkgSetting);
        }
        // 从前面分析可知,PackageSetting是重新创建的,result.existingSettingCopied值为false
        if (result.existingSettingCopied) {
            // ...
        } else {
            // 1. 获取刚才创建的PackageSetting
            pkgSetting = result.pkgSetting;

            // originalPkgSetting为null
            if (originalPkgSetting != null) {
                mSettings.addRenamedPackageLPw(pkg.packageName, originalPkgSetting.name);
            }
            // originalPkgSetting为null
            if (originalPkgSetting != null && (scanFlags & SCAN_CHECK_ONLY) == 0) {
                mTransferedPackages.add(originalPkgSetting.name);
            }
        }

        // 如果设置过sharedUserId,那么把这个PackageSetting添加到SharedUserSetting.packages
        if (pkgSetting.sharedUser != null) {
            pkgSetting.sharedUser.addPackage(pkgSetting);
        }

        // pkg.applicationInfo.uid是表示kenerl user-ID
        // 吐槽一下,Android中多用户的的一些概念是真的垃圾,容易混淆,也不容易理解!!!!
        pkg.applicationInfo.uid = pkgSetting.appId;

        // 由于现在还没有把信息保存到PKMS的mPackages中,因此这里不做任何事
        mSettings.writeUserRestrictionsLPw(pkgSetting, oldPkgSetting);

        // 首次开机,realPkgName为null
        if ((scanFlags & SCAN_CHECK_ONLY) == 0 && realPkgName != null) {
            mTransferedPackages.add(pkg.packageName);
        }

        if (reconciledPkg.collectedSharedLibraryInfos != null) {
            // 2. 把非系统app使用的库的信息,保存到PackageParser.Package中
            // 这个是针对非系统app,使用了<uses-static-library>或<uses-library>
            // 这里会把要使用的库保存到PackageParser.Package.usesLibraryInfos和PackageParser.Package.usesLibraryInfos.usesLibraryFiles
            executeSharedLibrariesUpdateLPr(pkg, null, reconciledPkg.collectedSharedLibraryInfos);
        }

        // 更新签名相关的信息
        final KeySetManagerService ksms = mSettings.mKeySetManagerService;
        if (reconciledPkg.removeAppKeySetData) {
            ksms.removeAppKeySetDataLPw(pkg.packageName);
        }
        if (reconciledPkg.sharedUserSignaturesChanged) {
            pkgSetting.sharedUser.signaturesChanged = Boolean.TRUE;
            pkgSetting.sharedUser.signatures.mSigningDetails = reconciledPkg.signingDetails;
        }
        pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails;

        // <adpot-permission>原来是把其它包的权限转移到自己包中,不过这个标签只能被系统app使用
        if ((scanFlags & SCAN_CHECK_ONLY) == 0 && pkg.mAdoptPermissions != null) {
            // This package wants to adopt ownership of permissions from
            // another package.
            for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) {
                final String origName = pkg.mAdoptPermissions.get(i);
                final PackageSetting orig = mSettings.getPackageLPr(origName);
                if (orig != null) {
                    if (verifyPackageUpdateLPr(orig, pkg)) {
                        Slog.i(TAG, "Adopting permissions from " + origName + " to "
                                + pkg.packageName);
                        mSettings.mPermissions.transferPermissions(origName, pkg.packageName);
                    }
                }
            }
        }

        if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) {
            for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) {
                final String codePathString = changedAbiCodePath.get(i);
                try {
                    mInstaller.rmdex(codePathString,
                            getDexCodeInstructionSet(getPreferredInstructionSet()));
                } catch (InstallerException ignored) {
                }
            }
        }

        if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
            // ...
        } else {
            final int userId = user == null ? 0 : user.getIdentifier();
            // 2. 把扫描的信息添加到PKMS的数据结构中
            // 经此一步,PKMS现在可以提供查询服务给客户端
            commitPackageSettings(pkg, oldPkg, pkgSetting, scanFlags,
                    (parseFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg);

            // 关于instant app的
            if (pkgSetting.getInstantApp(userId)) {
                // ...
            }
        }
    }

这个函数处理的信息比较杂乱,我大致分为了三步,如下

  1. 获取刚才创建的PackageSetting对象,并更新一些信息,例如为共享用户的SharedUserSetting保存包的信息。
  2. 对于非系统app,把它使用的库的信息保存到PackageParser.Package中。
  3. 调用 commitPackageSettings(),把数据提交到PKMS中。

前两步就不做分析了,让我们直接来看如何数据到PKMS的。

    private void commitPackageSettings(PackageParser.Package pkg, @Nullable PackageParser.Package oldPkg, PackageSetting pkgSetting, final @ScanFlags int scanFlags, boolean chatty, ReconciledPackage reconciledPkg) {
        final String pkgName = pkg.packageName;
        // mCustomResolverComponentName默认为null,是由R.string.config_customResolverActivity指定的
        if (mCustomResolverComponentName != null &&
                mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) {
            setUpCustomResolverActivity(pkg);
        }
        
        // 1.为frameworks-res.apk保存一个ResolverActivity信息
        if (pkg.packageName.equals("android")) {
            synchronized (mPackages) {
                if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
                    // 注意了,PKMS单独用两个变量保存了frameworks-res.apk信息
                    mPlatformPackage = pkg;
                    mAndroidApplication = pkg.applicationInfo;

                    pkg.mVersionCode = mSdkVersion;
                    pkg.mVersionCodeMajor = 0;
                    // 手动给frameworks-res.apk添加一个ResolverActivity的信息
                    if (!mResolverReplaced) {
                        mResolveActivity.applicationInfo = mAndroidApplication;
                        mResolveActivity.name = ResolverActivity.class.getName();
                        mResolveActivity.packageName = mAndroidApplication.packageName;
                        // 这个ResolverActivity的进程名是system:ui
                        mResolveActivity.processName = "system:ui";
                        // 这个就是standard luanch mode
                        mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
                        mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
                        // 不在recent界面显示
                        mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
                        mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
                        mResolveActivity.exported = true;
                        mResolveActivity.enabled = true;
                        mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
                        mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE
                                | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE
                                | ActivityInfo.CONFIG_SCREEN_LAYOUT
                                | ActivityInfo.CONFIG_ORIENTATION
                                | ActivityInfo.CONFIG_KEYBOARD
                                | ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
                        // mResolveInfo是用于查询返回的,它代表ResolverActivity信息
                        mResolveInfo.activityInfo = mResolveActivity;
                        mResolveInfo.priority = 0;
                        mResolveInfo.preferredOrder = 0;
                        mResolveInfo.match = 0;
                        // 创建ResolverActivity对应的ComponentName
                        mResolveComponentName = new ComponentName(
                                mAndroidApplication.packageName, mResolveActivity.name);
                    }
                }
            }
        }

        ArrayList<PackageParser.Package> clientLibPkgs = null;
        // writer
        synchronized (mPackages) {
            // 这个是针对使用<static-library>或<library>声明的库
            if (!ArrayUtils.isEmpty(reconciledPkg.allowedSharedLibraryInfos)) {
                for (SharedLibraryInfo info : reconciledPkg.allowedSharedLibraryInfos) {
                    // 2. 提交库的信息到PKMS的数据结构中
                    // 如果使用<static-library>声明的静态库,保存到PKMS的mStaticLibsByDeclaringPackage中
                    // 如果使用<library>声明的动态库,保存到PKMS的mSharedLibraries
                    commitSharedLibraryInfoLocked(info);
                }

                // 这个表示到目前为止,已经扫描完成的APK信息
                final Map<String, PackageParser.Package> combinedPackages =
                        reconciledPkg.getCombinedPackages();
                try {
                    // Shared libraries for the package need to be updated.
                    // 3. 收集系统APK使用库的信息
                    // 这一步是针对使用<uses-library>和<uses-static-library>的情况,其实前面已经分析过,
                    // 就是把库的信息保存到PackageParser.Package.usesLibraryInfos和PackageParser.Package.usesLibraryFiles中
                    updateSharedLibrariesLocked(pkg, null, combinedPackages);
                } catch (PackageManagerException e) {
                    Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e);
                }
                // Update all applications that use this library. Skip when booting
                // since this will be done after all packages are scaned.
                if ((scanFlags & SCAN_BOOTING) == 0) {
                    clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedPackages);
                }
            }
        }
        // 针对安装APK,本文不分析
        if (reconciledPkg.installResult != null) {
            reconciledPkg.installResult.libraryConsumers = clientLibPkgs;
        }

        if ((scanFlags & SCAN_BOOTING) != 0) {
            // No apps can run during boot scan, so they don't need to be frozen
        } else if ((scanFlags & SCAN_DONT_KILL_APP) != 0) {
            // Caller asked to not kill app, so it's probably not frozen
        } else if ((scanFlags & SCAN_IGNORE_FROZEN) != 0) {
            // Caller asked us to ignore frozen check for some reason; they
            // probably didn't know the package name
        } else {
            // We're doing major surgery on this package, so it better be frozen
            // right now to keep it from launching
            checkPackageFrozen(pkgName);
        }

        // Also need to kill any apps that are dependent on the library.
        // 首次开机,clientLibPkgs为null
        if (clientLibPkgs != null) {
            for (int i=0; i<clientLibPkgs.size(); i++) {
                PackageParser.Package clientPkg = clientLibPkgs.get(i);
                killApplication(clientPkg.applicationInfo.packageName,
                        clientPkg.applicationInfo.uid, "update lib");
            }
        }

        // writer
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");

        synchronized (mPackages) {
            // We don't expect installation to fail beyond this point

            // Add the new setting to mSettings
            // 4 把PackageSetting保存到PKMS的mSettings中,
            // 其实是保存到了Settings类的mPackages中
            mSettings.insertPackageSettingLPw(pkgSetting, pkg);

            // 5 把PackageParser.Package保存到PKMS的mPackages中
            // Add the new setting to mPackages
            mPackages.put(pkg.applicationInfo.packageName, pkg);

            // Add the package's KeySets to the global KeySetManagerService
            // TODO: KeySetManagerService似乎与签名相关
            KeySetManagerService ksms = mSettings.mKeySetManagerService;
            ksms.addScannedPackageLPw(pkg);

            // 6 PKMS用mComponentResolver保存四大组件的信息
            mComponentResolver.addAllComponents(pkg, chatty);

            // 7 PKMS用mPermissionManager保存APK声明和使用权限的信息
            mPermissionManager.addAllPermissionGroups(pkg, chatty);
            mPermissionManager.addAllPermissions(pkg, chatty);

            int collectionSize = pkg.instrumentation.size();
            StringBuilder r = null;
            int i;
            // 8 PKMS的mInstrumentation保存所有<instrumentation>信息
            for (i = 0; i < collectionSize; i++) {
                PackageParser.Instrumentation a = pkg.instrumentation.get(i);
                a.info.packageName = pkg.applicationInfo.packageName;
                a.info.sourceDir = pkg.applicationInfo.sourceDir;
                a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir;
                a.info.splitNames = pkg.splitNames;
                a.info.splitSourceDirs = pkg.applicationInfo.splitSourceDirs;
                a.info.splitPublicSourceDirs = pkg.applicationInfo.splitPublicSourceDirs;
                a.info.splitDependencies = pkg.applicationInfo.splitDependencies;
                a.info.dataDir = pkg.applicationInfo.dataDir;
                a.info.deviceProtectedDataDir = pkg.applicationInfo.deviceProtectedDataDir;
                a.info.credentialProtectedDataDir = pkg.applicationInfo.credentialProtectedDataDir;
                a.info.primaryCpuAbi = pkg.applicationInfo.primaryCpuAbi;
                a.info.secondaryCpuAbi = pkg.applicationInfo.secondaryCpuAbi;
                a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
                a.info.secondaryNativeLibraryDir = pkg.applicationInfo.secondaryNativeLibraryDir;
                mInstrumentation.put(a.getComponentName(), a);
                if (chatty) {
                    if (r == null) {
                        r = new StringBuilder(256);
                    } else {
                        r.append(' ');
                    }
                    r.append(a.info.name);
                }
            }

            // 9 PKMS的mProtectedBroadcasts保存了所有系统APK声明的<protected-broadcast>
            if (pkg.protectedBroadcasts != null) {
                collectionSize = pkg.protectedBroadcasts.size();
                synchronized (mProtectedBroadcasts) {
                    for (i = 0; i < collectionSize; i++) {
                        mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i));
                    }
                }
            }

            // 首次开机,oldPkg为null
            if (oldPkg != null) {
                // ...
            }
        }

        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }

第一步,为frameworks-res.apk保存一个ResolverActivity信息,当然这个可以通过framework的资源直接指定。ResolverActivity是用来干嘛的呢?当有多个Activity响应一个Intent时,就会出现一个选择界面,这个界面就是ResolverActivity。

第二步,如果APK在AndroidManifest.xml中使用了<static-library>标签,那么证明这个APK是一个库。于是,把这个库保存到PKMS的 mStaticLibsByDeclaringPackage (保存静态库)或 mSharedLibraries (保存动态库)中。

第三步,如果系统APK在AndroidManifest.xml使用了 <uses-static-library> 或 <uses-library> 标签,那么更新PackageParser.Package,保存使用库的信息。

第四步,把刚才创建的PackageSetting保存到Settings中的mPackage中。

第五步,用PKMS的mPackage保存PackageParser.Package。

第六步,用PKMS的 mComponentResolver 保存四在组件的信息,这个我来看下代码

    void addAllComponents(PackageParser.Package pkg, boolean chatty) {
        final ArrayList<PackageParser.ActivityIntentInfo> newIntents = new ArrayList<>();
        synchronized (mLock) {
            // 用mActivities保存Activity信息,并提取Intent信息到newIntents
            addActivitiesLocked(pkg, newIntents, chatty);
            // 用mReceivers保存Receiver信息
            addReceiversLocked(pkg, chatty);
            // 用mProviders保存ContentProvider信息
            addProvidersLocked(pkg, chatty);
            // 用mServices保存Service信息
            addServicesLocked(pkg, chatty);
        }

        // 首次开机时,此时还没有保存开机向导的信息
        final String setupWizardPackage = sPackageManagerInternal.getKnownPackageName(
                PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM);
        for (int i = newIntents.size() - 1; i >= 0; --i) {
            final PackageParser.ActivityIntentInfo intentInfo = newIntents.get(i);
            final PackageParser.Package disabledPkg = sPackageManagerInternal
                    .getDisabledSystemPackage(intentInfo.activity.info.packageName);
            final List<PackageParser.Activity> systemActivities =
                    disabledPkg != null ? disabledPkg.activities : null;
            adjustPriority(systemActivities, intentInfo, setupWizardPackage);
        }
    }

第七步,保存权限相关的信息,我会在后面的文章解析关于动态权限的信息,这里先略过。

第八步,PKMS的mInstrumentation保存所有<instrumentation>信息。

第九步,PKMS的mProtectedBroadcasts保存了所有系统APK声明的<protected-broadcast>。

感想

这篇文章已经是PKMS的第三篇文章,可以说只是入门了PKMS,但是分析的难度可不小。经此一役,后面的事情就可以水到渠成,让我们为自己鼓掌吧!

点击这里复制本文地址 以上内容由权冠洲的博客整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

联系我们| 本站介绍| 留言建议 | 交换友链 | 域名展示
本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除

权冠洲的博客 © All Rights Reserved.  Copyright quanguanzhou.top All Rights Reserved
苏公网安备 32030302000848号   苏ICP备20033101号-1

联系我们