Android APK安装流程(4)--APK加载

  • 第8步 APK加载

上面主要分析到APK的copy过程,这里我们开始分析APK的加载过程。直接看之前流程进行到下一步的processPendingInstall()方法:

    private void processPendingInstall(final InstallArgs args, final int currentStatus) {
        if (args.mMultiPackageInstallParams != null) {
            args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
        } else {
            //***1***
            PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
            //***2***
            processInstallRequestsAsync(
                    res.returnCode == PackageManager.INSTALL_SUCCEEDED,
                    Collections.singletonList(new InstallRequest(args, res)));
        }
    }


    // Queue up an async operation since the package installation may take a little while.
    private void processInstallRequestsAsync(boolean success,  List installRequests) {
        mHandler.post(() -> {
            if (success) {
                for (InstallRequest request : installRequests) {
                    //***3***
                    request.args.doPreInstall(request.installResult.returnCode);
                }
                synchronized (mInstallLock) {
                    //***4*** 核心流程
                    installPackagesTracedLI(installRequests);
                }
                for (InstallRequest request : installRequests) {
                    //**5***
                    request.args.doPostInstall(
                            request.installResult.returnCode, request.installResult.uid);
                }
            }
            for (InstallRequest request : installRequests) {
                //***6***
                restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
                        new PostInstallData(request.args, request.installResult, null));
            }
        });
    }
  • 1.InstallArgs.doPreInstall()方法(FileInstallArgs对象)主要是对安装失败时清除安装过程中的临时文件的处理:
        #FileInstallArgs
        int doPreInstall(int status) {
            if (status != PackageManager.INSTALL_SUCCEEDED) {
                //***7***
                cleanUp();
            }
            return status;
        }


        private boolean cleanUp() {
            if (codeFile == null || !codeFile.exists()) {
                return false;
            }
            //***8***
            removeCodePathLI(codeFile);

            if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {
                resourceFile.delete();
            }

            return true;
        }


        @GuardedBy("mInstallLock")
        void removeCodePathLI(File codePath) {
            if (codePath.isDirectory()) {
                try {
                    //***9***
                    mInstaller.rmPackageDir(codePath.getAbsolutePath());
                } catch (InstallerException e) {
                    Slog.w(TAG, "Failed to remove code path", e);
                }
            } else {
                codePath.delete();
            }
        }

    #Installer
    public void rmPackageDir(String packageDir) throws InstallerException {
        if (!checkBeforeRemote()) return;
        BlockGuard.getVmPolicy().onPathAccess(packageDir);
        try {
            //***10***
            mInstalld.rmPackageDir(packageDir);
        } catch (Exception e) {
            throw InstallerException.from(e);
        }
    }
  • 2.installPackagesTracedLI()扫描安装apk包,这个是核心流程:
    #PackageManagerService
    @GuardedBy({"mInstallLock", "mPackages"})
    private void installPackagesTracedLI(List requests) {
        try {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
            //***11***
            installPackagesLI(requests);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }

    /**
     * Installs one or more packages atomically. This operation is broken up into four phases:
     * 
    *
  • Prepare *
    Analyzes any current install state, parses the package and does initial * validation on it.
  • *
  • Scan *
    Interrogates the parsed packages given the context collected in prepare.
  • *
  • Reconcile *
    Validates scanned packages in the context of each other and the current system * state to ensure that the install will be successful. *
  • Commit *
    Commits all scanned packages and updates system state. This is the only place * that system state may be modified in the install flow and all predictable errors * must be determined before this phase.
  • *
* * Failure at any phase will result in a full failure to install all packages. */ @GuardedBy("mInstallLock") private void installPackagesLI(List requests) { ... for (InstallRequest request : requests) { // TODO(b/109941548): remove this once we've pulled everything from it and into // scan, reconcile or commit. final PrepareResult prepareResult; try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage"); //***12*** 准备阶段 prepareResult = preparePackageLI(request.args, request.installResult); } catch (PrepareFailure prepareFailure) { ... } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } ... try { //***13*** 扫描解析阶段 final List scanResults = scanPackageTracedLI( prepareResult.packageToScan, prepareResult.parseFlags, prepareResult.scanFlags, System.currentTimeMillis(), request.args.user); ... } catch (PackageManagerException e) { request.installResult.setError("Scanning Failed.", e); return; } } //整合验证阶段 ... synchronized (mPackages) { Map reconciledPackages; try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages"); //***14*** reconciledPackages = reconcilePackagesLocked( reconcileRequest, mSettings.mKeySetManagerService); } catch (ReconcileFailure e) { ... } //确认提交阶段 try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages"); commitRequest = new CommitRequest(reconciledPackages, sUserManager.getUserIds()); //***15*** commitPackagesLocked(commitRequest); success = true; } finally { for (PrepareResult result : prepareResults.values()) { if (result.freezer != null) { result.freezer.close(); } } Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } //***16*** executePostCommitSteps(commitRequest); } finally { if (!success) { for (ScanResult result : preparedScans.values()) { if (createdAppId.getOrDefault(result.request.pkg.packageName, false)) { //***17*** cleanUpAppIdCreation(result); } } // TODO(patb): create a more descriptive reason than unknown in future release // mark all non-failure installs as UNKNOWN so we do not treat them as success for (InstallRequest request : requests) { if (request.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) { request.installResult.returnCode = PackageManager.INSTALL_UNKNOWN; } } } for (PrepareResult result : prepareResults.values()) { if (result.freezer != null) { result.freezer.close(); } } Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } }

installPackagesLI()可以支持单包和多包加载,加载主要分为4个阶段:

  • 2-1.准备阶段:分析任何当前安装状态,解析包并对其进行初始验证。
    # PackageManagerService
    @GuardedBy("mInstallLock")
    private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
            throws PrepareFailure {
        ...
        final PackageParser.Package pkg;
        try {
            //***18*** 
            pkg = pp.parsePackage(tmpPackageFile, parseFlags);
            //***19*** 
            DexMetadataHelper.validatePackageDexMetadata(pkg);
        } catch (PackageParserException e) {
            throw new PrepareFailure("Failed parse during installPackageLI", e);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    
        // Instant apps have several additional install-time checks.
        if (instantApp) {
            ...
        }
    
        if (pkg.applicationInfo.isStaticSharedLibrary()) {
            // Static shared libraries have synthetic package names
            //***20***
            renameStaticSharedLibraryPackage(pkg);
            ...
        }
    
        // If we are installing a clustered package add results for the children
        if (pkg.childPackages != null) {
            ...
        }
    
        // If package doesn't declare API override, mark that we have an install
        // time CPU ABI override.
        if (TextUtils.isEmpty(pkg.cpuAbiOverride)) {
            pkg.cpuAbiOverride = args.abiOverride;
        }
    
        ...
        try {
            // either use what we've been given or parse directly from the APK
            if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
                pkg.setSigningDetails(args.signingDetails);
            } else {
                //***21**** 设置签名文件
                PackageParser.collectCertificates(pkg, false /* skipVerify */);
            }
        } catch (PackageParserException e) {
            throw new PrepareFailure("Failed collect during installPackageLI", e);
        }
    
            ...
            //***22***
            PackageSetting ps = mSettings.mPackages.get(pkgName);
            if (ps != null) {
                if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
    
                // Static shared libs have same package with different versions where
                // we internally use a synthetic package name to allow multiple versions
                // of the same package, therefore we need to compare signatures against
                // the package setting for the latest library version.
                PackageSetting signatureCheckPs = ps;
                if (pkg.applicationInfo.isStaticSharedLibrary()) {
                    SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(pkg);
                    if (libraryInfo != null) {
                        signatureCheckPs = mSettings.getPackageLPr(libraryInfo.getPackageName());
                    }
                }
    
                // Quick sanity check that we're signed correctly if updating;
                // we'll check this again later when scanning, but we want to
                // bail early here before tripping over redefined permissions.
                final KeySetManagerService ksms = mSettings.mKeySetManagerService;
                if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
                    ...
                } else {
                    ...
                }
    
                if (ps.pkg != null && ps.pkg.applicationInfo != null) {
                    systemApp = (ps.pkg.applicationInfo.flags &
                            ApplicationInfo.FLAG_SYSTEM) != 0;
                }
                res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
            }
    
    
            int N = pkg.permissions.size();
            for (int i = N - 1; i >= 0; i--) {
                //***23***
                final PackageParser.Permission perm = pkg.permissions.get(i);
                final BasePermission bp =
                        (BasePermission) mPermissionManager.getPermissionTEMP(perm.info.name);
    
                // Don't allow anyone but the system to define ephemeral permissions.
                if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
                        && !systemApp) {
                    ...
                }
    
                // Check whether the newly-scanned package wants to define an already-defined perm
                if (bp != null) {
                    // If the defining package is signed with our cert, it's okay.  This
                    // also includes the "updating the same package" case, of course.
                    // "updating same package" could also involve key-rotation.
                    final boolean sigsOk;
                    final String sourcePackageName = bp.getSourcePackageName();
                    final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting();
                    final KeySetManagerService ksms = mSettings.mKeySetManagerService;
                    if (sourcePackageName.equals(pkg.packageName)
                            && (ksms.shouldCheckUpgradeKeySetLocked(
                            sourcePackageSetting, scanFlags))) {
                        sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg);
                    } else {
    
                        // in the event of signing certificate rotation, we need to see if the
                        // package's certificate has rotated from the current one, or if it is an
                        // older certificate with which the current is ok with sharing permissions
                        if (sourcePackageSetting.signatures.mSigningDetails.checkCapability(
                                pkg.mSigningDetails,
                                PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
                            sigsOk = true;
                        } else if (pkg.mSigningDetails.checkCapability(
                                sourcePackageSetting.signatures.mSigningDetails,
                                PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
    
                            // the scanned package checks out, has signing certificate rotation
                            // history, and is newer; bring it over
                            ...
                    }
                    if (!sigsOk) {
                        // If the owning package is the system itself, we log but allow
                        // install to proceed; we fail the install on all other permission
                        // redefinitions.
                        ...
                    } else if (!PLATFORM_PACKAGE_NAME.equals(pkg.packageName)) {
                        // Prevent apps to change protection level to dangerous from any other
                        // type as this would allow a privilege escalation where an app adds a
                        // normal/signature permission in other app's group and later redefines
                        // it as dangerous leading to the group auto-grant.
                        ...
                    }
                }
            }
        }
    
        if (systemApp) {
            ...
        }
    
        if (args.move != null) {
            // We did an in-place move, so dex is ready to roll
            ...
    
        } else {
            // Enable SCAN_NO_DEX flag to skip dexopt at a later stage
            scanFlags |= SCAN_NO_DEX;
    
            try {
                String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
                        args.abiOverride : pkg.cpuAbiOverride);
                final boolean extractNativeLibs = !pkg.isLibrary();
                derivePackageAbi(pkg, abiOverride, extractNativeLibs);
            } catch (PackageManagerException pme) {
                Slog.e(TAG, "Error deriving application ABI", pme);
                throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
                        "Error deriving application ABI");
            }
        }
        //***24***
        //在这里存在两种路径,一种是变化前的路径,名字为/data/app/vmdlsessionId/base.apk,
        //另一种是安装后的路径,通过getNextCodePath()方法获得
        if (!args.doRename(res.returnCode, pkg)) {
            throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
        }
    
        try {
            //***25***
            setUpFsVerityIfPossible(pkg);
        } catch (InstallerException | IOException | DigestException | NoSuchAlgorithmException e) {
            throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
                    "Failed to set up verity: " + e);
        }
    
        if (!instantApp) {
            //***26***
            startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
        } else {
            if (DEBUG_DOMAIN_VERIFICATION) {
                Slog.d(TAG, "Not verifying instant app install for app links: " + pkgName);
            }
        }
        //***27***
        final PackageFreezer freezer =
                freezePackageForInstall(pkgName, installFlags, "installPackageLI");
        boolean shouldCloseFreezerBeforeReturn = true;
        try {
             ...
             //***28***
            if (replace) {
                targetVolumeUuid = null;
                if (pkg.applicationInfo.isStaticSharedLibrary()) {
                    // Static libs have a synthetic package name containing the version
                    // and cannot be updated as an update would get a new package name,
                    // unless this is the exact same version code which is useful for
                    // development.
                    ...
                }
                ...
                synchronized (mPackages) {
                    ...
    
                    // verify signatures are valid
                    final KeySetManagerService ksms = mSettings.mKeySetManagerService;
                    if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
                       ...
                    } else {
                        // default to original signature matching
                        ...
                    }
    
                    // don't allow a system upgrade unless the upgrade hash matches
                    if (oldPackage.restrictUpdateHash != null && oldPackage.isSystem()) {
                        ...
                        // retain upgrade restriction
                        pkg.restrictUpdateHash = oldPackage.restrictUpdateHash;
                    }
    
                    // Check for shared user id changes
                    ...
    
                    // In case of rollback, remember per-user/profile install state
                    ...
    
                    // don't allow an upgrade from full to ephemeral
                    if (isInstantApp) {
                        ...
                        } else if (!ps.getInstantApp(args.user.getIdentifier())) {
                            // can't downgrade from full to instant
                            ...
                        }
                    }
                }
    
                // Update what is removed
                ...
                for (int i = 0; i < installedUsers.length; i++) {
                    final int userId = installedUsers[i];
                    res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId));
                }
    
                childPackages = mSettings.getChildSettingsLPr(ps);
                if (childPackages != null) {
                    ...
                }
    
    
                sysPkg = (isSystemApp(oldPackage));
                if (sysPkg) {
                    // Set the system/privileged/oem/vendor/product flags as needed
                    ...
                } else { // non system replace
                    replace = true;
                    ...
                }
            } else { // new package install
                ...
                // Remember this for later, in case we need to rollback this install
                String pkgName1 = pkg.packageName;
                ...
                synchronized (mPackages) {
                    renamedPackage = mSettings.getRenamedPackageLPr(pkgName1);
                    if (renamedPackage != null) {
                        // A package with the same name is already installed, though
                        // it has been renamed to an older name.  The package we
                        // are trying to install should be installed as an update to
                        // the existing one, but that has not been requested, so bail.
                        ...
                    }
                    if (mPackages.containsKey(pkgName1)) {
                        // Don't allow installation over an existing package with the same name.
                        ...
                }
            }
            // we're passing the freezer back to be closed in a later phase of install
            shouldCloseFreezerBeforeReturn = false;
            //***29***
            return new PrepareResult(args.installReason, targetVolumeUuid, installerPackageName,
                    args.user, replace, targetScanFlags, targetParseFlags, existingPackage, pkg,
                    replace /* clearCodeCache */, sysPkg, renamedPackage, freezer,
                    ps, disabledPs, childPackages);
        } finally {
            if (shouldCloseFreezerBeforeReturn) {
                freezer.close();
            }
        }
    }
    
    准备阶段的方法很长,主要做了以下几个事情:
    2-1-1.PackageParser.parsePackage 扫描apk包中完整的AndroidManifest.xml内容,并把解析的package结果缓存到磁盘和内存中(//***18***)。
    2-1-2.往Package对象中设置好签名信息(//***21***)。
    2-1-3.从Settings中获取是否有当前包名对应的PackageSetting 包配置信息,此时还没有则跳开这里的if。获取PermissionManagerService查询权限信息。如果还是能查到,说明是包的升级,此时会进行包权限的校验。判断前后两次是不是内部包含的包权限内容都是一致,而只是顺序变了。当然如果之前没有安装,或者内容不一致,都会触发KeySetManagerService的checkUpgradeKeySetLocked进行更新(//***22***)。
    2-1-4.调用InstallArgs.doRename 把当前的包的名字给更新了(//***24***)。
    2-1-5.判断当前是否允许对包进行校验,如果允许则调用VerityUtils.generateApkVeritySetupData()对包的签名进行校验,校验通过根路径则调用Installd服务进一步调用installApkVerity进行校验,详细可以看setUpFsVerityIfPossible()方法(//***25***)。
    2-1-6.返回PrepareResult(//***29***)
    具体详细流程:
    1 准备scanflags: move 表示已经初始化过,添加SCAN_INITIAL标志, 不需要杀掉添加 SCAN_DONT_KILL_APP, instantApp 为SCAN_AS_INSTANT_APP, fullApp 为 SCAN_AS_FULL_APP, virtualPreload 虚拟预加载SCAN_AS_VIRTUAL_PRELOAD
    2 instant app 不能安装在外置存储
    3 pp.parsePackage(tmpPackageFile, parseFlags) 解析, DexMetadataHelper.validatePackageDexMetadata(pkg) 验证dm文件
    4 instantApp 验证, targetSdkVersion不能小于o, 不能是isharedUid
    5 静态库修改包名,包名添加上version信息,方便安装多版本库
    6 子包的处理
    7 cpuAbiOverride 处理, 如果安装选项设置了使用安装选项覆盖
    8 TEST_ONLY app 应用判断是否可以安装, 没有-t选项不允许安装
    9 判断是否是replace安装
     9.1 包含original-package使用旧包名验证是否安装过
     9.2 非original-package使用包名看下是否安装过
     9.3 子包禁止安装
     9.4 替换安装情况下, targetSdk 范围检查
     9.5 禁止PERSISTENT 非 stage安装(因为可能会导致persistent被杀)
     9.6 禁止子包安装
    10 替换安装情况对签名进行检查
    11 权限处理
     11.1 除了系统应用之外不允许定义PROTECTION_FLAG_INSTANT级别的权限
     11.2 对于要更新的权限执行以下操作
      11.2.1 如果是应用升级则并且有升级key限制则验证
      11.2.2 没有升级key限制则验证证书匹配才可以升级权限
      11.2.3 非PLATFORM_PACKAGE_NAME禁止签名不同升级权限
      11.2.4 PROTECTION_DANGEROUS 权限禁止修改(降低) 保护级别
    12 系统应用禁止是instantApp,禁止安装在外置存储
    13 abi的处理
     13.1 move 应用安装位置,直接设置primaryCpuAbi 和 secondaryCpuAbi
     13.2 非move应用 derivePackageAbi
    14 修改包名
    15 fsverify
    16 startIntentFilterVerifications
    17 创建 freezer 禁止启动
    19 替换安装情况
     19.1 静态库禁止同版本升级
     19.2 再次验证签名
     19.3 验证系统应用升级的restrict-update
     19.4 检查shareduid是否变化
     19.5 禁止fullapp -> instant app 安装
     19.6 设置更新后被移除的子包
     19.7 系统包根据旧包设置targetParseFlags targetScanFlags, 设置setApplicationInfoFlags位FLAG_UPDATED_SYSTEM_APP
    20 非替换安装情况(新安装)
     20.1 没有指定INSTALL_REPLACE_EXISTING 禁止非替换安装
    21 创建 PrepareResult返回
  • 2-2.扫描解析阶段:根据准备阶段中收集的上下文对包进行解析,主要用于生成PackageSetting数据结构。调用scanPackageTracedLI()扫描包内容,此时其实已经解析过一次包内容,在这里能直接获得缓存。

    #PackageManagerService
    @GuardedBy({"mInstallLock", "mPackages"})
    private List scanPackageTracedLI(PackageParser.Package pkg,
            final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
            @Nullable UserHandle user) throws PackageManagerException {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
        // If the package has children and this is the first dive in the function
        // we recursively scan the package with the SCAN_CHECK_ONLY flag set to see
        // whether all packages (parent and children) would be successfully scanned
        // before the actual scan since scanning mutates internal state and we want
        // to atomically install the package and its children.
        if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
            if (pkg.childPackages != null && pkg.childPackages.size() > 0) {
                scanFlags |= SCAN_CHECK_ONLY;
            }
        } else {
            scanFlags &= ~SCAN_CHECK_ONLY;
        }
    
        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
        final List scanResults = new ArrayList<>(1 + childCount);
        try {
            // Scan the parent 
            //***30***
            scanResults.add(scanPackageNewLI(pkg, parseFlags, scanFlags, currentTime, user));
            // Scan the children
            for (int i = 0; i < childCount; i++) {
                PackageParser.Package childPkg = pkg.childPackages.get(i);
                //***31***
                scanResults.add(scanPackageNewLI(childPkg, parseFlags,
                        scanFlags, currentTime, user));
            }
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    
        if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
            //***32***
            return scanPackageTracedLI(pkg, parseFlags, scanFlags, currentTime, user);
        }
    
        return scanResults;
    }
    
    
    @GuardedBy({"mInstallLock", "mPackages"})
    private ScanResult scanPackageNewLI(@NonNull PackageParser.Package pkg,
            final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
            @Nullable UserHandle user) throws PackageManagerException {
    
        final String renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
        final String realPkgName = getRealPackageName(pkg, renamedPkgName);
        if (realPkgName != null) {
            //***33***
            ensurePackageRenamed(pkg, renamedPkgName);
        }
        final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName);
        final PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.packageName);
        final PackageSetting disabledPkgSetting =
                mSettings.getDisabledSystemPkgLPr(pkg.packageName);
    
        if (mTransferedPackages.contains(pkg.packageName)) {
            Slog.w(TAG, "Package " + pkg.packageName
                    + " was transferred to another, but its .apk remains");
        }
        //***34***
        scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, pkg);
        synchronized (mPackages) {
            applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
            assertPackageIsValid(pkg, parseFlags, scanFlags);
    
            SharedUserSetting sharedUserSetting = null;
            if (pkg.mSharedUserId != null) {
                // SIDE EFFECTS; may potentially allocate a new shared user
                sharedUserSetting = mSettings.getSharedUserLPw(
                        pkg.mSharedUserId, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/);
                if (DEBUG_PACKAGE_SCANNING) {
                    if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
                        Log.d(TAG, "Shared UserID " + pkg.mSharedUserId
                                + " (uid=" + sharedUserSetting.userId + "):"
                                + " packages=" + sharedUserSetting.packages);
                }
            }
            final ScanRequest request = new ScanRequest(pkg, sharedUserSetting,
                    pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
                    originalPkgSetting, realPkgName, parseFlags, scanFlags,
                    (pkg == mPlatformPackage), user);
            //***35***
            return scanPackageOnlyLI(request, mFactoryTest, currentTime);
        }
    }
    

    扫描解析阶段的代码流程其实也挺长,具体细节如下:

    1. 对于包含child的包,先check扫描一遍,再非check扫描一遍
    2. 不包含child的包直接非check扫描一遍
    3. 扫描函数scanPackageNewLI()
        1. adjustScanFlags()
          1. 如果覆盖安装系统应用设置系统相关的扫描属性
          2. 如果instant安装设置 SCAN_AS_INSTANT_APP, 如果 VirtulalPreload设置 SCAN_AS_VIRTUAL_PRELOAD
          3. 如果签名是系统签名,并且shareduid 是privleged的,并且要安装的应用签名和平台签名一致,设置 SCAN_AS_PRIVILEGED(这相当于一种权限提升呀)
        2. applyPolicy() 这一步根据scanFlags设置pkg.applicationInfo下的标志和 四大组件的标志
        1. 系统应用设置
         1. directBootAware 设置所有组件的directBootAware标志
         2. 如果是stub安装设置 pkg.isStub = true
        2. 非系统应用删除一些特权flags,设置降低权限组优先级,pkg.permissionGroups.get(i).info.priority
        3. 非SCAN_AS_PRIVILEGED app
         1. pkg.protectedBroadcasts = null
         2. 不支持多用户的receivers services 和 providers 禁止导出
        4. 设置其他标志
        5. 不是SystemApp 不允许orginial-package
       3. assertPackageIsValid()
        1. PARSE_ENFORCE_CODE 标志,检查hascode属性的apk是否包含代码
        2. 必须设置codepath或者resourcePath
        3. 不允许用户安装和手册启动或者ota检查apex包重复
        4. 禁止重新安装平台包(android.jar)
        5. 非安装过程禁止同名包
        6. 静态库检查
       4. 创建ScanRequest
       5. scanPackageOnlyLI()扫描软件包设置Package 和PackageSettings
        1. 第一次启动或者ota需要重新确定abi
        2. sharedUser不能修改
        3. 创建PackageSettings(根据旧的或者重新创建)
        4. original-package 设置为旧报名,打日志
        5. 修改状态 instant_app 或者full_app (full 不能到instant。 instant 能到full?)
        6. 覆盖安装系统应用设置 ApplicationInfo.FLAG_UPDATED_SYSTEM_APP
        7. seInfo 设置 seInfoUser设置
        8. 设置进程名称
        9. 初始化系统user
        10. 非安装流程SCAN_NEW_INSTALL = 0
         1. 需要driverAbi
         2. 不需要driverAbi 设置primaryCpuAbi, secondaryCpuAbi
        11. 非安装流程, 设置primaryCpuAbi secondaryCpuAbi 和applicationInfo
        12. 设置PackageSettings 的 firstInstallTime lastUpdateTime
        13. pkgSetting.pkg = pkg, pkgSetting.pkgFlags = pkg.applicationInfo.flags, pkgSetting.versionCode = pkg.getLongVersionCode(), pkgSetting.volumeUuid = volumeUuid
        14. return new ScanResult

执行完2-2的scanPackageTrackLI()之后Pms的两大核心数据结构都已经准备好了,一个是代表扫描结果的final ArrayMap mPackages = new ArrayMap<>();中的PackageParser.Package,另外一个是mSettings.mPackages的PackageSetting 数据结构,这两个结构PackageParser.Package代表扫描结果,为静态数据,扫描完成后就不会发生变化。PackageSetting用于存储安装应用的动态数据,如权限授予情况等。PackageParser.Package由于是静态数据,扫描apk就可以获取。PackageSetting生成之后会被记录到文件中,以后每次系统启动都会重新加载。

  • 2-3.整合验证阶段:在2-2生成PackageSetting和PackageParser.Package数据结构后,还需要对多个安装apk结果进行调和,一般在 install-multi-package的时候会同时安装多个apk。调用方法是reconcilePackagesLocked():
    @GuardedBy("mPackages")
    private static Map reconcilePackagesLocked(
            final ReconcileRequest request, KeySetManagerService ksms)
            throws ReconcileFailure {
        final Map scannedPackages = request.scannedPackages;
    
        final Map result = new ArrayMap<>(scannedPackages.size());
    
        // make a copy of the existing set of packages so we can combine them with incoming packages
        final ArrayMap combinedPackages =
                new ArrayMap<>(request.allPackages.size() + scannedPackages.size());
        combinedPackages.putAll(request.allPackages);
    
        final Map> incomingSharedLibraries =
                new ArrayMap<>();
    
        for (String installPackageName : scannedPackages.keySet()) {
            final ScanResult scanResult = scannedPackages.get(installPackageName);
    
            // add / replace existing with incoming packages
            combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.pkg);
    
            // in the first pass, we'll build up the set of incoming shared libraries
            final List allowedSharedLibInfos =
                    getAllowedSharedLibInfos(scanResult, request.sharedLibrarySource);
            final SharedLibraryInfo staticLib = scanResult.staticSharedLibraryInfo;
            if (allowedSharedLibInfos != null) {
                for (SharedLibraryInfo info : allowedSharedLibInfos) {
                    if (!addSharedLibraryToPackageVersionMap(incomingSharedLibraries, info)) {
                        throw new ReconcileFailure("Static Shared Library " + staticLib.getName()
                                + " is being installed twice in this set!");
                    }
                }
            }
    
            // the following may be null if we're just reconciling on boot (and not during install)
            final InstallArgs installArgs = request.installArgs.get(installPackageName);
            final PackageInstalledInfo res = request.installResults.get(installPackageName);
            final PrepareResult prepareResult = request.preparedPackages.get(installPackageName);
            final boolean isInstall = installArgs != null;
            if (isInstall && (res == null || prepareResult == null)) {
                throw new ReconcileFailure("Reconcile arguments are not balanced for "
                        + installPackageName + "!");
            }
    
            final DeletePackageAction deletePackageAction;
            // we only want to try to delete for non system apps
            if (isInstall && prepareResult.replace && !prepareResult.system) {
                final boolean killApp = (scanResult.request.scanFlags & SCAN_DONT_KILL_APP) == 0;
                final int deleteFlags = PackageManager.DELETE_KEEP_DATA
                        | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
                deletePackageAction = mayDeletePackageLocked(res.removedInfo,
                        prepareResult.originalPs, prepareResult.disabledPs,
                        prepareResult.childPackageSettings, deleteFlags, null /* all users */);
                if (deletePackageAction == null) {
                    throw new ReconcileFailure(
                            PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE,
                            "May not delete " + installPackageName + " to replace");
                }
            } else {
                deletePackageAction = null;
            }
    
            final int scanFlags = scanResult.request.scanFlags;
            final int parseFlags = scanResult.request.parseFlags;
            final PackageParser.Package pkg = scanResult.request.pkg;
    
            final PackageSetting disabledPkgSetting = scanResult.request.disabledPkgSetting;
            final PackageSetting lastStaticSharedLibSetting =
                    request.lastStaticSharedLibSettings.get(installPackageName);
            final PackageSetting signatureCheckPs =
                    (prepareResult != null && lastStaticSharedLibSetting != null)
                            ? lastStaticSharedLibSetting
                            : scanResult.pkgSetting;
            boolean removeAppKeySetData = false;
            boolean sharedUserSignaturesChanged = false;
            SigningDetails signingDetails = null;
            if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
                if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
                    // We just determined the app is signed correctly, so bring
                    // over the latest parsed certs.
                } else {
                    if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
                        throw new ReconcileFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                                "Package " + pkg.packageName + " upgrade keys do not match the "
                                        + "previously installed version");
                    } else {
                        String msg = "System package " + pkg.packageName
                                + " signature changed; retaining data.";
                        reportSettingsProblem(Log.WARN, msg);
                    }
                }
                signingDetails = pkg.mSigningDetails;
            } else {
                try {
                    final VersionInfo versionInfo = request.versionInfos.get(installPackageName);
                    final boolean compareCompat = isCompatSignatureUpdateNeeded(versionInfo);
                    final boolean compareRecover = isRecoverSignatureUpdateNeeded(versionInfo);
                    final boolean compatMatch = verifySignatures(signatureCheckPs,
                            disabledPkgSetting, pkg.mSigningDetails, compareCompat, compareRecover);
                    // The new KeySets will be re-added later in the scanning process.
                    if (compatMatch) {
                        removeAppKeySetData = true;
                    }
                    // We just determined the app is signed correctly, so bring
                    // over the latest parsed certs.
                    signingDetails = pkg.mSigningDetails;
    
    
                    // if this is is a sharedUser, check to see if the new package is signed by a
                    // newer
                    // signing certificate than the existing one, and if so, copy over the new
                    // details
                    if (signatureCheckPs.sharedUser != null) {
                        if (pkg.mSigningDetails.hasAncestor(
                                signatureCheckPs.sharedUser.signatures.mSigningDetails)) {
                            signatureCheckPs.sharedUser.signatures.mSigningDetails =
                                    pkg.mSigningDetails;
                        }
                        if (signatureCheckPs.sharedUser.signaturesChanged == null) {
                            signatureCheckPs.sharedUser.signaturesChanged = Boolean.FALSE;
                        }
                    }
                } catch (PackageManagerException e) {
                    if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
                        throw new ReconcileFailure(e);
                    }
                    signingDetails = pkg.mSigningDetails;
    
                    // If the system app is part of a shared user we allow that shared user to
                    // change
                    // signatures as well as part of an OTA. We still need to verify that the
                    // signatures
                    // are consistent within the shared user for a given boot, so only allow
                    // updating
                    // the signatures on the first package scanned for the shared user (i.e. if the
                    // signaturesChanged state hasn't been initialized yet in SharedUserSetting).
                    if (signatureCheckPs.sharedUser != null) {
                        final Signature[] sharedUserSignatures =
                                signatureCheckPs.sharedUser.signatures.mSigningDetails.signatures;
                        if (signatureCheckPs.sharedUser.signaturesChanged != null
                                && compareSignatures(sharedUserSignatures,
                                        pkg.mSigningDetails.signatures)
                                        != PackageManager.SIGNATURE_MATCH) {
                            if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 29) {
                                // Mismatched signatures is an error and silently skipping system
                                // packages will likely break the device in unforeseen ways.
                                // However, we allow the device to boot anyway because, prior to Q,
                                // vendors were not expecting the platform to crash in this
                                // situation.
                                // This WILL be a hard failure on any new API levels after Q.
                                throw new ReconcileFailure(
                                        INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
                                        "Signature mismatch for shared user: "
                                                + scanResult.pkgSetting.sharedUser);
                            } else {
                                // Treat mismatched signatures on system packages using a shared
                                // UID as
                                // fatal for the system overall, rather than just failing to install
                                // whichever package happened to be scanned later.
                                throw new IllegalStateException(
                                        "Signature mismatch on system package "
                                                + pkg.packageName + " for shared user "
                                                + scanResult.pkgSetting.sharedUser);
                            }
                        }
    
                        sharedUserSignaturesChanged = true;
                        signatureCheckPs.sharedUser.signatures.mSigningDetails =
                                pkg.mSigningDetails;
                        signatureCheckPs.sharedUser.signaturesChanged = Boolean.TRUE;
                    }
                    // File a report about this.
                    String msg = "System package " + pkg.packageName
                            + " signature changed; retaining data.";
                    reportSettingsProblem(Log.WARN, msg);
                } catch (IllegalArgumentException e) {
                    // should never happen: certs matched when checking, but not when comparing
                    // old to new for sharedUser
                    throw new RuntimeException(
                            "Signing certificates comparison made on incomparable signing details"
                                    + " but somehow passed verifySignatures!", e);
                }
            }
    
            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()) {
            // Check all shared libraries and map to their actual file path.
            // We only do this here for apps not on a system dir, because those
            // are the only ones that can fail an install due to this.  We
            // will take care of the system apps by updating all of their
            // library paths after the scan is done. Also during the initial
            // scan don't update any libs as we do this wholesale after all
            // apps are scanned to avoid dependency based scanning.
            final ScanResult scanResult = scannedPackages.get(installPackageName);
            if ((scanResult.request.scanFlags & SCAN_BOOTING) != 0
                    || (scanResult.request.parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
                continue;
            }
            try {
                result.get(installPackageName).collectedSharedLibraryInfos =
                        collectSharedLibraryInfos(scanResult.request.pkg, combinedPackages,
                                request.sharedLibrarySource, incomingSharedLibraries);
    
            } catch (PackageManagerException e) {
                throw new ReconcileFailure(e.error, e.getMessage());
            }
        }
    
        return result;
    }
    
  • 2-4.确认提交阶段:提交所有扫描的包并更新系统状态。这是唯一可以在安装流中修改系统状态的地方,必须在此阶段之前确定所有可预测的错误。经过上述几个步骤,两个核心数据结构已经生成,但是并没有添加到容器中去(PackageManagerService.mPackages 和 PackageManagerService.mSettings.mPackage), 所以该包里面的组件等还不能查询到,也不能启动。 所以需要调用commitPackagesLocked()来进行提交, 提交之后该应用就算完整发布了。

    @GuardedBy("mPackages")
    private void commitPackagesLocked(final CommitRequest request) {
        // TODO: remove any expected failures from this method; this should only be able to fail due
        //       to unavoidable errors (I/O, etc.)
        for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) {
            final ScanResult scanResult = reconciledPkg.scanResult;
            final ScanRequest scanRequest = scanResult.request;
            final PackageParser.Package pkg = scanRequest.pkg;
            final String packageName = pkg.packageName;
            final PackageInstalledInfo res = reconciledPkg.installResult;
            //***36***
            if (reconciledPkg.prepareResult.replace) {
                PackageParser.Package oldPackage = mPackages.get(packageName);
    
                // Set the update and install times
                PackageSetting deletedPkgSetting = (PackageSetting) oldPackage.mExtras;
                setInstallAndUpdateTime(pkg, deletedPkgSetting.firstInstallTime,
                        System.currentTimeMillis());
    
                if (reconciledPkg.prepareResult.system) {
                    //***37***
                    // Remove existing system package
                    removePackageLI(oldPackage, true);
                    if (!disableSystemPackageLPw(oldPackage, pkg)) {
                        // We didn't need to disable the .apk as a current system package,
                        // which means we are replacing another update that is already
                        // installed.  We need to make sure to delete the older one's .apk.
                        res.removedInfo.args = createInstallArgsForExisting(
                                oldPackage.applicationInfo.getCodePath(),
                                oldPackage.applicationInfo.getResourcePath(),
                                getAppDexInstructionSets(oldPackage.applicationInfo));
                    } else {
                        res.removedInfo.args = null;
                    }
    
                    // Update the package dynamic state if succeeded
                    // Now that the install succeeded make sure we remove data
                    // directories for any child package the update removed.
                    final int deletedChildCount = (oldPackage.childPackages != null)
                            ? oldPackage.childPackages.size() : 0;
                    final int newChildCount = (pkg.childPackages != null)
                            ? pkg.childPackages.size() : 0;
                    for (int i = 0; i < deletedChildCount; i++) {
                        PackageParser.Package deletedChildPkg = oldPackage.childPackages.get(i);
                        boolean childPackageDeleted = true;
                        for (int j = 0; j < newChildCount; j++) {
                            PackageParser.Package newChildPkg = pkg.childPackages.get(j);
                            if (deletedChildPkg.packageName.equals(newChildPkg.packageName)) {
                                childPackageDeleted = false;
                                break;
                            }
                        }
                        if (childPackageDeleted) {
                            PackageSetting ps1 = mSettings.getDisabledSystemPkgLPr(
                                    deletedChildPkg.packageName);
                            if (ps1 != null && res.removedInfo.removedChildPackages != null) {
                                PackageRemovedInfo removedChildRes = res.removedInfo
                                        .removedChildPackages.get(deletedChildPkg.packageName);
                                removePackageDataLIF(ps1, request.mAllUsers, removedChildRes, 0,
                                        false);
                                removedChildRes.removedForAllUsers = mPackages.get(ps1.name)
                                        == null;
                            }
                        }
                    }
                } else {
                    try {//***38***
                        executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName,
                                true, request.mAllUsers, true, pkg);
                    } catch (SystemDeleteException e) {
                        if (Build.IS_ENG) {
                            throw new RuntimeException("Unexpected failure", e);
                            // ignore; not possible for non-system app
                        }
                    }
                    // Successfully deleted the old package; proceed with replace.
    
                    // If deleted package lived in a container, give users a chance to
                    // relinquish resources before killing.
                    if (oldPackage.isForwardLocked() || isExternal(oldPackage)) {
                        if (DEBUG_INSTALL) {
                            Slog.i(TAG, "upgrading pkg " + oldPackage
                                    + " is ASEC-hosted -> UNAVAILABLE");
                        }
                        final int[] uidArray = new int[]{oldPackage.applicationInfo.uid};
                        final ArrayList pkgList = new ArrayList<>(1);
                        pkgList.add(oldPackage.applicationInfo.packageName);
                        //***39***
                        sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
                    }
    
                    // Update the in-memory copy of the previous code paths.
                    PackageSetting ps1 = mSettings.mPackages.get(
                            reconciledPkg.prepareResult.existingPackage.packageName);
                    if ((reconciledPkg.installArgs.installFlags & PackageManager.DONT_KILL_APP)
                            == 0) {
                        if (ps1.mOldCodePaths == null) {
                            ps1.mOldCodePaths = new ArraySet<>();
                        }
                        Collections.addAll(ps1.mOldCodePaths, oldPackage.baseCodePath);
                        if (oldPackage.splitCodePaths != null) {
                            Collections.addAll(ps1.mOldCodePaths, oldPackage.splitCodePaths);
                        }
                    } else {
                        ps1.mOldCodePaths = null;
                    }
                    if (ps1.childPackageNames != null) {
                        for (int i = ps1.childPackageNames.size() - 1; i >= 0; --i) {
                            final String childPkgName = ps1.childPackageNames.get(i);
                            final PackageSetting childPs = mSettings.mPackages.get(childPkgName);
                            childPs.mOldCodePaths = ps1.mOldCodePaths;
                        }
                    }
    
                    if (reconciledPkg.installResult.returnCode
                            == PackageManager.INSTALL_SUCCEEDED) {
                        PackageSetting ps2 = mSettings.getPackageLPr(pkg.packageName);
                        if (ps2 != null) {
                            res.removedInfo.removedForAllUsers = mPackages.get(ps2.name) == null;
                            if (res.removedInfo.removedChildPackages != null) {
                                final int childCount1 = res.removedInfo.removedChildPackages.size();
                                // Iterate in reverse as we may modify the collection
                                for (int i = childCount1 - 1; i >= 0; i--) {
                                    String childPackageName =
                                            res.removedInfo.removedChildPackages.keyAt(i);
                                    if (res.addedChildPackages.containsKey(childPackageName)) {
                                        res.removedInfo.removedChildPackages.removeAt(i);
                                    } else {
                                        PackageRemovedInfo childInfo = res.removedInfo
                                                .removedChildPackages.valueAt(i);
                                        childInfo.removedForAllUsers = mPackages.get(
                                                childInfo.removedPackage) == null;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            //***40***
            commitReconciledScanResultLocked(reconciledPkg);
            //***41***
            updateSettingsLI(pkg, reconciledPkg.installArgs.installerPackageName, request.mAllUsers,
                    res, reconciledPkg.installArgs.user, reconciledPkg.installArgs.installReason);
    
            final PackageSetting ps = mSettings.mPackages.get(packageName);
            if (ps != null) {
                res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
                ps.setUpdateAvailable(false /*updateAvailable*/);
            }
            final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
            for (int i = 0; i < childCount; i++) {
                PackageParser.Package childPkg = pkg.childPackages.get(i);
                PackageInstalledInfo childRes = res.addedChildPackages.get(
                        childPkg.packageName);
                PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
                if (childPs != null) {
                    childRes.newUsers = childPs.queryInstalledUsers(
                            sUserManager.getUserIds(), true);
                }
            }
            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                //***42***
                updateSequenceNumberLP(ps, res.newUsers);
                //***43***
                updateInstantAppInstallerLocked(packageName);
            }
        }
    }
    

    确认阶段详细流程如下:

    1. replace
       1. 设置了一遍ps的firstInstalltime 和lastUpdateTime
       2. 系统应用
        1. 删除旧的package
        2. 删除覆盖安装的system 应用的应用,需要删除的东西放在removedInfo中
        3. 处理child package
       3. 非系统应用
        1. 删除package
        2. 手机要删除的数据

    2. commitReconciledScanResultLocked()正式提交
       1. sharedUser发生变化,移除旧的sharedUser
       2. 更新应用 使用旧的packageSettings更新 packageSettings,pkg.mExtras = pkgSetting
       3. 新安装 设置pkgSetting为 result.pkgSetting
       4. 添加package 到sharedUser
       5. 写入配置文件
       6. 更新sharedlibrary
       7. 更新签名信息
       8. transfer permission
       9. code path 有变化,mInstaller.rmdex
       10. SCAN_CHECK_ONLY mSettings.mPackages.put(oldPkgSetting.name, oldPkgSetting)
       11. commitPackageSettings()
        1. 如果因安装的包包含mCustomResolverComponentName, 更新
        2. 如果是android 应用,并且非check, 设置 mPlatformPackage pkg.mVersionCode = mSdkVersion; pkg.mVersionCodeMajor = 0; mAndroidApplication = pkg.applicationInfo; mResolverReplaced没有替换,设置系统的resolveActivity
        3. 更新sharedLibrary
        4. lib更新,杀掉 依赖的包
        5. mSettings.insertPackageSettingLPw(pkgSetting, pkg);
      // Add the new setting to mPackages
      mPackages.put(pkg.applicationInfo.packageName, pkg); 更新核心数据
        6. mComponentResolver.addAllComponents(pkg, chatty) 添加所有组件
        7. mPermissionManager.addAllPermissionGroups(pkg, chatty) 添加所有权限组
        8. mPermissionManager.addAllPermissions(pkg, chatty); 添加所有权限
        9. instrumentation
        10. pkg.protectedBroadcasts
        11. mPermissionManager.revokeRuntimePermissionsIfGroupChanged() 撤销需要撤销的权限

    3. updateSettingsLI()
       1. 系统应用
        1. 设置多用户
       2. 删除多余的用户
       3. 写配置文件

    4. updateSequenceNumberLP(ps, res.newUsers)

    5. updateInstantAppInstallerLocked(packageName)

  • 2.5 executePostCommitSteps()方法主要是dexoat部分工作,这部分不会修改核心数据结构,所以在mPackage锁外面执行。

    /**
     * On successful install, executes remaining steps after commit completes and the package lock
     * is released. These are typically more expensive or require calls to installd, which often
     * locks on {@link #mPackages}.
     */
    private void executePostCommitSteps(CommitRequest commitRequest) {
        for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
            final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags
                            & PackageManagerService.SCAN_AS_INSTANT_APP) != 0);
            final PackageParser.Package pkg = reconciledPkg.pkgSetting.pkg;
            final String packageName = pkg.packageName;
            //***44***
            prepareAppDataAfterInstallLIF(pkg);
            if (reconciledPkg.prepareResult.clearCodeCache) {
                clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
                        | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
            }
            if (reconciledPkg.prepareResult.replace) {
                mDexManager.notifyPackageUpdated(pkg.packageName,
                        pkg.baseCodePath, pkg.splitCodePaths);
            }
    
            // Prepare the application profiles for the new code paths.
            // This needs to be done before invoking dexopt so that any install-time profile
            // can be used for optimizations.
            //***45***
            mArtManagerService.prepareAppProfiles(
                    pkg,
                    resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()),
                    /* updateReferenceProfileContent= */ true);
    
            // Check whether we need to dexopt the app.
            //
            // NOTE: it is IMPORTANT to call dexopt:
            //   - after doRename which will sync the package data from PackageParser.Package and
            //     its corresponding ApplicationInfo.
            //   - after installNewPackageLIF or replacePackageLIF which will update result with the
            //     uid of the application (pkg.applicationInfo.uid).
            //     This update happens in place!
            //
            // We only need to dexopt if the package meets ALL of the following conditions:
            //   1) it is not an instant app or if it is then dexopt is enabled via gservices.
            //   2) it is not debuggable.
            //
            // Note that we do not dexopt instant apps by default. dexopt can take some time to
            // complete, so we skip this step during installation. Instead, we'll take extra time
            // the first time the instant app starts. It's preferred to do it this way to provide
            // continuous progress to the useur instead of mysteriously blocking somewhere in the
            // middle of running an instant app. The default behaviour can be overridden
            // via gservices.
            final boolean performDexopt =
                    (!instantApp || Global.getInt(mContext.getContentResolver(),
                    Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
                    && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
    
            if (performDexopt) {
                // Compile the layout resources.
                if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts");
                    //***46***
                    mViewCompiler.compileLayouts(pkg);
                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                }
    
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
                // Do not run PackageDexOptimizer through the local performDexOpt
                // method because `pkg` may not be in `mPackages` yet.
                //
                // Also, don't fail application installs if the dexopt step fails.
                DexoptOptions dexoptOptions = new DexoptOptions(packageName,
                        REASON_INSTALL,
                        DexoptOptions.DEXOPT_BOOT_COMPLETE
                                | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
                //***47***
                mPackageDexOptimizer.performDexOpt(pkg,
                        null /* instructionSets */,
                        getOrCreateCompilerPackageStats(pkg),
                        mDexManager.getPackageUseInfoOrDefault(packageName),
                        dexoptOptions);
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
    
            // Notify BackgroundDexOptService that the package has been changed.
            // If this is an update of a package which used to fail to compile,
            // BackgroundDexOptService will remove it from its blacklist.
            // TODO: Layering violation
            //***49***
            BackgroundDexOptService.notifyPackageChanged(packageName);
        }
    }
    
  • 3.调用FileInstallArgs.doPostInstall() 再做一些清理工作,和FileInstallArgs.doPreInstall() 执行的内容是相同的。

  • 4.调用PackageManagerService.restoreAndPostInstall()做一些后续工作,比如发送应用变化相关的广播:

    /** @param data Post-install is performed only if this is non-null. */
    private void restoreAndPostInstall(
            int userId, PackageInstalledInfo res, @Nullable PostInstallData data) {
        if (DEBUG_INSTALL) {
            Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package="
                    + res.pkg.packageName);
        }

        // A restore should be performed at this point if (a) the install
        // succeeded, (b) the operation is not an update, and (c) the new
        // package has not opted out of backup participation.
        final boolean update = res.removedInfo != null
                && res.removedInfo.removedPackage != null;
        final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
        boolean doRestore = !update
                && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);

        // Set up the post-install work request bookkeeping.  This will be used
        // and cleaned up by the post-install event handling regardless of whether
        // there's a restore pass performed.  Token values are >= 1.
        int token;
        if (mNextInstallToken < 0) mNextInstallToken = 1;
        token = mNextInstallToken++;
        if (data != null) {
            mRunningInstalls.put(token, data);
        } else if (DEBUG_INSTALL) {
            Log.v(TAG, "No post-install required for " + token);
        }

        if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);

        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
            // Pass responsibility to the Backup Manager.  It will perform a
            // restore if appropriate, then pass responsibility back to the
            // Package Manager to run the post-install observer callbacks
            // and broadcasts.
            IBackupManager bm = IBackupManager.Stub.asInterface(
                    ServiceManager.getService(Context.BACKUP_SERVICE));
            if (bm != null) {
                // For backwards compatibility as USER_ALL previously routed directly to USER_SYSTEM
                // in the BackupManager. USER_ALL is used in compatibility tests.
                if (userId == UserHandle.USER_ALL) {
                    userId = UserHandle.USER_SYSTEM;
                }
                if (DEBUG_INSTALL) {
                    Log.v(TAG, "token " + token + " to BM for possible restore for user " + userId);
                }
                Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
                try {
                    if (bm.isBackupServiceActive(userId)) {
                        bm.restoreAtInstallForUser(
                                userId, res.pkg.applicationInfo.packageName, token);
                    } else {
                        doRestore = false;
                    }
                } catch (RemoteException e) {
                    // can't happen; the backup manager is local
                } catch (Exception e) {
                    Slog.e(TAG, "Exception trying to enqueue restore", e);
                    doRestore = false;
                }
            } else {
                Slog.e(TAG, "Backup Manager not found!");
                doRestore = false;
            }
        }

        // If this is an update to a package that might be potentially downgraded, then we
        // need to check with the rollback manager whether there's any userdata that might
        // need to be restored for the package.
        //
        // TODO(narayan): Get this working for cases where userId == UserHandle.USER_ALL.
        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) {
            IRollbackManager rm = IRollbackManager.Stub.asInterface(
                    ServiceManager.getService(Context.ROLLBACK_SERVICE));

            final String packageName = res.pkg.applicationInfo.packageName;
            final String seInfo = res.pkg.applicationInfo.seInfo;
            final int[] allUsers = sUserManager.getUserIds();
            final int[] installedUsers;

            final PackageSetting ps;
            int appId = -1;
            long ceDataInode = -1;
            synchronized (mSettings) {
                ps = mSettings.getPackageLPr(packageName);
                if (ps != null) {
                    appId = ps.appId;
                    ceDataInode = ps.getCeDataInode(userId);
                }

                // NOTE: We ignore the user specified in the InstallParam because we know this is
                // an update, and hence need to restore data for all installed users.
                installedUsers = ps.queryInstalledUsers(allUsers, true);
            }

            if (ps != null) {
                try {
                    rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode,
                            seInfo, token);
                } catch (RemoteException re) {
                    // Cannot happen, the RollbackManager is hosted in the same process.
                }
                doRestore = true;
            }
        }

        if (!doRestore) {
            // No restore possible, or the Backup Manager was mysteriously not
            // available -- just fire the post-install work request directly.
            //无法进行恢复,或者备份管理器神秘地不可用,则直接触发安装后工作请求
            if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);

            Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
            //***50***
            Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
            mHandler.sendMessage(msg);
        }
    }

 1. 如果该应用可以备份恢复,并且BackupManager活跃状态通知尝试恢复数据;
 2. 没有restore情况下升级安装可能是降级安装, 尝试使用rollbackMnaager恢复数据, rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode,seInfo, token);
 3. 没有doRestore的情况下 POST_INSTALL, 否则等安装备份或者rollback调用.

