Android 安装应用-浏览阶段

  应用安装的浏览阶段主要是由PackageManagerService类中的scanPackageNewLI()实现的,看一下它的代码:

    // TODO: scanPackageNewLI() and scanPackageOnly() should be merged. But, first, commiting
    // the results / removing app data needs to be moved up a level to the callers of this
    // method. Also, we need to solve the problem of potentially creating a new shared user
    // setting. That can probably be done later and patch things up after the fact.
    @GuardedBy({"mInstallLock", "mLock"})
    private ScanResult scanPackageNewLI(@NonNull ParsedPackage parsedPackage,
            final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
            @Nullable UserHandle user, String cpuAbiOverride) throws PackageManagerException {

        final String renamedPkgName = mSettings.getRenamedPackageLPr(
                parsedPackage.getRealPackage());
        final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName);
        if (realPkgName != null) {
            ensurePackageRenamed(parsedPackage, renamedPkgName);
        }
        final PackageSetting originalPkgSetting = getOriginalPackageLocked(parsedPackage,
                renamedPkgName);
        final PackageSetting pkgSetting = mSettings.getPackageLPr(parsedPackage.getPackageName());
        final PackageSetting disabledPkgSetting =
                mSettings.getDisabledSystemPkgLPr(parsedPackage.getPackageName());

        if (mTransferredPackages.contains(parsedPackage.getPackageName())) {
            Slog.w(TAG, "Package " + parsedPackage.getPackageName()
                    + " was transferred to another, but its .apk remains");
        }

        scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, parsedPackage);
        synchronized (mLock) {
            boolean isUpdatedSystemApp;
            if (pkgSetting != null) {
                isUpdatedSystemApp = pkgSetting.getPkgState().isUpdatedSystemApp();
            } else {
                isUpdatedSystemApp = disabledPkgSetting != null;
            }
            applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage, isUpdatedSystemApp);
            assertPackageIsValid(parsedPackage, parseFlags, scanFlags);

            SharedUserSetting sharedUserSetting = null;
            if (parsedPackage.getSharedUserId() != null) {
                // SIDE EFFECTS; may potentially allocate a new shared user
                sharedUserSetting = mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(),
                        0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/);
                if (DEBUG_PACKAGE_SCANNING) {
                    if ((parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0) {
                        Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId()
                                + " (uid=" + sharedUserSetting.userId + "):"
                                + " packages=" + sharedUserSetting.packages);
                    }
                }
            }
            String platformPackageName = mPlatformPackage == null
                    ? null : mPlatformPackage.getPackageName();
            final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting,
                    pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
                    originalPkgSetting, realPkgName, parseFlags, scanFlags,
                    Objects.equals(parsedPackage.getPackageName(), platformPackageName), user,
                    cpuAbiOverride);
            return scanPackageOnlyLI(request, mInjector, mFactoryTest, currentTime);
        }
    }

  参数parsedPackage是解析安装文件得到的解析包对象。parsedPackage.getRealPackage()是在解析安装文件时,配置文件存在application同级别original-package标签 的属性 "name"的值,并且它的值和包名不一致时,会设置该值。在这里是找是否存在更改包名的情况,包名的更改关系维护在mSettings中的mRenamedPackages中,所以如果存在包名更改,renamedPkgName就是改名之前的包名。
  getRealPackageName(parsedPackage, renamedPkgName)是来判断改名之前的名字,是否存在parsedPackage对象的OriginalPackages中。如果存在,就返回parsedPackage.getRealPackage()。
  如果realPkgName != null不为null,说明存在改名字的情况,所以调用ensurePackageRenamed(parsedPackage, renamedPkgName)来将解析包的包名改为之前的包名。
  getOriginalPackageLocked(parsedPackage, renamedPkgName)是得到它原来的PackageSetting对象,但是像上面改名之前的包名在parsedPackage对象的OriginalPackages中的,则会返回null。因为它的名字已经是现在解析包的包名了。如果renamedPkgName不在parsedPackage对象的OriginalPackages中,并且parsedPackage对象的OriginalPackages中包名存在PackageSetting对象,但是看它的条件得旧包是系统包,并且在mPackages中不存在对应的值的情况下,才能返回它的PackageSetting对象。所以在这里我们也知道,包名修改是为了系统应用的功能,普通APP没法使用。在这里originalPkgSetting大部分情况下,为null。
  pkgSetting则是维护在mSettings中根据包名得到的PackageSetting对象。disabledPkgSetting是禁止的系统包的PackageSetting对象。
  mTransferredPackages中保存的是改过应用的包名。
  接下来就是调用adjustScanFlags()方法调整浏览标识。
  接着通过判断pkgSetting里面的状态和disabledPkgSetting != null来设置变量isUpdatedSystemApp的值。
  applyPolicy()方法,是用来根据标识来设置解析包对象的一些状态。
  assertPackageIsValid(parsedPackage, parseFlags, scanFlags)是进行一些判断,如果有些状态不符合要求,会报PackageManagerException异常。
  sharedUserSetting是解析包中配置的“android:sharedUserId”标签的共享用户的SharedUserSetting对象。
  platformPackageName是平台包名,它是由mPlatformPackage得出的值。mPlatformPackage是应用包名为"android"的安装包对象,如果存在,它不为null;如果不存在,它为null。
  下面会将上面说的变量封装到ScanRequest对象request中去。最后就是调用scanPackageOnlyLI(request, mInjector, mFactoryTest, currentTime),并将它的结果返回。下面看一下它的代码:

scanPackageOnlyLI(request, mInjector, mFactoryTest, currentTime)的实现

分段一

  它的代码也很长,所以分段阅读,第一段:

    @GuardedBy("mInstallLock")
    @VisibleForTesting
    @NonNull
    static ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
            Injector injector,
            boolean isUnderFactoryTest, long currentTime)
            throws PackageManagerException {
        final PackageAbiHelper packageAbiHelper = injector.getAbiHelper();
        final UserManagerInternal userManager = injector.getUserManagerInternal();
        ParsedPackage parsedPackage = request.parsedPackage;
        PackageSetting pkgSetting = request.pkgSetting;
        final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
        final PackageSetting originalPkgSetting = request.originalPkgSetting;
        final @ParseFlags int parseFlags = request.parseFlags;
        final @ScanFlags int scanFlags = request.scanFlags;
        final String realPkgName = request.realPkgName;
        final SharedUserSetting sharedUserSetting = request.sharedUserSetting;
        final UserHandle user = request.user;
        final boolean isPlatformPackage = request.isPlatformPackage;

        List<String> changedAbiCodePath = null;

        if (DEBUG_PACKAGE_SCANNING) {
            if ((parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0) {
                Log.d(TAG, "Scanning package " + parsedPackage.getPackageName());
            }
        }

        // Initialize package source and resource directories
        final File destCodeFile = new File(parsedPackage.getPath());

        // We keep references to the derived CPU Abis from settings in oder to reuse
        // them in the case where we're not upgrading or booting for the first time.
        String primaryCpuAbiFromSettings = null;
        String secondaryCpuAbiFromSettings = null;
        boolean needToDeriveAbi = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0;
        if (!needToDeriveAbi) {
            if (pkgSetting != null) {
                // TODO(b/154610922): if it is not first boot or upgrade, we should directly use
                // API info from existing package setting. However, stub packages currently do not
                // preserve ABI info, thus the special condition check here. Remove the special
                // check after we fix the stub generation.
                if (pkgSetting.pkg != null && pkgSetting.pkg.isStub()) {
                    needToDeriveAbi = true;
                } else {
                    primaryCpuAbiFromSettings = pkgSetting.primaryCpuAbiString;
                    secondaryCpuAbiFromSettings = pkgSetting.secondaryCpuAbiString;
                }
            } else {
                // Re-scanning a system package after uninstalling updates; need to derive ABI
                needToDeriveAbi = true;
            }
        }

  开始是给局部变量赋值。packageAbiHelper实际是PackageAbiHelperImpl类型。parsedPackage是解析的包实例,pkgSetting是旧包的PackageSetting对象。disabledPkgSetting是禁止的系统包的PackageSetting对象(包名相同)、originalPkgSetting是更改包名之前的原来包名对应的PackageSetting对象、realPkgName是如果存在更改包名现在的包名、user目前用户,像例子中也就是System用户(userId为0)。
  parsedPackage.getPath()是解析包的路径。解析Apk文件时,分为解析的是Apk还是目录。如果解析的直接是Apk,则parsedPackage.getPath()为Apk的完整路径名;如果是目录,则parsedPackage.getPath()为Apk文件的目录。
  primaryCpuAbiFromSettings是主要的cpu架构的abi,secondaryCpuAbiFromSettings是次要的cpu架构的abi。在升级系统或第一次启动的情况下,abi是需要从解析包里面取的。所以scanFlags 里面有SCAN_FIRST_BOOT_OR_UPGRADE标识时,会将变量needToDeriveAbi 设置为true,代表abi需要从解析包parsedPackage取得。
  所以needToDeriveAbi为false情况,如果pkgSetting 不为null,则直接从pkgSetting 取得abi。但是如果包设置pkgSetting对应的解析包pkg.isStub()的情况,那stub包是没有保留ABI信息的,所以也需要从当前解析的包信息里面取得。如果pkgSetting 为null,那也只能从解析包信息里面取得ABI。

分段二

  继续看scanPackageOnlyLI()的第二段代码:

        if (pkgSetting != null && pkgSetting.sharedUser != sharedUserSetting) {
            PackageManagerService.reportSettingsProblem(Log.WARN,
                    "Package " + parsedPackage.getPackageName() + " shared user changed from "
                            + (pkgSetting.sharedUser != null
                            ? pkgSetting.sharedUser.name : "<nothing>")
                            + " to "
                            + (sharedUserSetting != null ? sharedUserSetting.name : "<nothing>")
                            + "; replacing with new");
            pkgSetting = null;
        }

        String[] usesStaticLibraries = null;
        if (!parsedPackage.getUsesStaticLibraries().isEmpty()) {
            usesStaticLibraries = new String[parsedPackage.getUsesStaticLibraries().size()];
            parsedPackage.getUsesStaticLibraries().toArray(usesStaticLibraries);
        }

        final UUID newDomainSetId = injector.getDomainVerificationManagerInternal().generateNewId();

        // TODO(b/135203078): Remove appInfoFlag usage in favor of individually assigned booleans
        //  to avoid adding something that's unsupported due to lack of state, since it's called
        //  with null.
        final boolean createNewPackage = (pkgSetting == null);
        if (createNewPackage) {
            final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
            final boolean virtualPreload = (scanFlags & SCAN_AS_VIRTUAL_PRELOAD) != 0;

            // Flags contain system values stored in the server variant of AndroidPackage,
            // and so the server-side PackageInfoUtils is still called, even without a
            // PackageSetting to pass in.
            int pkgFlags = PackageInfoUtils.appInfoFlags(parsedPackage, null);
            int pkgPrivateFlags = PackageInfoUtils.appInfoPrivateFlags(parsedPackage, null);

            // REMOVE SharedUserSetting from method; update in a separate call
            pkgSetting = Settings.createNewSetting(parsedPackage.getPackageName(),
                    originalPkgSetting, disabledPkgSetting, realPkgName, sharedUserSetting,
                    destCodeFile, parsedPackage.getNativeLibraryRootDir(),
                    AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage),
                    AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage),
                    parsedPackage.getVersionCode(), pkgFlags, pkgPrivateFlags, user,
                    true /*allowInstall*/, instantApp, virtualPreload,
                    UserManagerService.getInstance(), usesStaticLibraries,
                    parsedPackage.getUsesStaticLibrariesVersions(), parsedPackage.getMimeGroups(),
                    newDomainSetId);
        } else {
            // make a deep copy to avoid modifying any existing system state.
            pkgSetting = new PackageSetting(pkgSetting);
            pkgSetting.pkg = parsedPackage;

            // REMOVE SharedUserSetting from method; update in a separate call.
            //
            // TODO(narayan): This update is bogus. nativeLibraryDir & primaryCpuAbi,
            // secondaryCpuAbi are not known at this point so we always update them
            // to null here, only to reset them at a later point.
            Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, sharedUserSetting,
                    destCodeFile, parsedPackage.getNativeLibraryDir(),
                    AndroidPackageUtils.getPrimaryCpuAbi(parsedPackage, pkgSetting),
                    AndroidPackageUtils.getSecondaryCpuAbi(parsedPackage, pkgSetting),
                    PackageInfoUtils.appInfoFlags(parsedPackage, pkgSetting),
                    PackageInfoUtils.appInfoPrivateFlags(parsedPackage, pkgSetting),
                    UserManagerService.getInstance(),
                    usesStaticLibraries, parsedPackage.getUsesStaticLibrariesVersions(),
                    parsedPackage.getMimeGroups(), newDomainSetId);
        }

  如果pkgSetting存在共享用户,但是和sharedUserSetting不同,则会将pkgSetting = null。sharedUserSetting是来自解析包,如果不同,认为共享用户发生了变化,这个时候,将pkgSetting置为null,后面将建一个新的PackageSetting对象。
  parsedPackage.getUsesStaticLibraries()来自解析Apk文件AndroidManifest.xml时,"application"标签包裹内"uses-static-library"标签的属性值。这里将它们取出来放到usesStaticLibraries变量内。
  injector.getDomainVerificationManagerInternal()得到的是DomainVerificationService对象,调用它的generateNewId()生成一个UUID值newDomainSetId。
  如果pkgSetting == null,将createNewPackage置为true,代表需要新建一个PackageSetting对象。scanFlags如果存在SCAN_AS_INSTANT_APP或SCAN_AS_VIRTUAL_PRELOAD标识,会将变量instantApp和virtualPreload设置为true。这俩属性在创建新PackageSetting对象时,使用。然后从解析包对象parsedPackage中得到标识pkgFlags、私有标识pkgPrivateFlags。再接着就是调用Settings.createNewSetting()创建一个新的PackageSetting对象。
  如果它不为null,则会通过深copy新建一个PackageSetting对象。并且将解析包指定给它。接着又调用Settings.updatePackageSetting()来更新pkgSetting的对应值。

