PackageManagferService (三) 应用安装

前言

上一篇《PackageManagerService(二)权限管理》描述了 Android 中 PackageManagerService 对于应用权限的管理。本篇将会介绍 PackageManagerService 应用安装流程。将会从整体架构展开,对于各层各模块所完成的功能进行简要描述。对于架构层面,会对于通信机制进行描述;对于模块层面,通过各模块提供的功能接口进行简要整理。

安装模块流程 PackageInstaller -> PackageInstallerService -> PackageManagerService -> Installer -> InstalldNativeService

​ IPackageInstaller.aidl

​ IInstalld.aidl

正文

1、应用安装概述

本章节将会对应用安装进行简要的描述,包括 Android 安装应用的方式、apk 安装包的结构以及如何打包的、apk 的签名及系统通过验签判断是否能将应用包是否允许安装到系统中。从以上三个方向展开描述。

1.1 应用安装方式

Android 应用安装有四种方式:开机自动安装、下载安装、adb 安装、第三方应用安装。

1.1.1 开机自动安装

开机自动安装是将应用安装包 push 到文件系统目录中,在 Android 的启动流程中,会在文件系统目录中(具体请见 PackageManagerService 初始化概述)去检索所有的 apk 文件,进行安装。

  • 方式:adb push
  • 界面:无

此安装方式没有安装界面,将 apk 文件 push 到车机内后,需要重新启动,执行开机流程进行自动安装。

1.1.2 下载安装

下载安装是通过应用商店或者网络下载 apk 的方式安装应用。当然应用商店各厂商平台会使用自研应用,逻辑、界面由厂商完成。内部可能通过 PackageInstaller 提供的接口进行应用的安装。

  • 方式:应用商店/网络下载安装
  • 界面:有
1.1.3 adb 安装

adb 安装是通过 adb install (adb shell pm install) 命令的方式安装应用。通过 adb 命令触发,这个过程会将 apk 文件 copy 到 /data/local/tmp/ 目录下,然后向 shell 服务发送 pm 命令安装 apk,最后调用 pm.runInstall() 方法来安装应用。

  • 方式:adb install
  • 界面:无

adb 命令对应的源码路径是:/android/system/core/adb/。commandline.c 根据传入 adb 参数判断是 install 安装指令,调用到 install_app()。

install_app() 中会完成如下操作:

​ 确定文件拷贝位置,分别对应拷贝到内部存储或者外部存储。这里是根据传入的参数确定的,默认是拷贝到内部存储。

​ 执行拷贝:将 apk 文件从电脑端拷贝到上述确定的目录中

​ 执行安装:调用 pm_command() 函数开始安装

​ 删除文件:当安装结束时删除该 apk 文件

pm_command() 安装是通过构造 shell 指令,通过 shell 的方式使用 send_shellcommand() 去执行 pm 脚本,使用 app_process 运行 pm.jar。

我们这里来跟踪下 adb 是如何跟 pm 关联的,上面描述了 adb 是通过 shell 的方式调用 pm 脚本完成的,这里可能会觉得模糊,通过几个问题整理下:

  • 问:pm 脚本在文件系统的哪个路径下?

答:/system/bin 目录下,下面是机器内部的文件

/system/bin $ ls -l | grep -i pm
-rwxr-xr-x 1 root   shell          34 2009-01-01 08:00 pm

/system/bin $ md5sum pm
ad18e38b44b0f9d47f12bbe9e25c15a6  pm
  • pm 脚本对应的文件在源码哪里?或者说是在哪里将脚本放到文件系统中的

答:路径为 /android/frameworks/base/cmds/pm。在 cmd 中,会保存系统支持的指令脚本文件,cmd 命令最终会通过解析,根据不同的参数调用到不同的脚本,支持的指令如下所示:
在这里插入图片描述
下面是 pm 的目录结构,可以发现有预置的 pm 脚本,通过 md5 对比确认发现跟文件系统内的 /system/bin/pm 脚本的 md5 值一致,通过 Android.mk 中可以发现是通过 BUILD_PREBUILT 预编译脚本。

/android/frameworks/base/cmds/pm$ tree
.
├── Android.mk
├── MODULE_LICENSE_APACHE2
├── NOTICE
└── pm  // md5sum pm = ad18e38b44b0f9d47f12bbe9e25c15a6  pm

--------------------------------------------------------------------------------------------------------------------------------
Android.mk
# Copyright 2007 The Android Open Source Project
#
LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := pm
LOCAL_SRC_FILES := pm
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_TAGS := optional
include $(BUILD_PREBUILT)

总结:通过 pm 的流程发现,实际是预编译脚本封装了 PackageManager 的方法,adb 通过 shell 执行 pm 脚本从而跟 PackageManager 交互。那么其他 cmd 命令的流程可能也是如此。

下图是 adb install 执行流程图:
在这里插入图片描述

1.1.4 第三方应用安装

第三方应用安装指的是通过非厂商提供的应用商店或者网络下载 apk 的方式安装,而是通过第三方应用,例如:应用宝等,下载并安装应用,其内部可能也是通过 PackageInstaller 的接口触发应用安装

  • 方式:通过第三方应用
  • 界面:有
1.1.5 应用安装方式对比图

下面是各方式触发对比图,可以简单对比加深了解。
在这里插入图片描述

1.2 应用安装包结构

应用包文件实际是一个 zip 文件,是被 Google 修改了后缀名称,将 apk 文件后缀改成 zip 可以查看内容,一般会有如下:

文件/目录描述
assert存放的原生资源文件,通过 AssetManager 类访问
libnative 库文件
META-INF存放签名信息,用来保证APK包的完整性和系统的安全。系统安装 APK 时应用管理器会按照对应算法对包里文件做校验,如果校验结果与 META-INF 中内容不一致,则不会安装这个 APK。
res资源文件,是被编译过的。raw 和图片是保持原样的,但是其他的文件会被编译成二进制文件。
AndroidManifest.xml每个应用都必须定义和包含,描述应用的名字、版本权限、引用的库文件等信息。apk 中的 AndroidManifest.xml 经过压缩,可以通过 AXMLPrinter2 工具解开。
classes.dexDalvik 字节码文件,Android 会将所有的 class 文件全部放到这个文件里。Android 使用的 dalvik 虚拟机与标准的 JAVA 虚拟机不兼容,dex 文件与 class 文件相比,不论是文件结构还是 opcode 都不一样。
resources.arsc编译后的二进制资源文件,保存资源文件的索引,由 aapt 生成

1.3 安装包打包过程及签名验签

1.3.1 安装包打包过程

应用安装包打包过程简要图如下所示:
在这里插入图片描述
编译器将应用源码以及应用使用的外部库例如 so、aar、jar 等转换成 DEX(Dalvik Executeable)执行文件,将资源文件编译成已编译资源。

打包器将 DEX 文件和已经编译的资源文件合并成单个 apk 文件,并对 apk 进行签名。

1.3.2 应用包签名及验签
1.3.2.1 概述

应用包签名及验签是为了确保安装到本系统的应用是被允许的。系统中的预置应用在版本编译期间会被加签,在安装是会去使用同一套密钥去验签,如果验签不通过,说明此应用没有经过系统安全允许。Android 原生是有一套安全密钥的,在 android/build/target/product/security 目录下,加签和验签均是使用的同一套密钥。各厂商可以替换此目录下的密钥,将原生的密钥替换成自己的密钥,那么除预置应用外,未经过厂商加签的应用安装时会被阻拦,从而让系统更加安全。对于一般项目而言,对于 userdebug 版本在调试阶段可以使用 Android 原生的密钥,对于 user 版本在用户阶段可以使用厂商密钥来保证系统的安全。注意,如果要替换厂商密钥,需要在首版发布前替换,以免引入其他问题,毕竟需要使用此目录下密钥的不仅仅是应用安装,如果在发版中间版本替换,会引出前后两版本密钥不匹配导致的差异问题。

