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