1*9e94795aSAndroid Build Coastguard Worker#!/usr/bin/env python 2*9e94795aSAndroid Build Coastguard Worker# 3*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2018 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 WorkerUsage: build_super_image input_file output_dir_or_file 19*9e94795aSAndroid Build Coastguard Worker 20*9e94795aSAndroid Build Coastguard Workerinput_file: one of the following: 21*9e94795aSAndroid Build Coastguard Worker - directory containing extracted target files. It will load info from 22*9e94795aSAndroid Build Coastguard Worker META/misc_info.txt and build full super image / split images using source 23*9e94795aSAndroid Build Coastguard Worker images from IMAGES/. 24*9e94795aSAndroid Build Coastguard Worker - target files package. Same as above, but extracts the archive before 25*9e94795aSAndroid Build Coastguard Worker building super image. 26*9e94795aSAndroid Build Coastguard Worker - a dictionary file containing input arguments to build. Check 27*9e94795aSAndroid Build Coastguard Worker `dump-super-image-info' for details. 28*9e94795aSAndroid Build Coastguard Worker In addition: 29*9e94795aSAndroid Build Coastguard Worker - If source images should be included in the output image (for super.img 30*9e94795aSAndroid Build Coastguard Worker and super split images), a list of "*_image" should be paths of each 31*9e94795aSAndroid Build Coastguard Worker source images. 32*9e94795aSAndroid Build Coastguard Worker 33*9e94795aSAndroid Build Coastguard Workeroutput_dir_or_file: 34*9e94795aSAndroid Build Coastguard Worker If a single super image is built (for super_empty.img, or super.img for 35*9e94795aSAndroid Build Coastguard Worker launch devices), this argument is the output file. 36*9e94795aSAndroid Build Coastguard Worker If a collection of split images are built (for retrofit devices), this 37*9e94795aSAndroid Build Coastguard Worker argument is the output directory. 38*9e94795aSAndroid Build Coastguard Worker""" 39*9e94795aSAndroid Build Coastguard Worker 40*9e94795aSAndroid Build Coastguard Workerfrom __future__ import print_function 41*9e94795aSAndroid Build Coastguard Worker 42*9e94795aSAndroid Build Coastguard Workerimport logging 43*9e94795aSAndroid Build Coastguard Workerimport os.path 44*9e94795aSAndroid Build Coastguard Workerimport shlex 45*9e94795aSAndroid Build Coastguard Workerimport sys 46*9e94795aSAndroid Build Coastguard Workerimport zipfile 47*9e94795aSAndroid Build Coastguard Worker 48*9e94795aSAndroid Build Coastguard Workerimport common 49*9e94795aSAndroid Build Coastguard Workerimport sparse_img 50*9e94795aSAndroid Build Coastguard Worker 51*9e94795aSAndroid Build Coastguard Workerif sys.hexversion < 0x02070000: 52*9e94795aSAndroid Build Coastguard Worker print("Python 2.7 or newer is required.", file=sys.stderr) 53*9e94795aSAndroid Build Coastguard Worker sys.exit(1) 54*9e94795aSAndroid Build Coastguard Worker 55*9e94795aSAndroid Build Coastguard Workerlogger = logging.getLogger(__name__) 56*9e94795aSAndroid Build Coastguard Worker 57*9e94795aSAndroid Build Coastguard Worker 58*9e94795aSAndroid Build Coastguard WorkerUNZIP_PATTERN = ["IMAGES/*", "META/*", "*/build.prop"] 59*9e94795aSAndroid Build Coastguard Worker 60*9e94795aSAndroid Build Coastguard Worker 61*9e94795aSAndroid Build Coastguard Workerdef GetArgumentsForImage(partition, group, image=None): 62*9e94795aSAndroid Build Coastguard Worker image_size = sparse_img.GetImagePartitionSize(image) if image else 0 63*9e94795aSAndroid Build Coastguard Worker 64*9e94795aSAndroid Build Coastguard Worker cmd = ["--partition", 65*9e94795aSAndroid Build Coastguard Worker "{}:readonly:{}:{}".format(partition, image_size, group)] 66*9e94795aSAndroid Build Coastguard Worker if image: 67*9e94795aSAndroid Build Coastguard Worker cmd += ["--image", "{}={}".format(partition, image)] 68*9e94795aSAndroid Build Coastguard Worker 69*9e94795aSAndroid Build Coastguard Worker return cmd 70*9e94795aSAndroid Build Coastguard Worker 71*9e94795aSAndroid Build Coastguard Worker 72*9e94795aSAndroid Build Coastguard Workerdef BuildSuperImageFromDict(info_dict, output): 73*9e94795aSAndroid Build Coastguard Worker 74*9e94795aSAndroid Build Coastguard Worker cmd = [info_dict["lpmake"], 75*9e94795aSAndroid Build Coastguard Worker "--metadata-size", "65536", 76*9e94795aSAndroid Build Coastguard Worker "--super-name", info_dict["super_metadata_device"]] 77*9e94795aSAndroid Build Coastguard Worker 78*9e94795aSAndroid Build Coastguard Worker ab_update = info_dict.get("ab_update") == "true" 79*9e94795aSAndroid Build Coastguard Worker virtual_ab = info_dict.get("virtual_ab") == "true" 80*9e94795aSAndroid Build Coastguard Worker virtual_ab_retrofit = info_dict.get("virtual_ab_retrofit") == "true" 81*9e94795aSAndroid Build Coastguard Worker retrofit = info_dict.get("dynamic_partition_retrofit") == "true" 82*9e94795aSAndroid Build Coastguard Worker block_devices = shlex.split(info_dict.get("super_block_devices", "").strip()) 83*9e94795aSAndroid Build Coastguard Worker groups = shlex.split(info_dict.get("super_partition_groups", "").strip()) 84*9e94795aSAndroid Build Coastguard Worker 85*9e94795aSAndroid Build Coastguard Worker if ab_update and retrofit: 86*9e94795aSAndroid Build Coastguard Worker cmd += ["--metadata-slots", "2"] 87*9e94795aSAndroid Build Coastguard Worker elif ab_update: 88*9e94795aSAndroid Build Coastguard Worker cmd += ["--metadata-slots", "3"] 89*9e94795aSAndroid Build Coastguard Worker else: 90*9e94795aSAndroid Build Coastguard Worker cmd += ["--metadata-slots", "2"] 91*9e94795aSAndroid Build Coastguard Worker 92*9e94795aSAndroid Build Coastguard Worker if ab_update and retrofit: 93*9e94795aSAndroid Build Coastguard Worker cmd.append("--auto-slot-suffixing") 94*9e94795aSAndroid Build Coastguard Worker if virtual_ab and not virtual_ab_retrofit: 95*9e94795aSAndroid Build Coastguard Worker cmd.append("--virtual-ab") 96*9e94795aSAndroid Build Coastguard Worker 97*9e94795aSAndroid Build Coastguard Worker for device in block_devices: 98*9e94795aSAndroid Build Coastguard Worker size = info_dict["super_{}_device_size".format(device)] 99*9e94795aSAndroid Build Coastguard Worker cmd += ["--device", "{}:{}".format(device, size)] 100*9e94795aSAndroid Build Coastguard Worker 101*9e94795aSAndroid Build Coastguard Worker append_suffix = ab_update and not retrofit 102*9e94795aSAndroid Build Coastguard Worker has_image = False 103*9e94795aSAndroid Build Coastguard Worker for group in groups: 104*9e94795aSAndroid Build Coastguard Worker group_size = info_dict["super_{}_group_size".format(group)] 105*9e94795aSAndroid Build Coastguard Worker if append_suffix: 106*9e94795aSAndroid Build Coastguard Worker cmd += ["--group", "{}_a:{}".format(group, group_size), 107*9e94795aSAndroid Build Coastguard Worker "--group", "{}_b:{}".format(group, group_size)] 108*9e94795aSAndroid Build Coastguard Worker else: 109*9e94795aSAndroid Build Coastguard Worker cmd += ["--group", "{}:{}".format(group, group_size)] 110*9e94795aSAndroid Build Coastguard Worker 111*9e94795aSAndroid Build Coastguard Worker partition_list = shlex.split( 112*9e94795aSAndroid Build Coastguard Worker info_dict["super_{}_partition_list".format(group)].strip()) 113*9e94795aSAndroid Build Coastguard Worker 114*9e94795aSAndroid Build Coastguard Worker for partition in partition_list: 115*9e94795aSAndroid Build Coastguard Worker image = info_dict.get("{}_image".format(partition)) 116*9e94795aSAndroid Build Coastguard Worker if image: 117*9e94795aSAndroid Build Coastguard Worker has_image = True 118*9e94795aSAndroid Build Coastguard Worker 119*9e94795aSAndroid Build Coastguard Worker if not append_suffix: 120*9e94795aSAndroid Build Coastguard Worker cmd += GetArgumentsForImage(partition, group, image) 121*9e94795aSAndroid Build Coastguard Worker continue 122*9e94795aSAndroid Build Coastguard Worker 123*9e94795aSAndroid Build Coastguard Worker # For A/B devices, super partition always contains sub-partitions in 124*9e94795aSAndroid Build Coastguard Worker # the _a slot, because this image should only be used for 125*9e94795aSAndroid Build Coastguard Worker # bootstrapping / initializing the device. When flashing the image, 126*9e94795aSAndroid Build Coastguard Worker # bootloader fastboot should always mark _a slot as bootable. 127*9e94795aSAndroid Build Coastguard Worker cmd += GetArgumentsForImage(partition + "_a", group + "_a", image) 128*9e94795aSAndroid Build Coastguard Worker 129*9e94795aSAndroid Build Coastguard Worker other_image = None 130*9e94795aSAndroid Build Coastguard Worker if partition == "system" and "system_other_image" in info_dict: 131*9e94795aSAndroid Build Coastguard Worker other_image = info_dict["system_other_image"] 132*9e94795aSAndroid Build Coastguard Worker has_image = True 133*9e94795aSAndroid Build Coastguard Worker 134*9e94795aSAndroid Build Coastguard Worker cmd += GetArgumentsForImage(partition + "_b", group + "_b", other_image) 135*9e94795aSAndroid Build Coastguard Worker 136*9e94795aSAndroid Build Coastguard Worker if info_dict.get("build_non_sparse_super_partition") != "true": 137*9e94795aSAndroid Build Coastguard Worker cmd.append("--sparse") 138*9e94795aSAndroid Build Coastguard Worker 139*9e94795aSAndroid Build Coastguard Worker cmd += ["--output", output] 140*9e94795aSAndroid Build Coastguard Worker 141*9e94795aSAndroid Build Coastguard Worker common.RunAndCheckOutput(cmd) 142*9e94795aSAndroid Build Coastguard Worker 143*9e94795aSAndroid Build Coastguard Worker if retrofit and has_image: 144*9e94795aSAndroid Build Coastguard Worker logger.info("Done writing images to directory %s", output) 145*9e94795aSAndroid Build Coastguard Worker else: 146*9e94795aSAndroid Build Coastguard Worker logger.info("Done writing image %s", output) 147*9e94795aSAndroid Build Coastguard Worker 148*9e94795aSAndroid Build Coastguard Worker return True 149*9e94795aSAndroid Build Coastguard Worker 150*9e94795aSAndroid Build Coastguard Worker 151*9e94795aSAndroid Build Coastguard Workerdef BuildSuperImageFromExtractedTargetFiles(inp, out): 152*9e94795aSAndroid Build Coastguard Worker info_dict = common.LoadInfoDict(inp) 153*9e94795aSAndroid Build Coastguard Worker partition_list = shlex.split( 154*9e94795aSAndroid Build Coastguard Worker info_dict.get("dynamic_partition_list", "").strip()) 155*9e94795aSAndroid Build Coastguard Worker 156*9e94795aSAndroid Build Coastguard Worker if "system" in partition_list: 157*9e94795aSAndroid Build Coastguard Worker image_path = os.path.join(inp, "IMAGES", "system_other.img") 158*9e94795aSAndroid Build Coastguard Worker if os.path.isfile(image_path): 159*9e94795aSAndroid Build Coastguard Worker info_dict["system_other_image"] = image_path 160*9e94795aSAndroid Build Coastguard Worker 161*9e94795aSAndroid Build Coastguard Worker missing_images = [] 162*9e94795aSAndroid Build Coastguard Worker for partition in partition_list: 163*9e94795aSAndroid Build Coastguard Worker image_path = os.path.join(inp, "IMAGES", "{}.img".format(partition)) 164*9e94795aSAndroid Build Coastguard Worker if not os.path.isfile(image_path): 165*9e94795aSAndroid Build Coastguard Worker missing_images.append(image_path) 166*9e94795aSAndroid Build Coastguard Worker else: 167*9e94795aSAndroid Build Coastguard Worker info_dict["{}_image".format(partition)] = image_path 168*9e94795aSAndroid Build Coastguard Worker if missing_images: 169*9e94795aSAndroid Build Coastguard Worker logger.warning("Skip building super image because the following " 170*9e94795aSAndroid Build Coastguard Worker "images are missing from target files:\n%s", 171*9e94795aSAndroid Build Coastguard Worker "\n".join(missing_images)) 172*9e94795aSAndroid Build Coastguard Worker return False 173*9e94795aSAndroid Build Coastguard Worker return BuildSuperImageFromDict(info_dict, out) 174*9e94795aSAndroid Build Coastguard Worker 175*9e94795aSAndroid Build Coastguard Worker 176*9e94795aSAndroid Build Coastguard Workerdef BuildSuperImageFromTargetFiles(inp, out): 177*9e94795aSAndroid Build Coastguard Worker input_tmp = common.UnzipTemp(inp, UNZIP_PATTERN) 178*9e94795aSAndroid Build Coastguard Worker return BuildSuperImageFromExtractedTargetFiles(input_tmp, out) 179*9e94795aSAndroid Build Coastguard Worker 180*9e94795aSAndroid Build Coastguard Worker 181*9e94795aSAndroid Build Coastguard Workerdef BuildSuperImage(inp, out): 182*9e94795aSAndroid Build Coastguard Worker 183*9e94795aSAndroid Build Coastguard Worker if isinstance(inp, dict): 184*9e94795aSAndroid Build Coastguard Worker logger.info("Building super image from info dict...") 185*9e94795aSAndroid Build Coastguard Worker return BuildSuperImageFromDict(inp, out) 186*9e94795aSAndroid Build Coastguard Worker 187*9e94795aSAndroid Build Coastguard Worker if isinstance(inp, str): 188*9e94795aSAndroid Build Coastguard Worker if os.path.isdir(inp): 189*9e94795aSAndroid Build Coastguard Worker logger.info("Building super image from extracted target files...") 190*9e94795aSAndroid Build Coastguard Worker return BuildSuperImageFromExtractedTargetFiles(inp, out) 191*9e94795aSAndroid Build Coastguard Worker 192*9e94795aSAndroid Build Coastguard Worker if zipfile.is_zipfile(inp): 193*9e94795aSAndroid Build Coastguard Worker logger.info("Building super image from target files...") 194*9e94795aSAndroid Build Coastguard Worker return BuildSuperImageFromTargetFiles(inp, out) 195*9e94795aSAndroid Build Coastguard Worker 196*9e94795aSAndroid Build Coastguard Worker if os.path.isfile(inp): 197*9e94795aSAndroid Build Coastguard Worker logger.info("Building super image from info dict...") 198*9e94795aSAndroid Build Coastguard Worker return BuildSuperImageFromDict(common.LoadDictionaryFromFile(inp), out) 199*9e94795aSAndroid Build Coastguard Worker 200*9e94795aSAndroid Build Coastguard Worker raise ValueError("{} is not a dictionary or a valid path".format(inp)) 201*9e94795aSAndroid Build Coastguard Worker 202*9e94795aSAndroid Build Coastguard Worker 203*9e94795aSAndroid Build Coastguard Workerdef main(argv): 204*9e94795aSAndroid Build Coastguard Worker 205*9e94795aSAndroid Build Coastguard Worker args = common.ParseOptions(argv, __doc__) 206*9e94795aSAndroid Build Coastguard Worker 207*9e94795aSAndroid Build Coastguard Worker if len(args) != 2: 208*9e94795aSAndroid Build Coastguard Worker common.Usage(__doc__) 209*9e94795aSAndroid Build Coastguard Worker sys.exit(1) 210*9e94795aSAndroid Build Coastguard Worker 211*9e94795aSAndroid Build Coastguard Worker common.InitLogging() 212*9e94795aSAndroid Build Coastguard Worker 213*9e94795aSAndroid Build Coastguard Worker BuildSuperImage(args[0], args[1]) 214*9e94795aSAndroid Build Coastguard Worker 215*9e94795aSAndroid Build Coastguard Worker 216*9e94795aSAndroid Build Coastguard Workerif __name__ == "__main__": 217*9e94795aSAndroid Build Coastguard Worker try: 218*9e94795aSAndroid Build Coastguard Worker common.CloseInheritedPipes() 219*9e94795aSAndroid Build Coastguard Worker main(sys.argv[1:]) 220*9e94795aSAndroid Build Coastguard Worker except common.ExternalError: 221*9e94795aSAndroid Build Coastguard Worker logger.exception("\n ERROR:\n") 222*9e94795aSAndroid Build Coastguard Worker sys.exit(1) 223*9e94795aSAndroid Build Coastguard Worker finally: 224*9e94795aSAndroid Build Coastguard Worker common.Cleanup() 225