1.3.2.2 签名方案
V1

APK 最初的签名方式,通过 jarsigner 进行签名,签名完之后是META-INF 目录下的三个文件:MANIFEST.MF、CERT.SF、CERT.RSA。

MANIFEST.MF:apk中每个文件名称和摘要SHA1(或者 SHA256),如果是目录则只有名称。

CERT.SF则是对MANIFEST.MF的摘要,包括三个部分:

​ SHA1-Digest-Manifest-Main-Attributes:对 MANIFEST.MF 头部的块做 SHA1(或者SHA256)后再用 Base64 编码。

​ SHA1-Digest-Manifest:对整个 MANIFEST.MF 文件做 SHA1(或者 SHA256)后再用 Base64 编码。

​ SHA1-Digest:对 MANIFEST.MF 的各个条目做 SHA1(或者 SHA256)后再用 Base64 编码。

CERT.RSA是将CERT.SF通过私钥签名,然后将签名以及包含公钥信息的数字证书一同写入 CERT.RSA 中保存。

通过这三层校验来确保apk中的每个文件都不被改动。

V2

APK 签名方案 v2 是在 Android 7.0 (Nougat) 中引入的。为了使 APK 可在 Android 6.0 (Marshmallow) 及更低版本的设备上安装,应先使用 JAR 签名功能对 APK 进行签名,然后再使用 v2 方案对其进行签名。

APK v1的缺点就是 META-INF 目录下的文件并不在校验范围内,所以之前多渠道打包等都是通过在这个目录下添加文件来实现的。

APK 签名方案 v2 是一种全文件签名方案,该方案能够发现对 APK 的受保护部分进行的所有更改,从而有助于加快验证速度并增强完整性保证。

使用 APK 签名方案 v2 进行签名时,会在 APK 文件中插入一个 APK 签名分块,该分块位于ZIP 中央目录 部分之前并紧邻该部分。在“APK 签名分块”内,v2 签名和签名者身份信息会存储在 APK 签名方案 v2 分块中。
在这里插入图片描述
通俗点说就是签名信息不再以文件的形式存储,而是将其转成二进制数据直接写在apk文件中,这样就避免了APK v1的 META-INF 目录的问题。

在 Android 7.0 及更高版本中,可以根据 APK 签名方案 v2+ 或 JAR 签名(v1 方案)验证 APK。更低版本的平台会忽略 v2 签名,仅验证 v1 签名。

V3

APK 签名方案 v3 是在 Android 9 中引入的。

Android 9 支持 APK 密钥轮替,这使应用能够在 APK 更新过程中更改其签名密钥。为了实现轮替,APK 必须指示新旧签名密钥之间的信任级别。为了支持密钥轮替,我们将 APK 签名方案从 v2 更新为 v3,以允许使用新旧密钥。v3 在 APK 签名分块中添加了有关受支持的 SDK 版本和 proof-of-rotation 结构的信息。

简单来说APK v3就是为了 Andorid 9 的APK 密钥轮替功能而出现的,就是在v2的基础上增加两个数据块来存储APK 密钥轮替所需要的一些信息,所以可以看成是v2的升级。具体结构见官网说明即可。

在 Android 9 及更高版本中,可以根据 APK 签名方案 v3、v2 或 v1 验证 APK。较旧的平台会忽略 v3 签名而尝试验证 v2 签名,然后尝试验证 v1 签名。
在这里插入图片描述

V4

APK 签名方案 v4 是在 Android 11 中引入的。

Android 11 通过 APK 签名方案 v4 支持与流式传输兼容的签名方案。v4 签名基于根据 APK 的所有字节计算得出的 Merkle 哈希树。它完全遵循 fs-verity 哈希树的结构(例如,对salt进行零填充,以及对最后一个分块进行零填充。)Android 11 将签名存储在单独的 [apk name].apk.idsig 文件中。v4 签名需要 v2 或 v3 签名作为补充。

APK v4同样是为了新功能而出现的,这个新功能就是 ADB 增量 APK 安装,可以参考Android11 功能和 API 概览: https://developer.android.google.cn/about/versions/11/features 。

因为需要流式传输,所以需要将文件分块,对每一块进行签名以便校验,使用的方式就是 Merkle 哈希树,APK v4就是做这部分功能的。所以APK v4与APK v2或APK v3可以算是并行的,所以APK v4签名后还需要 v2 或 v3 签名作为补充。

运行 adb install --incremental 命令时,adb 会要求 .apk.idsig 文件存在于 .apk 旁边(所以APK v4的签名文件.apk.idsig并不会打包进apk文件中)。

默认情况下,它还会使用 .idsig 文件尝试进行增量安装;如果此文件缺失或无效,该命令会回退到常规安装。

1.3.2.3 验签流程

应用在进行安装的过程中,PackageManagerService 会对应用的签名进行验证,以判断是否允许安装到系统中。

在 PackageManagerService 中,对应应用签名的校验是通过 collectCertificatesLI() 函数完成的,接下来我们将简要分析 PackageManagerService 是如何进行应用验签的。

下图是 collectCertificatesLI() 验证的简要流程:
在这里插入图片描述
下面是代码分析:

// android/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

	private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg,
            boolean forceCollect, boolean skipVerify) throws PackageManagerException {
        // When upgrading from pre-N MR1, verify the package time stamp using the package
        // directory and not the APK file.
        final long lastModifiedTime = mIsPreNMR1Upgrade
                ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg);
        final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(pkg);
        if (ps != null && !forceCollect
                && ps.codePathString.equals(pkg.codePath)
                && ps.timeStamp == lastModifiedTime
                && !isCompatSignatureUpdateNeeded(settingsVersionForPackage)
                && !isRecoverSignatureUpdateNeeded(settingsVersionForPackage)) {
            if (ps.signatures.mSigningDetails.signatures != null
                    && ps.signatures.mSigningDetails.signatures.length != 0
                    && ps.signatures.mSigningDetails.signatureSchemeVersion
                            != SignatureSchemeVersion.UNKNOWN) {
                // Optimization: reuse the existing cached signing data
                // if the package appears to be unchanged.
                pkg.mSigningDetails =
                        new PackageParser.SigningDetails(ps.signatures.mSigningDetails);
                return;
            }

            Slog.w(TAG, "PackageSetting for " + ps.name
                    + " is missing signatures.  Collecting certs again to recover them.");
        } else {
            Slog.i(TAG, pkg.codePath + " changed; collecting certs" +
                    (forceCollect ? " (forced)" : ""));
        }

        try {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
            PackageParser.collectCertificates(pkg, skipVerify);  // 实际调用 PackageParser.collectCertificates() 函数进行验签
        } catch (PackageParserException e) {
            throw PackageManagerException.from(e);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }

进入 PackageParser 的 collectCertificates() 函数