分段三

    继续看scanPackageOnlyLI()的第三段代码:

        if (createNewPackage && originalPkgSetting != null) {
            // This is the initial transition from the original package, so,
            // fix up the new package's name now. We must do this after looking
            // up the package under its new name, so getPackageLP takes care of
            // fiddling things correctly.
            parsedPackage.setPackageName(originalPkgSetting.name);

            // File a report about this.
            String msg = "New package " + pkgSetting.realName
                    + " renamed to replace old package " + pkgSetting.name;
            reportSettingsProblem(Log.WARN, msg);
        }

        final int userId = (user == null ? UserHandle.USER_SYSTEM : user.getIdentifier());
        // for existing packages, change the install state; but, only if it's explicitly specified
        if (!createNewPackage) {
            final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
            final boolean fullApp = (scanFlags & SCAN_AS_FULL_APP) != 0;
            setInstantAppForUser(injector, pkgSetting, userId, instantApp, fullApp);
        }
        // TODO(patb): see if we can do away with disabled check here.
        if (disabledPkgSetting != null
                || (0 != (scanFlags & SCAN_NEW_INSTALL)
                && pkgSetting != null && pkgSetting.isSystem())) {
            pkgSetting.getPkgState().setUpdatedSystemApp(true);
        }

        parsedPackage
                .setSeInfo(SELinuxMMAC.getSeInfo(parsedPackage, sharedUserSetting,
                        injector.getCompatibility()))
                .setSeInfoUser(SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState(
                        userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId)));

        if (parsedPackage.isSystem()) {
            configurePackageComponents(parsedPackage);
        }

  如果是新创建包,并且originalPkgSetting不为null,则将解析包的包名改为originalPkgSetting的包名。这可能发生在改包名的首次安装时。
  得到userId,默认为UserHandle.USER_SYSTEM。
  如果不是新创建包,会根据SCAN_AS_INSTANT_APP和SCAN_AS_FULL_APP标识,设置pkgSetting里面对应用户的状态。
  如果参数disabledPkgSetting不为null,或者scanFlags 存在SCAN_NEW_INSTALL标识,并且pkgSetting是系统包的情况下,会将pkgSetting的成员变量PackageStateUnserialized对象 pkgState的updatedSystemApp设置为true。什么时候会设置SCAN_NEW_INSTALL标识呢?它是在用户手动安装一个Apk的时候,会设置该标识。
  如果解析包parsedPackage是系统的,调用configurePackageComponents()来设置解析包里组件的enabled属性。

