boot.img和recovery.img的格式是google自定义的。
1. image的完整构成
一个完整的bootimage是由boot header、kernel、ramdisk、second stage(可选)、X509证书(可选)、签名信息(可选)组成。原始的boot.img只包括boot header、kernel、ramdisk、second stage(可选),且一般而言second staga都是没有的。2. 原始boot.img格式
包括文件头boot_img_hdr,kernel.gz(Linux内核zImage),以及ramdisk.cpio.gz(根文件系统)
结构如下:
*
** +-----------------+
** | boot header | 1 page
** +-----------------+
** | kernel | n pages
** +-----------------+
** | ramdisk | m pages
** +-----------------+
** | second stage | o pages
** +-----------------+
原始boot.img的每部分都是页对齐的。其中boot header固定占用1个page的大小。kernel、ramdisk、second stage实际的大小会在boot header中标明。
3. boot header结构
boot header其实就是一个结构体struct boot_img_hdr,它的定义如下
struct boot_img_hdr
{
unsigned char magic[BOOT_MAGIC_SIZE]; /* 8 byte */
unsigned kernel_size; /* size in bytes */
unsigned kernel_addr; /* physical load addr */
unsigned ramdisk_size; /* size in bytes */
unsigned ramdisk_addr; /* physical load addr */
unsigned second_size; /* size in bytes */
unsigned second_addr; /* physical load addr */
unsigned tags_addr; /* physical addr for kernel tags */
unsigned page_size; /* flash page size we assume */
unsigned unused[2]; /* future expansion: should be 0 */
unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
unsigned char cmdline[BOOT_ARGS_SIZE];
unsigned id[8]; /* timestamp / checksum / sha1 / etc */
};
这里有几个比较重要的值。一个是page_size,这个是页大小。前面说了,boot.img的每个部分都是页对齐的,那一个page的大小就记录在page_size里,通常是2048,也就是2K对齐。kernel_size是kernel.gz的原始大小,页对齐后,kernel占用的空间会比kernel_size大,多余的部分用0填充。ramdisk_size是ramdisk的原始大小,页对齐后,ramdisk占用的空间会比ramdisk_size大,多余的部分用0填充。
如果需要在android启动时对boot.img进行校验,确保其合法性,那么就需要在编译完成后对boot.img进行签名。google对boot.img的签名方式,就是使用verity .pk8对原始的boot.img进行加密。并且在boot.img的最后追加对应的verity.x509.pem证书,以及一段加密数据(也就是签名信息)
追加的证书,并不是直接把源码里面的verity.x509.pem粘贴上去的,而是做了编码的转换。verity.x509.pem是base64编码的,而追加的证书是二进制的ASN1格式。追加的证书也是页对齐的。ASN1格式会标明证书的实际大小。证书的开头是整个证书的大小,一般开头是0x30 0x82 0xaa 0xbb,30表示SEQUENCE, 0x82表示长度占用两个2字节,那么证书长度就是0xaabb。追加证书时也是页对齐的。(这里android 7.0和android 5.x似乎略有差别,android 5.x并没有做对齐处理)
除了证书以外,还有签名。签名是对原始boot.img的内容计算hash后,把hash值进行加密后得到的内容。具体的hash算法和加密算法都是在证书里规定的。最后得到的签名长度跟hash和加密算法相关。例如证书里规定sha1RSA2048,sha1摘要长度是160bit,那么RSA密文的长度就是256字节,所以最后的签名信息长度是256字节,且签名信息是不需要页对齐的。
https://source.android.com/security/verifiedboot/verified-boot?hl=zh-cn5. 镜像大小
boot.img的总大小是
total = align(sizeof(struct boot_img_hdr))
+ align(kernel_size)
+ align(ramdisk_size)
+ align(second_size)
+ align(cert_size)
+ signature_size;