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