// android/frameworks/base/core/java/android/content/pm/PackageParser.java

    /**
     * Collect certificates from all the APKs described in the given package,
     * populating {@link Package#mSigningDetails}. Also asserts that all APK
     * contents are signed correctly and consistently..
     * 从给定包中描述的所有apk中收集证书,填充{@link package #mSigningDetails}。还断言所有APK内容的签名是正确和一致的。
     */
    @UnsupportedAppUsage
    public static void collectCertificates(Package pkg, boolean skipVerify)
            throws PackageParserException {
        // 调用 collectCertificatesInternal() 函数继续处理
        collectCertificatesInternal(pkg, skipVerify);
        // 下面是对于分包的处理
        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
        for (int i = 0; i < childCount; i++) {
            Package childPkg = pkg.childPackages.get(i);
            childPkg.mSigningDetails = pkg.mSigningDetails;
        }
    }

    private static void collectCertificatesInternal(Package pkg, boolean skipVerify)
            throws PackageParserException {
        // 这里是初始化 pkg 包的验签方案,对应[UNKNOWN:0 JAR:1 SIGNING_BLOCK_V2:2 SIGNING_BLOCK_V3:3]
        pkg.mSigningDetails = SigningDetails.UNKNOWN;

        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
        try {
            // 调用重载函数进行 apk 验签
            collectCertificates(pkg, new File(pkg.baseCodePath), skipVerify);

            // 下面是对于分裂 apk 路径的处理
            if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
                for (int i = 0; i < pkg.splitCodePaths.length; i++) {
                    collectCertificates(pkg, new File(pkg.splitCodePaths[i]), skipVerify);
                }
            }
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }

    @UnsupportedAppUsage
    private static void collectCertificates(Package pkg, File apkFile, boolean skipVerify)
            throws PackageParserException {
        // 先获取到 apk 路径
        final String apkPath = apkFile.getAbsolutePath();

        // 最小验签方案等级为 V1,就是 JAR 包验签
        int minSignatureScheme = SigningDetails.SignatureSchemeVersion.JAR;
        if (pkg.applicationInfo.isStaticSharedLibrary()) {
            // must use v2 signing scheme
            minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
        }
        // 定义 SigningDetails,用于对应用程序包的相关数据进行签名的容器。
        SigningDetails verified;
        if (skipVerify) {
            // systemDir APKs are already trusted, save time by not verifying
            // 对于系统路径应用,已经是信任的了,跳过验证节省时间
            verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
                        apkPath, minSignatureScheme);
        } else {
            // 对于不能跳过验证的应用,调用 ApkSignatureVerifier.verify(),传入应用路径以及验签方案等级
            verified = ApkSignatureVerifier.verify(apkPath, minSignatureScheme);
        }

        // Verify that entries are signed consistently with the first pkg
        // we encountered. Note that for splits, certificates may have
        // already been populated during an earlier parse of a base APK.
        // 验证条目的签名是否与我们遇到的第一个 pkg 一致。注意,对于拆分,证书可能已经在早期解析基本 APK 期间填充。
        if (pkg.mSigningDetails == SigningDetails.UNKNOWN) {
            pkg.mSigningDetails = verified;
        } else {
            // 验证 pkg 包中保存的签名与计算的签名是否一致
            if (!Signature.areExactMatch(pkg.mSigningDetails.signatures, verified.signatures)) {
                throw new PackageParserException(
                        INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
                        apkPath + " has mismatched certificates");
            }
        }
    }

进入 ApkSignatureVerifier.verify() 函数

// android/frameworks/base/core/java/android/util/apk/ApkSignatureVerifier.java

    /**
     * Verifies the provided APK and returns the certificates associated with each signer.
     * 验证提供的APK并返回与每个签名者关联的证书
     *
     * @throws PackageParserException if the APK's signature failed to verify.
     */
    public static PackageParser.SigningDetails verify(String apkPath,
            @SignatureSchemeVersion int minSignatureSchemeVersion)
            throws PackageParserException {

        if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V3) {
            // V3 and before are older than the requested minimum signing version
            throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
                    "No signature found in package of version " + minSignatureSchemeVersion
            + " or newer for package " + apkPath);
        }

        // 首先会先进行 V3 方案的验证
        // first try v3
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV3");
        try {
            // v3 方案验证处理类 ApkSignatureSchemeV3Verifier
            ApkSignatureSchemeV3Verifier.VerifiedSigner vSigner =
                    ApkSignatureSchemeV3Verifier.verify(apkPath);
            Certificate[][] signerCerts = new Certificate[][] { vSigner.certs };
            Signature[] signerSigs = convertToSignatures(signerCerts);
            Signature[] pastSignerSigs = null;
            if (vSigner.por != null) {
                // populate proof-of-rotation information
                pastSignerSigs = new Signature[vSigner.por.certs.size()];
                for (int i = 0; i < pastSignerSigs.length; i++) {
                    pastSignerSigs[i] = new Signature(vSigner.por.certs.get(i).getEncoded());
                    pastSignerSigs[i].setFlags(vSigner.por.flagsList.get(i));
                }
            }
            return new PackageParser.SigningDetails(
                    signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V3,
                    pastSignerSigs);
        } catch (SignatureNotFoundException e) {
            // not signed with v3, try older if allowed
            if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V3) {
                throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
                        "No APK Signature Scheme v3 signature in package " + apkPath, e);
            }
        } catch (Exception e) {
            // APK Signature Scheme v2 signature found but did not verify
            throw new  PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
                    "Failed to collect certificates from " + apkPath
                            + " using APK Signature Scheme v3", e);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }

        // redundant, protective version check
        if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V2) {
            // V2 and before are older than the requested minimum signing version
            throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
                    "No signature found in package of version " + minSignatureSchemeVersion
                            + " or newer for package " + apkPath);
        }

        // 进行 V2 方案验证
        // try v2
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV2");
        try {
            // v2 方案验证处理类 ApkSignatureSchemeV2Verifier
            Certificate[][] signerCerts = ApkSignatureSchemeV2Verifier.verify(apkPath);
            Signature[] signerSigs = convertToSignatures(signerCerts);

            return new PackageParser.SigningDetails(
                    signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V2);
        } catch (SignatureNotFoundException e) {
            // not signed with v2, try older if allowed
            if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V2) {
                throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
                        "No APK Signature Scheme v2 signature in package " + apkPath, e);
            }
        } catch (Exception e) {
            // APK Signature Scheme v2 signature found but did not verify
            throw new  PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
                    "Failed to collect certificates from " + apkPath
                            + " using APK Signature Scheme v2", e);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }

        // redundant, protective version check
        if (minSignatureSchemeVersion > SignatureSchemeVersion.JAR) {
            // V1 and is older than the requested minimum signing version
            throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
                    "No signature found in package of version " + minSignatureSchemeVersion
                            + " or newer for package " + apkPath);
        }

        // 进行 V1 方案的验证
        // v2 didn't work, try jarsigner
        return verifyV1Signature(apkPath, true);
    }

简单概述下 v1 签名验证的流程:使用 CERT.RSA 这个文件中包含的公钥对数字签名进行解密,将解密后得到的 Hash 值结果与 CERT.SF 文件 hash 运算后的结果进行对比,一致的话就表明 CERT.SF 文件没有被篡改。

对于 V2 和 V3 方案的验证,由封装类完成,其大致原理应该与 V1 类似。

2、应用安装流程

本章节的应用安装流程是以下载安装的方式展开描述的。在应用的 apk 包下载完毕之后,点击进行安装时,系统会经过一系列模块进行处理,相关模块有:PackageInstaller、PackageManagerService、Installd。下面将会模块处理的顺序对应用安装流程展开描述。

PackageInstaller 是系统预置的软件包安装程序,当用户确认安装时,PackageInstaller 会组建 SessionParams 会话参数,通过 PackageInstaller 与 PackageInstallerService 通信创建 PackageInstallerSession 对象并返回对应 SessionId,在 onResume() 方法中创建了 InstallingAsyncTask 实例用于异步工作,InstallingAsyncTask 会将 apk 文件以流的方式写入到 PackageInstallerSession 中,完全写入之后会调用 PackageInstallerSession 的 commit() 函数进行安装,到这里 PackageInstaller 的除了信息回调的处理外,基本进入下一流程。

PackageInstallerSession 的 commit() 函数主要是组建了一则 MSG_COMMIT 的 Message 消息,消息处理对应 handleCommit() 函数,内部调用 commitNonStagedLocked() 函数,commitNonStagedLocked() 函数调用 PackageManagerService 的 installStage() 函数,并传入 ActiveInstallSession 作为参数。进入 PackageManagerService 流程。

PackageManagerService 的 installStage() 函数包含 ActiveInstallSession 参数,installStage() 函数主要组件一个 Message 消息,Message 内部包含 INIT_COPY 以及 InstallParams,InstallParams 是安装参数,是以及 ActiveInstallSession 对象创建的,将 Message 消息通过 Handler 转发处理。

2.1 相关模块及代码路径

