Android10 APK 安装流程解析之PackageManageService篇(二)

1,714 阅读5分钟

上一篇文章:

Android10 APK 安装流程解析之PackageInstaller篇(一)

我们上一篇文章对PacakgeInstaller做了一个简单的流程分析,在最后,我们可以看到,PacakgeInstaller调用了PMS的installStage方法,将APK的安装工作委托给PMS去执行。这篇文章,我们便从PMS的installStage方法处,继续分析PMS在APK安装过程中做的工作。

PackageManagerService.installStage

void installStage(ActiveInstallSession activeInstallSession) {
    final Message msg = mHandler.obtainMessage(INIT_COPY);
    final InstallParams params = new InstallParams(activeInstallSession);
    
    msg.obj = params;
    mHandler.sendMessage(msg);
}

代码的内容很简单,向PMS里的Handler发了一个what 为INIT_COPY的Message.

我们继续看Handler里的内容:

HandlerParams params = (HandlerParams) msg.obj;
if (params != null) {
    params.startCopy();
}

它调用了HandlerPararms类里的startCopy方法。


HandlerParams.startCopy

final void startCopy() {
    handleStartCopy();
    handleReturnCode();
}

HandlerParams是一个abstract类,handleStartCopyhandleReturnCode同样也是两个abstract方法。在整包的安装流程中,它由InstallParams这个类去实现。


