1*105f6285SAndroid Build Coastguard Worker#!/usr/bin/python3 2*105f6285SAndroid Build Coastguard Worker# 3*105f6285SAndroid Build Coastguard Worker# Copyright (C) 2024 The Android Open Source Project 4*105f6285SAndroid Build Coastguard Worker# 5*105f6285SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); you may not 6*105f6285SAndroid Build Coastguard Worker# use this file except in compliance with the License. You may obtain a copy of 7*105f6285SAndroid Build Coastguard Worker# the License at 8*105f6285SAndroid Build Coastguard Worker# 9*105f6285SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*105f6285SAndroid Build Coastguard Worker# 11*105f6285SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*105f6285SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13*105f6285SAndroid Build Coastguard Worker# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14*105f6285SAndroid Build Coastguard Worker# License for the specific language governing permissions and limitations under 15*105f6285SAndroid Build Coastguard Worker# the License. 16*105f6285SAndroid Build Coastguard Worker 17*105f6285SAndroid Build Coastguard Workerimport argparse 18*105f6285SAndroid Build Coastguard Workerimport dataclasses 19*105f6285SAndroid Build Coastguard Workerimport os 20*105f6285SAndroid Build Coastguard Workerimport shlex 21*105f6285SAndroid Build Coastguard Workerimport subprocess 22*105f6285SAndroid Build Coastguard Workerimport tempfile 23*105f6285SAndroid Build Coastguard Workerfrom typing import List 24*105f6285SAndroid Build Coastguard Worker 25*105f6285SAndroid Build Coastguard Workerfrom build_chd_utils import copy_files, unzip_otatools 26*105f6285SAndroid Build Coastguard Worker 27*105f6285SAndroid Build Coastguard Worker"""Builds a vendor_boot-chd_debug.img. 28*105f6285SAndroid Build Coastguard Worker 29*105f6285SAndroid Build Coastguard WorkerThe vendor_boot-chd_debug.img is built by adding those CHD specific debugging 30*105f6285SAndroid Build Coastguard Workerfiles to a Cuttlefish's vendor_boot-debug.img, using a new ramdisk fragment. 31*105f6285SAndroid Build Coastguard Worker 32*105f6285SAndroid Build Coastguard WorkerTest command: 33*105f6285SAndroid Build Coastguard Workerpython3 tools/treble/cuttlefish/build_chd_debug_ramdisk.py \ 34*105f6285SAndroid Build Coastguard Worker $ANDROID_PRODUCT_OUT/vendor_boot-debug.img \ 35*105f6285SAndroid Build Coastguard Worker -o $ANDROID_PRODUCT_OUT/vendor_boot-chd_debug.img \ 36*105f6285SAndroid Build Coastguard Worker --otatools_zip $ANDROID_PRODUCT_OUT/otatools.zip \ 37*105f6285SAndroid Build Coastguard Worker --add_file chd_debug.prop:adb_debug.prop 38*105f6285SAndroid Build Coastguard Worker""" 39*105f6285SAndroid Build Coastguard Worker 40*105f6285SAndroid Build Coastguard Worker# The value of ramdisk type needs to be synchronized with 41*105f6285SAndroid Build Coastguard Worker# `system/tools/mkbootimg/mkbootimg.py`. We choose `_PLATFORM` here because the 42*105f6285SAndroid Build Coastguard Worker# CHD debug ramdisk will be used in normal boot (not for _RECOVERY or _DLKM). 43*105f6285SAndroid Build Coastguard Worker_VENDOR_RAMDISK_TYPE_PLATFORM = '1' 44*105f6285SAndroid Build Coastguard Worker 45*105f6285SAndroid Build Coastguard Worker 46*105f6285SAndroid Build Coastguard Workerdef _parse_args() -> argparse.Namespace: 47*105f6285SAndroid Build Coastguard Worker """Parse the arguments for building the chd debug ramdisk. 48*105f6285SAndroid Build Coastguard Worker 49*105f6285SAndroid Build Coastguard Worker Returns: 50*105f6285SAndroid Build Coastguard Worker An object of the parsed arguments. 51*105f6285SAndroid Build Coastguard Worker """ 52*105f6285SAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 53*105f6285SAndroid Build Coastguard Worker parser.add_argument('input_img', 54*105f6285SAndroid Build Coastguard Worker help='The input Cuttlefish vendor boot debug image.') 55*105f6285SAndroid Build Coastguard Worker parser.add_argument('--output_img', '-o', required=True, 56*105f6285SAndroid Build Coastguard Worker help='The output CHD vendor boot debug image.') 57*105f6285SAndroid Build Coastguard Worker parser.add_argument('--otatools_zip', required=True, 58*105f6285SAndroid Build Coastguard Worker help='Path to the otatools.zip.') 59*105f6285SAndroid Build Coastguard Worker parser.add_argument('--add_file', action='append', default=[], 60*105f6285SAndroid Build Coastguard Worker help='The file to be added to the CHD debug ramdisk. ' 61*105f6285SAndroid Build Coastguard Worker 'The format is <src path>:<dst path>.') 62*105f6285SAndroid Build Coastguard Worker return parser.parse_args() 63*105f6285SAndroid Build Coastguard Worker 64*105f6285SAndroid Build Coastguard Worker 65*105f6285SAndroid Build Coastguard Worker@dataclasses.dataclass 66*105f6285SAndroid Build Coastguard Workerclass ImageOptions: 67*105f6285SAndroid Build Coastguard Worker """The options for building the CHD vendor boot debug image. 68*105f6285SAndroid Build Coastguard Worker 69*105f6285SAndroid Build Coastguard Worker Attributes: 70*105f6285SAndroid Build Coastguard Worker input_image: path of the input vendor boot debug image. 71*105f6285SAndroid Build Coastguard Worker output_image: path of the output CHD vendor boot debug image. 72*105f6285SAndroid Build Coastguard Worker otatools_dir: path of the otatools directory. 73*105f6285SAndroid Build Coastguard Worker temp_dir: path of the temporary directory for ramdisk filesystem. 74*105f6285SAndroid Build Coastguard Worker files_to_add: a list of files to be added in the debug ramdisk, where a 75*105f6285SAndroid Build Coastguard Worker pair defines the src and dst path of each file. 76*105f6285SAndroid Build Coastguard Worker files_to_remove: a list of files to be removed from the input vendor boot 77*105f6285SAndroid Build Coastguard Worker debug image. 78*105f6285SAndroid Build Coastguard Worker """ 79*105f6285SAndroid Build Coastguard Worker input_image: str 80*105f6285SAndroid Build Coastguard Worker output_image: str 81*105f6285SAndroid Build Coastguard Worker otatools_dir: str 82*105f6285SAndroid Build Coastguard Worker temp_dir: str 83*105f6285SAndroid Build Coastguard Worker files_to_add: List[str] = dataclasses.field(default_factory=list) 84*105f6285SAndroid Build Coastguard Worker files_to_remove: List[str] = dataclasses.field(default_factory=list) 85*105f6285SAndroid Build Coastguard Worker 86*105f6285SAndroid Build Coastguard Worker 87*105f6285SAndroid Build Coastguard Worker@dataclasses.dataclass 88*105f6285SAndroid Build Coastguard Workerclass BootImage: 89*105f6285SAndroid Build Coastguard Worker """Provide some functions to modify a boot image. 90*105f6285SAndroid Build Coastguard Worker 91*105f6285SAndroid Build Coastguard Worker Attributes: 92*105f6285SAndroid Build Coastguard Worker bootimg: path of the input boot image to be modified. 93*105f6285SAndroid Build Coastguard Worker bootimg_dir: path of a temporary directory that would be used to extract 94*105f6285SAndroid Build Coastguard Worker the input boot image. 95*105f6285SAndroid Build Coastguard Worker unpack_bootimg_bin: path of the `unpack_bootimg` executable. 96*105f6285SAndroid Build Coastguard Worker mkbootfs_bin: path of the `mkbootfs` executable. 97*105f6285SAndroid Build Coastguard Worker mkbootimg_bin: path of the `mkbootimg` executable. 98*105f6285SAndroid Build Coastguard Worker lz4_bin: path of the `lz4` executable. 99*105f6285SAndroid Build Coastguard Worker toybox_bin: path of the `toybox` executable. 100*105f6285SAndroid Build Coastguard Worker bootimg_args: the arguments that were used to build this boot image. 101*105f6285SAndroid Build Coastguard Worker """ 102*105f6285SAndroid Build Coastguard Worker bootimg: str 103*105f6285SAndroid Build Coastguard Worker bootimg_dir: str 104*105f6285SAndroid Build Coastguard Worker unpack_bootimg_bin: str 105*105f6285SAndroid Build Coastguard Worker mkbootfs_bin: str 106*105f6285SAndroid Build Coastguard Worker mkbootimg_bin: str 107*105f6285SAndroid Build Coastguard Worker lz4_bin: str 108*105f6285SAndroid Build Coastguard Worker toybox_bin: str 109*105f6285SAndroid Build Coastguard Worker bootimg_args: List[str] = dataclasses.field(default_factory=list) 110*105f6285SAndroid Build Coastguard Worker 111*105f6285SAndroid Build Coastguard Worker def _get_ramdisk_fragments(self) -> List[str]: 112*105f6285SAndroid Build Coastguard Worker """Get the path to all ramdisk fragments at `self.bootimg_dir`.""" 113*105f6285SAndroid Build Coastguard Worker return [os.path.join(self.bootimg_dir, file) 114*105f6285SAndroid Build Coastguard Worker for file in os.listdir(self.bootimg_dir) 115*105f6285SAndroid Build Coastguard Worker if file.startswith('vendor_ramdisk')] 116*105f6285SAndroid Build Coastguard Worker 117*105f6285SAndroid Build Coastguard Worker def _compress_ramdisk(self, root_dir: str, ramdisk_file: str) -> None: 118*105f6285SAndroid Build Coastguard Worker """Compress all the files under `root_dir` to generate `ramdisk_file`. 119*105f6285SAndroid Build Coastguard Worker 120*105f6285SAndroid Build Coastguard Worker Args: 121*105f6285SAndroid Build Coastguard Worker root_dir: root directory of the ramdisk content. 122*105f6285SAndroid Build Coastguard Worker ramdisk_file: path of the output ramdisk file. 123*105f6285SAndroid Build Coastguard Worker """ 124*105f6285SAndroid Build Coastguard Worker mkbootfs_cmd = [self.mkbootfs_bin, root_dir] 125*105f6285SAndroid Build Coastguard Worker mkbootfs_result = subprocess.run( 126*105f6285SAndroid Build Coastguard Worker mkbootfs_cmd, check=True, capture_output=True) 127*105f6285SAndroid Build Coastguard Worker compress_cmd = [self.lz4_bin, '-l', '-12', '--favor-decSpeed'] 128*105f6285SAndroid Build Coastguard Worker with open(ramdisk_file, 'w') as o: 129*105f6285SAndroid Build Coastguard Worker subprocess.run( 130*105f6285SAndroid Build Coastguard Worker compress_cmd, check=True, input=mkbootfs_result.stdout, stdout=o) 131*105f6285SAndroid Build Coastguard Worker 132*105f6285SAndroid Build Coastguard Worker def _decompress_ramdisk(self, ramdisk_file: str, output_dir: str) -> str: 133*105f6285SAndroid Build Coastguard Worker """Decompress `ramdisk_file` to a new file at `output_dir`. 134*105f6285SAndroid Build Coastguard Worker 135*105f6285SAndroid Build Coastguard Worker Args: 136*105f6285SAndroid Build Coastguard Worker ramdisk_file: path of the ramdisk file to be decompressed. 137*105f6285SAndroid Build Coastguard Worker output_dir: path of the output directory. 138*105f6285SAndroid Build Coastguard Worker 139*105f6285SAndroid Build Coastguard Worker Returns: 140*105f6285SAndroid Build Coastguard Worker Path of the uncompressed ramdisk. 141*105f6285SAndroid Build Coastguard Worker """ 142*105f6285SAndroid Build Coastguard Worker if not os.path.exists(output_dir): 143*105f6285SAndroid Build Coastguard Worker raise FileNotFoundError(f'Decompress output {output_dir} does not exist') 144*105f6285SAndroid Build Coastguard Worker uncompressed_ramdisk = os.path.join(output_dir, 'uncompressed_ramdisk') 145*105f6285SAndroid Build Coastguard Worker decompress_cmd = [self.lz4_bin, '-d', ramdisk_file, uncompressed_ramdisk] 146*105f6285SAndroid Build Coastguard Worker subprocess.run(decompress_cmd, check=True) 147*105f6285SAndroid Build Coastguard Worker return uncompressed_ramdisk 148*105f6285SAndroid Build Coastguard Worker 149*105f6285SAndroid Build Coastguard Worker def _extract_ramdisk(self, ramdisk_file: str, root_dir: str) -> None: 150*105f6285SAndroid Build Coastguard Worker """Extract the files from a uncompressed ramdisk to `root_dir`. 151*105f6285SAndroid Build Coastguard Worker 152*105f6285SAndroid Build Coastguard Worker Args: 153*105f6285SAndroid Build Coastguard Worker ramdisk_file: path of the ramdisk file to be extracted. 154*105f6285SAndroid Build Coastguard Worker root_dir: path of the extracted ramdisk root directory. 155*105f6285SAndroid Build Coastguard Worker """ 156*105f6285SAndroid Build Coastguard Worker # Use `toybox cpio` instead of `cpio` to avoid invoking cpio from the host 157*105f6285SAndroid Build Coastguard Worker # environment. 158*105f6285SAndroid Build Coastguard Worker extract_cmd = [self.toybox_bin, 'cpio', '-i', '-F', ramdisk_file] 159*105f6285SAndroid Build Coastguard Worker subprocess.run(extract_cmd, cwd=root_dir, check=True) 160*105f6285SAndroid Build Coastguard Worker 161*105f6285SAndroid Build Coastguard Worker def unpack(self) -> None: 162*105f6285SAndroid Build Coastguard Worker """Unpack the boot.img and capture the bootimg arguments.""" 163*105f6285SAndroid Build Coastguard Worker if self.bootimg_args: 164*105f6285SAndroid Build Coastguard Worker raise RuntimeError(f'cannot unpack {self.bootimg} twice') 165*105f6285SAndroid Build Coastguard Worker print(f'Unpacking {self.bootimg} to {self.bootimg_dir}') 166*105f6285SAndroid Build Coastguard Worker unpack_cmd = [ 167*105f6285SAndroid Build Coastguard Worker self.unpack_bootimg_bin, 168*105f6285SAndroid Build Coastguard Worker '--boot_img', self.bootimg, 169*105f6285SAndroid Build Coastguard Worker '--out', self.bootimg_dir, 170*105f6285SAndroid Build Coastguard Worker '--format', 'mkbootimg' 171*105f6285SAndroid Build Coastguard Worker ] 172*105f6285SAndroid Build Coastguard Worker unpack_result = subprocess.run(unpack_cmd, check=True, 173*105f6285SAndroid Build Coastguard Worker capture_output=True, encoding='utf-8') 174*105f6285SAndroid Build Coastguard Worker self.bootimg_args = shlex.split(unpack_result.stdout) 175*105f6285SAndroid Build Coastguard Worker 176*105f6285SAndroid Build Coastguard Worker def add_ramdisk(self, ramdisk_root: str) -> None: 177*105f6285SAndroid Build Coastguard Worker """Add a new ramdisk fragment and update the bootimg arguments. 178*105f6285SAndroid Build Coastguard Worker 179*105f6285SAndroid Build Coastguard Worker Args: 180*105f6285SAndroid Build Coastguard Worker ramdisk_root: path of the root directory which contains the content of 181*105f6285SAndroid Build Coastguard Worker the new ramdisk fragment. 182*105f6285SAndroid Build Coastguard Worker """ 183*105f6285SAndroid Build Coastguard Worker # Name the new ramdisk using the smallest unused index. 184*105f6285SAndroid Build Coastguard Worker ramdisk_fragments = self._get_ramdisk_fragments() 185*105f6285SAndroid Build Coastguard Worker new_ramdisk_name = f'vendor_ramdisk{len(ramdisk_fragments):02d}' 186*105f6285SAndroid Build Coastguard Worker new_ramdisk_file = os.path.join(self.bootimg_dir, new_ramdisk_name) 187*105f6285SAndroid Build Coastguard Worker if os.path.exists(new_ramdisk_file): 188*105f6285SAndroid Build Coastguard Worker raise FileExistsError(f'{new_ramdisk_file} already exists') 189*105f6285SAndroid Build Coastguard Worker print(f'Adding a new vendor ramdisk fragment {new_ramdisk_file}') 190*105f6285SAndroid Build Coastguard Worker self._compress_ramdisk(ramdisk_root, new_ramdisk_file) 191*105f6285SAndroid Build Coastguard Worker 192*105f6285SAndroid Build Coastguard Worker # Update the bootimg arguments to include the new ramdisk file. 193*105f6285SAndroid Build Coastguard Worker self.bootimg_args.extend([ 194*105f6285SAndroid Build Coastguard Worker '--ramdisk_type', _VENDOR_RAMDISK_TYPE_PLATFORM, 195*105f6285SAndroid Build Coastguard Worker '--ramdisk_name', 'chd', 196*105f6285SAndroid Build Coastguard Worker '--vendor_ramdisk_fragment', new_ramdisk_file 197*105f6285SAndroid Build Coastguard Worker ]) 198*105f6285SAndroid Build Coastguard Worker 199*105f6285SAndroid Build Coastguard Worker def remove_file(self, file_name: str) -> None: 200*105f6285SAndroid Build Coastguard Worker """Remove `file_name` from all the existing ramdisk fragments. 201*105f6285SAndroid Build Coastguard Worker 202*105f6285SAndroid Build Coastguard Worker Args: 203*105f6285SAndroid Build Coastguard Worker file_name: path of the file to be removed, relative to the ramdisk root 204*105f6285SAndroid Build Coastguard Worker directory. 205*105f6285SAndroid Build Coastguard Worker 206*105f6285SAndroid Build Coastguard Worker Raises: 207*105f6285SAndroid Build Coastguard Worker FileNotFoundError if `file_name` cannot be found in any of the ramdisk 208*105f6285SAndroid Build Coastguard Worker fragments. 209*105f6285SAndroid Build Coastguard Worker """ 210*105f6285SAndroid Build Coastguard Worker ramdisk_fragments = self._get_ramdisk_fragments() 211*105f6285SAndroid Build Coastguard Worker is_removed = False 212*105f6285SAndroid Build Coastguard Worker for ramdisk in ramdisk_fragments: 213*105f6285SAndroid Build Coastguard Worker print(f'Attempting to remove {file_name} from {ramdisk}') 214*105f6285SAndroid Build Coastguard Worker with tempfile.TemporaryDirectory() as temp_dir: 215*105f6285SAndroid Build Coastguard Worker uncompressed_ramdisk = self._decompress_ramdisk(ramdisk, temp_dir) 216*105f6285SAndroid Build Coastguard Worker extracted_ramdisk_dir = os.path.join(temp_dir, 'extracted_ramdisk') 217*105f6285SAndroid Build Coastguard Worker os.mkdir(extracted_ramdisk_dir) 218*105f6285SAndroid Build Coastguard Worker self._extract_ramdisk(uncompressed_ramdisk, extracted_ramdisk_dir) 219*105f6285SAndroid Build Coastguard Worker file_path = os.path.join(extracted_ramdisk_dir, file_name) 220*105f6285SAndroid Build Coastguard Worker if os.path.exists(file_path): 221*105f6285SAndroid Build Coastguard Worker os.remove(file_path) 222*105f6285SAndroid Build Coastguard Worker is_removed = True 223*105f6285SAndroid Build Coastguard Worker print(f'{file_path} was removed') 224*105f6285SAndroid Build Coastguard Worker self._compress_ramdisk(extracted_ramdisk_dir, ramdisk) 225*105f6285SAndroid Build Coastguard Worker 226*105f6285SAndroid Build Coastguard Worker if not is_removed: 227*105f6285SAndroid Build Coastguard Worker raise FileNotFoundError( 228*105f6285SAndroid Build Coastguard Worker f'cannot remove {file_name} from {ramdisk_fragments}' 229*105f6285SAndroid Build Coastguard Worker ) 230*105f6285SAndroid Build Coastguard Worker 231*105f6285SAndroid Build Coastguard Worker def pack(self, output_img: str) -> None: 232*105f6285SAndroid Build Coastguard Worker """Pack the boot.img using `self.bootimg_args`. 233*105f6285SAndroid Build Coastguard Worker 234*105f6285SAndroid Build Coastguard Worker Args: 235*105f6285SAndroid Build Coastguard Worker output_img: path of the output boot image. 236*105f6285SAndroid Build Coastguard Worker """ 237*105f6285SAndroid Build Coastguard Worker print(f'Packing {output_img} with args: {self.bootimg_args}') 238*105f6285SAndroid Build Coastguard Worker mkbootimg_cmd = [ 239*105f6285SAndroid Build Coastguard Worker self.mkbootimg_bin, '--vendor_boot', output_img 240*105f6285SAndroid Build Coastguard Worker ] + self.bootimg_args 241*105f6285SAndroid Build Coastguard Worker subprocess.check_call(mkbootimg_cmd) 242*105f6285SAndroid Build Coastguard Worker 243*105f6285SAndroid Build Coastguard Worker 244*105f6285SAndroid Build Coastguard Workerdef _prepare_env(otatools_dir: str) -> List[str]: 245*105f6285SAndroid Build Coastguard Worker """Get the executable path of the required otatools. 246*105f6285SAndroid Build Coastguard Worker 247*105f6285SAndroid Build Coastguard Worker We need `unpack_bootimg`, `mkbootfs`, `mkbootimg`, `lz4` and `toybox` for 248*105f6285SAndroid Build Coastguard Worker building CHD debug ramdisk. This function returns the path to the above tools 249*105f6285SAndroid Build Coastguard Worker in order. 250*105f6285SAndroid Build Coastguard Worker 251*105f6285SAndroid Build Coastguard Worker Args: 252*105f6285SAndroid Build Coastguard Worker otatools_dir: path of the otatools directory. 253*105f6285SAndroid Build Coastguard Worker 254*105f6285SAndroid Build Coastguard Worker Raises: 255*105f6285SAndroid Build Coastguard Worker FileNotFoundError if any required otatool does not exist. 256*105f6285SAndroid Build Coastguard Worker """ 257*105f6285SAndroid Build Coastguard Worker tools_path = [] 258*105f6285SAndroid Build Coastguard Worker for tool in ['unpack_bootimg', 'mkbootfs', 'mkbootimg', 'lz4', 'toybox']: 259*105f6285SAndroid Build Coastguard Worker tool_path = os.path.join(otatools_dir, 'bin', tool) 260*105f6285SAndroid Build Coastguard Worker if not os.path.exists(tool_path): 261*105f6285SAndroid Build Coastguard Worker raise FileNotFoundError(f'otatool {tool_path} does not exist') 262*105f6285SAndroid Build Coastguard Worker tools_path.append(tool_path) 263*105f6285SAndroid Build Coastguard Worker return tools_path 264*105f6285SAndroid Build Coastguard Worker 265*105f6285SAndroid Build Coastguard Worker 266*105f6285SAndroid Build Coastguard Workerdef build_chd_debug_ramdisk(options: ImageOptions) -> None: 267*105f6285SAndroid Build Coastguard Worker """Build a new vendor boot debug image. 268*105f6285SAndroid Build Coastguard Worker 269*105f6285SAndroid Build Coastguard Worker 1. If `options.files_to_remove` present, remove these files from all the 270*105f6285SAndroid Build Coastguard Worker existing ramdisk fragments. 271*105f6285SAndroid Build Coastguard Worker 2. If `options.files_to_add` present, create a new ramdisk fragment which 272*105f6285SAndroid Build Coastguard Worker adds these files, and add this new fragment into the input image. 273*105f6285SAndroid Build Coastguard Worker 274*105f6285SAndroid Build Coastguard Worker Args: 275*105f6285SAndroid Build Coastguard Worker options: a `ImageOptions` object which specifies the options for building 276*105f6285SAndroid Build Coastguard Worker a CHD vendor boot debug image. 277*105f6285SAndroid Build Coastguard Worker 278*105f6285SAndroid Build Coastguard Worker Raises: 279*105f6285SAndroid Build Coastguard Worker FileExistsError if having duplicated ramdisk fragments. 280*105f6285SAndroid Build Coastguard Worker FileNotFoundError if any required otatool does not exist or if 281*105f6285SAndroid Build Coastguard Worker `options.files_to_remove` is not present in any of the ramdisk fragments 282*105f6285SAndroid Build Coastguard Worker of `input_image`. 283*105f6285SAndroid Build Coastguard Worker """ 284*105f6285SAndroid Build Coastguard Worker unpack_bootimg, mkbootfs, mkbootimg, lz4, toybox = _prepare_env( 285*105f6285SAndroid Build Coastguard Worker options.otatools_dir) 286*105f6285SAndroid Build Coastguard Worker bootimg = BootImage( 287*105f6285SAndroid Build Coastguard Worker bootimg=options.input_image, 288*105f6285SAndroid Build Coastguard Worker bootimg_dir=os.path.join(options.temp_dir, 'bootimg'), 289*105f6285SAndroid Build Coastguard Worker unpack_bootimg_bin=unpack_bootimg, 290*105f6285SAndroid Build Coastguard Worker mkbootfs_bin=mkbootfs, 291*105f6285SAndroid Build Coastguard Worker mkbootimg_bin=mkbootimg, 292*105f6285SAndroid Build Coastguard Worker lz4_bin=lz4, 293*105f6285SAndroid Build Coastguard Worker toybox_bin=toybox) 294*105f6285SAndroid Build Coastguard Worker bootimg.unpack() 295*105f6285SAndroid Build Coastguard Worker 296*105f6285SAndroid Build Coastguard Worker for f in options.files_to_remove: 297*105f6285SAndroid Build Coastguard Worker bootimg.remove_file(f) 298*105f6285SAndroid Build Coastguard Worker 299*105f6285SAndroid Build Coastguard Worker if options.files_to_add: 300*105f6285SAndroid Build Coastguard Worker print(f'Adding {options.files_to_add} to {options.input_image}') 301*105f6285SAndroid Build Coastguard Worker new_ramdisk_fragment = os.path.join(options.temp_dir, 302*105f6285SAndroid Build Coastguard Worker 'new_ramdisk_fragment') 303*105f6285SAndroid Build Coastguard Worker os.mkdir(new_ramdisk_fragment) 304*105f6285SAndroid Build Coastguard Worker copy_files(options.files_to_add, new_ramdisk_fragment) 305*105f6285SAndroid Build Coastguard Worker bootimg.add_ramdisk(new_ramdisk_fragment) 306*105f6285SAndroid Build Coastguard Worker 307*105f6285SAndroid Build Coastguard Worker bootimg.pack(options.output_image) 308*105f6285SAndroid Build Coastguard Worker 309*105f6285SAndroid Build Coastguard Worker 310*105f6285SAndroid Build Coastguard Workerdef main(temp_dir: str) -> None: 311*105f6285SAndroid Build Coastguard Worker args = _parse_args() 312*105f6285SAndroid Build Coastguard Worker otatools_dir = os.path.join(temp_dir, 'otatools') 313*105f6285SAndroid Build Coastguard Worker unzip_otatools(args.otatools_zip, otatools_dir, [ 314*105f6285SAndroid Build Coastguard Worker 'bin/unpack_bootimg', 'bin/mkbootfs', 'bin/mkbootimg', 'bin/lz4', 315*105f6285SAndroid Build Coastguard Worker 'bin/toybox', 'lib64/*' 316*105f6285SAndroid Build Coastguard Worker ]) 317*105f6285SAndroid Build Coastguard Worker options = ImageOptions( 318*105f6285SAndroid Build Coastguard Worker input_image=args.input_img, 319*105f6285SAndroid Build Coastguard Worker output_image=args.output_img, 320*105f6285SAndroid Build Coastguard Worker otatools_dir=otatools_dir, 321*105f6285SAndroid Build Coastguard Worker temp_dir=temp_dir, 322*105f6285SAndroid Build Coastguard Worker files_to_add=args.add_file) 323*105f6285SAndroid Build Coastguard Worker build_chd_debug_ramdisk(options) 324*105f6285SAndroid Build Coastguard Worker 325*105f6285SAndroid Build Coastguard Worker 326*105f6285SAndroid Build Coastguard Workerif __name__ == '__main__': 327*105f6285SAndroid Build Coastguard Worker with tempfile.TemporaryDirectory() as temp_dir: 328*105f6285SAndroid Build Coastguard Worker main(temp_dir) 329