add_img_to_target_files.py revision 0effed4b9484392994a1169f23a7b282cfad91d7
1#!/usr/bin/env python 2# 3# Copyright (C) 2014 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17""" 18Given a target-files zipfile that does not contain images (ie, does 19not have an IMAGES/ top-level subdirectory), produce the images and 20add them to the zipfile. 21 22Usage: add_img_to_target_files [flag] target_files 23 24 -a (--add_missing) 25 Build and add missing images to "IMAGES/". If this option is 26 not specified, this script will simply exit when "IMAGES/" 27 directory exists in the target file. 28 29 -r (--rebuild_recovery) 30 Rebuild the recovery patch and write it to the system image. Only 31 meaningful when system image needs to be rebuilt. 32 33 --replace_verity_private_key 34 Replace the private key used for verity signing. (same as the option 35 in sign_target_files_apks) 36 37 --replace_verity_public_key 38 Replace the certificate (public key) used for verity verification. (same 39 as the option in sign_target_files_apks) 40 41 --is_signing 42 Skip building & adding the images for "userdata" and "cache" if we 43 are signing the target files. 44""" 45 46from __future__ import print_function 47 48import sys 49 50if sys.hexversion < 0x02070000: 51 print("Python 2.7 or newer is required.", file=sys.stderr) 52 sys.exit(1) 53 54import datetime 55import errno 56import os 57import shlex 58import shutil 59import subprocess 60import tempfile 61import zipfile 62 63import build_image 64import common 65import rangelib 66import sparse_img 67 68OPTIONS = common.OPTIONS 69 70OPTIONS.add_missing = False 71OPTIONS.rebuild_recovery = False 72OPTIONS.replace_updated_files_list = [] 73OPTIONS.replace_verity_public_key = False 74OPTIONS.replace_verity_private_key = False 75OPTIONS.is_signing = False 76 77 78class OutputFile(object): 79 def __init__(self, output_zip, input_dir, prefix, name): 80 self._output_zip = output_zip 81 self.input_name = os.path.join(input_dir, prefix, name) 82 83 if self._output_zip: 84 self._zip_name = os.path.join(prefix, name) 85 86 root, suffix = os.path.splitext(name) 87 self.name = common.MakeTempFile(prefix=root + '-', suffix=suffix) 88 else: 89 self.name = self.input_name 90 91 def Write(self): 92 if self._output_zip: 93 common.ZipWrite(self._output_zip, self.name, self._zip_name) 94 95 96def GetCareMap(which, imgname): 97 """Generate care_map of system (or vendor) partition""" 98 99 assert which in ("system", "vendor") 100 101 simg = sparse_img.SparseImage(imgname) 102 care_map_list = [which] 103 104 care_map_ranges = simg.care_map 105 key = which + "_adjusted_partition_size" 106 adjusted_blocks = OPTIONS.info_dict.get(key) 107 if adjusted_blocks: 108 assert adjusted_blocks > 0, "blocks should be positive for " + which 109 care_map_ranges = care_map_ranges.intersect(rangelib.RangeSet( 110 "0-%d" % (adjusted_blocks,))) 111 112 care_map_list.append(care_map_ranges.to_string_raw()) 113 return care_map_list 114 115 116def AddSystem(output_zip, prefix="IMAGES/", recovery_img=None, boot_img=None): 117 """Turn the contents of SYSTEM into a system image and store it in 118 output_zip. Returns the name of the system image file.""" 119 120 img = OutputFile(output_zip, OPTIONS.input_tmp, prefix, "system.img") 121 if os.path.exists(img.input_name): 122 print("system.img already exists in %s, no need to rebuild..." % (prefix,)) 123 return img.input_name 124 125 def output_sink(fn, data): 126 ofile = open(os.path.join(OPTIONS.input_tmp, "SYSTEM", fn), "w") 127 ofile.write(data) 128 ofile.close() 129 130 arc_name = "SYSTEM/" + fn 131 if arc_name in output_zip.namelist(): 132 OPTIONS.replace_updated_files_list.append(arc_name) 133 else: 134 common.ZipWrite(output_zip, ofile.name, arc_name) 135 136 if OPTIONS.rebuild_recovery: 137 print("Building new recovery patch") 138 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink, recovery_img, 139 boot_img, info_dict=OPTIONS.info_dict) 140 141 block_list = OutputFile(output_zip, OPTIONS.input_tmp, prefix, "system.map") 142 CreateImage(OPTIONS.input_tmp, OPTIONS.info_dict, "system", img, 143 block_list=block_list) 144 145 return img.name 146 147 148def AddSystemOther(output_zip, prefix="IMAGES/"): 149 """Turn the contents of SYSTEM_OTHER into a system_other image 150 and store it in output_zip.""" 151 152 img = OutputFile(output_zip, OPTIONS.input_tmp, prefix, "system_other.img") 153 if os.path.exists(img.input_name): 154 print("system_other.img already exists in %s, no need to rebuild..." % ( 155 prefix,)) 156 return 157 158 CreateImage(OPTIONS.input_tmp, OPTIONS.info_dict, "system_other", img) 159 160 161def AddVendor(output_zip, prefix="IMAGES/"): 162 """Turn the contents of VENDOR into a vendor image and store in it 163 output_zip.""" 164 165 img = OutputFile(output_zip, OPTIONS.input_tmp, prefix, "vendor.img") 166 if os.path.exists(img.input_name): 167 print("vendor.img already exists in %s, no need to rebuild..." % (prefix,)) 168 return img.input_name 169 170 block_list = OutputFile(output_zip, OPTIONS.input_tmp, prefix, "vendor.map") 171 CreateImage(OPTIONS.input_tmp, OPTIONS.info_dict, "vendor", img, 172 block_list=block_list) 173 return img.name 174 175 176def AddDtbo(output_zip, prefix="IMAGES/"): 177 """Adds the DTBO image. 178 179 Uses the image under prefix if it already exists. Otherwise looks for the 180 image under PREBUILT_IMAGES/, signs it as needed, and returns the image name. 181 """ 182 183 img = OutputFile(output_zip, OPTIONS.input_tmp, prefix, "dtbo.img") 184 if os.path.exists(img.input_name): 185 print("dtbo.img already exists in %s, no need to rebuild..." % (prefix,)) 186 return img.input_name 187 188 dtbo_prebuilt_path = os.path.join( 189 OPTIONS.input_tmp, "PREBUILT_IMAGES", "dtbo.img") 190 assert os.path.exists(dtbo_prebuilt_path) 191 shutil.copy(dtbo_prebuilt_path, img.name) 192 193 # AVB-sign the image as needed. 194 if OPTIONS.info_dict.get("avb_enable") == "true": 195 avbtool = os.getenv('AVBTOOL') or OPTIONS.info_dict["avb_avbtool"] 196 part_size = OPTIONS.info_dict["dtbo_size"] 197 # The AVB hash footer will be replaced if already present. 198 cmd = [avbtool, "add_hash_footer", "--image", img.name, 199 "--partition_size", str(part_size), "--partition_name", "dtbo"] 200 common.AppendAVBSigningArgs(cmd, "dtbo") 201 args = OPTIONS.info_dict.get("avb_dtbo_add_hash_footer_args") 202 if args and args.strip(): 203 cmd.extend(shlex.split(args)) 204 p = common.Run(cmd, stdout=subprocess.PIPE) 205 p.communicate() 206 assert p.returncode == 0, \ 207 "avbtool add_hash_footer of %s failed" % (img.name,) 208 209 img.Write() 210 return img.name 211 212 213def CreateImage(input_dir, info_dict, what, output_file, block_list=None): 214 print("creating " + what + ".img...") 215 216 # The name of the directory it is making an image out of matters to 217 # mkyaffs2image. It wants "system" but we have a directory named 218 # "SYSTEM", so create a symlink. 219 temp_dir = tempfile.mkdtemp() 220 OPTIONS.tempfiles.append(temp_dir) 221 try: 222 os.symlink(os.path.join(input_dir, what.upper()), 223 os.path.join(temp_dir, what)) 224 except OSError as e: 225 # bogus error on my mac version? 226 # File "./build/tools/releasetools/img_from_target_files" 227 # os.path.join(OPTIONS.input_tmp, "system")) 228 # OSError: [Errno 17] File exists 229 if e.errno == errno.EEXIST: 230 pass 231 232 image_props = build_image.ImagePropFromGlobalDict(info_dict, what) 233 fstab = info_dict["fstab"] 234 mount_point = "/" + what 235 if fstab and mount_point in fstab: 236 image_props["fs_type"] = fstab[mount_point].fs_type 237 238 # Use a fixed timestamp (01/01/2009) when packaging the image. 239 # Bug: 24377993 240 epoch = datetime.datetime.fromtimestamp(0) 241 timestamp = (datetime.datetime(2009, 1, 1) - epoch).total_seconds() 242 image_props["timestamp"] = int(timestamp) 243 244 if what == "system": 245 fs_config_prefix = "" 246 else: 247 fs_config_prefix = what + "_" 248 249 fs_config = os.path.join( 250 input_dir, "META/" + fs_config_prefix + "filesystem_config.txt") 251 if not os.path.exists(fs_config): 252 fs_config = None 253 254 # Override values loaded from info_dict. 255 if fs_config: 256 image_props["fs_config"] = fs_config 257 if block_list: 258 image_props["block_list"] = block_list.name 259 260 succ = build_image.BuildImage(os.path.join(temp_dir, what), 261 image_props, output_file.name) 262 assert succ, "build " + what + ".img image failed" 263 264 output_file.Write() 265 if block_list: 266 block_list.Write() 267 268 # Set the 'adjusted_partition_size' that excludes the verity blocks of the 269 # given image. When avb is enabled, this size is the max image size returned 270 # by the avb tool. 271 is_verity_partition = "verity_block_device" in image_props 272 verity_supported = (image_props.get("verity") == "true" or 273 image_props.get("avb_enable") == "true") 274 is_avb_enable = image_props.get("avb_hashtree_enable") == "true" 275 if verity_supported and (is_verity_partition or is_avb_enable): 276 adjusted_blocks_value = image_props.get("partition_size") 277 if adjusted_blocks_value: 278 adjusted_blocks_key = what + "_adjusted_partition_size" 279 info_dict[adjusted_blocks_key] = int(adjusted_blocks_value)/4096 - 1 280 281 282def AddUserdata(output_zip, prefix="IMAGES/"): 283 """Create a userdata image and store it in output_zip. 284 285 In most case we just create and store an empty userdata.img; 286 But the invoker can also request to create userdata.img with real 287 data from the target files, by setting "userdata_img_with_data=true" 288 in OPTIONS.info_dict. 289 """ 290 291 img = OutputFile(output_zip, OPTIONS.input_tmp, prefix, "userdata.img") 292 if os.path.exists(img.input_name): 293 print("userdata.img already exists in %s, no need to rebuild..." % ( 294 prefix,)) 295 return 296 297 # Skip userdata.img if no size. 298 image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, "data") 299 if not image_props.get("partition_size"): 300 return 301 302 print("creating userdata.img...") 303 304 # Use a fixed timestamp (01/01/2009) when packaging the image. 305 # Bug: 24377993 306 epoch = datetime.datetime.fromtimestamp(0) 307 timestamp = (datetime.datetime(2009, 1, 1) - epoch).total_seconds() 308 image_props["timestamp"] = int(timestamp) 309 310 # The name of the directory it is making an image out of matters to 311 # mkyaffs2image. So we create a temp dir, and within it we create an 312 # empty dir named "data", or a symlink to the DATA dir, 313 # and build the image from that. 314 temp_dir = tempfile.mkdtemp() 315 OPTIONS.tempfiles.append(temp_dir) 316 user_dir = os.path.join(temp_dir, "data") 317 empty = (OPTIONS.info_dict.get("userdata_img_with_data") != "true") 318 if empty: 319 # Create an empty dir. 320 os.mkdir(user_dir) 321 else: 322 # Symlink to the DATA dir. 323 os.symlink(os.path.join(OPTIONS.input_tmp, "DATA"), 324 user_dir) 325 326 fstab = OPTIONS.info_dict["fstab"] 327 if fstab: 328 image_props["fs_type"] = fstab["/data"].fs_type 329 succ = build_image.BuildImage(user_dir, image_props, img.name) 330 assert succ, "build userdata.img image failed" 331 332 common.CheckSize(img.name, "userdata.img", OPTIONS.info_dict) 333 img.Write() 334 335 336def AppendVBMetaArgsForPartition(cmd, partition, img_path, public_key_dir): 337 if not img_path: 338 return 339 340 # Check if chain partition is used. 341 key_path = OPTIONS.info_dict.get("avb_" + partition + "_key_path") 342 if key_path: 343 # extract public key in AVB format to be included in vbmeta.img 344 avbtool = os.getenv('AVBTOOL') or OPTIONS.info_dict["avb_avbtool"] 345 public_key_path = os.path.join(public_key_dir, "%s.avbpubkey" % partition) 346 p = common.Run([avbtool, "extract_public_key", "--key", key_path, 347 "--output", public_key_path], 348 stdout=subprocess.PIPE, stderr=subprocess.PIPE) 349 p.communicate() 350 assert p.returncode == 0, \ 351 "avbtool extract_public_key fail for partition: %r" % partition 352 353 rollback_index_location = OPTIONS.info_dict[ 354 "avb_" + partition + "_rollback_index_location"] 355 cmd.extend(["--chain_partition", "%s:%s:%s" % ( 356 partition, rollback_index_location, public_key_path)]) 357 else: 358 cmd.extend(["--include_descriptors_from_image", img_path]) 359 360 361def AddVBMeta(output_zip, boot_img_path, system_img_path, vendor_img_path, 362 dtbo_img_path, prefix="IMAGES/"): 363 """Create a VBMeta image and store it in output_zip.""" 364 img = OutputFile(output_zip, OPTIONS.input_tmp, prefix, "vbmeta.img") 365 avbtool = os.getenv('AVBTOOL') or OPTIONS.info_dict["avb_avbtool"] 366 cmd = [avbtool, "make_vbmeta_image", "--output", img.name] 367 common.AppendAVBSigningArgs(cmd, "vbmeta") 368 369 public_key_dir = tempfile.mkdtemp(prefix="avbpubkey-") 370 OPTIONS.tempfiles.append(public_key_dir) 371 372 AppendVBMetaArgsForPartition(cmd, "boot", boot_img_path, public_key_dir) 373 AppendVBMetaArgsForPartition(cmd, "system", system_img_path, public_key_dir) 374 AppendVBMetaArgsForPartition(cmd, "vendor", vendor_img_path, public_key_dir) 375 AppendVBMetaArgsForPartition(cmd, "dtbo", dtbo_img_path, public_key_dir) 376 377 args = OPTIONS.info_dict.get("avb_vbmeta_args") 378 if args and args.strip(): 379 cmd.extend(shlex.split(args)) 380 381 p = common.Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 382 p.communicate() 383 assert p.returncode == 0, "avbtool make_vbmeta_image failed" 384 img.Write() 385 386 387def AddPartitionTable(output_zip, prefix="IMAGES/"): 388 """Create a partition table image and store it in output_zip.""" 389 390 img = OutputFile(output_zip, OPTIONS.input_tmp, prefix, "partition-table.img") 391 bpt = OutputFile(output_zip, OPTIONS.input_tmp, prefix, "partition-table.bpt") 392 393 # use BPTTOOL from environ, or "bpttool" if empty or not set. 394 bpttool = os.getenv("BPTTOOL") or "bpttool" 395 cmd = [bpttool, "make_table", "--output_json", bpt.name, 396 "--output_gpt", img.name] 397 input_files_str = OPTIONS.info_dict["board_bpt_input_files"] 398 input_files = input_files_str.split(" ") 399 for i in input_files: 400 cmd.extend(["--input", i]) 401 disk_size = OPTIONS.info_dict.get("board_bpt_disk_size") 402 if disk_size: 403 cmd.extend(["--disk_size", disk_size]) 404 args = OPTIONS.info_dict.get("board_bpt_make_table_args") 405 if args: 406 cmd.extend(shlex.split(args)) 407 408 p = common.Run(cmd, stdout=subprocess.PIPE) 409 p.communicate() 410 assert p.returncode == 0, "bpttool make_table failed" 411 412 img.Write() 413 bpt.Write() 414 415 416def AddCache(output_zip, prefix="IMAGES/"): 417 """Create an empty cache image and store it in output_zip.""" 418 419 img = OutputFile(output_zip, OPTIONS.input_tmp, prefix, "cache.img") 420 if os.path.exists(img.input_name): 421 print("cache.img already exists in %s, no need to rebuild..." % (prefix,)) 422 return 423 424 image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, "cache") 425 # The build system has to explicitly request for cache.img. 426 if "fs_type" not in image_props: 427 return 428 429 print("creating cache.img...") 430 431 # Use a fixed timestamp (01/01/2009) when packaging the image. 432 # Bug: 24377993 433 epoch = datetime.datetime.fromtimestamp(0) 434 timestamp = (datetime.datetime(2009, 1, 1) - epoch).total_seconds() 435 image_props["timestamp"] = int(timestamp) 436 437 # The name of the directory it is making an image out of matters to 438 # mkyaffs2image. So we create a temp dir, and within it we create an 439 # empty dir named "cache", and build the image from that. 440 temp_dir = tempfile.mkdtemp() 441 OPTIONS.tempfiles.append(temp_dir) 442 user_dir = os.path.join(temp_dir, "cache") 443 os.mkdir(user_dir) 444 445 fstab = OPTIONS.info_dict["fstab"] 446 if fstab: 447 image_props["fs_type"] = fstab["/cache"].fs_type 448 succ = build_image.BuildImage(user_dir, image_props, img.name) 449 assert succ, "build cache.img image failed" 450 451 common.CheckSize(img.name, "cache.img", OPTIONS.info_dict) 452 img.Write() 453 454 455def ReplaceUpdatedFiles(zip_filename, files_list): 456 """Update all the zip entries listed in the files_list. 457 458 For now the list includes META/care_map.txt, and the related files under 459 SYSTEM/ after rebuilding recovery. 460 """ 461 462 cmd = ["zip", "-d", zip_filename] + files_list 463 p = common.Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 464 p.communicate() 465 466 output_zip = zipfile.ZipFile(zip_filename, "a", 467 compression=zipfile.ZIP_DEFLATED, 468 allowZip64=True) 469 for item in files_list: 470 file_path = os.path.join(OPTIONS.input_tmp, item) 471 assert os.path.exists(file_path) 472 common.ZipWrite(output_zip, file_path, arcname=item) 473 common.ZipClose(output_zip) 474 475 476def AddImagesToTargetFiles(filename): 477 if os.path.isdir(filename): 478 OPTIONS.input_tmp = os.path.abspath(filename) 479 input_zip = None 480 else: 481 OPTIONS.input_tmp, input_zip = common.UnzipTemp(filename) 482 483 if not OPTIONS.add_missing: 484 if os.path.isdir(os.path.join(OPTIONS.input_tmp, "IMAGES")): 485 print("target_files appears to already contain images.") 486 sys.exit(1) 487 488 has_vendor = os.path.isdir(os.path.join(OPTIONS.input_tmp, "VENDOR")) 489 has_system_other = os.path.isdir(os.path.join(OPTIONS.input_tmp, 490 "SYSTEM_OTHER")) 491 492 if input_zip: 493 OPTIONS.info_dict = common.LoadInfoDict(input_zip, OPTIONS.input_tmp) 494 495 common.ZipClose(input_zip) 496 output_zip = zipfile.ZipFile(filename, "a", 497 compression=zipfile.ZIP_DEFLATED, 498 allowZip64=True) 499 else: 500 OPTIONS.info_dict = common.LoadInfoDict(filename, filename) 501 output_zip = None 502 images_dir = os.path.join(OPTIONS.input_tmp, "IMAGES") 503 if not os.path.isdir(images_dir): 504 os.makedirs(images_dir) 505 images_dir = None 506 507 has_recovery = (OPTIONS.info_dict.get("no_recovery") != "true") 508 509 def banner(s): 510 print("\n\n++++ " + s + " ++++\n\n") 511 512 prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES", "boot.img") 513 boot_image = None 514 if os.path.exists(prebuilt_path): 515 banner("boot") 516 print("boot.img already exists in IMAGES/, no need to rebuild...") 517 if OPTIONS.rebuild_recovery: 518 boot_image = common.GetBootableImage( 519 "IMAGES/boot.img", "boot.img", OPTIONS.input_tmp, "BOOT") 520 else: 521 banner("boot") 522 boot_image = common.GetBootableImage( 523 "IMAGES/boot.img", "boot.img", OPTIONS.input_tmp, "BOOT") 524 if boot_image: 525 if output_zip: 526 boot_image.AddToZip(output_zip) 527 else: 528 boot_image.WriteToDir(OPTIONS.input_tmp) 529 530 recovery_image = None 531 if has_recovery: 532 banner("recovery") 533 prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES", "recovery.img") 534 if os.path.exists(prebuilt_path): 535 print("recovery.img already exists in IMAGES/, no need to rebuild...") 536 if OPTIONS.rebuild_recovery: 537 recovery_image = common.GetBootableImage( 538 "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp, 539 "RECOVERY") 540 else: 541 recovery_image = common.GetBootableImage( 542 "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY") 543 if recovery_image: 544 if output_zip: 545 recovery_image.AddToZip(output_zip) 546 else: 547 recovery_image.WriteToDir(OPTIONS.input_tmp) 548 549 banner("recovery (two-step image)") 550 # The special recovery.img for two-step package use. 551 recovery_two_step_image = common.GetBootableImage( 552 "IMAGES/recovery-two-step.img", "recovery-two-step.img", 553 OPTIONS.input_tmp, "RECOVERY", two_step_image=True) 554 if recovery_two_step_image: 555 if output_zip: 556 recovery_two_step_image.AddToZip(output_zip) 557 else: 558 recovery_two_step_image.WriteToDir(OPTIONS.input_tmp) 559 560 banner("system") 561 system_img_path = AddSystem( 562 output_zip, recovery_img=recovery_image, boot_img=boot_image) 563 vendor_img_path = None 564 if has_vendor: 565 banner("vendor") 566 vendor_img_path = AddVendor(output_zip) 567 if has_system_other: 568 banner("system_other") 569 AddSystemOther(output_zip) 570 if not OPTIONS.is_signing: 571 banner("userdata") 572 AddUserdata(output_zip) 573 banner("cache") 574 AddCache(output_zip) 575 576 if OPTIONS.info_dict.get("board_bpt_enable") == "true": 577 banner("partition-table") 578 AddPartitionTable(output_zip) 579 580 dtbo_img_path = None 581 if OPTIONS.info_dict.get("has_dtbo") == "true": 582 banner("dtbo") 583 dtbo_img_path = AddDtbo(output_zip) 584 585 if OPTIONS.info_dict.get("avb_enable") == "true": 586 banner("vbmeta") 587 boot_contents = boot_image.WriteToTemp() 588 AddVBMeta(output_zip, boot_contents.name, system_img_path, 589 vendor_img_path, dtbo_img_path) 590 591 # For devices using A/B update, copy over images from RADIO/ and/or 592 # VENDOR_IMAGES/ to IMAGES/ and make sure we have all the needed 593 # images ready under IMAGES/. All images should have '.img' as extension. 594 banner("radio") 595 ab_partitions = os.path.join(OPTIONS.input_tmp, "META", "ab_partitions.txt") 596 if os.path.exists(ab_partitions): 597 with open(ab_partitions, 'r') as f: 598 lines = f.readlines() 599 # For devices using A/B update, generate care_map for system and vendor 600 # partitions (if present), then write this file to target_files package. 601 care_map_list = [] 602 for line in lines: 603 if line.strip() == "system" and ( 604 "system_verity_block_device" in OPTIONS.info_dict or 605 OPTIONS.info_dict.get("system_avb_hashtree_enable") == "true"): 606 assert os.path.exists(system_img_path) 607 care_map_list += GetCareMap("system", system_img_path) 608 if line.strip() == "vendor" and ( 609 "vendor_verity_block_device" in OPTIONS.info_dict or 610 OPTIONS.info_dict.get("vendor_avb_hashtree_enable") == "true"): 611 assert os.path.exists(vendor_img_path) 612 care_map_list += GetCareMap("vendor", vendor_img_path) 613 614 img_name = line.strip() + ".img" 615 prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES", img_name) 616 if os.path.exists(prebuilt_path): 617 print("%s already exists, no need to overwrite..." % (img_name,)) 618 continue 619 620 img_radio_path = os.path.join(OPTIONS.input_tmp, "RADIO", img_name) 621 img_vendor_dir = os.path.join( 622 OPTIONS.input_tmp, "VENDOR_IMAGES") 623 if os.path.exists(img_radio_path): 624 if output_zip: 625 common.ZipWrite(output_zip, img_radio_path, 626 os.path.join("IMAGES", img_name)) 627 else: 628 shutil.copy(img_radio_path, prebuilt_path) 629 else: 630 for root, _, files in os.walk(img_vendor_dir): 631 if img_name in files: 632 if output_zip: 633 common.ZipWrite(output_zip, os.path.join(root, img_name), 634 os.path.join("IMAGES", img_name)) 635 else: 636 shutil.copy(os.path.join(root, img_name), prebuilt_path) 637 break 638 639 if output_zip: 640 # Zip spec says: All slashes MUST be forward slashes. 641 img_path = 'IMAGES/' + img_name 642 assert img_path in output_zip.namelist(), "cannot find " + img_name 643 else: 644 img_path = os.path.join(OPTIONS.input_tmp, "IMAGES", img_name) 645 assert os.path.exists(img_path), "cannot find " + img_name 646 647 if care_map_list: 648 care_map_path = "META/care_map.txt" 649 if output_zip and care_map_path not in output_zip.namelist(): 650 common.ZipWriteStr(output_zip, care_map_path, '\n'.join(care_map_list)) 651 else: 652 with open(os.path.join(OPTIONS.input_tmp, care_map_path), 'w') as fp: 653 fp.write('\n'.join(care_map_list)) 654 if output_zip: 655 OPTIONS.replace_updated_files_list.append(care_map_path) 656 657 if output_zip: 658 common.ZipClose(output_zip) 659 if OPTIONS.replace_updated_files_list: 660 ReplaceUpdatedFiles(output_zip.filename, 661 OPTIONS.replace_updated_files_list) 662 663 664def main(argv): 665 def option_handler(o, a): 666 if o in ("-a", "--add_missing"): 667 OPTIONS.add_missing = True 668 elif o in ("-r", "--rebuild_recovery",): 669 OPTIONS.rebuild_recovery = True 670 elif o == "--replace_verity_private_key": 671 OPTIONS.replace_verity_private_key = (True, a) 672 elif o == "--replace_verity_public_key": 673 OPTIONS.replace_verity_public_key = (True, a) 674 elif o == "--is_signing": 675 OPTIONS.is_signing = True 676 else: 677 return False 678 return True 679 680 args = common.ParseOptions( 681 argv, __doc__, extra_opts="ar", 682 extra_long_opts=["add_missing", "rebuild_recovery", 683 "replace_verity_public_key=", 684 "replace_verity_private_key=", 685 "is_signing"], 686 extra_option_handler=option_handler) 687 688 689 if len(args) != 1: 690 common.Usage(__doc__) 691 sys.exit(1) 692 693 AddImagesToTargetFiles(args[0]) 694 print("done.") 695 696if __name__ == '__main__': 697 try: 698 common.CloseInheritedPipes() 699 main(sys.argv[1:]) 700 except common.ExternalError as e: 701 print("\n ERROR: %s\n" % (e,)) 702 sys.exit(1) 703 finally: 704 common.Cleanup() 705