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<InstallRequest> 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<InstallRequest> 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:
     * <ul>
     *     <li><b>Prepare</b>
     *         <br/>Analyzes any current install state, parses the package and does initial
     *         validation on it.</li>
     *     <li><b>Scan</b>
     *         <br/>Interrogates the parsed packages given the context collected in prepare.</li>
     *     <li><b>Reconcile</b>
     *         <br/>Validates scanned packages in the context of each other and the current system
     *         state to ensure that the install will be successful.
     *     <li><b>Commit</b>
     *         <br/>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.</li>
     * </ul>
     *
     * Failure at any phase will result in a full failure to install all packages.
     */
    @GuardedBy("mInstallLock")
    private void installPackagesLI(List<InstallRequest> 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<ScanResult> 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<String, ReconciledPackage> 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.準備階段:分析任何當(dāng)前安裝狀態(tài),解析包并對其進行初始驗證。
    # 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**** 設(shè)置簽名文件
                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內(nèi)容,并把解析的package結(jié)果緩存到磁盤和內(nèi)存中(//***18***)。
    2-1-2.往Package對象中設(shè)置好簽名信息(//***21***)。
    2-1-3.從Settings中獲取是否有當(dāng)前包名對應(yīng)的PackageSetting 包配置信息,此時還沒有則跳開這里的if。獲取PermissionManagerService查詢權(quán)限信息。如果還是能查到,說明是包的升級,此時會進行包權(quán)限的校驗。判斷前后兩次是不是內(nèi)部包含的包權(quán)限內(nèi)容都是一致,而只是順序變了。當(dāng)然如果之前沒有安裝,或者內(nèi)容不一致,都會觸發(fā)KeySetManagerService的checkUpgradeKeySetLocked進行更新(//***22***)。
    2-1-4.調(diào)用InstallArgs.doRename 把當(dāng)前的包的名字給更新了(//***24***)。
    2-1-5.判斷當(dāng)前是否允許對包進行校驗,如果允許則調(diào)用VerityUtils.generateApkVeritySetupData()對包的簽名進行校驗,校驗通過根路徑則調(diào)用Installd服務(wù)進一步調(diào)用installApkVerity進行校驗,詳細可以看setUpFsVerityIfPossible()方法(//***25***)。
    2-1-6.返回PrepareResult(//***29***)
    具體詳細流程:
    1 準備scanflags: move 表示已經(jīng)初始化過,添加SCAN_INITIAL標志, 不需要殺掉添加 SCAN_DONT_KILL_APP, instantApp 為SCAN_AS_INSTANT_APP, fullApp 為 SCAN_AS_FULL_APP, virtualPreload 虛擬預(yù)加載SCAN_AS_VIRTUAL_PRELOAD
    2 instant app 不能安裝在外置存儲
    3 pp.parsePackage(tmpPackageFile, parseFlags) 解析, DexMetadataHelper.validatePackageDexMetadata(pkg) 驗證dm文件
    4 instantApp 驗證, targetSdkVersion不能小于o, 不能是isharedUid
    5 靜態(tài)庫修改包名,包名添加上version信息,方便安裝多版本庫
    6 子包的處理
    7 cpuAbiOverride 處理, 如果安裝選項設(shè)置了使用安裝選項覆蓋
    8 TEST_ONLY app 應(yīng)用判斷是否可以安裝, 沒有-t選項不允許安裝
    9 判斷是否是replace安裝
    ?9.1 包含original-package使用舊包名驗證是否安裝過
    ?9.2 非original-package使用包名看下是否安裝過
    ?9.3 子包禁止安裝
    ?9.4 替換安裝情況下, targetSdk 范圍檢查
    ?9.5 禁止PERSISTENT 非 stage安裝(因為可能會導(dǎo)致persistent被殺)
    ?9.6 禁止子包安裝
    10 替換安裝情況對簽名進行檢查
    11 權(quán)限處理
    ?11.1 除了系統(tǒng)應(yīng)用之外不允許定義PROTECTION_FLAG_INSTANT級別的權(quán)限
    ?11.2 對于要更新的權(quán)限執(zhí)行以下操作
    ??11.2.1 如果是應(yīng)用升級則并且有升級key限制則驗證
    ??11.2.2 沒有升級key限制則驗證證書匹配才可以升級權(quán)限
    ??11.2.3 非PLATFORM_PACKAGE_NAME禁止簽名不同升級權(quán)限
    ??11.2.4 PROTECTION_DANGEROUS 權(quán)限禁止修改(降低) 保護級別
    12 系統(tǒng)應(yīng)用禁止是instantApp,禁止安裝在外置存儲
    13 abi的處理
    ?13.1 move 應(yīng)用安裝位置,直接設(shè)置primaryCpuAbi 和 secondaryCpuAbi
    ?13.2 非move應(yīng)用 derivePackageAbi
    14 修改包名
    15 fsverify
    16 startIntentFilterVerifications
    17 創(chuàng)建 freezer 禁止啟動
    19 替換安裝情況
    ?19.1 靜態(tài)庫禁止同版本升級
    ?19.2 再次驗證簽名
    ?19.3 驗證系統(tǒng)應(yīng)用升級的restrict-update
    ?19.4 檢查shareduid是否變化
    ?19.5 禁止fullapp -> instant app 安裝
    ?19.6 設(shè)置更新后被移除的子包
    ?19.7 系統(tǒng)包根據(jù)舊包設(shè)置targetParseFlags targetScanFlags, 設(shè)置setApplicationInfoFlags位FLAG_UPDATED_SYSTEM_APP
    20 非替換安裝情況(新安裝)
    ?20.1 沒有指定INSTALL_REPLACE_EXISTING 禁止非替換安裝
    21 創(chuàng)建 PrepareResult返回
  • 2-2.掃描解析階段:根據(jù)準備階段中收集的上下文對包進行解析,主要用于生成PackageSetting數(shù)據(jù)結(jié)構(gòu)。調(diào)用scanPackageTracedLI()掃描包內(nèi)容,此時其實已經(jīng)解析過一次包內(nèi)容,在這里能直接獲得緩存。

    #PackageManagerService
    @GuardedBy({"mInstallLock", "mPackages"})
    private List<ScanResult> 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<ScanResult> 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);
        }
    }
    

    掃描解析階段的代碼流程其實也挺長,具體細節(jié)如下:

    1. 對于包含child的包,先check掃描一遍,再非check掃描一遍
    2. 不包含child的包直接非check掃描一遍
    3. 掃描函數(shù)scanPackageNewLI()
      ? 1. adjustScanFlags()
      ? ? 1. 如果覆蓋安裝系統(tǒng)應(yīng)用設(shè)置系統(tǒng)相關(guān)的掃描屬性
      ? ? 2. 如果instant安裝設(shè)置 SCAN_AS_INSTANT_APP, 如果 VirtulalPreload設(shè)置 SCAN_AS_VIRTUAL_PRELOAD
      ? ? 3. 如果簽名是系統(tǒng)簽名,并且shareduid 是privleged的,并且要安裝的應(yīng)用簽名和平臺簽名一致,設(shè)置 SCAN_AS_PRIVILEGED(這相當(dāng)于一種權(quán)限提升呀)
      ? 2. applyPolicy() 這一步根據(jù)scanFlags設(shè)置pkg.applicationInfo下的標志和 四大組件的標志
      ??1. 系統(tǒng)應(yīng)用設(shè)置
      ???1. directBootAware 設(shè)置所有組件的directBootAware標志
      ???2. 如果是stub安裝設(shè)置 pkg.isStub = true
      ??2. 非系統(tǒng)應(yīng)用刪除一些特權(quán)flags,設(shè)置降低權(quán)限組優(yōu)先級,pkg.permissionGroups.get(i).info.priority
      ??3. 非SCAN_AS_PRIVILEGED app
      ???1. pkg.protectedBroadcasts = null
      ???2. 不支持多用戶的receivers services 和 providers 禁止導(dǎo)出
      ??4. 設(shè)置其他標志
      ??5. 不是SystemApp 不允許orginial-package
      ?3. assertPackageIsValid()
      ??1. PARSE_ENFORCE_CODE 標志,檢查hascode屬性的apk是否包含代碼
      ??2. 必須設(shè)置codepath或者resourcePath
      ??3. 不允許用戶安裝和手冊啟動或者ota檢查apex包重復(fù)
      ??4. 禁止重新安裝平臺包(android.jar)
      ??5. 非安裝過程禁止同名包
      ??6. 靜態(tài)庫檢查
      ?4. 創(chuàng)建ScanRequest
      ?5. scanPackageOnlyLI()掃描軟件包設(shè)置Package 和PackageSettings
      ??1. 第一次啟動或者ota需要重新確定abi
      ??2. sharedUser不能修改
      ??3. 創(chuàng)建PackageSettings(根據(jù)舊的或者重新創(chuàng)建)
      ??4. original-package 設(shè)置為舊報名,打日志
      ??5. 修改狀態(tài) instant_app 或者full_app (full 不能到instant。 instant 能到full?)
      ??6. 覆蓋安裝系統(tǒng)應(yīng)用設(shè)置 ApplicationInfo.FLAG_UPDATED_SYSTEM_APP
      ??7. seInfo 設(shè)置 seInfoUser設(shè)置
      ??8. 設(shè)置進程名稱
      ??9. 初始化系統(tǒng)user
      ??10. 非安裝流程SCAN_NEW_INSTALL = 0
      ???1. 需要driverAbi
      ???2. 不需要driverAbi 設(shè)置primaryCpuAbi, secondaryCpuAbi
      ??11. 非安裝流程, 設(shè)置primaryCpuAbi secondaryCpuAbi 和applicationInfo
      ??12. 設(shè)置PackageSettings 的 firstInstallTime lastUpdateTime
      ??13. pkgSetting.pkg = pkg, pkgSetting.pkgFlags = pkg.applicationInfo.flags, pkgSetting.versionCode = pkg.getLongVersionCode(), pkgSetting.volumeUuid = volumeUuid
      ??14. return new ScanResult

執(zhí)行完2-2的scanPackageTrackLI()之后Pms的兩大核心數(shù)據(jù)結(jié)構(gòu)都已經(jīng)準備好了,一個是代表掃描結(jié)果的final ArrayMap<String, PackageParser.Package> mPackages = new ArrayMap<>();中的PackageParser.Package,另外一個是mSettings.mPackages的PackageSetting 數(shù)據(jù)結(jié)構(gòu),這兩個結(jié)構(gòu)PackageParser.Package代表掃描結(jié)果,為靜態(tài)數(shù)據(jù),掃描完成后就不會發(fā)生變化。PackageSetting用于存儲安裝應(yīng)用的動態(tài)數(shù)據(jù),如權(quán)限授予情況等。PackageParser.Package由于是靜態(tài)數(shù)據(jù),掃描apk就可以獲取。PackageSetting生成之后會被記錄到文件中,以后每次系統(tǒng)啟動都會重新加載。

  • 2-3.整合驗證階段:在2-2生成PackageSetting和PackageParser.Package數(shù)據(jù)結(jié)構(gòu)后,還需要對多個安裝apk結(jié)果進行調(diào)和,一般在 install-multi-package的時候會同時安裝多個apk。調(diào)用方法是reconcilePackagesLocked():
    @GuardedBy("mPackages")
    private static Map<String, ReconciledPackage> reconcilePackagesLocked(
            final ReconcileRequest request, KeySetManagerService ksms)
            throws ReconcileFailure {
        final Map<String, ScanResult> scannedPackages = request.scannedPackages;
    
        final Map<String, ReconciledPackage> result = new ArrayMap<>(scannedPackages.size());
    
        // make a copy of the existing set of packages so we can combine them with incoming packages
        final ArrayMap<String, PackageParser.Package> combinedPackages =
                new ArrayMap<>(request.allPackages.size() + scannedPackages.size());
        combinedPackages.putAll(request.allPackages);
    
        final Map<String, LongSparseArray<SharedLibraryInfo>> 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<SharedLibraryInfo> 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.確認提交階段:提交所有掃描的包并更新系統(tǒng)狀態(tài)。這是唯一可以在安裝流中修改系統(tǒng)狀態(tài)的地方,必須在此階段之前確定所有可預(yù)測的錯誤。經(jīng)過上述幾個步驟,兩個核心數(shù)據(jù)結(jié)構(gòu)已經(jīng)生成,但是并沒有添加到容器中去(PackageManagerService.mPackages 和 PackageManagerService.mSettings.mPackage), 所以該包里面的組件等還不能查詢到,也不能啟動。 所以需要調(diào)用commitPackagesLocked()來進行提交, 提交之后該應(yīng)用就算完整發(fā)布了。

    @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<String> 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. 設(shè)置了一遍ps的firstInstalltime 和lastUpdateTime
      ?2. 系統(tǒng)應(yīng)用
      ??1. 刪除舊的package
      ??2. 刪除覆蓋安裝的system 應(yīng)用的應(yīng)用,需要刪除的東西放在removedInfo中
      ??3. 處理child package
      ?3. 非系統(tǒng)應(yīng)用
      ??1. 刪除package
      ??2. 手機要刪除的數(shù)據(jù)

    2. commitReconciledScanResultLocked()正式提交
      ?1. sharedUser發(fā)生變化,移除舊的sharedUser
      ?2. 更新應(yīng)用 使用舊的packageSettings更新 packageSettings,pkg.mExtras = pkgSetting
      ?3. 新安裝 設(shè)置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 應(yīng)用,并且非check, 設(shè)置 mPlatformPackage pkg.mVersionCode = mSdkVersion; pkg.mVersionCodeMajor = 0; mAndroidApplication = pkg.applicationInfo; mResolverReplaced沒有替換,設(shè)置系統(tǒng)的resolveActivity
      ??3. 更新sharedLibrary
      ??4. lib更新,殺掉 依賴的包
      ??5. mSettings.insertPackageSettingLPw(pkgSetting, pkg);
      // Add the new setting to mPackages
      mPackages.put(pkg.applicationInfo.packageName, pkg); 更新核心數(shù)據(jù)
      ??6. mComponentResolver.addAllComponents(pkg, chatty) 添加所有組件
      ??7. mPermissionManager.addAllPermissionGroups(pkg, chatty) 添加所有權(quán)限組
      ??8. mPermissionManager.addAllPermissions(pkg, chatty); 添加所有權(quán)限
      ??9. instrumentation
      ??10. pkg.protectedBroadcasts
      ??11. mPermissionManager.revokeRuntimePermissionsIfGroupChanged() 撤銷需要撤銷的權(quán)限

    3. updateSettingsLI()
      ?1. 系統(tǒng)應(yīng)用
      ??1. 設(shè)置多用戶
      ?2. 刪除多余的用戶
      ?3. 寫配置文件

    4. updateSequenceNumberLP(ps, res.newUsers)

    5. updateInstantAppInstallerLocked(packageName)

  • 2.5 executePostCommitSteps()方法主要是dexoat部分工作,這部分不會修改核心數(shù)據(jù)結(jié)構(gòu),所以在mPackage鎖外面執(zhí)行。

    /**
     * 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.調(diào)用FileInstallArgs.doPostInstall() 再做一些清理工作,和FileInstallArgs.doPreInstall() 執(zhí)行的內(nèi)容是相同的。

  • 4.調(diào)用PackageManagerService.restoreAndPostInstall()做一些后續(xù)工作,比如發(fā)送應(yīng)用變化相關(guān)的廣播:

    /** @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.
            //無法進行恢復(fù),或者備份管理器神秘地不可用,則直接觸發(fā)安裝后工作請求
            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. 如果該應(yīng)用可以備份恢復(fù),并且BackupManager活躍狀態(tài)通知嘗試恢復(fù)數(shù)據(jù);
?2. 沒有restore情況下升級安裝可能是降級安裝, 嘗試使用rollbackMnaager恢復(fù)數(shù)據(jù), rm.snapshotAndRestoreUserData(packageName, installedUsers, appId, ceDataInode,seInfo, token);
?3. 沒有doRestore的情況下 POST_INSTALL, 否則等安裝備份或者rollback調(diào)用.

Handler接收POST_INSTALL消息會調(diào)用handlePackagePostInstall()處理,該方法比較長,主要做了以下幾個事兒:

  1. 如果安裝成功:
    ?1. remove 發(fā)送廣播
    ?2. 權(quán)限假如白名單
    ?3. 根據(jù)安裝參數(shù)授予運行時全新啊
    ?4. 對每一個安裝的用戶
    ??1. 發(fā)送newuser廣播
    ??2. 發(fā)送ACTION_PACKAGE_REPLACED廣播
  2. 最后執(zhí)行scheduleDeferredNoKillInstallObserver()或者notifyInstallObserver()方法,其中scheduleDeferredNoKillInstallObserver()最后也會調(diào)用到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.");
            }
        }
    }

這里的installObserverAndroid APK安裝流程(3)里PackageInstallerSession的localObserver,它的回調(diào)方法onPackageInstalled()執(zhí)行的是destroyInternal()dispatchSessionFinished(),而dispatchSessionFinished()前文中出現(xiàn)多次,其主要做了3件事:
?1. 發(fā)送Handler消息MSG_ON_PACKAGE_INSTALLED
?2. 發(fā)送了一個ACTION_SESSION_COMMITTED廣播到InstallEventReceiver
?3. 回調(diào)了onSessionFinished

其中第1點的MSG_ON_PACKAGE_INSTALLED的消息處理中又調(diào)用了
observer.onPackageInstalled()回調(diào)方法。這個observer是PackageInstallSession的commit流程中生成的對象mRemoteObserver(參考Android APK安裝流程(2)--APK的拷貝的48步)。mRemoteObserver是PackageInstallObserverAdapter的getBinder()方法獲取的對象。其onPackageInstalled()方法主要就是創(chuàng)建一個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 中獲取當(dāng)前EventResultObserver對應(yīng)的id,并且回調(diào)onResult。此時就會回調(diào)到InstallInstalling的launchFinishBasedOnResult方法,顯示出安裝成功/失敗的界面,具體可參考Android APK安裝流程(2)的3、4、8、9流程。

最后看一下時序圖

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容