blob: 1a4383c2bf8baf8497b55dff1d487725d613e0ce [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
Tao Bao481bab82017-12-21 11:23:09 -080052 properties on the OEM partition of the intended device. Multiple expected
53 values can be used by providing multiple files. Only the first dict will
54 be used to compute fingerprint, while the rest will be used to assert
55 OEM-specific properties.
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -080056
Tao Bao8608cde2016-02-25 19:49:55 -080057 --oem_no_mount
58 For devices with OEM-specific properties but without an OEM partition,
59 do not mount the OEM partition in the updater-script. This should be
60 very rarely used, since it's expected to have a dedicated OEM partition
61 for OEM-specific properties. Only meaningful when -o is specified.
62
Tao Bao337633f2017-12-06 15:20:19 -080063 --wipe_user_data
Doug Zongkerdbfaae52009-04-21 17:12:54 -070064 Generate an OTA package that will wipe the user data partition
65 when installed.
66
Tao Bao5d182562016-02-23 11:38:39 -080067 --downgrade
68 Intentionally generate an incremental OTA that updates from a newer
69 build to an older one (based on timestamp comparison). "post-timestamp"
70 will be replaced by "ota-downgrade=yes" in the metadata file. A data
71 wipe will always be enforced, so "ota-wipe=yes" will also be included in
Tao Bao4996cf02016-03-08 17:53:39 -080072 the metadata file. The update-binary in the source build will be used in
Tao Bao3e6161a2017-02-28 11:48:48 -080073 the OTA package, unless --binary flag is specified. Please also check the
74 doc for --override_timestamp below.
75
76 --override_timestamp
77 Intentionally generate an incremental OTA that updates from a newer
78 build to an older one (based on timestamp comparison), by overriding the
79 timestamp in package metadata. This differs from --downgrade flag: we
80 know for sure this is NOT an actual downgrade case, but two builds are
81 cut in a reverse order. A legit use case is that we cut a new build C
82 (after having A and B), but want to enfore an update path of A -> C -> B.
83 Specifying --downgrade may not help since that would enforce a data wipe
84 for C -> B update. The value of "post-timestamp" will be set to the newer
85 timestamp plus one, so that the package can be pushed and applied.
Tao Bao5d182562016-02-23 11:38:39 -080086
Doug Zongker1c390a22009-05-14 19:06:36 -070087 -e (--extra_script) <file>
88 Insert the contents of file at the end of the update script.
89
Doug Zongker9b23f2c2013-11-25 14:44:12 -080090 -2 (--two_step)
91 Generate a 'two-step' OTA package, where recovery is updated
92 first, so that any changes made to the system partition are done
93 using the new recovery (new kernel, etc.).
94
Doug Zongker26e66192014-02-20 13:22:07 -080095 --block
Tao Bao457cbf62017-03-06 09:56:01 -080096 Generate a block-based OTA for non-A/B device. We have deprecated the
97 support for file-based OTA since O. Block-based OTA will be used by
98 default for all non-A/B devices. Keeping this flag here to not break
99 existing callers.
Doug Zongker26e66192014-02-20 13:22:07 -0800100
Doug Zongker25568482014-03-03 10:21:27 -0800101 -b (--binary) <file>
102 Use the given binary as the update-binary in the output package,
103 instead of the binary in the build's target_files. Use for
104 development only.
105
Martin Blumenstingl374e1142014-05-31 20:42:55 +0200106 -t (--worker_threads) <int>
107 Specifies the number of worker-threads that will be used when
108 generating patches for incremental updates (defaults to 3).
109
Tao Bao8dcf7382015-05-21 14:09:49 -0700110 --stash_threshold <float>
111 Specifies the threshold that will be used to compute the maximum
112 allowed stash size (defaults to 0.8).
Tao Bao9bc6bb22015-11-09 16:58:28 -0800113
Tao Baod62c6032015-11-30 09:40:20 -0800114 --log_diff <file>
115 Generate a log file that shows the differences in the source and target
116 builds for an incremental package. This option is only meaningful when
117 -i is specified.
Tao Baodea0f8b2016-06-20 17:55:06 -0700118
119 --payload_signer <signer>
120 Specify the signer when signing the payload and metadata for A/B OTAs.
121 By default (i.e. without this flag), it calls 'openssl pkeyutl' to sign
122 with the package private key. If the private key cannot be accessed
123 directly, a payload signer that knows how to do that should be specified.
124 The signer will be supplied with "-inkey <path_to_key>",
125 "-in <input_file>" and "-out <output_file>" parameters.
Baligh Uddin2abbbd02016-06-22 12:14:16 -0700126
127 --payload_signer_args <args>
128 Specify the arguments needed for payload signer.
Doug Zongkereef39442009-04-02 12:14:19 -0700129"""
130
Tao Bao89fbb0f2017-01-10 10:47:58 -0800131from __future__ import print_function
132
Doug Zongkerfc44a512014-08-26 13:10:25 -0700133import multiprocessing
Tao Bao2dd1c482017-02-03 16:49:39 -0800134import os.path
Baligh Uddin2abbbd02016-06-22 12:14:16 -0700135import shlex
Tao Bao481bab82017-12-21 11:23:09 -0800136import subprocess
137import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700138import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -0700139import zipfile
140
141import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700142import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -0700143import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700144
Tao Bao481bab82017-12-21 11:23:09 -0800145if sys.hexversion < 0x02070000:
146 print("Python 2.7 or newer is required.", file=sys.stderr)
147 sys.exit(1)
148
149
Doug Zongkereef39442009-04-02 12:14:19 -0700150OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700151OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700152OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700153OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700154OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700155OPTIONS.wipe_user_data = False
Tao Bao5d182562016-02-23 11:38:39 -0800156OPTIONS.downgrade = False
Tao Bao3e6161a2017-02-28 11:48:48 -0800157OPTIONS.timestamp = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700158OPTIONS.extra_script = None
Doug Zongkerfc44a512014-08-26 13:10:25 -0700159OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
160if OPTIONS.worker_threads == 0:
161 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800162OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900163OPTIONS.no_signing = False
Tao Bao457cbf62017-03-06 09:56:01 -0800164OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -0800165OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700166OPTIONS.oem_source = None
Tao Bao8608cde2016-02-25 19:49:55 -0800167OPTIONS.oem_no_mount = False
Doug Zongker62d4f182014-08-04 16:06:43 -0700168OPTIONS.fallback_to_full = True
Tao Bao43078aa2015-04-21 14:32:35 -0700169OPTIONS.full_radio = False
leozwangaa6c1a12015-08-14 10:57:58 -0700170OPTIONS.full_bootloader = False
Tao Baod47d8e12015-05-21 14:09:49 -0700171# Stash size cannot exceed cache_size * threshold.
172OPTIONS.cache_size = None
173OPTIONS.stash_threshold = 0.8
Tao Baod62c6032015-11-30 09:40:20 -0800174OPTIONS.log_diff = None
Tao Baodea0f8b2016-06-20 17:55:06 -0700175OPTIONS.payload_signer = None
Baligh Uddin2abbbd02016-06-22 12:14:16 -0700176OPTIONS.payload_signer_args = []
Tao Bao5f8ff932017-03-21 22:35:00 -0700177OPTIONS.extracted_input = None
Christian Oderf63e2cd2017-05-01 22:30:15 +0200178OPTIONS.key_passwords = []
Tao Bao8dcf7382015-05-21 14:09:49 -0700179
Tao Bao2dd1c482017-02-03 16:49:39 -0800180METADATA_NAME = 'META-INF/com/android/metadata'
Tao Bao6b0b2f92017-03-05 11:38:11 -0800181UNZIP_PATTERN = ['IMAGES/*', 'META/*']
182
Tao Bao2dd1c482017-02-03 16:49:39 -0800183
Tao Bao481bab82017-12-21 11:23:09 -0800184class BuildInfo(object):
185 """A class that holds the information for a given build.
186
187 This class wraps up the property querying for a given source or target build.
188 It abstracts away the logic of handling OEM-specific properties, and caches
189 the commonly used properties such as fingerprint.
190
191 There are two types of info dicts: a) build-time info dict, which is generated
192 at build time (i.e. included in a target_files zip); b) OEM info dict that is
193 specified at package generation time (via command line argument
194 '--oem_settings'). If a build doesn't use OEM-specific properties (i.e. not
195 having "oem_fingerprint_properties" in build-time info dict), all the queries
196 would be answered based on build-time info dict only. Otherwise if using
197 OEM-specific properties, some of them will be calculated from two info dicts.
198
199 Users can query properties similarly as using a dict() (e.g. info['fstab']),
200 or to query build properties via GetBuildProp() or GetVendorBuildProp().
201
202 Attributes:
203 info_dict: The build-time info dict.
204 is_ab: Whether it's a build that uses A/B OTA.
205 oem_dicts: A list of OEM dicts.
206 oem_props: A list of OEM properties that should be read from OEM dicts; None
207 if the build doesn't use any OEM-specific property.
208 fingerprint: The fingerprint of the build, which would be calculated based
209 on OEM properties if applicable.
210 device: The device name, which could come from OEM dicts if applicable.
211 """
212
213 def __init__(self, info_dict, oem_dicts):
214 """Initializes a BuildInfo instance with the given dicts.
215
216 Arguments:
217 info_dict: The build-time info dict.
218 oem_dicts: A list of OEM dicts (which is parsed from --oem_settings). Note
219 that it always uses the first dict to calculate the fingerprint or the
220 device name. The rest would be used for asserting OEM properties only
221 (e.g. one package can be installed on one of these devices).
222 """
223 self.info_dict = info_dict
224 self.oem_dicts = oem_dicts
225
226 self._is_ab = info_dict.get("ab_update") == "true"
227 self._oem_props = info_dict.get("oem_fingerprint_properties")
228
229 if self._oem_props:
230 assert oem_dicts, "OEM source required for this build"
231
232 # These two should be computed only after setting self._oem_props.
233 self._device = self.GetOemProperty("ro.product.device")
234 self._fingerprint = self.CalculateFingerprint()
235
236 @property
237 def is_ab(self):
238 return self._is_ab
239
240 @property
241 def device(self):
242 return self._device
243
244 @property
245 def fingerprint(self):
246 return self._fingerprint
247
248 @property
249 def oem_props(self):
250 return self._oem_props
251
252 def __getitem__(self, key):
253 return self.info_dict[key]
254
255 def get(self, key, default=None):
256 return self.info_dict.get(key, default)
257
258 def GetBuildProp(self, prop):
259 """Returns the inquired build property."""
260 try:
261 return self.info_dict.get("build.prop", {})[prop]
262 except KeyError:
263 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
264
265 def GetVendorBuildProp(self, prop):
266 """Returns the inquired vendor build property."""
267 try:
268 return self.info_dict.get("vendor.build.prop", {})[prop]
269 except KeyError:
270 raise common.ExternalError(
271 "couldn't find %s in vendor.build.prop" % (prop,))
272
273 def GetOemProperty(self, key):
274 if self.oem_props is not None and key in self.oem_props:
275 return self.oem_dicts[0][key]
276 return self.GetBuildProp(key)
277
278 def CalculateFingerprint(self):
279 if self.oem_props is None:
280 return self.GetBuildProp("ro.build.fingerprint")
281 return "%s/%s/%s:%s" % (
282 self.GetOemProperty("ro.product.brand"),
283 self.GetOemProperty("ro.product.name"),
284 self.GetOemProperty("ro.product.device"),
285 self.GetBuildProp("ro.build.thumbprint"))
286
287 def WriteMountOemScript(self, script):
288 assert self.oem_props is not None
289 recovery_mount_options = self.info_dict.get("recovery_mount_options")
290 script.Mount("/oem", recovery_mount_options)
291
292 def WriteDeviceAssertions(self, script, oem_no_mount):
293 # Read the property directly if not using OEM properties.
294 if not self.oem_props:
295 script.AssertDevice(self.device)
296 return
297
298 # Otherwise assert OEM properties.
299 if not self.oem_dicts:
300 raise common.ExternalError(
301 "No OEM file provided to answer expected assertions")
302
303 for prop in self.oem_props.split():
304 values = []
305 for oem_dict in self.oem_dicts:
306 if prop in oem_dict:
307 values.append(oem_dict[prop])
308 if not values:
309 raise common.ExternalError(
310 "The OEM file is missing the property %s" % (prop,))
311 script.AssertOemProperty(prop, values, oem_no_mount)
312
313
Doug Zongkereef39442009-04-02 12:14:19 -0700314def SignOutput(temp_zip_name, output_zip_name):
Christian Oderf63e2cd2017-05-01 22:30:15 +0200315 pw = OPTIONS.key_passwords[OPTIONS.package_key]
Doug Zongkereef39442009-04-02 12:14:19 -0700316
Doug Zongker951495f2009-08-14 12:44:19 -0700317 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
318 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700319
320
Tao Bao481bab82017-12-21 11:23:09 -0800321def _LoadOemDicts(oem_source):
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800322 """Returns the list of loaded OEM properties dict."""
Tao Bao481bab82017-12-21 11:23:09 -0800323 if not oem_source:
324 return None
325
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800326 oem_dicts = []
Tao Bao481bab82017-12-21 11:23:09 -0800327 for oem_file in oem_source:
328 with open(oem_file) as fp:
329 oem_dicts.append(common.LoadDictionaryFromLines(fp.readlines()))
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800330 return oem_dicts
Doug Zongkereef39442009-04-02 12:14:19 -0700331
Doug Zongkereef39442009-04-02 12:14:19 -0700332
Tao Baod42e97e2016-11-30 12:11:57 -0800333def _WriteRecoveryImageToBoot(script, output_zip):
334 """Find and write recovery image to /boot in two-step OTA.
335
336 In two-step OTAs, we write recovery image to /boot as the first step so that
337 we can reboot to there and install a new recovery image to /recovery.
338 A special "recovery-two-step.img" will be preferred, which encodes the correct
339 path of "/boot". Otherwise the device may show "device is corrupt" message
340 when booting into /boot.
341
342 Fall back to using the regular recovery.img if the two-step recovery image
343 doesn't exist. Note that rebuilding the special image at this point may be
344 infeasible, because we don't have the desired boot signer and keys when
345 calling ota_from_target_files.py.
346 """
347
348 recovery_two_step_img_name = "recovery-two-step.img"
349 recovery_two_step_img_path = os.path.join(
350 OPTIONS.input_tmp, "IMAGES", recovery_two_step_img_name)
351 if os.path.exists(recovery_two_step_img_path):
352 recovery_two_step_img = common.GetBootableImage(
353 recovery_two_step_img_name, recovery_two_step_img_name,
354 OPTIONS.input_tmp, "RECOVERY")
355 common.ZipWriteStr(
356 output_zip, recovery_two_step_img_name, recovery_two_step_img.data)
Tao Bao89fbb0f2017-01-10 10:47:58 -0800357 print("two-step package: using %s in stage 1/3" % (
358 recovery_two_step_img_name,))
Tao Baod42e97e2016-11-30 12:11:57 -0800359 script.WriteRawImage("/boot", recovery_two_step_img_name)
360 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -0800361 print("two-step package: using recovery.img in stage 1/3")
Tao Baod42e97e2016-11-30 12:11:57 -0800362 # The "recovery.img" entry has been written into package earlier.
363 script.WriteRawImage("/boot", "recovery.img")
364
365
Doug Zongkerc9253822014-02-04 12:17:58 -0800366def HasRecoveryPatch(target_files_zip):
Tao Baof2cffbd2015-07-22 12:33:18 -0700367 namelist = [name for name in target_files_zip.namelist()]
368 return ("SYSTEM/recovery-from-boot.p" in namelist or
369 "SYSTEM/etc/recovery.img" in namelist)
Doug Zongker73ef8252009-07-23 15:12:53 -0700370
Tao Bao457cbf62017-03-06 09:56:01 -0800371
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700372def HasVendorPartition(target_files_zip):
373 try:
374 target_files_zip.getinfo("VENDOR/")
375 return True
376 except KeyError:
377 return False
378
Tao Bao457cbf62017-03-06 09:56:01 -0800379
Tao Bao481bab82017-12-21 11:23:09 -0800380def HasTrebleEnabled(target_files_zip, target_info):
Tao Baobcd1d162017-08-26 13:10:26 -0700381 return (HasVendorPartition(target_files_zip) and
Tao Bao481bab82017-12-21 11:23:09 -0800382 target_info.GetBuildProp("ro.treble.enabled") == "true")
Tao Baobcd1d162017-08-26 13:10:26 -0700383
384
Tao Bao481bab82017-12-21 11:23:09 -0800385def WriteFingerprintAssertion(script, target_info, source_info):
386 source_oem_props = source_info.oem_props
387 target_oem_props = target_info.oem_props
Michael Runge6e836112014-04-15 17:40:21 -0700388
Tao Bao481bab82017-12-21 11:23:09 -0800389 if source_oem_props is None and target_oem_props is None:
390 script.AssertSomeFingerprint(
391 source_info.fingerprint, target_info.fingerprint)
392 elif source_oem_props is not None and target_oem_props is not None:
393 script.AssertSomeThumbprint(
394 target_info.GetBuildProp("ro.build.thumbprint"),
395 source_info.GetBuildProp("ro.build.thumbprint"))
396 elif source_oem_props is None and target_oem_props is not None:
397 script.AssertFingerprintOrThumbprint(
398 source_info.fingerprint,
399 target_info.GetBuildProp("ro.build.thumbprint"))
400 else:
401 script.AssertFingerprintOrThumbprint(
402 target_info.fingerprint,
403 source_info.GetBuildProp("ro.build.thumbprint"))
Doug Zongker73ef8252009-07-23 15:12:53 -0700404
Doug Zongkerfc44a512014-08-26 13:10:25 -0700405
Tao Bao7e0f1602017-03-06 15:50:08 -0800406def GetImage(which, tmpdir):
407 """Returns an image object suitable for passing to BlockImageDiff.
408
409 'which' partition must be "system" or "vendor". A prebuilt image and file
410 map must already exist in tmpdir.
411 """
Doug Zongker3c84f562014-07-31 11:06:30 -0700412
413 assert which in ("system", "vendor")
414
415 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700416 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
Doug Zongker3c84f562014-07-31 11:06:30 -0700417
Tao Bao7e0f1602017-03-06 15:50:08 -0800418 # The image and map files must have been created prior to calling
419 # ota_from_target_files.py (since LMP).
420 assert os.path.exists(path) and os.path.exists(mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700421
Tao Baoff777812015-05-12 11:42:31 -0700422 # Bug: http://b/20939131
423 # In ext4 filesystems, block 0 might be changed even being mounted
424 # R/O. We add it to clobbered_blocks so that it will be written to the
425 # target unconditionally. Note that they are still part of care_map.
426 clobbered_blocks = "0"
427
428 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700429
430
Tao Bao481bab82017-12-21 11:23:09 -0800431def AddCompatibilityArchiveIfTrebleEnabled(target_zip, output_zip, target_info,
432 source_info=None):
Tao Baobcd1d162017-08-26 13:10:26 -0700433 """Adds compatibility info into the output zip if it's Treble-enabled target.
Tao Bao21803d32017-04-19 10:16:09 -0700434
435 Metadata used for on-device compatibility verification is retrieved from
436 target_zip then added to compatibility.zip which is added to the output_zip
437 archive.
438
Tao Baobcd1d162017-08-26 13:10:26 -0700439 Compatibility archive should only be included for devices that have enabled
440 Treble support.
Tao Bao21803d32017-04-19 10:16:09 -0700441
442 Args:
443 target_zip: Zip file containing the source files to be included for OTA.
444 output_zip: Zip file that will be sent for OTA.
Tao Bao481bab82017-12-21 11:23:09 -0800445 target_info: The BuildInfo instance that holds the target build info.
446 source_info: The BuildInfo instance that holds the source build info, if
447 generating an incremental OTA; None otherwise.
Tao Bao21803d32017-04-19 10:16:09 -0700448 """
449
Tao Baobcd1d162017-08-26 13:10:26 -0700450 def AddCompatibilityArchive(system_updated, vendor_updated):
451 """Adds compatibility info based on system/vendor update status.
Tao Bao21803d32017-04-19 10:16:09 -0700452
Tao Baobcd1d162017-08-26 13:10:26 -0700453 Args:
454 system_updated: If True, the system image will be updated and therefore
455 its metadata should be included.
456 vendor_updated: If True, the vendor image will be updated and therefore
457 its metadata should be included.
458 """
459 # Determine what metadata we need. Files are names relative to META/.
460 compatibility_files = []
461 vendor_metadata = ("vendor_manifest.xml", "vendor_matrix.xml")
462 system_metadata = ("system_manifest.xml", "system_matrix.xml")
463 if vendor_updated:
464 compatibility_files += vendor_metadata
465 if system_updated:
466 compatibility_files += system_metadata
Tao Bao21803d32017-04-19 10:16:09 -0700467
Tao Baobcd1d162017-08-26 13:10:26 -0700468 # Create new archive.
469 compatibility_archive = tempfile.NamedTemporaryFile()
Tao Bao481bab82017-12-21 11:23:09 -0800470 compatibility_archive_zip = zipfile.ZipFile(
471 compatibility_archive, "w", compression=zipfile.ZIP_DEFLATED)
Tao Bao21803d32017-04-19 10:16:09 -0700472
Tao Baobcd1d162017-08-26 13:10:26 -0700473 # Add metadata.
474 for file_name in compatibility_files:
475 target_file_name = "META/" + file_name
Tao Bao21803d32017-04-19 10:16:09 -0700476
Tao Baobcd1d162017-08-26 13:10:26 -0700477 if target_file_name in target_zip.namelist():
478 data = target_zip.read(target_file_name)
479 common.ZipWriteStr(compatibility_archive_zip, file_name, data)
Tao Bao21803d32017-04-19 10:16:09 -0700480
Tao Baobcd1d162017-08-26 13:10:26 -0700481 # Ensure files are written before we copy into output_zip.
482 compatibility_archive_zip.close()
483
484 # Only add the archive if we have any compatibility info.
485 if compatibility_archive_zip.namelist():
486 common.ZipWrite(output_zip, compatibility_archive.name,
487 arcname="compatibility.zip",
488 compress_type=zipfile.ZIP_STORED)
489
490 # Will only proceed if the target has enabled the Treble support (as well as
491 # having a /vendor partition).
Tao Bao481bab82017-12-21 11:23:09 -0800492 if not HasTrebleEnabled(target_zip, target_info):
Tao Baobcd1d162017-08-26 13:10:26 -0700493 return
494
495 # We don't support OEM thumbprint in Treble world (which calculates
496 # fingerprints in a different way as shown in CalculateFingerprint()).
Tao Bao481bab82017-12-21 11:23:09 -0800497 assert not target_info.oem_props
Tao Baobcd1d162017-08-26 13:10:26 -0700498
499 # Full OTA carries the info for system/vendor both.
Tao Bao481bab82017-12-21 11:23:09 -0800500 if source_info is None:
Tao Baobcd1d162017-08-26 13:10:26 -0700501 AddCompatibilityArchive(True, True)
502 return
503
Tao Bao481bab82017-12-21 11:23:09 -0800504 assert not source_info.oem_props
Tao Baobcd1d162017-08-26 13:10:26 -0700505
Tao Bao481bab82017-12-21 11:23:09 -0800506 source_fp = source_info.fingerprint
507 target_fp = target_info.fingerprint
Tao Baobcd1d162017-08-26 13:10:26 -0700508 system_updated = source_fp != target_fp
509
Tao Bao481bab82017-12-21 11:23:09 -0800510 source_fp_vendor = source_info.GetVendorBuildProp(
511 "ro.vendor.build.fingerprint")
512 target_fp_vendor = target_info.GetVendorBuildProp(
513 "ro.vendor.build.fingerprint")
Tao Baobcd1d162017-08-26 13:10:26 -0700514 vendor_updated = source_fp_vendor != target_fp_vendor
515
516 AddCompatibilityArchive(system_updated, vendor_updated)
Tao Bao21803d32017-04-19 10:16:09 -0700517
518
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700519def WriteFullOTAPackage(input_zip, output_zip):
Tao Bao481bab82017-12-21 11:23:09 -0800520 target_info = BuildInfo(OPTIONS.info_dict, OPTIONS.oem_dicts)
Doug Zongkereef39442009-04-02 12:14:19 -0700521
Tao Bao481bab82017-12-21 11:23:09 -0800522 # We don't know what version it will be installed on top of. We expect the API
523 # just won't change very often. Similarly for fstab, it might have changed in
524 # the target build.
525 target_api_version = target_info["recovery_api_version"]
526 script = edify_generator.EdifyGenerator(target_api_version, target_info)
Michael Runge6e836112014-04-15 17:40:21 -0700527
Tao Bao481bab82017-12-21 11:23:09 -0800528 if target_info.oem_props and not OPTIONS.oem_no_mount:
529 target_info.WriteMountOemScript(script)
530
Dan Albert8b72aef2015-03-23 19:13:21 -0700531 metadata = {
Tao Bao481bab82017-12-21 11:23:09 -0800532 "post-build": target_info.fingerprint,
533 "pre-device": target_info.device,
534 "post-timestamp": target_info.GetBuildProp("ro.build.date.utc"),
535 "ota-type" : "BLOCK",
Dan Albert8b72aef2015-03-23 19:13:21 -0700536 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700537
Doug Zongker05d3dea2009-06-22 11:32:31 -0700538 device_specific = common.DeviceSpecificParams(
539 input_zip=input_zip,
Tao Bao481bab82017-12-21 11:23:09 -0800540 input_version=target_api_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700541 output_zip=output_zip,
542 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700543 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700544 metadata=metadata,
545 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700546
Tao Bao457cbf62017-03-06 09:56:01 -0800547 assert HasRecoveryPatch(input_zip)
Doug Zongkerc9253822014-02-04 12:17:58 -0800548
Tao Bao481bab82017-12-21 11:23:09 -0800549 # Assertions (e.g. downgrade check, device properties check).
550 ts = target_info.GetBuildProp("ro.build.date.utc")
551 ts_text = target_info.GetBuildProp("ro.build.date")
Elliott Hughesd8a52f92016-06-20 14:35:47 -0700552 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700553
Tao Bao481bab82017-12-21 11:23:09 -0800554 target_info.WriteDeviceAssertions(script, OPTIONS.oem_no_mount)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700555 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800556
557 # Two-step package strategy (in chronological order, which is *not*
558 # the order in which the generated script has things):
559 #
560 # if stage is not "2/3" or "3/3":
561 # write recovery image to boot partition
562 # set stage to "2/3"
563 # reboot to boot partition and restart recovery
564 # else if stage is "2/3":
565 # write recovery image to recovery partition
566 # set stage to "3/3"
567 # reboot to recovery partition and restart recovery
568 # else:
569 # (stage must be "3/3")
570 # set stage to ""
571 # do normal full package installation:
572 # wipe and install system, boot image, etc.
573 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700574 # complete script normally
575 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800576
577 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
578 OPTIONS.input_tmp, "RECOVERY")
579 if OPTIONS.two_step:
Tao Bao481bab82017-12-21 11:23:09 -0800580 if not target_info.get("multistage_support"):
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800581 assert False, "two-step packages not supported by this build"
Tao Bao481bab82017-12-21 11:23:09 -0800582 fs = target_info["fstab"]["/misc"]
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800583 assert fs.fs_type.upper() == "EMMC", \
584 "two-step packages only supported on devices with EMMC /misc partitions"
585 bcb_dev = {"bcb_dev": fs.device}
586 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
587 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700588if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800589""" % bcb_dev)
Tao Baod42e97e2016-11-30 12:11:57 -0800590
591 # Stage 2/3: Write recovery image to /recovery (currently running /boot).
592 script.Comment("Stage 2/3")
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800593 script.WriteRawImage("/recovery", "recovery.img")
594 script.AppendExtra("""
595set_stage("%(bcb_dev)s", "3/3");
596reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700597else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800598""" % bcb_dev)
599
Tao Baod42e97e2016-11-30 12:11:57 -0800600 # Stage 3/3: Make changes.
601 script.Comment("Stage 3/3")
602
Tao Bao6c55a8a2015-04-08 15:30:27 -0700603 # Dump fingerprints
Tao Bao481bab82017-12-21 11:23:09 -0800604 script.Print("Target: {}".format(target_info.fingerprint))
Tao Bao6c55a8a2015-04-08 15:30:27 -0700605
Doug Zongkere5ff5902012-01-17 10:55:37 -0800606 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700607
Doug Zongker01ce19c2014-02-04 13:48:15 -0800608 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700609
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700610 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800611 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700612 if HasVendorPartition(input_zip):
613 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700614
Doug Zongker4b9596f2014-06-09 14:15:45 -0700615 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800616
Tao Bao457cbf62017-03-06 09:56:01 -0800617 # Full OTA is done as an "incremental" against an empty source image. This
618 # has the effect of writing new data from the package to the entire
619 # partition, but lets us reuse the updater code that writes incrementals to
620 # do it.
621 system_tgt = GetImage("system", OPTIONS.input_tmp)
622 system_tgt.ResetFileMap()
623 system_diff = common.BlockDifference("system", system_tgt, src=None)
624 system_diff.WriteScript(script, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700625
Tao Bao7a5bf8a2015-07-21 18:01:20 -0700626 boot_img = common.GetBootableImage(
627 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800628
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700629 if HasVendorPartition(input_zip):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700630 script.ShowProgress(0.1, 0)
631
Tao Bao457cbf62017-03-06 09:56:01 -0800632 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp)
633 vendor_tgt.ResetFileMap()
634 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
635 vendor_diff.WriteScript(script, output_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700636
Tao Bao481bab82017-12-21 11:23:09 -0800637 AddCompatibilityArchiveIfTrebleEnabled(input_zip, output_zip, target_info)
Tao Baobcd1d162017-08-26 13:10:26 -0700638
Tao Bao481bab82017-12-21 11:23:09 -0800639 common.CheckSize(boot_img.data, "boot.img", target_info)
Doug Zongker73ef8252009-07-23 15:12:53 -0700640 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700641
Doug Zongker01ce19c2014-02-04 13:48:15 -0800642 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700643 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700644
Doug Zongker01ce19c2014-02-04 13:48:15 -0800645 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700646 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700647
Doug Zongker1c390a22009-05-14 19:06:36 -0700648 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700649 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700650
Doug Zongker14833602010-02-02 13:12:04 -0800651 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800652
Doug Zongker922206e2014-03-04 13:16:24 -0800653 if OPTIONS.wipe_user_data:
654 script.ShowProgress(0.1, 10)
655 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700656
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800657 if OPTIONS.two_step:
658 script.AppendExtra("""
659set_stage("%(bcb_dev)s", "");
660""" % bcb_dev)
661 script.AppendExtra("else\n")
Tao Baod42e97e2016-11-30 12:11:57 -0800662
663 # Stage 1/3: Nothing to verify for full OTA. Write recovery image to /boot.
664 script.Comment("Stage 1/3")
665 _WriteRecoveryImageToBoot(script, output_zip)
666
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800667 script.AppendExtra("""
668set_stage("%(bcb_dev)s", "2/3");
669reboot_now("%(bcb_dev)s", "");
670endif;
671endif;
672""" % bcb_dev)
Tao Baod8d14be2016-02-04 14:26:02 -0800673
Tao Bao5d182562016-02-23 11:38:39 -0800674 script.SetProgress(1)
675 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -0800676 metadata["ota-required-cache"] = str(script.required_cache)
Doug Zongker2ea21062010-04-28 16:05:21 -0700677 WriteMetadata(metadata, output_zip)
678
Doug Zongkerfc44a512014-08-26 13:10:25 -0700679
Doug Zongker2ea21062010-04-28 16:05:21 -0700680def WriteMetadata(metadata, output_zip):
Tao Bao2dd1c482017-02-03 16:49:39 -0800681 value = "".join(["%s=%s\n" % kv for kv in sorted(metadata.iteritems())])
682 common.ZipWriteStr(output_zip, METADATA_NAME, value,
683 compress_type=zipfile.ZIP_STORED)
Doug Zongkereef39442009-04-02 12:14:19 -0700684
Doug Zongkerfc44a512014-08-26 13:10:25 -0700685
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700686def GetBuildProp(prop, info_dict):
Tao Baobcd1d162017-08-26 13:10:26 -0700687 """Returns the inquired build property from a given info_dict."""
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700688 try:
689 return info_dict.get("build.prop", {})[prop]
690 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700691 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700692
Doug Zongkerfc44a512014-08-26 13:10:25 -0700693
Tao Baobcd1d162017-08-26 13:10:26 -0700694def GetVendorBuildProp(prop, info_dict):
695 """Returns the inquired vendor build property from a given info_dict."""
696 try:
697 return info_dict.get("vendor.build.prop", {})[prop]
698 except KeyError:
699 raise common.ExternalError(
700 "couldn't find %s in vendor.build.prop" % (prop,))
701
702
Tao Bao481bab82017-12-21 11:23:09 -0800703def HandleDowngradeMetadata(metadata, target_info, source_info):
Tao Baob31892e2017-02-07 11:21:17 -0800704 # Only incremental OTAs are allowed to reach here.
705 assert OPTIONS.incremental_source is not None
706
Tao Bao481bab82017-12-21 11:23:09 -0800707 post_timestamp = target_info.GetBuildProp("ro.build.date.utc")
708 pre_timestamp = source_info.GetBuildProp("ro.build.date.utc")
Tao Baob31892e2017-02-07 11:21:17 -0800709 is_downgrade = long(post_timestamp) < long(pre_timestamp)
710
711 if OPTIONS.downgrade:
Tao Baob31892e2017-02-07 11:21:17 -0800712 if not is_downgrade:
713 raise RuntimeError("--downgrade specified but no downgrade detected: "
714 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
Tao Bao3e6161a2017-02-28 11:48:48 -0800715 metadata["ota-downgrade"] = "yes"
716 elif OPTIONS.timestamp:
717 if not is_downgrade:
Tao Bao481bab82017-12-21 11:23:09 -0800718 raise RuntimeError("--override_timestamp specified but no timestamp hack "
719 "needed: pre: %s, post: %s" % (pre_timestamp,
720 post_timestamp))
Tao Bao3e6161a2017-02-28 11:48:48 -0800721 metadata["post-timestamp"] = str(long(pre_timestamp) + 1)
Tao Baob31892e2017-02-07 11:21:17 -0800722 else:
723 if is_downgrade:
Tao Bao3e6161a2017-02-28 11:48:48 -0800724 raise RuntimeError("Downgrade detected based on timestamp check: "
Tao Bao481bab82017-12-21 11:23:09 -0800725 "pre: %s, post: %s. Need to specify "
726 "--override_timestamp OR --downgrade to allow "
727 "building the incremental." % (pre_timestamp,
728 post_timestamp))
Tao Baob31892e2017-02-07 11:21:17 -0800729 metadata["post-timestamp"] = post_timestamp
730
731
Geremy Condra36bd3652014-02-06 19:45:10 -0800732def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
Tao Bao481bab82017-12-21 11:23:09 -0800733 target_info = BuildInfo(OPTIONS.target_info_dict, OPTIONS.oem_dicts)
734 source_info = BuildInfo(OPTIONS.source_info_dict, OPTIONS.oem_dicts)
Geremy Condra36bd3652014-02-06 19:45:10 -0800735
Tao Bao481bab82017-12-21 11:23:09 -0800736 target_api_version = target_info["recovery_api_version"]
737 source_api_version = source_info["recovery_api_version"]
738 if source_api_version == 0:
Tao Bao3e30d972016-03-15 13:20:19 -0700739 print("WARNING: generating edify script for a source that "
740 "can't install it.")
Geremy Condra36bd3652014-02-06 19:45:10 -0800741
Tao Bao481bab82017-12-21 11:23:09 -0800742 script = edify_generator.EdifyGenerator(
743 source_api_version, target_info, fstab=source_info["fstab"])
744
745 if target_info.oem_props or source_info.oem_props:
746 if not OPTIONS.oem_no_mount:
747 source_info.WriteMountOemScript(script)
Tao Bao3806c232015-07-05 21:08:33 -0700748
Dan Albert8b72aef2015-03-23 19:13:21 -0700749 metadata = {
Tao Bao481bab82017-12-21 11:23:09 -0800750 "pre-device": source_info.device,
Tao Baod8d14be2016-02-04 14:26:02 -0800751 "ota-type": "BLOCK",
Dan Albert8b72aef2015-03-23 19:13:21 -0700752 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800753
Tao Bao481bab82017-12-21 11:23:09 -0800754 HandleDowngradeMetadata(metadata, target_info, source_info)
Tao Bao5d182562016-02-23 11:38:39 -0800755
Geremy Condra36bd3652014-02-06 19:45:10 -0800756 device_specific = common.DeviceSpecificParams(
757 source_zip=source_zip,
Tao Bao481bab82017-12-21 11:23:09 -0800758 source_version=source_api_version,
Geremy Condra36bd3652014-02-06 19:45:10 -0800759 target_zip=target_zip,
Tao Bao481bab82017-12-21 11:23:09 -0800760 target_version=target_api_version,
Geremy Condra36bd3652014-02-06 19:45:10 -0800761 output_zip=output_zip,
762 script=script,
763 metadata=metadata,
Tao Bao481bab82017-12-21 11:23:09 -0800764 info_dict=source_info)
Geremy Condra36bd3652014-02-06 19:45:10 -0800765
Tao Bao481bab82017-12-21 11:23:09 -0800766 metadata["pre-build"] = source_info.fingerprint
767 metadata["post-build"] = target_info.fingerprint
768 metadata["pre-build-incremental"] = source_info.GetBuildProp(
769 "ro.build.version.incremental")
770 metadata["post-build-incremental"] = target_info.GetBuildProp(
771 "ro.build.version.incremental")
Geremy Condra36bd3652014-02-06 19:45:10 -0800772
773 source_boot = common.GetBootableImage(
Tao Bao481bab82017-12-21 11:23:09 -0800774 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT", source_info)
Geremy Condra36bd3652014-02-06 19:45:10 -0800775 target_boot = common.GetBootableImage(
Tao Bao481bab82017-12-21 11:23:09 -0800776 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT", target_info)
Geremy Condra36bd3652014-02-06 19:45:10 -0800777 updating_boot = (not OPTIONS.two_step and
778 (source_boot.data != target_boot.data))
779
Geremy Condra36bd3652014-02-06 19:45:10 -0800780 target_recovery = common.GetBootableImage(
781 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800782
Tao Bao7e0f1602017-03-06 15:50:08 -0800783 system_src = GetImage("system", OPTIONS.source_tmp)
784 system_tgt = GetImage("system", OPTIONS.target_tmp)
Tao Baodd2a5892015-03-12 12:32:37 -0700785
Tao Bao0582cb62017-12-21 11:47:01 -0800786 blockimgdiff_version = max(
Tao Bao481bab82017-12-21 11:23:09 -0800787 int(i) for i in target_info.get("blockimgdiff_versions", "1").split(","))
Tao Bao0582cb62017-12-21 11:47:01 -0800788 assert blockimgdiff_version >= 3
Tao Baodd2a5892015-03-12 12:32:37 -0700789
Tao Baof8acad12016-07-07 09:09:58 -0700790 # Check the first block of the source system partition for remount R/W only
791 # if the filesystem is ext4.
Tao Bao481bab82017-12-21 11:23:09 -0800792 system_src_partition = source_info["fstab"]["/system"]
Tao Baof8acad12016-07-07 09:09:58 -0700793 check_first_block = system_src_partition.fs_type == "ext4"
Tao Bao293fd132016-06-11 12:19:23 -0700794 # Disable using imgdiff for squashfs. 'imgdiff -z' expects input files to be
795 # in zip formats. However with squashfs, a) all files are compressed in LZ4;
796 # b) the blocks listed in block map may not contain all the bytes for a given
797 # file (because they're rounded to be 4K-aligned).
Tao Bao481bab82017-12-21 11:23:09 -0800798 system_tgt_partition = target_info["fstab"]["/system"]
Tao Baof8acad12016-07-07 09:09:58 -0700799 disable_imgdiff = (system_src_partition.fs_type == "squashfs" or
800 system_tgt_partition.fs_type == "squashfs")
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700801 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tianjie Xufc3422a2015-12-15 11:53:59 -0800802 check_first_block,
Tao Bao293fd132016-06-11 12:19:23 -0700803 version=blockimgdiff_version,
804 disable_imgdiff=disable_imgdiff)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700805
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700806 if HasVendorPartition(target_zip):
807 if not HasVendorPartition(source_zip):
808 raise RuntimeError("can't generate incremental that adds /vendor")
Tao Bao7e0f1602017-03-06 15:50:08 -0800809 vendor_src = GetImage("vendor", OPTIONS.source_tmp)
810 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp)
Tianjie Xufc3422a2015-12-15 11:53:59 -0800811
812 # Check first block of vendor partition for remount R/W only if
813 # disk type is ext4
Tao Bao481bab82017-12-21 11:23:09 -0800814 vendor_partition = source_info["fstab"]["/vendor"]
Tao Baod8d14be2016-02-04 14:26:02 -0800815 check_first_block = vendor_partition.fs_type == "ext4"
Tao Bao293fd132016-06-11 12:19:23 -0700816 disable_imgdiff = vendor_partition.fs_type == "squashfs"
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700817 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tianjie Xufc3422a2015-12-15 11:53:59 -0800818 check_first_block,
Tao Bao293fd132016-06-11 12:19:23 -0700819 version=blockimgdiff_version,
820 disable_imgdiff=disable_imgdiff)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700821 else:
822 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800823
Tao Baobcd1d162017-08-26 13:10:26 -0700824 AddCompatibilityArchiveIfTrebleEnabled(
Tao Bao481bab82017-12-21 11:23:09 -0800825 target_zip, output_zip, target_info, source_info)
Tao Baobcd1d162017-08-26 13:10:26 -0700826
Tao Bao481bab82017-12-21 11:23:09 -0800827 # Assertions (e.g. device properties check).
828 target_info.WriteDeviceAssertions(script, OPTIONS.oem_no_mount)
Geremy Condra36bd3652014-02-06 19:45:10 -0800829 device_specific.IncrementalOTA_Assertions()
830
831 # Two-step incremental package strategy (in chronological order,
832 # which is *not* the order in which the generated script has
833 # things):
834 #
835 # if stage is not "2/3" or "3/3":
836 # do verification on current system
837 # write recovery image to boot partition
838 # set stage to "2/3"
839 # reboot to boot partition and restart recovery
840 # else if stage is "2/3":
841 # write recovery image to recovery partition
842 # set stage to "3/3"
843 # reboot to recovery partition and restart recovery
844 # else:
845 # (stage must be "3/3")
846 # perform update:
847 # patch system files, etc.
848 # force full install of new boot image
849 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700850 # complete script normally
851 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800852
853 if OPTIONS.two_step:
Tao Bao481bab82017-12-21 11:23:09 -0800854 if not source_info.get("multistage_support"):
Geremy Condra36bd3652014-02-06 19:45:10 -0800855 assert False, "two-step packages not supported by this build"
Tao Baodd24da92015-07-29 14:09:23 -0700856 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Geremy Condra36bd3652014-02-06 19:45:10 -0800857 assert fs.fs_type.upper() == "EMMC", \
858 "two-step packages only supported on devices with EMMC /misc partitions"
Tao Bao481bab82017-12-21 11:23:09 -0800859 bcb_dev = {"bcb_dev" : fs.device}
Geremy Condra36bd3652014-02-06 19:45:10 -0800860 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
861 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700862if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800863""" % bcb_dev)
Tao Baod42e97e2016-11-30 12:11:57 -0800864
865 # Stage 2/3: Write recovery image to /recovery (currently running /boot).
866 script.Comment("Stage 2/3")
Dan Albert8b72aef2015-03-23 19:13:21 -0700867 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800868 script.WriteRawImage("/recovery", "recovery.img")
869 script.AppendExtra("""
870set_stage("%(bcb_dev)s", "3/3");
871reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700872else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800873""" % bcb_dev)
874
Tao Baod42e97e2016-11-30 12:11:57 -0800875 # Stage 1/3: (a) Verify the current system.
876 script.Comment("Stage 1/3")
877
Tao Bao6c55a8a2015-04-08 15:30:27 -0700878 # Dump fingerprints
Tao Bao481bab82017-12-21 11:23:09 -0800879 script.Print("Source: {}".format(source_info.fingerprint))
880 script.Print("Target: {}".format(target_info.fingerprint))
Tao Bao6c55a8a2015-04-08 15:30:27 -0700881
Geremy Condra36bd3652014-02-06 19:45:10 -0800882 script.Print("Verifying current system...")
883
884 device_specific.IncrementalOTA_VerifyBegin()
885
Tao Bao481bab82017-12-21 11:23:09 -0800886 WriteFingerprintAssertion(script, target_info, source_info)
Geremy Condra36bd3652014-02-06 19:45:10 -0800887
Tao Baod8d14be2016-02-04 14:26:02 -0800888 # Check the required cache size (i.e. stashed blocks).
889 size = []
890 if system_diff:
891 size.append(system_diff.required_cache)
892 if vendor_diff:
893 size.append(vendor_diff.required_cache)
894
Geremy Condra36bd3652014-02-06 19:45:10 -0800895 if updating_boot:
Tao Bao481bab82017-12-21 11:23:09 -0800896 boot_type, boot_device = common.GetTypeAndDevice("/boot", source_info)
Geremy Condra36bd3652014-02-06 19:45:10 -0800897 d = common.Difference(target_boot, source_boot)
898 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700899 if d is None:
900 include_full_boot = True
901 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
902 else:
903 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800904
Tao Bao89fbb0f2017-01-10 10:47:58 -0800905 print("boot target: %d source: %d diff: %d" % (
906 target_boot.size, source_boot.size, len(d)))
Geremy Condra36bd3652014-02-06 19:45:10 -0800907
Doug Zongkerf8340082014-08-05 10:39:37 -0700908 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800909
Doug Zongkerf8340082014-08-05 10:39:37 -0700910 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
911 (boot_type, boot_device,
912 source_boot.size, source_boot.sha1,
913 target_boot.size, target_boot.sha1))
Tao Baod8d14be2016-02-04 14:26:02 -0800914 size.append(target_boot.size)
915
916 if size:
917 script.CacheFreeSpaceCheck(max(size))
Geremy Condra36bd3652014-02-06 19:45:10 -0800918
919 device_specific.IncrementalOTA_VerifyEnd()
920
921 if OPTIONS.two_step:
Tao Baod42e97e2016-11-30 12:11:57 -0800922 # Stage 1/3: (b) Write recovery image to /boot.
923 _WriteRecoveryImageToBoot(script, output_zip)
924
Geremy Condra36bd3652014-02-06 19:45:10 -0800925 script.AppendExtra("""
926set_stage("%(bcb_dev)s", "2/3");
927reboot_now("%(bcb_dev)s", "");
928else
929""" % bcb_dev)
930
Tao Baod42e97e2016-11-30 12:11:57 -0800931 # Stage 3/3: Make changes.
932 script.Comment("Stage 3/3")
933
Jesse Zhao75bcea02015-01-06 10:59:53 -0800934 # Verify the existing partitions.
Tao Baod522bdc2016-04-12 15:53:16 -0700935 system_diff.WriteVerifyScript(script, touched_blocks_only=True)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800936 if vendor_diff:
Tao Baod522bdc2016-04-12 15:53:16 -0700937 vendor_diff.WriteVerifyScript(script, touched_blocks_only=True)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800938
Geremy Condra36bd3652014-02-06 19:45:10 -0800939 script.Comment("---- start making changes here ----")
940
941 device_specific.IncrementalOTA_InstallBegin()
942
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700943 system_diff.WriteScript(script, output_zip,
944 progress=0.8 if vendor_diff else 0.9)
Tao Bao68658c02015-06-01 13:40:49 -0700945
Doug Zongkerfc44a512014-08-26 13:10:25 -0700946 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700947 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800948
949 if OPTIONS.two_step:
950 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
951 script.WriteRawImage("/boot", "boot.img")
Tao Bao89fbb0f2017-01-10 10:47:58 -0800952 print("writing full boot image (forced by two-step mode)")
Geremy Condra36bd3652014-02-06 19:45:10 -0800953
954 if not OPTIONS.two_step:
955 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700956 if include_full_boot:
Tao Bao89fbb0f2017-01-10 10:47:58 -0800957 print("boot image changed; including full.")
Doug Zongkerf8340082014-08-05 10:39:37 -0700958 script.Print("Installing boot image...")
959 script.WriteRawImage("/boot", "boot.img")
960 else:
961 # Produce the boot image by applying a patch to the current
962 # contents of the boot partition, and write it back to the
963 # partition.
Tao Bao89fbb0f2017-01-10 10:47:58 -0800964 print("boot image changed; including patch.")
Doug Zongkerf8340082014-08-05 10:39:37 -0700965 script.Print("Patching boot image...")
966 script.ShowProgress(0.1, 10)
967 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
968 % (boot_type, boot_device,
969 source_boot.size, source_boot.sha1,
970 target_boot.size, target_boot.sha1),
971 "-",
972 target_boot.size, target_boot.sha1,
973 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800974 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -0800975 print("boot image unchanged; skipping.")
Geremy Condra36bd3652014-02-06 19:45:10 -0800976
977 # Do device-specific installation (eg, write radio image).
978 device_specific.IncrementalOTA_InstallEnd()
979
980 if OPTIONS.extra_script is not None:
981 script.AppendExtra(OPTIONS.extra_script)
982
Doug Zongker922206e2014-03-04 13:16:24 -0800983 if OPTIONS.wipe_user_data:
984 script.Print("Erasing user data...")
985 script.FormatPartition("/data")
Tao Bao5d182562016-02-23 11:38:39 -0800986 metadata["ota-wipe"] = "yes"
Doug Zongker922206e2014-03-04 13:16:24 -0800987
Geremy Condra36bd3652014-02-06 19:45:10 -0800988 if OPTIONS.two_step:
989 script.AppendExtra("""
990set_stage("%(bcb_dev)s", "");
991endif;
992endif;
993""" % bcb_dev)
994
995 script.SetProgress(1)
Tao Bao4996cf02016-03-08 17:53:39 -0800996 # For downgrade OTAs, we prefer to use the update-binary in the source
997 # build that is actually newer than the one in the target build.
998 if OPTIONS.downgrade:
999 script.AddToZip(source_zip, output_zip, input_path=OPTIONS.updater_binary)
1000 else:
1001 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -08001002 metadata["ota-required-cache"] = str(script.required_cache)
Geremy Condra36bd3652014-02-06 19:45:10 -08001003 WriteMetadata(metadata, output_zip)
1004
Doug Zongker32b527d2014-03-04 10:03:02 -08001005
Tao Baoc098e9e2016-01-07 13:03:56 -08001006def WriteABOTAPackageWithBrilloScript(target_file, output_file,
1007 source_file=None):
1008 """Generate an Android OTA package that has A/B update payload."""
1009
Tao Bao2dd1c482017-02-03 16:49:39 -08001010 def ComputeStreamingMetadata(zip_file, reserve_space=False,
1011 expected_length=None):
1012 """Compute the streaming metadata for a given zip.
1013
1014 When 'reserve_space' is True, we reserve extra space for the offset and
1015 length of the metadata entry itself, although we don't know the final
1016 values until the package gets signed. This function will be called again
1017 after signing. We then write the actual values and pad the string to the
1018 length we set earlier. Note that we can't use the actual length of the
1019 metadata entry in the second run. Otherwise the offsets for other entries
1020 will be changing again.
1021 """
Tao Baoc96316c2017-01-24 22:10:49 -08001022
1023 def ComputeEntryOffsetSize(name):
1024 """Compute the zip entry offset and size."""
1025 info = zip_file.getinfo(name)
1026 offset = info.header_offset + len(info.FileHeader())
1027 size = info.file_size
Tao Bao2dd1c482017-02-03 16:49:39 -08001028 return '%s:%d:%d' % (os.path.basename(name), offset, size)
Tao Baoc96316c2017-01-24 22:10:49 -08001029
1030 # payload.bin and payload_properties.txt must exist.
1031 offsets = [ComputeEntryOffsetSize('payload.bin'),
1032 ComputeEntryOffsetSize('payload_properties.txt')]
1033
1034 # care_map.txt is available only if dm-verity is enabled.
1035 if 'care_map.txt' in zip_file.namelist():
1036 offsets.append(ComputeEntryOffsetSize('care_map.txt'))
Tao Bao2dd1c482017-02-03 16:49:39 -08001037
Tao Bao21803d32017-04-19 10:16:09 -07001038 if 'compatibility.zip' in zip_file.namelist():
1039 offsets.append(ComputeEntryOffsetSize('compatibility.zip'))
1040
Tao Bao2dd1c482017-02-03 16:49:39 -08001041 # 'META-INF/com/android/metadata' is required. We don't know its actual
1042 # offset and length (as well as the values for other entries). So we
1043 # reserve 10-byte as a placeholder, which is to cover the space for metadata
1044 # entry ('xx:xxx', since it's ZIP_STORED which should appear at the
1045 # beginning of the zip), as well as the possible value changes in other
1046 # entries.
1047 if reserve_space:
1048 offsets.append('metadata:' + ' ' * 10)
1049 else:
1050 offsets.append(ComputeEntryOffsetSize(METADATA_NAME))
1051
1052 value = ','.join(offsets)
1053 if expected_length is not None:
1054 assert len(value) <= expected_length, \
1055 'Insufficient reserved space: reserved=%d, actual=%d' % (
1056 expected_length, len(value))
1057 value += ' ' * (expected_length - len(value))
1058 return value
Tao Baoc96316c2017-01-24 22:10:49 -08001059
Alex Deymod8d96ec2016-06-10 16:38:31 -07001060 # The place where the output from the subprocess should go.
1061 log_file = sys.stdout if OPTIONS.verbose else subprocess.PIPE
1062
Tao Baodea0f8b2016-06-20 17:55:06 -07001063 # A/B updater expects a signing key in RSA format. Gets the key ready for
1064 # later use in step 3, unless a payload_signer has been specified.
1065 if OPTIONS.payload_signer is None:
1066 cmd = ["openssl", "pkcs8",
1067 "-in", OPTIONS.package_key + OPTIONS.private_key_suffix,
Christian Oderf63e2cd2017-05-01 22:30:15 +02001068 "-inform", "DER"]
1069 pw = OPTIONS.key_passwords[OPTIONS.package_key]
1070 cmd.extend(["-passin", "pass:" + pw] if pw else ["-nocrypt"])
Tao Baodea0f8b2016-06-20 17:55:06 -07001071 rsa_key = common.MakeTempFile(prefix="key-", suffix=".key")
1072 cmd.extend(["-out", rsa_key])
Tao Bao481bab82017-12-21 11:23:09 -08001073 p1 = common.Run(cmd, verbose=False, stdout=log_file,
1074 stderr=subprocess.STDOUT)
Tao Bao6047c242016-06-21 13:35:26 -07001075 p1.communicate()
Tao Baodea0f8b2016-06-20 17:55:06 -07001076 assert p1.returncode == 0, "openssl pkcs8 failed"
Tao Baoc098e9e2016-01-07 13:03:56 -08001077
Tao Baodea0f8b2016-06-20 17:55:06 -07001078 # Stage the output zip package for package signing.
Tao Baoc098e9e2016-01-07 13:03:56 -08001079 temp_zip_file = tempfile.NamedTemporaryFile()
1080 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1081 compression=zipfile.ZIP_DEFLATED)
1082
Tao Bao481bab82017-12-21 11:23:09 -08001083 if source_file is not None:
1084 target_info = BuildInfo(OPTIONS.target_info_dict, OPTIONS.oem_dicts)
1085 source_info = BuildInfo(OPTIONS.source_info_dict, OPTIONS.oem_dicts)
1086 else:
1087 target_info = BuildInfo(OPTIONS.info_dict, OPTIONS.oem_dicts)
1088 source_info = None
Tao Baoc098e9e2016-01-07 13:03:56 -08001089
Tao Bao481bab82017-12-21 11:23:09 -08001090 # Metadata to comply with Android OTA package format.
Tao Baoc098e9e2016-01-07 13:03:56 -08001091 metadata = {
Tao Bao481bab82017-12-21 11:23:09 -08001092 "post-build" : target_info.fingerprint,
1093 "post-build-incremental" : target_info.GetBuildProp(
1094 "ro.build.version.incremental"),
1095 "ota-required-cache" : "0",
1096 "ota-type" : "AB",
Tao Baoc098e9e2016-01-07 13:03:56 -08001097 }
1098
1099 if source_file is not None:
Tao Bao481bab82017-12-21 11:23:09 -08001100 metadata["pre-device"] = source_info.device
1101 metadata["pre-build"] = source_info.fingerprint
1102 metadata["pre-build-incremental"] = source_info.GetBuildProp(
1103 "ro.build.version.incremental")
Tao Baoc098e9e2016-01-07 13:03:56 -08001104
Tao Bao481bab82017-12-21 11:23:09 -08001105 HandleDowngradeMetadata(metadata, target_info, source_info)
Tao Baob31892e2017-02-07 11:21:17 -08001106 else:
Tao Bao481bab82017-12-21 11:23:09 -08001107 metadata["pre-device"] = target_info.device
1108 metadata["post-timestamp"] = target_info.GetBuildProp("ro.build.date.utc")
Tao Baob31892e2017-02-07 11:21:17 -08001109
Tao Baoc098e9e2016-01-07 13:03:56 -08001110 # 1. Generate payload.
1111 payload_file = common.MakeTempFile(prefix="payload-", suffix=".bin")
1112 cmd = ["brillo_update_payload", "generate",
1113 "--payload", payload_file,
1114 "--target_image", target_file]
1115 if source_file is not None:
1116 cmd.extend(["--source_image", source_file])
Alex Deymod8d96ec2016-06-10 16:38:31 -07001117 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1118 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001119 assert p1.returncode == 0, "brillo_update_payload generate failed"
1120
1121 # 2. Generate hashes of the payload and metadata files.
1122 payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
1123 metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
1124 cmd = ["brillo_update_payload", "hash",
1125 "--unsigned_payload", payload_file,
1126 "--signature_size", "256",
1127 "--metadata_hash_file", metadata_sig_file,
1128 "--payload_hash_file", payload_sig_file]
Alex Deymod8d96ec2016-06-10 16:38:31 -07001129 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1130 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001131 assert p1.returncode == 0, "brillo_update_payload hash failed"
1132
1133 # 3. Sign the hashes and insert them back into the payload file.
1134 signed_payload_sig_file = common.MakeTempFile(prefix="signed-sig-",
1135 suffix=".bin")
1136 signed_metadata_sig_file = common.MakeTempFile(prefix="signed-sig-",
1137 suffix=".bin")
1138 # 3a. Sign the payload hash.
Tao Baodea0f8b2016-06-20 17:55:06 -07001139 if OPTIONS.payload_signer is not None:
Baligh Uddin2abbbd02016-06-22 12:14:16 -07001140 cmd = [OPTIONS.payload_signer]
1141 cmd.extend(OPTIONS.payload_signer_args)
Tao Baodea0f8b2016-06-20 17:55:06 -07001142 else:
1143 cmd = ["openssl", "pkeyutl", "-sign",
1144 "-inkey", rsa_key,
1145 "-pkeyopt", "digest:sha256"]
1146 cmd.extend(["-in", payload_sig_file,
1147 "-out", signed_payload_sig_file])
Alex Deymod8d96ec2016-06-10 16:38:31 -07001148 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1149 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001150 assert p1.returncode == 0, "openssl sign payload failed"
1151
1152 # 3b. Sign the metadata hash.
Tao Baodea0f8b2016-06-20 17:55:06 -07001153 if OPTIONS.payload_signer is not None:
Baligh Uddin2abbbd02016-06-22 12:14:16 -07001154 cmd = [OPTIONS.payload_signer]
1155 cmd.extend(OPTIONS.payload_signer_args)
Tao Baodea0f8b2016-06-20 17:55:06 -07001156 else:
1157 cmd = ["openssl", "pkeyutl", "-sign",
1158 "-inkey", rsa_key,
1159 "-pkeyopt", "digest:sha256"]
1160 cmd.extend(["-in", metadata_sig_file,
1161 "-out", signed_metadata_sig_file])
Alex Deymod8d96ec2016-06-10 16:38:31 -07001162 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1163 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001164 assert p1.returncode == 0, "openssl sign metadata failed"
1165
1166 # 3c. Insert the signatures back into the payload file.
1167 signed_payload_file = common.MakeTempFile(prefix="signed-payload-",
1168 suffix=".bin")
1169 cmd = ["brillo_update_payload", "sign",
1170 "--unsigned_payload", payload_file,
1171 "--payload", signed_payload_file,
1172 "--signature_size", "256",
1173 "--metadata_signature_file", signed_metadata_sig_file,
1174 "--payload_signature_file", signed_payload_sig_file]
Alex Deymod8d96ec2016-06-10 16:38:31 -07001175 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1176 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001177 assert p1.returncode == 0, "brillo_update_payload sign failed"
1178
Alex Deymo19241c12016-02-04 22:29:29 -08001179 # 4. Dump the signed payload properties.
1180 properties_file = common.MakeTempFile(prefix="payload-properties-",
1181 suffix=".txt")
1182 cmd = ["brillo_update_payload", "properties",
1183 "--payload", signed_payload_file,
1184 "--properties_file", properties_file]
Alex Deymod8d96ec2016-06-10 16:38:31 -07001185 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1186 p1.communicate()
Alex Deymo19241c12016-02-04 22:29:29 -08001187 assert p1.returncode == 0, "brillo_update_payload properties failed"
1188
Tao Bao7c5dc572016-06-14 17:48:11 -07001189 if OPTIONS.wipe_user_data:
1190 with open(properties_file, "a") as f:
1191 f.write("POWERWASH=1\n")
1192 metadata["ota-wipe"] = "yes"
1193
Tao Baoc96316c2017-01-24 22:10:49 -08001194 # Add the signed payload file and properties into the zip. In order to
1195 # support streaming, we pack payload.bin, payload_properties.txt and
1196 # care_map.txt as ZIP_STORED. So these entries can be read directly with
1197 # the offset and length pairs.
Tao Baoc098e9e2016-01-07 13:03:56 -08001198 common.ZipWrite(output_zip, signed_payload_file, arcname="payload.bin",
1199 compress_type=zipfile.ZIP_STORED)
Tao Baoc96316c2017-01-24 22:10:49 -08001200 common.ZipWrite(output_zip, properties_file,
1201 arcname="payload_properties.txt",
1202 compress_type=zipfile.ZIP_STORED)
Tao Baoc098e9e2016-01-07 13:03:56 -08001203
Tianjie Xucfa86222016-03-07 16:31:19 -08001204 # If dm-verity is supported for the device, copy contents of care_map
1205 # into A/B OTA package.
Tao Bao21803d32017-04-19 10:16:09 -07001206 target_zip = zipfile.ZipFile(target_file, "r")
Tao Bao481bab82017-12-21 11:23:09 -08001207 if (target_info.get("verity") == "true" or
1208 target_info.get("avb_enable") == "true"):
Tianjie Xucfa86222016-03-07 16:31:19 -08001209 care_map_path = "META/care_map.txt"
1210 namelist = target_zip.namelist()
1211 if care_map_path in namelist:
1212 care_map_data = target_zip.read(care_map_path)
Tao Baoc96316c2017-01-24 22:10:49 -08001213 common.ZipWriteStr(output_zip, "care_map.txt", care_map_data,
Tao Bao481bab82017-12-21 11:23:09 -08001214 compress_type=zipfile.ZIP_STORED)
Tianjie Xucfa86222016-03-07 16:31:19 -08001215 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001216 print("Warning: cannot find care map file in target_file package")
Tao Bao21803d32017-04-19 10:16:09 -07001217
Tao Bao481bab82017-12-21 11:23:09 -08001218 # source_info must be None for full OTAs.
Tao Baobcd1d162017-08-26 13:10:26 -07001219 if source_file is None:
Tao Bao481bab82017-12-21 11:23:09 -08001220 assert source_info is None
Tao Bao21803d32017-04-19 10:16:09 -07001221
Tao Baobcd1d162017-08-26 13:10:26 -07001222 AddCompatibilityArchiveIfTrebleEnabled(
Tao Bao481bab82017-12-21 11:23:09 -08001223 target_zip, output_zip, target_info, source_info)
Tao Bao21803d32017-04-19 10:16:09 -07001224
Tao Bao21803d32017-04-19 10:16:09 -07001225 common.ZipClose(target_zip)
Tianjie Xucfa86222016-03-07 16:31:19 -08001226
Tao Bao2dd1c482017-02-03 16:49:39 -08001227 # Write the current metadata entry with placeholders.
Tao Baobfdcb122017-01-31 15:06:05 -08001228 metadata['ota-streaming-property-files'] = ComputeStreamingMetadata(
Tao Bao2dd1c482017-02-03 16:49:39 -08001229 output_zip, reserve_space=True)
Tao Baoc96316c2017-01-24 22:10:49 -08001230 WriteMetadata(metadata, output_zip)
1231 common.ZipClose(output_zip)
1232
Tao Bao2dd1c482017-02-03 16:49:39 -08001233 # SignOutput(), which in turn calls signapk.jar, will possibly reorder the
Tao Bao89d7ab22017-12-14 17:05:33 -08001234 # ZIP entries, as well as padding the entry headers. We do a preliminary
Tao Bao2dd1c482017-02-03 16:49:39 -08001235 # signing (with an incomplete metadata entry) to allow that to happen. Then
Tao Bao89d7ab22017-12-14 17:05:33 -08001236 # compute the ZIP entry offsets, write back the final metadata and do the
Tao Bao2dd1c482017-02-03 16:49:39 -08001237 # final signing.
Tao Bao89d7ab22017-12-14 17:05:33 -08001238 prelim_signing = common.MakeTempFile(suffix='.zip')
1239 SignOutput(temp_zip_file.name, prelim_signing)
Tao Bao2dd1c482017-02-03 16:49:39 -08001240 common.ZipClose(temp_zip_file)
Tao Baoc96316c2017-01-24 22:10:49 -08001241
Tao Bao2dd1c482017-02-03 16:49:39 -08001242 # Open the signed zip. Compute the final metadata that's needed for streaming.
Tao Bao89d7ab22017-12-14 17:05:33 -08001243 prelim_signing_zip = zipfile.ZipFile(prelim_signing, 'r')
Tao Bao2dd1c482017-02-03 16:49:39 -08001244 expected_length = len(metadata['ota-streaming-property-files'])
1245 metadata['ota-streaming-property-files'] = ComputeStreamingMetadata(
Tao Bao89d7ab22017-12-14 17:05:33 -08001246 prelim_signing_zip, reserve_space=False, expected_length=expected_length)
1247 common.ZipClose(prelim_signing_zip)
Tao Bao2dd1c482017-02-03 16:49:39 -08001248
Tao Bao89d7ab22017-12-14 17:05:33 -08001249 # Replace the METADATA entry.
1250 common.ZipDelete(prelim_signing, METADATA_NAME)
1251 output_zip = zipfile.ZipFile(prelim_signing, 'a',
Tao Bao2dd1c482017-02-03 16:49:39 -08001252 compression=zipfile.ZIP_DEFLATED)
Tao Bao2dd1c482017-02-03 16:49:39 -08001253 WriteMetadata(metadata, output_zip)
Tao Bao2dd1c482017-02-03 16:49:39 -08001254 common.ZipClose(output_zip)
1255
1256 # Re-sign the package after updating the metadata entry.
Tao Bao89d7ab22017-12-14 17:05:33 -08001257 SignOutput(prelim_signing, output_file)
Tao Bao2dd1c482017-02-03 16:49:39 -08001258
1259 # Reopen the final signed zip to double check the streaming metadata.
Tao Bao89d7ab22017-12-14 17:05:33 -08001260 output_zip = zipfile.ZipFile(output_file, 'r')
Tao Bao2dd1c482017-02-03 16:49:39 -08001261 actual = metadata['ota-streaming-property-files'].strip()
1262 expected = ComputeStreamingMetadata(output_zip)
1263 assert actual == expected, \
1264 "Mismatching streaming metadata: %s vs %s." % (actual, expected)
Tao Baoc96316c2017-01-24 22:10:49 -08001265 common.ZipClose(output_zip)
1266
Tao Baoc098e9e2016-01-07 13:03:56 -08001267
Doug Zongkereef39442009-04-02 12:14:19 -07001268def main(argv):
1269
1270 def option_handler(o, a):
Tao Bao4b76a0e2017-10-31 12:13:33 -07001271 if o in ("-k", "--package_key"):
Doug Zongkereef39442009-04-02 12:14:19 -07001272 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001273 elif o in ("-i", "--incremental_from"):
1274 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001275 elif o == "--full_radio":
1276 OPTIONS.full_radio = True
leozwangaa6c1a12015-08-14 10:57:58 -07001277 elif o == "--full_bootloader":
1278 OPTIONS.full_bootloader = True
Tao Bao337633f2017-12-06 15:20:19 -08001279 elif o == "--wipe_user_data":
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001280 OPTIONS.wipe_user_data = True
Tao Bao5d182562016-02-23 11:38:39 -08001281 elif o == "--downgrade":
1282 OPTIONS.downgrade = True
1283 OPTIONS.wipe_user_data = True
Tao Bao3e6161a2017-02-28 11:48:48 -08001284 elif o == "--override_timestamp":
1285 OPTIONS.timestamp = True
Michael Runge6e836112014-04-15 17:40:21 -07001286 elif o in ("-o", "--oem_settings"):
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -08001287 OPTIONS.oem_source = a.split(',')
Tao Bao8608cde2016-02-25 19:49:55 -08001288 elif o == "--oem_no_mount":
1289 OPTIONS.oem_no_mount = True
Doug Zongker1c390a22009-05-14 19:06:36 -07001290 elif o in ("-e", "--extra_script"):
1291 OPTIONS.extra_script = a
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001292 elif o in ("-t", "--worker_threads"):
1293 if a.isdigit():
1294 OPTIONS.worker_threads = int(a)
1295 else:
1296 raise ValueError("Cannot parse value %r for option %r - only "
1297 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001298 elif o in ("-2", "--two_step"):
1299 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001300 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001301 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001302 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001303 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001304 elif o == "--block":
1305 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001306 elif o in ("-b", "--binary"):
1307 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001308 elif o in ("--no_fallback_to_full",):
1309 OPTIONS.fallback_to_full = False
Tao Bao8dcf7382015-05-21 14:09:49 -07001310 elif o == "--stash_threshold":
1311 try:
1312 OPTIONS.stash_threshold = float(a)
1313 except ValueError:
1314 raise ValueError("Cannot parse value %r for option %r - expecting "
1315 "a float" % (a, o))
Tao Baod62c6032015-11-30 09:40:20 -08001316 elif o == "--log_diff":
1317 OPTIONS.log_diff = a
Tao Baodea0f8b2016-06-20 17:55:06 -07001318 elif o == "--payload_signer":
1319 OPTIONS.payload_signer = a
Baligh Uddin2abbbd02016-06-22 12:14:16 -07001320 elif o == "--payload_signer_args":
1321 OPTIONS.payload_signer_args = shlex.split(a)
Dan Willemsencea5cd22017-03-21 14:44:27 -07001322 elif o == "--extracted_input_target_files":
1323 OPTIONS.extracted_input = a
Doug Zongkereef39442009-04-02 12:14:19 -07001324 else:
1325 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001326 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001327
1328 args = common.ParseOptions(argv, __doc__,
Tao Bao337633f2017-12-06 15:20:19 -08001329 extra_opts="b:k:i:d:e:t:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001330 extra_long_opts=[
Dan Albert8b72aef2015-03-23 19:13:21 -07001331 "package_key=",
1332 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001333 "full_radio",
leozwangaa6c1a12015-08-14 10:57:58 -07001334 "full_bootloader",
Dan Albert8b72aef2015-03-23 19:13:21 -07001335 "wipe_user_data",
Tao Bao5d182562016-02-23 11:38:39 -08001336 "downgrade",
Tao Bao3e6161a2017-02-28 11:48:48 -08001337 "override_timestamp",
Dan Albert8b72aef2015-03-23 19:13:21 -07001338 "extra_script=",
1339 "worker_threads=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001340 "two_step",
1341 "no_signing",
1342 "block",
1343 "binary=",
1344 "oem_settings=",
Tao Bao8608cde2016-02-25 19:49:55 -08001345 "oem_no_mount",
Dan Albert8b72aef2015-03-23 19:13:21 -07001346 "verify",
1347 "no_fallback_to_full",
Tao Bao8dcf7382015-05-21 14:09:49 -07001348 "stash_threshold=",
Tao Baod62c6032015-11-30 09:40:20 -08001349 "log_diff=",
Tao Baodea0f8b2016-06-20 17:55:06 -07001350 "payload_signer=",
Baligh Uddin2abbbd02016-06-22 12:14:16 -07001351 "payload_signer_args=",
Dan Willemsencea5cd22017-03-21 14:44:27 -07001352 "extracted_input_target_files=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001353 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001354
1355 if len(args) != 2:
1356 common.Usage(__doc__)
1357 sys.exit(1)
1358
Tao Bao5d182562016-02-23 11:38:39 -08001359 if OPTIONS.downgrade:
1360 # Sanity check to enforce a data wipe.
1361 if not OPTIONS.wipe_user_data:
1362 raise ValueError("Cannot downgrade without a data wipe")
1363
1364 # We should only allow downgrading incrementals (as opposed to full).
1365 # Otherwise the device may go back from arbitrary build with this full
1366 # OTA package.
1367 if OPTIONS.incremental_source is None:
Elliott Hughesd8a52f92016-06-20 14:35:47 -07001368 raise ValueError("Cannot generate downgradable full OTAs")
Tao Bao5d182562016-02-23 11:38:39 -08001369
Tao Bao3e6161a2017-02-28 11:48:48 -08001370 assert not (OPTIONS.downgrade and OPTIONS.timestamp), \
1371 "Cannot have --downgrade AND --override_timestamp both"
1372
Tao Baoc098e9e2016-01-07 13:03:56 -08001373 # Load the dict file from the zip directly to have a peek at the OTA type.
1374 # For packages using A/B update, unzipping is not needed.
Dan Willemsencea5cd22017-03-21 14:44:27 -07001375 if OPTIONS.extracted_input is not None:
Tao Bao481bab82017-12-21 11:23:09 -08001376 OPTIONS.info_dict = common.LoadInfoDict(OPTIONS.extracted_input,
1377 OPTIONS.extracted_input)
Dan Willemsencea5cd22017-03-21 14:44:27 -07001378 else:
1379 input_zip = zipfile.ZipFile(args[0], "r")
1380 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
1381 common.ZipClose(input_zip)
Tao Baoc098e9e2016-01-07 13:03:56 -08001382
Tao Bao481bab82017-12-21 11:23:09 -08001383 OPTIONS.oem_dicts = _LoadOemDicts(OPTIONS.oem_source)
1384
Tao Baoc098e9e2016-01-07 13:03:56 -08001385 ab_update = OPTIONS.info_dict.get("ab_update") == "true"
1386
Christian Oderf63e2cd2017-05-01 22:30:15 +02001387 # Use the default key to sign the package if not specified with package_key.
1388 # package_keys are needed on ab_updates, so always define them if an
1389 # ab_update is getting created.
1390 if not OPTIONS.no_signing or ab_update:
1391 if OPTIONS.package_key is None:
1392 OPTIONS.package_key = OPTIONS.info_dict.get(
1393 "default_system_dev_certificate",
1394 "build/target/product/security/testkey")
1395 # Get signing keys
1396 OPTIONS.key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
1397
Tao Baoc098e9e2016-01-07 13:03:56 -08001398 if ab_update:
1399 if OPTIONS.incremental_source is not None:
1400 OPTIONS.target_info_dict = OPTIONS.info_dict
1401 source_zip = zipfile.ZipFile(OPTIONS.incremental_source, "r")
1402 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1403 common.ZipClose(source_zip)
1404
1405 if OPTIONS.verbose:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001406 print("--- target info ---")
Tao Baoc098e9e2016-01-07 13:03:56 -08001407 common.DumpInfoDict(OPTIONS.info_dict)
1408
1409 if OPTIONS.incremental_source is not None:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001410 print("--- source info ---")
Tao Baoc098e9e2016-01-07 13:03:56 -08001411 common.DumpInfoDict(OPTIONS.source_info_dict)
1412
1413 WriteABOTAPackageWithBrilloScript(
1414 target_file=args[0],
1415 output_file=args[1],
1416 source_file=OPTIONS.incremental_source)
1417
Tao Bao89fbb0f2017-01-10 10:47:58 -08001418 print("done.")
Tao Baoc098e9e2016-01-07 13:03:56 -08001419 return
1420
Doug Zongker1c390a22009-05-14 19:06:36 -07001421 if OPTIONS.extra_script is not None:
1422 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1423
Dan Willemsencea5cd22017-03-21 14:44:27 -07001424 if OPTIONS.extracted_input is not None:
1425 OPTIONS.input_tmp = OPTIONS.extracted_input
1426 OPTIONS.target_tmp = OPTIONS.input_tmp
Tao Bao481bab82017-12-21 11:23:09 -08001427 OPTIONS.info_dict = common.LoadInfoDict(OPTIONS.input_tmp,
1428 OPTIONS.input_tmp)
Dan Willemsencea5cd22017-03-21 14:44:27 -07001429 input_zip = zipfile.ZipFile(args[0], "r")
1430 else:
1431 print("unzipping target target-files...")
1432 OPTIONS.input_tmp, input_zip = common.UnzipTemp(
1433 args[0], UNZIP_PATTERN)
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001434
Dan Willemsencea5cd22017-03-21 14:44:27 -07001435 OPTIONS.target_tmp = OPTIONS.input_tmp
1436 OPTIONS.info_dict = common.LoadInfoDict(input_zip, OPTIONS.target_tmp)
Kenny Roote2e9f612013-05-29 12:59:35 -07001437
Doug Zongker37974732010-09-16 17:44:38 -07001438 if OPTIONS.verbose:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001439 print("--- target info ---")
Doug Zongker37974732010-09-16 17:44:38 -07001440 common.DumpInfoDict(OPTIONS.info_dict)
1441
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001442 # If the caller explicitly specified the device-specific extensions
1443 # path via -s/--device_specific, use that. Otherwise, use
1444 # META/releasetools.py if it is present in the target target_files.
1445 # Otherwise, take the path of the file from 'tool_extensions' in the
1446 # info dict and look for that in the local filesystem, relative to
1447 # the current directory.
1448
Doug Zongker37974732010-09-16 17:44:38 -07001449 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001450 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1451 if os.path.exists(from_input):
Tao Bao89fbb0f2017-01-10 10:47:58 -08001452 print("(using device-specific extensions from target_files)")
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001453 OPTIONS.device_specific = from_input
1454 else:
1455 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1456
Doug Zongker37974732010-09-16 17:44:38 -07001457 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001458 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001459
Tao Baoc098e9e2016-01-07 13:03:56 -08001460 if OPTIONS.info_dict.get("no_recovery") == "true":
Tao Baodb45efa2015-10-27 19:25:18 -07001461 raise common.ExternalError(
1462 "--- target build has specified no recovery ---")
1463
Tao Bao767e3ac2015-11-10 12:19:19 -08001464 # Set up the output zip. Create a temporary zip file if signing is needed.
1465 if OPTIONS.no_signing:
1466 if os.path.exists(args[1]):
1467 os.unlink(args[1])
1468 output_zip = zipfile.ZipFile(args[1], "w",
1469 compression=zipfile.ZIP_DEFLATED)
1470 else:
1471 temp_zip_file = tempfile.NamedTemporaryFile()
1472 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1473 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001474
Daniel Rosenberg40ef35b2015-11-10 19:21:34 -08001475 # Non A/B OTAs rely on /cache partition to store temporary files.
Tao Bao767e3ac2015-11-10 12:19:19 -08001476 cache_size = OPTIONS.info_dict.get("cache_size", None)
Tao Baoc098e9e2016-01-07 13:03:56 -08001477 if cache_size is None:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001478 print("--- can't determine the cache partition size ---")
Tao Bao767e3ac2015-11-10 12:19:19 -08001479 OPTIONS.cache_size = cache_size
Tao Bao8dcf7382015-05-21 14:09:49 -07001480
Tao Bao767e3ac2015-11-10 12:19:19 -08001481 # Generate a full OTA.
Tao Bao0c6a4142017-12-15 10:11:19 -08001482 if OPTIONS.incremental_source is None:
Tao Baoc098e9e2016-01-07 13:03:56 -08001483 WriteFullOTAPackage(input_zip, output_zip)
Tao Bao767e3ac2015-11-10 12:19:19 -08001484
1485 # Generate an incremental OTA. It will fall back to generate a full OTA on
1486 # failure unless no_fallback_to_full is specified.
1487 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001488 print("unzipping source target-files...")
Tao Bao767e3ac2015-11-10 12:19:19 -08001489 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
Tao Bao6b0b2f92017-03-05 11:38:11 -08001490 OPTIONS.incremental_source,
Tao Bao457cbf62017-03-06 09:56:01 -08001491 UNZIP_PATTERN)
Tao Bao767e3ac2015-11-10 12:19:19 -08001492 OPTIONS.target_info_dict = OPTIONS.info_dict
1493 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip,
1494 OPTIONS.source_tmp)
1495 if OPTIONS.verbose:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001496 print("--- source info ---")
Tao Bao767e3ac2015-11-10 12:19:19 -08001497 common.DumpInfoDict(OPTIONS.source_info_dict)
1498 try:
Tao Bao457cbf62017-03-06 09:56:01 -08001499 WriteBlockIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Baod62c6032015-11-30 09:40:20 -08001500 if OPTIONS.log_diff:
1501 out_file = open(OPTIONS.log_diff, 'w')
1502 import target_files_diff
1503 target_files_diff.recursiveDiff('',
1504 OPTIONS.source_tmp,
1505 OPTIONS.input_tmp,
1506 out_file)
1507 out_file.close()
Tao Bao767e3ac2015-11-10 12:19:19 -08001508 except ValueError:
1509 if not OPTIONS.fallback_to_full:
1510 raise
Tao Bao89fbb0f2017-01-10 10:47:58 -08001511 print("--- failed to build incremental; falling back to full ---")
Tao Bao767e3ac2015-11-10 12:19:19 -08001512 OPTIONS.incremental_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -07001513 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001514
Tao Bao767e3ac2015-11-10 12:19:19 -08001515 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001516
Tao Bao767e3ac2015-11-10 12:19:19 -08001517 # Sign the generated zip package unless no_signing is specified.
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001518 if not OPTIONS.no_signing:
1519 SignOutput(temp_zip_file.name, args[1])
1520 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001521
Tao Bao89fbb0f2017-01-10 10:47:58 -08001522 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001523
1524
1525if __name__ == '__main__':
1526 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001527 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001528 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001529 except common.ExternalError as e:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001530 print("\n ERROR: %s\n" % (e,))
Doug Zongkereef39442009-04-02 12:14:19 -07001531 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001532 finally:
1533 common.Cleanup()