InstallParams.handleStartCopy

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

    // If we're already staged, we've firmly committed to an install location
    if (origin.staged) {
        if (origin.file != null) {
            installFlags |= PackageManager.INSTALL_INTERNAL;
        } else {
            throw new IllegalStateException("Invalid stage location");
        }
    }

    //是否安装在内部存储中
    final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
    //是否安装文件为Instant App
    final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
    PackageInfoLite pkgLite = null;

    //解析给定的包并返回最小的细节
    //在这个方法里,将会解析AndroidManifest.xml文件,并获得targetSdkVersion、
    //minSdkVersion、versionCode、debuggable等信息
    //与此同时,它还会去计算安装时需要的空间大小
    pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
            origin.resolvedPath, installFlags, packageAbiOverride);

    //如果磁盘可用空间太少,先尝试释放缓存。
    if (!origin.staged && pkgLite.recommendedInstallLocation
            == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
        // TODO: focus freeing disk space on the target device
        final StorageManager storage = StorageManager.from(mContext);
        final long lowThreshold = storage.getStorageLowBytes(
                Environment.getDataDirectory());

        final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
                origin.resolvedPath, packageAbiOverride);
        if (sizeBytes >= 0) {
            try {
                mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
                pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
                        origin.resolvedPath, installFlags, packageAbiOverride);
            } catch (InstallerException e) {
                Slog.w(TAG, "Failed to free cache", e);
            }
        }

        if (pkgLite.recommendedInstallLocation
                == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
            pkgLite.recommendedInstallLocation
                    = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
        }
    }


    if (ret == PackageManager.INSTALL_SUCCEEDED) {
        int loc = pkgLite.recommendedInstallLocation;
        if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
            //无法在指定的安装位置安装新包
            ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
        } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
            //已安装相同的包
            ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
        } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
            //设备剩余磁盘空间不足
            ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
        } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
           //无效的安装文件
            ret = PackageManager.INSTALL_FAILED_INVALID_APK;
        } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
             //安装文件的URI无效
            ret = PackageManager.INSTALL_FAILED_INVALID_URI;
        } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
            //由于介质不可用而无法在指定的安装位置安装新软件包
            ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
        } else {
            //检查安装状态,并根据安装的flag重新确定安装位置
            loc = installLocationPolicy(pkgLite);
            if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
                //安装不可降级
                ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
            } else if (loc == PackageHelper.RECOMMEND_FAILED_WRONG_INSTALLED_VERSION) {
                //要求的版本号和当前安装的apk的版本号不匹配
                ret = PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
            } else if (!onInt) {
                // Override install location with flags
                if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
                    // Set the flag to install on external media.
                    installFlags &= ~PackageManager.INSTALL_INTERNAL;
                } else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
                    if (DEBUG_INSTANT) {
                        Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
                    }
                    installFlags |= PackageManager.INSTALL_INSTANT_APP;
                    installFlags &= ~PackageManager.INSTALL_INTERNAL;
                } else {
                    // Make sure the flag for installing on external
                    // media is unset
                    installFlags |= PackageManager.INSTALL_INTERNAL;
                }
            }
        }
    }

    final InstallArgs args = createInstallArgs(this);
    mVerificationCompleted = true;
    mIntegrityVerificationCompleted = true;
    mEnableRollbackCompleted = true;
    mArgs = args;

    if (ret == PackageManager.INSTALL_SUCCEEDED) {
        final int verificationId = mPendingVerificationToken++;

        // 校验APK
        if (!origin.existing) {
            PackageVerificationState verificationState =
                    new PackageVerificationState(this);
            mPendingVerification.append(verificationId, verificationState);

            sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState);
            ret = sendPackageVerificationRequest(
                    verificationId, pkgLite, verificationState);

            // If both verifications are skipped, we should remove the state.
            if (verificationState.areAllVerificationsComplete()) {
                mPendingVerification.remove(verificationId);
            }
        }

          //APK 回滚相关的逻辑
        if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
            // TODO(ruhler) b/112431924: Don't do this in case of 'move'?
            final int enableRollbackToken = mPendingEnableRollbackToken++;
            Trace.asyncTraceBegin(
                    TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
            mPendingEnableRollback.append(enableRollbackToken, this);

            Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
            enableRollbackIntent.putExtra(
                    PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
                    enableRollbackToken);
            enableRollbackIntent.putExtra(
                    PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
                    mSessionId);
            enableRollbackIntent.setType(PACKAGE_MIME_TYPE);
            enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

            // Allow the broadcast to be sent before boot complete.
            // This is needed when committing the apk part of a staged
            // session in early boot. The rollback manager registers
            // its receiver early enough during the boot process that
            // it will not miss the broadcast.
            enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);

            mContext.sendOrderedBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM,
                    android.Manifest.permission.PACKAGE_ROLLBACK_AGENT,
                    new BroadcastReceiver() {
                        @Override
                        public void onReceive(Context context, Intent intent) {
                            // the duration to wait for rollback to be enabled, in millis
                            long rollbackTimeout = DeviceConfig.getLong(
                                    DeviceConfig.NAMESPACE_ROLLBACK,
                                    PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
                                    DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
                            if (rollbackTimeout < 0) {
                                rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
                            }
                            final Message msg = mHandler.obtainMessage(
                                    ENABLE_ROLLBACK_TIMEOUT);
                            msg.arg1 = enableRollbackToken;
                            msg.arg2 = mSessionId;
                            mHandler.sendMessageDelayed(msg, rollbackTimeout);
                        }
                    }, null, 0, null, null);

            mEnableRollbackCompleted = false;
        }
    }

    mRet = ret;
}

handleStartCopy主要做了以下工作:

  • 解析APK的简略信息,以满足安装的初始化要求以及信息校验需求
  • 进一步确定APK的安装位置,并确定磁盘是否有足够的安装空间,没有的话尝试释放缓存
  • 对APK安装信息做校验

HandlerParams.handleReturnCode

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) {
            //这里并没有真正执行复制操作,只是将InstallArgs里的codeFile和
            //resourceFile指向InstallParam里的文件对象
            mRet = mArgs.copyApk();
        }
        //执行安装操作
        processPendingInstall(mArgs, mRet);
    }
}

processPendingInstall

private void processPendingInstall(final InstallArgs args, final int currentStatus) {
    if (args.mMultiPackageInstallParams != null) {
        args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
    } else {
        //单包走这个分支
        //PackageInstalledInfo 用于保存 安装的结果,成功还是失败,失败原因是什么
        PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
        processInstallRequestsAsync(
                res.returnCode == PackageManager.INSTALL_SUCCEEDED,
                Collections.singletonList(new InstallRequest(args, res)));
    }
}

