Android App 的安装过程

当我们点击某一个 App 安装包进行安装时,首先会弹出一个系统界面指示我们进行安装操作。这个界面是 Android Framework 中预置的一个 ActivityPackageInstallerActivity。当点击安装后,PackageInstallerActivity 最终会将所安装的 apk 信息通过 PackageInstallerSession传给 PMS,具体方法在 commitNonStagedLocked 方法中,如下所示:

commitNonStagedLocked()

//PackageInstallerSession.java
private void commitNonStagedLocked(List<PackageInstallerSession> childSessions)
        throws PackageManagerException {
    final PackageManagerService.ActiveInstallSession committingSession =
            makeSessionActiveLocked();
    if (committingSession == null) {
        return;
    }
    if (isMultiPackage()) {
        List<PackageManagerService.ActiveInstallSession> activeChildSessions =
                new ArrayList<>(childSessions.size());
        boolean success = true;
        PackageManagerException failure = null;
        for (int i = 0; i < childSessions.size(); ++i) {
            final PackageInstallerSession session = childSessions.get(i);
            try {
                final PackageManagerService.ActiveInstallSession activeSession =
                        session.makeSessionActiveLocked();
                if (activeSession != null) {
                    activeChildSessions.add(activeSession);
                }
            } catch (PackageManagerException e) {
                failure = e;
                success = false;
            }
        }
        if (!success) {
            PackageInstallerService.sendOnPackageInstalled(mContext,
                    mRemoteStatusReceiver, sessionId,
                    isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId, null,
                    failure.error, failure.getLocalizedMessage(), null);
            return;
        }
        mPm.installStage(activeChildSessions);
    } else {
        mPm.installStage(committingSession);
    }
}
复制代码
复制代码

mPm就是系统服务 PackageManagerService。installStage 方法就是正式开始 apk 的安装过程。

整个 apk 的安装过程可以分为两大步:

  • 拷贝安装包
  • 装载代码

拷贝安装包

void installStage(ActiveInstallSession activeInstallSession) {
    if (DEBUG_INSTANT) {
        if ((activeInstallSession.getSessionParams().installFlags
                & PackageManager.INSTALL_INSTANT_APP) != 0) {
            Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
        }
    }
    //创建了类型为INIT_COPY的Message
  
    final Message msg = mHandler.obtainMessage(INIT_COPY);
    //创建InstallParams
    final InstallParams params = new InstallParams(activeInstallSession);
    //...
    msg.obj = params;
    //...
    mHandler.sendMessage(msg);
}
复制代码
复制代码

Message 发送出去之后,由 PMS 的内部类 PackageHandler 接收并处理,如下:

class PackageHandler extends Handler {

        PackageHandler(Looper looper) {
            super(looper);
        }

        public void handleMessage(Message msg) {
            try {
                doHandleMessage(msg);
            } finally {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            }
        }
        void doHandleMessage(Message msg) {
            switch (msg.what) {
                case INIT_COPY: {
                    
                    HandlerParams params = (HandlerParams) msg.obj;
                    if (params != null) {
                        //...
                        //开始复制
                        params.startCopy();
                        //...
                    }
                    break;
                }
            }
        }
}
复制代码
复制代码

startCopy()

//HandlerParams的startCopy()方法
final void startCopy() {
    if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
    handleStartCopy();
    handleReturnCode();
}
复制代码
复制代码

handleStartCopy()

InstallParams 的handleStartCopy 方法

这个方法是整个安装包拷贝的核心方法,具体如下:

public void handleStartCopy() {
    int ret = PackageManager.INSTALL_SUCCEEDED;

    // If we're already staged, we've firmly committed to an install location
    //设置安装标志位,决定是安装在手机内部存储空间还是sdcard中
    if (origin.staged) {
        if (origin.file != null) {
            installFlags |= PackageManager.INSTALL_INTERNAL;
        } else {
            throw new IllegalStateException("Invalid stage location");
        }
    }
    //判断apk安装位置
    final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
    final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
    PackageInfoLite pkgLite = null;


    pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
            origin.resolvedPath, installFlags, packageAbiOverride);

    //创建一个InstallArgs
    final InstallArgs args = createInstallArgs(this);
    mArgs = args;


    mRet = ret;
}
复制代码
复制代码