Handler接收POST_INSTALL消息会调用handlePackagePostInstall()处理,该方法比较长,主要做了以下几个事儿:

  1. 如果安装成功:
     1. remove 发送广播
     2. 权限假如白名单
     3. 根据安装参数授予运行时全新啊
     4. 对每一个安装的用户
      1. 发送newuser广播
      2. 发送ACTION_PACKAGE_REPLACED广播
  2. 最后执行scheduleDeferredNoKillInstallObserver()或者notifyInstallObserver()方法,其中scheduleDeferredNoKillInstallObserver()最后也会调用到notifyInstallObserver(),所以我们看notifyInstallObserver()方法:
    private void notifyInstallObserver(PackageInstalledInfo info,
            IPackageInstallObserver2 installObserver) {
        if (installObserver != null) {
            try {
                Bundle extras = extrasForInstallResult(info);
                //***51***
                installObserver.onPackageInstalled(info.name, info.returnCode,
                        info.returnMsg, extras);
            } catch (RemoteException e) {
                Slog.i(TAG, "Observer no longer exists.");
            }
        }
    }

这里的installObserver是Android APK安装流程(3)里PackageInstallerSession的localObserver,它的回调方法onPackageInstalled()执行的是destroyInternal()dispatchSessionFinished(),而dispatchSessionFinished()前文中出现多次,其主要做了3件事:
 1. 发送Handler消息MSG_ON_PACKAGE_INSTALLED
 2. 发送了一个ACTION_SESSION_COMMITTED广播到InstallEventReceiver
 3. 回调了onSessionFinished

