在传统的应用安装方案中,开发者需要通过ADB(Android Debug Bridge)与终端用户建立有线或无线连接,或者用户直接从软件商店下载。然而,这种方案要求用户等待完整的安装包传输完成后才能开始安装,导致了不良的用户体验。
增量安装技术是一种流式的安装方案:只要核心文件传输完成,应用就可以立即启动。流式安装允许优先传输核心数据以启动应用,并在后台持续传输剩余数据。
APK的核心数据包括可执行文件和重要的资源文件等。在开始数据传输之前,ADB会优先筛选出安装包中的核心文件进行传输。一旦移动设备接收到启动应用所需的核心数据块,该应用程序就可以在虚拟文件系统上启动了。
在Android 11中,Google已经在内核中引入了增量文件系统,以支持增量安装功能。更多详细信息,请参考https://source.android.com/devices/architecture/kernel/incfs。
Android OS现在支持通过ADB进行APK的流式传输,这一特性使得安装过程更加高效。此外,为了满足增量安装的需求,Android 11还引入了全新的V4签名方案。
我们的方案不会改变之前的签名方案,而是引入了一种全新的签名方式。该方式基于APK所有字节数据计算出Merkle哈希树,并将Merkle树的根哈希和盐值作为签名数据,用于验证包完整性。这些新的签名数据将保存在.idsig文件中,并且在进行增量安装之前,必须为APK创建相应的V4签名文件。
二、增量安装
上图所示为增量安装的基本框架[1]。
ADB会筛选出需要优先传输的文件,并通过增量文件流传递数据。同时,在传输过程中,还会生成传输日志并向开发者提供。
在移动设备上,有一个专门的增量文件系统内核模块,用于在操作系统中实现增量服务。这个增量服务负责接收来自ADB的增量安装请求,并通知增量文件系统内核模块和包管理器(Package Manager)启动相应的增量安装流程,并跟踪应用程序的安装过程。
在收到增量安装请求后,增量文件系统内核模块会接收来自ADB的APK核心数据,并将其存放在增量文件系统内部。
增量文件系统是一种虚拟文件系统,它在设备文件系统上运行。当接收到APK的核心数据文件时,它会为整个包分配空间,并创建APK包的虚拟文件以进行增量安装。
核心数据安装完毕后便可在设备上显示应用图标和应用所在目录。在用户启动应用后,ADB将在后台继续传输剩余的APK包数据。
上图所示为ADB优先选择的APK核心文件。ADB以增量的方式将APK数据传输给移动设备。预先传输的数据可以让APK提前启动。ADB追踪正在传输的数据并创建日志文件并提供给应用开发者。
三、Merkle树
Android V4签名方案的签名和验证采用了基于Merkle树的算法。
Merkle树最初的设计目的是为了解决两个问题:一是单一Lamport密钥无法签署多条信息,二是在处理大量信息时公钥会变得过长[2]。
Merkle树本质上是将一系列Lamport公钥组合在一起,并用哈希函数计算出一个统一的公钥,这个公钥便是Merkle树的根哈希。
接下来将介绍如何利用Merkle树生成和验证签名的过程。
关于下图所示的Merkle树:
-
数据块1~数据块4有各自的密钥对(Xi,Yi),
-
每个数据块的公钥计算哈希值hi=H(Yi),并将其作为叶子节点添加到Merkle树中。
-
通过合并其子节点的值并计算哈希,非叶子节点的值得以生成。
以节点a1,0的计算为例,可以将其表示为a1,0=H(a0,0||a0,1)。
通过这种方式,我们可以逐步计算出根节点的哈希值,并构建Merkle树。最终,我们将根节点的值作为公钥来验证签名。
签名包括对数据块进行加密的密钥以及验证该密钥的路径。这个验证路径是从叶子节点到根节点路径上所有兄弟节点的集合。
在验证Merkle树签名时,首先需要验证数据块的一次性签名,并进一步确认公钥的准确性。
以数据块1为例,首先要验证密钥对(X0,Y0)是否匹配正确;
如果要验证Y0的正确性,可以根据a0,0的验证路径和根哈希进行验证。
节点a[0,0]的验证路径经过a[0,1]和a[1,1]。
通过a[0,0]与a[0,1]可计算出a[1,0],a[1,0]与a[1,1]可计算出根节点a[2,0],与Merkle树的公钥进行对比,若一致接收签名。
四、V4签名
V4签名是基于APK字节计算的Merkle树,用于文件验证。
V4签名的数据结构被保存在.idsig文件中,其中包含了用于验证签名的根哈希。
当前仅支持版本2的V4Signature结构。该结构包含一个int32类型的version字段,以及一个sized_bytes类型的hashing_info字段。template <class SizeT>struct sized_bytes {SizeT size;byte bytes[size];};
hashing_info 保存着哈希树的相关信息:哈希算法(SHA256)、数据块大小(4KB),盐值、根哈希。hashing_info的定义如下:
public static class HashingInfo { public final int hashAlgorithm; public final byte log2BlockSize; public final byte checksumType; public HashingInfo(int hashAlgorithm, byte log2BlockSize, byte checksumType) { this.hashAlgorithm = hashAlgorithm; this.log2BlockSize = log2BlockSize; this.checksumType = checksumType; } }public static class SigningInfo { public final byte[] apkDigest; public final byte[] certificate; public final byte[] publicKey; public SigningInfo(byte[] apkDigest, byte[] certificate, byte[] publicKey) { this.apkDigest = apkDigest; this.certificate = certificate; this.publicKey = publicKey; } }首先以自底向上的方式生成Merkle树,如下图所示:
我们首先将APK的源数据划分为多个4KB的数据块,如果源文件最后部分不足4KB,则进行零填充来凑足4KB;接下来,我们对这些4KB的数据块进行SHA256计算,以获取32B的哈希值。这些哈希值将构成Merkle树的第一层。
为了生成Merkle树的第二层,需要将第一层的哈希值进行组合。组合的方法是按顺序将第一层的128个哈希值组成4KB大小的数据块。如果不足4KB,则用零进行填充。最后,对这些4KB块进行SHA256计算,得到Merkle树的第二层。
从那一点开始,以此类推,直到计算出Merkle数的根哈希。生成的哈希树将以V4Signature的形式保存在.idsig文件中。
通过根哈希计算Hashinfo结构,然后利用Hashinfo和APK摘要生成V4签名。
当ADB请求进行增量安装时,PMS会从.idsig文件中提取原生签名,并将其封装在V4Signature对象中。在验证过程中,PMS会从V4Signature对象获取签名数据和公钥,并采用与上一代签名方案类似的方式进行验证。
五、总结
本文主要探讨了增量安装技术的应用框架和安卓V4签名方案的理论基础。以增量安装和V4签名方案为切入点,详细介绍了增量安装技术的应用框架以及V4签名方案的理论依据。
总结而言,增量安装是一种流式安装技术,可以快速启动应用程序。V4签名是为了支持增量安装而设计的一种具有Merkle树结构的签名。
在可预见的未来,增量安装和V4签名都将具有更广泛的应用场景。
还木有评论哦,快来抢沙发吧~