1*9e94795aSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*9e94795aSAndroid Build Coastguard Worker# 3*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2011 The Android Open Source Project 4*9e94795aSAndroid Build Coastguard Worker# 5*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*9e94795aSAndroid Build Coastguard Worker# 9*9e94795aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*9e94795aSAndroid Build Coastguard Worker# 11*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*9e94795aSAndroid Build Coastguard Worker# limitations under the License. 16*9e94795aSAndroid Build Coastguard Worker 17*9e94795aSAndroid Build Coastguard Worker""" 18*9e94795aSAndroid Build Coastguard WorkerBuilds output_image from the given input_directory, properties_file, 19*9e94795aSAndroid Build Coastguard Workerand writes the image to target_output_directory. 20*9e94795aSAndroid Build Coastguard Worker 21*9e94795aSAndroid Build Coastguard WorkerUsage: build_image input_directory properties_file output_image \\ 22*9e94795aSAndroid Build Coastguard Worker target_output_directory 23*9e94795aSAndroid Build Coastguard Worker""" 24*9e94795aSAndroid Build Coastguard Worker 25*9e94795aSAndroid Build Coastguard Workerimport datetime 26*9e94795aSAndroid Build Coastguard Worker 27*9e94795aSAndroid Build Coastguard Workerimport argparse 28*9e94795aSAndroid Build Coastguard Workerimport glob 29*9e94795aSAndroid Build Coastguard Workerimport logging 30*9e94795aSAndroid Build Coastguard Workerimport os 31*9e94795aSAndroid Build Coastguard Workerimport os.path 32*9e94795aSAndroid Build Coastguard Workerimport re 33*9e94795aSAndroid Build Coastguard Workerimport shlex 34*9e94795aSAndroid Build Coastguard Workerimport shutil 35*9e94795aSAndroid Build Coastguard Workerimport sys 36*9e94795aSAndroid Build Coastguard Workerimport uuid 37*9e94795aSAndroid Build Coastguard Workerimport tempfile 38*9e94795aSAndroid Build Coastguard Worker 39*9e94795aSAndroid Build Coastguard Workerimport common 40*9e94795aSAndroid Build Coastguard Workerimport verity_utils 41*9e94795aSAndroid Build Coastguard Worker 42*9e94795aSAndroid Build Coastguard Worker 43*9e94795aSAndroid Build Coastguard Workerlogger = logging.getLogger(__name__) 44*9e94795aSAndroid Build Coastguard Worker 45*9e94795aSAndroid Build Coastguard WorkerOPTIONS = common.OPTIONS 46*9e94795aSAndroid Build Coastguard WorkerBLOCK_SIZE = common.BLOCK_SIZE 47*9e94795aSAndroid Build Coastguard WorkerBYTES_IN_MB = 1024 * 1024 48*9e94795aSAndroid Build Coastguard Worker 49*9e94795aSAndroid Build Coastguard Worker# Use a fixed timestamp (01/01/2009 00:00:00 UTC) for files when packaging 50*9e94795aSAndroid Build Coastguard Worker# images. (b/24377993, b/80600931) 51*9e94795aSAndroid Build Coastguard WorkerFIXED_FILE_TIMESTAMP = int(( 52*9e94795aSAndroid Build Coastguard Worker datetime.datetime(2009, 1, 1, 0, 0, 0, 0, None) - 53*9e94795aSAndroid Build Coastguard Worker datetime.datetime.utcfromtimestamp(0)).total_seconds()) 54*9e94795aSAndroid Build Coastguard Worker 55*9e94795aSAndroid Build Coastguard Worker 56*9e94795aSAndroid Build Coastguard Workerclass BuildImageError(Exception): 57*9e94795aSAndroid Build Coastguard Worker """An Exception raised during image building.""" 58*9e94795aSAndroid Build Coastguard Worker 59*9e94795aSAndroid Build Coastguard Worker def __init__(self, message): 60*9e94795aSAndroid Build Coastguard Worker Exception.__init__(self, message) 61*9e94795aSAndroid Build Coastguard Worker 62*9e94795aSAndroid Build Coastguard Worker 63*9e94795aSAndroid Build Coastguard Workerdef GetDiskUsage(path): 64*9e94795aSAndroid Build Coastguard Worker """Returns the number of bytes that "path" occupies on host. 65*9e94795aSAndroid Build Coastguard Worker 66*9e94795aSAndroid Build Coastguard Worker Args: 67*9e94795aSAndroid Build Coastguard Worker path: The directory or file to calculate size on. 68*9e94795aSAndroid Build Coastguard Worker 69*9e94795aSAndroid Build Coastguard Worker Returns: 70*9e94795aSAndroid Build Coastguard Worker The number of bytes based on a 1K block_size. 71*9e94795aSAndroid Build Coastguard Worker """ 72*9e94795aSAndroid Build Coastguard Worker cmd = ["du", "-b", "-k", "-s", path] 73*9e94795aSAndroid Build Coastguard Worker output = common.RunAndCheckOutput(cmd, verbose=False) 74*9e94795aSAndroid Build Coastguard Worker return int(output.split()[0]) * 1024 75*9e94795aSAndroid Build Coastguard Worker 76*9e94795aSAndroid Build Coastguard Worker 77*9e94795aSAndroid Build Coastguard Workerdef GetInodeUsage(path): 78*9e94795aSAndroid Build Coastguard Worker """Returns the number of inodes that "path" occupies on host. 79*9e94795aSAndroid Build Coastguard Worker 80*9e94795aSAndroid Build Coastguard Worker Args: 81*9e94795aSAndroid Build Coastguard Worker path: The directory or file to calculate inode number on. 82*9e94795aSAndroid Build Coastguard Worker 83*9e94795aSAndroid Build Coastguard Worker Returns: 84*9e94795aSAndroid Build Coastguard Worker The number of inodes used. 85*9e94795aSAndroid Build Coastguard Worker """ 86*9e94795aSAndroid Build Coastguard Worker cmd = ["find", path, "-print"] 87*9e94795aSAndroid Build Coastguard Worker output = common.RunAndCheckOutput(cmd, verbose=False) 88*9e94795aSAndroid Build Coastguard Worker # increase by > 6% as number of files and directories is not whole picture. 89*9e94795aSAndroid Build Coastguard Worker inodes = output.count('\n') 90*9e94795aSAndroid Build Coastguard Worker spare_inodes = inodes * 6 // 100 91*9e94795aSAndroid Build Coastguard Worker min_spare_inodes = 12 92*9e94795aSAndroid Build Coastguard Worker if spare_inodes < min_spare_inodes: 93*9e94795aSAndroid Build Coastguard Worker spare_inodes = min_spare_inodes 94*9e94795aSAndroid Build Coastguard Worker return inodes + spare_inodes 95*9e94795aSAndroid Build Coastguard Worker 96*9e94795aSAndroid Build Coastguard Worker 97*9e94795aSAndroid Build Coastguard Workerdef GetFilesystemCharacteristics(fs_type, image_path, sparse_image=True): 98*9e94795aSAndroid Build Coastguard Worker """Returns various filesystem characteristics of "image_path". 99*9e94795aSAndroid Build Coastguard Worker 100*9e94795aSAndroid Build Coastguard Worker Args: 101*9e94795aSAndroid Build Coastguard Worker image_path: The file to analyze. 102*9e94795aSAndroid Build Coastguard Worker sparse_image: Image is sparse 103*9e94795aSAndroid Build Coastguard Worker 104*9e94795aSAndroid Build Coastguard Worker Returns: 105*9e94795aSAndroid Build Coastguard Worker The characteristics dictionary. 106*9e94795aSAndroid Build Coastguard Worker """ 107*9e94795aSAndroid Build Coastguard Worker unsparse_image_path = image_path 108*9e94795aSAndroid Build Coastguard Worker if sparse_image: 109*9e94795aSAndroid Build Coastguard Worker unsparse_image_path = UnsparseImage(image_path, replace=False) 110*9e94795aSAndroid Build Coastguard Worker 111*9e94795aSAndroid Build Coastguard Worker if fs_type.startswith("ext"): 112*9e94795aSAndroid Build Coastguard Worker cmd = ["tune2fs", "-l", unsparse_image_path] 113*9e94795aSAndroid Build Coastguard Worker elif fs_type.startswith("f2fs"): 114*9e94795aSAndroid Build Coastguard Worker cmd = ["fsck.f2fs", "-l", unsparse_image_path] 115*9e94795aSAndroid Build Coastguard Worker 116*9e94795aSAndroid Build Coastguard Worker try: 117*9e94795aSAndroid Build Coastguard Worker output = common.RunAndCheckOutput(cmd, verbose=False) 118*9e94795aSAndroid Build Coastguard Worker finally: 119*9e94795aSAndroid Build Coastguard Worker if sparse_image: 120*9e94795aSAndroid Build Coastguard Worker os.remove(unsparse_image_path) 121*9e94795aSAndroid Build Coastguard Worker fs_dict = {} 122*9e94795aSAndroid Build Coastguard Worker for line in output.splitlines(): 123*9e94795aSAndroid Build Coastguard Worker fields = line.split(":") 124*9e94795aSAndroid Build Coastguard Worker if len(fields) == 2: 125*9e94795aSAndroid Build Coastguard Worker fs_dict[fields[0].strip()] = fields[1].strip() 126*9e94795aSAndroid Build Coastguard Worker return fs_dict 127*9e94795aSAndroid Build Coastguard Worker 128*9e94795aSAndroid Build Coastguard Worker 129*9e94795aSAndroid Build Coastguard Workerdef UnsparseImage(sparse_image_path, replace=True): 130*9e94795aSAndroid Build Coastguard Worker img_dir = os.path.dirname(sparse_image_path) 131*9e94795aSAndroid Build Coastguard Worker unsparse_image_path = "unsparse_" + os.path.basename(sparse_image_path) 132*9e94795aSAndroid Build Coastguard Worker unsparse_image_path = os.path.join(img_dir, unsparse_image_path) 133*9e94795aSAndroid Build Coastguard Worker if os.path.exists(unsparse_image_path): 134*9e94795aSAndroid Build Coastguard Worker if replace: 135*9e94795aSAndroid Build Coastguard Worker os.unlink(unsparse_image_path) 136*9e94795aSAndroid Build Coastguard Worker else: 137*9e94795aSAndroid Build Coastguard Worker return unsparse_image_path 138*9e94795aSAndroid Build Coastguard Worker inflate_command = ["simg2img", sparse_image_path, unsparse_image_path] 139*9e94795aSAndroid Build Coastguard Worker try: 140*9e94795aSAndroid Build Coastguard Worker common.RunAndCheckOutput(inflate_command) 141*9e94795aSAndroid Build Coastguard Worker except: 142*9e94795aSAndroid Build Coastguard Worker os.remove(unsparse_image_path) 143*9e94795aSAndroid Build Coastguard Worker raise 144*9e94795aSAndroid Build Coastguard Worker return unsparse_image_path 145*9e94795aSAndroid Build Coastguard Worker 146*9e94795aSAndroid Build Coastguard Worker 147*9e94795aSAndroid Build Coastguard Workerdef ConvertBlockMapToBaseFs(block_map_file): 148*9e94795aSAndroid Build Coastguard Worker base_fs_file = common.MakeTempFile(prefix="script_gen_", suffix=".base_fs") 149*9e94795aSAndroid Build Coastguard Worker convert_command = ["blk_alloc_to_base_fs", block_map_file, base_fs_file] 150*9e94795aSAndroid Build Coastguard Worker common.RunAndCheckOutput(convert_command) 151*9e94795aSAndroid Build Coastguard Worker return base_fs_file 152*9e94795aSAndroid Build Coastguard Worker 153*9e94795aSAndroid Build Coastguard Worker 154*9e94795aSAndroid Build Coastguard Workerdef SetUpInDirAndFsConfig(origin_in, prop_dict): 155*9e94795aSAndroid Build Coastguard Worker """Returns the in_dir and fs_config that should be used for image building. 156*9e94795aSAndroid Build Coastguard Worker 157*9e94795aSAndroid Build Coastguard Worker When building system.img for all targets, it creates and returns a staged dir 158*9e94795aSAndroid Build Coastguard Worker that combines the contents of /system (i.e. in the given in_dir) and root. 159*9e94795aSAndroid Build Coastguard Worker 160*9e94795aSAndroid Build Coastguard Worker Args: 161*9e94795aSAndroid Build Coastguard Worker origin_in: Path to the input directory. 162*9e94795aSAndroid Build Coastguard Worker prop_dict: A property dict that contains info like partition size. Values 163*9e94795aSAndroid Build Coastguard Worker may be updated. 164*9e94795aSAndroid Build Coastguard Worker 165*9e94795aSAndroid Build Coastguard Worker Returns: 166*9e94795aSAndroid Build Coastguard Worker A tuple of in_dir and fs_config that should be used to build the image. 167*9e94795aSAndroid Build Coastguard Worker """ 168*9e94795aSAndroid Build Coastguard Worker fs_config = prop_dict.get("fs_config") 169*9e94795aSAndroid Build Coastguard Worker 170*9e94795aSAndroid Build Coastguard Worker if prop_dict["mount_point"] == "system_other": 171*9e94795aSAndroid Build Coastguard Worker prop_dict["mount_point"] = "system" 172*9e94795aSAndroid Build Coastguard Worker return origin_in, fs_config 173*9e94795aSAndroid Build Coastguard Worker 174*9e94795aSAndroid Build Coastguard Worker if prop_dict["mount_point"] != "system": 175*9e94795aSAndroid Build Coastguard Worker return origin_in, fs_config 176*9e94795aSAndroid Build Coastguard Worker 177*9e94795aSAndroid Build Coastguard Worker if "first_pass" in prop_dict: 178*9e94795aSAndroid Build Coastguard Worker prop_dict["mount_point"] = "/" 179*9e94795aSAndroid Build Coastguard Worker return prop_dict["first_pass"] 180*9e94795aSAndroid Build Coastguard Worker 181*9e94795aSAndroid Build Coastguard Worker # Construct a staging directory of the root file system. 182*9e94795aSAndroid Build Coastguard Worker in_dir = common.MakeTempDir() 183*9e94795aSAndroid Build Coastguard Worker root_dir = prop_dict.get("root_dir") 184*9e94795aSAndroid Build Coastguard Worker if root_dir: 185*9e94795aSAndroid Build Coastguard Worker shutil.rmtree(in_dir) 186*9e94795aSAndroid Build Coastguard Worker shutil.copytree(root_dir, in_dir, symlinks=True) 187*9e94795aSAndroid Build Coastguard Worker in_dir_system = os.path.join(in_dir, "system") 188*9e94795aSAndroid Build Coastguard Worker shutil.rmtree(in_dir_system, ignore_errors=True) 189*9e94795aSAndroid Build Coastguard Worker shutil.copytree(origin_in, in_dir_system, symlinks=True) 190*9e94795aSAndroid Build Coastguard Worker 191*9e94795aSAndroid Build Coastguard Worker # Change the mount point to "/". 192*9e94795aSAndroid Build Coastguard Worker prop_dict["mount_point"] = "/" 193*9e94795aSAndroid Build Coastguard Worker if fs_config: 194*9e94795aSAndroid Build Coastguard Worker # We need to merge the fs_config files of system and root. 195*9e94795aSAndroid Build Coastguard Worker merged_fs_config = common.MakeTempFile( 196*9e94795aSAndroid Build Coastguard Worker prefix="merged_fs_config", suffix=".txt") 197*9e94795aSAndroid Build Coastguard Worker with open(merged_fs_config, "w") as fw: 198*9e94795aSAndroid Build Coastguard Worker if "root_fs_config" in prop_dict: 199*9e94795aSAndroid Build Coastguard Worker with open(prop_dict["root_fs_config"]) as fr: 200*9e94795aSAndroid Build Coastguard Worker fw.writelines(fr.readlines()) 201*9e94795aSAndroid Build Coastguard Worker with open(fs_config) as fr: 202*9e94795aSAndroid Build Coastguard Worker fw.writelines(fr.readlines()) 203*9e94795aSAndroid Build Coastguard Worker fs_config = merged_fs_config 204*9e94795aSAndroid Build Coastguard Worker prop_dict["first_pass"] = (in_dir, fs_config) 205*9e94795aSAndroid Build Coastguard Worker return in_dir, fs_config 206*9e94795aSAndroid Build Coastguard Worker 207*9e94795aSAndroid Build Coastguard Worker 208*9e94795aSAndroid Build Coastguard Workerdef CheckHeadroom(ext4fs_output, prop_dict): 209*9e94795aSAndroid Build Coastguard Worker """Checks if there's enough headroom space available. 210*9e94795aSAndroid Build Coastguard Worker 211*9e94795aSAndroid Build Coastguard Worker Headroom is the reserved space on system image (via PRODUCT_SYSTEM_HEADROOM), 212*9e94795aSAndroid Build Coastguard Worker which is useful for devices with low disk space that have system image 213*9e94795aSAndroid Build Coastguard Worker variation between builds. The 'partition_headroom' in prop_dict is the size 214*9e94795aSAndroid Build Coastguard Worker in bytes, while the numbers in 'ext4fs_output' are for 4K-blocks. 215*9e94795aSAndroid Build Coastguard Worker 216*9e94795aSAndroid Build Coastguard Worker Args: 217*9e94795aSAndroid Build Coastguard Worker ext4fs_output: The output string from mke2fs command. 218*9e94795aSAndroid Build Coastguard Worker prop_dict: The property dict. 219*9e94795aSAndroid Build Coastguard Worker 220*9e94795aSAndroid Build Coastguard Worker Raises: 221*9e94795aSAndroid Build Coastguard Worker AssertionError: On invalid input. 222*9e94795aSAndroid Build Coastguard Worker BuildImageError: On check failure. 223*9e94795aSAndroid Build Coastguard Worker """ 224*9e94795aSAndroid Build Coastguard Worker assert ext4fs_output is not None 225*9e94795aSAndroid Build Coastguard Worker assert prop_dict.get('fs_type', '').startswith('ext4') 226*9e94795aSAndroid Build Coastguard Worker assert 'partition_headroom' in prop_dict 227*9e94795aSAndroid Build Coastguard Worker assert 'mount_point' in prop_dict 228*9e94795aSAndroid Build Coastguard Worker 229*9e94795aSAndroid Build Coastguard Worker ext4fs_stats = re.compile( 230*9e94795aSAndroid Build Coastguard Worker r'Created filesystem with .* (?P<used_blocks>[0-9]+)/' 231*9e94795aSAndroid Build Coastguard Worker r'(?P<total_blocks>[0-9]+) blocks') 232*9e94795aSAndroid Build Coastguard Worker last_line = ext4fs_output.strip().split('\n')[-1] 233*9e94795aSAndroid Build Coastguard Worker m = ext4fs_stats.match(last_line) 234*9e94795aSAndroid Build Coastguard Worker used_blocks = int(m.groupdict().get('used_blocks')) 235*9e94795aSAndroid Build Coastguard Worker total_blocks = int(m.groupdict().get('total_blocks')) 236*9e94795aSAndroid Build Coastguard Worker headroom_blocks = int(prop_dict['partition_headroom']) // BLOCK_SIZE 237*9e94795aSAndroid Build Coastguard Worker adjusted_blocks = total_blocks - headroom_blocks 238*9e94795aSAndroid Build Coastguard Worker if used_blocks > adjusted_blocks: 239*9e94795aSAndroid Build Coastguard Worker mount_point = prop_dict["mount_point"] 240*9e94795aSAndroid Build Coastguard Worker raise BuildImageError( 241*9e94795aSAndroid Build Coastguard Worker "Error: Not enough room on {} (total: {} blocks, used: {} blocks, " 242*9e94795aSAndroid Build Coastguard Worker "headroom: {} blocks, available: {} blocks)".format( 243*9e94795aSAndroid Build Coastguard Worker mount_point, total_blocks, used_blocks, headroom_blocks, 244*9e94795aSAndroid Build Coastguard Worker adjusted_blocks)) 245*9e94795aSAndroid Build Coastguard Worker 246*9e94795aSAndroid Build Coastguard Worker 247*9e94795aSAndroid Build Coastguard Workerdef CalculateSizeAndReserved(prop_dict, size): 248*9e94795aSAndroid Build Coastguard Worker fs_type = prop_dict.get("fs_type", "") 249*9e94795aSAndroid Build Coastguard Worker partition_headroom = int(prop_dict.get("partition_headroom", 0)) 250*9e94795aSAndroid Build Coastguard Worker # If not specified, give us 16MB margin for GetDiskUsage error ... 251*9e94795aSAndroid Build Coastguard Worker reserved_size = int(prop_dict.get( 252*9e94795aSAndroid Build Coastguard Worker "partition_reserved_size", BYTES_IN_MB * 16)) 253*9e94795aSAndroid Build Coastguard Worker 254*9e94795aSAndroid Build Coastguard Worker if fs_type == "erofs": 255*9e94795aSAndroid Build Coastguard Worker reserved_size = int(prop_dict.get("partition_reserved_size", 0)) 256*9e94795aSAndroid Build Coastguard Worker if reserved_size == 0: 257*9e94795aSAndroid Build Coastguard Worker # give .3% margin or a minimum size for AVB footer 258*9e94795aSAndroid Build Coastguard Worker return max(size * 1003 // 1000, 256 * 1024) 259*9e94795aSAndroid Build Coastguard Worker 260*9e94795aSAndroid Build Coastguard Worker if fs_type.startswith("ext4") and partition_headroom > reserved_size: 261*9e94795aSAndroid Build Coastguard Worker reserved_size = partition_headroom 262*9e94795aSAndroid Build Coastguard Worker 263*9e94795aSAndroid Build Coastguard Worker return int(size * 1.1) + reserved_size 264*9e94795aSAndroid Build Coastguard Worker 265*9e94795aSAndroid Build Coastguard Worker 266*9e94795aSAndroid Build Coastguard Workerdef BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config): 267*9e94795aSAndroid Build Coastguard Worker """Builds a pure image for the files under in_dir and writes it to out_file. 268*9e94795aSAndroid Build Coastguard Worker 269*9e94795aSAndroid Build Coastguard Worker Args: 270*9e94795aSAndroid Build Coastguard Worker in_dir: Path to input directory. 271*9e94795aSAndroid Build Coastguard Worker prop_dict: A property dict that contains info like partition size. Values 272*9e94795aSAndroid Build Coastguard Worker will be updated with computed values. 273*9e94795aSAndroid Build Coastguard Worker out_file: The output image file. 274*9e94795aSAndroid Build Coastguard Worker target_out: Path to the TARGET_OUT directory as in Makefile. It actually 275*9e94795aSAndroid Build Coastguard Worker points to the /system directory under PRODUCT_OUT. fs_config (the one 276*9e94795aSAndroid Build Coastguard Worker under system/core/libcutils) reads device specific FS config files from 277*9e94795aSAndroid Build Coastguard Worker there. 278*9e94795aSAndroid Build Coastguard Worker fs_config: The fs_config file that drives the prototype 279*9e94795aSAndroid Build Coastguard Worker 280*9e94795aSAndroid Build Coastguard Worker Raises: 281*9e94795aSAndroid Build Coastguard Worker BuildImageError: On build image failures. 282*9e94795aSAndroid Build Coastguard Worker """ 283*9e94795aSAndroid Build Coastguard Worker build_command = [] 284*9e94795aSAndroid Build Coastguard Worker fs_type = prop_dict.get("fs_type", "") 285*9e94795aSAndroid Build Coastguard Worker run_fsck = None 286*9e94795aSAndroid Build Coastguard Worker needs_projid = prop_dict.get("needs_projid", 0) 287*9e94795aSAndroid Build Coastguard Worker needs_casefold = prop_dict.get("needs_casefold", 0) 288*9e94795aSAndroid Build Coastguard Worker needs_compress = prop_dict.get("needs_compress", 0) 289*9e94795aSAndroid Build Coastguard Worker 290*9e94795aSAndroid Build Coastguard Worker disable_sparse = "disable_sparse" in prop_dict 291*9e94795aSAndroid Build Coastguard Worker manual_sparse = False 292*9e94795aSAndroid Build Coastguard Worker 293*9e94795aSAndroid Build Coastguard Worker if fs_type.startswith("ext"): 294*9e94795aSAndroid Build Coastguard Worker build_command = [prop_dict["ext_mkuserimg"]] 295*9e94795aSAndroid Build Coastguard Worker if "extfs_sparse_flag" in prop_dict and not disable_sparse: 296*9e94795aSAndroid Build Coastguard Worker build_command.append(prop_dict["extfs_sparse_flag"]) 297*9e94795aSAndroid Build Coastguard Worker run_fsck = RunE2fsck 298*9e94795aSAndroid Build Coastguard Worker build_command.extend([in_dir, out_file, fs_type, 299*9e94795aSAndroid Build Coastguard Worker prop_dict["mount_point"]]) 300*9e94795aSAndroid Build Coastguard Worker build_command.append(prop_dict["image_size"]) 301*9e94795aSAndroid Build Coastguard Worker if "journal_size" in prop_dict: 302*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-j", prop_dict["journal_size"]]) 303*9e94795aSAndroid Build Coastguard Worker if "timestamp" in prop_dict: 304*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-T", str(prop_dict["timestamp"])]) 305*9e94795aSAndroid Build Coastguard Worker if fs_config: 306*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-C", fs_config]) 307*9e94795aSAndroid Build Coastguard Worker if target_out: 308*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-D", target_out]) 309*9e94795aSAndroid Build Coastguard Worker if "block_list" in prop_dict: 310*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-B", prop_dict["block_list"]]) 311*9e94795aSAndroid Build Coastguard Worker if "base_fs_file" in prop_dict: 312*9e94795aSAndroid Build Coastguard Worker base_fs_file = ConvertBlockMapToBaseFs(prop_dict["base_fs_file"]) 313*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-d", base_fs_file]) 314*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-L", prop_dict["mount_point"]]) 315*9e94795aSAndroid Build Coastguard Worker if "extfs_inode_count" in prop_dict: 316*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-i", prop_dict["extfs_inode_count"]]) 317*9e94795aSAndroid Build Coastguard Worker if "extfs_rsv_pct" in prop_dict: 318*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-M", prop_dict["extfs_rsv_pct"]]) 319*9e94795aSAndroid Build Coastguard Worker if "flash_erase_block_size" in prop_dict: 320*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-e", prop_dict["flash_erase_block_size"]]) 321*9e94795aSAndroid Build Coastguard Worker if "flash_logical_block_size" in prop_dict: 322*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-o", prop_dict["flash_logical_block_size"]]) 323*9e94795aSAndroid Build Coastguard Worker # Specify UUID and hash_seed if using mke2fs. 324*9e94795aSAndroid Build Coastguard Worker if os.path.basename(prop_dict["ext_mkuserimg"]) == "mkuserimg_mke2fs": 325*9e94795aSAndroid Build Coastguard Worker if "uuid" in prop_dict: 326*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-U", prop_dict["uuid"]]) 327*9e94795aSAndroid Build Coastguard Worker if "hash_seed" in prop_dict: 328*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-S", prop_dict["hash_seed"]]) 329*9e94795aSAndroid Build Coastguard Worker if prop_dict.get("ext4_share_dup_blocks") == "true": 330*9e94795aSAndroid Build Coastguard Worker build_command.append("-c") 331*9e94795aSAndroid Build Coastguard Worker if (needs_projid): 332*9e94795aSAndroid Build Coastguard Worker build_command.extend(["--inode_size", "512"]) 333*9e94795aSAndroid Build Coastguard Worker else: 334*9e94795aSAndroid Build Coastguard Worker build_command.extend(["--inode_size", "256"]) 335*9e94795aSAndroid Build Coastguard Worker if "selinux_fc" in prop_dict: 336*9e94795aSAndroid Build Coastguard Worker build_command.append(prop_dict["selinux_fc"]) 337*9e94795aSAndroid Build Coastguard Worker elif fs_type.startswith("erofs"): 338*9e94795aSAndroid Build Coastguard Worker build_command = ["mkfs.erofs"] 339*9e94795aSAndroid Build Coastguard Worker 340*9e94795aSAndroid Build Coastguard Worker compressor = None 341*9e94795aSAndroid Build Coastguard Worker if "erofs_default_compressor" in prop_dict: 342*9e94795aSAndroid Build Coastguard Worker compressor = prop_dict["erofs_default_compressor"] 343*9e94795aSAndroid Build Coastguard Worker if "erofs_compressor" in prop_dict: 344*9e94795aSAndroid Build Coastguard Worker compressor = prop_dict["erofs_compressor"] 345*9e94795aSAndroid Build Coastguard Worker if compressor and compressor != "none": 346*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-z", compressor]) 347*9e94795aSAndroid Build Coastguard Worker 348*9e94795aSAndroid Build Coastguard Worker compress_hints = None 349*9e94795aSAndroid Build Coastguard Worker if "erofs_default_compress_hints" in prop_dict: 350*9e94795aSAndroid Build Coastguard Worker compress_hints = prop_dict["erofs_default_compress_hints"] 351*9e94795aSAndroid Build Coastguard Worker if "erofs_compress_hints" in prop_dict: 352*9e94795aSAndroid Build Coastguard Worker compress_hints = prop_dict["erofs_compress_hints"] 353*9e94795aSAndroid Build Coastguard Worker if compress_hints: 354*9e94795aSAndroid Build Coastguard Worker build_command.extend(["--compress-hints", compress_hints]) 355*9e94795aSAndroid Build Coastguard Worker 356*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-b", prop_dict.get("erofs_blocksize", "4096")]) 357*9e94795aSAndroid Build Coastguard Worker 358*9e94795aSAndroid Build Coastguard Worker build_command.extend(["--mount-point", prop_dict["mount_point"]]) 359*9e94795aSAndroid Build Coastguard Worker if target_out: 360*9e94795aSAndroid Build Coastguard Worker build_command.extend(["--product-out", target_out]) 361*9e94795aSAndroid Build Coastguard Worker if fs_config: 362*9e94795aSAndroid Build Coastguard Worker build_command.extend(["--fs-config-file", fs_config]) 363*9e94795aSAndroid Build Coastguard Worker if "selinux_fc" in prop_dict: 364*9e94795aSAndroid Build Coastguard Worker build_command.extend(["--file-contexts", prop_dict["selinux_fc"]]) 365*9e94795aSAndroid Build Coastguard Worker if "timestamp" in prop_dict: 366*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-T", str(prop_dict["timestamp"])]) 367*9e94795aSAndroid Build Coastguard Worker if "uuid" in prop_dict: 368*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-U", prop_dict["uuid"]]) 369*9e94795aSAndroid Build Coastguard Worker if "block_list" in prop_dict: 370*9e94795aSAndroid Build Coastguard Worker build_command.extend(["--block-list-file", prop_dict["block_list"]]) 371*9e94795aSAndroid Build Coastguard Worker if "erofs_pcluster_size" in prop_dict: 372*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-C", prop_dict["erofs_pcluster_size"]]) 373*9e94795aSAndroid Build Coastguard Worker if "erofs_share_dup_blocks" in prop_dict: 374*9e94795aSAndroid Build Coastguard Worker build_command.extend(["--chunksize", "4096"]) 375*9e94795aSAndroid Build Coastguard Worker if "erofs_use_legacy_compression" in prop_dict: 376*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-E", "legacy-compress"]) 377*9e94795aSAndroid Build Coastguard Worker 378*9e94795aSAndroid Build Coastguard Worker build_command.extend([out_file, in_dir]) 379*9e94795aSAndroid Build Coastguard Worker if "erofs_sparse_flag" in prop_dict and not disable_sparse: 380*9e94795aSAndroid Build Coastguard Worker manual_sparse = True 381*9e94795aSAndroid Build Coastguard Worker 382*9e94795aSAndroid Build Coastguard Worker run_fsck = RunErofsFsck 383*9e94795aSAndroid Build Coastguard Worker elif fs_type.startswith("squash"): 384*9e94795aSAndroid Build Coastguard Worker build_command = ["mksquashfsimage"] 385*9e94795aSAndroid Build Coastguard Worker build_command.extend([in_dir, out_file]) 386*9e94795aSAndroid Build Coastguard Worker if "squashfs_sparse_flag" in prop_dict and not disable_sparse: 387*9e94795aSAndroid Build Coastguard Worker build_command.extend([prop_dict["squashfs_sparse_flag"]]) 388*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-m", prop_dict["mount_point"]]) 389*9e94795aSAndroid Build Coastguard Worker if target_out: 390*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-d", target_out]) 391*9e94795aSAndroid Build Coastguard Worker if fs_config: 392*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-C", fs_config]) 393*9e94795aSAndroid Build Coastguard Worker if "selinux_fc" in prop_dict: 394*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-c", prop_dict["selinux_fc"]]) 395*9e94795aSAndroid Build Coastguard Worker if "block_list" in prop_dict: 396*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-B", prop_dict["block_list"]]) 397*9e94795aSAndroid Build Coastguard Worker if "squashfs_block_size" in prop_dict: 398*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-b", prop_dict["squashfs_block_size"]]) 399*9e94795aSAndroid Build Coastguard Worker if "squashfs_compressor" in prop_dict: 400*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-z", prop_dict["squashfs_compressor"]]) 401*9e94795aSAndroid Build Coastguard Worker if "squashfs_compressor_opt" in prop_dict: 402*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-zo", prop_dict["squashfs_compressor_opt"]]) 403*9e94795aSAndroid Build Coastguard Worker if prop_dict.get("squashfs_disable_4k_align") == "true": 404*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-a"]) 405*9e94795aSAndroid Build Coastguard Worker elif fs_type.startswith("f2fs"): 406*9e94795aSAndroid Build Coastguard Worker build_command = ["mkf2fsuserimg"] 407*9e94795aSAndroid Build Coastguard Worker build_command.extend([out_file, prop_dict["image_size"]]) 408*9e94795aSAndroid Build Coastguard Worker if "f2fs_sparse_flag" in prop_dict and not disable_sparse: 409*9e94795aSAndroid Build Coastguard Worker build_command.extend([prop_dict["f2fs_sparse_flag"]]) 410*9e94795aSAndroid Build Coastguard Worker if fs_config: 411*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-C", fs_config]) 412*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-f", in_dir]) 413*9e94795aSAndroid Build Coastguard Worker if target_out: 414*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-D", target_out]) 415*9e94795aSAndroid Build Coastguard Worker if "selinux_fc" in prop_dict: 416*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-s", prop_dict["selinux_fc"]]) 417*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-t", prop_dict["mount_point"]]) 418*9e94795aSAndroid Build Coastguard Worker if "timestamp" in prop_dict: 419*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-T", str(prop_dict["timestamp"])]) 420*9e94795aSAndroid Build Coastguard Worker if "block_list" in prop_dict: 421*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-B", prop_dict["block_list"]]) 422*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-L", prop_dict["mount_point"]]) 423*9e94795aSAndroid Build Coastguard Worker if (needs_projid): 424*9e94795aSAndroid Build Coastguard Worker build_command.append("--prjquota") 425*9e94795aSAndroid Build Coastguard Worker if (needs_casefold): 426*9e94795aSAndroid Build Coastguard Worker build_command.append("--casefold") 427*9e94795aSAndroid Build Coastguard Worker if (needs_compress or prop_dict.get("f2fs_compress") == "true"): 428*9e94795aSAndroid Build Coastguard Worker build_command.append("--compression") 429*9e94795aSAndroid Build Coastguard Worker if "ro_mount_point" in prop_dict: 430*9e94795aSAndroid Build Coastguard Worker build_command.append("--readonly") 431*9e94795aSAndroid Build Coastguard Worker if (prop_dict.get("f2fs_compress") == "true"): 432*9e94795aSAndroid Build Coastguard Worker build_command.append("--sldc") 433*9e94795aSAndroid Build Coastguard Worker if (prop_dict.get("f2fs_sldc_flags") == None): 434*9e94795aSAndroid Build Coastguard Worker build_command.append(str(0)) 435*9e94795aSAndroid Build Coastguard Worker else: 436*9e94795aSAndroid Build Coastguard Worker sldc_flags_str = prop_dict.get("f2fs_sldc_flags") 437*9e94795aSAndroid Build Coastguard Worker sldc_flags = sldc_flags_str.split() 438*9e94795aSAndroid Build Coastguard Worker build_command.append(str(len(sldc_flags))) 439*9e94795aSAndroid Build Coastguard Worker build_command.extend(sldc_flags) 440*9e94795aSAndroid Build Coastguard Worker f2fs_blocksize = prop_dict.get("f2fs_blocksize", "4096") 441*9e94795aSAndroid Build Coastguard Worker build_command.extend(["-b", f2fs_blocksize]) 442*9e94795aSAndroid Build Coastguard Worker else: 443*9e94795aSAndroid Build Coastguard Worker raise BuildImageError( 444*9e94795aSAndroid Build Coastguard Worker "Error: unknown filesystem type: {}".format(fs_type)) 445*9e94795aSAndroid Build Coastguard Worker 446*9e94795aSAndroid Build Coastguard Worker try: 447*9e94795aSAndroid Build Coastguard Worker mkfs_output = common.RunAndCheckOutput(build_command) 448*9e94795aSAndroid Build Coastguard Worker except: 449*9e94795aSAndroid Build Coastguard Worker try: 450*9e94795aSAndroid Build Coastguard Worker du = GetDiskUsage(in_dir) 451*9e94795aSAndroid Build Coastguard Worker du_str = "{} bytes ({} MB)".format(du, du // BYTES_IN_MB) 452*9e94795aSAndroid Build Coastguard Worker # Suppress any errors from GetDiskUsage() to avoid hiding the real errors 453*9e94795aSAndroid Build Coastguard Worker # from common.RunAndCheckOutput(). 454*9e94795aSAndroid Build Coastguard Worker except Exception: # pylint: disable=broad-except 455*9e94795aSAndroid Build Coastguard Worker logger.exception("Failed to compute disk usage with du") 456*9e94795aSAndroid Build Coastguard Worker du_str = "unknown" 457*9e94795aSAndroid Build Coastguard Worker print( 458*9e94795aSAndroid Build Coastguard Worker "Out of space? Out of inodes? The tree size of {} is {}, " 459*9e94795aSAndroid Build Coastguard Worker "with reserved space of {} bytes ({} MB).".format( 460*9e94795aSAndroid Build Coastguard Worker in_dir, du_str, 461*9e94795aSAndroid Build Coastguard Worker int(prop_dict.get("partition_reserved_size", 0)), 462*9e94795aSAndroid Build Coastguard Worker int(prop_dict.get("partition_reserved_size", 0)) // BYTES_IN_MB)) 463*9e94795aSAndroid Build Coastguard Worker if ("image_size" in prop_dict and "partition_size" in prop_dict): 464*9e94795aSAndroid Build Coastguard Worker print( 465*9e94795aSAndroid Build Coastguard Worker "The max image size for filesystem files is {} bytes ({} MB), " 466*9e94795aSAndroid Build Coastguard Worker "out of a total partition size of {} bytes ({} MB).".format( 467*9e94795aSAndroid Build Coastguard Worker int(prop_dict["image_size"]), 468*9e94795aSAndroid Build Coastguard Worker int(prop_dict["image_size"]) // BYTES_IN_MB, 469*9e94795aSAndroid Build Coastguard Worker int(prop_dict["partition_size"]), 470*9e94795aSAndroid Build Coastguard Worker int(prop_dict["partition_size"]) // BYTES_IN_MB)) 471*9e94795aSAndroid Build Coastguard Worker raise 472*9e94795aSAndroid Build Coastguard Worker 473*9e94795aSAndroid Build Coastguard Worker if run_fsck and prop_dict.get("skip_fsck") != "true": 474*9e94795aSAndroid Build Coastguard Worker run_fsck(out_file) 475*9e94795aSAndroid Build Coastguard Worker 476*9e94795aSAndroid Build Coastguard Worker if manual_sparse: 477*9e94795aSAndroid Build Coastguard Worker temp_file = out_file + ".sparse" 478*9e94795aSAndroid Build Coastguard Worker img2simg_argv = ["img2simg", out_file, temp_file] 479*9e94795aSAndroid Build Coastguard Worker common.RunAndCheckOutput(img2simg_argv) 480*9e94795aSAndroid Build Coastguard Worker os.rename(temp_file, out_file) 481*9e94795aSAndroid Build Coastguard Worker 482*9e94795aSAndroid Build Coastguard Worker return mkfs_output 483*9e94795aSAndroid Build Coastguard Worker 484*9e94795aSAndroid Build Coastguard Worker 485*9e94795aSAndroid Build Coastguard Workerdef RunE2fsck(out_file): 486*9e94795aSAndroid Build Coastguard Worker unsparse_image = UnsparseImage(out_file, replace=False) 487*9e94795aSAndroid Build Coastguard Worker 488*9e94795aSAndroid Build Coastguard Worker # Run e2fsck on the inflated image file 489*9e94795aSAndroid Build Coastguard Worker e2fsck_command = ["e2fsck", "-f", "-n", unsparse_image] 490*9e94795aSAndroid Build Coastguard Worker try: 491*9e94795aSAndroid Build Coastguard Worker common.RunAndCheckOutput(e2fsck_command) 492*9e94795aSAndroid Build Coastguard Worker finally: 493*9e94795aSAndroid Build Coastguard Worker os.remove(unsparse_image) 494*9e94795aSAndroid Build Coastguard Worker 495*9e94795aSAndroid Build Coastguard Worker 496*9e94795aSAndroid Build Coastguard Workerdef RunErofsFsck(out_file): 497*9e94795aSAndroid Build Coastguard Worker fsck_command = ["fsck.erofs", "--extract", out_file] 498*9e94795aSAndroid Build Coastguard Worker try: 499*9e94795aSAndroid Build Coastguard Worker common.RunAndCheckOutput(fsck_command) 500*9e94795aSAndroid Build Coastguard Worker except: 501*9e94795aSAndroid Build Coastguard Worker print("Check failed for EROFS image {}".format(out_file)) 502*9e94795aSAndroid Build Coastguard Worker raise 503*9e94795aSAndroid Build Coastguard Worker 504*9e94795aSAndroid Build Coastguard Worker 505*9e94795aSAndroid Build Coastguard Workerdef SetUUIDIfNotExist(image_props): 506*9e94795aSAndroid Build Coastguard Worker 507*9e94795aSAndroid Build Coastguard Worker # Use repeatable ext4 FS UUID and hash_seed UUID (based on partition name and 508*9e94795aSAndroid Build Coastguard Worker # build fingerprint). Also use the legacy build id, because the vbmeta digest 509*9e94795aSAndroid Build Coastguard Worker # isn't available at this point. 510*9e94795aSAndroid Build Coastguard Worker what = image_props["mount_point"] 511*9e94795aSAndroid Build Coastguard Worker fingerprint = image_props.get("fingerprint", "") 512*9e94795aSAndroid Build Coastguard Worker uuid_seed = what + "-" + fingerprint 513*9e94795aSAndroid Build Coastguard Worker logger.info("Using fingerprint %s for partition %s", fingerprint, what) 514*9e94795aSAndroid Build Coastguard Worker image_props["uuid"] = str(uuid.uuid5(uuid.NAMESPACE_URL, uuid_seed)) 515*9e94795aSAndroid Build Coastguard Worker hash_seed = "hash_seed-" + uuid_seed 516*9e94795aSAndroid Build Coastguard Worker image_props["hash_seed"] = str(uuid.uuid5(uuid.NAMESPACE_URL, hash_seed)) 517*9e94795aSAndroid Build Coastguard Worker 518*9e94795aSAndroid Build Coastguard Worker 519*9e94795aSAndroid Build Coastguard Workerdef BuildImage(in_dir, prop_dict, out_file, target_out=None): 520*9e94795aSAndroid Build Coastguard Worker """Builds an image for the files under in_dir and writes it to out_file. 521*9e94795aSAndroid Build Coastguard Worker 522*9e94795aSAndroid Build Coastguard Worker Args: 523*9e94795aSAndroid Build Coastguard Worker in_dir: Path to input directory. 524*9e94795aSAndroid Build Coastguard Worker prop_dict: A property dict that contains info like partition size. Values 525*9e94795aSAndroid Build Coastguard Worker will be updated with computed values. 526*9e94795aSAndroid Build Coastguard Worker out_file: The output image file. 527*9e94795aSAndroid Build Coastguard Worker target_out: Path to the TARGET_OUT directory as in Makefile. It actually 528*9e94795aSAndroid Build Coastguard Worker points to the /system directory under PRODUCT_OUT. fs_config (the one 529*9e94795aSAndroid Build Coastguard Worker under system/core/libcutils) reads device specific FS config files from 530*9e94795aSAndroid Build Coastguard Worker there. 531*9e94795aSAndroid Build Coastguard Worker 532*9e94795aSAndroid Build Coastguard Worker Raises: 533*9e94795aSAndroid Build Coastguard Worker BuildImageError: On build image failures. 534*9e94795aSAndroid Build Coastguard Worker """ 535*9e94795aSAndroid Build Coastguard Worker in_dir, fs_config = SetUpInDirAndFsConfig(in_dir, prop_dict) 536*9e94795aSAndroid Build Coastguard Worker SetUUIDIfNotExist(prop_dict) 537*9e94795aSAndroid Build Coastguard Worker 538*9e94795aSAndroid Build Coastguard Worker build_command = [] 539*9e94795aSAndroid Build Coastguard Worker fs_type = prop_dict.get("fs_type", "") 540*9e94795aSAndroid Build Coastguard Worker 541*9e94795aSAndroid Build Coastguard Worker fs_spans_partition = True 542*9e94795aSAndroid Build Coastguard Worker if fs_type.startswith("squash") or fs_type.startswith("erofs"): 543*9e94795aSAndroid Build Coastguard Worker fs_spans_partition = False 544*9e94795aSAndroid Build Coastguard Worker elif fs_type.startswith("f2fs") and prop_dict.get("f2fs_compress") == "true": 545*9e94795aSAndroid Build Coastguard Worker fs_spans_partition = False 546*9e94795aSAndroid Build Coastguard Worker 547*9e94795aSAndroid Build Coastguard Worker # Get a builder for creating an image that's to be verified by Verified Boot, 548*9e94795aSAndroid Build Coastguard Worker # or None if not applicable. 549*9e94795aSAndroid Build Coastguard Worker verity_image_builder = verity_utils.CreateVerityImageBuilder(prop_dict) 550*9e94795aSAndroid Build Coastguard Worker 551*9e94795aSAndroid Build Coastguard Worker disable_sparse = "disable_sparse" in prop_dict 552*9e94795aSAndroid Build Coastguard Worker mkfs_output = None 553*9e94795aSAndroid Build Coastguard Worker if (prop_dict.get("use_dynamic_partition_size") == "true" and 554*9e94795aSAndroid Build Coastguard Worker "partition_size" not in prop_dict): 555*9e94795aSAndroid Build Coastguard Worker # If partition_size is not defined, use output of `du' + reserved_size. 556*9e94795aSAndroid Build Coastguard Worker # For compressed file system, it's better to use the compressed size to avoid wasting space. 557*9e94795aSAndroid Build Coastguard Worker if fs_type.startswith("erofs"): 558*9e94795aSAndroid Build Coastguard Worker mkfs_output = BuildImageMkfs( 559*9e94795aSAndroid Build Coastguard Worker in_dir, prop_dict, out_file, target_out, fs_config) 560*9e94795aSAndroid Build Coastguard Worker if "erofs_sparse_flag" in prop_dict and not disable_sparse: 561*9e94795aSAndroid Build Coastguard Worker image_path = UnsparseImage(out_file, replace=False) 562*9e94795aSAndroid Build Coastguard Worker size = GetDiskUsage(image_path) 563*9e94795aSAndroid Build Coastguard Worker os.remove(image_path) 564*9e94795aSAndroid Build Coastguard Worker else: 565*9e94795aSAndroid Build Coastguard Worker size = GetDiskUsage(out_file) 566*9e94795aSAndroid Build Coastguard Worker else: 567*9e94795aSAndroid Build Coastguard Worker size = GetDiskUsage(in_dir) 568*9e94795aSAndroid Build Coastguard Worker logger.info( 569*9e94795aSAndroid Build Coastguard Worker "The tree size of %s is %d MB.", in_dir, size // BYTES_IN_MB) 570*9e94795aSAndroid Build Coastguard Worker size = CalculateSizeAndReserved(prop_dict, size) 571*9e94795aSAndroid Build Coastguard Worker # Round this up to a multiple of 4K so that avbtool works 572*9e94795aSAndroid Build Coastguard Worker size = common.RoundUpTo4K(size) 573*9e94795aSAndroid Build Coastguard Worker if fs_type.startswith("ext"): 574*9e94795aSAndroid Build Coastguard Worker prop_dict["partition_size"] = str(size) 575*9e94795aSAndroid Build Coastguard Worker prop_dict["image_size"] = str(size) 576*9e94795aSAndroid Build Coastguard Worker if "extfs_inode_count" not in prop_dict: 577*9e94795aSAndroid Build Coastguard Worker prop_dict["extfs_inode_count"] = str(GetInodeUsage(in_dir)) 578*9e94795aSAndroid Build Coastguard Worker logger.info( 579*9e94795aSAndroid Build Coastguard Worker "First Pass based on estimates of %d MB and %s inodes.", 580*9e94795aSAndroid Build Coastguard Worker size // BYTES_IN_MB, prop_dict["extfs_inode_count"]) 581*9e94795aSAndroid Build Coastguard Worker BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config) 582*9e94795aSAndroid Build Coastguard Worker sparse_image = False 583*9e94795aSAndroid Build Coastguard Worker if "extfs_sparse_flag" in prop_dict and not disable_sparse: 584*9e94795aSAndroid Build Coastguard Worker sparse_image = True 585*9e94795aSAndroid Build Coastguard Worker fs_dict = GetFilesystemCharacteristics(fs_type, out_file, sparse_image) 586*9e94795aSAndroid Build Coastguard Worker os.remove(out_file) 587*9e94795aSAndroid Build Coastguard Worker block_size = int(fs_dict.get("Block size", "4096")) 588*9e94795aSAndroid Build Coastguard Worker free_size = int(fs_dict.get("Free blocks", "0")) * block_size 589*9e94795aSAndroid Build Coastguard Worker reserved_size = int(prop_dict.get("partition_reserved_size", 0)) 590*9e94795aSAndroid Build Coastguard Worker partition_headroom = int(fs_dict.get("partition_headroom", 0)) 591*9e94795aSAndroid Build Coastguard Worker if fs_type.startswith("ext4") and partition_headroom > reserved_size: 592*9e94795aSAndroid Build Coastguard Worker reserved_size = partition_headroom 593*9e94795aSAndroid Build Coastguard Worker if free_size <= reserved_size: 594*9e94795aSAndroid Build Coastguard Worker logger.info( 595*9e94795aSAndroid Build Coastguard Worker "Not worth reducing image %d <= %d.", free_size, reserved_size) 596*9e94795aSAndroid Build Coastguard Worker else: 597*9e94795aSAndroid Build Coastguard Worker size -= free_size 598*9e94795aSAndroid Build Coastguard Worker size += reserved_size 599*9e94795aSAndroid Build Coastguard Worker if reserved_size == 0: 600*9e94795aSAndroid Build Coastguard Worker # add .3% margin 601*9e94795aSAndroid Build Coastguard Worker size = size * 1003 // 1000 602*9e94795aSAndroid Build Coastguard Worker # Use a minimum size, otherwise we will fail to calculate an AVB footer 603*9e94795aSAndroid Build Coastguard Worker # or fail to construct an ext4 image. 604*9e94795aSAndroid Build Coastguard Worker size = max(size, 256 * 1024) 605*9e94795aSAndroid Build Coastguard Worker if block_size <= 4096: 606*9e94795aSAndroid Build Coastguard Worker size = common.RoundUpTo4K(size) 607*9e94795aSAndroid Build Coastguard Worker else: 608*9e94795aSAndroid Build Coastguard Worker size = ((size + block_size - 1) // block_size) * block_size 609*9e94795aSAndroid Build Coastguard Worker extfs_inode_count = prop_dict["extfs_inode_count"] 610*9e94795aSAndroid Build Coastguard Worker inodes = int(fs_dict.get("Inode count", extfs_inode_count)) 611*9e94795aSAndroid Build Coastguard Worker inodes -= int(fs_dict.get("Free inodes", "0")) 612*9e94795aSAndroid Build Coastguard Worker # add .2% margin or 1 inode, whichever is greater 613*9e94795aSAndroid Build Coastguard Worker spare_inodes = inodes * 2 // 1000 614*9e94795aSAndroid Build Coastguard Worker min_spare_inodes = 1 615*9e94795aSAndroid Build Coastguard Worker if spare_inodes < min_spare_inodes: 616*9e94795aSAndroid Build Coastguard Worker spare_inodes = min_spare_inodes 617*9e94795aSAndroid Build Coastguard Worker inodes += spare_inodes 618*9e94795aSAndroid Build Coastguard Worker prop_dict["extfs_inode_count"] = str(inodes) 619*9e94795aSAndroid Build Coastguard Worker prop_dict["partition_size"] = str(size) 620*9e94795aSAndroid Build Coastguard Worker logger.info( 621*9e94795aSAndroid Build Coastguard Worker "Allocating %d Inodes for %s.", inodes, out_file) 622*9e94795aSAndroid Build Coastguard Worker elif fs_type.startswith("f2fs") and prop_dict.get("f2fs_compress") == "true": 623*9e94795aSAndroid Build Coastguard Worker prop_dict["partition_size"] = str(size) 624*9e94795aSAndroid Build Coastguard Worker prop_dict["image_size"] = str(size) 625*9e94795aSAndroid Build Coastguard Worker BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config) 626*9e94795aSAndroid Build Coastguard Worker sparse_image = False 627*9e94795aSAndroid Build Coastguard Worker if "f2fs_sparse_flag" in prop_dict and not disable_sparse: 628*9e94795aSAndroid Build Coastguard Worker sparse_image = True 629*9e94795aSAndroid Build Coastguard Worker fs_dict = GetFilesystemCharacteristics(fs_type, out_file, sparse_image) 630*9e94795aSAndroid Build Coastguard Worker os.remove(out_file) 631*9e94795aSAndroid Build Coastguard Worker block_count = int(fs_dict.get("block_count", "0")) 632*9e94795aSAndroid Build Coastguard Worker log_blocksize = int(fs_dict.get("log_blocksize", "12")) 633*9e94795aSAndroid Build Coastguard Worker size = block_count << log_blocksize 634*9e94795aSAndroid Build Coastguard Worker prop_dict["partition_size"] = str(size) 635*9e94795aSAndroid Build Coastguard Worker if verity_image_builder: 636*9e94795aSAndroid Build Coastguard Worker size = verity_image_builder.CalculateDynamicPartitionSize(size) 637*9e94795aSAndroid Build Coastguard Worker prop_dict["partition_size"] = str(size) 638*9e94795aSAndroid Build Coastguard Worker logger.info( 639*9e94795aSAndroid Build Coastguard Worker "Allocating %d MB for %s", size // BYTES_IN_MB, out_file) 640*9e94795aSAndroid Build Coastguard Worker 641*9e94795aSAndroid Build Coastguard Worker prop_dict["image_size"] = prop_dict["partition_size"] 642*9e94795aSAndroid Build Coastguard Worker 643*9e94795aSAndroid Build Coastguard Worker # Adjust the image size to make room for the hashes if this is to be verified. 644*9e94795aSAndroid Build Coastguard Worker if verity_image_builder: 645*9e94795aSAndroid Build Coastguard Worker max_image_size = verity_image_builder.CalculateMaxImageSize() 646*9e94795aSAndroid Build Coastguard Worker prop_dict["image_size"] = str(max_image_size) 647*9e94795aSAndroid Build Coastguard Worker 648*9e94795aSAndroid Build Coastguard Worker if not mkfs_output: 649*9e94795aSAndroid Build Coastguard Worker mkfs_output = BuildImageMkfs( 650*9e94795aSAndroid Build Coastguard Worker in_dir, prop_dict, out_file, target_out, fs_config) 651*9e94795aSAndroid Build Coastguard Worker 652*9e94795aSAndroid Build Coastguard Worker # Update the image (eg filesystem size). This can be different eg if mkfs 653*9e94795aSAndroid Build Coastguard Worker # rounds the requested size down due to alignment. 654*9e94795aSAndroid Build Coastguard Worker prop_dict["image_size"] = common.sparse_img.GetImagePartitionSize(out_file) 655*9e94795aSAndroid Build Coastguard Worker 656*9e94795aSAndroid Build Coastguard Worker # Check if there's enough headroom space available for ext4 image. 657*9e94795aSAndroid Build Coastguard Worker if "partition_headroom" in prop_dict and fs_type.startswith("ext4"): 658*9e94795aSAndroid Build Coastguard Worker CheckHeadroom(mkfs_output, prop_dict) 659*9e94795aSAndroid Build Coastguard Worker 660*9e94795aSAndroid Build Coastguard Worker if not fs_spans_partition and verity_image_builder: 661*9e94795aSAndroid Build Coastguard Worker verity_image_builder.PadSparseImage(out_file) 662*9e94795aSAndroid Build Coastguard Worker 663*9e94795aSAndroid Build Coastguard Worker # Create the verified image if this is to be verified. 664*9e94795aSAndroid Build Coastguard Worker if verity_image_builder: 665*9e94795aSAndroid Build Coastguard Worker verity_image_builder.Build(out_file) 666*9e94795aSAndroid Build Coastguard Worker 667*9e94795aSAndroid Build Coastguard Worker 668*9e94795aSAndroid Build Coastguard Workerdef TryParseFingerprint(glob_dict: dict): 669*9e94795aSAndroid Build Coastguard Worker for (key, val) in glob_dict.items(): 670*9e94795aSAndroid Build Coastguard Worker if not key.endswith("_add_hashtree_footer_args") and not key.endswith("_add_hash_footer_args"): 671*9e94795aSAndroid Build Coastguard Worker continue 672*9e94795aSAndroid Build Coastguard Worker for arg in shlex.split(val): 673*9e94795aSAndroid Build Coastguard Worker m = re.match(r"^com\.android\.build\.\w+\.fingerprint:", arg) 674*9e94795aSAndroid Build Coastguard Worker if m is None: 675*9e94795aSAndroid Build Coastguard Worker continue 676*9e94795aSAndroid Build Coastguard Worker fingerprint = arg[len(m.group()):] 677*9e94795aSAndroid Build Coastguard Worker glob_dict["fingerprint"] = fingerprint 678*9e94795aSAndroid Build Coastguard Worker return 679*9e94795aSAndroid Build Coastguard Worker 680*9e94795aSAndroid Build Coastguard Worker 681*9e94795aSAndroid Build Coastguard Workerdef ImagePropFromGlobalDict(glob_dict, mount_point): 682*9e94795aSAndroid Build Coastguard Worker """Build an image property dictionary from the global dictionary. 683*9e94795aSAndroid Build Coastguard Worker 684*9e94795aSAndroid Build Coastguard Worker Args: 685*9e94795aSAndroid Build Coastguard Worker glob_dict: the global dictionary from the build system. 686*9e94795aSAndroid Build Coastguard Worker mount_point: such as "system", "data" etc. 687*9e94795aSAndroid Build Coastguard Worker """ 688*9e94795aSAndroid Build Coastguard Worker d = {} 689*9e94795aSAndroid Build Coastguard Worker TryParseFingerprint(glob_dict) 690*9e94795aSAndroid Build Coastguard Worker 691*9e94795aSAndroid Build Coastguard Worker # Set fixed timestamp for building the OTA package. 692*9e94795aSAndroid Build Coastguard Worker if "use_fixed_timestamp" in glob_dict: 693*9e94795aSAndroid Build Coastguard Worker d["timestamp"] = FIXED_FILE_TIMESTAMP 694*9e94795aSAndroid Build Coastguard Worker if "build.prop" in glob_dict: 695*9e94795aSAndroid Build Coastguard Worker timestamp = glob_dict["build.prop"].GetProp("ro.build.date.utc") 696*9e94795aSAndroid Build Coastguard Worker if timestamp: 697*9e94795aSAndroid Build Coastguard Worker d["timestamp"] = timestamp 698*9e94795aSAndroid Build Coastguard Worker 699*9e94795aSAndroid Build Coastguard Worker def copy_prop(src_p, dest_p): 700*9e94795aSAndroid Build Coastguard Worker """Copy a property from the global dictionary. 701*9e94795aSAndroid Build Coastguard Worker 702*9e94795aSAndroid Build Coastguard Worker Args: 703*9e94795aSAndroid Build Coastguard Worker src_p: The source property in the global dictionary. 704*9e94795aSAndroid Build Coastguard Worker dest_p: The destination property. 705*9e94795aSAndroid Build Coastguard Worker Returns: 706*9e94795aSAndroid Build Coastguard Worker True if property was found and copied, False otherwise. 707*9e94795aSAndroid Build Coastguard Worker """ 708*9e94795aSAndroid Build Coastguard Worker if src_p in glob_dict: 709*9e94795aSAndroid Build Coastguard Worker d[dest_p] = str(glob_dict[src_p]) 710*9e94795aSAndroid Build Coastguard Worker return True 711*9e94795aSAndroid Build Coastguard Worker return False 712*9e94795aSAndroid Build Coastguard Worker 713*9e94795aSAndroid Build Coastguard Worker common_props = ( 714*9e94795aSAndroid Build Coastguard Worker "extfs_sparse_flag", 715*9e94795aSAndroid Build Coastguard Worker "erofs_default_compressor", 716*9e94795aSAndroid Build Coastguard Worker "erofs_default_compress_hints", 717*9e94795aSAndroid Build Coastguard Worker "erofs_pcluster_size", 718*9e94795aSAndroid Build Coastguard Worker "erofs_blocksize", 719*9e94795aSAndroid Build Coastguard Worker "erofs_share_dup_blocks", 720*9e94795aSAndroid Build Coastguard Worker "erofs_sparse_flag", 721*9e94795aSAndroid Build Coastguard Worker "erofs_use_legacy_compression", 722*9e94795aSAndroid Build Coastguard Worker "squashfs_sparse_flag", 723*9e94795aSAndroid Build Coastguard Worker "system_f2fs_compress", 724*9e94795aSAndroid Build Coastguard Worker "system_f2fs_sldc_flags", 725*9e94795aSAndroid Build Coastguard Worker "f2fs_sparse_flag", 726*9e94795aSAndroid Build Coastguard Worker "f2fs_blocksize", 727*9e94795aSAndroid Build Coastguard Worker "skip_fsck", 728*9e94795aSAndroid Build Coastguard Worker "ext_mkuserimg", 729*9e94795aSAndroid Build Coastguard Worker "avb_enable", 730*9e94795aSAndroid Build Coastguard Worker "avb_avbtool", 731*9e94795aSAndroid Build Coastguard Worker "use_dynamic_partition_size", 732*9e94795aSAndroid Build Coastguard Worker "fingerprint", 733*9e94795aSAndroid Build Coastguard Worker ) 734*9e94795aSAndroid Build Coastguard Worker for p in common_props: 735*9e94795aSAndroid Build Coastguard Worker copy_prop(p, p) 736*9e94795aSAndroid Build Coastguard Worker 737*9e94795aSAndroid Build Coastguard Worker ro_mount_points = set([ 738*9e94795aSAndroid Build Coastguard Worker "odm", 739*9e94795aSAndroid Build Coastguard Worker "odm_dlkm", 740*9e94795aSAndroid Build Coastguard Worker "oem", 741*9e94795aSAndroid Build Coastguard Worker "product", 742*9e94795aSAndroid Build Coastguard Worker "system", 743*9e94795aSAndroid Build Coastguard Worker "system_dlkm", 744*9e94795aSAndroid Build Coastguard Worker "system_ext", 745*9e94795aSAndroid Build Coastguard Worker "system_other", 746*9e94795aSAndroid Build Coastguard Worker "vendor", 747*9e94795aSAndroid Build Coastguard Worker "vendor_dlkm", 748*9e94795aSAndroid Build Coastguard Worker ]) 749*9e94795aSAndroid Build Coastguard Worker 750*9e94795aSAndroid Build Coastguard Worker # Tuple layout: (readonly, specific prop, general prop) 751*9e94795aSAndroid Build Coastguard Worker fmt_props = ( 752*9e94795aSAndroid Build Coastguard Worker # Generic first, then specific file type. 753*9e94795aSAndroid Build Coastguard Worker (False, "fs_type", "fs_type"), 754*9e94795aSAndroid Build Coastguard Worker (False, "{}_fs_type", "fs_type"), 755*9e94795aSAndroid Build Coastguard Worker 756*9e94795aSAndroid Build Coastguard Worker # Ordering for these doesn't matter. 757*9e94795aSAndroid Build Coastguard Worker (False, "{}_selinux_fc", "selinux_fc"), 758*9e94795aSAndroid Build Coastguard Worker (False, "{}_size", "partition_size"), 759*9e94795aSAndroid Build Coastguard Worker (True, "avb_{}_add_hashtree_footer_args", "avb_add_hashtree_footer_args"), 760*9e94795aSAndroid Build Coastguard Worker (True, "avb_{}_algorithm", "avb_algorithm"), 761*9e94795aSAndroid Build Coastguard Worker (True, "avb_{}_hashtree_enable", "avb_hashtree_enable"), 762*9e94795aSAndroid Build Coastguard Worker (True, "avb_{}_key_path", "avb_key_path"), 763*9e94795aSAndroid Build Coastguard Worker (True, "avb_{}_salt", "avb_salt"), 764*9e94795aSAndroid Build Coastguard Worker (True, "erofs_use_legacy_compression", "erofs_use_legacy_compression"), 765*9e94795aSAndroid Build Coastguard Worker (True, "ext4_share_dup_blocks", "ext4_share_dup_blocks"), 766*9e94795aSAndroid Build Coastguard Worker (True, "{}_base_fs_file", "base_fs_file"), 767*9e94795aSAndroid Build Coastguard Worker (True, "{}_disable_sparse", "disable_sparse"), 768*9e94795aSAndroid Build Coastguard Worker (True, "{}_erofs_compressor", "erofs_compressor"), 769*9e94795aSAndroid Build Coastguard Worker (True, "{}_erofs_compress_hints", "erofs_compress_hints"), 770*9e94795aSAndroid Build Coastguard Worker (True, "{}_erofs_pcluster_size", "erofs_pcluster_size"), 771*9e94795aSAndroid Build Coastguard Worker (True, "{}_erofs_blocksize", "erofs_blocksize"), 772*9e94795aSAndroid Build Coastguard Worker (True, "{}_erofs_share_dup_blocks", "erofs_share_dup_blocks"), 773*9e94795aSAndroid Build Coastguard Worker (True, "{}_extfs_inode_count", "extfs_inode_count"), 774*9e94795aSAndroid Build Coastguard Worker (True, "{}_f2fs_compress", "f2fs_compress"), 775*9e94795aSAndroid Build Coastguard Worker (True, "{}_f2fs_sldc_flags", "f2fs_sldc_flags"), 776*9e94795aSAndroid Build Coastguard Worker (True, "{}_f2fs_blocksize", "f2fs_block_size"), 777*9e94795aSAndroid Build Coastguard Worker (True, "{}_reserved_size", "partition_reserved_size"), 778*9e94795aSAndroid Build Coastguard Worker (True, "{}_squashfs_block_size", "squashfs_block_size"), 779*9e94795aSAndroid Build Coastguard Worker (True, "{}_squashfs_compressor", "squashfs_compressor"), 780*9e94795aSAndroid Build Coastguard Worker (True, "{}_squashfs_compressor_opt", "squashfs_compressor_opt"), 781*9e94795aSAndroid Build Coastguard Worker (True, "{}_squashfs_disable_4k_align", "squashfs_disable_4k_align"), 782*9e94795aSAndroid Build Coastguard Worker (True, "{}_verity_block_device", "verity_block_device"), 783*9e94795aSAndroid Build Coastguard Worker ) 784*9e94795aSAndroid Build Coastguard Worker 785*9e94795aSAndroid Build Coastguard Worker # Translate prefixed properties into generic ones. 786*9e94795aSAndroid Build Coastguard Worker if mount_point == "data": 787*9e94795aSAndroid Build Coastguard Worker prefix = "userdata" 788*9e94795aSAndroid Build Coastguard Worker else: 789*9e94795aSAndroid Build Coastguard Worker prefix = mount_point 790*9e94795aSAndroid Build Coastguard Worker 791*9e94795aSAndroid Build Coastguard Worker for readonly, src_prop, dest_prop in fmt_props: 792*9e94795aSAndroid Build Coastguard Worker if readonly and mount_point not in ro_mount_points: 793*9e94795aSAndroid Build Coastguard Worker continue 794*9e94795aSAndroid Build Coastguard Worker 795*9e94795aSAndroid Build Coastguard Worker if src_prop == "fs_type": 796*9e94795aSAndroid Build Coastguard Worker # This property is legacy and only used on a few partitions. b/202600377 797*9e94795aSAndroid Build Coastguard Worker allowed_partitions = set(["system", "system_other", "data", "oem"]) 798*9e94795aSAndroid Build Coastguard Worker if mount_point not in allowed_partitions: 799*9e94795aSAndroid Build Coastguard Worker continue 800*9e94795aSAndroid Build Coastguard Worker 801*9e94795aSAndroid Build Coastguard Worker if (mount_point == "system_other") and (dest_prop != "partition_size"): 802*9e94795aSAndroid Build Coastguard Worker # Propagate system properties to system_other. They'll get overridden 803*9e94795aSAndroid Build Coastguard Worker # after as needed. 804*9e94795aSAndroid Build Coastguard Worker copy_prop(src_prop.format("system"), dest_prop) 805*9e94795aSAndroid Build Coastguard Worker 806*9e94795aSAndroid Build Coastguard Worker copy_prop(src_prop.format(prefix), dest_prop) 807*9e94795aSAndroid Build Coastguard Worker 808*9e94795aSAndroid Build Coastguard Worker # Set prefixed properties that need a default value. 809*9e94795aSAndroid Build Coastguard Worker if mount_point in ro_mount_points: 810*9e94795aSAndroid Build Coastguard Worker prop = "{}_journal_size".format(prefix) 811*9e94795aSAndroid Build Coastguard Worker if not copy_prop(prop, "journal_size"): 812*9e94795aSAndroid Build Coastguard Worker d["journal_size"] = "0" 813*9e94795aSAndroid Build Coastguard Worker 814*9e94795aSAndroid Build Coastguard Worker prop = "{}_extfs_rsv_pct".format(prefix) 815*9e94795aSAndroid Build Coastguard Worker if not copy_prop(prop, "extfs_rsv_pct"): 816*9e94795aSAndroid Build Coastguard Worker d["extfs_rsv_pct"] = "0" 817*9e94795aSAndroid Build Coastguard Worker 818*9e94795aSAndroid Build Coastguard Worker d["ro_mount_point"] = "1" 819*9e94795aSAndroid Build Coastguard Worker 820*9e94795aSAndroid Build Coastguard Worker # Copy partition-specific properties. 821*9e94795aSAndroid Build Coastguard Worker d["mount_point"] = mount_point 822*9e94795aSAndroid Build Coastguard Worker if mount_point == "system": 823*9e94795aSAndroid Build Coastguard Worker copy_prop("system_headroom", "partition_headroom") 824*9e94795aSAndroid Build Coastguard Worker copy_prop("root_dir", "root_dir") 825*9e94795aSAndroid Build Coastguard Worker copy_prop("root_fs_config", "root_fs_config") 826*9e94795aSAndroid Build Coastguard Worker elif mount_point == "data": 827*9e94795aSAndroid Build Coastguard Worker # Copy the generic fs type first, override with specific one if available. 828*9e94795aSAndroid Build Coastguard Worker copy_prop("flash_logical_block_size", "flash_logical_block_size") 829*9e94795aSAndroid Build Coastguard Worker copy_prop("flash_erase_block_size", "flash_erase_block_size") 830*9e94795aSAndroid Build Coastguard Worker copy_prop("needs_casefold", "needs_casefold") 831*9e94795aSAndroid Build Coastguard Worker copy_prop("needs_projid", "needs_projid") 832*9e94795aSAndroid Build Coastguard Worker copy_prop("needs_compress", "needs_compress") 833*9e94795aSAndroid Build Coastguard Worker d["partition_name"] = mount_point 834*9e94795aSAndroid Build Coastguard Worker return d 835*9e94795aSAndroid Build Coastguard Worker 836*9e94795aSAndroid Build Coastguard Worker 837*9e94795aSAndroid Build Coastguard Workerdef LoadGlobalDict(filename): 838*9e94795aSAndroid Build Coastguard Worker """Load "name=value" pairs from filename""" 839*9e94795aSAndroid Build Coastguard Worker d = {} 840*9e94795aSAndroid Build Coastguard Worker f = open(filename) 841*9e94795aSAndroid Build Coastguard Worker for line in f: 842*9e94795aSAndroid Build Coastguard Worker line = line.strip() 843*9e94795aSAndroid Build Coastguard Worker if not line or line.startswith("#"): 844*9e94795aSAndroid Build Coastguard Worker continue 845*9e94795aSAndroid Build Coastguard Worker k, v = line.split("=", 1) 846*9e94795aSAndroid Build Coastguard Worker d[k] = v 847*9e94795aSAndroid Build Coastguard Worker f.close() 848*9e94795aSAndroid Build Coastguard Worker return d 849*9e94795aSAndroid Build Coastguard Worker 850*9e94795aSAndroid Build Coastguard Worker 851*9e94795aSAndroid Build Coastguard Workerdef GlobalDictFromImageProp(image_prop, mount_point): 852*9e94795aSAndroid Build Coastguard Worker d = {} 853*9e94795aSAndroid Build Coastguard Worker 854*9e94795aSAndroid Build Coastguard Worker def copy_prop(src_p, dest_p): 855*9e94795aSAndroid Build Coastguard Worker if src_p in image_prop: 856*9e94795aSAndroid Build Coastguard Worker d[dest_p] = image_prop[src_p] 857*9e94795aSAndroid Build Coastguard Worker return True 858*9e94795aSAndroid Build Coastguard Worker return False 859*9e94795aSAndroid Build Coastguard Worker 860*9e94795aSAndroid Build Coastguard Worker if mount_point == "system": 861*9e94795aSAndroid Build Coastguard Worker copy_prop("partition_size", "system_size") 862*9e94795aSAndroid Build Coastguard Worker elif mount_point == "system_other": 863*9e94795aSAndroid Build Coastguard Worker copy_prop("partition_size", "system_other_size") 864*9e94795aSAndroid Build Coastguard Worker elif mount_point == "vendor": 865*9e94795aSAndroid Build Coastguard Worker copy_prop("partition_size", "vendor_size") 866*9e94795aSAndroid Build Coastguard Worker elif mount_point == "odm": 867*9e94795aSAndroid Build Coastguard Worker copy_prop("partition_size", "odm_size") 868*9e94795aSAndroid Build Coastguard Worker elif mount_point == "vendor_dlkm": 869*9e94795aSAndroid Build Coastguard Worker copy_prop("partition_size", "vendor_dlkm_size") 870*9e94795aSAndroid Build Coastguard Worker elif mount_point == "odm_dlkm": 871*9e94795aSAndroid Build Coastguard Worker copy_prop("partition_size", "odm_dlkm_size") 872*9e94795aSAndroid Build Coastguard Worker elif mount_point == "system_dlkm": 873*9e94795aSAndroid Build Coastguard Worker copy_prop("partition_size", "system_dlkm_size") 874*9e94795aSAndroid Build Coastguard Worker elif mount_point == "product": 875*9e94795aSAndroid Build Coastguard Worker copy_prop("partition_size", "product_size") 876*9e94795aSAndroid Build Coastguard Worker elif mount_point == "system_ext": 877*9e94795aSAndroid Build Coastguard Worker copy_prop("partition_size", "system_ext_size") 878*9e94795aSAndroid Build Coastguard Worker return d 879*9e94795aSAndroid Build Coastguard Worker 880*9e94795aSAndroid Build Coastguard Worker 881*9e94795aSAndroid Build Coastguard Workerdef BuildVBMeta(in_dir, glob_dict, output_path): 882*9e94795aSAndroid Build Coastguard Worker """Creates a VBMeta image. 883*9e94795aSAndroid Build Coastguard Worker 884*9e94795aSAndroid Build Coastguard Worker It generates the requested VBMeta image. The requested image could be for 885*9e94795aSAndroid Build Coastguard Worker top-level or chained VBMeta image, which is determined based on the name. 886*9e94795aSAndroid Build Coastguard Worker 887*9e94795aSAndroid Build Coastguard Worker Args: 888*9e94795aSAndroid Build Coastguard Worker output_path: Path to generated vbmeta.img 889*9e94795aSAndroid Build Coastguard Worker partitions: A dict that's keyed by partition names with image paths as 890*9e94795aSAndroid Build Coastguard Worker values. Only valid partition names are accepted, as partitions listed 891*9e94795aSAndroid Build Coastguard Worker in common.AVB_PARTITIONS and custom partitions listed in 892*9e94795aSAndroid Build Coastguard Worker OPTIONS.info_dict.get("avb_custom_images_partition_list") 893*9e94795aSAndroid Build Coastguard Worker name: Name of the VBMeta partition, e.g. 'vbmeta', 'vbmeta_system'. 894*9e94795aSAndroid Build Coastguard Worker needed_partitions: Partitions whose descriptors should be included into the 895*9e94795aSAndroid Build Coastguard Worker generated VBMeta image. 896*9e94795aSAndroid Build Coastguard Worker 897*9e94795aSAndroid Build Coastguard Worker Returns: 898*9e94795aSAndroid Build Coastguard Worker Path to the created image. 899*9e94795aSAndroid Build Coastguard Worker 900*9e94795aSAndroid Build Coastguard Worker Raises: 901*9e94795aSAndroid Build Coastguard Worker AssertionError: On invalid input args. 902*9e94795aSAndroid Build Coastguard Worker """ 903*9e94795aSAndroid Build Coastguard Worker vbmeta_partitions = common.AVB_PARTITIONS[:] 904*9e94795aSAndroid Build Coastguard Worker name = os.path.basename(output_path).rstrip(".img") 905*9e94795aSAndroid Build Coastguard Worker vbmeta_system = glob_dict.get("avb_vbmeta_system", "").strip() 906*9e94795aSAndroid Build Coastguard Worker vbmeta_vendor = glob_dict.get("avb_vbmeta_vendor", "").strip() 907*9e94795aSAndroid Build Coastguard Worker if "vbmeta_system" in name: 908*9e94795aSAndroid Build Coastguard Worker vbmeta_partitions = vbmeta_system.split() 909*9e94795aSAndroid Build Coastguard Worker elif "vbmeta_vendor" in name: 910*9e94795aSAndroid Build Coastguard Worker vbmeta_partitions = vbmeta_vendor.split() 911*9e94795aSAndroid Build Coastguard Worker else: 912*9e94795aSAndroid Build Coastguard Worker if vbmeta_system: 913*9e94795aSAndroid Build Coastguard Worker vbmeta_partitions = [ 914*9e94795aSAndroid Build Coastguard Worker item for item in vbmeta_partitions 915*9e94795aSAndroid Build Coastguard Worker if item not in vbmeta_system.split()] 916*9e94795aSAndroid Build Coastguard Worker vbmeta_partitions.append("vbmeta_system") 917*9e94795aSAndroid Build Coastguard Worker 918*9e94795aSAndroid Build Coastguard Worker if vbmeta_vendor: 919*9e94795aSAndroid Build Coastguard Worker vbmeta_partitions = [ 920*9e94795aSAndroid Build Coastguard Worker item for item in vbmeta_partitions 921*9e94795aSAndroid Build Coastguard Worker if item not in vbmeta_vendor.split()] 922*9e94795aSAndroid Build Coastguard Worker vbmeta_partitions.append("vbmeta_vendor") 923*9e94795aSAndroid Build Coastguard Worker 924*9e94795aSAndroid Build Coastguard Worker partitions = {part: os.path.join(in_dir, part + ".img") 925*9e94795aSAndroid Build Coastguard Worker for part in vbmeta_partitions} 926*9e94795aSAndroid Build Coastguard Worker partitions = {part: path for (part, path) in partitions.items() if os.path.exists(path)} 927*9e94795aSAndroid Build Coastguard Worker common.BuildVBMeta(output_path, partitions, name, vbmeta_partitions) 928*9e94795aSAndroid Build Coastguard Worker 929*9e94795aSAndroid Build Coastguard Worker 930*9e94795aSAndroid Build Coastguard Workerdef BuildImageOrVBMeta(input_directory, target_out, glob_dict, image_properties, out_file): 931*9e94795aSAndroid Build Coastguard Worker try: 932*9e94795aSAndroid Build Coastguard Worker if "vbmeta" in os.path.basename(out_file): 933*9e94795aSAndroid Build Coastguard Worker OPTIONS.info_dict = glob_dict 934*9e94795aSAndroid Build Coastguard Worker BuildVBMeta(input_directory, glob_dict, out_file) 935*9e94795aSAndroid Build Coastguard Worker else: 936*9e94795aSAndroid Build Coastguard Worker BuildImage(input_directory, image_properties, out_file, target_out) 937*9e94795aSAndroid Build Coastguard Worker except: 938*9e94795aSAndroid Build Coastguard Worker logger.error("Failed to build %s from %s", out_file, input_directory) 939*9e94795aSAndroid Build Coastguard Worker raise 940*9e94795aSAndroid Build Coastguard Worker 941*9e94795aSAndroid Build Coastguard Worker 942*9e94795aSAndroid Build Coastguard Workerdef CopyInputDirectory(src, dst, filter_file): 943*9e94795aSAndroid Build Coastguard Worker with open(filter_file, 'r') as f: 944*9e94795aSAndroid Build Coastguard Worker for line in f: 945*9e94795aSAndroid Build Coastguard Worker line = line.strip() 946*9e94795aSAndroid Build Coastguard Worker if not line: 947*9e94795aSAndroid Build Coastguard Worker return 948*9e94795aSAndroid Build Coastguard Worker if line != os.path.normpath(line): 949*9e94795aSAndroid Build Coastguard Worker sys.exit(f"{line}: not normalized") 950*9e94795aSAndroid Build Coastguard Worker if line.startswith("../") or line.startswith('/'): 951*9e94795aSAndroid Build Coastguard Worker sys.exit(f"{line}: escapes staging directory by starting with ../ or /") 952*9e94795aSAndroid Build Coastguard Worker full_src = os.path.join(src, line) 953*9e94795aSAndroid Build Coastguard Worker full_dst = os.path.join(dst, line) 954*9e94795aSAndroid Build Coastguard Worker if os.path.isdir(full_src): 955*9e94795aSAndroid Build Coastguard Worker os.makedirs(full_dst, exist_ok=True) 956*9e94795aSAndroid Build Coastguard Worker else: 957*9e94795aSAndroid Build Coastguard Worker os.makedirs(os.path.dirname(full_dst), exist_ok=True) 958*9e94795aSAndroid Build Coastguard Worker os.link(full_src, full_dst, follow_symlinks=False) 959*9e94795aSAndroid Build Coastguard Worker 960*9e94795aSAndroid Build Coastguard Worker 961*9e94795aSAndroid Build Coastguard Workerdef main(argv): 962*9e94795aSAndroid Build Coastguard Worker parser = argparse.ArgumentParser( 963*9e94795aSAndroid Build Coastguard Worker description="Builds output_image from the given input_directory and properties_file, and " 964*9e94795aSAndroid Build Coastguard Worker "writes the image to target_output_directory.") 965*9e94795aSAndroid Build Coastguard Worker parser.add_argument("--input-directory-filter-file", 966*9e94795aSAndroid Build Coastguard Worker help="the path to a file that contains a list of all files in the input_directory. If this " 967*9e94795aSAndroid Build Coastguard Worker "option is provided, all files under the input_directory that are not listed in this file will " 968*9e94795aSAndroid Build Coastguard Worker "be deleted before building the image. This is to work around the fact that building a module " 969*9e94795aSAndroid Build Coastguard Worker "will install in by default, so there could be files in the input_directory that are not " 970*9e94795aSAndroid Build Coastguard Worker "actually supposed to be part of the partition. The paths in this file must be relative to " 971*9e94795aSAndroid Build Coastguard Worker "input_directory.") 972*9e94795aSAndroid Build Coastguard Worker parser.add_argument("input_directory", 973*9e94795aSAndroid Build Coastguard Worker help="the staging directory to be converted to an image file") 974*9e94795aSAndroid Build Coastguard Worker parser.add_argument("properties_file", 975*9e94795aSAndroid Build Coastguard Worker help="a file containing the 'global dictionary' of properties that affect how the image is " 976*9e94795aSAndroid Build Coastguard Worker "built") 977*9e94795aSAndroid Build Coastguard Worker parser.add_argument("out_file", 978*9e94795aSAndroid Build Coastguard Worker help="the output file to write") 979*9e94795aSAndroid Build Coastguard Worker parser.add_argument("target_out", 980*9e94795aSAndroid Build Coastguard Worker help="the path to $(TARGET_OUT). Certain tools will use this to look through multiple staging " 981*9e94795aSAndroid Build Coastguard Worker "directories for fs config files.") 982*9e94795aSAndroid Build Coastguard Worker parser.add_argument("-v", action="store_true", 983*9e94795aSAndroid Build Coastguard Worker help="Enable verbose logging", dest="verbose") 984*9e94795aSAndroid Build Coastguard Worker args = parser.parse_args() 985*9e94795aSAndroid Build Coastguard Worker if args.verbose: 986*9e94795aSAndroid Build Coastguard Worker OPTIONS.verbose = True 987*9e94795aSAndroid Build Coastguard Worker 988*9e94795aSAndroid Build Coastguard Worker common.InitLogging() 989*9e94795aSAndroid Build Coastguard Worker 990*9e94795aSAndroid Build Coastguard Worker glob_dict = LoadGlobalDict(args.properties_file) 991*9e94795aSAndroid Build Coastguard Worker if "mount_point" in glob_dict: 992*9e94795aSAndroid Build Coastguard Worker # The caller knows the mount point and provides a dictionary needed by 993*9e94795aSAndroid Build Coastguard Worker # BuildImage(). 994*9e94795aSAndroid Build Coastguard Worker image_properties = glob_dict 995*9e94795aSAndroid Build Coastguard Worker else: 996*9e94795aSAndroid Build Coastguard Worker image_filename = os.path.basename(args.out_file) 997*9e94795aSAndroid Build Coastguard Worker mount_point = "" 998*9e94795aSAndroid Build Coastguard Worker if image_filename == "system.img": 999*9e94795aSAndroid Build Coastguard Worker mount_point = "system" 1000*9e94795aSAndroid Build Coastguard Worker elif image_filename == "system_other.img": 1001*9e94795aSAndroid Build Coastguard Worker mount_point = "system_other" 1002*9e94795aSAndroid Build Coastguard Worker elif image_filename == "userdata.img": 1003*9e94795aSAndroid Build Coastguard Worker mount_point = "data" 1004*9e94795aSAndroid Build Coastguard Worker elif image_filename == "cache.img": 1005*9e94795aSAndroid Build Coastguard Worker mount_point = "cache" 1006*9e94795aSAndroid Build Coastguard Worker elif image_filename == "vendor.img": 1007*9e94795aSAndroid Build Coastguard Worker mount_point = "vendor" 1008*9e94795aSAndroid Build Coastguard Worker elif image_filename == "odm.img": 1009*9e94795aSAndroid Build Coastguard Worker mount_point = "odm" 1010*9e94795aSAndroid Build Coastguard Worker elif image_filename == "vendor_dlkm.img": 1011*9e94795aSAndroid Build Coastguard Worker mount_point = "vendor_dlkm" 1012*9e94795aSAndroid Build Coastguard Worker elif image_filename == "odm_dlkm.img": 1013*9e94795aSAndroid Build Coastguard Worker mount_point = "odm_dlkm" 1014*9e94795aSAndroid Build Coastguard Worker elif image_filename == "system_dlkm.img": 1015*9e94795aSAndroid Build Coastguard Worker mount_point = "system_dlkm" 1016*9e94795aSAndroid Build Coastguard Worker elif image_filename == "oem.img": 1017*9e94795aSAndroid Build Coastguard Worker mount_point = "oem" 1018*9e94795aSAndroid Build Coastguard Worker elif image_filename == "product.img": 1019*9e94795aSAndroid Build Coastguard Worker mount_point = "product" 1020*9e94795aSAndroid Build Coastguard Worker elif image_filename == "system_ext.img": 1021*9e94795aSAndroid Build Coastguard Worker mount_point = "system_ext" 1022*9e94795aSAndroid Build Coastguard Worker elif "vbmeta" in image_filename: 1023*9e94795aSAndroid Build Coastguard Worker mount_point = "vbmeta" 1024*9e94795aSAndroid Build Coastguard Worker else: 1025*9e94795aSAndroid Build Coastguard Worker logger.error("Unknown image file name %s", image_filename) 1026*9e94795aSAndroid Build Coastguard Worker sys.exit(1) 1027*9e94795aSAndroid Build Coastguard Worker 1028*9e94795aSAndroid Build Coastguard Worker if "vbmeta" != mount_point: 1029*9e94795aSAndroid Build Coastguard Worker image_properties = ImagePropFromGlobalDict(glob_dict, mount_point) 1030*9e94795aSAndroid Build Coastguard Worker 1031*9e94795aSAndroid Build Coastguard Worker if args.input_directory_filter_file and not os.environ.get("BUILD_BROKEN_INCORRECT_PARTITION_IMAGES"): 1032*9e94795aSAndroid Build Coastguard Worker with tempfile.TemporaryDirectory(dir=os.path.dirname(args.input_directory)) as new_input_directory: 1033*9e94795aSAndroid Build Coastguard Worker CopyInputDirectory(args.input_directory, new_input_directory, args.input_directory_filter_file) 1034*9e94795aSAndroid Build Coastguard Worker BuildImageOrVBMeta(new_input_directory, args.target_out, glob_dict, image_properties, args.out_file) 1035*9e94795aSAndroid Build Coastguard Worker else: 1036*9e94795aSAndroid Build Coastguard Worker BuildImageOrVBMeta(args.input_directory, args.target_out, glob_dict, image_properties, args.out_file) 1037*9e94795aSAndroid Build Coastguard Worker 1038*9e94795aSAndroid Build Coastguard Worker 1039*9e94795aSAndroid Build Coastguard Workerif __name__ == '__main__': 1040*9e94795aSAndroid Build Coastguard Worker try: 1041*9e94795aSAndroid Build Coastguard Worker main(sys.argv[1:]) 1042*9e94795aSAndroid Build Coastguard Worker finally: 1043*9e94795aSAndroid Build Coastguard Worker common.Cleanup() 1044