1# Copyright (C) 2020 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15import collections 16import logging 17import os 18import zipfile 19 20import common 21import edify_generator 22import verity_utils 23from check_target_files_vintf import CheckVintfIfTrebleEnabled, HasPartition 24from common import OPTIONS 25from ota_utils import UNZIP_PATTERN, FinalizeMetadata, GetPackageMetadata, PropertyFiles 26 27logger = logging.getLogger(__name__) 28 29 30def GetBlockDifferences(target_zip, source_zip, target_info, source_info, 31 device_specific): 32 """Returns a ordered dict of block differences with partition name as key.""" 33 34 def GetIncrementalBlockDifferenceForPartition(name): 35 if not HasPartition(source_zip, name): 36 raise RuntimeError( 37 "can't generate incremental that adds {}".format(name)) 38 39 partition_src = common.GetUserImage(name, OPTIONS.source_tmp, source_zip, 40 info_dict=source_info, 41 allow_shared_blocks=allow_shared_blocks) 42 43 hashtree_info_generator = verity_utils.CreateHashtreeInfoGenerator( 44 name, 4096, target_info) 45 partition_tgt = common.GetUserImage(name, OPTIONS.target_tmp, target_zip, 46 info_dict=target_info, 47 allow_shared_blocks=allow_shared_blocks, 48 hashtree_info_generator=hashtree_info_generator) 49 50 # Check the first block of the source system partition for remount R/W only 51 # if the filesystem is ext4. 52 partition_source_info = source_info["fstab"]["/" + name] 53 check_first_block = partition_source_info.fs_type == "ext4" 54 # Disable using imgdiff for squashfs. 'imgdiff -z' expects input files to be 55 # in zip formats. However with squashfs, a) all files are compressed in LZ4; 56 # b) the blocks listed in block map may not contain all the bytes for a 57 # given file (because they're rounded to be 4K-aligned). 58 partition_target_info = target_info["fstab"]["/" + name] 59 disable_imgdiff = (partition_source_info.fs_type == "squashfs" or 60 partition_target_info.fs_type == "squashfs") 61 return common.BlockDifference(name, partition_tgt, partition_src, 62 check_first_block, 63 version=blockimgdiff_version, 64 disable_imgdiff=disable_imgdiff) 65 66 if source_zip: 67 # See notes in common.GetUserImage() 68 allow_shared_blocks = (source_info.get('ext4_share_dup_blocks') == "true" or 69 target_info.get('ext4_share_dup_blocks') == "true") 70 blockimgdiff_version = max( 71 int(i) for i in target_info.get( 72 "blockimgdiff_versions", "1").split(",")) 73 assert blockimgdiff_version >= 3 74 75 block_diff_dict = collections.OrderedDict() 76 partition_names = ["system", "vendor", "product", "odm", "system_ext", 77 "vendor_dlkm", "odm_dlkm"] 78 for partition in partition_names: 79 if not HasPartition(target_zip, partition): 80 continue 81 # Full OTA update. 82 if not source_zip: 83 tgt = common.GetUserImage(partition, OPTIONS.input_tmp, target_zip, 84 info_dict=target_info, 85 reset_file_map=True) 86 block_diff_dict[partition] = common.BlockDifference(partition, tgt, 87 src=None) 88 # Incremental OTA update. 89 else: 90 block_diff_dict[partition] = GetIncrementalBlockDifferenceForPartition( 91 partition) 92 assert "system" in block_diff_dict 93 94 # Get the block diffs from the device specific script. If there is a 95 # duplicate block diff for a partition, ignore the diff in the generic script 96 # and use the one in the device specific script instead. 97 if source_zip: 98 device_specific_diffs = device_specific.IncrementalOTA_GetBlockDifferences() 99 function_name = "IncrementalOTA_GetBlockDifferences" 100 else: 101 device_specific_diffs = device_specific.FullOTA_GetBlockDifferences() 102 function_name = "FullOTA_GetBlockDifferences" 103 104 if device_specific_diffs: 105 assert all(isinstance(diff, common.BlockDifference) 106 for diff in device_specific_diffs), \ 107 "{} is not returning a list of BlockDifference objects".format( 108 function_name) 109 for diff in device_specific_diffs: 110 if diff.partition in block_diff_dict: 111 logger.warning("Duplicate block difference found. Device specific block" 112 " diff for partition '%s' overrides the one in generic" 113 " script.", diff.partition) 114 block_diff_dict[diff.partition] = diff 115 116 return block_diff_dict 117 118 119def WriteFullOTAPackage(input_zip, output_file): 120 target_info = common.BuildInfo(OPTIONS.info_dict, OPTIONS.oem_dicts) 121 122 # We don't know what version it will be installed on top of. We expect the API 123 # just won't change very often. Similarly for fstab, it might have changed in 124 # the target build. 125 target_api_version = target_info["recovery_api_version"] 126 script = edify_generator.EdifyGenerator(target_api_version, target_info) 127 128 if target_info.oem_props and not OPTIONS.oem_no_mount: 129 target_info.WriteMountOemScript(script) 130 131 metadata = GetPackageMetadata(target_info) 132 133 if not OPTIONS.no_signing: 134 staging_file = common.MakeTempFile(suffix='.zip') 135 else: 136 staging_file = output_file 137 138 output_zip = zipfile.ZipFile( 139 staging_file, "w", compression=zipfile.ZIP_DEFLATED) 140 141 device_specific = common.DeviceSpecificParams( 142 input_zip=input_zip, 143 input_version=target_api_version, 144 output_zip=output_zip, 145 script=script, 146 input_tmp=OPTIONS.input_tmp, 147 metadata=metadata, 148 info_dict=OPTIONS.info_dict) 149 150 assert HasRecoveryPatch(input_zip, info_dict=OPTIONS.info_dict) 151 152 # Assertions (e.g. downgrade check, device properties check). 153 ts = target_info.GetBuildProp("ro.build.date.utc") 154 ts_text = target_info.GetBuildProp("ro.build.date") 155 script.AssertOlderBuild(ts, ts_text) 156 157 target_info.WriteDeviceAssertions(script, OPTIONS.oem_no_mount) 158 device_specific.FullOTA_Assertions() 159 160 block_diff_dict = GetBlockDifferences(target_zip=input_zip, source_zip=None, 161 target_info=target_info, 162 source_info=None, 163 device_specific=device_specific) 164 165 # Two-step package strategy (in chronological order, which is *not* 166 # the order in which the generated script has things): 167 # 168 # if stage is not "2/3" or "3/3": 169 # write recovery image to boot partition 170 # set stage to "2/3" 171 # reboot to boot partition and restart recovery 172 # else if stage is "2/3": 173 # write recovery image to recovery partition 174 # set stage to "3/3" 175 # reboot to recovery partition and restart recovery 176 # else: 177 # (stage must be "3/3") 178 # set stage to "" 179 # do normal full package installation: 180 # wipe and install system, boot image, etc. 181 # set up system to update recovery partition on first boot 182 # complete script normally 183 # (allow recovery to mark itself finished and reboot) 184 185 recovery_img = common.GetBootableImage("recovery.img", "recovery.img", 186 OPTIONS.input_tmp, "RECOVERY") 187 if OPTIONS.two_step: 188 if not target_info.get("multistage_support"): 189 assert False, "two-step packages not supported by this build" 190 fs = target_info["fstab"]["/misc"] 191 assert fs.fs_type.upper() == "EMMC", \ 192 "two-step packages only supported on devices with EMMC /misc partitions" 193 bcb_dev = {"bcb_dev": fs.device} 194 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data) 195 script.AppendExtra(""" 196if get_stage("%(bcb_dev)s") == "2/3" then 197""" % bcb_dev) 198 199 # Stage 2/3: Write recovery image to /recovery (currently running /boot). 200 script.Comment("Stage 2/3") 201 script.WriteRawImage("/recovery", "recovery.img") 202 script.AppendExtra(""" 203set_stage("%(bcb_dev)s", "3/3"); 204reboot_now("%(bcb_dev)s", "recovery"); 205else if get_stage("%(bcb_dev)s") == "3/3" then 206""" % bcb_dev) 207 208 # Stage 3/3: Make changes. 209 script.Comment("Stage 3/3") 210 211 # Dump fingerprints 212 script.Print("Target: {}".format(target_info.fingerprint)) 213 214 device_specific.FullOTA_InstallBegin() 215 216 # All other partitions as well as the data wipe use 10% of the progress, and 217 # the update of the system partition takes the remaining progress. 218 system_progress = 0.9 - (len(block_diff_dict) - 1) * 0.1 219 if OPTIONS.wipe_user_data: 220 system_progress -= 0.1 221 progress_dict = {partition: 0.1 for partition in block_diff_dict} 222 progress_dict["system"] = system_progress 223 224 if target_info.get('use_dynamic_partitions') == "true": 225 # Use empty source_info_dict to indicate that all partitions / groups must 226 # be re-added. 227 dynamic_partitions_diff = common.DynamicPartitionsDifference( 228 info_dict=OPTIONS.info_dict, 229 block_diffs=block_diff_dict.values(), 230 progress_dict=progress_dict) 231 dynamic_partitions_diff.WriteScript(script, output_zip, 232 write_verify_script=OPTIONS.verify) 233 else: 234 for block_diff in block_diff_dict.values(): 235 block_diff.WriteScript(script, output_zip, 236 progress=progress_dict.get(block_diff.partition), 237 write_verify_script=OPTIONS.verify) 238 239 CheckVintfIfTrebleEnabled(OPTIONS.input_tmp, target_info) 240 241 boot_img = common.GetBootableImage( 242 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT") 243 common.CheckSize(boot_img.data, "boot.img", target_info) 244 common.ZipWriteStr(output_zip, "boot.img", boot_img.data) 245 246 script.WriteRawImage("/boot", "boot.img") 247 248 script.ShowProgress(0.1, 10) 249 device_specific.FullOTA_InstallEnd() 250 251 if OPTIONS.extra_script is not None: 252 script.AppendExtra(OPTIONS.extra_script) 253 254 script.UnmountAll() 255 256 if OPTIONS.wipe_user_data: 257 script.ShowProgress(0.1, 10) 258 script.FormatPartition("/data") 259 260 if OPTIONS.two_step: 261 script.AppendExtra(""" 262set_stage("%(bcb_dev)s", ""); 263""" % bcb_dev) 264 script.AppendExtra("else\n") 265 266 # Stage 1/3: Nothing to verify for full OTA. Write recovery image to /boot. 267 script.Comment("Stage 1/3") 268 _WriteRecoveryImageToBoot(script, output_zip) 269 270 script.AppendExtra(""" 271set_stage("%(bcb_dev)s", "2/3"); 272reboot_now("%(bcb_dev)s", ""); 273endif; 274endif; 275""" % bcb_dev) 276 277 script.SetProgress(1) 278 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary) 279 metadata.required_cache = script.required_cache 280 281 # We haven't written the metadata entry, which will be done in 282 # FinalizeMetadata. 283 common.ZipClose(output_zip) 284 285 needed_property_files = ( 286 NonAbOtaPropertyFiles(), 287 ) 288 FinalizeMetadata(metadata, staging_file, output_file, needed_property_files) 289 290 291def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_file): 292 target_info = common.BuildInfo(OPTIONS.target_info_dict, OPTIONS.oem_dicts) 293 source_info = common.BuildInfo(OPTIONS.source_info_dict, OPTIONS.oem_dicts) 294 295 target_api_version = target_info["recovery_api_version"] 296 source_api_version = source_info["recovery_api_version"] 297 if source_api_version == 0: 298 logger.warning( 299 "Generating edify script for a source that can't install it.") 300 301 script = edify_generator.EdifyGenerator( 302 source_api_version, target_info, fstab=source_info["fstab"]) 303 304 if target_info.oem_props or source_info.oem_props: 305 if not OPTIONS.oem_no_mount: 306 source_info.WriteMountOemScript(script) 307 308 metadata = GetPackageMetadata(target_info, source_info) 309 310 if not OPTIONS.no_signing: 311 staging_file = common.MakeTempFile(suffix='.zip') 312 else: 313 staging_file = output_file 314 315 output_zip = zipfile.ZipFile( 316 staging_file, "w", compression=zipfile.ZIP_DEFLATED) 317 318 device_specific = common.DeviceSpecificParams( 319 source_zip=source_zip, 320 source_version=source_api_version, 321 source_tmp=OPTIONS.source_tmp, 322 target_zip=target_zip, 323 target_version=target_api_version, 324 target_tmp=OPTIONS.target_tmp, 325 output_zip=output_zip, 326 script=script, 327 metadata=metadata, 328 info_dict=source_info) 329 330 source_boot = common.GetBootableImage( 331 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT", source_info) 332 target_boot = common.GetBootableImage( 333 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT", target_info) 334 updating_boot = (not OPTIONS.two_step and 335 (source_boot.data != target_boot.data)) 336 337 target_recovery = common.GetBootableImage( 338 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY") 339 340 block_diff_dict = GetBlockDifferences(target_zip=target_zip, 341 source_zip=source_zip, 342 target_info=target_info, 343 source_info=source_info, 344 device_specific=device_specific) 345 346 CheckVintfIfTrebleEnabled(OPTIONS.target_tmp, target_info) 347 348 # Assertions (e.g. device properties check). 349 target_info.WriteDeviceAssertions(script, OPTIONS.oem_no_mount) 350 device_specific.IncrementalOTA_Assertions() 351 352 # Two-step incremental package strategy (in chronological order, 353 # which is *not* the order in which the generated script has 354 # things): 355 # 356 # if stage is not "2/3" or "3/3": 357 # do verification on current system 358 # write recovery image to boot partition 359 # set stage to "2/3" 360 # reboot to boot partition and restart recovery 361 # else if stage is "2/3": 362 # write recovery image to recovery partition 363 # set stage to "3/3" 364 # reboot to recovery partition and restart recovery 365 # else: 366 # (stage must be "3/3") 367 # perform update: 368 # patch system files, etc. 369 # force full install of new boot image 370 # set up system to update recovery partition on first boot 371 # complete script normally 372 # (allow recovery to mark itself finished and reboot) 373 374 if OPTIONS.two_step: 375 if not source_info.get("multistage_support"): 376 assert False, "two-step packages not supported by this build" 377 fs = source_info["fstab"]["/misc"] 378 assert fs.fs_type.upper() == "EMMC", \ 379 "two-step packages only supported on devices with EMMC /misc partitions" 380 bcb_dev = {"bcb_dev": fs.device} 381 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data) 382 script.AppendExtra(""" 383if get_stage("%(bcb_dev)s") == "2/3" then 384""" % bcb_dev) 385 386 # Stage 2/3: Write recovery image to /recovery (currently running /boot). 387 script.Comment("Stage 2/3") 388 script.AppendExtra("sleep(20);\n") 389 script.WriteRawImage("/recovery", "recovery.img") 390 script.AppendExtra(""" 391set_stage("%(bcb_dev)s", "3/3"); 392reboot_now("%(bcb_dev)s", "recovery"); 393else if get_stage("%(bcb_dev)s") != "3/3" then 394""" % bcb_dev) 395 396 # Stage 1/3: (a) Verify the current system. 397 script.Comment("Stage 1/3") 398 399 # Dump fingerprints 400 script.Print("Source: {}".format(source_info.fingerprint)) 401 script.Print("Target: {}".format(target_info.fingerprint)) 402 403 script.Print("Verifying current system...") 404 405 device_specific.IncrementalOTA_VerifyBegin() 406 407 WriteFingerprintAssertion(script, target_info, source_info) 408 409 # Check the required cache size (i.e. stashed blocks). 410 required_cache_sizes = [diff.required_cache for diff in 411 block_diff_dict.values()] 412 if updating_boot: 413 boot_type, boot_device_expr = common.GetTypeAndDeviceExpr("/boot", 414 source_info) 415 d = common.Difference(target_boot, source_boot) 416 _, _, d = d.ComputePatch() 417 if d is None: 418 include_full_boot = True 419 common.ZipWriteStr(output_zip, "boot.img", target_boot.data) 420 else: 421 include_full_boot = False 422 423 logger.info( 424 "boot target: %d source: %d diff: %d", target_boot.size, 425 source_boot.size, len(d)) 426 427 common.ZipWriteStr(output_zip, "boot.img.p", d) 428 429 target_expr = 'concat("{}:",{},":{}:{}")'.format( 430 boot_type, boot_device_expr, target_boot.size, target_boot.sha1) 431 source_expr = 'concat("{}:",{},":{}:{}")'.format( 432 boot_type, boot_device_expr, source_boot.size, source_boot.sha1) 433 script.PatchPartitionExprCheck(target_expr, source_expr) 434 435 required_cache_sizes.append(target_boot.size) 436 437 if required_cache_sizes: 438 script.CacheFreeSpaceCheck(max(required_cache_sizes)) 439 440 # Verify the existing partitions. 441 for diff in block_diff_dict.values(): 442 diff.WriteVerifyScript(script, touched_blocks_only=True) 443 444 device_specific.IncrementalOTA_VerifyEnd() 445 446 if OPTIONS.two_step: 447 # Stage 1/3: (b) Write recovery image to /boot. 448 _WriteRecoveryImageToBoot(script, output_zip) 449 450 script.AppendExtra(""" 451set_stage("%(bcb_dev)s", "2/3"); 452reboot_now("%(bcb_dev)s", ""); 453else 454""" % bcb_dev) 455 456 # Stage 3/3: Make changes. 457 script.Comment("Stage 3/3") 458 459 script.Comment("---- start making changes here ----") 460 461 device_specific.IncrementalOTA_InstallBegin() 462 463 progress_dict = {partition: 0.1 for partition in block_diff_dict} 464 progress_dict["system"] = 1 - len(block_diff_dict) * 0.1 465 466 if OPTIONS.source_info_dict.get("use_dynamic_partitions") == "true": 467 if OPTIONS.target_info_dict.get("use_dynamic_partitions") != "true": 468 raise RuntimeError( 469 "can't generate incremental that disables dynamic partitions") 470 dynamic_partitions_diff = common.DynamicPartitionsDifference( 471 info_dict=OPTIONS.target_info_dict, 472 source_info_dict=OPTIONS.source_info_dict, 473 block_diffs=block_diff_dict.values(), 474 progress_dict=progress_dict) 475 dynamic_partitions_diff.WriteScript( 476 script, output_zip, write_verify_script=OPTIONS.verify) 477 else: 478 for block_diff in block_diff_dict.values(): 479 block_diff.WriteScript(script, output_zip, 480 progress=progress_dict.get(block_diff.partition), 481 write_verify_script=OPTIONS.verify) 482 483 if OPTIONS.two_step: 484 common.ZipWriteStr(output_zip, "boot.img", target_boot.data) 485 script.WriteRawImage("/boot", "boot.img") 486 logger.info("writing full boot image (forced by two-step mode)") 487 488 if not OPTIONS.two_step: 489 if updating_boot: 490 if include_full_boot: 491 logger.info("boot image changed; including full.") 492 script.Print("Installing boot image...") 493 script.WriteRawImage("/boot", "boot.img") 494 else: 495 # Produce the boot image by applying a patch to the current 496 # contents of the boot partition, and write it back to the 497 # partition. 498 logger.info("boot image changed; including patch.") 499 script.Print("Patching boot image...") 500 script.ShowProgress(0.1, 10) 501 target_expr = 'concat("{}:",{},":{}:{}")'.format( 502 boot_type, boot_device_expr, target_boot.size, target_boot.sha1) 503 source_expr = 'concat("{}:",{},":{}:{}")'.format( 504 boot_type, boot_device_expr, source_boot.size, source_boot.sha1) 505 script.PatchPartitionExpr(target_expr, source_expr, '"boot.img.p"') 506 else: 507 logger.info("boot image unchanged; skipping.") 508 509 # Do device-specific installation (eg, write radio image). 510 device_specific.IncrementalOTA_InstallEnd() 511 512 if OPTIONS.extra_script is not None: 513 script.AppendExtra(OPTIONS.extra_script) 514 515 if OPTIONS.wipe_user_data: 516 script.Print("Erasing user data...") 517 script.FormatPartition("/data") 518 519 if OPTIONS.two_step: 520 script.AppendExtra(""" 521set_stage("%(bcb_dev)s", ""); 522endif; 523endif; 524""" % bcb_dev) 525 526 script.SetProgress(1) 527 # For downgrade OTAs, we prefer to use the update-binary in the source 528 # build that is actually newer than the one in the target build. 529 if OPTIONS.downgrade: 530 script.AddToZip(source_zip, output_zip, input_path=OPTIONS.updater_binary) 531 else: 532 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary) 533 metadata.required_cache = script.required_cache 534 535 # We haven't written the metadata entry yet, which will be handled in 536 # FinalizeMetadata(). 537 common.ZipClose(output_zip) 538 539 # Sign the generated zip package unless no_signing is specified. 540 needed_property_files = ( 541 NonAbOtaPropertyFiles(), 542 ) 543 FinalizeMetadata(metadata, staging_file, output_file, needed_property_files) 544 545 546def GenerateNonAbOtaPackage(target_file, output_file, source_file=None): 547 """Generates a non-A/B OTA package.""" 548 # Check the loaded info dicts first. 549 if OPTIONS.info_dict.get("no_recovery") == "true": 550 raise common.ExternalError( 551 "--- target build has specified no recovery ---") 552 553 # Non-A/B OTAs rely on /cache partition to store temporary files. 554 cache_size = OPTIONS.info_dict.get("cache_size") 555 if cache_size is None: 556 logger.warning("--- can't determine the cache partition size ---") 557 OPTIONS.cache_size = cache_size 558 559 if OPTIONS.extra_script is not None: 560 with open(OPTIONS.extra_script) as fp: 561 OPTIONS.extra_script = fp.read() 562 563 if OPTIONS.extracted_input is not None: 564 OPTIONS.input_tmp = OPTIONS.extracted_input 565 else: 566 logger.info("unzipping target target-files...") 567 OPTIONS.input_tmp = common.UnzipTemp(target_file, UNZIP_PATTERN) 568 OPTIONS.target_tmp = OPTIONS.input_tmp 569 570 # If the caller explicitly specified the device-specific extensions path via 571 # -s / --device_specific, use that. Otherwise, use META/releasetools.py if it 572 # is present in the target target_files. Otherwise, take the path of the file 573 # from 'tool_extensions' in the info dict and look for that in the local 574 # filesystem, relative to the current directory. 575 if OPTIONS.device_specific is None: 576 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py") 577 if os.path.exists(from_input): 578 logger.info("(using device-specific extensions from target_files)") 579 OPTIONS.device_specific = from_input 580 else: 581 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions") 582 583 if OPTIONS.device_specific is not None: 584 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific) 585 586 # Generate a full OTA. 587 if source_file is None: 588 with zipfile.ZipFile(target_file) as input_zip: 589 WriteFullOTAPackage( 590 input_zip, 591 output_file) 592 593 # Generate an incremental OTA. 594 else: 595 logger.info("unzipping source target-files...") 596 OPTIONS.source_tmp = common.UnzipTemp( 597 OPTIONS.incremental_source, UNZIP_PATTERN) 598 with zipfile.ZipFile(target_file) as input_zip, \ 599 zipfile.ZipFile(source_file) as source_zip: 600 WriteBlockIncrementalOTAPackage( 601 input_zip, 602 source_zip, 603 output_file) 604 605 606def WriteFingerprintAssertion(script, target_info, source_info): 607 source_oem_props = source_info.oem_props 608 target_oem_props = target_info.oem_props 609 610 if source_oem_props is None and target_oem_props is None: 611 script.AssertSomeFingerprint( 612 source_info.fingerprint, target_info.fingerprint) 613 elif source_oem_props is not None and target_oem_props is not None: 614 script.AssertSomeThumbprint( 615 target_info.GetBuildProp("ro.build.thumbprint"), 616 source_info.GetBuildProp("ro.build.thumbprint")) 617 elif source_oem_props is None and target_oem_props is not None: 618 script.AssertFingerprintOrThumbprint( 619 source_info.fingerprint, 620 target_info.GetBuildProp("ro.build.thumbprint")) 621 else: 622 script.AssertFingerprintOrThumbprint( 623 target_info.fingerprint, 624 source_info.GetBuildProp("ro.build.thumbprint")) 625 626 627class NonAbOtaPropertyFiles(PropertyFiles): 628 """The property-files for non-A/B OTA. 629 630 For non-A/B OTA, the property-files string contains the info for METADATA 631 entry, with which a system updater can be fetched the package metadata prior 632 to downloading the entire package. 633 """ 634 635 def __init__(self): 636 super(NonAbOtaPropertyFiles, self).__init__() 637 self.name = 'ota-property-files' 638 639 640def _WriteRecoveryImageToBoot(script, output_zip): 641 """Find and write recovery image to /boot in two-step OTA. 642 643 In two-step OTAs, we write recovery image to /boot as the first step so that 644 we can reboot to there and install a new recovery image to /recovery. 645 A special "recovery-two-step.img" will be preferred, which encodes the correct 646 path of "/boot". Otherwise the device may show "device is corrupt" message 647 when booting into /boot. 648 649 Fall back to using the regular recovery.img if the two-step recovery image 650 doesn't exist. Note that rebuilding the special image at this point may be 651 infeasible, because we don't have the desired boot signer and keys when 652 calling ota_from_target_files.py. 653 """ 654 655 recovery_two_step_img_name = "recovery-two-step.img" 656 recovery_two_step_img_path = os.path.join( 657 OPTIONS.input_tmp, "OTA", recovery_two_step_img_name) 658 if os.path.exists(recovery_two_step_img_path): 659 common.ZipWrite( 660 output_zip, 661 recovery_two_step_img_path, 662 arcname=recovery_two_step_img_name) 663 logger.info( 664 "two-step package: using %s in stage 1/3", recovery_two_step_img_name) 665 script.WriteRawImage("/boot", recovery_two_step_img_name) 666 else: 667 logger.info("two-step package: using recovery.img in stage 1/3") 668 # The "recovery.img" entry has been written into package earlier. 669 script.WriteRawImage("/boot", "recovery.img") 670 671 672def HasRecoveryPatch(target_files_zip, info_dict): 673 board_uses_vendorimage = info_dict.get("board_uses_vendorimage") == "true" 674 675 if board_uses_vendorimage: 676 target_files_dir = "VENDOR" 677 else: 678 target_files_dir = "SYSTEM/vendor" 679 680 patch = "%s/recovery-from-boot.p" % target_files_dir 681 img = "%s/etc/recovery.img" % target_files_dir 682 683 namelist = target_files_zip.namelist() 684 return patch in namelist or img in namelist 685