1"""Helper library for repacking GKI boot images.""" 2import os 3import shutil 4import subprocess 5import tempfile 6 7from treble.fetcher import fetcher_lib 8 9 10def fetch_bootimg(client, out_dir, build_id, kernel_version, target): 11 """Fetches boot.img artifacts from a given build ID.""" 12 fetcher_lib.fetch_artifacts( 13 client=client, 14 build_id=build_id, 15 target=target, 16 pattern=r'(gki_.*-img-.*\.zip|gki_.*-target_files-.*\.zip|otatools.zip)' 17 .format(version=kernel_version), 18 out_dir=out_dir) 19 20 21def fetch_kernel(client, out_dir, build_id, kernel_target, kernel_debug_target): 22 """Fetches kernel artifacts from a given build ID.""" 23 kernel_dir = os.path.join(out_dir, 'kernel') 24 kernel_debug_dir = os.path.join(out_dir, 'kernel_debug') 25 os.makedirs(kernel_dir) 26 os.makedirs(kernel_debug_dir) 27 28 fetcher_lib.fetch_artifacts( 29 client=client, 30 build_id=build_id, 31 target=kernel_target, 32 pattern=r'(Image|Image.lz4|System\.map|abi_symbollist|vmlinux|vmlinux.symvers)', 33 out_dir=kernel_dir) 34 fetcher_lib.fetch_artifacts( 35 client=client, 36 build_id=build_id, 37 target=kernel_debug_target, 38 pattern=r'(Image|Image.lz4|System\.map|abi-generated.xml|abi-full-generated.xml|vmlinux|vymlinx.symvers)', 39 out_dir=kernel_debug_dir) 40 41 print('Compressing kernels') 42 43 def compress_kernel(kernel_path): 44 zipped_kernel_path = os.path.join(os.path.dirname(kernel_path), 'Image.gz') 45 with open(zipped_kernel_path, 'wb') as zipped_kernel: 46 cmd = [ 47 'gzip', 48 '-nc', 49 kernel_path, 50 ] 51 print(' '.join(cmd)) 52 subprocess.check_call(cmd, stdout=zipped_kernel) 53 54 compress_kernel(os.path.join(kernel_dir, 'Image')) 55 compress_kernel(os.path.join(kernel_debug_dir, 'Image')) 56 57 return kernel_dir, kernel_debug_dir 58 59 60def _replace_kernel(bootimg_path, kernel_path): 61 """Unpacks a boot.img, replaces the kernel, then repacks.""" 62 with tempfile.TemporaryDirectory() as unpack_dir: 63 print('Unpacking bootimg %s' % bootimg_path) 64 cmd = [ 65 'out/host/linux-x86/bin/unpack_bootimg', 66 '--boot_img', 67 bootimg_path, 68 '--out', 69 unpack_dir, 70 '--format', 71 'mkbootimg', 72 ] 73 print(' '.join(cmd)) 74 mkbootimg_args = subprocess.check_output(cmd).decode('utf-8').split(' ') 75 print('Copying kernel %s' % kernel_path) 76 shutil.copy(kernel_path, os.path.join(unpack_dir, 'kernel')) 77 print('Repacking with mkbootimg') 78 cmd = [ 79 'out/host/linux-x86/bin/mkbootimg', 80 '--output', 81 bootimg_path, 82 ] + mkbootimg_args 83 print(' '.join(cmd)) 84 subprocess.check_call(cmd) 85 86 87def repack_bootimgs(bootimg_dir, kernel_dir, kernel_debug_dir): 88 """Repacks all boot images in a given dir using the provided kernels.""" 89 for bootimg_path in os.listdir(bootimg_dir): 90 bootimg_path = os.path.join(bootimg_dir, bootimg_path) 91 if not bootimg_path.endswith('.img'): 92 continue 93 94 kernel_name = 'Image' 95 if '-gz' in bootimg_path: 96 kernel_name = 'Image.gz' 97 elif '-lz4' in bootimg_path: 98 kernel_name = 'Image.lz4' 99 100 kernel_path = os.path.join(kernel_dir, kernel_name) 101 if bootimg_path.endswith('-allsyms.img'): 102 kernel_path = os.path.join(kernel_debug_dir, kernel_name) 103 104 _replace_kernel(bootimg_path, kernel_path) 105 106 107def repack_img_zip(img_zip_path, kernel_dir, kernel_debug_dir, kernel_version): 108 """Repacks boot images within an img.zip archive.""" 109 with tempfile.TemporaryDirectory() as unzip_dir: 110 pattern = 'boot-{}*'.format(kernel_version) 111 print('Unzipping %s to repack bootimgs' % img_zip_path) 112 cmd = [ 113 'unzip', 114 '-d', 115 unzip_dir, 116 img_zip_path, 117 pattern, 118 ] 119 print(' '.join(cmd)) 120 subprocess.check_call(cmd) 121 repack_bootimgs(unzip_dir, kernel_dir, kernel_debug_dir) 122 cmd = [ 123 'zip', 124 img_zip_path, 125 pattern, 126 ] 127 print(' '.join(cmd)) 128 subprocess.check_call(cmd, cwd=unzip_dir) 129 130 131def replace_target_files_zip_kernels(target_files_zip_path, kernel_out_dir, 132 kernel_version): 133 """Replaces the BOOT/kernel-* kernels within a target_files.zip archive.""" 134 with tempfile.TemporaryDirectory() as unzip_dir: 135 pattern = 'BOOT/kernel-{}*'.format(kernel_version) 136 print( 137 'Unzipping %s to replace kernels in preparation for signing' % 138 target_files_zip_path,) 139 cmd = [ 140 'unzip', 141 '-d', 142 unzip_dir, 143 target_files_zip_path, 144 pattern, 145 ] 146 print(' '.join(cmd)) 147 subprocess.check_call(cmd) 148 for kernel in os.listdir(kernel_out_dir): 149 if kernel.startswith('kernel-{}'.format(kernel_version)): 150 print('Copying %s' % kernel) 151 shutil.copy( 152 os.path.join(kernel_out_dir, kernel), 153 os.path.join(unzip_dir, 'BOOT')) 154 cmd = [ 155 'zip', 156 target_files_zip_path, 157 pattern, 158 ] 159 print(' '.join(cmd)) 160 subprocess.check_call(cmd, cwd=unzip_dir) 161