模块一:PackageInstaller
路径:/android/frameworks/base/packages/PackageInstaller  // PackageInstaller 应用代码路径
跨进程方式:aidl
跨进程文件:
	/android/frameworks/base/core/java/android/content/pm/IPackageInstaller.aidl  // PackageInstaller 的 aidl 文件
	/android/frameworks/base/core/java/android/content/pm/IPackageInstallerSession.aidl  // PackageInstallSession 的 aidl 文件
客户端:
	/android/frameworks/base/core/java/android/content/pm/PackageInstaller.java  // PackageInstaller 对外提供功能接口的文件
服务端:
	/android/frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java  // PackageInstaller 的服务端
	/android/frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java  // PackageInstallerSession 的服务端

--------------------------------------------------------------------------------------------------------------------------------

模块二:PackageManagerService
路径:/android/frameworks/base/services/core/java/com/android/server/pm  // PackageManagerService 服务端代码路径
跨进程方式:aidl
跨进程文件:
	/android/frameworks/base/core/java/android/content/pm/IPackageManager.aidl  // PackageManager 的 aidl 文件
客户端:
	/android/frameworks/base/core/java/android/content/pm/PackageManager.java  // PackageManager 对外提供功能接口的文件
服务端:
	/android/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java  // PackageManagerService 服务端文件

--------------------------------------------------------------------------------------------------------------------------------

模块三:Installd
路径:/android/frameworks/native/cmds/installd  // Installd 服务代码路径
跨进程方式:aidl
跨进程文件:
	/android/frameworks/native/cmds/installd/binder/android/os/IInstalld.aidl  // Installd 的 aidl 文件
客户端:
	/android/frameworks/base/services/core/java/com/android/server/pm/Installer.java  // Installer 提供 Installd 功能接口的文件
服务端:
	/android/frameworks/native/cmds/installd/installd.cpp  // Installd 服务的启动文件
	/android/frameworks/native/cmds/installd/InstalldNativeService.cpp  // Installd 服务的实现文件

2.2 序列图

在这里插入图片描述

2.3 安装流程

2.3.1 PackageInstaller

安装流程首先会调用到 PackageInstaller 中,PackageInstaller 是 Android 提供的安装应用。

2.3.1.1 PackageInstallerActivity.startInstall()

当用户点击确认安装时,PackageInstall 安装应用会调用 PackageInstallerActivity.startInstall() 进行安装流程。

startInstall() 方法组装了一个 Intent,并跳转到 InstallInstalling 这个 Activity,并关闭掉当前的 PackageInstallerActivity。

    private void startInstall() {
        // Start subactivity to actually install the application
        Intent newIntent = new Intent();
        newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
                mPkgInfo.applicationInfo);
        newIntent.setData(mPackageURI);
        newIntent.setClass(this, InstallInstalling.class);  // 打开 InstallInstalling Activity
        String installerPackageName = getIntent().getStringExtra(
                Intent.EXTRA_INSTALLER_PACKAGE_NAME);
        if (mOriginatingURI != null) {
            newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
        }
        if (mReferrerURI != null) {
            newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
        }
        if (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
            newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
        }
        if (installerPackageName != null) {
            newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
                    installerPackageName);
        }
        if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
            newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
        }
        newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
        if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
        startActivity(newIntent);  // 开启新的 Activity
        finish();
    }
2.3.1.2 InstallInstalling.onCreate()

进入 InstallInstalling Activity,首先进入 onCreate() 函数。

在 onCreate() 函数中,主要完成下面的工作:

  • 对于 Package 协议,判断是否已经安装完成
  • 对于 File,判断是否是继续安装还是全新安装,继续安装情况下,获取之前的 sessionId 和 installId,并且根据 installId 注册安装监听;对于全新安装情况,需要根据传入的 apk 信息组装会话参数 SessionParams 对象,并以此创建新的 sessionId,注册新的观察监听安装事件。
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ApplicationInfo appInfo = getIntent()
                .getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
        mPackageURI = getIntent().getData();

        // 这里对于 package 协议,调用 PackageManager.installExistingPackage() 函数,判断是否已经安装成功
        if ("package".equals(mPackageURI.getScheme())) {
            try {
                getPackageManager().installExistingPackage(appInfo.packageName);
                launchSuccess();
            } catch (PackageManager.NameNotFoundException e) {
                launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
            }
        } else {
            // 对于 File 类型,则需要进行安装
            final File sourceFile = new File(mPackageURI.getPath());
            PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo, sourceFile);

            mAlert.setIcon(as.icon);
            mAlert.setTitle(as.label);
            mAlert.setView(R.layout.install_content_view);
            mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
                    (ignored, ignored2) -> {
                        if (mInstallingTask != null) {
                            mInstallingTask.cancel(true);
                        }

                        if (mSessionId > 0) {
                            getPackageManager().getPackageInstaller().abandonSession(mSessionId);
                            mSessionId = 0;
                        }

                        setResult(RESULT_CANCELED);
                        finish();
                    }, null);
            setupAlert();
            requireViewById(R.id.installing).setVisibility(View.VISIBLE);

            // 判断 savedInstanceState 是否为空,如果为空的话,表明可能之前进行过安装,此时需要获取之前的会话 id mSessionId 和 等待安装事件 id mInstallId
            if (savedInstanceState != null) {
                mSessionId = savedInstanceState.getInt(SESSION_ID);
                mInstallId = savedInstanceState.getInt(INSTALL_ID);

                // Reregister for result; might instantly call back if result was delivered while
                // activity was destroyed
                // 根据 mInstallId 向 InstallEventReceiver 注册一个观察者,launchFinishBasedOnResult 会接收到安装事件的回调,无论安装成功或者失败都会关闭当前的 Activity(InstallInstalling)
                try {
                    InstallEventReceiver.addObserver(this, mInstallId,
                            this::launchFinishBasedOnResult);
                } catch (EventResultPersister.OutOfIdsException e) {
                    // Does not happen
                }
            } else {
                // 对于 savedInstanceState 为空的情况,表明可能是一次全新的安装,需要组装会话参数来创建新的会话
                PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                        PackageInstaller.SessionParams.MODE_FULL_INSTALL);
                params.setInstallAsInstantApp(false);
                params.setReferrerUri(getIntent().getParcelableExtra(Intent.EXTRA_REFERRER));
                params.setOriginatingUri(getIntent()
                        .getParcelableExtra(Intent.EXTRA_ORIGINATING_URI));
                params.setOriginatingUid(getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
                        UID_UNKNOWN));
                params.setInstallerPackageName(getIntent().getStringExtra(
                        Intent.EXTRA_INSTALLER_PACKAGE_NAME));
                params.setInstallReason(PackageManager.INSTALL_REASON_USER);

                File file = new File(mPackageURI.getPath());
                try {
                    PackageParser.PackageLite pkg = PackageParser.parsePackageLite(file, 0);
                    params.setAppPackageName(pkg.packageName);
                    params.setInstallLocation(pkg.installLocation);
                    params.setSize(
                            PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride));
                } catch (PackageParser.PackageParserException e) {
                    Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming defaults.");
                    Log.e(LOG_TAG,
                            "Cannot calculate installed size " + file + ". Try only apk size.");
                    params.setSize(file.length());
                } catch (IOException e) {
                    Log.e(LOG_TAG,
                            "Cannot calculate installed size " + file + ". Try only apk size.");
                    params.setSize(file.length());
                }

                // 向 InstallEventReceiver 注册一个观察者返回一个新的 mInstallId,其中 InstallEventReceiver 继承自 BroadcastReceiver,用于接收安装事件并回调给 EventResultPersister
                try {
                    mInstallId = InstallEventReceiver
                            .addObserver(this, EventResultPersister.GENERATE_NEW_ID,
                                    this::launchFinishBasedOnResult);
                } catch (EventResultPersister.OutOfIdsException e) {
                    launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
                }

                // PackageInstaller 的 createSession 方法内部会通过 IPackageInstaller 与 PackageInstallerService 进行进程间通信,最终调用的是 PackageInstallerService 的 createSession 方法来创建并返回 
                try {
                    mSessionId = getPackageManager().getPackageInstaller().createSession(params);
                } catch (IOException e) {
                    launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
                }
            }

            mCancelButton = mAlert.getButton(DialogInterface.BUTTON_NEGATIVE);

            mSessionCallback = new InstallSessionCallback();
        }
    }
