blob: e5f853f3b6f206c7b2e1fb679f46997bf179e257 [file] [log] [blame]
Doug Zongkereef39442009-04-02 12:14:19 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2008 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""
18Given a target-files zipfile, produces an OTA package that installs
19that build. An incremental OTA is produced if -i is given, otherwise
20a full OTA is produced.
21
22Usage: ota_from_target_files [flags] input_target_files output_ota_package
23
Doug Zongkerafb32ea2011-09-22 10:28:04 -070024 -k (--package_key) <key> Key to use to sign the package (default is
25 the value of default_system_dev_certificate from the input
26 target-files's META/misc_info.txt, or
27 "build/target/product/security/testkey" if that value is not
28 specified).
29
30 For incremental OTAs, the default value is based on the source
31 target-file, not the target build.
Doug Zongkereef39442009-04-02 12:14:19 -070032
33 -i (--incremental_from) <file>
34 Generate an incremental OTA using the given target-files zip as
35 the starting build.
36
Tao Bao43078aa2015-04-21 14:32:35 -070037 --full_radio
38 When generating an incremental OTA, always include a full copy of
39 radio image. This option is only meaningful when -i is specified,
40 because a full radio is always included in a full OTA if applicable.
41
leozwangaa6c1a12015-08-14 10:57:58 -070042 --full_bootloader
43 Similar to --full_radio. When generating an incremental OTA, always
44 include a full copy of bootloader image.
45
Tao Baoedb35b82017-10-30 16:07:13 -070046 --verify
47 Remount and verify the checksums of the files written to the system and
48 vendor (if used) partitions. Non-A/B incremental OTAs only.
Michael Runge63f01de2014-10-28 19:24:19 -070049
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -080050 -o (--oem_settings) <main_file[,additional_files...]>
51 Comma seperated list of files used to specify the expected OEM-specific
52 properties on the OEM partition of the intended device.
53 Multiple expected values can be used by providing multiple files.
54
Tao Bao8608cde2016-02-25 19:49:55 -080055 --oem_no_mount
56 For devices with OEM-specific properties but without an OEM partition,
57 do not mount the OEM partition in the updater-script. This should be
58 very rarely used, since it's expected to have a dedicated OEM partition
59 for OEM-specific properties. Only meaningful when -o is specified.
60
Doug Zongkerdbfaae52009-04-21 17:12:54 -070061 -w (--wipe_user_data)
62 Generate an OTA package that will wipe the user data partition
63 when installed.
64
Tao Bao5d182562016-02-23 11:38:39 -080065 --downgrade
66 Intentionally generate an incremental OTA that updates from a newer
67 build to an older one (based on timestamp comparison). "post-timestamp"
68 will be replaced by "ota-downgrade=yes" in the metadata file. A data
69 wipe will always be enforced, so "ota-wipe=yes" will also be included in
Tao Bao4996cf02016-03-08 17:53:39 -080070 the metadata file. The update-binary in the source build will be used in
Tao Bao3e6161a2017-02-28 11:48:48 -080071 the OTA package, unless --binary flag is specified. Please also check the
72 doc for --override_timestamp below.
73
74 --override_timestamp
75 Intentionally generate an incremental OTA that updates from a newer
76 build to an older one (based on timestamp comparison), by overriding the
77 timestamp in package metadata. This differs from --downgrade flag: we
78 know for sure this is NOT an actual downgrade case, but two builds are
79 cut in a reverse order. A legit use case is that we cut a new build C
80 (after having A and B), but want to enfore an update path of A -> C -> B.
81 Specifying --downgrade may not help since that would enforce a data wipe
82 for C -> B update. The value of "post-timestamp" will be set to the newer
83 timestamp plus one, so that the package can be pushed and applied.
Tao Bao5d182562016-02-23 11:38:39 -080084
Doug Zongker1c390a22009-05-14 19:06:36 -070085 -e (--extra_script) <file>
86 Insert the contents of file at the end of the update script.
87
Doug Zongker9b23f2c2013-11-25 14:44:12 -080088 -2 (--two_step)
89 Generate a 'two-step' OTA package, where recovery is updated
90 first, so that any changes made to the system partition are done
91 using the new recovery (new kernel, etc.).
92
Doug Zongker26e66192014-02-20 13:22:07 -080093 --block
Tao Bao457cbf62017-03-06 09:56:01 -080094 Generate a block-based OTA for non-A/B device. We have deprecated the
95 support for file-based OTA since O. Block-based OTA will be used by
96 default for all non-A/B devices. Keeping this flag here to not break
97 existing callers.
Doug Zongker26e66192014-02-20 13:22:07 -080098
Doug Zongker25568482014-03-03 10:21:27 -080099 -b (--binary) <file>
100 Use the given binary as the update-binary in the output package,
101 instead of the binary in the build's target_files. Use for
102 development only.
103
Martin Blumenstingl374e1142014-05-31 20:42:55 +0200104 -t (--worker_threads) <int>
105 Specifies the number of worker-threads that will be used when
106 generating patches for incremental updates (defaults to 3).
107
Tao Bao8dcf7382015-05-21 14:09:49 -0700108 --stash_threshold <float>
109 Specifies the threshold that will be used to compute the maximum
110 allowed stash size (defaults to 0.8).
Tao Bao9bc6bb22015-11-09 16:58:28 -0800111
112 --gen_verify
113 Generate an OTA package that verifies the partitions.
Tao Baod62c6032015-11-30 09:40:20 -0800114
115 --log_diff <file>
116 Generate a log file that shows the differences in the source and target
117 builds for an incremental package. This option is only meaningful when
118 -i is specified.
Tao Baodea0f8b2016-06-20 17:55:06 -0700119
120 --payload_signer <signer>
121 Specify the signer when signing the payload and metadata for A/B OTAs.
122 By default (i.e. without this flag), it calls 'openssl pkeyutl' to sign
123 with the package private key. If the private key cannot be accessed
124 directly, a payload signer that knows how to do that should be specified.
125 The signer will be supplied with "-inkey <path_to_key>",
126 "-in <input_file>" and "-out <output_file>" parameters.
Baligh Uddin2abbbd02016-06-22 12:14:16 -0700127
128 --payload_signer_args <args>
129 Specify the arguments needed for payload signer.
Doug Zongkereef39442009-04-02 12:14:19 -0700130"""
131
Tao Bao89fbb0f2017-01-10 10:47:58 -0800132from __future__ import print_function
133
Doug Zongkereef39442009-04-02 12:14:19 -0700134import sys
135
Doug Zongkercf6d5a92014-02-18 10:57:07 -0800136if sys.hexversion < 0x02070000:
Tao Bao89fbb0f2017-01-10 10:47:58 -0800137 print("Python 2.7 or newer is required.", file=sys.stderr)
Doug Zongkereef39442009-04-02 12:14:19 -0700138 sys.exit(1)
139
Doug Zongkerfc44a512014-08-26 13:10:25 -0700140import multiprocessing
Tao Bao2dd1c482017-02-03 16:49:39 -0800141import os.path
Tao Baoc098e9e2016-01-07 13:03:56 -0800142import subprocess
Baligh Uddin2abbbd02016-06-22 12:14:16 -0700143import shlex
Doug Zongkereef39442009-04-02 12:14:19 -0700144import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -0700145import zipfile
146
147import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700148import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -0700149import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700150
151OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700152OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700153OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700154OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700155OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700156OPTIONS.wipe_user_data = False
Tao Bao5d182562016-02-23 11:38:39 -0800157OPTIONS.downgrade = False
Tao Bao3e6161a2017-02-28 11:48:48 -0800158OPTIONS.timestamp = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700159OPTIONS.extra_script = None
Doug Zongkerfc44a512014-08-26 13:10:25 -0700160OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
161if OPTIONS.worker_threads == 0:
162 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800163OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900164OPTIONS.no_signing = False
Tao Bao457cbf62017-03-06 09:56:01 -0800165OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -0800166OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700167OPTIONS.oem_source = None
Tao Bao8608cde2016-02-25 19:49:55 -0800168OPTIONS.oem_no_mount = False
Doug Zongker62d4f182014-08-04 16:06:43 -0700169OPTIONS.fallback_to_full = True
Tao Bao43078aa2015-04-21 14:32:35 -0700170OPTIONS.full_radio = False
leozwangaa6c1a12015-08-14 10:57:58 -0700171OPTIONS.full_bootloader = False
Tao Baod47d8e12015-05-21 14:09:49 -0700172# Stash size cannot exceed cache_size * threshold.
173OPTIONS.cache_size = None
174OPTIONS.stash_threshold = 0.8
Tao Bao9bc6bb22015-11-09 16:58:28 -0800175OPTIONS.gen_verify = False
Tao Baod62c6032015-11-30 09:40:20 -0800176OPTIONS.log_diff = None
Tao Baodea0f8b2016-06-20 17:55:06 -0700177OPTIONS.payload_signer = None
Baligh Uddin2abbbd02016-06-22 12:14:16 -0700178OPTIONS.payload_signer_args = []
Tao Bao5f8ff932017-03-21 22:35:00 -0700179OPTIONS.extracted_input = None
Christian Oderf63e2cd2017-05-01 22:30:15 +0200180OPTIONS.key_passwords = []
Tao Bao8dcf7382015-05-21 14:09:49 -0700181
Tao Bao2dd1c482017-02-03 16:49:39 -0800182METADATA_NAME = 'META-INF/com/android/metadata'
Tao Bao6b0b2f92017-03-05 11:38:11 -0800183UNZIP_PATTERN = ['IMAGES/*', 'META/*']
184
Tao Bao2dd1c482017-02-03 16:49:39 -0800185
Doug Zongkereef39442009-04-02 12:14:19 -0700186def SignOutput(temp_zip_name, output_zip_name):
Christian Oderf63e2cd2017-05-01 22:30:15 +0200187 pw = OPTIONS.key_passwords[OPTIONS.package_key]
Doug Zongkereef39442009-04-02 12:14:19 -0700188
Doug Zongker951495f2009-08-14 12:44:19 -0700189 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
190 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700191
192
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800193def AppendAssertions(script, info_dict, oem_dicts=None):
Michael Runge6e836112014-04-15 17:40:21 -0700194 oem_props = info_dict.get("oem_fingerprint_properties")
Tao Bao3e30d972016-03-15 13:20:19 -0700195 if not oem_props:
Michael Runge6e836112014-04-15 17:40:21 -0700196 device = GetBuildProp("ro.product.device", info_dict)
197 script.AssertDevice(device)
198 else:
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800199 if not oem_dicts:
Dan Albert8b72aef2015-03-23 19:13:21 -0700200 raise common.ExternalError(
201 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700202 for prop in oem_props.split():
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800203 values = []
204 for oem_dict in oem_dicts:
205 if oem_dict.get(prop):
206 values.append(oem_dict[prop])
207 if not values:
Dan Albert8b72aef2015-03-23 19:13:21 -0700208 raise common.ExternalError(
209 "The OEM file is missing the property %s" % prop)
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800210 script.AssertOemProperty(prop, values)
211
212
Tao Baoebce6972017-03-06 10:22:20 -0800213def _LoadOemDicts(script, recovery_mount_options=None):
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800214 """Returns the list of loaded OEM properties dict."""
215 oem_dicts = None
216 if OPTIONS.oem_source is None:
217 raise common.ExternalError("OEM source required for this build")
Tao Baoebce6972017-03-06 10:22:20 -0800218 if not OPTIONS.oem_no_mount and script:
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800219 script.Mount("/oem", recovery_mount_options)
220 oem_dicts = []
221 for oem_file in OPTIONS.oem_source:
222 oem_dicts.append(common.LoadDictionaryFromLines(
223 open(oem_file).readlines()))
224 return oem_dicts
Doug Zongkereef39442009-04-02 12:14:19 -0700225
Doug Zongkereef39442009-04-02 12:14:19 -0700226
Tao Baod42e97e2016-11-30 12:11:57 -0800227def _WriteRecoveryImageToBoot(script, output_zip):
228 """Find and write recovery image to /boot in two-step OTA.
229
230 In two-step OTAs, we write recovery image to /boot as the first step so that
231 we can reboot to there and install a new recovery image to /recovery.
232 A special "recovery-two-step.img" will be preferred, which encodes the correct
233 path of "/boot". Otherwise the device may show "device is corrupt" message
234 when booting into /boot.
235
236 Fall back to using the regular recovery.img if the two-step recovery image
237 doesn't exist. Note that rebuilding the special image at this point may be
238 infeasible, because we don't have the desired boot signer and keys when
239 calling ota_from_target_files.py.
240 """
241
242 recovery_two_step_img_name = "recovery-two-step.img"
243 recovery_two_step_img_path = os.path.join(
244 OPTIONS.input_tmp, "IMAGES", recovery_two_step_img_name)
245 if os.path.exists(recovery_two_step_img_path):
246 recovery_two_step_img = common.GetBootableImage(
247 recovery_two_step_img_name, recovery_two_step_img_name,
248 OPTIONS.input_tmp, "RECOVERY")
249 common.ZipWriteStr(
250 output_zip, recovery_two_step_img_name, recovery_two_step_img.data)
Tao Bao89fbb0f2017-01-10 10:47:58 -0800251 print("two-step package: using %s in stage 1/3" % (
252 recovery_two_step_img_name,))
Tao Baod42e97e2016-11-30 12:11:57 -0800253 script.WriteRawImage("/boot", recovery_two_step_img_name)
254 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -0800255 print("two-step package: using recovery.img in stage 1/3")
Tao Baod42e97e2016-11-30 12:11:57 -0800256 # The "recovery.img" entry has been written into package earlier.
257 script.WriteRawImage("/boot", "recovery.img")
258
259
Doug Zongkerc9253822014-02-04 12:17:58 -0800260def HasRecoveryPatch(target_files_zip):
Tao Baof2cffbd2015-07-22 12:33:18 -0700261 namelist = [name for name in target_files_zip.namelist()]
262 return ("SYSTEM/recovery-from-boot.p" in namelist or
263 "SYSTEM/etc/recovery.img" in namelist)
Doug Zongker73ef8252009-07-23 15:12:53 -0700264
Tao Bao457cbf62017-03-06 09:56:01 -0800265
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700266def HasVendorPartition(target_files_zip):
267 try:
268 target_files_zip.getinfo("VENDOR/")
269 return True
270 except KeyError:
271 return False
272
Tao Bao457cbf62017-03-06 09:56:01 -0800273
Tao Baobcd1d162017-08-26 13:10:26 -0700274def HasTrebleEnabled(target_files_zip, info_dict):
275 return (HasVendorPartition(target_files_zip) and
276 GetBuildProp("ro.treble.enabled", info_dict) == "true")
277
278
Michael Runge6e836112014-04-15 17:40:21 -0700279def GetOemProperty(name, oem_props, oem_dict, info_dict):
280 if oem_props is not None and name in oem_props:
281 return oem_dict[name]
282 return GetBuildProp(name, info_dict)
283
284
285def CalculateFingerprint(oem_props, oem_dict, info_dict):
286 if oem_props is None:
287 return GetBuildProp("ro.build.fingerprint", info_dict)
288 return "%s/%s/%s:%s" % (
Dan Albert8b72aef2015-03-23 19:13:21 -0700289 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
290 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
291 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
292 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700293
Doug Zongkerfc44a512014-08-26 13:10:25 -0700294
Tao Bao7e0f1602017-03-06 15:50:08 -0800295def GetImage(which, tmpdir):
296 """Returns an image object suitable for passing to BlockImageDiff.
297
298 'which' partition must be "system" or "vendor". A prebuilt image and file
299 map must already exist in tmpdir.
300 """
Doug Zongker3c84f562014-07-31 11:06:30 -0700301
302 assert which in ("system", "vendor")
303
304 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700305 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
Doug Zongker3c84f562014-07-31 11:06:30 -0700306
Tao Bao7e0f1602017-03-06 15:50:08 -0800307 # The image and map files must have been created prior to calling
308 # ota_from_target_files.py (since LMP).
309 assert os.path.exists(path) and os.path.exists(mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700310
Tao Baoff777812015-05-12 11:42:31 -0700311 # Bug: http://b/20939131
312 # In ext4 filesystems, block 0 might be changed even being mounted
313 # R/O. We add it to clobbered_blocks so that it will be written to the
314 # target unconditionally. Note that they are still part of care_map.
315 clobbered_blocks = "0"
316
317 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700318
319
Tao Baobcd1d162017-08-26 13:10:26 -0700320def AddCompatibilityArchiveIfTrebleEnabled(target_zip, output_zip,
321 target_info_dict,
322 source_info_dict=None):
323 """Adds compatibility info into the output zip if it's Treble-enabled target.
Tao Bao21803d32017-04-19 10:16:09 -0700324
325 Metadata used for on-device compatibility verification is retrieved from
326 target_zip then added to compatibility.zip which is added to the output_zip
327 archive.
328
Tao Baobcd1d162017-08-26 13:10:26 -0700329 Compatibility archive should only be included for devices that have enabled
330 Treble support.
Tao Bao21803d32017-04-19 10:16:09 -0700331
332 Args:
333 target_zip: Zip file containing the source files to be included for OTA.
334 output_zip: Zip file that will be sent for OTA.
Tao Baobcd1d162017-08-26 13:10:26 -0700335 target_info_dict: The dict that holds the target build info.
336 source_info_dict: The dict that holds the source build info, if generating
337 an incremental OTA; None otherwise.
Tao Bao21803d32017-04-19 10:16:09 -0700338 """
339
Tao Baobcd1d162017-08-26 13:10:26 -0700340 def AddCompatibilityArchive(system_updated, vendor_updated):
341 """Adds compatibility info based on system/vendor update status.
Tao Bao21803d32017-04-19 10:16:09 -0700342
Tao Baobcd1d162017-08-26 13:10:26 -0700343 Args:
344 system_updated: If True, the system image will be updated and therefore
345 its metadata should be included.
346 vendor_updated: If True, the vendor image will be updated and therefore
347 its metadata should be included.
348 """
349 # Determine what metadata we need. Files are names relative to META/.
350 compatibility_files = []
351 vendor_metadata = ("vendor_manifest.xml", "vendor_matrix.xml")
352 system_metadata = ("system_manifest.xml", "system_matrix.xml")
353 if vendor_updated:
354 compatibility_files += vendor_metadata
355 if system_updated:
356 compatibility_files += system_metadata
Tao Bao21803d32017-04-19 10:16:09 -0700357
Tao Baobcd1d162017-08-26 13:10:26 -0700358 # Create new archive.
359 compatibility_archive = tempfile.NamedTemporaryFile()
360 compatibility_archive_zip = zipfile.ZipFile(compatibility_archive, "w",
361 compression=zipfile.ZIP_DEFLATED)
Tao Bao21803d32017-04-19 10:16:09 -0700362
Tao Baobcd1d162017-08-26 13:10:26 -0700363 # Add metadata.
364 for file_name in compatibility_files:
365 target_file_name = "META/" + file_name
Tao Bao21803d32017-04-19 10:16:09 -0700366
Tao Baobcd1d162017-08-26 13:10:26 -0700367 if target_file_name in target_zip.namelist():
368 data = target_zip.read(target_file_name)
369 common.ZipWriteStr(compatibility_archive_zip, file_name, data)
Tao Bao21803d32017-04-19 10:16:09 -0700370
Tao Baobcd1d162017-08-26 13:10:26 -0700371 # Ensure files are written before we copy into output_zip.
372 compatibility_archive_zip.close()
373
374 # Only add the archive if we have any compatibility info.
375 if compatibility_archive_zip.namelist():
376 common.ZipWrite(output_zip, compatibility_archive.name,
377 arcname="compatibility.zip",
378 compress_type=zipfile.ZIP_STORED)
379
380 # Will only proceed if the target has enabled the Treble support (as well as
381 # having a /vendor partition).
382 if not HasTrebleEnabled(target_zip, target_info_dict):
383 return
384
385 # We don't support OEM thumbprint in Treble world (which calculates
386 # fingerprints in a different way as shown in CalculateFingerprint()).
387 assert not target_info_dict.get("oem_fingerprint_properties")
388
389 # Full OTA carries the info for system/vendor both.
390 if source_info_dict is None:
391 AddCompatibilityArchive(True, True)
392 return
393
394 assert not source_info_dict.get("oem_fingerprint_properties")
395
396 source_fp = GetBuildProp("ro.build.fingerprint", source_info_dict)
397 target_fp = GetBuildProp("ro.build.fingerprint", target_info_dict)
398 system_updated = source_fp != target_fp
399
400 source_fp_vendor = GetVendorBuildProp("ro.vendor.build.fingerprint",
401 source_info_dict)
402 target_fp_vendor = GetVendorBuildProp("ro.vendor.build.fingerprint",
403 target_info_dict)
404 vendor_updated = source_fp_vendor != target_fp_vendor
405
406 AddCompatibilityArchive(system_updated, vendor_updated)
Tao Bao21803d32017-04-19 10:16:09 -0700407
408
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700409def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700410 # TODO: how to determine this? We don't know what version it will
Tao Bao34b47bf2015-06-22 19:17:41 -0700411 # be installed on top of. For now, we expect the API just won't
412 # change very often. Similarly for fstab, it might have changed
413 # in the target build.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700414 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700415
Tao Bao838c68f2016-03-15 19:16:18 +0000416 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Tao Bao3e30d972016-03-15 13:20:19 -0700417 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800418 oem_dicts = None
Tao Bao3e30d972016-03-15 13:20:19 -0700419 if oem_props:
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800420 oem_dicts = _LoadOemDicts(script, recovery_mount_options)
Michael Runge6e836112014-04-15 17:40:21 -0700421
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800422 target_fp = CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
423 OPTIONS.info_dict)
Dan Albert8b72aef2015-03-23 19:13:21 -0700424 metadata = {
Tao Bao39f3eaf2017-03-09 15:01:11 -0800425 "post-build": target_fp,
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800426 "pre-device": GetOemProperty("ro.product.device", oem_props,
427 oem_dicts and oem_dicts[0],
Dan Albert8b72aef2015-03-23 19:13:21 -0700428 OPTIONS.info_dict),
429 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
430 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700431
Doug Zongker05d3dea2009-06-22 11:32:31 -0700432 device_specific = common.DeviceSpecificParams(
433 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700434 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700435 output_zip=output_zip,
436 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700437 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700438 metadata=metadata,
439 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700440
Tao Bao457cbf62017-03-06 09:56:01 -0800441 assert HasRecoveryPatch(input_zip)
Doug Zongkerc9253822014-02-04 12:17:58 -0800442
Tao Bao457cbf62017-03-06 09:56:01 -0800443 metadata["ota-type"] = "BLOCK"
Tao Baod8d14be2016-02-04 14:26:02 -0800444
Elliott Hughesd8a52f92016-06-20 14:35:47 -0700445 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
446 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
447 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700448
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800449 AppendAssertions(script, OPTIONS.info_dict, oem_dicts)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700450 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800451
452 # Two-step package strategy (in chronological order, which is *not*
453 # the order in which the generated script has things):
454 #
455 # if stage is not "2/3" or "3/3":
456 # write recovery image to boot partition
457 # set stage to "2/3"
458 # reboot to boot partition and restart recovery
459 # else if stage is "2/3":
460 # write recovery image to recovery partition
461 # set stage to "3/3"
462 # reboot to recovery partition and restart recovery
463 # else:
464 # (stage must be "3/3")
465 # set stage to ""
466 # do normal full package installation:
467 # wipe and install system, boot image, etc.
468 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700469 # complete script normally
470 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800471
472 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
473 OPTIONS.input_tmp, "RECOVERY")
474 if OPTIONS.two_step:
475 if not OPTIONS.info_dict.get("multistage_support", None):
476 assert False, "two-step packages not supported by this build"
477 fs = OPTIONS.info_dict["fstab"]["/misc"]
478 assert fs.fs_type.upper() == "EMMC", \
479 "two-step packages only supported on devices with EMMC /misc partitions"
480 bcb_dev = {"bcb_dev": fs.device}
481 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
482 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700483if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800484""" % bcb_dev)
Tao Baod42e97e2016-11-30 12:11:57 -0800485
486 # Stage 2/3: Write recovery image to /recovery (currently running /boot).
487 script.Comment("Stage 2/3")
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800488 script.WriteRawImage("/recovery", "recovery.img")
489 script.AppendExtra("""
490set_stage("%(bcb_dev)s", "3/3");
491reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700492else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800493""" % bcb_dev)
494
Tao Baod42e97e2016-11-30 12:11:57 -0800495 # Stage 3/3: Make changes.
496 script.Comment("Stage 3/3")
497
Tao Bao6c55a8a2015-04-08 15:30:27 -0700498 # Dump fingerprints
Tao Bao3e30d972016-03-15 13:20:19 -0700499 script.Print("Target: %s" % target_fp)
Tao Bao6c55a8a2015-04-08 15:30:27 -0700500
Doug Zongkere5ff5902012-01-17 10:55:37 -0800501 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700502
Doug Zongker01ce19c2014-02-04 13:48:15 -0800503 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700504
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700505 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800506 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700507 if HasVendorPartition(input_zip):
508 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700509
Michael Runge7cd99ba2014-10-22 17:21:48 -0700510 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
511
Doug Zongker4b9596f2014-06-09 14:15:45 -0700512 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800513
Tao Bao457cbf62017-03-06 09:56:01 -0800514 # Full OTA is done as an "incremental" against an empty source image. This
515 # has the effect of writing new data from the package to the entire
516 # partition, but lets us reuse the updater code that writes incrementals to
517 # do it.
518 system_tgt = GetImage("system", OPTIONS.input_tmp)
519 system_tgt.ResetFileMap()
520 system_diff = common.BlockDifference("system", system_tgt, src=None)
521 system_diff.WriteScript(script, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700522
Tao Bao7a5bf8a2015-07-21 18:01:20 -0700523 boot_img = common.GetBootableImage(
524 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800525
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700526 if HasVendorPartition(input_zip):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700527 script.ShowProgress(0.1, 0)
528
Tao Bao457cbf62017-03-06 09:56:01 -0800529 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp)
530 vendor_tgt.ResetFileMap()
531 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
532 vendor_diff.WriteScript(script, output_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700533
Tao Baobcd1d162017-08-26 13:10:26 -0700534 AddCompatibilityArchiveIfTrebleEnabled(input_zip, output_zip,
535 OPTIONS.info_dict)
536
Doug Zongker37974732010-09-16 17:44:38 -0700537 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700538 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700539
Doug Zongker01ce19c2014-02-04 13:48:15 -0800540 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700541 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700542
Doug Zongker01ce19c2014-02-04 13:48:15 -0800543 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700544 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700545
Doug Zongker1c390a22009-05-14 19:06:36 -0700546 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700547 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700548
Doug Zongker14833602010-02-02 13:12:04 -0800549 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800550
Doug Zongker922206e2014-03-04 13:16:24 -0800551 if OPTIONS.wipe_user_data:
552 script.ShowProgress(0.1, 10)
553 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700554
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800555 if OPTIONS.two_step:
556 script.AppendExtra("""
557set_stage("%(bcb_dev)s", "");
558""" % bcb_dev)
559 script.AppendExtra("else\n")
Tao Baod42e97e2016-11-30 12:11:57 -0800560
561 # Stage 1/3: Nothing to verify for full OTA. Write recovery image to /boot.
562 script.Comment("Stage 1/3")
563 _WriteRecoveryImageToBoot(script, output_zip)
564
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800565 script.AppendExtra("""
566set_stage("%(bcb_dev)s", "2/3");
567reboot_now("%(bcb_dev)s", "");
568endif;
569endif;
570""" % bcb_dev)
Tao Baod8d14be2016-02-04 14:26:02 -0800571
Tao Bao5d182562016-02-23 11:38:39 -0800572 script.SetProgress(1)
573 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -0800574 metadata["ota-required-cache"] = str(script.required_cache)
Doug Zongker2ea21062010-04-28 16:05:21 -0700575 WriteMetadata(metadata, output_zip)
576
Doug Zongkerfc44a512014-08-26 13:10:25 -0700577
Doug Zongker2ea21062010-04-28 16:05:21 -0700578def WriteMetadata(metadata, output_zip):
Tao Bao2dd1c482017-02-03 16:49:39 -0800579 value = "".join(["%s=%s\n" % kv for kv in sorted(metadata.iteritems())])
580 common.ZipWriteStr(output_zip, METADATA_NAME, value,
581 compress_type=zipfile.ZIP_STORED)
Doug Zongkereef39442009-04-02 12:14:19 -0700582
Doug Zongkerfc44a512014-08-26 13:10:25 -0700583
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700584def GetBuildProp(prop, info_dict):
Tao Baobcd1d162017-08-26 13:10:26 -0700585 """Returns the inquired build property from a given info_dict."""
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700586 try:
587 return info_dict.get("build.prop", {})[prop]
588 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700589 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700590
Doug Zongkerfc44a512014-08-26 13:10:25 -0700591
Tao Baobcd1d162017-08-26 13:10:26 -0700592def GetVendorBuildProp(prop, info_dict):
593 """Returns the inquired vendor build property from a given info_dict."""
594 try:
595 return info_dict.get("vendor.build.prop", {})[prop]
596 except KeyError:
597 raise common.ExternalError(
598 "couldn't find %s in vendor.build.prop" % (prop,))
599
600
Tao Baob31892e2017-02-07 11:21:17 -0800601def HandleDowngradeMetadata(metadata):
602 # Only incremental OTAs are allowed to reach here.
603 assert OPTIONS.incremental_source is not None
604
605 post_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict)
606 pre_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
607 is_downgrade = long(post_timestamp) < long(pre_timestamp)
608
609 if OPTIONS.downgrade:
Tao Baob31892e2017-02-07 11:21:17 -0800610 if not is_downgrade:
611 raise RuntimeError("--downgrade specified but no downgrade detected: "
612 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
Tao Bao3e6161a2017-02-28 11:48:48 -0800613 metadata["ota-downgrade"] = "yes"
614 elif OPTIONS.timestamp:
615 if not is_downgrade:
616 raise RuntimeError("--timestamp specified but no timestamp hack needed: "
617 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
618 metadata["post-timestamp"] = str(long(pre_timestamp) + 1)
Tao Baob31892e2017-02-07 11:21:17 -0800619 else:
620 if is_downgrade:
Tao Bao3e6161a2017-02-28 11:48:48 -0800621 raise RuntimeError("Downgrade detected based on timestamp check: "
622 "pre: %s, post: %s. Need to specify --timestamp OR "
623 "--downgrade to allow building the incremental." % (
624 pre_timestamp, post_timestamp))
Tao Baob31892e2017-02-07 11:21:17 -0800625 metadata["post-timestamp"] = post_timestamp
626
627
Geremy Condra36bd3652014-02-06 19:45:10 -0800628def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
629 source_version = OPTIONS.source_info_dict["recovery_api_version"]
630 target_version = OPTIONS.target_info_dict["recovery_api_version"]
631
632 if source_version == 0:
Tao Bao3e30d972016-03-15 13:20:19 -0700633 print("WARNING: generating edify script for a source that "
634 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -0700635 script = edify_generator.EdifyGenerator(
636 source_version, OPTIONS.target_info_dict,
637 fstab=OPTIONS.source_info_dict["fstab"])
Geremy Condra36bd3652014-02-06 19:45:10 -0800638
Tao Bao3806c232015-07-05 21:08:33 -0700639 recovery_mount_options = OPTIONS.source_info_dict.get(
640 "recovery_mount_options")
Tao Bao3e30d972016-03-15 13:20:19 -0700641 source_oem_props = OPTIONS.source_info_dict.get("oem_fingerprint_properties")
642 target_oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800643 oem_dicts = None
644 if source_oem_props and target_oem_props:
645 oem_dicts = _LoadOemDicts(script, recovery_mount_options)
Tao Bao3806c232015-07-05 21:08:33 -0700646
Dan Albert8b72aef2015-03-23 19:13:21 -0700647 metadata = {
Tao Bao3e30d972016-03-15 13:20:19 -0700648 "pre-device": GetOemProperty("ro.product.device", source_oem_props,
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800649 oem_dicts and oem_dicts[0],
650 OPTIONS.source_info_dict),
Tao Baod8d14be2016-02-04 14:26:02 -0800651 "ota-type": "BLOCK",
Dan Albert8b72aef2015-03-23 19:13:21 -0700652 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800653
Tao Baob31892e2017-02-07 11:21:17 -0800654 HandleDowngradeMetadata(metadata)
Tao Bao5d182562016-02-23 11:38:39 -0800655
Geremy Condra36bd3652014-02-06 19:45:10 -0800656 device_specific = common.DeviceSpecificParams(
657 source_zip=source_zip,
658 source_version=source_version,
659 target_zip=target_zip,
660 target_version=target_version,
661 output_zip=output_zip,
662 script=script,
663 metadata=metadata,
Tao Bao6f0b2192015-10-13 16:37:12 -0700664 info_dict=OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800665
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800666 source_fp = CalculateFingerprint(source_oem_props, oem_dicts and oem_dicts[0],
Tao Bao3806c232015-07-05 21:08:33 -0700667 OPTIONS.source_info_dict)
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800668 target_fp = CalculateFingerprint(target_oem_props, oem_dicts and oem_dicts[0],
Tao Bao3806c232015-07-05 21:08:33 -0700669 OPTIONS.target_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800670 metadata["pre-build"] = source_fp
671 metadata["post-build"] = target_fp
Tianjie Xud06f07e2016-06-09 14:18:45 -0700672 metadata["pre-build-incremental"] = GetBuildProp(
673 "ro.build.version.incremental", OPTIONS.source_info_dict)
674 metadata["post-build-incremental"] = GetBuildProp(
675 "ro.build.version.incremental", OPTIONS.target_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800676
677 source_boot = common.GetBootableImage(
678 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
679 OPTIONS.source_info_dict)
680 target_boot = common.GetBootableImage(
681 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
682 updating_boot = (not OPTIONS.two_step and
683 (source_boot.data != target_boot.data))
684
Geremy Condra36bd3652014-02-06 19:45:10 -0800685 target_recovery = common.GetBootableImage(
686 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800687
Tao Bao7e0f1602017-03-06 15:50:08 -0800688 system_src = GetImage("system", OPTIONS.source_tmp)
689 system_tgt = GetImage("system", OPTIONS.target_tmp)
Tao Baodd2a5892015-03-12 12:32:37 -0700690
691 blockimgdiff_version = 1
692 if OPTIONS.info_dict:
693 blockimgdiff_version = max(
694 int(i) for i in
695 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
696
Tao Baof8acad12016-07-07 09:09:58 -0700697 # Check the first block of the source system partition for remount R/W only
698 # if the filesystem is ext4.
699 system_src_partition = OPTIONS.source_info_dict["fstab"]["/system"]
700 check_first_block = system_src_partition.fs_type == "ext4"
Tao Bao293fd132016-06-11 12:19:23 -0700701 # Disable using imgdiff for squashfs. 'imgdiff -z' expects input files to be
702 # in zip formats. However with squashfs, a) all files are compressed in LZ4;
703 # b) the blocks listed in block map may not contain all the bytes for a given
704 # file (because they're rounded to be 4K-aligned).
Tao Baof8acad12016-07-07 09:09:58 -0700705 system_tgt_partition = OPTIONS.target_info_dict["fstab"]["/system"]
706 disable_imgdiff = (system_src_partition.fs_type == "squashfs" or
707 system_tgt_partition.fs_type == "squashfs")
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700708 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tianjie Xufc3422a2015-12-15 11:53:59 -0800709 check_first_block,
Tao Bao293fd132016-06-11 12:19:23 -0700710 version=blockimgdiff_version,
711 disable_imgdiff=disable_imgdiff)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700712
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700713 if HasVendorPartition(target_zip):
714 if not HasVendorPartition(source_zip):
715 raise RuntimeError("can't generate incremental that adds /vendor")
Tao Bao7e0f1602017-03-06 15:50:08 -0800716 vendor_src = GetImage("vendor", OPTIONS.source_tmp)
717 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp)
Tianjie Xufc3422a2015-12-15 11:53:59 -0800718
719 # Check first block of vendor partition for remount R/W only if
720 # disk type is ext4
721 vendor_partition = OPTIONS.source_info_dict["fstab"]["/vendor"]
Tao Baod8d14be2016-02-04 14:26:02 -0800722 check_first_block = vendor_partition.fs_type == "ext4"
Tao Bao293fd132016-06-11 12:19:23 -0700723 disable_imgdiff = vendor_partition.fs_type == "squashfs"
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700724 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tianjie Xufc3422a2015-12-15 11:53:59 -0800725 check_first_block,
Tao Bao293fd132016-06-11 12:19:23 -0700726 version=blockimgdiff_version,
727 disable_imgdiff=disable_imgdiff)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700728 else:
729 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800730
Tao Baobcd1d162017-08-26 13:10:26 -0700731 AddCompatibilityArchiveIfTrebleEnabled(
732 target_zip, output_zip, OPTIONS.target_info_dict,
733 OPTIONS.source_info_dict)
734
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800735 AppendAssertions(script, OPTIONS.target_info_dict, oem_dicts)
Geremy Condra36bd3652014-02-06 19:45:10 -0800736 device_specific.IncrementalOTA_Assertions()
737
738 # Two-step incremental package strategy (in chronological order,
739 # which is *not* the order in which the generated script has
740 # things):
741 #
742 # if stage is not "2/3" or "3/3":
743 # do verification on current system
744 # write recovery image to boot partition
745 # set stage to "2/3"
746 # reboot to boot partition and restart recovery
747 # else if stage is "2/3":
748 # write recovery image to recovery partition
749 # set stage to "3/3"
750 # reboot to recovery partition and restart recovery
751 # else:
752 # (stage must be "3/3")
753 # perform update:
754 # patch system files, etc.
755 # force full install of new boot image
756 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700757 # complete script normally
758 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800759
760 if OPTIONS.two_step:
Tao Baodd24da92015-07-29 14:09:23 -0700761 if not OPTIONS.source_info_dict.get("multistage_support", None):
Geremy Condra36bd3652014-02-06 19:45:10 -0800762 assert False, "two-step packages not supported by this build"
Tao Baodd24da92015-07-29 14:09:23 -0700763 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Geremy Condra36bd3652014-02-06 19:45:10 -0800764 assert fs.fs_type.upper() == "EMMC", \
765 "two-step packages only supported on devices with EMMC /misc partitions"
766 bcb_dev = {"bcb_dev": fs.device}
767 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
768 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700769if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800770""" % bcb_dev)
Tao Baod42e97e2016-11-30 12:11:57 -0800771
772 # Stage 2/3: Write recovery image to /recovery (currently running /boot).
773 script.Comment("Stage 2/3")
Dan Albert8b72aef2015-03-23 19:13:21 -0700774 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800775 script.WriteRawImage("/recovery", "recovery.img")
776 script.AppendExtra("""
777set_stage("%(bcb_dev)s", "3/3");
778reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700779else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800780""" % bcb_dev)
781
Tao Baod42e97e2016-11-30 12:11:57 -0800782 # Stage 1/3: (a) Verify the current system.
783 script.Comment("Stage 1/3")
784
Tao Bao6c55a8a2015-04-08 15:30:27 -0700785 # Dump fingerprints
Tao Baof9023852016-12-14 11:53:38 -0800786 script.Print("Source: %s" % (source_fp,))
787 script.Print("Target: %s" % (target_fp,))
Tao Bao6c55a8a2015-04-08 15:30:27 -0700788
Geremy Condra36bd3652014-02-06 19:45:10 -0800789 script.Print("Verifying current system...")
790
791 device_specific.IncrementalOTA_VerifyBegin()
792
Tao Bao3e30d972016-03-15 13:20:19 -0700793 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
794 # patching on a device that's already on the target build will damage the
795 # system. Because operations like move don't check the block state, they
796 # always apply the changes unconditionally.
797 if blockimgdiff_version <= 2:
798 if source_oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700799 script.AssertSomeFingerprint(source_fp)
800 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700801 script.AssertSomeThumbprint(
802 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Tao Bao3e30d972016-03-15 13:20:19 -0700803
804 else: # blockimgdiff_version > 2
805 if source_oem_props is None and target_oem_props is None:
806 script.AssertSomeFingerprint(source_fp, target_fp)
807 elif source_oem_props is not None and target_oem_props is not None:
Tao Baodd2a5892015-03-12 12:32:37 -0700808 script.AssertSomeThumbprint(
809 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
810 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Tao Bao3e30d972016-03-15 13:20:19 -0700811 elif source_oem_props is None and target_oem_props is not None:
812 script.AssertFingerprintOrThumbprint(
813 source_fp,
814 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict))
815 else:
816 script.AssertFingerprintOrThumbprint(
817 target_fp,
818 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800819
Tao Baod8d14be2016-02-04 14:26:02 -0800820 # Check the required cache size (i.e. stashed blocks).
821 size = []
822 if system_diff:
823 size.append(system_diff.required_cache)
824 if vendor_diff:
825 size.append(vendor_diff.required_cache)
826
Geremy Condra36bd3652014-02-06 19:45:10 -0800827 if updating_boot:
Tao Baodd24da92015-07-29 14:09:23 -0700828 boot_type, boot_device = common.GetTypeAndDevice(
829 "/boot", OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800830 d = common.Difference(target_boot, source_boot)
831 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700832 if d is None:
833 include_full_boot = True
834 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
835 else:
836 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800837
Tao Bao89fbb0f2017-01-10 10:47:58 -0800838 print("boot target: %d source: %d diff: %d" % (
839 target_boot.size, source_boot.size, len(d)))
Geremy Condra36bd3652014-02-06 19:45:10 -0800840
Doug Zongkerf8340082014-08-05 10:39:37 -0700841 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800842
Doug Zongkerf8340082014-08-05 10:39:37 -0700843 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
844 (boot_type, boot_device,
845 source_boot.size, source_boot.sha1,
846 target_boot.size, target_boot.sha1))
Tao Baod8d14be2016-02-04 14:26:02 -0800847 size.append(target_boot.size)
848
849 if size:
850 script.CacheFreeSpaceCheck(max(size))
Geremy Condra36bd3652014-02-06 19:45:10 -0800851
852 device_specific.IncrementalOTA_VerifyEnd()
853
854 if OPTIONS.two_step:
Tao Baod42e97e2016-11-30 12:11:57 -0800855 # Stage 1/3: (b) Write recovery image to /boot.
856 _WriteRecoveryImageToBoot(script, output_zip)
857
Geremy Condra36bd3652014-02-06 19:45:10 -0800858 script.AppendExtra("""
859set_stage("%(bcb_dev)s", "2/3");
860reboot_now("%(bcb_dev)s", "");
861else
862""" % bcb_dev)
863
Tao Baod42e97e2016-11-30 12:11:57 -0800864 # Stage 3/3: Make changes.
865 script.Comment("Stage 3/3")
866
Jesse Zhao75bcea02015-01-06 10:59:53 -0800867 # Verify the existing partitions.
Tao Baod522bdc2016-04-12 15:53:16 -0700868 system_diff.WriteVerifyScript(script, touched_blocks_only=True)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800869 if vendor_diff:
Tao Baod522bdc2016-04-12 15:53:16 -0700870 vendor_diff.WriteVerifyScript(script, touched_blocks_only=True)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800871
Geremy Condra36bd3652014-02-06 19:45:10 -0800872 script.Comment("---- start making changes here ----")
873
874 device_specific.IncrementalOTA_InstallBegin()
875
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700876 system_diff.WriteScript(script, output_zip,
877 progress=0.8 if vendor_diff else 0.9)
Tao Bao68658c02015-06-01 13:40:49 -0700878
Doug Zongkerfc44a512014-08-26 13:10:25 -0700879 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700880 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800881
882 if OPTIONS.two_step:
883 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
884 script.WriteRawImage("/boot", "boot.img")
Tao Bao89fbb0f2017-01-10 10:47:58 -0800885 print("writing full boot image (forced by two-step mode)")
Geremy Condra36bd3652014-02-06 19:45:10 -0800886
887 if not OPTIONS.two_step:
888 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700889 if include_full_boot:
Tao Bao89fbb0f2017-01-10 10:47:58 -0800890 print("boot image changed; including full.")
Doug Zongkerf8340082014-08-05 10:39:37 -0700891 script.Print("Installing boot image...")
892 script.WriteRawImage("/boot", "boot.img")
893 else:
894 # Produce the boot image by applying a patch to the current
895 # contents of the boot partition, and write it back to the
896 # partition.
Tao Bao89fbb0f2017-01-10 10:47:58 -0800897 print("boot image changed; including patch.")
Doug Zongkerf8340082014-08-05 10:39:37 -0700898 script.Print("Patching boot image...")
899 script.ShowProgress(0.1, 10)
900 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
901 % (boot_type, boot_device,
902 source_boot.size, source_boot.sha1,
903 target_boot.size, target_boot.sha1),
904 "-",
905 target_boot.size, target_boot.sha1,
906 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800907 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -0800908 print("boot image unchanged; skipping.")
Geremy Condra36bd3652014-02-06 19:45:10 -0800909
910 # Do device-specific installation (eg, write radio image).
911 device_specific.IncrementalOTA_InstallEnd()
912
913 if OPTIONS.extra_script is not None:
914 script.AppendExtra(OPTIONS.extra_script)
915
Doug Zongker922206e2014-03-04 13:16:24 -0800916 if OPTIONS.wipe_user_data:
917 script.Print("Erasing user data...")
918 script.FormatPartition("/data")
Tao Bao5d182562016-02-23 11:38:39 -0800919 metadata["ota-wipe"] = "yes"
Doug Zongker922206e2014-03-04 13:16:24 -0800920
Geremy Condra36bd3652014-02-06 19:45:10 -0800921 if OPTIONS.two_step:
922 script.AppendExtra("""
923set_stage("%(bcb_dev)s", "");
924endif;
925endif;
926""" % bcb_dev)
927
928 script.SetProgress(1)
Tao Bao4996cf02016-03-08 17:53:39 -0800929 # For downgrade OTAs, we prefer to use the update-binary in the source
930 # build that is actually newer than the one in the target build.
931 if OPTIONS.downgrade:
932 script.AddToZip(source_zip, output_zip, input_path=OPTIONS.updater_binary)
933 else:
934 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -0800935 metadata["ota-required-cache"] = str(script.required_cache)
Geremy Condra36bd3652014-02-06 19:45:10 -0800936 WriteMetadata(metadata, output_zip)
937
Doug Zongker32b527d2014-03-04 10:03:02 -0800938
Tao Bao9bc6bb22015-11-09 16:58:28 -0800939def WriteVerifyPackage(input_zip, output_zip):
940 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
941
942 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
943 recovery_mount_options = OPTIONS.info_dict.get(
944 "recovery_mount_options")
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800945 oem_dicts = None
Tao Bao3e30d972016-03-15 13:20:19 -0700946 if oem_props:
Tao Baoebce6972017-03-06 10:22:20 -0800947 oem_dicts = _LoadOemDicts(script, recovery_mount_options)
Tao Bao9bc6bb22015-11-09 16:58:28 -0800948
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800949 target_fp = CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
950 OPTIONS.info_dict)
Tao Bao9bc6bb22015-11-09 16:58:28 -0800951 metadata = {
952 "post-build": target_fp,
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800953 "pre-device": GetOemProperty("ro.product.device", oem_props,
954 oem_dicts and oem_dicts[0],
Tao Bao9bc6bb22015-11-09 16:58:28 -0800955 OPTIONS.info_dict),
956 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
957 }
958
959 device_specific = common.DeviceSpecificParams(
960 input_zip=input_zip,
961 input_version=OPTIONS.info_dict["recovery_api_version"],
962 output_zip=output_zip,
963 script=script,
964 input_tmp=OPTIONS.input_tmp,
965 metadata=metadata,
966 info_dict=OPTIONS.info_dict)
967
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800968 AppendAssertions(script, OPTIONS.info_dict, oem_dicts)
Tao Bao9bc6bb22015-11-09 16:58:28 -0800969
970 script.Print("Verifying device images against %s..." % target_fp)
971 script.AppendExtra("")
972
973 script.Print("Verifying boot...")
974 boot_img = common.GetBootableImage(
975 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
976 boot_type, boot_device = common.GetTypeAndDevice(
977 "/boot", OPTIONS.info_dict)
978 script.Verify("%s:%s:%d:%s" % (
979 boot_type, boot_device, boot_img.size, boot_img.sha1))
980 script.AppendExtra("")
981
982 script.Print("Verifying recovery...")
983 recovery_img = common.GetBootableImage(
984 "recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
985 recovery_type, recovery_device = common.GetTypeAndDevice(
986 "/recovery", OPTIONS.info_dict)
987 script.Verify("%s:%s:%d:%s" % (
988 recovery_type, recovery_device, recovery_img.size, recovery_img.sha1))
989 script.AppendExtra("")
990
Tao Bao7e0f1602017-03-06 15:50:08 -0800991 system_tgt = GetImage("system", OPTIONS.input_tmp)
Tao Bao9bc6bb22015-11-09 16:58:28 -0800992 system_tgt.ResetFileMap()
993 system_diff = common.BlockDifference("system", system_tgt, src=None)
994 system_diff.WriteStrictVerifyScript(script)
995
996 if HasVendorPartition(input_zip):
Tao Bao7e0f1602017-03-06 15:50:08 -0800997 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp)
Tao Bao9bc6bb22015-11-09 16:58:28 -0800998 vendor_tgt.ResetFileMap()
999 vendor_diff = common.BlockDifference("vendor", vendor_tgt, src=None)
1000 vendor_diff.WriteStrictVerifyScript(script)
1001
1002 # Device specific partitions, such as radio, bootloader and etc.
1003 device_specific.VerifyOTA_Assertions()
1004
1005 script.SetProgress(1.0)
1006 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -08001007 metadata["ota-required-cache"] = str(script.required_cache)
Tao Bao9bc6bb22015-11-09 16:58:28 -08001008 WriteMetadata(metadata, output_zip)
1009
1010
Tao Baoc098e9e2016-01-07 13:03:56 -08001011def WriteABOTAPackageWithBrilloScript(target_file, output_file,
1012 source_file=None):
1013 """Generate an Android OTA package that has A/B update payload."""
1014
Tao Bao2dd1c482017-02-03 16:49:39 -08001015 def ComputeStreamingMetadata(zip_file, reserve_space=False,
1016 expected_length=None):
1017 """Compute the streaming metadata for a given zip.
1018
1019 When 'reserve_space' is True, we reserve extra space for the offset and
1020 length of the metadata entry itself, although we don't know the final
1021 values until the package gets signed. This function will be called again
1022 after signing. We then write the actual values and pad the string to the
1023 length we set earlier. Note that we can't use the actual length of the
1024 metadata entry in the second run. Otherwise the offsets for other entries
1025 will be changing again.
1026 """
Tao Baoc96316c2017-01-24 22:10:49 -08001027
1028 def ComputeEntryOffsetSize(name):
1029 """Compute the zip entry offset and size."""
1030 info = zip_file.getinfo(name)
1031 offset = info.header_offset + len(info.FileHeader())
1032 size = info.file_size
Tao Bao2dd1c482017-02-03 16:49:39 -08001033 return '%s:%d:%d' % (os.path.basename(name), offset, size)
Tao Baoc96316c2017-01-24 22:10:49 -08001034
1035 # payload.bin and payload_properties.txt must exist.
1036 offsets = [ComputeEntryOffsetSize('payload.bin'),
1037 ComputeEntryOffsetSize('payload_properties.txt')]
1038
1039 # care_map.txt is available only if dm-verity is enabled.
1040 if 'care_map.txt' in zip_file.namelist():
1041 offsets.append(ComputeEntryOffsetSize('care_map.txt'))
Tao Bao2dd1c482017-02-03 16:49:39 -08001042
Tao Bao21803d32017-04-19 10:16:09 -07001043 if 'compatibility.zip' in zip_file.namelist():
1044 offsets.append(ComputeEntryOffsetSize('compatibility.zip'))
1045
Tao Bao2dd1c482017-02-03 16:49:39 -08001046 # 'META-INF/com/android/metadata' is required. We don't know its actual
1047 # offset and length (as well as the values for other entries). So we
1048 # reserve 10-byte as a placeholder, which is to cover the space for metadata
1049 # entry ('xx:xxx', since it's ZIP_STORED which should appear at the
1050 # beginning of the zip), as well as the possible value changes in other
1051 # entries.
1052 if reserve_space:
1053 offsets.append('metadata:' + ' ' * 10)
1054 else:
1055 offsets.append(ComputeEntryOffsetSize(METADATA_NAME))
1056
1057 value = ','.join(offsets)
1058 if expected_length is not None:
1059 assert len(value) <= expected_length, \
1060 'Insufficient reserved space: reserved=%d, actual=%d' % (
1061 expected_length, len(value))
1062 value += ' ' * (expected_length - len(value))
1063 return value
Tao Baoc96316c2017-01-24 22:10:49 -08001064
Alex Deymod8d96ec2016-06-10 16:38:31 -07001065 # The place where the output from the subprocess should go.
1066 log_file = sys.stdout if OPTIONS.verbose else subprocess.PIPE
1067
Tao Baodea0f8b2016-06-20 17:55:06 -07001068 # A/B updater expects a signing key in RSA format. Gets the key ready for
1069 # later use in step 3, unless a payload_signer has been specified.
1070 if OPTIONS.payload_signer is None:
1071 cmd = ["openssl", "pkcs8",
1072 "-in", OPTIONS.package_key + OPTIONS.private_key_suffix,
Christian Oderf63e2cd2017-05-01 22:30:15 +02001073 "-inform", "DER"]
1074 pw = OPTIONS.key_passwords[OPTIONS.package_key]
1075 cmd.extend(["-passin", "pass:" + pw] if pw else ["-nocrypt"])
Tao Baodea0f8b2016-06-20 17:55:06 -07001076 rsa_key = common.MakeTempFile(prefix="key-", suffix=".key")
1077 cmd.extend(["-out", rsa_key])
Christian Oderf63e2cd2017-05-01 22:30:15 +02001078 p1 = common.Run(cmd, verbose=False, stdout=log_file, stderr=subprocess.STDOUT)
Tao Bao6047c242016-06-21 13:35:26 -07001079 p1.communicate()
Tao Baodea0f8b2016-06-20 17:55:06 -07001080 assert p1.returncode == 0, "openssl pkcs8 failed"
Tao Baoc098e9e2016-01-07 13:03:56 -08001081
Tao Baodea0f8b2016-06-20 17:55:06 -07001082 # Stage the output zip package for package signing.
Tao Baoc098e9e2016-01-07 13:03:56 -08001083 temp_zip_file = tempfile.NamedTemporaryFile()
1084 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1085 compression=zipfile.ZIP_DEFLATED)
1086
1087 # Metadata to comply with Android OTA package format.
1088 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties", None)
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -08001089 oem_dicts = None
Tao Baoc098e9e2016-01-07 13:03:56 -08001090 if oem_props:
Tao Baoebce6972017-03-06 10:22:20 -08001091 oem_dicts = _LoadOemDicts(None)
Tao Baoc098e9e2016-01-07 13:03:56 -08001092
1093 metadata = {
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -08001094 "post-build": CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
Tao Baoc098e9e2016-01-07 13:03:56 -08001095 OPTIONS.info_dict),
Tianjie Xud06f07e2016-06-09 14:18:45 -07001096 "post-build-incremental" : GetBuildProp("ro.build.version.incremental",
1097 OPTIONS.info_dict),
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -08001098 "pre-device": GetOemProperty("ro.product.device", oem_props,
1099 oem_dicts and oem_dicts[0],
Tao Baoc098e9e2016-01-07 13:03:56 -08001100 OPTIONS.info_dict),
Tao Baod8d14be2016-02-04 14:26:02 -08001101 "ota-required-cache": "0",
1102 "ota-type": "AB",
Tao Baoc098e9e2016-01-07 13:03:56 -08001103 }
1104
1105 if source_file is not None:
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -08001106 metadata["pre-build"] = CalculateFingerprint(oem_props,
1107 oem_dicts and oem_dicts[0],
Tao Baoc098e9e2016-01-07 13:03:56 -08001108 OPTIONS.source_info_dict)
Tianjie Xud06f07e2016-06-09 14:18:45 -07001109 metadata["pre-build-incremental"] = GetBuildProp(
1110 "ro.build.version.incremental", OPTIONS.source_info_dict)
Tao Baoc098e9e2016-01-07 13:03:56 -08001111
Tao Baob31892e2017-02-07 11:21:17 -08001112 HandleDowngradeMetadata(metadata)
1113 else:
1114 metadata["post-timestamp"] = GetBuildProp(
1115 "ro.build.date.utc", OPTIONS.info_dict)
1116
Tao Baoc098e9e2016-01-07 13:03:56 -08001117 # 1. Generate payload.
1118 payload_file = common.MakeTempFile(prefix="payload-", suffix=".bin")
1119 cmd = ["brillo_update_payload", "generate",
1120 "--payload", payload_file,
1121 "--target_image", target_file]
1122 if source_file is not None:
1123 cmd.extend(["--source_image", source_file])
Alex Deymod8d96ec2016-06-10 16:38:31 -07001124 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1125 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001126 assert p1.returncode == 0, "brillo_update_payload generate failed"
1127
1128 # 2. Generate hashes of the payload and metadata files.
1129 payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
1130 metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
1131 cmd = ["brillo_update_payload", "hash",
1132 "--unsigned_payload", payload_file,
1133 "--signature_size", "256",
1134 "--metadata_hash_file", metadata_sig_file,
1135 "--payload_hash_file", payload_sig_file]
Alex Deymod8d96ec2016-06-10 16:38:31 -07001136 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1137 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001138 assert p1.returncode == 0, "brillo_update_payload hash failed"
1139
1140 # 3. Sign the hashes and insert them back into the payload file.
1141 signed_payload_sig_file = common.MakeTempFile(prefix="signed-sig-",
1142 suffix=".bin")
1143 signed_metadata_sig_file = common.MakeTempFile(prefix="signed-sig-",
1144 suffix=".bin")
1145 # 3a. Sign the payload hash.
Tao Baodea0f8b2016-06-20 17:55:06 -07001146 if OPTIONS.payload_signer is not None:
Baligh Uddin2abbbd02016-06-22 12:14:16 -07001147 cmd = [OPTIONS.payload_signer]
1148 cmd.extend(OPTIONS.payload_signer_args)
Tao Baodea0f8b2016-06-20 17:55:06 -07001149 else:
1150 cmd = ["openssl", "pkeyutl", "-sign",
1151 "-inkey", rsa_key,
1152 "-pkeyopt", "digest:sha256"]
1153 cmd.extend(["-in", payload_sig_file,
1154 "-out", signed_payload_sig_file])
Alex Deymod8d96ec2016-06-10 16:38:31 -07001155 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1156 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001157 assert p1.returncode == 0, "openssl sign payload failed"
1158
1159 # 3b. Sign the metadata hash.
Tao Baodea0f8b2016-06-20 17:55:06 -07001160 if OPTIONS.payload_signer is not None:
Baligh Uddin2abbbd02016-06-22 12:14:16 -07001161 cmd = [OPTIONS.payload_signer]
1162 cmd.extend(OPTIONS.payload_signer_args)
Tao Baodea0f8b2016-06-20 17:55:06 -07001163 else:
1164 cmd = ["openssl", "pkeyutl", "-sign",
1165 "-inkey", rsa_key,
1166 "-pkeyopt", "digest:sha256"]
1167 cmd.extend(["-in", metadata_sig_file,
1168 "-out", signed_metadata_sig_file])
Alex Deymod8d96ec2016-06-10 16:38:31 -07001169 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1170 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001171 assert p1.returncode == 0, "openssl sign metadata failed"
1172
1173 # 3c. Insert the signatures back into the payload file.
1174 signed_payload_file = common.MakeTempFile(prefix="signed-payload-",
1175 suffix=".bin")
1176 cmd = ["brillo_update_payload", "sign",
1177 "--unsigned_payload", payload_file,
1178 "--payload", signed_payload_file,
1179 "--signature_size", "256",
1180 "--metadata_signature_file", signed_metadata_sig_file,
1181 "--payload_signature_file", signed_payload_sig_file]
Alex Deymod8d96ec2016-06-10 16:38:31 -07001182 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1183 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001184 assert p1.returncode == 0, "brillo_update_payload sign failed"
1185
Alex Deymo19241c12016-02-04 22:29:29 -08001186 # 4. Dump the signed payload properties.
1187 properties_file = common.MakeTempFile(prefix="payload-properties-",
1188 suffix=".txt")
1189 cmd = ["brillo_update_payload", "properties",
1190 "--payload", signed_payload_file,
1191 "--properties_file", properties_file]
Alex Deymod8d96ec2016-06-10 16:38:31 -07001192 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1193 p1.communicate()
Alex Deymo19241c12016-02-04 22:29:29 -08001194 assert p1.returncode == 0, "brillo_update_payload properties failed"
1195
Tao Bao7c5dc572016-06-14 17:48:11 -07001196 if OPTIONS.wipe_user_data:
1197 with open(properties_file, "a") as f:
1198 f.write("POWERWASH=1\n")
1199 metadata["ota-wipe"] = "yes"
1200
Tao Baoc96316c2017-01-24 22:10:49 -08001201 # Add the signed payload file and properties into the zip. In order to
1202 # support streaming, we pack payload.bin, payload_properties.txt and
1203 # care_map.txt as ZIP_STORED. So these entries can be read directly with
1204 # the offset and length pairs.
Tao Baoc098e9e2016-01-07 13:03:56 -08001205 common.ZipWrite(output_zip, signed_payload_file, arcname="payload.bin",
1206 compress_type=zipfile.ZIP_STORED)
Tao Baoc96316c2017-01-24 22:10:49 -08001207 common.ZipWrite(output_zip, properties_file,
1208 arcname="payload_properties.txt",
1209 compress_type=zipfile.ZIP_STORED)
Tao Baoc098e9e2016-01-07 13:03:56 -08001210
Tianjie Xucfa86222016-03-07 16:31:19 -08001211 # If dm-verity is supported for the device, copy contents of care_map
1212 # into A/B OTA package.
Tao Bao21803d32017-04-19 10:16:09 -07001213 target_zip = zipfile.ZipFile(target_file, "r")
Tianjie Xu6b2e1552017-06-01 11:32:32 -07001214 if (OPTIONS.info_dict.get("verity") == "true" or
Bowgo Tsai3e599ea2017-05-26 18:30:04 +08001215 OPTIONS.info_dict.get("avb_enable") == "true"):
Tianjie Xucfa86222016-03-07 16:31:19 -08001216 care_map_path = "META/care_map.txt"
1217 namelist = target_zip.namelist()
1218 if care_map_path in namelist:
1219 care_map_data = target_zip.read(care_map_path)
Tao Baoc96316c2017-01-24 22:10:49 -08001220 common.ZipWriteStr(output_zip, "care_map.txt", care_map_data,
1221 compress_type=zipfile.ZIP_STORED)
Tianjie Xucfa86222016-03-07 16:31:19 -08001222 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001223 print("Warning: cannot find care map file in target_file package")
Tao Bao21803d32017-04-19 10:16:09 -07001224
Tao Baobcd1d162017-08-26 13:10:26 -07001225 # OPTIONS.source_info_dict must be None for incrementals.
1226 if source_file is None:
1227 assert OPTIONS.source_info_dict is None
Tao Bao21803d32017-04-19 10:16:09 -07001228
Tao Baobcd1d162017-08-26 13:10:26 -07001229 AddCompatibilityArchiveIfTrebleEnabled(
1230 target_zip, output_zip, OPTIONS.info_dict, OPTIONS.source_info_dict)
Tao Bao21803d32017-04-19 10:16:09 -07001231
Tao Bao21803d32017-04-19 10:16:09 -07001232 common.ZipClose(target_zip)
Tianjie Xucfa86222016-03-07 16:31:19 -08001233
Tao Bao2dd1c482017-02-03 16:49:39 -08001234 # Write the current metadata entry with placeholders.
Tao Baobfdcb122017-01-31 15:06:05 -08001235 metadata['ota-streaming-property-files'] = ComputeStreamingMetadata(
Tao Bao2dd1c482017-02-03 16:49:39 -08001236 output_zip, reserve_space=True)
Tao Baoc96316c2017-01-24 22:10:49 -08001237 WriteMetadata(metadata, output_zip)
1238 common.ZipClose(output_zip)
1239
Tao Bao2dd1c482017-02-03 16:49:39 -08001240 # SignOutput(), which in turn calls signapk.jar, will possibly reorder the
Tao Bao89d7ab22017-12-14 17:05:33 -08001241 # ZIP entries, as well as padding the entry headers. We do a preliminary
Tao Bao2dd1c482017-02-03 16:49:39 -08001242 # signing (with an incomplete metadata entry) to allow that to happen. Then
Tao Bao89d7ab22017-12-14 17:05:33 -08001243 # compute the ZIP entry offsets, write back the final metadata and do the
Tao Bao2dd1c482017-02-03 16:49:39 -08001244 # final signing.
Tao Bao89d7ab22017-12-14 17:05:33 -08001245 prelim_signing = common.MakeTempFile(suffix='.zip')
1246 SignOutput(temp_zip_file.name, prelim_signing)
Tao Bao2dd1c482017-02-03 16:49:39 -08001247 common.ZipClose(temp_zip_file)
Tao Baoc96316c2017-01-24 22:10:49 -08001248
Tao Bao2dd1c482017-02-03 16:49:39 -08001249 # Open the signed zip. Compute the final metadata that's needed for streaming.
Tao Bao89d7ab22017-12-14 17:05:33 -08001250 prelim_signing_zip = zipfile.ZipFile(prelim_signing, 'r')
Tao Bao2dd1c482017-02-03 16:49:39 -08001251 expected_length = len(metadata['ota-streaming-property-files'])
1252 metadata['ota-streaming-property-files'] = ComputeStreamingMetadata(
Tao Bao89d7ab22017-12-14 17:05:33 -08001253 prelim_signing_zip, reserve_space=False, expected_length=expected_length)
1254 common.ZipClose(prelim_signing_zip)
Tao Bao2dd1c482017-02-03 16:49:39 -08001255
Tao Bao89d7ab22017-12-14 17:05:33 -08001256 # Replace the METADATA entry.
1257 common.ZipDelete(prelim_signing, METADATA_NAME)
1258 output_zip = zipfile.ZipFile(prelim_signing, 'a',
Tao Bao2dd1c482017-02-03 16:49:39 -08001259 compression=zipfile.ZIP_DEFLATED)
Tao Bao2dd1c482017-02-03 16:49:39 -08001260 WriteMetadata(metadata, output_zip)
Tao Bao2dd1c482017-02-03 16:49:39 -08001261 common.ZipClose(output_zip)
1262
1263 # Re-sign the package after updating the metadata entry.
Tao Bao89d7ab22017-12-14 17:05:33 -08001264 SignOutput(prelim_signing, output_file)
Tao Bao2dd1c482017-02-03 16:49:39 -08001265
1266 # Reopen the final signed zip to double check the streaming metadata.
Tao Bao89d7ab22017-12-14 17:05:33 -08001267 output_zip = zipfile.ZipFile(output_file, 'r')
Tao Bao2dd1c482017-02-03 16:49:39 -08001268 actual = metadata['ota-streaming-property-files'].strip()
1269 expected = ComputeStreamingMetadata(output_zip)
1270 assert actual == expected, \
1271 "Mismatching streaming metadata: %s vs %s." % (actual, expected)
Tao Baoc96316c2017-01-24 22:10:49 -08001272 common.ZipClose(output_zip)
1273
Tao Baoc098e9e2016-01-07 13:03:56 -08001274
Doug Zongkereef39442009-04-02 12:14:19 -07001275def main(argv):
1276
1277 def option_handler(o, a):
Tao Bao4b76a0e2017-10-31 12:13:33 -07001278 if o in ("-k", "--package_key"):
Doug Zongkereef39442009-04-02 12:14:19 -07001279 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001280 elif o in ("-i", "--incremental_from"):
1281 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001282 elif o == "--full_radio":
1283 OPTIONS.full_radio = True
leozwangaa6c1a12015-08-14 10:57:58 -07001284 elif o == "--full_bootloader":
1285 OPTIONS.full_bootloader = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001286 elif o in ("-w", "--wipe_user_data"):
1287 OPTIONS.wipe_user_data = True
Tao Bao5d182562016-02-23 11:38:39 -08001288 elif o == "--downgrade":
1289 OPTIONS.downgrade = True
1290 OPTIONS.wipe_user_data = True
Tao Bao3e6161a2017-02-28 11:48:48 -08001291 elif o == "--override_timestamp":
1292 OPTIONS.timestamp = True
Michael Runge6e836112014-04-15 17:40:21 -07001293 elif o in ("-o", "--oem_settings"):
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -08001294 OPTIONS.oem_source = a.split(',')
Tao Bao8608cde2016-02-25 19:49:55 -08001295 elif o == "--oem_no_mount":
1296 OPTIONS.oem_no_mount = True
Doug Zongker1c390a22009-05-14 19:06:36 -07001297 elif o in ("-e", "--extra_script"):
1298 OPTIONS.extra_script = a
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001299 elif o in ("-t", "--worker_threads"):
1300 if a.isdigit():
1301 OPTIONS.worker_threads = int(a)
1302 else:
1303 raise ValueError("Cannot parse value %r for option %r - only "
1304 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001305 elif o in ("-2", "--two_step"):
1306 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001307 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001308 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001309 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001310 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001311 elif o == "--block":
1312 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001313 elif o in ("-b", "--binary"):
1314 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001315 elif o in ("--no_fallback_to_full",):
1316 OPTIONS.fallback_to_full = False
Tao Bao8dcf7382015-05-21 14:09:49 -07001317 elif o == "--stash_threshold":
1318 try:
1319 OPTIONS.stash_threshold = float(a)
1320 except ValueError:
1321 raise ValueError("Cannot parse value %r for option %r - expecting "
1322 "a float" % (a, o))
Tao Bao9bc6bb22015-11-09 16:58:28 -08001323 elif o == "--gen_verify":
1324 OPTIONS.gen_verify = True
Tao Baod62c6032015-11-30 09:40:20 -08001325 elif o == "--log_diff":
1326 OPTIONS.log_diff = a
Tao Baodea0f8b2016-06-20 17:55:06 -07001327 elif o == "--payload_signer":
1328 OPTIONS.payload_signer = a
Baligh Uddin2abbbd02016-06-22 12:14:16 -07001329 elif o == "--payload_signer_args":
1330 OPTIONS.payload_signer_args = shlex.split(a)
Dan Willemsencea5cd22017-03-21 14:44:27 -07001331 elif o == "--extracted_input_target_files":
1332 OPTIONS.extracted_input = a
Doug Zongkereef39442009-04-02 12:14:19 -07001333 else:
1334 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001335 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001336
1337 args = common.ParseOptions(argv, __doc__,
Tao Bao2a0d1da2017-01-13 11:56:54 -08001338 extra_opts="b:k:i:d:we:t:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001339 extra_long_opts=[
Dan Albert8b72aef2015-03-23 19:13:21 -07001340 "package_key=",
1341 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001342 "full_radio",
leozwangaa6c1a12015-08-14 10:57:58 -07001343 "full_bootloader",
Dan Albert8b72aef2015-03-23 19:13:21 -07001344 "wipe_user_data",
Tao Bao5d182562016-02-23 11:38:39 -08001345 "downgrade",
Tao Bao3e6161a2017-02-28 11:48:48 -08001346 "override_timestamp",
Dan Albert8b72aef2015-03-23 19:13:21 -07001347 "extra_script=",
1348 "worker_threads=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001349 "two_step",
1350 "no_signing",
1351 "block",
1352 "binary=",
1353 "oem_settings=",
Tao Bao8608cde2016-02-25 19:49:55 -08001354 "oem_no_mount",
Dan Albert8b72aef2015-03-23 19:13:21 -07001355 "verify",
1356 "no_fallback_to_full",
Tao Bao8dcf7382015-05-21 14:09:49 -07001357 "stash_threshold=",
Tao Baod62c6032015-11-30 09:40:20 -08001358 "gen_verify",
1359 "log_diff=",
Tao Baodea0f8b2016-06-20 17:55:06 -07001360 "payload_signer=",
Baligh Uddin2abbbd02016-06-22 12:14:16 -07001361 "payload_signer_args=",
Dan Willemsencea5cd22017-03-21 14:44:27 -07001362 "extracted_input_target_files=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001363 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001364
1365 if len(args) != 2:
1366 common.Usage(__doc__)
1367 sys.exit(1)
1368
Tao Bao5d182562016-02-23 11:38:39 -08001369 if OPTIONS.downgrade:
1370 # Sanity check to enforce a data wipe.
1371 if not OPTIONS.wipe_user_data:
1372 raise ValueError("Cannot downgrade without a data wipe")
1373
1374 # We should only allow downgrading incrementals (as opposed to full).
1375 # Otherwise the device may go back from arbitrary build with this full
1376 # OTA package.
1377 if OPTIONS.incremental_source is None:
Elliott Hughesd8a52f92016-06-20 14:35:47 -07001378 raise ValueError("Cannot generate downgradable full OTAs")
Tao Bao5d182562016-02-23 11:38:39 -08001379
Tao Bao3e6161a2017-02-28 11:48:48 -08001380 assert not (OPTIONS.downgrade and OPTIONS.timestamp), \
1381 "Cannot have --downgrade AND --override_timestamp both"
1382
Tao Baoc098e9e2016-01-07 13:03:56 -08001383 # Load the dict file from the zip directly to have a peek at the OTA type.
1384 # For packages using A/B update, unzipping is not needed.
Dan Willemsencea5cd22017-03-21 14:44:27 -07001385 if OPTIONS.extracted_input is not None:
1386 OPTIONS.info_dict = common.LoadInfoDict(OPTIONS.extracted_input, OPTIONS.extracted_input)
1387 else:
1388 input_zip = zipfile.ZipFile(args[0], "r")
1389 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
1390 common.ZipClose(input_zip)
Tao Baoc098e9e2016-01-07 13:03:56 -08001391
1392 ab_update = OPTIONS.info_dict.get("ab_update") == "true"
1393
Christian Oderf63e2cd2017-05-01 22:30:15 +02001394 # Use the default key to sign the package if not specified with package_key.
1395 # package_keys are needed on ab_updates, so always define them if an
1396 # ab_update is getting created.
1397 if not OPTIONS.no_signing or ab_update:
1398 if OPTIONS.package_key is None:
1399 OPTIONS.package_key = OPTIONS.info_dict.get(
1400 "default_system_dev_certificate",
1401 "build/target/product/security/testkey")
1402 # Get signing keys
1403 OPTIONS.key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
1404
Tao Baoc098e9e2016-01-07 13:03:56 -08001405 if ab_update:
1406 if OPTIONS.incremental_source is not None:
1407 OPTIONS.target_info_dict = OPTIONS.info_dict
1408 source_zip = zipfile.ZipFile(OPTIONS.incremental_source, "r")
1409 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1410 common.ZipClose(source_zip)
1411
1412 if OPTIONS.verbose:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001413 print("--- target info ---")
Tao Baoc098e9e2016-01-07 13:03:56 -08001414 common.DumpInfoDict(OPTIONS.info_dict)
1415
1416 if OPTIONS.incremental_source is not None:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001417 print("--- source info ---")
Tao Baoc098e9e2016-01-07 13:03:56 -08001418 common.DumpInfoDict(OPTIONS.source_info_dict)
1419
1420 WriteABOTAPackageWithBrilloScript(
1421 target_file=args[0],
1422 output_file=args[1],
1423 source_file=OPTIONS.incremental_source)
1424
Tao Bao89fbb0f2017-01-10 10:47:58 -08001425 print("done.")
Tao Baoc098e9e2016-01-07 13:03:56 -08001426 return
1427
Doug Zongker1c390a22009-05-14 19:06:36 -07001428 if OPTIONS.extra_script is not None:
1429 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1430
Dan Willemsencea5cd22017-03-21 14:44:27 -07001431 if OPTIONS.extracted_input is not None:
1432 OPTIONS.input_tmp = OPTIONS.extracted_input
1433 OPTIONS.target_tmp = OPTIONS.input_tmp
1434 OPTIONS.info_dict = common.LoadInfoDict(OPTIONS.input_tmp, OPTIONS.input_tmp)
1435 input_zip = zipfile.ZipFile(args[0], "r")
1436 else:
1437 print("unzipping target target-files...")
1438 OPTIONS.input_tmp, input_zip = common.UnzipTemp(
1439 args[0], UNZIP_PATTERN)
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001440
Dan Willemsencea5cd22017-03-21 14:44:27 -07001441 OPTIONS.target_tmp = OPTIONS.input_tmp
1442 OPTIONS.info_dict = common.LoadInfoDict(input_zip, OPTIONS.target_tmp)
Kenny Roote2e9f612013-05-29 12:59:35 -07001443
Doug Zongker37974732010-09-16 17:44:38 -07001444 if OPTIONS.verbose:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001445 print("--- target info ---")
Doug Zongker37974732010-09-16 17:44:38 -07001446 common.DumpInfoDict(OPTIONS.info_dict)
1447
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001448 # If the caller explicitly specified the device-specific extensions
1449 # path via -s/--device_specific, use that. Otherwise, use
1450 # META/releasetools.py if it is present in the target target_files.
1451 # Otherwise, take the path of the file from 'tool_extensions' in the
1452 # info dict and look for that in the local filesystem, relative to
1453 # the current directory.
1454
Doug Zongker37974732010-09-16 17:44:38 -07001455 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001456 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1457 if os.path.exists(from_input):
Tao Bao89fbb0f2017-01-10 10:47:58 -08001458 print("(using device-specific extensions from target_files)")
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001459 OPTIONS.device_specific = from_input
1460 else:
1461 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1462
Doug Zongker37974732010-09-16 17:44:38 -07001463 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001464 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001465
Tao Baoc098e9e2016-01-07 13:03:56 -08001466 if OPTIONS.info_dict.get("no_recovery") == "true":
Tao Baodb45efa2015-10-27 19:25:18 -07001467 raise common.ExternalError(
1468 "--- target build has specified no recovery ---")
1469
Tao Bao767e3ac2015-11-10 12:19:19 -08001470 # Set up the output zip. Create a temporary zip file if signing is needed.
1471 if OPTIONS.no_signing:
1472 if os.path.exists(args[1]):
1473 os.unlink(args[1])
1474 output_zip = zipfile.ZipFile(args[1], "w",
1475 compression=zipfile.ZIP_DEFLATED)
1476 else:
1477 temp_zip_file = tempfile.NamedTemporaryFile()
1478 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1479 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001480
Daniel Rosenberg40ef35b2015-11-10 19:21:34 -08001481 # Non A/B OTAs rely on /cache partition to store temporary files.
Tao Bao767e3ac2015-11-10 12:19:19 -08001482 cache_size = OPTIONS.info_dict.get("cache_size", None)
Tao Baoc098e9e2016-01-07 13:03:56 -08001483 if cache_size is None:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001484 print("--- can't determine the cache partition size ---")
Tao Bao767e3ac2015-11-10 12:19:19 -08001485 OPTIONS.cache_size = cache_size
Tao Bao8dcf7382015-05-21 14:09:49 -07001486
Tao Bao9bc6bb22015-11-09 16:58:28 -08001487 # Generate a verify package.
1488 if OPTIONS.gen_verify:
1489 WriteVerifyPackage(input_zip, output_zip)
1490
Tao Bao767e3ac2015-11-10 12:19:19 -08001491 # Generate a full OTA.
Tao Bao9bc6bb22015-11-09 16:58:28 -08001492 elif OPTIONS.incremental_source is None:
Tao Baoc098e9e2016-01-07 13:03:56 -08001493 WriteFullOTAPackage(input_zip, output_zip)
Tao Bao767e3ac2015-11-10 12:19:19 -08001494
1495 # Generate an incremental OTA. It will fall back to generate a full OTA on
1496 # failure unless no_fallback_to_full is specified.
1497 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001498 print("unzipping source target-files...")
Tao Bao767e3ac2015-11-10 12:19:19 -08001499 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
Tao Bao6b0b2f92017-03-05 11:38:11 -08001500 OPTIONS.incremental_source,
Tao Bao457cbf62017-03-06 09:56:01 -08001501 UNZIP_PATTERN)
Tao Bao767e3ac2015-11-10 12:19:19 -08001502 OPTIONS.target_info_dict = OPTIONS.info_dict
1503 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip,
1504 OPTIONS.source_tmp)
1505 if OPTIONS.verbose:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001506 print("--- source info ---")
Tao Bao767e3ac2015-11-10 12:19:19 -08001507 common.DumpInfoDict(OPTIONS.source_info_dict)
1508 try:
Tao Bao457cbf62017-03-06 09:56:01 -08001509 WriteBlockIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Baod62c6032015-11-30 09:40:20 -08001510 if OPTIONS.log_diff:
1511 out_file = open(OPTIONS.log_diff, 'w')
1512 import target_files_diff
1513 target_files_diff.recursiveDiff('',
1514 OPTIONS.source_tmp,
1515 OPTIONS.input_tmp,
1516 out_file)
1517 out_file.close()
Tao Bao767e3ac2015-11-10 12:19:19 -08001518 except ValueError:
1519 if not OPTIONS.fallback_to_full:
1520 raise
Tao Bao89fbb0f2017-01-10 10:47:58 -08001521 print("--- failed to build incremental; falling back to full ---")
Tao Bao767e3ac2015-11-10 12:19:19 -08001522 OPTIONS.incremental_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -07001523 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001524
Tao Bao767e3ac2015-11-10 12:19:19 -08001525 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001526
Tao Bao767e3ac2015-11-10 12:19:19 -08001527 # Sign the generated zip package unless no_signing is specified.
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001528 if not OPTIONS.no_signing:
1529 SignOutput(temp_zip_file.name, args[1])
1530 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001531
Tao Bao89fbb0f2017-01-10 10:47:58 -08001532 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001533
1534
1535if __name__ == '__main__':
1536 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001537 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001538 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001539 except common.ExternalError as e:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001540 print("\n ERROR: %s\n" % (e,))
Doug Zongkereef39442009-04-02 12:14:19 -07001541 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001542 finally:
1543 common.Cleanup()