createInstallArgs创建一个 InstallArgs,实际上是其子类 FileInstallArgs 类型,然后调用其 copyApk 方法进行安装包的拷贝操作。

private InstallArgs createInstallArgs(InstallParams params) {
    if (params.move != null) {
        return new MoveInstallArgs(params);
    } else {
        return new FileInstallArgs(params);
    }
}
复制代码
复制代码

handleReturnCode()

InstallParams 的 handleReturnCode 方法

@Override
void handleReturnCode() {
    if (mVerificationCompleted && mEnableRollbackCompleted) {
        if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
            String packageName = "";
            try {
                PackageLite packageInfo =
                        new PackageParser().parsePackageLite(origin.file, 0);//①
                packageName = packageInfo.packageName;
            } catch (PackageParserException e) {
                Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(), e);
            }
            try {
                observer.onPackageInstalled(packageName, mRet, "Dry run", new Bundle());
            } catch (RemoteException e) {
                Slog.i(TAG, "Observer no longer exists.");
            }
            return;
        }
        if (mRet == PackageManager.INSTALL_SUCCEEDED) {
           //复制apk
            mRet = mArgs.copyApk();
        }
        //执行安装
        processPendingInstall(mArgs, mRet);
    }
}
复制代码
复制代码

①处调用 PackageParser 的 parsePackage 方法解析 apk 文件,主要是解析 AndroidManifest.xml 文件,将结果记录在 PackageParser.Package 中。我们在清单文件中声明的 Activity、Service 等组件就是在这一步中被记录到系统 Framework 中,后续才可以通过 startActivity 或者 startService 启动相应的活动或者服务。

copyApk()

int copyApk() {
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
    try {
        return doCopyApk();
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}
复制代码
复制代码

doCopyApk()

private int doCopyApk() {
    if (origin.staged) {
        if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
        codeFile = origin.file;
        resourceFile = origin.file;
        return PackageManager.INSTALL_SUCCEEDED;
    }

    try {
        final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
        //创建存储安装包的目标路径,实际上是/data/app/应用包名目录
        final File tempDir =
                mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
        codeFile = tempDir;
        resourceFile = tempDir;
    } catch (IOException e) {
        Slog.w(TAG, "Failed to create copy file: " + e);
        return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
    }
    //调用copyPackage 方法将安装包 apk 拷贝到目标路径中
    int ret = PackageManagerServiceUtils.copyPackage(
            origin.file.getAbsolutePath(), codeFile);
    if (ret != PackageManager.INSTALL_SUCCEEDED) {
        Slog.e(TAG, "Failed to copy package");
        return ret;
    }

    final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
    NativeLibraryHelper.Handle handle = null;
    try {
        handle = NativeLibraryHelper.Handle.create(codeFile);
        //将 apk 中的动态库 .so 文件也拷贝到目标路径中。
        ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
                abiOverride);
    } catch (IOException e) {
        Slog.e(TAG, "Copying native libraries failed", e);
        ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
    } finally {
        IoUtils.closeQuietly(handle);
    }

    return ret;
}
复制代码
复制代码

copyPackage()

//PackageManagerServiceUtils.java
public static int copyPackage(String packagePath, File targetDir) {
    if (packagePath == null) {
        return PackageManager.INSTALL_FAILED_INVALID_URI;
    }
    try {
        final File packageFile = new File(packagePath);
        final PackageParser.PackageLite pkg = PackageParser.parsePackageLite(packageFile, 0);
        copyFile(pkg.baseCodePath, targetDir, "base.apk");
        if (!ArrayUtils.isEmpty(pkg.splitNames)) {
            for (int i = 0; i < pkg.splitNames.length; i++) {
                copyFile(pkg.splitCodePaths[i], targetDir,
                        "split_" + pkg.splitNames[i] + ".apk");
            }
        }
        return PackageManager.INSTALL_SUCCEEDED;
    } catch (PackageParserException | IOException | ErrnoException e) {
        Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e);
        return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
    }
}
复制代码
复制代码