2.3.1.3 InstallInstalling.onResume()

接着在 InstallInstalling 的 onResume() 函数中,创建了 InstallingAsyncTask 异步任务类

对于 AsyncTask 简介:

  • 异步任务开始时,execute() 方法传入的参数类型 , 也是 doInBackground() 方法传入的参数类型
  • 异步任务执行时,进度值类型 , onProgressUpdate() 方法传入的参数类型
  • 异步任务结束时,结果类型 , onPostExecute() 方法传入参数类型 , 或 onCancelled() 方法参数

AsyncTask 常用方法解析 :

  • doInBackground() : 核心方法,执行异步任务,该方法在子线程中执行
  • onPreExecute() : 在 doInBackground() 执行前先执行的方法,主线程中执行,可更新 UI 界面
  • onProgressUpdate() : 调用 publishProgress() 回调的方法,主线程中执行,可更新 UI 界面
  • onPostExecute() : doInBackground() 执行完毕后再执行的方法,主线程中执行,可更新 UI 界面

对于 InstallingAsyncTask,InstallingAsyncTask 是集成自 AsyncTask 类,完成这里的异步处理任务

在 doInBackground() 异步处理中,将 APK 的信息通过IO 流的形式写入到 PackageInstall.Session 中。

在 onPostExecute() 处理中,APK 的信息全部写入到 PackageInstall.Session 中后,调用 PackageInstaller.Session 的 commit() 方法进行安装。

    protected void onResume() {
        super.onResume();

        // This is the first onResume in a single life of the activity
        // 这是该活动的单个生命周期中的第一个 onResume 流程
        if (mInstallingTask == null) {
            PackageInstaller installer = getPackageManager().getPackageInstaller();
            PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);

            if (sessionInfo != null && !sessionInfo.isActive()) {
                mInstallingTask = new InstallingAsyncTask();
                mInstallingTask.execute();
            } else {
                // we will receive a broadcast when the install is finished
                // 当安装完成时,我们将收到广播
                mCancelButton.setEnabled(false);
                setFinishOnTouchOutside(false);
            }
        }
    }

--------------------------------------------------------------------------------------------------------------------------------

    /**
     * Send the package to the package installer and then register a event result observer that
     * will call {@link #launchFinishBasedOnResult(int, int, String)}
     * 将包发送到包安装程序,然后注册将调用的事件结果观察器 launchFinishBasedOnResult()
     */
    private final class InstallingAsyncTask extends AsyncTask<Void, Void,
            PackageInstaller.Session> {
        volatile boolean isDone;

        @Override
        protected PackageInstaller.Session doInBackground(Void... params) {
            PackageInstaller.Session session;
            try {
                // 获取之前创建的 Session 对象,PackageInstaller.Session
                session = getPackageManager().getPackageInstaller().openSession(mSessionId);
            } catch (IOException e) {
                return null;
            }

            // 初始进度
            session.setStagingProgress(0);

            try {
                File file = new File(mPackageURI.getPath());

                // 读取 apk 文件
                try (InputStream in = new FileInputStream(file)) {
                    long sizeBytes = file.length();
                    // 打开会话对象 session 的输入流
                    try (OutputStream out = session
                            .openWrite("PackageInstaller", 0, sizeBytes)) {
                        // 一次读取数据的大小为 1024 KB
                        byte[] buffer = new byte[1024 * 1024];
                        while (true) {
                            int numRead = in.read(buffer);

                            if (numRead == -1) {
                                session.fsync(out);
                                break;
                            }

                            if (isCancelled()) {
                                session.close();
                                break;
                            }

                            // 将读取的数据写入到 Session 中
                            out.write(buffer, 0, numRead);
                            if (sizeBytes > 0) {
                                // 计算并设置写入 Session 的总进度
                                float fraction = ((float) numRead / (float) sizeBytes);
                                session.addProgress(fraction);
                            }
                        }
                    }
                }

                return session;
            } catch (IOException | SecurityException e) {
                Log.e(LOG_TAG, "Could not write package", e);

                session.close();

                return null;
            } finally {
                synchronized (this) {
                    isDone = true;
                    notifyAll();
                }
            }
        }

        @Override
        protected void onPostExecute(PackageInstaller.Session session) {
            // 判断会话对象是否为空
            if (session != null) {
                // session 不为空的情况下,创建一个 PendingIntent,并且调用 PackageInstall.Session.commit() 函数进行安装
                Intent broadcastIntent = new Intent(BROADCAST_ACTION);
                broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                broadcastIntent.setPackage(getPackageName());
                broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);

                PendingIntent pendingIntent = PendingIntent.getBroadcast(
                        InstallInstalling.this,
                        mInstallId,
                        broadcastIntent,
                        PendingIntent.FLAG_UPDATE_CURRENT);

                session.commit(pendingIntent.getIntentSender());
                mCancelButton.setEnabled(false);
                setFinishOnTouchOutside(false);
            } else {
                // session 为空的情况下,取消 sessionId
                getPackageManager().getPackageInstaller().abandonSession(mSessionId);

                if (!isCancelled()) {
                    launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
                }
            }
        }
    }
2.3.1.4 PackageInstallerSession.commit()

调用 PackageInstaller.Session.commit() 函数实际会调用到 PackageInstallerSession.commit() 方法中,PackageInstaller 会通过 sessionId 绑定 PackageInstallerService 的 PackageInstallerSession。

    @Override
    public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
        if (hasParentSessionId()) {
            throw new IllegalStateException(
                    "Session " + sessionId + " is a child of multi-package session "
                            + mParentSessionId +  " and may not be committed directly.");
        }
        // markAsCommitted() 方法中会将包的信息封装为 PackageInstallObserverAdapter
        if (!markAsCommitted(statusReceiver, forTransfer)) {
            return;
        }
        if (isMultiPackage()) {
            final SparseIntArray remainingSessions = mChildSessionIds.clone();
            final IntentSender childIntentSender =
                    new ChildStatusIntentReceiver(remainingSessions, statusReceiver)
                            .getIntentSender();
            RuntimeException commitException = null;
            boolean commitFailed = false;
            for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
                final int childSessionId = mChildSessionIds.keyAt(i);
                try {
                    // commit all children, regardless if any of them fail; we'll throw/return
                    // as appropriate once all children have been processed
                    if (!mSessionProvider.getSession(childSessionId)
                            .markAsCommitted(childIntentSender, forTransfer)) {
                        commitFailed = true;
                    }
                } catch (RuntimeException e) {
                    commitException = e;
                }
            }
            if (commitException != null) {
                throw commitException;
            }
            if (commitFailed) {
                return;
            }
        }
        // 向 Handler 发送一个类型为 MSG_COMMIT 的消息
        mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
    }

--------------------------------------------------------------------------------------------------------------------------------

    private final Handler.Callback mHandlerCallback = new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_COMMIT:
                    // 对于 MSG_COMMIT 类型消息,调用 handleCommit() 处理
                    handleCommit();
                    break;
                case MSG_ON_PACKAGE_INSTALLED:
                    final SomeArgs args = (SomeArgs) msg.obj;
                    final String packageName = (String) args.arg1;
                    final String message = (String) args.arg2;
                    final Bundle extras = (Bundle) args.arg3;
                    final IPackageInstallObserver2 observer = (IPackageInstallObserver2) args.arg4;
                    final int returnCode = args.argi1;
                    args.recycle();

                    try {
                        observer.onPackageInstalled(packageName, returnCode, message, extras);
                    } catch (RemoteException ignored) {
                    }

                    break;
            }

            return true;
        }
    };