分段四

继续看scanPackageOnlyLI()的第四段代码:

        final String cpuAbiOverride = deriveAbiOverride(request.cpuAbiOverride);
        final boolean isUpdatedSystemApp = pkgSetting.getPkgState().isUpdatedSystemApp();

        final File appLib32InstallDir = getAppLib32InstallDir();
        if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
            if (needToDeriveAbi) {
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
                final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi =
                        packageAbiHelper.derivePackageAbi(parsedPackage, isUpdatedSystemApp,
                                cpuAbiOverride, appLib32InstallDir);
                derivedAbi.first.applyTo(parsedPackage);
                derivedAbi.second.applyTo(parsedPackage);
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

                // Some system apps still use directory structure for native libraries
                // in which case we might end up not detecting abi solely based on apk
                // structure. Try to detect abi based on directory structure.

                String pkgRawPrimaryCpuAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage);
                if (parsedPackage.isSystem() && !isUpdatedSystemApp
                        && pkgRawPrimaryCpuAbi == null) {
                    final PackageAbiHelper.Abis abis = packageAbiHelper.getBundledAppAbis(
                            parsedPackage);
                    abis.applyTo(parsedPackage);
                    abis.applyTo(pkgSetting);
                    final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
                            packageAbiHelper.deriveNativeLibraryPaths(parsedPackage,
                                    isUpdatedSystemApp, appLib32InstallDir);
                    nativeLibraryPaths.applyTo(parsedPackage);
                }
            } else {
                // This is not a first boot or an upgrade, don't bother deriving the
                // ABI during the scan. Instead, trust the value that was stored in the
                // package setting.
                parsedPackage.setPrimaryCpuAbi(primaryCpuAbiFromSettings)
                        .setSecondaryCpuAbi(secondaryCpuAbiFromSettings);

                final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
                        packageAbiHelper.deriveNativeLibraryPaths(parsedPackage,
                                isUpdatedSystemApp, appLib32InstallDir);
                nativeLibraryPaths.applyTo(parsedPackage);

                if (DEBUG_ABI_SELECTION) {
                    Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
                            parsedPackage.getPackageName() + " " +
                            AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage)
                            + ", "
                            + AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage));
                }
            }
        } else {
            if ((scanFlags & SCAN_MOVE) != 0) {
                // We haven't run dex-opt for this move (since we've moved the compiled output too)
                // but we already have this packages package info in the PackageSetting. We just
                // use that and derive the native library path based on the new codepath.
                parsedPackage.setPrimaryCpuAbi(pkgSetting.primaryCpuAbiString)
                        .setSecondaryCpuAbi(pkgSetting.secondaryCpuAbiString);
            }

            // Set native library paths again. For moves, the path will be updated based on the
            // ABIs we've determined above. For non-moves, the path will be updated based on the
            // ABIs we determined during compilation, but the path will depend on the final
            // package path (after the rename away from the stage path).
            final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
                    packageAbiHelper.deriveNativeLibraryPaths(parsedPackage, isUpdatedSystemApp,
                            appLib32InstallDir);
            nativeLibraryPaths.applyTo(parsedPackage);
        }

  cpuAbiOverride是从request.cpuAbiOverride里面得到的Abi,isUpdatedSystemApp则是代表是系统升级App。
  文件appLib32InstallDir的路径为"/data/app-lib"。
  下面要从scanFlags存不存在SCAN_NEW_INSTALL标识两种情况去讨论,SCAN_NEW_INSTALL是在用户手动安装APP的时候,会设置。
  1、scanFlags不存在SCAN_NEW_INSTALL标识,并且需要从解析包里得到Abi值
  会调用packageAbiHelper.derivePackageAbi()函数得到Pair对象值。packageAbiHelper.derivePackageAbi()其实主要是将本地库文件提取出来,并且确定解析包的主要、次要CPU ABI。可以进入这篇文件里面了解一下,Android 提取出Apk的本地库
  然后将Pair对象值应用到解析包。Pair的first是Abis对象,Pair的second是PackageAbiHelper.NativeLibraryPaths。看一下它俩的applyTo()方法:

Abis
public void applyTo(ParsedPackage pkg) {
            pkg.setPrimaryCpuAbi(primary)
                    .setSecondaryCpuAbi(secondary);
        }NativeLibraryPaths
        public void applyTo(ParsedPackage pkg) {
            pkg.setNativeLibraryRootDir(nativeLibraryRootDir)
                    .setNativeLibraryRootRequiresIsa(nativeLibraryRootRequiresIsa)
                    .setNativeLibraryDir(nativeLibraryDir)
                    .setSecondaryNativeLibraryDir(secondaryNativeLibraryDir);
        }        

  可以看到,解析包对象主要设置了它的primaryCpuAbi、secondaryCpuAbi、nativeLibraryRootDir、nativeLibraryRootRequiresIsa、nativeLibraryDir、secondaryNativeLibraryDir。
  如果设置完之后,parsedPackage的主CpuAbi依然为null,这个时候,会调用packageAbiHelper.getBundledAppAbis()通过Apk文件所在的目录结构结合系统支持的ABI来得到Abi。得到结果之后,应用到解析包和包设置对象中。最后packageAbiHelper.deriveNativeLibraryPaths()(该方法也在这篇文章有介绍)得到本地库的路径然后设置到解析包中。
  2、scanFlags不存在SCAN_NEW_INSTALL标识,并且不需要从解析包里得到Abi值。
  在这种情况下,解析包直接取primaryCpuAbiFromSettings、secondaryCpuAbiFromSettings的值,从前面我们知道,它俩的值是从包设置对象里面取得的。接着调用packageAbiHelper.deriveNativeLibraryPaths()得到本地库的路径然后设置到解析包中。
  3、scanFlags存在SCAN_NEW_INSTALL标识
  代表着有可能用户手动安装APP的。SCAN_MOVE代表是要移动一个安装包,这个时候,将parsedPackage的Abi设置成包设置里的。接着也是调用packageAbiHelper.deriveNativeLibraryPaths()得到本地库的路径然后设置到解析包中。 Android 安装应用-准备阶段 里面已经执行过这些步骤了,为什么在这里又执行了一遍呢?Android 安装应用-准备阶段 里面执行过之后,紧接着就进行了更改文件目录名的操作,所以这些个路径其实已经发生改变了,在这里又执行了一遍,就将路径名改对了。

分段五

