blob: 471ef252a352c2654d52f88d6cff0ab55e50d57c [file] [log] [blame]
Kelvin Zhangcff4d762020-07-29 16:37:51 -04001# 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)
Tianjiea2076132020-08-19 17:25:32 -0700279 metadata.required_cache = script.required_cache
Kelvin Zhangcff4d762020-07-29 16:37:51 -0400280
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)
Tianjiea2076132020-08-19 17:25:32 -0700533 metadata.required_cache = script.required_cache
Kelvin Zhangcff4d762020-07-29 16:37:51 -0400534
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