--------------------------------------------------------------------------------------------------------------------------------

    private void handleCommit() {
        if (isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked()) {
            DevicePolicyEventLogger
                    .createEvent(DevicePolicyEnums.INSTALL_PACKAGE)
                    .setAdmin(mInstallerPackageName)
                    .write();
        }
        if (params.isStaged) {
            mStagingManager.commitSession(this);
            destroyInternal();
            dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
            return;
        }

        if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
            destroyInternal();
            dispatchSessionFinished(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
                    "APEX packages can only be installed using staged sessions.", null);
            return;
        }

        // For a multiPackage session, read the child sessions
        // outside of the lock, because reading the child
        // sessions with the lock held could lead to deadlock
        // (b/123391593).
        List<PackageInstallerSession> childSessions = getChildSessions();

        try {
            synchronized (mLock) {
                // 调用 commitNonStagedLocked() 继续安装
                commitNonStagedLocked(childSessions);
            }
        } catch (PackageManagerException e) {
            final String completeMsg = ExceptionUtils.getCompleteMessage(e);
            Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
            destroyInternal();
            dispatchSessionFinished(e.error, completeMsg, null);
        }
    }

--------------------------------------------------------------------------------------------------------------------------------

    private void commitNonStagedLocked(List<PackageInstallerSession> childSessions)
            throws PackageManagerException {
        final PackageManagerService.ActiveInstallSession committingSession =
                makeSessionActiveLocked();
        if (committingSession == null) {
            return;
        }
        // 对于分包的情况,需要对各个包进行 makeSessionActiveLocked() 处理,并添加到 activeChildSessions 集合中,最后调用 PackageManagerService.installStage() 函数进行安装
        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) {
                try {
                    mRemoteObserver.onPackageInstalled(
                            null, failure.error, failure.getLocalizedMessage(), null);
                } catch (RemoteException ignored) {
                }
                return;
            }
            mPm.installStage(activeChildSessions);
        } else {
            // 对于单包的情况,调用 PackageManagerService.installStage() 函数进行安装
            mPm.installStage(committingSession);
        }
    }
2.3.2 PackageManagerService

PackageManagerService 提供系统的包管理,下面将调用到 PackageManagerService 的应用安装接口中。

2.3.2.1 PackageManagerService.installStage()

这里调用到 PackageManagerService 流程中。

installStage() 函数通过发送 INIT_COPY 的消息,最终会调用 HandlerParams.startCopy() 进行安装。

对于 HandlerParams 类的描述:

HandlerParams 是一个抽象类,用于描述执行安装拷贝的过程,实现类有两个 MultiPackageInstallParams 和 InstallParams;MultiPackageInstallParams 是处理分包的情况;InstallParams 是处理单包的情况。

startCopy() 函数会以此调用 handleStartCopy() 和 handleReturnCode() 函数处理。

    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 的消息
        final Message msg = mHandler.obtainMessage(INIT_COPY);
        // 创建 InstallParams,它对应于包的安装数据
        final InstallParams params = new InstallParams(activeInstallSession);
        params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
        msg.obj = params;

        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
                System.identityHashCode(msg.obj));
        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                System.identityHashCode(msg.obj));

        // 将InstallParams通过消息发送出去
        mHandler.sendMessage(msg);
    }

--------------------------------------------------------------------------------------------------------------------------------

// PackageManagerService 的内部类 PackageHandler 是消息处理类
    class PackageHandler extends Handler {
		void doHandleMessage(Message msg) {
            switch (msg.what) {
                case INIT_COPY: {
                    HandlerParams params = (HandlerParams) msg.obj;
                    if (params != null) {
                        if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                                System.identityHashCode(params));
                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
                        // 调用 params.startCopy() 进行安装
                        params.startCopy();
                        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                    }
                    break;
                }
            }
        }
    }

handleStartCopy() 需要执行下面几步:

  • 首先检查文件和 cid 是否已生成,如生成则设置 installFlags

  • 检查空间大小,如果空间不够则释放无用空间

  • 覆盖原有安装位置的文件,并根据返回结果来确定函数的返回值,并设置 installFlags

  • 确定是否有任何已安装的包验证器,如有,则延迟检测。主要分三步:首先新建一个验证 Intent,然后设置相关的信息,之后获取验证器列表,最后向每个验证器发送验证 Intent

handleReturnCode() 执行下面几步:

  • 调用 copyApk() 进行 APK 的拷贝动作,通过文件流的操作,把 APK 拷贝到 /data/app 等目录
  • 调用 processPendingInstall() 继续安装,APK拷贝完成后,进入真正的安装
2.3.2.2 PackageManagerService.processPendingInstall()

processPendingInstall() 设置安装参数,并调用 processInstallRequestsAsync() 函数进行处理。

processInstallRequestsAsync() 函数创建一个新的线程,调用 installPackagesTracedLI() 函数继续安装。

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

--------------------------------------------------------------------------------------------------------------------------------

private void processInstallRequestsAsync(boolean success,
        List<InstallRequest> installRequests) {
    mHandler.post(() -> {
        if (success) {
            for (InstallRequest request : installRequests) {
                // 1.如果之前安装失败,清除无用信息
                request.args.doPreInstall(request.installResult.returnCode);
            }
            synchronized (mInstallLock) {
                // 2. installPackagesTracedLI 是安装过程的核心方法,然后调用 installPackagesLI 进行安装。
                installPackagesTracedLI(installRequests);
            }
            for (InstallRequest request : installRequests) {
                // 3.如果之前安装失败,清除无用信息
                request.args.doPostInstall(
                        request.installResult.returnCode, request.installResult.uid);
            }
        }
        for (InstallRequest request : installRequests) {
            // 执行安装后的 post install
            restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
                    new PostInstallData(request.args, request.installResult, null));
        }
    });
}
2.3.2.3 PackageManagerService.installPackagesTracedLI()