copyFile()

private static void copyFile(String sourcePath, File targetDir, String targetName)
        throws ErrnoException, IOException {
    if (!FileUtils.isValidExtFilename(targetName)) {
        throw new IllegalArgumentException("Invalid filename: " + targetName);
    }
    Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);
    final File targetFile = new File(targetDir, targetName);
    final FileDescriptor targetFd = Os.open(targetFile.getAbsolutePath(),
            O_RDWR | O_CREAT, 0644);
    Os.chmod(targetFile.getAbsolutePath(), 0644);
    FileInputStream source = null;
    try {
        source = new FileInputStream(sourcePath);
        FileUtils.copy(source.getFD(), targetFd);
    } finally {
        IoUtils.closeQuietly(source);
    }
}
复制代码
复制代码

最终安装包在 data/app 目录下以 base.apk 的方式保存,至此安装包拷贝工作就已经完成。

装载代码

InstallParams 的 handleReturnCode 方法复制完apk,最终调用processPendingInstall方法来处理安装过程。

processPendingInstall()

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

private PackageInstalledInfo createPackageInstalledInfo(
        int currentStatus) {
    PackageInstalledInfo res = new PackageInstalledInfo();
    res.setReturnCode(currentStatus);
    res.uid = -1;
    res.pkg = null;
    res.removedInfo = null;
    return 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) {
                request.args.doPreInstall(request.installResult.returnCode);
            }
            synchronized (mInstallLock) {
                //安装
                installPackagesTracedLI(installRequests);
            }
            for (InstallRequest request : installRequests) {
                request.args.doPostInstall(
                        request.installResult.returnCode, request.installResult.uid);
            }
        }
        for (InstallRequest request : installRequests) {
            restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
                    new PostInstallData(request.args, request.installResult, null));
        }
    });
}
复制代码
复制代码

installPackagesTracedLI()