processInstallRequestsAsync

private void processInstallRequestsAsync(boolean success,
        List<InstallRequest> installRequests) {
        //在Handler所在的线程执行安装操作,这是个子线程
    mHandler.post(() -> {
        if (success) {
            for (InstallRequest request : installRequests) {
                //检测returnCode是否为INSTALL_SUCCEEDED,否的话清除复制的APK并删除相关目录与文件
                request.args.doPreInstall(request.installResult.returnCode);
            }
            synchronized (mInstallLock) {
                //解析APK
                installPackagesTracedLI(installRequests);
            }
            for (InstallRequest request : installRequests) {
                //和doPreInstall方法一样
                request.args.doPostInstall(
                        request.installResult.returnCode, request.installResult.uid);
            }
        }
        for (InstallRequest request : installRequests) {
            //APK安装完成的后续操作,如apk备份、回滚、发送安装相关的广播
            restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
                    new PostInstallData(request.args, request.installResult, null));
        }
    });
}

installPackagesTracedLI方法里只是简单的调用installPackagesLI。我们重点来看installPackagesLI方法,它负责Apk的内容的解析,属于安装过程中的核心方法。


installPackagesLI

private void installPackagesLI(List<InstallRequest> requests) {
    final Map<String, ScanResult> preparedScans = new ArrayMap<>(requests.size());
    final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
    final Map<String, PackageInstalledInfo> installResults = new ArrayMap<>(requests.size());
    final Map<String, PrepareResult> prepareResults = new ArrayMap<>(requests.size());
    final Map<String, VersionInfo> versionInfos = new ArrayMap<>(requests.size());
    final Map<String, PackageSetting> lastStaticSharedLibSettings =
            new ArrayMap<>(requests.size());
    final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size());
    boolean success = false;
    try {
        for (InstallRequest request : requests) {
            final PrepareResult prepareResult;
            try {
                //准备阶段,根据安装信息确定扫描Flags,在这个方法里,主要做了以下几件事
                //1、对apk的AndroidManifest.xml文件做了全面的解析,比如apk中的所有
                //activity、service、permission等信息,并将解析结果保存在了PackageParser.Package类里
                //2、通过Dm-verity校验dex文件的有效性
                //3、解析apk签名信息
                //4、解析android资源索引表resources.arsc文件
                prepareResult = preparePackageLI(request.args, request.installResult);
            } catch (PrepareFailure prepareFailure) {
                request.installResult.setError(prepareFailure.error,
                        prepareFailure.getMessage());
                request.installResult.origPackage = prepareFailure.conflictingPackage;
                request.installResult.origPermission = prepareFailure.conflictingPermission;
                return;
            } finally {
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
            request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
            request.installResult.installerPackageName = request.args.installerPackageName;

            final String packageName = prepareResult.packageToScan.packageName;
            //保存了APK预解析信息
            prepareResults.put(packageName, prepareResult);
            //保存安装结果
            installResults.put(packageName, request.installResult);
            //保存安装的请求参数
            installArgs.put(packageName, request.args);
            try {
                //扫描阶段,进一步搜集apk信息,比如PackageSetting、apk里的动态库和静态库的位置
                final List<ScanResult> scanResults = scanPackageTracedLI(
                        prepareResult.packageToScan, prepareResult.parseFlags,
                        prepareResult.scanFlags, System.currentTimeMillis(),
                        request.args.user);
                for (ScanResult result : scanResults) {
                    //保存APK扫描结果
                    if (null != preparedScans.put(result.pkgSetting.pkg.packageName, result)) {
                        request.installResult.setError(
                                PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
                                "Duplicate package " + result.pkgSetting.pkg.packageName
                                        + " in multi-package install request.");
                        return;
                    }
                    //向系统中注册一个appId
                    createdAppId.put(packageName, optimisticallyRegisterAppId(result));
                    //app版本信息管理
                    versionInfos.put(result.pkgSetting.pkg.packageName,
                            getSettingsVersionForPackage(result.pkgSetting.pkg));
                    if (result.staticSharedLibraryInfo != null) {
                        final PackageSetting sharedLibLatestVersionSetting =
                                getSharedLibLatestVersionSetting(result);
                        if (sharedLibLatestVersionSetting != null) {
                           //lib库信息管理 lastStaticSharedLibSettings.put(result.pkgSetting.pkg.packageName,
                                    sharedLibLatestVersionSetting);
                        }
                    }
                }
            } catch (PackageManagerException e) {
                request.installResult.setError("Scanning Failed.", e);
                return;
            }
        }
        
        //验证阶段,需要对apk的签名进行校验,是否与已安装的apk签名不一致。还有是否需要在安装前先执行删除动作
        ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
                installResults,
                prepareResults,
                mSharedLibraries,
                Collections.unmodifiableMap(mPackages), versionInfos,
                lastStaticSharedLibSettings);
        CommitRequest commitRequest = null;
        synchronized (mPackages) {
            Map<String, ReconciledPackage> reconciledPackages;
            try {
                //开始校验apk能否安装
                reconciledPackages = reconcilePackagesLocked(
                        reconcileRequest, mSettings.mKeySetManagerService);
            } catch (ReconcileFailure e) {
                for (InstallRequest request : requests) {
                    request.installResult.setError("Reconciliation failed...", e);
                }
                return;
            } finally {
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
            try {
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
                commitRequest = new CommitRequest(reconciledPackages,
                        sUserManager.getUserIds());
                //如果需要对应用做覆盖安装,首先删掉已安装的应用
                //并更新PackageSetting信息
                commitPackagesLocked(commitRequest);
                success = true;
            } finally {
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
        }
        //安装成功后的后续操作
        //1、为安装的app 创建app data目录,已存在时对目录进行校验,该操作主要是Installd进程负责完成
        //2. 准备新代码路径的应用程序配置文件,需要在调用dexopt之前完成
        //3. 检查是否需要对dex文件做优化,如果需要的话执行优化操作
        executePostCommitSteps(commitRequest);
    } finally {
        if (!success) {
            for (ScanResult result : preparedScans.values()) {
                if (createdAppId.getOrDefault(result.request.pkg.packageName, false)) {
                    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以原子方式安装一个或多个程序包。此操作分为四个阶段:

  • 准备阶段 : 分析当前的安装信息,解析包的AndroidManifest.xml文件并对其进行初始验证。
  • 扫描阶段 : 根据准备阶段中收集的上下文扫描包并进一步解析的包里的内容。
  • 验证阶段 : 对软件包信息进行校验,比如校验签名,以确保安装成功。
  • 提交阶段 : 提交所有扫描的包的信息并更新系统状态。这是安装流程中唯一可以修改系统状态的地方,在此阶段之前必须对所有可预测的错误做检查。

有读者就会问了,上面的流程都是对apk文件里的信息做解析,安装的过程在哪里?

android的安装主要生成了以下文件:

  1. PackageInstallerSessiondoWriteInternal方法,将apk文件复制到/data/app/vmdl${sessionId}.tmp/base.apk路径下。

  2. PackageInstallerSessioncommitNonStagedLocked方法中会调用extractNativeLibraries方法,将apk文件里的Native Lib文件解压到/data/app/vmdl${sessionId}.tmp/lib目录下。

  3. 准备阶段preparePackageLI会将安装目录由vmdl${sessionId}.tmp重命名为${packageName}-${Base64.encodeToString(随机16位byte数组)}

  4. 提交阶段executePostCommitSteps方法会调用PackageDexOptimizer中的performDexOpt方法,在/data/app/${packageName}-${Base64.encodeToString(随机16位byte数组)}/oat目录下生成base.art,base.odex,base.vdex三个文件。


最后,我们用流程图来总结一下Apk的安装过程:

未命名文件.png