应用的实际安装是通过 PackageManagerService 的 installPackagesTracedLI() 函数完成的。installPackagesTracedLI() 函数封装了 PackageManagerService 实际安装应用的过程。

    private void installPackagesTracedLI(List<InstallRequest> requests) {
        try {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
            installPackagesLI(requests); // 调用 installPackagesLI() 函数进行安装
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }
2.3.2.4 PackageManagerService.installPackagesLI()

应用安装调用到 installPackagesLI() 函数中,此函数中将应用安装流程分为下面五个阶段:

  • Prepare 准备:分析任何当前安装状态,解析包并对其进行初始验证。
  • Scan 扫描:根据 prepare 中收集的上下文查询已解析的包。
  • Reconcile 调和:在彼此和当前系统状态的上下文中验证扫描的包,以确保安装成功。
  • Commit 提交:提交所有扫描包并更新系统状态。这是安装流程中唯一可以修改系统状态的地方,所有可预测的错误必须在此阶段之前确定。
  • Install 安装:创建应用数据,并且判断是否要执行 dex 优化。
    /**
     * 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) {
        // 初始化一系列集合,用来保存安装过程中应用文件名及对应扫描结果、安装参数、安装请求、准备结果、版本信息、包信息以及创建应用 ID 的数据
        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 {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
            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");
                    // Prepare 准备:分析任何当前安装状态,解析包并对其进行初始验证。
                    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;
                // 保存包名对应的 prepareResult 准备结果以及安装参数等信息
                prepareResults.put(packageName, prepareResult);
                installResults.put(packageName, request.installResult);
                installArgs.put(packageName, request.args);
                try {
                    // Scan 扫描:根据 prepare 中收集的上下文查询已解析的包。
                    final List<ScanResult> scanResults = scanPackageTracedLI(
                            prepareResult.packageToScan, prepareResult.parseFlags,
                            prepareResult.scanFlags, System.currentTimeMillis(),
                            request.args.user);
                    for (ScanResult result : scanResults) {
                        // 保存包名及对应的扫描结果信息
                        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;
                        }
                        // 创建应用 ID 并保存
                        createdAppId.put(packageName, optimisticallyRegisterAppId(result));
                        // 保存版本信息
                        versionInfos.put(result.pkgSetting.pkg.packageName,
                                getSettingsVersionForPackage(result.pkgSetting.pkg));
                        if (result.staticSharedLibraryInfo != null) {
                            final PackageSetting sharedLibLatestVersionSetting =
                                    getSharedLibLatestVersionSetting(result);
                            if (sharedLibLatestVersionSetting != null) {
                                lastStaticSharedLibSettings.put(result.pkgSetting.pkg.packageName,
                                        sharedLibLatestVersionSetting);
                            }
                        }
                    }
                } catch (PackageManagerException e) {
                    request.installResult.setError("Scanning Failed.", e);
                    return;
                }
            }
            ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
                    installResults,
                    prepareResults,
                    mSharedLibraries,
                    Collections.unmodifiableMap(mPackages), versionInfos,
                    lastStaticSharedLibSettings);
            CommitRequest commitRequest = null;
            synchronized (mPackages) {
                Map<String, ReconciledPackage> reconciledPackages;
                try {
                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
                    // Reconcile 调和:在彼此和当前系统状态的上下文中验证扫描的包,以确保安装成功。
                    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());
                    // Commit 提交:提交所有扫描包并更新系统状态。这是安装流程中唯一可以修改系统状态的地方,所有可预测的错误必须在此阶段之前确定。
                    commitPackagesLocked(commitRequest);
                    success = true;
                } finally {
                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                }
            }
            // Install 安装:创建应用数据,并且判断是否要执行 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);
        }
    }
2.3.2.4.1 Prepare 准备

应用安装实际过程第一阶段,先对应用包进行准备工作,包括分析当前安装状态,分析包并对其进行初始验证。

我们先来看一下 Prepare 准备阶段的结果 PrepareResult 类

    private static class PrepareResult {
        public final int installReason;
        public final String volumeUuid;
        public final String installerPackageName;
        public final UserHandle user;
        public final boolean replace;
        public final int scanFlags;
        public final int parseFlags;
        @Nullable /* The original Package if it is being replaced, otherwise {@code null} */
        public final PackageParser.Package existingPackage;
        public final PackageParser.Package packageToScan;
        public final boolean clearCodeCache;
        public final boolean system;
        /* The original package name if it was changed during an update, otherwise {@code null}. */
        @Nullable
        public final String renamedPackage;
        public final PackageFreezer freezer;
        public final PackageSetting originalPs;
        public final PackageSetting disabledPs;
        public final PackageSetting[] childPackageSettings;

        private PrepareResult(int installReason, String volumeUuid,
                String installerPackageName, UserHandle user, boolean replace, int scanFlags,
                int parseFlags, PackageParser.Package existingPackage,
                PackageParser.Package packageToScan, boolean clearCodeCache, boolean system,
                String renamedPackage, PackageFreezer freezer, PackageSetting originalPs,
                PackageSetting disabledPs, PackageSetting[] childPackageSettings) {
            this.installReason = installReason;
            this.volumeUuid = volumeUuid;
            this.installerPackageName = installerPackageName;
            this.user = user;
            this.replace = replace;
            this.scanFlags = scanFlags;
            this.parseFlags = parseFlags;
            this.existingPackage = existingPackage;
            this.packageToScan = packageToScan;
            this.clearCodeCache = clearCodeCache;
            this.system = system;
            this.renamedPackage = renamedPackage;
            this.freezer = freezer;
            this.originalPs = originalPs;
            this.disabledPs = disabledPs;
            this.childPackageSettings = childPackageSettings;
        }
    }

Prepare 阶段调用的是 preparePackageLI() 函数,下面将简要概括 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);

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

--------------------------------------------------------------------------------------------------------------------------------
    /*
     * 1、调用 PackageParser.parsePackage() 函数解析 APK
     * 2、对于 instantApp,安装时有额外的检查,例如应用的 SDK 版本要大于 Android O,并且需要配置 mSharedUserId
     */
        // 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");
            }
        }

--------------------------------------------------------------------------------------------------------------------------------
    /*
     * 1、如果应用有静态共享库,需要更名,并且需要安装在内部存储
     * 2、对于多安装包的集群包,需要为集群包添加结果
     * 3、设置应用的 CPU ABI
     */
        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");
            }
        }

--------------------------------------------------------------------------------------------------------------------------------
    /*
     * 1、调用 PackageParser.collectCertificates() 函数从应用中获取证书信息
     * 2、如果是 instantApp,那么签名方案不能小于 V2
     */
        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");
        }

--------------------------------------------------------------------------------------------------------------------------------
    /*
     * 1、通过 replace 变量去判断此应用安装是 安装已经存在的包 还是 全新的安装
     * 2、对于 replace 安装情况下,需要对一些情况进行判断
     */
        // 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.");
                    }
                }
            }

--------------------------------------------------------------------------------------------------------------------------------
    /*
     * 1、静态共享库具有不同版本的相同包,我们在内部使用合成包名来允许相同包的多个版本,因此我们需要将签名与最新库版本的包设置进行比较。
     * 2、如果更新,快速检查我们的签名是否正确;稍后我们将在扫描时再次检查这一点,但我们希望在被重新定义的权限绊倒之前提前退出。
     */
            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)) {
                    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);
            }

--------------------------------------------------------------------------------------------------------------------------------
    /*
     * 1、这里是对应用包声明的权限的控制,比如防止应用程序将 protection 级别从任何其他类型更改为 dangerous
     */
            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();
                            }
                        }
                    }
                }
            }
        }

--------------------------------------------------------------------------------------------------------------------------------
    /*
     * 1、对于系统 APP,如果在外部存储上或者被其他应用替代,则会提醒异常
     * 2、生成安装包 Abi (Application binary interface,应用二进制接口,描述应用程序和操作系统之间或其他应用程序的低级接口)
     */
        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();
                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");
            }
        }

        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);
            }
        }
        
--------------------------------------------------------------------------------------------------------------------------------
    /*
     * 1、冻结 APK,调用 freezePackageForInstall() 函数冻结 APK,准备进行安装
     * 2、通过 replace 参数判断是替换安装还是安装新的 APK,对于替换安装,包含系统升级后应用的更新流程
     */
        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;

                }
            } 
            
--------------------------------------------------------------------------------------------------------------------------------
    /*
     * 1、对于全新的安装,相对于替换安装则少了很多准备工作,进行了一些命名的检查
     */
            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.");
                    }
                }
            }
            
--------------------------------------------------------------------------------------------------------------------------------
    /*
     * 1、设置标志位,能够在后续的安装中,关闭冻结
     * 2、Prepare 准备阶段返回结果,构建 PrepareResult 对象作为结果
     */
            // 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();
            }
        }
    }
2.3.2.4.2 Scan 扫描

扫描阶段会调用 scanPackageTracedLI() 函数完成。这里的调用栈如下:

scanPackageTracedLI()
scanPackageLI()
scanPackageChildLI()
addForInitLI()
scanPackageNewLI()

scanPackageTracedLI() 中调用 scanPackageLI() 函数;scanPackageLI() 函数会调用 PackageParser.parsePackage() 解析包,然后调用 scanPackageChildLI() 函数继续扫描;scanPackageChildLI() 函数会对于单包和多包的情况调用 addForInitLI() 函数继续处理。在 addForInitLI() 函数中会有各种场景的过滤,例如对于系统分区下的应用,在系统更新后的场景下,会去对包再次进行扫描 ;是否跳过验签;是否是隐藏的系统应用;然后调用 scanPackageNewLI() 函数获取 scanResult 扫描结果对象。