private void installPackagesTracedLI(List<InstallRequest> requests) {
    try {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
        installPackagesLI(requests);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}
复制代码
复制代码

preparePackageLI()

private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
        throws PrepareFailure {
    final int installFlags = args.installFlags;
    final String installerPackageName = args.installerPackageName;
    final String volumeUuid = args.volumeUuid;
    final File tmpPackageFile = new File(args.getCodePath());
    final boolean onExternal = args.volumeUuid != null;
    final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
    final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
    final boolean virtualPreload =
            ((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
    @ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
    if (args.move != null) {
        // moving a complete application; perform an initial scan on the new install location
        scanFlags |= SCAN_INITIAL;
    }
    if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
        scanFlags |= SCAN_DONT_KILL_APP;
    }
    if (instantApp) {
        scanFlags |= SCAN_AS_INSTANT_APP;
    }
    if (fullApp) {
        scanFlags |= SCAN_AS_FULL_APP;
    }
    if (virtualPreload) {
        scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
    }

    if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);

    // Validity check
    if (instantApp && onExternal) {
        Slog.i(TAG, "Incompatible ephemeral install; external=" + onExternal);
        throw new PrepareFailure(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
    }

    // Retrieve PackageSettings and parse package
    @ParseFlags final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
            | PackageParser.PARSE_ENFORCE_CODE
            | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);

    PackageParser pp = new PackageParser();
    pp.setSeparateProcesses(mSeparateProcesses);
    pp.setDisplayMetrics(mMetrics);
    pp.setCallback(mPackageParserCallback);

    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
    final PackageParser.Package pkg;
    try {
        pkg = pp.parsePackage(tmpPackageFile, parseFlags);
        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.targetSdkVersion < Build.VERSION_CODES.O) {
            Slog.w(TAG,
                    "Instant app package " + pkg.packageName + " does not target at least O");
            throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                    "Instant app package must target at least O");
        }
        if (pkg.mSharedUserId != null) {
            Slog.w(TAG, "Instant app package " + pkg.packageName
                    + " may not declare sharedUserId.");
            throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                    "Instant app package may not declare a sharedUserId");
        }
    }

    if (pkg.applicationInfo.isStaticSharedLibrary()) {
        // Static shared libraries have synthetic package names
        renameStaticSharedLibraryPackage(pkg);

        // No static shared libs on external storage
        if (onExternal) {
            Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
            throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                    "Packages declaring static-shared libs cannot be updated");
        }
    }

    // If we are installing a clustered package add results for the children
    if (pkg.childPackages != null) {
        synchronized (mPackages) {
            final int childCount = pkg.childPackages.size();
            for (int i = 0; i < childCount; i++) {
                PackageParser.Package childPkg = pkg.childPackages.get(i);
                PackageInstalledInfo childRes = new PackageInstalledInfo();
                childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
                childRes.pkg = childPkg;
                childRes.name = childPkg.packageName;
                PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
                if (childPs != null) {
                    childRes.origUsers = childPs.queryInstalledUsers(
                            sUserManager.getUserIds(), true);
                }
                if ((mPackages.containsKey(childPkg.packageName))) {
                    childRes.removedInfo = new PackageRemovedInfo(this);
                    childRes.removedInfo.removedPackage = childPkg.packageName;
                    childRes.removedInfo.installerPackageName = childPs.installerPackageName;
                }
                if (res.addedChildPackages == null) {
                    res.addedChildPackages = new ArrayMap<>();
                }
                res.addedChildPackages.put(childPkg.packageName, childRes);
            }
        }
    }

    // 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;
    }

    String pkgName = res.name = pkg.packageName;
    if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0) {
        if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
            throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
        }
    }

    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 {
            PackageParser.collectCertificates(pkg, false /* skipVerify */);
        }
    } catch (PackageParserException e) {
        throw new PrepareFailure("Failed collect during installPackageLI", e);
    }

    if (instantApp && pkg.mSigningDetails.signatureSchemeVersion
            < SignatureSchemeVersion.SIGNING_BLOCK_V2) {
        Slog.w(TAG, "Instant app package " + pkg.packageName
                + " is not signed with at least APK Signature Scheme v2");
        throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                "Instant app package must be signed with APK Signature Scheme v2 or greater");
    }

    // Get rid of all references to package scan path via parser.
    pp = null;
    boolean systemApp = false;
    boolean replace = false;
    synchronized (mPackages) {
        // Check if installing already existing package
        if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
            String oldName = mSettings.getRenamedPackageLPr(pkgName);
            if (pkg.mOriginalPackages != null
                    && pkg.mOriginalPackages.contains(oldName)
                    && mPackages.containsKey(oldName)) {
                // This package is derived from an original package,
                // and this device has been updating from that original
                // name.  We must continue using the original name, so
                // rename the new package here.
                pkg.setPackageName(oldName);
                pkgName = pkg.packageName;
                replace = true;
                if (DEBUG_INSTALL) {
                    Slog.d(TAG, "Replacing existing renamed package: oldName="
                            + oldName + " pkgName=" + pkgName);
                }
            } else if (mPackages.containsKey(pkgName)) {
                // This package, under its official name, already exists
                // on the device; we should replace it.
                replace = true;
                if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
            }

            // Child packages are installed through the parent package
            if (pkg.parentPackage != null) {
                throw new PrepareFailure(
                        PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
                        "Package " + pkg.packageName + " is child of package "
                                + pkg.parentPackage.parentPackage + ". Child packages "
                                + "can be updated only through the parent package.");
            }

            if (replace) {
                // Prevent apps opting out from runtime permissions
                PackageParser.Package oldPackage = mPackages.get(pkgName);
                final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion;
                final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;
                if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
                        && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
                    throw new PrepareFailure(
                            PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
                            "Package " + pkg.packageName + " new target SDK " + newTargetSdk
                                    + " doesn't support runtime permissions but the old"
                                    + " target SDK " + oldTargetSdk + " does.");
                }
                // Prevent persistent apps from being updated
                if (((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0)
                        && ((installFlags & PackageManager.INSTALL_STAGED) == 0)) {
                    throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK,
                            "Package " + oldPackage.packageName + " is a persistent app. "
                                    + "Persistent apps are not updateable.");
                }
                // Prevent installing of child packages
                if (oldPackage.parentPackage != null) {
                    throw new PrepareFailure(
                            PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
                            "Package " + pkg.packageName + " is child of package "
                                    + oldPackage.parentPackage + ". Child packages "
                                    + "can be updated only through the parent package.");
                }
            }
        }

        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 validity 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)) {
                if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
                    throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
                            + pkg.packageName + " upgrade keys do not match the "
                            + "previously installed version");
                }
            } else {
                try {
                    final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
                    final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
                    // We don't care about disabledPkgSetting on install for now.
                    final boolean compatMatch = verifySignatures(
                            signatureCheckPs, null, pkg.mSigningDetails, compareCompat,
                            compareRecover);
                    // The new KeySets will be re-added later in the scanning process.
                    if (compatMatch) {
                        synchronized (mPackages) {
                            ksms.removeAppKeySetDataLPw(pkg.packageName);
                        }
                    }
                } catch (PackageManagerException e) {
                    throw new PrepareFailure(e.error, e.getMessage());
                }
            }

            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--) {
            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) {
                Slog.w(TAG, "Non-System package " + pkg.packageName
                        + " attempting to delcare ephemeral permission "
                        + perm.info.name + "; Removing ephemeral.");
                perm.info.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT;
            }

            // 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
                        sourcePackageSetting.signatures.mSigningDetails = pkg.mSigningDetails;
                        sigsOk = true;
                    } else {
                        sigsOk = false;
                    }
                }
                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.
                    if (!sourcePackageName.equals("android")) {
                        throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
                                + pkg.packageName
                                + " attempting to redeclare permission "
                                + perm.info.name + " already owned by "
                                + sourcePackageName)
                                .conflictsWithExistingPermission(perm.info.name,
                                        sourcePackageName);
                    } else {
                        Slog.w(TAG, "Package " + pkg.packageName
                                + " attempting to redeclare system permission "
                                + perm.info.name + "; ignoring new declaration");
                        pkg.permissions.remove(i);
                    }
                } 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 ((perm.info.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
                            == PermissionInfo.PROTECTION_DANGEROUS) {
                        if (bp != null && !bp.isRuntime()) {
                            Slog.w(TAG, "Package " + pkg.packageName + " trying to change a "
                                    + "non-runtime permission " + perm.info.name
                                    + " to runtime; keeping old protection level");
                            perm.info.protectionLevel = bp.getProtectionLevel();
                        }
                    }
                }
            }
        }
    }

    if (systemApp) {
        if (onExternal) {
            // Abort update; system app can't be replaced with app on sdcard
            throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                    "Cannot install updates to system apps on sdcard");
        } else if (instantApp) {
            // Abort update; system app can't be replaced with an instant app
            throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                    "Cannot update a system app with an instant app");
        }
    }

    if (args.move != null) {
        // We did an in-place move, so dex is ready to roll
        scanFlags |= SCAN_NO_DEX;
        scanFlags |= SCAN_MOVE;

        synchronized (mPackages) {
            final PackageSetting ps = mSettings.mPackages.get(pkgName);
            if (ps == null) {
                res.setError(INSTALL_FAILED_INTERNAL_ERROR,
                        "Missing settings for moved package " + pkgName);
            }

            // We moved the entire application as-is, so bring over the
            // previously derived ABI information.
            pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
            pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
        }

    } 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();
            final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
                    derivedAbi = mInjector.getAbiHelper().derivePackageAbi(
                            pkg, abiOverride, extractNativeLibs);
            derivedAbi.first.applyTo(pkg);
            derivedAbi.second.applyTo(pkg);
        } catch (PackageManagerException pme) {
            Slog.e(TAG, "Error deriving application ABI", pme);
            throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
                    "Error deriving application ABI");
        }
    }

    if (!args.doRename(res.returnCode, pkg)) {
        throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
    }

    try {
        setUpFsVerityIfPossible(pkg);
    } catch (InstallerException | IOException | DigestException | NoSuchAlgorithmException e) {
        throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
                "Failed to set up verity: " + e);
    }

    if (!instantApp) {
        startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
    } else {
        if (DEBUG_DOMAIN_VERIFICATION) {
            Slog.d(TAG, "Not verifying instant app install for app links: " + pkgName);
        }
    }
    final PackageFreezer freezer =
            freezePackageForInstall(pkgName, installFlags, "installPackageLI");
    boolean shouldCloseFreezerBeforeReturn = true;
    try {
        final PackageParser.Package existingPackage;
        String renamedPackage = null;
        boolean sysPkg = false;
        String targetVolumeUuid = volumeUuid;
        int targetScanFlags = scanFlags;
        int targetParseFlags = parseFlags;
        final PackageSetting ps;
        final PackageSetting disabledPs;
        final PackageSetting[] childPackages;
        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.
                PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
                if (existingPkg != null
                        && existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) {
                    throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PACKAGE,
                            "Packages declaring "
                                    + "static-shared libs cannot be updated");
                }
            }

            final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;

            final PackageParser.Package oldPackage;
            final String pkgName11 = pkg.packageName;
            final int[] allUsers;
            final int[] installedUsers;

            synchronized (mPackages) {
                oldPackage = mPackages.get(pkgName11);
                existingPackage = oldPackage;
                if (DEBUG_INSTALL) {
                    Slog.d(TAG,
                            "replacePackageLI: new=" + pkg + ", old=" + oldPackage);
                }

                ps = mSettings.mPackages.get(pkgName11);
                disabledPs = mSettings.getDisabledSystemPkgLPr(ps);

                // verify signatures are valid
                final KeySetManagerService ksms = mSettings.mKeySetManagerService;
                if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
                    if (!ksms.checkUpgradeKeySetLocked(ps, pkg)) {
                        throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                                "New package not signed by keys specified by upgrade-keysets: "
                                        + pkgName11);
                    }
                } else {
                    // default to original signature matching
                    if (!pkg.mSigningDetails.checkCapability(oldPackage.mSigningDetails,
                            SigningDetails.CertCapabilities.INSTALLED_DATA)
                            && !oldPackage.mSigningDetails.checkCapability(
                            pkg.mSigningDetails,
                            SigningDetails.CertCapabilities.ROLLBACK)) {
                        throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                                "New package has a different signature: " + pkgName11);
                    }
                }

                // don't allow a system upgrade unless the upgrade hash matches
                if (oldPackage.restrictUpdateHash != null && oldPackage.isSystem()) {
                    final byte[] digestBytes;
                    try {
                        final MessageDigest digest = MessageDigest.getInstance("SHA-512");
                        updateDigest(digest, new File(pkg.baseCodePath));
                        if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
                            for (String path : pkg.splitCodePaths) {
                                updateDigest(digest, new File(path));
                            }
                        }
                        digestBytes = digest.digest();
                    } catch (NoSuchAlgorithmException | IOException e) {
                        throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
                                "Could not compute hash: " + pkgName11);
                    }
                    if (!Arrays.equals(oldPackage.restrictUpdateHash, digestBytes)) {
                        throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
                                "New package fails restrict-update check: " + pkgName11);
                    }
                    // retain upgrade restriction
                    pkg.restrictUpdateHash = oldPackage.restrictUpdateHash;
                }

                // Check for shared user id changes
                String invalidPackageName =
                        getParentOrChildPackageChangedSharedUser(oldPackage, pkg);
                if (invalidPackageName != null) {
                    throw new PrepareFailure(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
                            "Package " + invalidPackageName + " tried to change user "
                                    + oldPackage.mSharedUserId);
                }

                // In case of rollback, remember per-user/profile install state
                allUsers = sUserManager.getUserIds();
                installedUsers = ps.queryInstalledUsers(allUsers, true);


                // don't allow an upgrade from full to ephemeral
                if (isInstantApp) {
                    if (args.user == null || args.user.getIdentifier() == UserHandle.USER_ALL) {
                        for (int currentUser : allUsers) {
                            if (!ps.getInstantApp(currentUser)) {
                                // can't downgrade from full to instant
                                Slog.w(TAG,
                                        "Can't replace full app with instant app: " + pkgName11
                                                + " for user: " + currentUser);
                                throw new PrepareFailure(
                                        PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
                            }
                        }
                    } else if (!ps.getInstantApp(args.user.getIdentifier())) {
                        // can't downgrade from full to instant
                        Slog.w(TAG, "Can't replace full app with instant app: " + pkgName11
                                + " for user: " + args.user.getIdentifier());
                        throw new PrepareFailure(
                                PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
                    }
                }
            }

            // Update what is removed
            res.removedInfo = new PackageRemovedInfo(this);
            res.removedInfo.uid = oldPackage.applicationInfo.uid;
            res.removedInfo.removedPackage = oldPackage.packageName;
            res.removedInfo.installerPackageName = ps.installerPackageName;
            res.removedInfo.isStaticSharedLib = pkg.staticSharedLibName != null;
            res.removedInfo.isUpdate = true;
            res.removedInfo.origUsers = installedUsers;
            res.removedInfo.installReasons = new SparseArray<>(installedUsers.length);
            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) {
                for (PackageSetting childPs : childPackages) {
                    boolean childPackageUpdated = false;
                    PackageParser.Package childPkg = (childPs == null) ? null : childPs.pkg;
                    if (res.addedChildPackages != null) {
                        PackageInstalledInfo childRes = res.addedChildPackages.get(
                                childPkg.packageName);
                        if (childRes != null) {
                            childRes.removedInfo.uid = childPkg.applicationInfo.uid;
                            childRes.removedInfo.removedPackage = childPkg.packageName;
                            if (childPs != null) {
                                childRes.removedInfo.installerPackageName =
                                        childPs.installerPackageName;
                            }
                            childRes.removedInfo.isUpdate = true;
                            childRes.removedInfo.installReasons =
                                    res.removedInfo.installReasons;
                            childPackageUpdated = true;
                        }
                    }
                    if (!childPackageUpdated) {
                        PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(this);
                        childRemovedRes.removedPackage = childPkg.packageName;
                        if (childPs != null) {
                            childRemovedRes.installerPackageName = childPs.installerPackageName;
                        }
                        childRemovedRes.isUpdate = false;
                        childRemovedRes.dataRemoved = true;
                        synchronized (mPackages) {
                            if (childPs != null) {
                                childRemovedRes.origUsers = childPs.queryInstalledUsers(
                                        allUsers,
                                        true);
                            }
                        }
                        if (res.removedInfo.removedChildPackages == null) {
                            res.removedInfo.removedChildPackages = new ArrayMap<>();
                        }
                        res.removedInfo.removedChildPackages.put(childPkg.packageName,
                                childRemovedRes);
                    }
                }
            }


            sysPkg = (isSystemApp(oldPackage));
            if (sysPkg) {
                // Set the system/privileged/oem/vendor/product flags as needed
                final boolean privileged = isPrivilegedApp(oldPackage);
                final boolean oem = isOemApp(oldPackage);
                final boolean vendor = isVendorApp(oldPackage);
                final boolean product = isProductApp(oldPackage);
                final boolean odm = isOdmApp(oldPackage);
                final @ParseFlags int systemParseFlags = parseFlags;
                final @ScanFlags int systemScanFlags = scanFlags
                        | SCAN_AS_SYSTEM
                        | (privileged ? SCAN_AS_PRIVILEGED : 0)
                        | (oem ? SCAN_AS_OEM : 0)
                        | (vendor ? SCAN_AS_VENDOR : 0)
                        | (product ? SCAN_AS_PRODUCT : 0)
                        | (odm ? SCAN_AS_ODM : 0);

                if (DEBUG_INSTALL) {
                    Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
                            + ", old=" + oldPackage);
                }
                res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
                pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
                        ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
                targetParseFlags = systemParseFlags;
                targetScanFlags = systemScanFlags;
            } else { // non system replace
                replace = true;
                if (DEBUG_INSTALL) {
                    Slog.d(TAG,
                            "replaceNonSystemPackageLI: new=" + pkg + ", old="
                                    + oldPackage);
                }

                String pkgName1 = oldPackage.packageName;
                boolean deletedPkg = true;
                boolean addedPkg = false;
                boolean updatedSettings = false;

                final long origUpdateTime = (pkg.mExtras != null)
                        ? ((PackageSetting) pkg.mExtras).lastUpdateTime : 0;

            }
        } else { // new package install
            ps = null;
            childPackages = null;
            disabledPs = null;
            replace = false;
            existingPackage = null;
            // Remember this for later, in case we need to rollback this install
            String pkgName1 = pkg.packageName;

            if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);

            // TODO(patb): MOVE TO RECONCILE
            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.
                    throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS,
                            "Attempt to re-install " + pkgName1
                                    + " without first uninstalling package running as "
                                    + renamedPackage);
                }
                if (mPackages.containsKey(pkgName1)) {
                    // Don't allow installation over an existing package with the same name.
                    throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS,
                            "Attempt to re-install " + pkgName1
                                    + " without first uninstalling.");
                }
            }
        }
        // we're passing the freezer back to be closed in a later phase of install
        shouldCloseFreezerBeforeReturn = false;

        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();
        }
    }
}
复制代码
复制代码

