blob: d2041e894118d4f46b84e81a02a196bbead5a4e9 [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
Tao Bao337633f2017-12-06 15:20:19 -080061 --wipe_user_data
Doug Zongkerdbfaae52009-04-21 17:12:54 -070062 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
Tao Bao2dd1c482017-02-03 16:49:39 -0800140import copy
Doug Zongkerfc44a512014-08-26 13:10:25 -0700141import multiprocessing
Tao Bao2dd1c482017-02-03 16:49:39 -0800142import os.path
Tao Baoc098e9e2016-01-07 13:03:56 -0800143import subprocess
Baligh Uddin2abbbd02016-06-22 12:14:16 -0700144import shlex
Doug Zongkereef39442009-04-02 12:14:19 -0700145import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -0700146import zipfile
147
148import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700149import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -0700150import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700151
152OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700153OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700154OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700155OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700156OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700157OPTIONS.wipe_user_data = False
Tao Bao5d182562016-02-23 11:38:39 -0800158OPTIONS.downgrade = False
Tao Bao3e6161a2017-02-28 11:48:48 -0800159OPTIONS.timestamp = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700160OPTIONS.extra_script = None
Doug Zongkerfc44a512014-08-26 13:10:25 -0700161OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
162if OPTIONS.worker_threads == 0:
163 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800164OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900165OPTIONS.no_signing = False
Tao Bao457cbf62017-03-06 09:56:01 -0800166OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -0800167OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700168OPTIONS.oem_source = None
Tao Bao8608cde2016-02-25 19:49:55 -0800169OPTIONS.oem_no_mount = False
Doug Zongker62d4f182014-08-04 16:06:43 -0700170OPTIONS.fallback_to_full = True
Tao Bao43078aa2015-04-21 14:32:35 -0700171OPTIONS.full_radio = False
leozwangaa6c1a12015-08-14 10:57:58 -0700172OPTIONS.full_bootloader = False
Tao Baod47d8e12015-05-21 14:09:49 -0700173# Stash size cannot exceed cache_size * threshold.
174OPTIONS.cache_size = None
175OPTIONS.stash_threshold = 0.8
Tao Bao9bc6bb22015-11-09 16:58:28 -0800176OPTIONS.gen_verify = False
Tao Baod62c6032015-11-30 09:40:20 -0800177OPTIONS.log_diff = None
Tao Baodea0f8b2016-06-20 17:55:06 -0700178OPTIONS.payload_signer = None
Baligh Uddin2abbbd02016-06-22 12:14:16 -0700179OPTIONS.payload_signer_args = []
Tao Bao5f8ff932017-03-21 22:35:00 -0700180OPTIONS.extracted_input = None
Christian Oderf63e2cd2017-05-01 22:30:15 +0200181OPTIONS.key_passwords = []
Tao Bao8dcf7382015-05-21 14:09:49 -0700182
Tao Bao2dd1c482017-02-03 16:49:39 -0800183METADATA_NAME = 'META-INF/com/android/metadata'
Tao Bao6b0b2f92017-03-05 11:38:11 -0800184UNZIP_PATTERN = ['IMAGES/*', 'META/*']
185
Tao Bao2dd1c482017-02-03 16:49:39 -0800186
Doug Zongkereef39442009-04-02 12:14:19 -0700187def SignOutput(temp_zip_name, output_zip_name):
Christian Oderf63e2cd2017-05-01 22:30:15 +0200188 pw = OPTIONS.key_passwords[OPTIONS.package_key]
Doug Zongkereef39442009-04-02 12:14:19 -0700189
Doug Zongker951495f2009-08-14 12:44:19 -0700190 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
191 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700192
193
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800194def AppendAssertions(script, info_dict, oem_dicts=None):
Michael Runge6e836112014-04-15 17:40:21 -0700195 oem_props = info_dict.get("oem_fingerprint_properties")
Tao Bao3e30d972016-03-15 13:20:19 -0700196 if not oem_props:
Michael Runge6e836112014-04-15 17:40:21 -0700197 device = GetBuildProp("ro.product.device", info_dict)
198 script.AssertDevice(device)
199 else:
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800200 if not oem_dicts:
Dan Albert8b72aef2015-03-23 19:13:21 -0700201 raise common.ExternalError(
202 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700203 for prop in oem_props.split():
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800204 values = []
205 for oem_dict in oem_dicts:
206 if oem_dict.get(prop):
207 values.append(oem_dict[prop])
208 if not values:
Dan Albert8b72aef2015-03-23 19:13:21 -0700209 raise common.ExternalError(
210 "The OEM file is missing the property %s" % prop)
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800211 script.AssertOemProperty(prop, values)
212
213
Tao Baoebce6972017-03-06 10:22:20 -0800214def _LoadOemDicts(script, recovery_mount_options=None):
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800215 """Returns the list of loaded OEM properties dict."""
216 oem_dicts = None
217 if OPTIONS.oem_source is None:
218 raise common.ExternalError("OEM source required for this build")
Tao Baoebce6972017-03-06 10:22:20 -0800219 if not OPTIONS.oem_no_mount and script:
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800220 script.Mount("/oem", recovery_mount_options)
221 oem_dicts = []
222 for oem_file in OPTIONS.oem_source:
223 oem_dicts.append(common.LoadDictionaryFromLines(
224 open(oem_file).readlines()))
225 return oem_dicts
Doug Zongkereef39442009-04-02 12:14:19 -0700226
Doug Zongkereef39442009-04-02 12:14:19 -0700227
Tao Baod42e97e2016-11-30 12:11:57 -0800228def _WriteRecoveryImageToBoot(script, output_zip):
229 """Find and write recovery image to /boot in two-step OTA.
230
231 In two-step OTAs, we write recovery image to /boot as the first step so that
232 we can reboot to there and install a new recovery image to /recovery.
233 A special "recovery-two-step.img" will be preferred, which encodes the correct
234 path of "/boot". Otherwise the device may show "device is corrupt" message
235 when booting into /boot.
236
237 Fall back to using the regular recovery.img if the two-step recovery image
238 doesn't exist. Note that rebuilding the special image at this point may be
239 infeasible, because we don't have the desired boot signer and keys when
240 calling ota_from_target_files.py.
241 """
242
243 recovery_two_step_img_name = "recovery-two-step.img"
244 recovery_two_step_img_path = os.path.join(
245 OPTIONS.input_tmp, "IMAGES", recovery_two_step_img_name)
246 if os.path.exists(recovery_two_step_img_path):
247 recovery_two_step_img = common.GetBootableImage(
248 recovery_two_step_img_name, recovery_two_step_img_name,
249 OPTIONS.input_tmp, "RECOVERY")
250 common.ZipWriteStr(
251 output_zip, recovery_two_step_img_name, recovery_two_step_img.data)
Tao Bao89fbb0f2017-01-10 10:47:58 -0800252 print("two-step package: using %s in stage 1/3" % (
253 recovery_two_step_img_name,))
Tao Baod42e97e2016-11-30 12:11:57 -0800254 script.WriteRawImage("/boot", recovery_two_step_img_name)
255 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -0800256 print("two-step package: using recovery.img in stage 1/3")
Tao Baod42e97e2016-11-30 12:11:57 -0800257 # The "recovery.img" entry has been written into package earlier.
258 script.WriteRawImage("/boot", "recovery.img")
259
260
Doug Zongkerc9253822014-02-04 12:17:58 -0800261def HasRecoveryPatch(target_files_zip):
Tao Baof2cffbd2015-07-22 12:33:18 -0700262 namelist = [name for name in target_files_zip.namelist()]
263 return ("SYSTEM/recovery-from-boot.p" in namelist or
264 "SYSTEM/etc/recovery.img" in namelist)
Doug Zongker73ef8252009-07-23 15:12:53 -0700265
Tao Bao457cbf62017-03-06 09:56:01 -0800266
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700267def HasVendorPartition(target_files_zip):
268 try:
269 target_files_zip.getinfo("VENDOR/")
270 return True
271 except KeyError:
272 return False
273
Tao Bao457cbf62017-03-06 09:56:01 -0800274
Tao Baobcd1d162017-08-26 13:10:26 -0700275def HasTrebleEnabled(target_files_zip, info_dict):
276 return (HasVendorPartition(target_files_zip) and
277 GetBuildProp("ro.treble.enabled", info_dict) == "true")
278
279
Michael Runge6e836112014-04-15 17:40:21 -0700280def GetOemProperty(name, oem_props, oem_dict, info_dict):
281 if oem_props is not None and name in oem_props:
282 return oem_dict[name]
283 return GetBuildProp(name, info_dict)
284
285
286def CalculateFingerprint(oem_props, oem_dict, info_dict):
287 if oem_props is None:
288 return GetBuildProp("ro.build.fingerprint", info_dict)
289 return "%s/%s/%s:%s" % (
Dan Albert8b72aef2015-03-23 19:13:21 -0700290 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
291 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
292 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
293 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700294
Doug Zongkerfc44a512014-08-26 13:10:25 -0700295
Tao Bao7e0f1602017-03-06 15:50:08 -0800296def GetImage(which, tmpdir):
297 """Returns an image object suitable for passing to BlockImageDiff.
298
299 'which' partition must be "system" or "vendor". A prebuilt image and file
300 map must already exist in tmpdir.
301 """
Doug Zongker3c84f562014-07-31 11:06:30 -0700302
303 assert which in ("system", "vendor")
304
305 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700306 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
Doug Zongker3c84f562014-07-31 11:06:30 -0700307
Tao Bao7e0f1602017-03-06 15:50:08 -0800308 # The image and map files must have been created prior to calling
309 # ota_from_target_files.py (since LMP).
310 assert os.path.exists(path) and os.path.exists(mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700311
Tao Baoff777812015-05-12 11:42:31 -0700312 # Bug: http://b/20939131
313 # In ext4 filesystems, block 0 might be changed even being mounted
314 # R/O. We add it to clobbered_blocks so that it will be written to the
315 # target unconditionally. Note that they are still part of care_map.
316 clobbered_blocks = "0"
317
318 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700319
320
Tao Baobcd1d162017-08-26 13:10:26 -0700321def AddCompatibilityArchiveIfTrebleEnabled(target_zip, output_zip,
322 target_info_dict,
323 source_info_dict=None):
324 """Adds compatibility info into the output zip if it's Treble-enabled target.
Tao Bao21803d32017-04-19 10:16:09 -0700325
326 Metadata used for on-device compatibility verification is retrieved from
327 target_zip then added to compatibility.zip which is added to the output_zip
328 archive.
329
Tao Baobcd1d162017-08-26 13:10:26 -0700330 Compatibility archive should only be included for devices that have enabled
331 Treble support.
Tao Bao21803d32017-04-19 10:16:09 -0700332
333 Args:
334 target_zip: Zip file containing the source files to be included for OTA.
335 output_zip: Zip file that will be sent for OTA.
Tao Baobcd1d162017-08-26 13:10:26 -0700336 target_info_dict: The dict that holds the target build info.
337 source_info_dict: The dict that holds the source build info, if generating
338 an incremental OTA; None otherwise.
Tao Bao21803d32017-04-19 10:16:09 -0700339 """
340
Tao Baobcd1d162017-08-26 13:10:26 -0700341 def AddCompatibilityArchive(system_updated, vendor_updated):
342 """Adds compatibility info based on system/vendor update status.
Tao Bao21803d32017-04-19 10:16:09 -0700343
Tao Baobcd1d162017-08-26 13:10:26 -0700344 Args:
345 system_updated: If True, the system image will be updated and therefore
346 its metadata should be included.
347 vendor_updated: If True, the vendor image will be updated and therefore
348 its metadata should be included.
349 """
350 # Determine what metadata we need. Files are names relative to META/.
351 compatibility_files = []
352 vendor_metadata = ("vendor_manifest.xml", "vendor_matrix.xml")
353 system_metadata = ("system_manifest.xml", "system_matrix.xml")
354 if vendor_updated:
355 compatibility_files += vendor_metadata
356 if system_updated:
357 compatibility_files += system_metadata
Tao Bao21803d32017-04-19 10:16:09 -0700358
Tao Baobcd1d162017-08-26 13:10:26 -0700359 # Create new archive.
360 compatibility_archive = tempfile.NamedTemporaryFile()
361 compatibility_archive_zip = zipfile.ZipFile(compatibility_archive, "w",
362 compression=zipfile.ZIP_DEFLATED)
Tao Bao21803d32017-04-19 10:16:09 -0700363
Tao Baobcd1d162017-08-26 13:10:26 -0700364 # Add metadata.
365 for file_name in compatibility_files:
366 target_file_name = "META/" + file_name
Tao Bao21803d32017-04-19 10:16:09 -0700367
Tao Baobcd1d162017-08-26 13:10:26 -0700368 if target_file_name in target_zip.namelist():
369 data = target_zip.read(target_file_name)
370 common.ZipWriteStr(compatibility_archive_zip, file_name, data)
Tao Bao21803d32017-04-19 10:16:09 -0700371
Tao Baobcd1d162017-08-26 13:10:26 -0700372 # Ensure files are written before we copy into output_zip.
373 compatibility_archive_zip.close()
374
375 # Only add the archive if we have any compatibility info.
376 if compatibility_archive_zip.namelist():
377 common.ZipWrite(output_zip, compatibility_archive.name,
378 arcname="compatibility.zip",
379 compress_type=zipfile.ZIP_STORED)
380
381 # Will only proceed if the target has enabled the Treble support (as well as
382 # having a /vendor partition).
383 if not HasTrebleEnabled(target_zip, target_info_dict):
384 return
385
386 # We don't support OEM thumbprint in Treble world (which calculates
387 # fingerprints in a different way as shown in CalculateFingerprint()).
388 assert not target_info_dict.get("oem_fingerprint_properties")
389
390 # Full OTA carries the info for system/vendor both.
391 if source_info_dict is None:
392 AddCompatibilityArchive(True, True)
393 return
394
395 assert not source_info_dict.get("oem_fingerprint_properties")
396
397 source_fp = GetBuildProp("ro.build.fingerprint", source_info_dict)
398 target_fp = GetBuildProp("ro.build.fingerprint", target_info_dict)
399 system_updated = source_fp != target_fp
400
401 source_fp_vendor = GetVendorBuildProp("ro.vendor.build.fingerprint",
402 source_info_dict)
403 target_fp_vendor = GetVendorBuildProp("ro.vendor.build.fingerprint",
404 target_info_dict)
405 vendor_updated = source_fp_vendor != target_fp_vendor
406
407 AddCompatibilityArchive(system_updated, vendor_updated)
Tao Bao21803d32017-04-19 10:16:09 -0700408
409
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700410def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700411 # TODO: how to determine this? We don't know what version it will
Tao Bao34b47bf2015-06-22 19:17:41 -0700412 # be installed on top of. For now, we expect the API just won't
413 # change very often. Similarly for fstab, it might have changed
414 # in the target build.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700415 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700416
Tao Bao838c68f2016-03-15 19:16:18 +0000417 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Tao Bao3e30d972016-03-15 13:20:19 -0700418 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800419 oem_dicts = None
Tao Bao3e30d972016-03-15 13:20:19 -0700420 if oem_props:
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800421 oem_dicts = _LoadOemDicts(script, recovery_mount_options)
Michael Runge6e836112014-04-15 17:40:21 -0700422
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800423 target_fp = CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
424 OPTIONS.info_dict)
Dan Albert8b72aef2015-03-23 19:13:21 -0700425 metadata = {
Tao Bao39f3eaf2017-03-09 15:01:11 -0800426 "post-build": target_fp,
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800427 "pre-device": GetOemProperty("ro.product.device", oem_props,
428 oem_dicts and oem_dicts[0],
Dan Albert8b72aef2015-03-23 19:13:21 -0700429 OPTIONS.info_dict),
430 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
431 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700432
Doug Zongker05d3dea2009-06-22 11:32:31 -0700433 device_specific = common.DeviceSpecificParams(
434 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700435 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700436 output_zip=output_zip,
437 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700438 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700439 metadata=metadata,
440 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700441
Tao Bao457cbf62017-03-06 09:56:01 -0800442 assert HasRecoveryPatch(input_zip)
Doug Zongkerc9253822014-02-04 12:17:58 -0800443
Tao Bao457cbf62017-03-06 09:56:01 -0800444 metadata["ota-type"] = "BLOCK"
Tao Baod8d14be2016-02-04 14:26:02 -0800445
Elliott Hughesd8a52f92016-06-20 14:35:47 -0700446 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
447 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
448 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700449
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800450 AppendAssertions(script, OPTIONS.info_dict, oem_dicts)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700451 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800452
453 # Two-step package strategy (in chronological order, which is *not*
454 # the order in which the generated script has things):
455 #
456 # if stage is not "2/3" or "3/3":
457 # write recovery image to boot partition
458 # set stage to "2/3"
459 # reboot to boot partition and restart recovery
460 # else if stage is "2/3":
461 # write recovery image to recovery partition
462 # set stage to "3/3"
463 # reboot to recovery partition and restart recovery
464 # else:
465 # (stage must be "3/3")
466 # set stage to ""
467 # do normal full package installation:
468 # wipe and install system, boot image, etc.
469 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700470 # complete script normally
471 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800472
473 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
474 OPTIONS.input_tmp, "RECOVERY")
475 if OPTIONS.two_step:
476 if not OPTIONS.info_dict.get("multistage_support", None):
477 assert False, "two-step packages not supported by this build"
478 fs = OPTIONS.info_dict["fstab"]["/misc"]
479 assert fs.fs_type.upper() == "EMMC", \
480 "two-step packages only supported on devices with EMMC /misc partitions"
481 bcb_dev = {"bcb_dev": fs.device}
482 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
483 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700484if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800485""" % bcb_dev)
Tao Baod42e97e2016-11-30 12:11:57 -0800486
487 # Stage 2/3: Write recovery image to /recovery (currently running /boot).
488 script.Comment("Stage 2/3")
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800489 script.WriteRawImage("/recovery", "recovery.img")
490 script.AppendExtra("""
491set_stage("%(bcb_dev)s", "3/3");
492reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700493else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800494""" % bcb_dev)
495
Tao Baod42e97e2016-11-30 12:11:57 -0800496 # Stage 3/3: Make changes.
497 script.Comment("Stage 3/3")
498
Tao Bao6c55a8a2015-04-08 15:30:27 -0700499 # Dump fingerprints
Tao Bao3e30d972016-03-15 13:20:19 -0700500 script.Print("Target: %s" % target_fp)
Tao Bao6c55a8a2015-04-08 15:30:27 -0700501
Doug Zongkere5ff5902012-01-17 10:55:37 -0800502 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700503
Doug Zongker01ce19c2014-02-04 13:48:15 -0800504 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700505
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700506 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800507 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700508 if HasVendorPartition(input_zip):
509 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700510
Michael Runge7cd99ba2014-10-22 17:21:48 -0700511 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
512
Doug Zongker4b9596f2014-06-09 14:15:45 -0700513 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800514
Tao Bao457cbf62017-03-06 09:56:01 -0800515 # Full OTA is done as an "incremental" against an empty source image. This
516 # has the effect of writing new data from the package to the entire
517 # partition, but lets us reuse the updater code that writes incrementals to
518 # do it.
519 system_tgt = GetImage("system", OPTIONS.input_tmp)
520 system_tgt.ResetFileMap()
521 system_diff = common.BlockDifference("system", system_tgt, src=None)
522 system_diff.WriteScript(script, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700523
Tao Bao7a5bf8a2015-07-21 18:01:20 -0700524 boot_img = common.GetBootableImage(
525 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800526
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700527 if HasVendorPartition(input_zip):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700528 script.ShowProgress(0.1, 0)
529
Tao Bao457cbf62017-03-06 09:56:01 -0800530 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp)
531 vendor_tgt.ResetFileMap()
532 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
533 vendor_diff.WriteScript(script, output_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700534
Tao Baobcd1d162017-08-26 13:10:26 -0700535 AddCompatibilityArchiveIfTrebleEnabled(input_zip, output_zip,
536 OPTIONS.info_dict)
537
Doug Zongker37974732010-09-16 17:44:38 -0700538 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700539 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700540
Doug Zongker01ce19c2014-02-04 13:48:15 -0800541 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700542 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700543
Doug Zongker01ce19c2014-02-04 13:48:15 -0800544 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700545 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700546
Doug Zongker1c390a22009-05-14 19:06:36 -0700547 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700548 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700549
Doug Zongker14833602010-02-02 13:12:04 -0800550 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800551
Doug Zongker922206e2014-03-04 13:16:24 -0800552 if OPTIONS.wipe_user_data:
553 script.ShowProgress(0.1, 10)
554 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700555
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800556 if OPTIONS.two_step:
557 script.AppendExtra("""
558set_stage("%(bcb_dev)s", "");
559""" % bcb_dev)
560 script.AppendExtra("else\n")
Tao Baod42e97e2016-11-30 12:11:57 -0800561
562 # Stage 1/3: Nothing to verify for full OTA. Write recovery image to /boot.
563 script.Comment("Stage 1/3")
564 _WriteRecoveryImageToBoot(script, output_zip)
565
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800566 script.AppendExtra("""
567set_stage("%(bcb_dev)s", "2/3");
568reboot_now("%(bcb_dev)s", "");
569endif;
570endif;
571""" % bcb_dev)
Tao Baod8d14be2016-02-04 14:26:02 -0800572
Tao Bao5d182562016-02-23 11:38:39 -0800573 script.SetProgress(1)
574 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -0800575 metadata["ota-required-cache"] = str(script.required_cache)
Doug Zongker2ea21062010-04-28 16:05:21 -0700576 WriteMetadata(metadata, output_zip)
577
Doug Zongkerfc44a512014-08-26 13:10:25 -0700578
Doug Zongker2ea21062010-04-28 16:05:21 -0700579def WriteMetadata(metadata, output_zip):
Tao Bao2dd1c482017-02-03 16:49:39 -0800580 value = "".join(["%s=%s\n" % kv for kv in sorted(metadata.iteritems())])
581 common.ZipWriteStr(output_zip, METADATA_NAME, value,
582 compress_type=zipfile.ZIP_STORED)
Doug Zongkereef39442009-04-02 12:14:19 -0700583
Doug Zongkerfc44a512014-08-26 13:10:25 -0700584
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700585def GetBuildProp(prop, info_dict):
Tao Baobcd1d162017-08-26 13:10:26 -0700586 """Returns the inquired build property from a given info_dict."""
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700587 try:
588 return info_dict.get("build.prop", {})[prop]
589 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700590 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700591
Doug Zongkerfc44a512014-08-26 13:10:25 -0700592
Tao Baobcd1d162017-08-26 13:10:26 -0700593def GetVendorBuildProp(prop, info_dict):
594 """Returns the inquired vendor build property from a given info_dict."""
595 try:
596 return info_dict.get("vendor.build.prop", {})[prop]
597 except KeyError:
598 raise common.ExternalError(
599 "couldn't find %s in vendor.build.prop" % (prop,))
600
601
Tao Baob31892e2017-02-07 11:21:17 -0800602def HandleDowngradeMetadata(metadata):
603 # Only incremental OTAs are allowed to reach here.
604 assert OPTIONS.incremental_source is not None
605
606 post_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict)
607 pre_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
608 is_downgrade = long(post_timestamp) < long(pre_timestamp)
609
610 if OPTIONS.downgrade:
Tao Baob31892e2017-02-07 11:21:17 -0800611 if not is_downgrade:
612 raise RuntimeError("--downgrade specified but no downgrade detected: "
613 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
Tao Bao3e6161a2017-02-28 11:48:48 -0800614 metadata["ota-downgrade"] = "yes"
615 elif OPTIONS.timestamp:
616 if not is_downgrade:
617 raise RuntimeError("--timestamp specified but no timestamp hack needed: "
618 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
619 metadata["post-timestamp"] = str(long(pre_timestamp) + 1)
Tao Baob31892e2017-02-07 11:21:17 -0800620 else:
621 if is_downgrade:
Tao Bao3e6161a2017-02-28 11:48:48 -0800622 raise RuntimeError("Downgrade detected based on timestamp check: "
623 "pre: %s, post: %s. Need to specify --timestamp OR "
624 "--downgrade to allow building the incremental." % (
625 pre_timestamp, post_timestamp))
Tao Baob31892e2017-02-07 11:21:17 -0800626 metadata["post-timestamp"] = post_timestamp
627
628
Geremy Condra36bd3652014-02-06 19:45:10 -0800629def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
630 source_version = OPTIONS.source_info_dict["recovery_api_version"]
631 target_version = OPTIONS.target_info_dict["recovery_api_version"]
632
633 if source_version == 0:
Tao Bao3e30d972016-03-15 13:20:19 -0700634 print("WARNING: generating edify script for a source that "
635 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -0700636 script = edify_generator.EdifyGenerator(
637 source_version, OPTIONS.target_info_dict,
638 fstab=OPTIONS.source_info_dict["fstab"])
Geremy Condra36bd3652014-02-06 19:45:10 -0800639
Tao Bao3806c232015-07-05 21:08:33 -0700640 recovery_mount_options = OPTIONS.source_info_dict.get(
641 "recovery_mount_options")
Tao Bao3e30d972016-03-15 13:20:19 -0700642 source_oem_props = OPTIONS.source_info_dict.get("oem_fingerprint_properties")
643 target_oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800644 oem_dicts = None
645 if source_oem_props and target_oem_props:
646 oem_dicts = _LoadOemDicts(script, recovery_mount_options)
Tao Bao3806c232015-07-05 21:08:33 -0700647
Dan Albert8b72aef2015-03-23 19:13:21 -0700648 metadata = {
Tao Bao3e30d972016-03-15 13:20:19 -0700649 "pre-device": GetOemProperty("ro.product.device", source_oem_props,
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800650 oem_dicts and oem_dicts[0],
651 OPTIONS.source_info_dict),
Tao Baod8d14be2016-02-04 14:26:02 -0800652 "ota-type": "BLOCK",
Dan Albert8b72aef2015-03-23 19:13:21 -0700653 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800654
Tao Baob31892e2017-02-07 11:21:17 -0800655 HandleDowngradeMetadata(metadata)
Tao Bao5d182562016-02-23 11:38:39 -0800656
Geremy Condra36bd3652014-02-06 19:45:10 -0800657 device_specific = common.DeviceSpecificParams(
658 source_zip=source_zip,
659 source_version=source_version,
660 target_zip=target_zip,
661 target_version=target_version,
662 output_zip=output_zip,
663 script=script,
664 metadata=metadata,
Tao Bao6f0b2192015-10-13 16:37:12 -0700665 info_dict=OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800666
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800667 source_fp = CalculateFingerprint(source_oem_props, oem_dicts and oem_dicts[0],
Tao Bao3806c232015-07-05 21:08:33 -0700668 OPTIONS.source_info_dict)
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800669 target_fp = CalculateFingerprint(target_oem_props, oem_dicts and oem_dicts[0],
Tao Bao3806c232015-07-05 21:08:33 -0700670 OPTIONS.target_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800671 metadata["pre-build"] = source_fp
672 metadata["post-build"] = target_fp
Tianjie Xud06f07e2016-06-09 14:18:45 -0700673 metadata["pre-build-incremental"] = GetBuildProp(
674 "ro.build.version.incremental", OPTIONS.source_info_dict)
675 metadata["post-build-incremental"] = GetBuildProp(
676 "ro.build.version.incremental", OPTIONS.target_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800677
678 source_boot = common.GetBootableImage(
679 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
680 OPTIONS.source_info_dict)
681 target_boot = common.GetBootableImage(
682 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
683 updating_boot = (not OPTIONS.two_step and
684 (source_boot.data != target_boot.data))
685
Geremy Condra36bd3652014-02-06 19:45:10 -0800686 target_recovery = common.GetBootableImage(
687 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800688
Tao Bao7e0f1602017-03-06 15:50:08 -0800689 system_src = GetImage("system", OPTIONS.source_tmp)
690 system_tgt = GetImage("system", OPTIONS.target_tmp)
Tao Baodd2a5892015-03-12 12:32:37 -0700691
692 blockimgdiff_version = 1
693 if OPTIONS.info_dict:
694 blockimgdiff_version = max(
695 int(i) for i in
696 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
697
Tao Baof8acad12016-07-07 09:09:58 -0700698 # Check the first block of the source system partition for remount R/W only
699 # if the filesystem is ext4.
700 system_src_partition = OPTIONS.source_info_dict["fstab"]["/system"]
701 check_first_block = system_src_partition.fs_type == "ext4"
Tao Bao293fd132016-06-11 12:19:23 -0700702 # Disable using imgdiff for squashfs. 'imgdiff -z' expects input files to be
703 # in zip formats. However with squashfs, a) all files are compressed in LZ4;
704 # b) the blocks listed in block map may not contain all the bytes for a given
705 # file (because they're rounded to be 4K-aligned).
Tao Baof8acad12016-07-07 09:09:58 -0700706 system_tgt_partition = OPTIONS.target_info_dict["fstab"]["/system"]
707 disable_imgdiff = (system_src_partition.fs_type == "squashfs" or
708 system_tgt_partition.fs_type == "squashfs")
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700709 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tianjie Xufc3422a2015-12-15 11:53:59 -0800710 check_first_block,
Tao Bao293fd132016-06-11 12:19:23 -0700711 version=blockimgdiff_version,
712 disable_imgdiff=disable_imgdiff)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700713
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700714 if HasVendorPartition(target_zip):
715 if not HasVendorPartition(source_zip):
716 raise RuntimeError("can't generate incremental that adds /vendor")
Tao Bao7e0f1602017-03-06 15:50:08 -0800717 vendor_src = GetImage("vendor", OPTIONS.source_tmp)
718 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp)
Tianjie Xufc3422a2015-12-15 11:53:59 -0800719
720 # Check first block of vendor partition for remount R/W only if
721 # disk type is ext4
722 vendor_partition = OPTIONS.source_info_dict["fstab"]["/vendor"]
Tao Baod8d14be2016-02-04 14:26:02 -0800723 check_first_block = vendor_partition.fs_type == "ext4"
Tao Bao293fd132016-06-11 12:19:23 -0700724 disable_imgdiff = vendor_partition.fs_type == "squashfs"
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700725 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tianjie Xufc3422a2015-12-15 11:53:59 -0800726 check_first_block,
Tao Bao293fd132016-06-11 12:19:23 -0700727 version=blockimgdiff_version,
728 disable_imgdiff=disable_imgdiff)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700729 else:
730 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800731
Tao Baobcd1d162017-08-26 13:10:26 -0700732 AddCompatibilityArchiveIfTrebleEnabled(
733 target_zip, output_zip, OPTIONS.target_info_dict,
734 OPTIONS.source_info_dict)
735
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800736 AppendAssertions(script, OPTIONS.target_info_dict, oem_dicts)
Geremy Condra36bd3652014-02-06 19:45:10 -0800737 device_specific.IncrementalOTA_Assertions()
738
739 # Two-step incremental package strategy (in chronological order,
740 # which is *not* the order in which the generated script has
741 # things):
742 #
743 # if stage is not "2/3" or "3/3":
744 # do verification on current system
745 # write recovery image to boot partition
746 # set stage to "2/3"
747 # reboot to boot partition and restart recovery
748 # else if stage is "2/3":
749 # write recovery image to recovery partition
750 # set stage to "3/3"
751 # reboot to recovery partition and restart recovery
752 # else:
753 # (stage must be "3/3")
754 # perform update:
755 # patch system files, etc.
756 # force full install of new boot image
757 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700758 # complete script normally
759 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800760
761 if OPTIONS.two_step:
Tao Baodd24da92015-07-29 14:09:23 -0700762 if not OPTIONS.source_info_dict.get("multistage_support", None):
Geremy Condra36bd3652014-02-06 19:45:10 -0800763 assert False, "two-step packages not supported by this build"
Tao Baodd24da92015-07-29 14:09:23 -0700764 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Geremy Condra36bd3652014-02-06 19:45:10 -0800765 assert fs.fs_type.upper() == "EMMC", \
766 "two-step packages only supported on devices with EMMC /misc partitions"
767 bcb_dev = {"bcb_dev": fs.device}
768 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
769 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700770if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800771""" % bcb_dev)
Tao Baod42e97e2016-11-30 12:11:57 -0800772
773 # Stage 2/3: Write recovery image to /recovery (currently running /boot).
774 script.Comment("Stage 2/3")
Dan Albert8b72aef2015-03-23 19:13:21 -0700775 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800776 script.WriteRawImage("/recovery", "recovery.img")
777 script.AppendExtra("""
778set_stage("%(bcb_dev)s", "3/3");
779reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700780else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800781""" % bcb_dev)
782
Tao Baod42e97e2016-11-30 12:11:57 -0800783 # Stage 1/3: (a) Verify the current system.
784 script.Comment("Stage 1/3")
785
Tao Bao6c55a8a2015-04-08 15:30:27 -0700786 # Dump fingerprints
Tao Baof9023852016-12-14 11:53:38 -0800787 script.Print("Source: %s" % (source_fp,))
788 script.Print("Target: %s" % (target_fp,))
Tao Bao6c55a8a2015-04-08 15:30:27 -0700789
Geremy Condra36bd3652014-02-06 19:45:10 -0800790 script.Print("Verifying current system...")
791
792 device_specific.IncrementalOTA_VerifyBegin()
793
Tao Bao3e30d972016-03-15 13:20:19 -0700794 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
795 # patching on a device that's already on the target build will damage the
796 # system. Because operations like move don't check the block state, they
797 # always apply the changes unconditionally.
798 if blockimgdiff_version <= 2:
799 if source_oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700800 script.AssertSomeFingerprint(source_fp)
801 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700802 script.AssertSomeThumbprint(
803 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Tao Bao3e30d972016-03-15 13:20:19 -0700804
805 else: # blockimgdiff_version > 2
806 if source_oem_props is None and target_oem_props is None:
807 script.AssertSomeFingerprint(source_fp, target_fp)
808 elif source_oem_props is not None and target_oem_props is not None:
Tao Baodd2a5892015-03-12 12:32:37 -0700809 script.AssertSomeThumbprint(
810 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
811 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Tao Bao3e30d972016-03-15 13:20:19 -0700812 elif source_oem_props is None and target_oem_props is not None:
813 script.AssertFingerprintOrThumbprint(
814 source_fp,
815 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict))
816 else:
817 script.AssertFingerprintOrThumbprint(
818 target_fp,
819 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800820
Tao Baod8d14be2016-02-04 14:26:02 -0800821 # Check the required cache size (i.e. stashed blocks).
822 size = []
823 if system_diff:
824 size.append(system_diff.required_cache)
825 if vendor_diff:
826 size.append(vendor_diff.required_cache)
827
Geremy Condra36bd3652014-02-06 19:45:10 -0800828 if updating_boot:
Tao Baodd24da92015-07-29 14:09:23 -0700829 boot_type, boot_device = common.GetTypeAndDevice(
830 "/boot", OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800831 d = common.Difference(target_boot, source_boot)
832 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700833 if d is None:
834 include_full_boot = True
835 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
836 else:
837 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800838
Tao Bao89fbb0f2017-01-10 10:47:58 -0800839 print("boot target: %d source: %d diff: %d" % (
840 target_boot.size, source_boot.size, len(d)))
Geremy Condra36bd3652014-02-06 19:45:10 -0800841
Doug Zongkerf8340082014-08-05 10:39:37 -0700842 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800843
Doug Zongkerf8340082014-08-05 10:39:37 -0700844 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
845 (boot_type, boot_device,
846 source_boot.size, source_boot.sha1,
847 target_boot.size, target_boot.sha1))
Tao Baod8d14be2016-02-04 14:26:02 -0800848 size.append(target_boot.size)
849
850 if size:
851 script.CacheFreeSpaceCheck(max(size))
Geremy Condra36bd3652014-02-06 19:45:10 -0800852
853 device_specific.IncrementalOTA_VerifyEnd()
854
855 if OPTIONS.two_step:
Tao Baod42e97e2016-11-30 12:11:57 -0800856 # Stage 1/3: (b) Write recovery image to /boot.
857 _WriteRecoveryImageToBoot(script, output_zip)
858
Geremy Condra36bd3652014-02-06 19:45:10 -0800859 script.AppendExtra("""
860set_stage("%(bcb_dev)s", "2/3");
861reboot_now("%(bcb_dev)s", "");
862else
863""" % bcb_dev)
864
Tao Baod42e97e2016-11-30 12:11:57 -0800865 # Stage 3/3: Make changes.
866 script.Comment("Stage 3/3")
867
Jesse Zhao75bcea02015-01-06 10:59:53 -0800868 # Verify the existing partitions.
Tao Baod522bdc2016-04-12 15:53:16 -0700869 system_diff.WriteVerifyScript(script, touched_blocks_only=True)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800870 if vendor_diff:
Tao Baod522bdc2016-04-12 15:53:16 -0700871 vendor_diff.WriteVerifyScript(script, touched_blocks_only=True)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800872
Geremy Condra36bd3652014-02-06 19:45:10 -0800873 script.Comment("---- start making changes here ----")
874
875 device_specific.IncrementalOTA_InstallBegin()
876
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700877 system_diff.WriteScript(script, output_zip,
878 progress=0.8 if vendor_diff else 0.9)
Tao Bao68658c02015-06-01 13:40:49 -0700879
Doug Zongkerfc44a512014-08-26 13:10:25 -0700880 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700881 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800882
883 if OPTIONS.two_step:
884 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
885 script.WriteRawImage("/boot", "boot.img")
Tao Bao89fbb0f2017-01-10 10:47:58 -0800886 print("writing full boot image (forced by two-step mode)")
Geremy Condra36bd3652014-02-06 19:45:10 -0800887
888 if not OPTIONS.two_step:
889 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700890 if include_full_boot:
Tao Bao89fbb0f2017-01-10 10:47:58 -0800891 print("boot image changed; including full.")
Doug Zongkerf8340082014-08-05 10:39:37 -0700892 script.Print("Installing boot image...")
893 script.WriteRawImage("/boot", "boot.img")
894 else:
895 # Produce the boot image by applying a patch to the current
896 # contents of the boot partition, and write it back to the
897 # partition.
Tao Bao89fbb0f2017-01-10 10:47:58 -0800898 print("boot image changed; including patch.")
Doug Zongkerf8340082014-08-05 10:39:37 -0700899 script.Print("Patching boot image...")
900 script.ShowProgress(0.1, 10)
901 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
902 % (boot_type, boot_device,
903 source_boot.size, source_boot.sha1,
904 target_boot.size, target_boot.sha1),
905 "-",
906 target_boot.size, target_boot.sha1,
907 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800908 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -0800909 print("boot image unchanged; skipping.")
Geremy Condra36bd3652014-02-06 19:45:10 -0800910
911 # Do device-specific installation (eg, write radio image).
912 device_specific.IncrementalOTA_InstallEnd()
913
914 if OPTIONS.extra_script is not None:
915 script.AppendExtra(OPTIONS.extra_script)
916
Doug Zongker922206e2014-03-04 13:16:24 -0800917 if OPTIONS.wipe_user_data:
918 script.Print("Erasing user data...")
919 script.FormatPartition("/data")
Tao Bao5d182562016-02-23 11:38:39 -0800920 metadata["ota-wipe"] = "yes"
Doug Zongker922206e2014-03-04 13:16:24 -0800921
Geremy Condra36bd3652014-02-06 19:45:10 -0800922 if OPTIONS.two_step:
923 script.AppendExtra("""
924set_stage("%(bcb_dev)s", "");
925endif;
926endif;
927""" % bcb_dev)
928
929 script.SetProgress(1)
Tao Bao4996cf02016-03-08 17:53:39 -0800930 # For downgrade OTAs, we prefer to use the update-binary in the source
931 # build that is actually newer than the one in the target build.
932 if OPTIONS.downgrade:
933 script.AddToZip(source_zip, output_zip, input_path=OPTIONS.updater_binary)
934 else:
935 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -0800936 metadata["ota-required-cache"] = str(script.required_cache)
Geremy Condra36bd3652014-02-06 19:45:10 -0800937 WriteMetadata(metadata, output_zip)
938
Doug Zongker32b527d2014-03-04 10:03:02 -0800939
Tao Bao9bc6bb22015-11-09 16:58:28 -0800940def WriteVerifyPackage(input_zip, output_zip):
941 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
942
943 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
944 recovery_mount_options = OPTIONS.info_dict.get(
945 "recovery_mount_options")
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800946 oem_dicts = None
Tao Bao3e30d972016-03-15 13:20:19 -0700947 if oem_props:
Tao Baoebce6972017-03-06 10:22:20 -0800948 oem_dicts = _LoadOemDicts(script, recovery_mount_options)
Tao Bao9bc6bb22015-11-09 16:58:28 -0800949
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800950 target_fp = CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
951 OPTIONS.info_dict)
Tao Bao9bc6bb22015-11-09 16:58:28 -0800952 metadata = {
953 "post-build": target_fp,
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800954 "pre-device": GetOemProperty("ro.product.device", oem_props,
955 oem_dicts and oem_dicts[0],
Tao Bao9bc6bb22015-11-09 16:58:28 -0800956 OPTIONS.info_dict),
957 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
958 }
959
960 device_specific = common.DeviceSpecificParams(
961 input_zip=input_zip,
962 input_version=OPTIONS.info_dict["recovery_api_version"],
963 output_zip=output_zip,
964 script=script,
965 input_tmp=OPTIONS.input_tmp,
966 metadata=metadata,
967 info_dict=OPTIONS.info_dict)
968
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800969 AppendAssertions(script, OPTIONS.info_dict, oem_dicts)
Tao Bao9bc6bb22015-11-09 16:58:28 -0800970
971 script.Print("Verifying device images against %s..." % target_fp)
972 script.AppendExtra("")
973
974 script.Print("Verifying boot...")
975 boot_img = common.GetBootableImage(
976 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
977 boot_type, boot_device = common.GetTypeAndDevice(
978 "/boot", OPTIONS.info_dict)
979 script.Verify("%s:%s:%d:%s" % (
980 boot_type, boot_device, boot_img.size, boot_img.sha1))
981 script.AppendExtra("")
982
983 script.Print("Verifying recovery...")
984 recovery_img = common.GetBootableImage(
985 "recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
986 recovery_type, recovery_device = common.GetTypeAndDevice(
987 "/recovery", OPTIONS.info_dict)
988 script.Verify("%s:%s:%d:%s" % (
989 recovery_type, recovery_device, recovery_img.size, recovery_img.sha1))
990 script.AppendExtra("")
991
Tao Bao7e0f1602017-03-06 15:50:08 -0800992 system_tgt = GetImage("system", OPTIONS.input_tmp)
Tao Bao9bc6bb22015-11-09 16:58:28 -0800993 system_tgt.ResetFileMap()
994 system_diff = common.BlockDifference("system", system_tgt, src=None)
995 system_diff.WriteStrictVerifyScript(script)
996
997 if HasVendorPartition(input_zip):
Tao Bao7e0f1602017-03-06 15:50:08 -0800998 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp)
Tao Bao9bc6bb22015-11-09 16:58:28 -0800999 vendor_tgt.ResetFileMap()
1000 vendor_diff = common.BlockDifference("vendor", vendor_tgt, src=None)
1001 vendor_diff.WriteStrictVerifyScript(script)
1002
1003 # Device specific partitions, such as radio, bootloader and etc.
1004 device_specific.VerifyOTA_Assertions()
1005
1006 script.SetProgress(1.0)
1007 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -08001008 metadata["ota-required-cache"] = str(script.required_cache)
Tao Bao9bc6bb22015-11-09 16:58:28 -08001009 WriteMetadata(metadata, output_zip)
1010
1011
Tao Baoc098e9e2016-01-07 13:03:56 -08001012def WriteABOTAPackageWithBrilloScript(target_file, output_file,
1013 source_file=None):
1014 """Generate an Android OTA package that has A/B update payload."""
1015
Tao Bao2dd1c482017-02-03 16:49:39 -08001016 def ComputeStreamingMetadata(zip_file, reserve_space=False,
1017 expected_length=None):
1018 """Compute the streaming metadata for a given zip.
1019
1020 When 'reserve_space' is True, we reserve extra space for the offset and
1021 length of the metadata entry itself, although we don't know the final
1022 values until the package gets signed. This function will be called again
1023 after signing. We then write the actual values and pad the string to the
1024 length we set earlier. Note that we can't use the actual length of the
1025 metadata entry in the second run. Otherwise the offsets for other entries
1026 will be changing again.
1027 """
Tao Baoc96316c2017-01-24 22:10:49 -08001028
1029 def ComputeEntryOffsetSize(name):
1030 """Compute the zip entry offset and size."""
1031 info = zip_file.getinfo(name)
1032 offset = info.header_offset + len(info.FileHeader())
1033 size = info.file_size
Tao Bao2dd1c482017-02-03 16:49:39 -08001034 return '%s:%d:%d' % (os.path.basename(name), offset, size)
Tao Baoc96316c2017-01-24 22:10:49 -08001035
1036 # payload.bin and payload_properties.txt must exist.
1037 offsets = [ComputeEntryOffsetSize('payload.bin'),
1038 ComputeEntryOffsetSize('payload_properties.txt')]
1039
1040 # care_map.txt is available only if dm-verity is enabled.
1041 if 'care_map.txt' in zip_file.namelist():
1042 offsets.append(ComputeEntryOffsetSize('care_map.txt'))
Tao Bao2dd1c482017-02-03 16:49:39 -08001043
Tao Bao21803d32017-04-19 10:16:09 -07001044 if 'compatibility.zip' in zip_file.namelist():
1045 offsets.append(ComputeEntryOffsetSize('compatibility.zip'))
1046
Tao Bao2dd1c482017-02-03 16:49:39 -08001047 # 'META-INF/com/android/metadata' is required. We don't know its actual
1048 # offset and length (as well as the values for other entries). So we
1049 # reserve 10-byte as a placeholder, which is to cover the space for metadata
1050 # entry ('xx:xxx', since it's ZIP_STORED which should appear at the
1051 # beginning of the zip), as well as the possible value changes in other
1052 # entries.
1053 if reserve_space:
1054 offsets.append('metadata:' + ' ' * 10)
1055 else:
1056 offsets.append(ComputeEntryOffsetSize(METADATA_NAME))
1057
1058 value = ','.join(offsets)
1059 if expected_length is not None:
1060 assert len(value) <= expected_length, \
1061 'Insufficient reserved space: reserved=%d, actual=%d' % (
1062 expected_length, len(value))
1063 value += ' ' * (expected_length - len(value))
1064 return value
Tao Baoc96316c2017-01-24 22:10:49 -08001065
Alex Deymod8d96ec2016-06-10 16:38:31 -07001066 # The place where the output from the subprocess should go.
1067 log_file = sys.stdout if OPTIONS.verbose else subprocess.PIPE
1068
Tao Baodea0f8b2016-06-20 17:55:06 -07001069 # A/B updater expects a signing key in RSA format. Gets the key ready for
1070 # later use in step 3, unless a payload_signer has been specified.
1071 if OPTIONS.payload_signer is None:
1072 cmd = ["openssl", "pkcs8",
1073 "-in", OPTIONS.package_key + OPTIONS.private_key_suffix,
Christian Oderf63e2cd2017-05-01 22:30:15 +02001074 "-inform", "DER"]
1075 pw = OPTIONS.key_passwords[OPTIONS.package_key]
1076 cmd.extend(["-passin", "pass:" + pw] if pw else ["-nocrypt"])
Tao Baodea0f8b2016-06-20 17:55:06 -07001077 rsa_key = common.MakeTempFile(prefix="key-", suffix=".key")
1078 cmd.extend(["-out", rsa_key])
Christian Oderf63e2cd2017-05-01 22:30:15 +02001079 p1 = common.Run(cmd, verbose=False, stdout=log_file, stderr=subprocess.STDOUT)
Tao Bao6047c242016-06-21 13:35:26 -07001080 p1.communicate()
Tao Baodea0f8b2016-06-20 17:55:06 -07001081 assert p1.returncode == 0, "openssl pkcs8 failed"
Tao Baoc098e9e2016-01-07 13:03:56 -08001082
Tao Baodea0f8b2016-06-20 17:55:06 -07001083 # Stage the output zip package for package signing.
Tao Baoc098e9e2016-01-07 13:03:56 -08001084 temp_zip_file = tempfile.NamedTemporaryFile()
1085 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1086 compression=zipfile.ZIP_DEFLATED)
1087
1088 # Metadata to comply with Android OTA package format.
1089 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties", None)
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -08001090 oem_dicts = None
Tao Baoc098e9e2016-01-07 13:03:56 -08001091 if oem_props:
Tao Baoebce6972017-03-06 10:22:20 -08001092 oem_dicts = _LoadOemDicts(None)
Tao Baoc098e9e2016-01-07 13:03:56 -08001093
1094 metadata = {
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -08001095 "post-build": CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
Tao Baoc098e9e2016-01-07 13:03:56 -08001096 OPTIONS.info_dict),
Tianjie Xud06f07e2016-06-09 14:18:45 -07001097 "post-build-incremental" : GetBuildProp("ro.build.version.incremental",
1098 OPTIONS.info_dict),
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -08001099 "pre-device": GetOemProperty("ro.product.device", oem_props,
1100 oem_dicts and oem_dicts[0],
Tao Baoc098e9e2016-01-07 13:03:56 -08001101 OPTIONS.info_dict),
Tao Baod8d14be2016-02-04 14:26:02 -08001102 "ota-required-cache": "0",
1103 "ota-type": "AB",
Tao Baoc098e9e2016-01-07 13:03:56 -08001104 }
1105
1106 if source_file is not None:
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -08001107 metadata["pre-build"] = CalculateFingerprint(oem_props,
1108 oem_dicts and oem_dicts[0],
Tao Baoc098e9e2016-01-07 13:03:56 -08001109 OPTIONS.source_info_dict)
Tianjie Xud06f07e2016-06-09 14:18:45 -07001110 metadata["pre-build-incremental"] = GetBuildProp(
1111 "ro.build.version.incremental", OPTIONS.source_info_dict)
Tao Baoc098e9e2016-01-07 13:03:56 -08001112
Tao Baob31892e2017-02-07 11:21:17 -08001113 HandleDowngradeMetadata(metadata)
1114 else:
1115 metadata["post-timestamp"] = GetBuildProp(
1116 "ro.build.date.utc", OPTIONS.info_dict)
1117
Tao Baoc098e9e2016-01-07 13:03:56 -08001118 # 1. Generate payload.
1119 payload_file = common.MakeTempFile(prefix="payload-", suffix=".bin")
1120 cmd = ["brillo_update_payload", "generate",
1121 "--payload", payload_file,
1122 "--target_image", target_file]
1123 if source_file is not None:
1124 cmd.extend(["--source_image", source_file])
Alex Deymod8d96ec2016-06-10 16:38:31 -07001125 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1126 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001127 assert p1.returncode == 0, "brillo_update_payload generate failed"
1128
1129 # 2. Generate hashes of the payload and metadata files.
1130 payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
1131 metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
1132 cmd = ["brillo_update_payload", "hash",
1133 "--unsigned_payload", payload_file,
1134 "--signature_size", "256",
1135 "--metadata_hash_file", metadata_sig_file,
1136 "--payload_hash_file", payload_sig_file]
Alex Deymod8d96ec2016-06-10 16:38:31 -07001137 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1138 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001139 assert p1.returncode == 0, "brillo_update_payload hash failed"
1140
1141 # 3. Sign the hashes and insert them back into the payload file.
1142 signed_payload_sig_file = common.MakeTempFile(prefix="signed-sig-",
1143 suffix=".bin")
1144 signed_metadata_sig_file = common.MakeTempFile(prefix="signed-sig-",
1145 suffix=".bin")
1146 # 3a. Sign the payload hash.
Tao Baodea0f8b2016-06-20 17:55:06 -07001147 if OPTIONS.payload_signer is not None:
Baligh Uddin2abbbd02016-06-22 12:14:16 -07001148 cmd = [OPTIONS.payload_signer]
1149 cmd.extend(OPTIONS.payload_signer_args)
Tao Baodea0f8b2016-06-20 17:55:06 -07001150 else:
1151 cmd = ["openssl", "pkeyutl", "-sign",
1152 "-inkey", rsa_key,
1153 "-pkeyopt", "digest:sha256"]
1154 cmd.extend(["-in", payload_sig_file,
1155 "-out", signed_payload_sig_file])
Alex Deymod8d96ec2016-06-10 16:38:31 -07001156 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1157 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001158 assert p1.returncode == 0, "openssl sign payload failed"
1159
1160 # 3b. Sign the metadata hash.
Tao Baodea0f8b2016-06-20 17:55:06 -07001161 if OPTIONS.payload_signer is not None:
Baligh Uddin2abbbd02016-06-22 12:14:16 -07001162 cmd = [OPTIONS.payload_signer]
1163 cmd.extend(OPTIONS.payload_signer_args)
Tao Baodea0f8b2016-06-20 17:55:06 -07001164 else:
1165 cmd = ["openssl", "pkeyutl", "-sign",
1166 "-inkey", rsa_key,
1167 "-pkeyopt", "digest:sha256"]
1168 cmd.extend(["-in", metadata_sig_file,
1169 "-out", signed_metadata_sig_file])
Alex Deymod8d96ec2016-06-10 16:38:31 -07001170 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1171 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001172 assert p1.returncode == 0, "openssl sign metadata failed"
1173
1174 # 3c. Insert the signatures back into the payload file.
1175 signed_payload_file = common.MakeTempFile(prefix="signed-payload-",
1176 suffix=".bin")
1177 cmd = ["brillo_update_payload", "sign",
1178 "--unsigned_payload", payload_file,
1179 "--payload", signed_payload_file,
1180 "--signature_size", "256",
1181 "--metadata_signature_file", signed_metadata_sig_file,
1182 "--payload_signature_file", signed_payload_sig_file]
Alex Deymod8d96ec2016-06-10 16:38:31 -07001183 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1184 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001185 assert p1.returncode == 0, "brillo_update_payload sign failed"
1186
Alex Deymo19241c12016-02-04 22:29:29 -08001187 # 4. Dump the signed payload properties.
1188 properties_file = common.MakeTempFile(prefix="payload-properties-",
1189 suffix=".txt")
1190 cmd = ["brillo_update_payload", "properties",
1191 "--payload", signed_payload_file,
1192 "--properties_file", properties_file]
Alex Deymod8d96ec2016-06-10 16:38:31 -07001193 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1194 p1.communicate()
Alex Deymo19241c12016-02-04 22:29:29 -08001195 assert p1.returncode == 0, "brillo_update_payload properties failed"
1196
Tao Bao7c5dc572016-06-14 17:48:11 -07001197 if OPTIONS.wipe_user_data:
1198 with open(properties_file, "a") as f:
1199 f.write("POWERWASH=1\n")
1200 metadata["ota-wipe"] = "yes"
1201
Tao Baoc96316c2017-01-24 22:10:49 -08001202 # Add the signed payload file and properties into the zip. In order to
1203 # support streaming, we pack payload.bin, payload_properties.txt and
1204 # care_map.txt as ZIP_STORED. So these entries can be read directly with
1205 # the offset and length pairs.
Tao Baoc098e9e2016-01-07 13:03:56 -08001206 common.ZipWrite(output_zip, signed_payload_file, arcname="payload.bin",
1207 compress_type=zipfile.ZIP_STORED)
Tao Baoc96316c2017-01-24 22:10:49 -08001208 common.ZipWrite(output_zip, properties_file,
1209 arcname="payload_properties.txt",
1210 compress_type=zipfile.ZIP_STORED)
Tao Baoc098e9e2016-01-07 13:03:56 -08001211
Tianjie Xucfa86222016-03-07 16:31:19 -08001212 # If dm-verity is supported for the device, copy contents of care_map
1213 # into A/B OTA package.
Tao Bao21803d32017-04-19 10:16:09 -07001214 target_zip = zipfile.ZipFile(target_file, "r")
Tianjie Xu6b2e1552017-06-01 11:32:32 -07001215 if (OPTIONS.info_dict.get("verity") == "true" or
Bowgo Tsai3e599ea2017-05-26 18:30:04 +08001216 OPTIONS.info_dict.get("avb_enable") == "true"):
Tianjie Xucfa86222016-03-07 16:31:19 -08001217 care_map_path = "META/care_map.txt"
1218 namelist = target_zip.namelist()
1219 if care_map_path in namelist:
1220 care_map_data = target_zip.read(care_map_path)
Tao Baoc96316c2017-01-24 22:10:49 -08001221 common.ZipWriteStr(output_zip, "care_map.txt", care_map_data,
1222 compress_type=zipfile.ZIP_STORED)
Tianjie Xucfa86222016-03-07 16:31:19 -08001223 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001224 print("Warning: cannot find care map file in target_file package")
Tao Bao21803d32017-04-19 10:16:09 -07001225
Tao Baobcd1d162017-08-26 13:10:26 -07001226 # OPTIONS.source_info_dict must be None for incrementals.
1227 if source_file is None:
1228 assert OPTIONS.source_info_dict is None
Tao Bao21803d32017-04-19 10:16:09 -07001229
Tao Baobcd1d162017-08-26 13:10:26 -07001230 AddCompatibilityArchiveIfTrebleEnabled(
1231 target_zip, output_zip, OPTIONS.info_dict, OPTIONS.source_info_dict)
Tao Bao21803d32017-04-19 10:16:09 -07001232
Tao Bao21803d32017-04-19 10:16:09 -07001233 common.ZipClose(target_zip)
Tianjie Xucfa86222016-03-07 16:31:19 -08001234
Tao Bao2dd1c482017-02-03 16:49:39 -08001235 # Write the current metadata entry with placeholders.
Tao Baobfdcb122017-01-31 15:06:05 -08001236 metadata['ota-streaming-property-files'] = ComputeStreamingMetadata(
Tao Bao2dd1c482017-02-03 16:49:39 -08001237 output_zip, reserve_space=True)
Tao Baoc96316c2017-01-24 22:10:49 -08001238 WriteMetadata(metadata, output_zip)
1239 common.ZipClose(output_zip)
1240
Tao Bao2dd1c482017-02-03 16:49:39 -08001241 # SignOutput(), which in turn calls signapk.jar, will possibly reorder the
1242 # zip entries, as well as padding the entry headers. We do a preliminary
1243 # signing (with an incomplete metadata entry) to allow that to happen. Then
1244 # compute the zip entry offsets, write back the final metadata and do the
1245 # final signing.
1246 prelim_signing = tempfile.NamedTemporaryFile()
1247 SignOutput(temp_zip_file.name, prelim_signing.name)
1248 common.ZipClose(temp_zip_file)
Tao Baoc96316c2017-01-24 22:10:49 -08001249
Tao Bao2dd1c482017-02-03 16:49:39 -08001250 # Open the signed zip. Compute the final metadata that's needed for streaming.
1251 prelim_zip = zipfile.ZipFile(prelim_signing, "r",
1252 compression=zipfile.ZIP_DEFLATED)
1253 expected_length = len(metadata['ota-streaming-property-files'])
1254 metadata['ota-streaming-property-files'] = ComputeStreamingMetadata(
1255 prelim_zip, reserve_space=False, expected_length=expected_length)
1256
1257 # Copy the zip entries, as we cannot update / delete entries with zipfile.
1258 final_signing = tempfile.NamedTemporaryFile()
1259 output_zip = zipfile.ZipFile(final_signing, "w",
1260 compression=zipfile.ZIP_DEFLATED)
1261 for item in prelim_zip.infolist():
1262 if item.filename == METADATA_NAME:
1263 continue
1264
1265 data = prelim_zip.read(item.filename)
1266 out_info = copy.copy(item)
1267 common.ZipWriteStr(output_zip, out_info, data)
1268
1269 # Now write the final metadata entry.
1270 WriteMetadata(metadata, output_zip)
1271 common.ZipClose(prelim_zip)
1272 common.ZipClose(output_zip)
1273
1274 # Re-sign the package after updating the metadata entry.
1275 SignOutput(final_signing.name, output_file)
1276 final_signing.close()
1277
1278 # Reopen the final signed zip to double check the streaming metadata.
Tao Baoc96316c2017-01-24 22:10:49 -08001279 output_zip = zipfile.ZipFile(output_file, "r")
Tao Bao2dd1c482017-02-03 16:49:39 -08001280 actual = metadata['ota-streaming-property-files'].strip()
1281 expected = ComputeStreamingMetadata(output_zip)
1282 assert actual == expected, \
1283 "Mismatching streaming metadata: %s vs %s." % (actual, expected)
Tao Baoc96316c2017-01-24 22:10:49 -08001284 common.ZipClose(output_zip)
1285
Tao Baoc098e9e2016-01-07 13:03:56 -08001286
Doug Zongkereef39442009-04-02 12:14:19 -07001287def main(argv):
1288
1289 def option_handler(o, a):
Tao Bao4b76a0e2017-10-31 12:13:33 -07001290 if o in ("-k", "--package_key"):
Doug Zongkereef39442009-04-02 12:14:19 -07001291 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001292 elif o in ("-i", "--incremental_from"):
1293 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001294 elif o == "--full_radio":
1295 OPTIONS.full_radio = True
leozwangaa6c1a12015-08-14 10:57:58 -07001296 elif o == "--full_bootloader":
1297 OPTIONS.full_bootloader = True
Tao Bao337633f2017-12-06 15:20:19 -08001298 elif o == "--wipe_user_data":
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001299 OPTIONS.wipe_user_data = True
Tao Bao5d182562016-02-23 11:38:39 -08001300 elif o == "--downgrade":
1301 OPTIONS.downgrade = True
1302 OPTIONS.wipe_user_data = True
Tao Bao3e6161a2017-02-28 11:48:48 -08001303 elif o == "--override_timestamp":
1304 OPTIONS.timestamp = True
Michael Runge6e836112014-04-15 17:40:21 -07001305 elif o in ("-o", "--oem_settings"):
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -08001306 OPTIONS.oem_source = a.split(',')
Tao Bao8608cde2016-02-25 19:49:55 -08001307 elif o == "--oem_no_mount":
1308 OPTIONS.oem_no_mount = True
Doug Zongker1c390a22009-05-14 19:06:36 -07001309 elif o in ("-e", "--extra_script"):
1310 OPTIONS.extra_script = a
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001311 elif o in ("-t", "--worker_threads"):
1312 if a.isdigit():
1313 OPTIONS.worker_threads = int(a)
1314 else:
1315 raise ValueError("Cannot parse value %r for option %r - only "
1316 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001317 elif o in ("-2", "--two_step"):
1318 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001319 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001320 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001321 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001322 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001323 elif o == "--block":
1324 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001325 elif o in ("-b", "--binary"):
1326 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001327 elif o in ("--no_fallback_to_full",):
1328 OPTIONS.fallback_to_full = False
Tao Bao8dcf7382015-05-21 14:09:49 -07001329 elif o == "--stash_threshold":
1330 try:
1331 OPTIONS.stash_threshold = float(a)
1332 except ValueError:
1333 raise ValueError("Cannot parse value %r for option %r - expecting "
1334 "a float" % (a, o))
Tao Bao9bc6bb22015-11-09 16:58:28 -08001335 elif o == "--gen_verify":
1336 OPTIONS.gen_verify = True
Tao Baod62c6032015-11-30 09:40:20 -08001337 elif o == "--log_diff":
1338 OPTIONS.log_diff = a
Tao Baodea0f8b2016-06-20 17:55:06 -07001339 elif o == "--payload_signer":
1340 OPTIONS.payload_signer = a
Baligh Uddin2abbbd02016-06-22 12:14:16 -07001341 elif o == "--payload_signer_args":
1342 OPTIONS.payload_signer_args = shlex.split(a)
Dan Willemsencea5cd22017-03-21 14:44:27 -07001343 elif o == "--extracted_input_target_files":
1344 OPTIONS.extracted_input = a
Doug Zongkereef39442009-04-02 12:14:19 -07001345 else:
1346 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001347 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001348
1349 args = common.ParseOptions(argv, __doc__,
Tao Bao337633f2017-12-06 15:20:19 -08001350 extra_opts="b:k:i:d:e:t:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001351 extra_long_opts=[
Dan Albert8b72aef2015-03-23 19:13:21 -07001352 "package_key=",
1353 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001354 "full_radio",
leozwangaa6c1a12015-08-14 10:57:58 -07001355 "full_bootloader",
Dan Albert8b72aef2015-03-23 19:13:21 -07001356 "wipe_user_data",
Tao Bao5d182562016-02-23 11:38:39 -08001357 "downgrade",
Tao Bao3e6161a2017-02-28 11:48:48 -08001358 "override_timestamp",
Dan Albert8b72aef2015-03-23 19:13:21 -07001359 "extra_script=",
1360 "worker_threads=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001361 "two_step",
1362 "no_signing",
1363 "block",
1364 "binary=",
1365 "oem_settings=",
Tao Bao8608cde2016-02-25 19:49:55 -08001366 "oem_no_mount",
Dan Albert8b72aef2015-03-23 19:13:21 -07001367 "verify",
1368 "no_fallback_to_full",
Tao Bao8dcf7382015-05-21 14:09:49 -07001369 "stash_threshold=",
Tao Baod62c6032015-11-30 09:40:20 -08001370 "gen_verify",
1371 "log_diff=",
Tao Baodea0f8b2016-06-20 17:55:06 -07001372 "payload_signer=",
Baligh Uddin2abbbd02016-06-22 12:14:16 -07001373 "payload_signer_args=",
Dan Willemsencea5cd22017-03-21 14:44:27 -07001374 "extracted_input_target_files=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001375 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001376
1377 if len(args) != 2:
1378 common.Usage(__doc__)
1379 sys.exit(1)
1380
Tao Bao5d182562016-02-23 11:38:39 -08001381 if OPTIONS.downgrade:
1382 # Sanity check to enforce a data wipe.
1383 if not OPTIONS.wipe_user_data:
1384 raise ValueError("Cannot downgrade without a data wipe")
1385
1386 # We should only allow downgrading incrementals (as opposed to full).
1387 # Otherwise the device may go back from arbitrary build with this full
1388 # OTA package.
1389 if OPTIONS.incremental_source is None:
Elliott Hughesd8a52f92016-06-20 14:35:47 -07001390 raise ValueError("Cannot generate downgradable full OTAs")
Tao Bao5d182562016-02-23 11:38:39 -08001391
Tao Bao3e6161a2017-02-28 11:48:48 -08001392 assert not (OPTIONS.downgrade and OPTIONS.timestamp), \
1393 "Cannot have --downgrade AND --override_timestamp both"
1394
Tao Baoc098e9e2016-01-07 13:03:56 -08001395 # Load the dict file from the zip directly to have a peek at the OTA type.
1396 # For packages using A/B update, unzipping is not needed.
Dan Willemsencea5cd22017-03-21 14:44:27 -07001397 if OPTIONS.extracted_input is not None:
1398 OPTIONS.info_dict = common.LoadInfoDict(OPTIONS.extracted_input, OPTIONS.extracted_input)
1399 else:
1400 input_zip = zipfile.ZipFile(args[0], "r")
1401 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
1402 common.ZipClose(input_zip)
Tao Baoc098e9e2016-01-07 13:03:56 -08001403
1404 ab_update = OPTIONS.info_dict.get("ab_update") == "true"
1405
Christian Oderf63e2cd2017-05-01 22:30:15 +02001406 # Use the default key to sign the package if not specified with package_key.
1407 # package_keys are needed on ab_updates, so always define them if an
1408 # ab_update is getting created.
1409 if not OPTIONS.no_signing or ab_update:
1410 if OPTIONS.package_key is None:
1411 OPTIONS.package_key = OPTIONS.info_dict.get(
1412 "default_system_dev_certificate",
1413 "build/target/product/security/testkey")
1414 # Get signing keys
1415 OPTIONS.key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
1416
Tao Baoc098e9e2016-01-07 13:03:56 -08001417 if ab_update:
1418 if OPTIONS.incremental_source is not None:
1419 OPTIONS.target_info_dict = OPTIONS.info_dict
1420 source_zip = zipfile.ZipFile(OPTIONS.incremental_source, "r")
1421 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1422 common.ZipClose(source_zip)
1423
1424 if OPTIONS.verbose:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001425 print("--- target info ---")
Tao Baoc098e9e2016-01-07 13:03:56 -08001426 common.DumpInfoDict(OPTIONS.info_dict)
1427
1428 if OPTIONS.incremental_source is not None:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001429 print("--- source info ---")
Tao Baoc098e9e2016-01-07 13:03:56 -08001430 common.DumpInfoDict(OPTIONS.source_info_dict)
1431
1432 WriteABOTAPackageWithBrilloScript(
1433 target_file=args[0],
1434 output_file=args[1],
1435 source_file=OPTIONS.incremental_source)
1436
Tao Bao89fbb0f2017-01-10 10:47:58 -08001437 print("done.")
Tao Baoc098e9e2016-01-07 13:03:56 -08001438 return
1439
Doug Zongker1c390a22009-05-14 19:06:36 -07001440 if OPTIONS.extra_script is not None:
1441 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1442
Dan Willemsencea5cd22017-03-21 14:44:27 -07001443 if OPTIONS.extracted_input is not None:
1444 OPTIONS.input_tmp = OPTIONS.extracted_input
1445 OPTIONS.target_tmp = OPTIONS.input_tmp
1446 OPTIONS.info_dict = common.LoadInfoDict(OPTIONS.input_tmp, OPTIONS.input_tmp)
1447 input_zip = zipfile.ZipFile(args[0], "r")
1448 else:
1449 print("unzipping target target-files...")
1450 OPTIONS.input_tmp, input_zip = common.UnzipTemp(
1451 args[0], UNZIP_PATTERN)
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001452
Dan Willemsencea5cd22017-03-21 14:44:27 -07001453 OPTIONS.target_tmp = OPTIONS.input_tmp
1454 OPTIONS.info_dict = common.LoadInfoDict(input_zip, OPTIONS.target_tmp)
Kenny Roote2e9f612013-05-29 12:59:35 -07001455
Doug Zongker37974732010-09-16 17:44:38 -07001456 if OPTIONS.verbose:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001457 print("--- target info ---")
Doug Zongker37974732010-09-16 17:44:38 -07001458 common.DumpInfoDict(OPTIONS.info_dict)
1459
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001460 # If the caller explicitly specified the device-specific extensions
1461 # path via -s/--device_specific, use that. Otherwise, use
1462 # META/releasetools.py if it is present in the target target_files.
1463 # Otherwise, take the path of the file from 'tool_extensions' in the
1464 # info dict and look for that in the local filesystem, relative to
1465 # the current directory.
1466
Doug Zongker37974732010-09-16 17:44:38 -07001467 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001468 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1469 if os.path.exists(from_input):
Tao Bao89fbb0f2017-01-10 10:47:58 -08001470 print("(using device-specific extensions from target_files)")
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001471 OPTIONS.device_specific = from_input
1472 else:
1473 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1474
Doug Zongker37974732010-09-16 17:44:38 -07001475 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001476 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001477
Tao Baoc098e9e2016-01-07 13:03:56 -08001478 if OPTIONS.info_dict.get("no_recovery") == "true":
Tao Baodb45efa2015-10-27 19:25:18 -07001479 raise common.ExternalError(
1480 "--- target build has specified no recovery ---")
1481
Tao Bao767e3ac2015-11-10 12:19:19 -08001482 # Set up the output zip. Create a temporary zip file if signing is needed.
1483 if OPTIONS.no_signing:
1484 if os.path.exists(args[1]):
1485 os.unlink(args[1])
1486 output_zip = zipfile.ZipFile(args[1], "w",
1487 compression=zipfile.ZIP_DEFLATED)
1488 else:
1489 temp_zip_file = tempfile.NamedTemporaryFile()
1490 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1491 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001492
Daniel Rosenberg40ef35b2015-11-10 19:21:34 -08001493 # Non A/B OTAs rely on /cache partition to store temporary files.
Tao Bao767e3ac2015-11-10 12:19:19 -08001494 cache_size = OPTIONS.info_dict.get("cache_size", None)
Tao Baoc098e9e2016-01-07 13:03:56 -08001495 if cache_size is None:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001496 print("--- can't determine the cache partition size ---")
Tao Bao767e3ac2015-11-10 12:19:19 -08001497 OPTIONS.cache_size = cache_size
Tao Bao8dcf7382015-05-21 14:09:49 -07001498
Tao Bao9bc6bb22015-11-09 16:58:28 -08001499 # Generate a verify package.
1500 if OPTIONS.gen_verify:
1501 WriteVerifyPackage(input_zip, output_zip)
1502
Tao Bao767e3ac2015-11-10 12:19:19 -08001503 # Generate a full OTA.
Tao Bao9bc6bb22015-11-09 16:58:28 -08001504 elif OPTIONS.incremental_source is None:
Tao Baoc098e9e2016-01-07 13:03:56 -08001505 WriteFullOTAPackage(input_zip, output_zip)
Tao Bao767e3ac2015-11-10 12:19:19 -08001506
1507 # Generate an incremental OTA. It will fall back to generate a full OTA on
1508 # failure unless no_fallback_to_full is specified.
1509 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001510 print("unzipping source target-files...")
Tao Bao767e3ac2015-11-10 12:19:19 -08001511 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
Tao Bao6b0b2f92017-03-05 11:38:11 -08001512 OPTIONS.incremental_source,
Tao Bao457cbf62017-03-06 09:56:01 -08001513 UNZIP_PATTERN)
Tao Bao767e3ac2015-11-10 12:19:19 -08001514 OPTIONS.target_info_dict = OPTIONS.info_dict
1515 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip,
1516 OPTIONS.source_tmp)
1517 if OPTIONS.verbose:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001518 print("--- source info ---")
Tao Bao767e3ac2015-11-10 12:19:19 -08001519 common.DumpInfoDict(OPTIONS.source_info_dict)
1520 try:
Tao Bao457cbf62017-03-06 09:56:01 -08001521 WriteBlockIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Baod62c6032015-11-30 09:40:20 -08001522 if OPTIONS.log_diff:
1523 out_file = open(OPTIONS.log_diff, 'w')
1524 import target_files_diff
1525 target_files_diff.recursiveDiff('',
1526 OPTIONS.source_tmp,
1527 OPTIONS.input_tmp,
1528 out_file)
1529 out_file.close()
Tao Bao767e3ac2015-11-10 12:19:19 -08001530 except ValueError:
1531 if not OPTIONS.fallback_to_full:
1532 raise
Tao Bao89fbb0f2017-01-10 10:47:58 -08001533 print("--- failed to build incremental; falling back to full ---")
Tao Bao767e3ac2015-11-10 12:19:19 -08001534 OPTIONS.incremental_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -07001535 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001536
Tao Bao767e3ac2015-11-10 12:19:19 -08001537 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001538
Tao Bao767e3ac2015-11-10 12:19:19 -08001539 # Sign the generated zip package unless no_signing is specified.
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001540 if not OPTIONS.no_signing:
1541 SignOutput(temp_zip_file.name, args[1])
1542 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001543
Tao Bao89fbb0f2017-01-10 10:47:58 -08001544 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001545
1546
1547if __name__ == '__main__':
1548 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001549 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001550 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001551 except common.ExternalError as e:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001552 print("\n ERROR: %s\n" % (e,))
Doug Zongkereef39442009-04-02 12:14:19 -07001553 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001554 finally:
1555 common.Cleanup()