private PackageParser.Package addForInitLI(PackageParser.Package pkg,
        @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
        @Nullable UserHandle user)
                throws PackageManagerException {
  // 判断系统应用是否需要更新
    synchronized (mPackages) {
      // 更新子应用
        if (isSystemPkgUpdated) {
        ...
            }
        if (isSystemPkgBetter) {
             // 更新安装包到 system 分区中
            synchronized (mPackages) {
                // just remove the loaded entries from package lists
                mPackages.remove(pkgSetting.name);
            }
      ...
            // 创建安装参数 InstallArgs
            final InstallArgs args = createInstallArgsForExisting(
                    pkgSetting.codePathString,
                    pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
            args.cleanUpResourcesLI();
            synchronized (mPackages) {
                mSettings.enableSystemPackageLPw(pkgSetting.name);
            }
        }
    // 安装包校验
        collectCertificatesLI(pkgSetting, pkg, forceCollect, skipVerify);
    ...
    try (PackageFreezer freezer = freezePackage(pkg.packageName,
                        "scanPackageInternalLI")) {
             // 如果两个 apk 签名不匹配,则调用 deletePackageLIF 方法清除 apk 文件及其数据
            deletePackageLIF(pkg.packageName, null, true, null, 0, null, false, null);
        }
    ...
    // 更新系统 apk 程序
        InstallArgs args = createInstallArgsForExisting(
                pkgSetting.codePathString,
                pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
        synchronized (mInstallLock) {
            args.cleanUpResourcesLI();
        }
  }
  // 如果新安装的系统APP 会被旧的APP 数据覆盖,所以需要隐藏隐藏系统应用程序,并重新扫描 /data/app 目录
    if (shouldHideSystemApp) {
        synchronized (mPackages) {
            mSettings.disableSystemPackageLPw(pkg.packageName, true);
        }
    }
}
2.3.2.4.3 Reconcile 调和

PackageManagerService 在对 Package 进行扫描之后,会调用 reconcilePackagesLocked() 函数进行调和。

将当前正在安装应用信息合并到存储所有应用基本信息的 map 中;

如果当前正在覆盖安装非系统应用则需要删除原有的应用,这里只是构造了对应的 action 对象;

如果是覆盖安装,则判断新安装的应用签名与原有应用签名是否一致;如果不是覆盖安装且如果当前应用与其他应用共享 uid 则合并签名;

    private static Map<String, ReconciledPackage> reconcilePackagesLocked(
            final ReconcileRequest request, KeySetManagerService ksms, Injector injector)
            throws ReconcileFailure {
         //当前正在安装应用信息,key为对应包名
        final Map<String, ScanResult> scannedPackages = request.scannedPackages;
        final Map<String, ReconciledPackage> result = new ArrayMap<>(scannedPackages.size());
        //request.allPackages表示当前系统中已经安装的应用(key为包名),这里包含了当前正在安装包
        final ArrayMap<String, AndroidPackage> combinedPackages = new ArrayMap<>(request.allPackages.size() + scannedPackages.size());
        combinedPackages.putAll(request.allPackages);
        final Map<String, WatchedLongSparseArray<SharedLibraryInfo>> incomingSharedLibraries = new ArrayMap<>();

        for (String installPackageName : scannedPackages.keySet()) {
            final ScanResult scanResult = scannedPackages.get(installPackageName);
            //将正在安装的应用信息替换map中的原有信息
            combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage);
            //当前正在安装的应用是否存在被共享的so库,只有系统应用才有
            ......
            //获取前面应用安装过程中存储的信息
            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;
            // 如果是覆盖安装并且是非系统应用,则需要卸载原有的应用
            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,deleteFlags, null);
                if (deletePackageAction == null) {
                    throw new ReconcileFailure(PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE,"May not delete " + installPackageName + " to replace");
                }
            } else {
                deletePackageAction = null;
            }
            //临时变量赋值
            ......
            //如果是应用升级判断新安装应用签名是与原有的应用签名一致
            if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
                if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
                } else {
                    //签名不一致则抛出异常
                    ......
                }
                signingDetails = parsedPackage.getSigningDetails();
            } else {
                 //如果正在安装应用签名与某些应用共享uid,则合并他们的签名信息
                ......
            }
            result.put(installPackageName, new ReconciledPackage(request, installArgs, scanResult.pkgSetting, res, request.preparedPackages.get(installPackageName), scanResult, deletePackageAction, allowedSharedLibInfos, signingDetails, sharedUserSignaturesChanged, removeAppKeySetData));
        }
        //共享库相关
        ......
        return result;
    }

2.3.2.4.4 Commit 提交

PackageManagerService 会调用 commitPackagesLocked() 函数继续安装新的 Package

    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;

            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) {
                    // 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.
                        // 我们使用 apk 作为当前系统包,这意味着我们正在替换已经安装的另一个更新。我们需要确保删除旧版本的 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 {
                        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);
                        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;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            commitReconciledScanResultLocked(reconciledPkg);
            // 更新系统应用包信息
            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) {
                updateSequenceNumberLP(ps, res.newUsers);
                updateInstantAppInstallerLocked(packageName);
            }
        }
    }

2.3.2.4.5 Install 安装

PackageManagerService 会调用 executePostCommitSteps() 函数进行安装。

executePostCommitSteps() 函数中会调用 prepareAppDataAfterInstallLIF() 进行安装,并且会判断 Package 是否需要进行 Dex 优化。

prepareAppDataAfterInstallLIF() 的调用栈如下:

prepareAppDataAfterInstallLIF()
    |
prepareAppDataLIF()
    |
prepareAppDataLeafLIF()
    |
[Installer.java]
createAppData()

最终会调用到 Installer 模块中。

下面是 executePostCommitSteps() 函数的代码:

    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;
            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.
            // 为新的代码路径准备应用程序概要文件。这需要在调用 dexopt 之前完成,以便可以使用任何安装时配置文件进行优化。
            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");
                    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);
                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
            // 通知 BackgroundDexOptService 包已经更改。
            // 如果这是一个曾经编译失败的包的更新,BackgroundDexOptService 将把它从黑名单中删除。
            BackgroundDexOptService.notifyPackageChanged(packageName);
        }
    }
         
2.3.3 Installer

PackageManagerService 会调用 Installer 服务,调用 Installer 的 createAppData() 创建应用数据。

Installer 服务是 Android 提供的用于安装的服务,Installer 持有 Installd 守护进程对应的 Binder 服务的代理对象,本质上是通过 Binder 通信调用底层的 Installd 服务真正完成 APK 文件格式的优化和转换、建立相关的数据目录、删除文件、安装应用等工作。

这里简要描述下 Installer 服务与 Installd守护进程。

Installer 与 Installd 通过 Aidl 的方式进行通信,文件为 /android/frameworks/native/cmds/installd/binder/android/os/IInstalld.aidl。Installer 是一个系统服务,在 SystemServer 的 startBootstrapServices() 函数中启动,启动时获取 Installd 服务的代理对象。

请参考如下序列图:
在这里插入图片描述
问题:为什么需要 Installd?

答:Android 在 PackageManagerService 的服务中提供了包安装的流程,但是为什么还需要 Installd 参与呢?原因是 system_server 以 system 用户的身份运行,PackageManagerService 运行在 system_server 中,那么也就是 system 用户。system 用户并没有访问应用程序目录的权限,但是 Installd 服务是以 root 用户启动的,可以访问 /data/data/ 下的目录,Installd 需要完成一些创建应用数据的任务。

3、总结

本篇文章主要描述了应用安装时系统是如何处理的,从整体运行逻辑、参与模块、模块分工,简要描述了应用安装的过程。

系统从 PackageInstaller 服务开始接收应用的安装请求,再构建安装会话参数传递到 PackageManagerService 中继续安装;PackageManagerService 将具体的安装过程细分为五个步骤:准备、扫描、调和、提交、安装;然后通过 Installer 服务,调用 Installd 功能建立相关应用数据等操作。

本篇文档在整理过程中,主要从整体角度描述应用安装的过程,对于部分实现细节并没有展开描述。

最后,文中如果有描述不正确的地方,还请大家指出,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值