其中第1点的MSG_ON_PACKAGE_INSTALLED的消息处理中又调用了
observer.onPackageInstalled()回调方法。这个observer是PackageInstallSession的commit流程中生成的对象mRemoteObserver(参考Android APK安装流程(2)--APK的拷贝的48步)。mRemoteObserver是PackageInstallObserverAdapter的getBinder()方法获取的对象。其onPackageInstalled()方法主要就是创建一个Notification告知用户安装完成:

    #PackageInstallerService$PackageInstallObserverAdapter
        @Override
        public void onPackageInstalled(String basePackageName, int returnCode, String msg,
                Bundle extras) {
            if (PackageManager.INSTALL_SUCCEEDED == returnCode && mShowNotification) {
                boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
                Notification notification = buildSuccessNotification(mContext,
                        mContext.getResources()
                                .getString(update ? R.string.package_updated_device_owner :
                                        R.string.package_installed_device_owner),
                        basePackageName,
                        mUserId);
                if (notification != null) {
                    NotificationManager notificationManager = (NotificationManager)
                            mContext.getSystemService(Context.NOTIFICATION_SERVICE);
                    notificationManager.notify(basePackageName,
                            SystemMessage.NOTE_PACKAGE_STATE,
                            notification);
                }
            }
            final Intent fillIn = new Intent();
            fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
            fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
                    PackageManager.installStatusToPublicStatus(returnCode));
            fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
                    PackageManager.installStatusToString(returnCode, msg));
            fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
            if (extras != null) {
                final String existing = extras.getString(
                        PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
                if (!TextUtils.isEmpty(existing)) {
                    fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
                }
            }
            try {
                mTarget.sendIntent(mContext, 0, fillIn, null, null);
            } catch (SendIntentException ignored) {
            }
        }