继续看scanPackageOnlyLI()的第五段代码:

        // This is a special case for the "system" package, where the ABI is
        // dictated by the zygote configuration (and init.rc). We should keep track
        // of this ABI so that we can deal with "normal" applications that run under
        // the same UID correctly.
        if (isPlatformPackage) {
            parsedPackage.setPrimaryCpuAbi(VMRuntime.getRuntime().is64Bit() ?
                    Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0]);
        }
        // If there's a mismatch between the abi-override in the package setting
        // and the abiOverride specified for the install. Warn about this because we
        // would've already compiled the app without taking the package setting into
        // account.
        if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) {
            if (cpuAbiOverride == null) {
                Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride +
                        " for package " + parsedPackage.getPackageName());
            }
        }

        pkgSetting.primaryCpuAbiString = AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage);
        pkgSetting.secondaryCpuAbiString = AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage);
        pkgSetting.cpuAbiOverrideString = cpuAbiOverride;

        if (DEBUG_ABI_SELECTION) {
            Slog.d(TAG, "Resolved nativeLibraryRoot for " + parsedPackage.getPackageName()
                    + " to root=" + parsedPackage.getNativeLibraryRootDir()
                    + ", to dir=" + parsedPackage.getNativeLibraryDir()
                    + ", isa=" + parsedPackage.isNativeLibraryRootRequiresIsa());
        }

        // Push the derived path down into PackageSettings so we know what to
        // clean up at uninstall time.
        pkgSetting.legacyNativeLibraryPathString = parsedPackage.getNativeLibraryRootDir();

        if (DEBUG_ABI_SELECTION) {
            Log.d(TAG, "Abis for package[" + parsedPackage.getPackageName() + "] are"
                    + " primary=" + pkgSetting.primaryCpuAbiString
                    + " secondary=" + pkgSetting.primaryCpuAbiString
                    + " abiOverride=" + pkgSetting.cpuAbiOverrideString);
        }

        if ((scanFlags & SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
            // We don't do this here during boot because we can do it all
            // at once after scanning all existing packages.
            //
            // We also do this *before* we perform dexopt on this package, so that
            // we can avoid redundant dexopts, and also to make sure we've got the
            // code and package path correct.
            changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.sharedUser, parsedPackage,
                    packageAbiHelper.getAdjustedAbiForSharedUser(
                            pkgSetting.sharedUser.packages, parsedPackage));
        }

        parsedPackage.setFactoryTest(isUnderFactoryTest && parsedPackage.getRequestedPermissions()
                .contains(android.Manifest.permission.FACTORY_TEST));

        if (parsedPackage.isSystem()) {
            pkgSetting.setIsOrphaned(true);
        }

  如果是平台包,根据虚拟机是不是64位,将平台包的主Cpu ABI设置为系统支持的64位或32位的数组的第一序列的值。
  设置SCAN_NO_DEX是为了跳过dexopt。
  接着设置了包设置对象pkgSetting的主要、次要ABI为解析包里的主要次要ABI。并将pkgSetting.cpuAbiOverrideString = cpuAbiOverride。
  接着会将解析包的本地库文件的根目录,设置到包设置对象的legacyNativeLibraryPathString属性中。
  在不是启动的过程(SCAN_BOOTING代表系统启动)中,并且包设置对象pkgSetting的共享用户不为null的情况下,先调用packageAbiHelper.getAdjustedAbiForSharedUser(pkgSetting.sharedUser.packages, parsedPackage) 得到共享用户下包需要调整的ABI,接着调用applyAdjustedAbiToSharedUser()会找到共享用户下的包们主要CPU ABI为null的包,将包的getPath()放入changedAbiCodePath中。
  接着设置解析包的FACTORY_TEST标识。它是由系统处于的工程测试模式打开 和解析包中权限包含android.Manifest.permission.FACTORY_TEST共同确定的。
  如果解析包是系统的,会设置包设置对象setIsOrphaned(true)。