restoreAndPostInstall()

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);
        //发送安装消息
        Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
        mHandler.sendMessage(msg);
    }
}
复制代码

case POST_INSTALL: {
    if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);

    PostInstallData data = mRunningInstalls.get(msg.arg1);
    final boolean didRestore = (msg.arg2 != 0);
    mRunningInstalls.delete(msg.arg1);

    if (data != null && data.mPostInstallRunnable != null) {
        data.mPostInstallRunnable.run();
    } else if (data != null) {
        InstallArgs args = data.args;
        PackageInstalledInfo parentRes = data.res;

        final boolean grantPermissions = (args.installFlags
                & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
        final boolean killApp = (args.installFlags
                & PackageManager.INSTALL_DONT_KILL_APP) == 0;
        final boolean virtualPreload = ((args.installFlags
                & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
        final String[] grantedPermissions = args.installGrantPermissions;
        final List<String> whitelistedRestrictedPermissions = ((args.installFlags
                & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0
                    && parentRes.pkg != null)
                ? parentRes.pkg.requestedPermissions
                : args.whitelistedRestrictedPermissions;

        // Handle the parent package
        handlePackagePostInstall(parentRes, grantPermissions,
                killApp, virtualPreload, grantedPermissions,
                whitelistedRestrictedPermissions, didRestore,
                args.installerPackageName, args.observer);

        // Handle the child packages
        final int childCount = (parentRes.addedChildPackages != null)
                ? parentRes.addedChildPackages.size() : 0;
        for (int i = 0; i < childCount; i++) {
            PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
            handlePackagePostInstall(childRes, grantPermissions,
                    killApp, virtualPreload, grantedPermissions,
                    whitelistedRestrictedPermissions, false /*didRestore*/,
                    args.installerPackageName, args.observer);
        }

        // Log tracing if needed
        if (args.traceMethod != null) {
            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod,
                    args.traceCookie);
        }
    } else if (DEBUG_INSTALL) {
        // No post-install when we run restore from installExistingPackageForUser
        Slog.i(TAG, "Nothing to do for post-install token " + msg.arg1);
    }

    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
} break;
复制代码
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享