其中第2点看以下InstallEventReceiver接收到广播后的处理:

    @Override
    public void onReceive(Context context, Intent intent) {
        getReceiver(context).onEventReceived(context, intent);
    }


    void onEventReceived(@NonNull Context context, @NonNull Intent intent) {
        int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, 0);

        if (status == PackageInstaller.STATUS_PENDING_USER_ACTION) {
            context.startActivity(intent.getParcelableExtra(Intent.EXTRA_INTENT));

            return;
        }

        int id = intent.getIntExtra(EXTRA_ID, 0);
        String statusMessage = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
        int legacyStatus = intent.getIntExtra(PackageInstaller.EXTRA_LEGACY_STATUS, 0);

        EventResultObserver observerToCall = null;
        synchronized (mLock) {
            int numObservers = mObservers.size();
            for (int i = 0; i < numObservers; i++) {
                if (mObservers.keyAt(i) == id) {
                    observerToCall = mObservers.valueAt(i);
                    mObservers.removeAt(i);

                    break;
                }
            }

            if (observerToCall != null) {
                observerToCall.onResult(status, legacyStatus, statusMessage);
            } else {
                mResults.put(id, new EventResult(status, legacyStatus, statusMessage));
                writeState();
            }
        }
    }

从EXTRA_ID 中获取当前EventResultObserver对应的id,并且回调onResult。此时就会回调到InstallInstalling的launchFinishBasedOnResult方法,显示出安装成功/失败的界面,具体可参考Android APK安装流程(2)的3、4、8、9流程。

最后看一下时序图

你可能感兴趣的:(Android APK安装流程(4)--APK加载)