得到共享用户下包需要调整的ABI

  packageAbiHelper是PackageAbiHelperImpl实例,先看一下PackageAbiHelperImpl的getAdjustedAbiForSharedUser():

    /**
     * Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
     * i.e, so that all packages can be run inside a single process if required.
     *
     * Optionally, callers can pass in a parsed package via {@code newPackage} in which case
     * this function will either try and make the ABI for all packages in
     * {@code packagesForUser} match {@code scannedPackage} or will update the ABI of
     * {@code scannedPackage} to match the ABI selected for {@code packagesForUser}. This
     * variant is used when installing or updating a package that belongs to a shared user.
     *
     * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
     * adds unnecessary complexity.
     */
    @Override
    @Nullable
    public String getAdjustedAbiForSharedUser(
            Set<PackageSetting> packagesForUser, AndroidPackage scannedPackage) {
        String requiredInstructionSet = null;
        if (scannedPackage != null) {
            String pkgRawPrimaryCpuAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(scannedPackage);
            if (pkgRawPrimaryCpuAbi != null) {
                requiredInstructionSet = VMRuntime.getInstructionSet(pkgRawPrimaryCpuAbi);
            }
        }

        PackageSetting requirer = null;
        for (PackageSetting ps : packagesForUser) {
            // If packagesForUser contains scannedPackage, we skip it. This will happen
            // when scannedPackage is an update of an existing package. Without this check,
            // we will never be able to change the ABI of any package belonging to a shared
            // user, even if it's compatible with other packages.
            if (scannedPackage != null && scannedPackage.getPackageName().equals(ps.name)) {
                continue;
            }
            if (ps.primaryCpuAbiString == null) {
                continue;
            }

            final String instructionSet =
                    VMRuntime.getInstructionSet(ps.primaryCpuAbiString);
            if (requiredInstructionSet != null && !requiredInstructionSet.equals(instructionSet)) {
                // We have a mismatch between instruction sets (say arm vs arm64) warn about
                // this but there's not much we can do.
                String errorMessage = "Instruction set mismatch, "
                        + ((requirer == null) ? "[caller]" : requirer)
                        + " requires " + requiredInstructionSet + " whereas " + ps
                        + " requires " + instructionSet;
                Slog.w(PackageManagerService.TAG, errorMessage);
            }

            if (requiredInstructionSet == null) {
                requiredInstructionSet = instructionSet;
                requirer = ps;
            }
        }

        if (requiredInstructionSet == null) {
            return null;
        }
        final String adjustedAbi;
        if (requirer != null) {
            // requirer != null implies that either scannedPackage was null or that
            // scannedPackage did not require an ABI, in which case we have to adjust
            // scannedPackage to match the ABI of the set (which is the same as
            // requirer's ABI)
            adjustedAbi = requirer.primaryCpuAbiString;
        } else {
            // requirer == null implies that we're updating all ABIs in the set to
            // match scannedPackage.
            adjustedAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(scannedPackage);
        }
        return adjustedAbi;
    }

  先取到解析包的主要ABI对应的指令集requiredInstructionSet。
  接着循环包设置对象集合packagesForUser,如果解析包不为null,并且包名和当前循环的包名相等,就直接跳出,进行下次循环。
  如果循环的包设置的主要ABI为null,就进行下次循环。
  接下来,如果解析包的指令集为null,找到第一个主要ABI不为null的包设置对象,在解析包的主要指令为null的情况下,将解析包的指令设置给requiredInstructionSet变量,将包对象设置为requirer。
  接着判断requirer不为null,其实就是取值为循环包设置集合里面第一个ABI不为null的包设置对象的ABI。
  如果requirer为null,取值就是解析包的主要ABI。
  其实它这个方法,主要就是解析包的主要ABI存在,就取解析包的主要ABI;如果不存在,就去包设置集合里面寻找第一个主要ABI不为null的包设置的主要ABI。

得到共享用户中包需要修改ABI的包的路径

    /**
     * Applies the adjusted ABI calculated by
     * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, AndroidPackage)} to all
     * relevant packages and settings.
     * @param sharedUserSetting The {@code SharedUserSetting} to adjust
     * @param scannedPackage the package being scanned or null
     * @param adjustedAbi the adjusted ABI calculated by {@link PackageAbiHelper}
     * @return the list of code paths that belong to packages that had their ABIs adjusted.
     */
    private static List<String> applyAdjustedAbiToSharedUser(SharedUserSetting sharedUserSetting,
            ParsedPackage scannedPackage, String adjustedAbi) {
        if (scannedPackage != null)  {
            scannedPackage.setPrimaryCpuAbi(adjustedAbi);
        }
        List<String> changedAbiCodePath = null;
        for (PackageSetting ps : sharedUserSetting.packages) {
            if (scannedPackage == null || !scannedPackage.getPackageName().equals(ps.name)) {
                if (ps.primaryCpuAbiString != null) {
                    continue;
                }

                ps.primaryCpuAbiString = adjustedAbi;
                if (ps.pkg != null) {
                    if (!TextUtils.equals(adjustedAbi,
                            AndroidPackageUtils.getRawPrimaryCpuAbi(ps.pkg))) {
                        if (DEBUG_ABI_SELECTION) {
                            Slog.i(TAG,
                                    "Adjusting ABI for " + ps.name + " to " + adjustedAbi
                                            + " (scannedPackage="
                                            + (scannedPackage != null ? scannedPackage : "null")
                                            + ")");
                        }
                        if (changedAbiCodePath == null) {
                            changedAbiCodePath = new ArrayList<>();
                        }
                        changedAbiCodePath.add(ps.getPathString());
                    }
                }
            }
        }
        return changedAbiCodePath;
    }

  解析包不为null,直接设置解析包的主要ABI。
  接着就是在循环中寻找,包名和解析包的包名不同的情况下,包设置的主要ABI为null的包设置对象,并且会将包设置对象的主要ABI设置为调整的ABI adjustedAbi。然后检查包设置对象的解析包对象的ABI和调整的ABI不同,就会将包设置对象的getPathString()添加到结果集合中。

分段六

  继续看scanPackageOnlyLI()的最后一段代码:

        // Take care of first install / last update times.
        final long scanFileTime = getLastModifiedTime(parsedPackage);
        if (currentTime != 0) {
            if (pkgSetting.firstInstallTime == 0) {
                pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime;
            } else if ((scanFlags & SCAN_UPDATE_TIME) != 0) {
                pkgSetting.lastUpdateTime = currentTime;
            }
        } else if (pkgSetting.firstInstallTime == 0) {
            // We need *something*.  Take time time stamp of the file.
            pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = scanFileTime;
        } else if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0) {
            if (scanFileTime != pkgSetting.timeStamp) {
                // A package on the system image has changed; consider this
                // to be an update.
                pkgSetting.lastUpdateTime = scanFileTime;
            }
        }
        pkgSetting.setTimeStamp(scanFileTime);
        // TODO(b/135203078): Remove, move to constructor
        pkgSetting.pkg = parsedPackage;
        pkgSetting.pkgFlags = PackageInfoUtils.appInfoFlags(parsedPackage, pkgSetting);
        pkgSetting.pkgPrivateFlags =
                PackageInfoUtils.appInfoPrivateFlags(parsedPackage, pkgSetting);
        if (parsedPackage.getLongVersionCode() != pkgSetting.versionCode) {
            pkgSetting.versionCode = parsedPackage.getLongVersionCode();
        }
        // Update volume if needed
        final String volumeUuid = parsedPackage.getVolumeUuid();
        if (!Objects.equals(volumeUuid, pkgSetting.volumeUuid)) {
            Slog.i(PackageManagerService.TAG,
                    "Update" + (pkgSetting.isSystem() ? " system" : "")
                    + " package " + parsedPackage.getPackageName()
                    + " volume from " + pkgSetting.volumeUuid
                    + " to " + volumeUuid);
            pkgSetting.volumeUuid = volumeUuid;
        }

        SharedLibraryInfo staticSharedLibraryInfo = null;
        if (!TextUtils.isEmpty(parsedPackage.getStaticSharedLibName())) {
            staticSharedLibraryInfo =
                    AndroidPackageUtils.createSharedLibraryForStatic(parsedPackage);
        }
        List<SharedLibraryInfo> dynamicSharedLibraryInfos = null;
        if (!ArrayUtils.isEmpty(parsedPackage.getLibraryNames())) {
            dynamicSharedLibraryInfos = new ArrayList<>(parsedPackage.getLibraryNames().size());
            for (String name : parsedPackage.getLibraryNames()) {
                dynamicSharedLibraryInfos.add(
                        AndroidPackageUtils.createSharedLibraryForDynamic(parsedPackage, name));
            }
        }

        return new ScanResult(request, true, pkgSetting, changedAbiCodePath,
                !createNewPackage /* existingSettingCopied */, staticSharedLibraryInfo,
                dynamicSharedLibraryInfos);
    }

  处理包设置对象的firstInstallTime、lastUpdateTime。
  这里注意这一点,在这里将包设置对象的pkg设置为解析包对象parsedPackage。
  将包设置对象和解析包对象的Flags合并赋值给包设置对象的pkgFlags。
  将解析包对象的PrivateFlags合并赋值给包设置对象的pkgPrivateFlags。
  如果解析包对象的版本和包设置对象的版本不同,将包设置对象的版本改为解析包对象的版本。
  如果解析包对象的版本和包设置对象的volumeUuid不同,将pkgSetting.volumeUuid = volumeUuid。
  如果解析包对象里面如果配置了静态库,则生成静态库对象staticSharedLibraryInfo。
  如果解析包对象里面如果配置了动态库,则生成动态库对象添加到dynamicSharedLibraryInfos。
  最后将相关信息封装到ScanResult对象返回。封装的内容包括生成的ScanRequest对象,成功结果true、新生成的PackageSetting对象pkgSetting、共享用户中其他修改了ABI的文件路径、是否是深拷贝存在的PackageSetting对象、静态分享库信息、动态分享库信息。

总结

  根据标识调整浏览标识,设置解析包的状态,也会检查一些状态。
  将相关内容封装到ScanRequest对象中,包括解析包对象、共享用户对象、旧安装包对象、现在使用PackageSetting对象、禁止的系统PackageSetting对象、旧PackageSetting对象(改包名之前)、真包名、解析标识、浏览标识、是否是系统平台包、用户、CPU ABI参数。
  创建了一个新的PackageSetting对象(可能是直接new,也可能深copy现在使用的PackageSetting对象)。
  如果是系统第一次启动或者系统更新之后第一次启动时,需要去安装包里得到主要CPU ABI和次要CPU ABI,本地库解析的路径,提取本地库文件(能否提取需要判断)。如果不是,它的主要CPU ABI和次要CPU ABI取值是在生成PackageSetting对象时定的,但它会重新确定本地库解析的路径。
  最后将生成的ScanRequest对象,成功结果true、新生成的PackageSetting对象pkgSetting、共享用户中其他修改了ABI的文件路径、是否是深拷贝存在的PackageSetting对象、静态分享库信息、动态分享库信息,封装成ScanResult对象返回。

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值