blob: cd497b2b9368322c0191e36d568962a72b7290c2 [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
Tao Baof7140c02018-01-30 17:09:24 -080095 --include_secondary
96 Additionally include the payload for secondary slot images (default:
97 False). Only meaningful when generating A/B OTAs.
98
99 By default, an A/B OTA package doesn't contain the images for the
100 secondary slot (e.g. system_other.img). Specifying this flag allows
101 generating a separate payload that will install secondary slot images.
102
103 Such a package needs to be applied in a two-stage manner, with a reboot
104 in-between. During the first stage, the updater applies the primary
105 payload only. Upon finishing, it reboots the device into the newly updated
106 slot. It then continues to install the secondary payload to the inactive
107 slot, but without switching the active slot at the end (needs the matching
108 support in update_engine, i.e. SWITCH_SLOT_ON_REBOOT flag).
109
110 Due to the special install procedure, the secondary payload will be always
111 generated as a full payload.
112
Doug Zongker26e66192014-02-20 13:22:07 -0800113 --block
Tao Bao457cbf62017-03-06 09:56:01 -0800114 Generate a block-based OTA for non-A/B device. We have deprecated the
115 support for file-based OTA since O. Block-based OTA will be used by
116 default for all non-A/B devices. Keeping this flag here to not break
117 existing callers.
Doug Zongker26e66192014-02-20 13:22:07 -0800118
Doug Zongker25568482014-03-03 10:21:27 -0800119 -b (--binary) <file>
120 Use the given binary as the update-binary in the output package,
121 instead of the binary in the build's target_files. Use for
122 development only.
123
Martin Blumenstingl374e1142014-05-31 20:42:55 +0200124 -t (--worker_threads) <int>
125 Specifies the number of worker-threads that will be used when
126 generating patches for incremental updates (defaults to 3).
127
Tao Bao8dcf7382015-05-21 14:09:49 -0700128 --stash_threshold <float>
129 Specifies the threshold that will be used to compute the maximum
130 allowed stash size (defaults to 0.8).
Tao Bao9bc6bb22015-11-09 16:58:28 -0800131
Tao Baod62c6032015-11-30 09:40:20 -0800132 --log_diff <file>
133 Generate a log file that shows the differences in the source and target
134 builds for an incremental package. This option is only meaningful when
135 -i is specified.
Tao Baodea0f8b2016-06-20 17:55:06 -0700136
137 --payload_signer <signer>
138 Specify the signer when signing the payload and metadata for A/B OTAs.
139 By default (i.e. without this flag), it calls 'openssl pkeyutl' to sign
140 with the package private key. If the private key cannot be accessed
141 directly, a payload signer that knows how to do that should be specified.
142 The signer will be supplied with "-inkey <path_to_key>",
143 "-in <input_file>" and "-out <output_file>" parameters.
Baligh Uddin2abbbd02016-06-22 12:14:16 -0700144
145 --payload_signer_args <args>
146 Specify the arguments needed for payload signer.
Doug Zongkereef39442009-04-02 12:14:19 -0700147"""
148
Tao Bao89fbb0f2017-01-10 10:47:58 -0800149from __future__ import print_function
150
Doug Zongkerfc44a512014-08-26 13:10:25 -0700151import multiprocessing
Tao Bao2dd1c482017-02-03 16:49:39 -0800152import os.path
Baligh Uddin2abbbd02016-06-22 12:14:16 -0700153import shlex
Tao Bao481bab82017-12-21 11:23:09 -0800154import subprocess
155import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700156import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -0700157import zipfile
158
159import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700160import edify_generator
Doug Zongkereef39442009-04-02 12:14:19 -0700161
Tao Bao481bab82017-12-21 11:23:09 -0800162if sys.hexversion < 0x02070000:
163 print("Python 2.7 or newer is required.", file=sys.stderr)
164 sys.exit(1)
165
166
Doug Zongkereef39442009-04-02 12:14:19 -0700167OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700168OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700169OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700170OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700171OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700172OPTIONS.wipe_user_data = False
Tao Bao5d182562016-02-23 11:38:39 -0800173OPTIONS.downgrade = False
Tao Bao3e6161a2017-02-28 11:48:48 -0800174OPTIONS.timestamp = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700175OPTIONS.extra_script = None
Doug Zongkerfc44a512014-08-26 13:10:25 -0700176OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
177if OPTIONS.worker_threads == 0:
178 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800179OPTIONS.two_step = False
Tao Baof7140c02018-01-30 17:09:24 -0800180OPTIONS.include_secondary = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900181OPTIONS.no_signing = False
Tao Bao457cbf62017-03-06 09:56:01 -0800182OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -0800183OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700184OPTIONS.oem_source = None
Tao Bao8608cde2016-02-25 19:49:55 -0800185OPTIONS.oem_no_mount = False
Tao Bao43078aa2015-04-21 14:32:35 -0700186OPTIONS.full_radio = False
leozwangaa6c1a12015-08-14 10:57:58 -0700187OPTIONS.full_bootloader = False
Tao Baod47d8e12015-05-21 14:09:49 -0700188# Stash size cannot exceed cache_size * threshold.
189OPTIONS.cache_size = None
190OPTIONS.stash_threshold = 0.8
Tao Baod62c6032015-11-30 09:40:20 -0800191OPTIONS.log_diff = None
Tao Baodea0f8b2016-06-20 17:55:06 -0700192OPTIONS.payload_signer = None
Baligh Uddin2abbbd02016-06-22 12:14:16 -0700193OPTIONS.payload_signer_args = []
Tao Bao5f8ff932017-03-21 22:35:00 -0700194OPTIONS.extracted_input = None
Christian Oderf63e2cd2017-05-01 22:30:15 +0200195OPTIONS.key_passwords = []
Tao Bao8dcf7382015-05-21 14:09:49 -0700196
Tao Bao2dd1c482017-02-03 16:49:39 -0800197METADATA_NAME = 'META-INF/com/android/metadata'
Tao Bao6b0b2f92017-03-05 11:38:11 -0800198UNZIP_PATTERN = ['IMAGES/*', 'META/*']
199
Tao Bao2dd1c482017-02-03 16:49:39 -0800200
Tao Bao481bab82017-12-21 11:23:09 -0800201class BuildInfo(object):
202 """A class that holds the information for a given build.
203
204 This class wraps up the property querying for a given source or target build.
205 It abstracts away the logic of handling OEM-specific properties, and caches
206 the commonly used properties such as fingerprint.
207
208 There are two types of info dicts: a) build-time info dict, which is generated
209 at build time (i.e. included in a target_files zip); b) OEM info dict that is
210 specified at package generation time (via command line argument
211 '--oem_settings'). If a build doesn't use OEM-specific properties (i.e. not
212 having "oem_fingerprint_properties" in build-time info dict), all the queries
213 would be answered based on build-time info dict only. Otherwise if using
214 OEM-specific properties, some of them will be calculated from two info dicts.
215
216 Users can query properties similarly as using a dict() (e.g. info['fstab']),
217 or to query build properties via GetBuildProp() or GetVendorBuildProp().
218
219 Attributes:
220 info_dict: The build-time info dict.
221 is_ab: Whether it's a build that uses A/B OTA.
222 oem_dicts: A list of OEM dicts.
223 oem_props: A list of OEM properties that should be read from OEM dicts; None
224 if the build doesn't use any OEM-specific property.
225 fingerprint: The fingerprint of the build, which would be calculated based
226 on OEM properties if applicable.
227 device: The device name, which could come from OEM dicts if applicable.
228 """
229
230 def __init__(self, info_dict, oem_dicts):
231 """Initializes a BuildInfo instance with the given dicts.
232
233 Arguments:
234 info_dict: The build-time info dict.
235 oem_dicts: A list of OEM dicts (which is parsed from --oem_settings). Note
236 that it always uses the first dict to calculate the fingerprint or the
237 device name. The rest would be used for asserting OEM properties only
238 (e.g. one package can be installed on one of these devices).
239 """
240 self.info_dict = info_dict
241 self.oem_dicts = oem_dicts
242
243 self._is_ab = info_dict.get("ab_update") == "true"
244 self._oem_props = info_dict.get("oem_fingerprint_properties")
245
246 if self._oem_props:
247 assert oem_dicts, "OEM source required for this build"
248
249 # These two should be computed only after setting self._oem_props.
250 self._device = self.GetOemProperty("ro.product.device")
251 self._fingerprint = self.CalculateFingerprint()
252
253 @property
254 def is_ab(self):
255 return self._is_ab
256
257 @property
258 def device(self):
259 return self._device
260
261 @property
262 def fingerprint(self):
263 return self._fingerprint
264
265 @property
266 def oem_props(self):
267 return self._oem_props
268
269 def __getitem__(self, key):
270 return self.info_dict[key]
271
272 def get(self, key, default=None):
273 return self.info_dict.get(key, default)
274
275 def GetBuildProp(self, prop):
276 """Returns the inquired build property."""
277 try:
278 return self.info_dict.get("build.prop", {})[prop]
279 except KeyError:
280 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
281
282 def GetVendorBuildProp(self, prop):
283 """Returns the inquired vendor build property."""
284 try:
285 return self.info_dict.get("vendor.build.prop", {})[prop]
286 except KeyError:
287 raise common.ExternalError(
288 "couldn't find %s in vendor.build.prop" % (prop,))
289
290 def GetOemProperty(self, key):
291 if self.oem_props is not None and key in self.oem_props:
292 return self.oem_dicts[0][key]
293 return self.GetBuildProp(key)
294
295 def CalculateFingerprint(self):
296 if self.oem_props is None:
297 return self.GetBuildProp("ro.build.fingerprint")
298 return "%s/%s/%s:%s" % (
299 self.GetOemProperty("ro.product.brand"),
300 self.GetOemProperty("ro.product.name"),
301 self.GetOemProperty("ro.product.device"),
302 self.GetBuildProp("ro.build.thumbprint"))
303
304 def WriteMountOemScript(self, script):
305 assert self.oem_props is not None
306 recovery_mount_options = self.info_dict.get("recovery_mount_options")
307 script.Mount("/oem", recovery_mount_options)
308
309 def WriteDeviceAssertions(self, script, oem_no_mount):
310 # Read the property directly if not using OEM properties.
311 if not self.oem_props:
312 script.AssertDevice(self.device)
313 return
314
315 # Otherwise assert OEM properties.
316 if not self.oem_dicts:
317 raise common.ExternalError(
318 "No OEM file provided to answer expected assertions")
319
320 for prop in self.oem_props.split():
321 values = []
322 for oem_dict in self.oem_dicts:
323 if prop in oem_dict:
324 values.append(oem_dict[prop])
325 if not values:
326 raise common.ExternalError(
327 "The OEM file is missing the property %s" % (prop,))
328 script.AssertOemProperty(prop, values, oem_no_mount)
329
330
Tao Baofabe0832018-01-17 15:52:28 -0800331class PayloadSigner(object):
332 """A class that wraps the payload signing works.
333
334 When generating a Payload, hashes of the payload and metadata files will be
335 signed with the device key, either by calling an external payload signer or
336 by calling openssl with the package key. This class provides a unified
337 interface, so that callers can just call PayloadSigner.Sign().
338
339 If an external payload signer has been specified (OPTIONS.payload_signer), it
340 calls the signer with the provided args (OPTIONS.payload_signer_args). Note
341 that the signing key should be provided as part of the payload_signer_args.
342 Otherwise without an external signer, it uses the package key
343 (OPTIONS.package_key) and calls openssl for the signing works.
344 """
345
346 def __init__(self):
347 if OPTIONS.payload_signer is None:
348 # Prepare the payload signing key.
349 private_key = OPTIONS.package_key + OPTIONS.private_key_suffix
350 pw = OPTIONS.key_passwords[OPTIONS.package_key]
351
352 cmd = ["openssl", "pkcs8", "-in", private_key, "-inform", "DER"]
353 cmd.extend(["-passin", "pass:" + pw] if pw else ["-nocrypt"])
354 signing_key = common.MakeTempFile(prefix="key-", suffix=".key")
355 cmd.extend(["-out", signing_key])
356
357 get_signing_key = common.Run(cmd, verbose=False, stdout=subprocess.PIPE,
358 stderr=subprocess.STDOUT)
359 stdoutdata, _ = get_signing_key.communicate()
360 assert get_signing_key.returncode == 0, \
361 "Failed to get signing key: {}".format(stdoutdata)
362
363 self.signer = "openssl"
364 self.signer_args = ["pkeyutl", "-sign", "-inkey", signing_key,
365 "-pkeyopt", "digest:sha256"]
366 else:
367 self.signer = OPTIONS.payload_signer
368 self.signer_args = OPTIONS.payload_signer_args
369
370 def Sign(self, in_file):
371 """Signs the given input file. Returns the output filename."""
372 out_file = common.MakeTempFile(prefix="signed-", suffix=".bin")
373 cmd = [self.signer] + self.signer_args + ['-in', in_file, '-out', out_file]
374 signing = common.Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
375 stdoutdata, _ = signing.communicate()
376 assert signing.returncode == 0, \
377 "Failed to sign the input file: {}".format(stdoutdata)
378 return out_file
379
380
Tao Baoc7b403a2018-01-30 18:19:04 -0800381class Payload(object):
382 """Manages the creation and the signing of an A/B OTA Payload."""
383
384 PAYLOAD_BIN = 'payload.bin'
385 PAYLOAD_PROPERTIES_TXT = 'payload_properties.txt'
Tao Baof7140c02018-01-30 17:09:24 -0800386 SECONDARY_PAYLOAD_BIN = 'secondary/payload.bin'
387 SECONDARY_PAYLOAD_PROPERTIES_TXT = 'secondary/payload_properties.txt'
Tao Baoc7b403a2018-01-30 18:19:04 -0800388
389 def __init__(self):
390 # The place where the output from the subprocess should go.
391 self._log_file = sys.stdout if OPTIONS.verbose else subprocess.PIPE
392 self.payload_file = None
393 self.payload_properties = None
394
395 def Generate(self, target_file, source_file=None, additional_args=None):
396 """Generates a payload from the given target-files zip(s).
397
398 Args:
399 target_file: The filename of the target build target-files zip.
400 source_file: The filename of the source build target-files zip; or None if
401 generating a full OTA.
402 additional_args: A list of additional args that should be passed to
403 brillo_update_payload script; or None.
404 """
405 if additional_args is None:
406 additional_args = []
407
408 payload_file = common.MakeTempFile(prefix="payload-", suffix=".bin")
409 cmd = ["brillo_update_payload", "generate",
410 "--payload", payload_file,
411 "--target_image", target_file]
412 if source_file is not None:
413 cmd.extend(["--source_image", source_file])
414 cmd.extend(additional_args)
415 p = common.Run(cmd, stdout=self._log_file, stderr=subprocess.STDOUT)
416 stdoutdata, _ = p.communicate()
417 assert p.returncode == 0, \
418 "brillo_update_payload generate failed: {}".format(stdoutdata)
419
420 self.payload_file = payload_file
421 self.payload_properties = None
422
423 def Sign(self, payload_signer):
424 """Generates and signs the hashes of the payload and metadata.
425
426 Args:
427 payload_signer: A PayloadSigner() instance that serves the signing work.
428
429 Raises:
430 AssertionError: On any failure when calling brillo_update_payload script.
431 """
432 assert isinstance(payload_signer, PayloadSigner)
433
434 # 1. Generate hashes of the payload and metadata files.
435 payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
436 metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
437 cmd = ["brillo_update_payload", "hash",
438 "--unsigned_payload", self.payload_file,
439 "--signature_size", "256",
440 "--metadata_hash_file", metadata_sig_file,
441 "--payload_hash_file", payload_sig_file]
442 p1 = common.Run(cmd, stdout=self._log_file, stderr=subprocess.STDOUT)
443 p1.communicate()
444 assert p1.returncode == 0, "brillo_update_payload hash failed"
445
446 # 2. Sign the hashes.
447 signed_payload_sig_file = payload_signer.Sign(payload_sig_file)
448 signed_metadata_sig_file = payload_signer.Sign(metadata_sig_file)
449
450 # 3. Insert the signatures back into the payload file.
451 signed_payload_file = common.MakeTempFile(prefix="signed-payload-",
452 suffix=".bin")
453 cmd = ["brillo_update_payload", "sign",
454 "--unsigned_payload", self.payload_file,
455 "--payload", signed_payload_file,
456 "--signature_size", "256",
457 "--metadata_signature_file", signed_metadata_sig_file,
458 "--payload_signature_file", signed_payload_sig_file]
459 p1 = common.Run(cmd, stdout=self._log_file, stderr=subprocess.STDOUT)
460 p1.communicate()
461 assert p1.returncode == 0, "brillo_update_payload sign failed"
462
463 # 4. Dump the signed payload properties.
464 properties_file = common.MakeTempFile(prefix="payload-properties-",
465 suffix=".txt")
466 cmd = ["brillo_update_payload", "properties",
467 "--payload", signed_payload_file,
468 "--properties_file", properties_file]
469 p1 = common.Run(cmd, stdout=self._log_file, stderr=subprocess.STDOUT)
470 p1.communicate()
471 assert p1.returncode == 0, "brillo_update_payload properties failed"
472
473 if OPTIONS.wipe_user_data:
474 with open(properties_file, "a") as f:
475 f.write("POWERWASH=1\n")
476
477 self.payload_file = signed_payload_file
478 self.payload_properties = properties_file
479
Tao Baof7140c02018-01-30 17:09:24 -0800480 def WriteToZip(self, output_zip, secondary=False):
Tao Baoc7b403a2018-01-30 18:19:04 -0800481 """Writes the payload to the given zip.
482
483 Args:
484 output_zip: The output ZipFile instance.
Tao Baof7140c02018-01-30 17:09:24 -0800485 secondary: Whether the payload should be packed as secondary payload
486 (default: False).
Tao Baoc7b403a2018-01-30 18:19:04 -0800487 """
488 assert self.payload_file is not None
489 assert self.payload_properties is not None
490
Tao Baof7140c02018-01-30 17:09:24 -0800491 if secondary:
492 payload_arcname = Payload.SECONDARY_PAYLOAD_BIN
493 payload_properties_arcname = Payload.SECONDARY_PAYLOAD_PROPERTIES_TXT
494 else:
495 payload_arcname = Payload.PAYLOAD_BIN
496 payload_properties_arcname = Payload.PAYLOAD_PROPERTIES_TXT
497
Tao Baoc7b403a2018-01-30 18:19:04 -0800498 # Add the signed payload file and properties into the zip. In order to
499 # support streaming, we pack them as ZIP_STORED. So these entries can be
500 # read directly with the offset and length pairs.
Tao Baof7140c02018-01-30 17:09:24 -0800501 common.ZipWrite(output_zip, self.payload_file, arcname=payload_arcname,
Tao Baoc7b403a2018-01-30 18:19:04 -0800502 compress_type=zipfile.ZIP_STORED)
503 common.ZipWrite(output_zip, self.payload_properties,
Tao Baof7140c02018-01-30 17:09:24 -0800504 arcname=payload_properties_arcname,
Tao Baoc7b403a2018-01-30 18:19:04 -0800505 compress_type=zipfile.ZIP_STORED)
506
507
Doug Zongkereef39442009-04-02 12:14:19 -0700508def SignOutput(temp_zip_name, output_zip_name):
Christian Oderf63e2cd2017-05-01 22:30:15 +0200509 pw = OPTIONS.key_passwords[OPTIONS.package_key]
Doug Zongkereef39442009-04-02 12:14:19 -0700510
Doug Zongker951495f2009-08-14 12:44:19 -0700511 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
512 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700513
514
Tao Bao481bab82017-12-21 11:23:09 -0800515def _LoadOemDicts(oem_source):
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800516 """Returns the list of loaded OEM properties dict."""
Tao Bao481bab82017-12-21 11:23:09 -0800517 if not oem_source:
518 return None
519
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800520 oem_dicts = []
Tao Bao481bab82017-12-21 11:23:09 -0800521 for oem_file in oem_source:
522 with open(oem_file) as fp:
523 oem_dicts.append(common.LoadDictionaryFromLines(fp.readlines()))
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800524 return oem_dicts
Doug Zongkereef39442009-04-02 12:14:19 -0700525
Doug Zongkereef39442009-04-02 12:14:19 -0700526
Tao Baod42e97e2016-11-30 12:11:57 -0800527def _WriteRecoveryImageToBoot(script, output_zip):
528 """Find and write recovery image to /boot in two-step OTA.
529
530 In two-step OTAs, we write recovery image to /boot as the first step so that
531 we can reboot to there and install a new recovery image to /recovery.
532 A special "recovery-two-step.img" will be preferred, which encodes the correct
533 path of "/boot". Otherwise the device may show "device is corrupt" message
534 when booting into /boot.
535
536 Fall back to using the regular recovery.img if the two-step recovery image
537 doesn't exist. Note that rebuilding the special image at this point may be
538 infeasible, because we don't have the desired boot signer and keys when
539 calling ota_from_target_files.py.
540 """
541
542 recovery_two_step_img_name = "recovery-two-step.img"
543 recovery_two_step_img_path = os.path.join(
544 OPTIONS.input_tmp, "IMAGES", recovery_two_step_img_name)
545 if os.path.exists(recovery_two_step_img_path):
546 recovery_two_step_img = common.GetBootableImage(
547 recovery_two_step_img_name, recovery_two_step_img_name,
548 OPTIONS.input_tmp, "RECOVERY")
549 common.ZipWriteStr(
550 output_zip, recovery_two_step_img_name, recovery_two_step_img.data)
Tao Bao89fbb0f2017-01-10 10:47:58 -0800551 print("two-step package: using %s in stage 1/3" % (
552 recovery_two_step_img_name,))
Tao Baod42e97e2016-11-30 12:11:57 -0800553 script.WriteRawImage("/boot", recovery_two_step_img_name)
554 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -0800555 print("two-step package: using recovery.img in stage 1/3")
Tao Baod42e97e2016-11-30 12:11:57 -0800556 # The "recovery.img" entry has been written into package earlier.
557 script.WriteRawImage("/boot", "recovery.img")
558
559
Doug Zongkerc9253822014-02-04 12:17:58 -0800560def HasRecoveryPatch(target_files_zip):
Tao Baof2cffbd2015-07-22 12:33:18 -0700561 namelist = [name for name in target_files_zip.namelist()]
562 return ("SYSTEM/recovery-from-boot.p" in namelist or
563 "SYSTEM/etc/recovery.img" in namelist)
Doug Zongker73ef8252009-07-23 15:12:53 -0700564
Tao Bao457cbf62017-03-06 09:56:01 -0800565
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700566def HasVendorPartition(target_files_zip):
567 try:
568 target_files_zip.getinfo("VENDOR/")
569 return True
570 except KeyError:
571 return False
572
Tao Bao457cbf62017-03-06 09:56:01 -0800573
Tao Bao481bab82017-12-21 11:23:09 -0800574def HasTrebleEnabled(target_files_zip, target_info):
Tao Baobcd1d162017-08-26 13:10:26 -0700575 return (HasVendorPartition(target_files_zip) and
Tao Bao481bab82017-12-21 11:23:09 -0800576 target_info.GetBuildProp("ro.treble.enabled") == "true")
Tao Baobcd1d162017-08-26 13:10:26 -0700577
578
Tao Bao481bab82017-12-21 11:23:09 -0800579def WriteFingerprintAssertion(script, target_info, source_info):
580 source_oem_props = source_info.oem_props
581 target_oem_props = target_info.oem_props
Michael Runge6e836112014-04-15 17:40:21 -0700582
Tao Bao481bab82017-12-21 11:23:09 -0800583 if source_oem_props is None and target_oem_props is None:
584 script.AssertSomeFingerprint(
585 source_info.fingerprint, target_info.fingerprint)
586 elif source_oem_props is not None and target_oem_props is not None:
587 script.AssertSomeThumbprint(
588 target_info.GetBuildProp("ro.build.thumbprint"),
589 source_info.GetBuildProp("ro.build.thumbprint"))
590 elif source_oem_props is None and target_oem_props is not None:
591 script.AssertFingerprintOrThumbprint(
592 source_info.fingerprint,
593 target_info.GetBuildProp("ro.build.thumbprint"))
594 else:
595 script.AssertFingerprintOrThumbprint(
596 target_info.fingerprint,
597 source_info.GetBuildProp("ro.build.thumbprint"))
Doug Zongker73ef8252009-07-23 15:12:53 -0700598
Doug Zongkerfc44a512014-08-26 13:10:25 -0700599
Tao Bao481bab82017-12-21 11:23:09 -0800600def AddCompatibilityArchiveIfTrebleEnabled(target_zip, output_zip, target_info,
601 source_info=None):
Tao Baobcd1d162017-08-26 13:10:26 -0700602 """Adds compatibility info into the output zip if it's Treble-enabled target.
Tao Bao21803d32017-04-19 10:16:09 -0700603
604 Metadata used for on-device compatibility verification is retrieved from
605 target_zip then added to compatibility.zip which is added to the output_zip
606 archive.
607
Tao Baobcd1d162017-08-26 13:10:26 -0700608 Compatibility archive should only be included for devices that have enabled
609 Treble support.
Tao Bao21803d32017-04-19 10:16:09 -0700610
611 Args:
612 target_zip: Zip file containing the source files to be included for OTA.
613 output_zip: Zip file that will be sent for OTA.
Tao Bao481bab82017-12-21 11:23:09 -0800614 target_info: The BuildInfo instance that holds the target build info.
615 source_info: The BuildInfo instance that holds the source build info, if
616 generating an incremental OTA; None otherwise.
Tao Bao21803d32017-04-19 10:16:09 -0700617 """
618
Tao Baobcd1d162017-08-26 13:10:26 -0700619 def AddCompatibilityArchive(system_updated, vendor_updated):
620 """Adds compatibility info based on system/vendor update status.
Tao Bao21803d32017-04-19 10:16:09 -0700621
Tao Baobcd1d162017-08-26 13:10:26 -0700622 Args:
623 system_updated: If True, the system image will be updated and therefore
624 its metadata should be included.
625 vendor_updated: If True, the vendor image will be updated and therefore
626 its metadata should be included.
627 """
628 # Determine what metadata we need. Files are names relative to META/.
629 compatibility_files = []
630 vendor_metadata = ("vendor_manifest.xml", "vendor_matrix.xml")
631 system_metadata = ("system_manifest.xml", "system_matrix.xml")
632 if vendor_updated:
633 compatibility_files += vendor_metadata
634 if system_updated:
635 compatibility_files += system_metadata
Tao Bao21803d32017-04-19 10:16:09 -0700636
Tao Baobcd1d162017-08-26 13:10:26 -0700637 # Create new archive.
638 compatibility_archive = tempfile.NamedTemporaryFile()
Tao Bao481bab82017-12-21 11:23:09 -0800639 compatibility_archive_zip = zipfile.ZipFile(
640 compatibility_archive, "w", compression=zipfile.ZIP_DEFLATED)
Tao Bao21803d32017-04-19 10:16:09 -0700641
Tao Baobcd1d162017-08-26 13:10:26 -0700642 # Add metadata.
643 for file_name in compatibility_files:
644 target_file_name = "META/" + file_name
Tao Bao21803d32017-04-19 10:16:09 -0700645
Tao Baobcd1d162017-08-26 13:10:26 -0700646 if target_file_name in target_zip.namelist():
647 data = target_zip.read(target_file_name)
648 common.ZipWriteStr(compatibility_archive_zip, file_name, data)
Tao Bao21803d32017-04-19 10:16:09 -0700649
Tao Baobcd1d162017-08-26 13:10:26 -0700650 # Ensure files are written before we copy into output_zip.
651 compatibility_archive_zip.close()
652
653 # Only add the archive if we have any compatibility info.
654 if compatibility_archive_zip.namelist():
655 common.ZipWrite(output_zip, compatibility_archive.name,
656 arcname="compatibility.zip",
657 compress_type=zipfile.ZIP_STORED)
658
659 # Will only proceed if the target has enabled the Treble support (as well as
660 # having a /vendor partition).
Tao Bao481bab82017-12-21 11:23:09 -0800661 if not HasTrebleEnabled(target_zip, target_info):
Tao Baobcd1d162017-08-26 13:10:26 -0700662 return
663
664 # We don't support OEM thumbprint in Treble world (which calculates
665 # fingerprints in a different way as shown in CalculateFingerprint()).
Tao Bao481bab82017-12-21 11:23:09 -0800666 assert not target_info.oem_props
Tao Baobcd1d162017-08-26 13:10:26 -0700667
668 # Full OTA carries the info for system/vendor both.
Tao Bao481bab82017-12-21 11:23:09 -0800669 if source_info is None:
Tao Baobcd1d162017-08-26 13:10:26 -0700670 AddCompatibilityArchive(True, True)
671 return
672
Tao Bao481bab82017-12-21 11:23:09 -0800673 assert not source_info.oem_props
Tao Baobcd1d162017-08-26 13:10:26 -0700674
Tao Bao481bab82017-12-21 11:23:09 -0800675 source_fp = source_info.fingerprint
676 target_fp = target_info.fingerprint
Tao Baobcd1d162017-08-26 13:10:26 -0700677 system_updated = source_fp != target_fp
678
Tao Bao481bab82017-12-21 11:23:09 -0800679 source_fp_vendor = source_info.GetVendorBuildProp(
680 "ro.vendor.build.fingerprint")
681 target_fp_vendor = target_info.GetVendorBuildProp(
682 "ro.vendor.build.fingerprint")
Tao Baobcd1d162017-08-26 13:10:26 -0700683 vendor_updated = source_fp_vendor != target_fp_vendor
684
685 AddCompatibilityArchive(system_updated, vendor_updated)
Tao Bao21803d32017-04-19 10:16:09 -0700686
687
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700688def WriteFullOTAPackage(input_zip, output_zip):
Tao Bao481bab82017-12-21 11:23:09 -0800689 target_info = BuildInfo(OPTIONS.info_dict, OPTIONS.oem_dicts)
Doug Zongkereef39442009-04-02 12:14:19 -0700690
Tao Bao481bab82017-12-21 11:23:09 -0800691 # We don't know what version it will be installed on top of. We expect the API
692 # just won't change very often. Similarly for fstab, it might have changed in
693 # the target build.
694 target_api_version = target_info["recovery_api_version"]
695 script = edify_generator.EdifyGenerator(target_api_version, target_info)
Michael Runge6e836112014-04-15 17:40:21 -0700696
Tao Bao481bab82017-12-21 11:23:09 -0800697 if target_info.oem_props and not OPTIONS.oem_no_mount:
698 target_info.WriteMountOemScript(script)
699
Tao Baodf3a48b2018-01-10 16:30:43 -0800700 metadata = GetPackageMetadata(target_info)
Doug Zongker2ea21062010-04-28 16:05:21 -0700701
Doug Zongker05d3dea2009-06-22 11:32:31 -0700702 device_specific = common.DeviceSpecificParams(
703 input_zip=input_zip,
Tao Bao481bab82017-12-21 11:23:09 -0800704 input_version=target_api_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700705 output_zip=output_zip,
706 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700707 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700708 metadata=metadata,
709 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700710
Tao Bao457cbf62017-03-06 09:56:01 -0800711 assert HasRecoveryPatch(input_zip)
Doug Zongkerc9253822014-02-04 12:17:58 -0800712
Tao Bao481bab82017-12-21 11:23:09 -0800713 # Assertions (e.g. downgrade check, device properties check).
714 ts = target_info.GetBuildProp("ro.build.date.utc")
715 ts_text = target_info.GetBuildProp("ro.build.date")
Elliott Hughesd8a52f92016-06-20 14:35:47 -0700716 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700717
Tao Bao481bab82017-12-21 11:23:09 -0800718 target_info.WriteDeviceAssertions(script, OPTIONS.oem_no_mount)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700719 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800720
721 # Two-step package strategy (in chronological order, which is *not*
722 # the order in which the generated script has things):
723 #
724 # if stage is not "2/3" or "3/3":
725 # write recovery image to boot partition
726 # set stage to "2/3"
727 # reboot to boot partition and restart recovery
728 # else if stage is "2/3":
729 # write recovery image to recovery partition
730 # set stage to "3/3"
731 # reboot to recovery partition and restart recovery
732 # else:
733 # (stage must be "3/3")
734 # set stage to ""
735 # do normal full package installation:
736 # wipe and install system, boot image, etc.
737 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700738 # complete script normally
739 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800740
741 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
742 OPTIONS.input_tmp, "RECOVERY")
743 if OPTIONS.two_step:
Tao Bao481bab82017-12-21 11:23:09 -0800744 if not target_info.get("multistage_support"):
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800745 assert False, "two-step packages not supported by this build"
Tao Bao481bab82017-12-21 11:23:09 -0800746 fs = target_info["fstab"]["/misc"]
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800747 assert fs.fs_type.upper() == "EMMC", \
748 "two-step packages only supported on devices with EMMC /misc partitions"
749 bcb_dev = {"bcb_dev": fs.device}
750 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
751 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700752if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800753""" % bcb_dev)
Tao Baod42e97e2016-11-30 12:11:57 -0800754
755 # Stage 2/3: Write recovery image to /recovery (currently running /boot).
756 script.Comment("Stage 2/3")
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800757 script.WriteRawImage("/recovery", "recovery.img")
758 script.AppendExtra("""
759set_stage("%(bcb_dev)s", "3/3");
760reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700761else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800762""" % bcb_dev)
763
Tao Baod42e97e2016-11-30 12:11:57 -0800764 # Stage 3/3: Make changes.
765 script.Comment("Stage 3/3")
766
Tao Bao6c55a8a2015-04-08 15:30:27 -0700767 # Dump fingerprints
Tao Bao481bab82017-12-21 11:23:09 -0800768 script.Print("Target: {}".format(target_info.fingerprint))
Tao Bao6c55a8a2015-04-08 15:30:27 -0700769
Doug Zongkere5ff5902012-01-17 10:55:37 -0800770 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700771
Doug Zongker01ce19c2014-02-04 13:48:15 -0800772 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700773
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700774 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800775 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700776 if HasVendorPartition(input_zip):
777 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700778
Doug Zongker4b9596f2014-06-09 14:15:45 -0700779 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800780
Tao Bao457cbf62017-03-06 09:56:01 -0800781 # Full OTA is done as an "incremental" against an empty source image. This
782 # has the effect of writing new data from the package to the entire
783 # partition, but lets us reuse the updater code that writes incrementals to
784 # do it.
Tao Baoc765cca2018-01-31 17:32:40 -0800785 system_tgt = common.GetSparseImage("system", OPTIONS.input_tmp, input_zip)
Tao Bao457cbf62017-03-06 09:56:01 -0800786 system_tgt.ResetFileMap()
787 system_diff = common.BlockDifference("system", system_tgt, src=None)
788 system_diff.WriteScript(script, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700789
Tao Bao7a5bf8a2015-07-21 18:01:20 -0700790 boot_img = common.GetBootableImage(
791 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800792
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700793 if HasVendorPartition(input_zip):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700794 script.ShowProgress(0.1, 0)
795
Tao Baoc765cca2018-01-31 17:32:40 -0800796 vendor_tgt = common.GetSparseImage("vendor", OPTIONS.input_tmp, input_zip)
Tao Bao457cbf62017-03-06 09:56:01 -0800797 vendor_tgt.ResetFileMap()
798 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
799 vendor_diff.WriteScript(script, output_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700800
Tao Bao481bab82017-12-21 11:23:09 -0800801 AddCompatibilityArchiveIfTrebleEnabled(input_zip, output_zip, target_info)
Tao Baobcd1d162017-08-26 13:10:26 -0700802
Tao Bao481bab82017-12-21 11:23:09 -0800803 common.CheckSize(boot_img.data, "boot.img", target_info)
Doug Zongker73ef8252009-07-23 15:12:53 -0700804 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700805
Doug Zongker01ce19c2014-02-04 13:48:15 -0800806 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700807 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700808
Doug Zongker01ce19c2014-02-04 13:48:15 -0800809 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700810 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700811
Doug Zongker1c390a22009-05-14 19:06:36 -0700812 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700813 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700814
Doug Zongker14833602010-02-02 13:12:04 -0800815 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800816
Doug Zongker922206e2014-03-04 13:16:24 -0800817 if OPTIONS.wipe_user_data:
818 script.ShowProgress(0.1, 10)
819 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700820
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800821 if OPTIONS.two_step:
822 script.AppendExtra("""
823set_stage("%(bcb_dev)s", "");
824""" % bcb_dev)
825 script.AppendExtra("else\n")
Tao Baod42e97e2016-11-30 12:11:57 -0800826
827 # Stage 1/3: Nothing to verify for full OTA. Write recovery image to /boot.
828 script.Comment("Stage 1/3")
829 _WriteRecoveryImageToBoot(script, output_zip)
830
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800831 script.AppendExtra("""
832set_stage("%(bcb_dev)s", "2/3");
833reboot_now("%(bcb_dev)s", "");
834endif;
835endif;
836""" % bcb_dev)
Tao Baod8d14be2016-02-04 14:26:02 -0800837
Tao Bao5d182562016-02-23 11:38:39 -0800838 script.SetProgress(1)
839 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -0800840 metadata["ota-required-cache"] = str(script.required_cache)
Doug Zongker2ea21062010-04-28 16:05:21 -0700841 WriteMetadata(metadata, output_zip)
842
Doug Zongkerfc44a512014-08-26 13:10:25 -0700843
Doug Zongker2ea21062010-04-28 16:05:21 -0700844def WriteMetadata(metadata, output_zip):
Tao Bao2dd1c482017-02-03 16:49:39 -0800845 value = "".join(["%s=%s\n" % kv for kv in sorted(metadata.iteritems())])
846 common.ZipWriteStr(output_zip, METADATA_NAME, value,
847 compress_type=zipfile.ZIP_STORED)
Doug Zongkereef39442009-04-02 12:14:19 -0700848
Doug Zongkerfc44a512014-08-26 13:10:25 -0700849
Tao Bao481bab82017-12-21 11:23:09 -0800850def HandleDowngradeMetadata(metadata, target_info, source_info):
Tao Baob31892e2017-02-07 11:21:17 -0800851 # Only incremental OTAs are allowed to reach here.
852 assert OPTIONS.incremental_source is not None
853
Tao Bao481bab82017-12-21 11:23:09 -0800854 post_timestamp = target_info.GetBuildProp("ro.build.date.utc")
855 pre_timestamp = source_info.GetBuildProp("ro.build.date.utc")
Tao Baob31892e2017-02-07 11:21:17 -0800856 is_downgrade = long(post_timestamp) < long(pre_timestamp)
857
858 if OPTIONS.downgrade:
Tao Baob31892e2017-02-07 11:21:17 -0800859 if not is_downgrade:
860 raise RuntimeError("--downgrade specified but no downgrade detected: "
861 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
Tao Bao3e6161a2017-02-28 11:48:48 -0800862 metadata["ota-downgrade"] = "yes"
863 elif OPTIONS.timestamp:
864 if not is_downgrade:
Tao Bao481bab82017-12-21 11:23:09 -0800865 raise RuntimeError("--override_timestamp specified but no timestamp hack "
866 "needed: pre: %s, post: %s" % (pre_timestamp,
867 post_timestamp))
Tao Bao3e6161a2017-02-28 11:48:48 -0800868 metadata["post-timestamp"] = str(long(pre_timestamp) + 1)
Tao Baob31892e2017-02-07 11:21:17 -0800869 else:
870 if is_downgrade:
Tao Bao3e6161a2017-02-28 11:48:48 -0800871 raise RuntimeError("Downgrade detected based on timestamp check: "
Tao Bao481bab82017-12-21 11:23:09 -0800872 "pre: %s, post: %s. Need to specify "
873 "--override_timestamp OR --downgrade to allow "
874 "building the incremental." % (pre_timestamp,
875 post_timestamp))
Tao Baob31892e2017-02-07 11:21:17 -0800876 metadata["post-timestamp"] = post_timestamp
877
878
Tao Baodf3a48b2018-01-10 16:30:43 -0800879def GetPackageMetadata(target_info, source_info=None):
880 """Generates and returns the metadata dict.
881
882 It generates a dict() that contains the info to be written into an OTA
883 package (META-INF/com/android/metadata). It also handles the detection of
884 downgrade / timestamp override / data wipe based on the global options.
885
886 Args:
887 target_info: The BuildInfo instance that holds the target build info.
888 source_info: The BuildInfo instance that holds the source build info, or
889 None if generating full OTA.
890
891 Returns:
892 A dict to be written into package metadata entry.
893 """
894 assert isinstance(target_info, BuildInfo)
895 assert source_info is None or isinstance(source_info, BuildInfo)
896
897 metadata = {
898 'post-build' : target_info.fingerprint,
899 'post-build-incremental' : target_info.GetBuildProp(
900 'ro.build.version.incremental'),
Tao Bao35dc2552018-02-01 13:18:00 -0800901 'post-sdk-level' : target_info.GetBuildProp(
902 'ro.build.version.sdk'),
903 'post-security-patch-level' : target_info.GetBuildProp(
904 'ro.build.version.security_patch'),
Tao Baodf3a48b2018-01-10 16:30:43 -0800905 }
906
907 if target_info.is_ab:
908 metadata['ota-type'] = 'AB'
909 metadata['ota-required-cache'] = '0'
910 else:
911 metadata['ota-type'] = 'BLOCK'
912
913 if OPTIONS.wipe_user_data:
914 metadata['ota-wipe'] = 'yes'
915
916 is_incremental = source_info is not None
917 if is_incremental:
918 metadata['pre-build'] = source_info.fingerprint
919 metadata['pre-build-incremental'] = source_info.GetBuildProp(
920 'ro.build.version.incremental')
921 metadata['pre-device'] = source_info.device
922 else:
923 metadata['pre-device'] = target_info.device
924
925 # Detect downgrades, or fill in the post-timestamp.
926 if is_incremental:
927 HandleDowngradeMetadata(metadata, target_info, source_info)
928 else:
929 metadata['post-timestamp'] = target_info.GetBuildProp('ro.build.date.utc')
930
931 return metadata
932
933
Geremy Condra36bd3652014-02-06 19:45:10 -0800934def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
Tao Bao481bab82017-12-21 11:23:09 -0800935 target_info = BuildInfo(OPTIONS.target_info_dict, OPTIONS.oem_dicts)
936 source_info = BuildInfo(OPTIONS.source_info_dict, OPTIONS.oem_dicts)
Geremy Condra36bd3652014-02-06 19:45:10 -0800937
Tao Bao481bab82017-12-21 11:23:09 -0800938 target_api_version = target_info["recovery_api_version"]
939 source_api_version = source_info["recovery_api_version"]
940 if source_api_version == 0:
Tao Bao3e30d972016-03-15 13:20:19 -0700941 print("WARNING: generating edify script for a source that "
942 "can't install it.")
Geremy Condra36bd3652014-02-06 19:45:10 -0800943
Tao Bao481bab82017-12-21 11:23:09 -0800944 script = edify_generator.EdifyGenerator(
945 source_api_version, target_info, fstab=source_info["fstab"])
946
947 if target_info.oem_props or source_info.oem_props:
948 if not OPTIONS.oem_no_mount:
949 source_info.WriteMountOemScript(script)
Tao Bao3806c232015-07-05 21:08:33 -0700950
Tao Baodf3a48b2018-01-10 16:30:43 -0800951 metadata = GetPackageMetadata(target_info, source_info)
Tao Bao5d182562016-02-23 11:38:39 -0800952
Geremy Condra36bd3652014-02-06 19:45:10 -0800953 device_specific = common.DeviceSpecificParams(
954 source_zip=source_zip,
Tao Bao481bab82017-12-21 11:23:09 -0800955 source_version=source_api_version,
Geremy Condra36bd3652014-02-06 19:45:10 -0800956 target_zip=target_zip,
Tao Bao481bab82017-12-21 11:23:09 -0800957 target_version=target_api_version,
Geremy Condra36bd3652014-02-06 19:45:10 -0800958 output_zip=output_zip,
959 script=script,
960 metadata=metadata,
Tao Bao481bab82017-12-21 11:23:09 -0800961 info_dict=source_info)
Geremy Condra36bd3652014-02-06 19:45:10 -0800962
Geremy Condra36bd3652014-02-06 19:45:10 -0800963 source_boot = common.GetBootableImage(
Tao Bao481bab82017-12-21 11:23:09 -0800964 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT", source_info)
Geremy Condra36bd3652014-02-06 19:45:10 -0800965 target_boot = common.GetBootableImage(
Tao Bao481bab82017-12-21 11:23:09 -0800966 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT", target_info)
Geremy Condra36bd3652014-02-06 19:45:10 -0800967 updating_boot = (not OPTIONS.two_step and
968 (source_boot.data != target_boot.data))
969
Geremy Condra36bd3652014-02-06 19:45:10 -0800970 target_recovery = common.GetBootableImage(
971 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800972
Tao Baoc765cca2018-01-31 17:32:40 -0800973 system_src = common.GetSparseImage("system", OPTIONS.source_tmp, source_zip)
974 system_tgt = common.GetSparseImage("system", OPTIONS.target_tmp, target_zip)
Tao Baodd2a5892015-03-12 12:32:37 -0700975
Tao Bao0582cb62017-12-21 11:47:01 -0800976 blockimgdiff_version = max(
Tao Bao481bab82017-12-21 11:23:09 -0800977 int(i) for i in target_info.get("blockimgdiff_versions", "1").split(","))
Tao Bao0582cb62017-12-21 11:47:01 -0800978 assert blockimgdiff_version >= 3
Tao Baodd2a5892015-03-12 12:32:37 -0700979
Tao Baof8acad12016-07-07 09:09:58 -0700980 # Check the first block of the source system partition for remount R/W only
981 # if the filesystem is ext4.
Tao Bao481bab82017-12-21 11:23:09 -0800982 system_src_partition = source_info["fstab"]["/system"]
Tao Baof8acad12016-07-07 09:09:58 -0700983 check_first_block = system_src_partition.fs_type == "ext4"
Tao Bao293fd132016-06-11 12:19:23 -0700984 # Disable using imgdiff for squashfs. 'imgdiff -z' expects input files to be
985 # in zip formats. However with squashfs, a) all files are compressed in LZ4;
986 # b) the blocks listed in block map may not contain all the bytes for a given
987 # file (because they're rounded to be 4K-aligned).
Tao Bao481bab82017-12-21 11:23:09 -0800988 system_tgt_partition = target_info["fstab"]["/system"]
Tao Baof8acad12016-07-07 09:09:58 -0700989 disable_imgdiff = (system_src_partition.fs_type == "squashfs" or
990 system_tgt_partition.fs_type == "squashfs")
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700991 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tianjie Xufc3422a2015-12-15 11:53:59 -0800992 check_first_block,
Tao Bao293fd132016-06-11 12:19:23 -0700993 version=blockimgdiff_version,
994 disable_imgdiff=disable_imgdiff)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700995
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700996 if HasVendorPartition(target_zip):
997 if not HasVendorPartition(source_zip):
998 raise RuntimeError("can't generate incremental that adds /vendor")
Tao Baoc765cca2018-01-31 17:32:40 -0800999 vendor_src = common.GetSparseImage("vendor", OPTIONS.source_tmp, source_zip)
1000 vendor_tgt = common.GetSparseImage("vendor", OPTIONS.target_tmp, target_zip)
Tianjie Xufc3422a2015-12-15 11:53:59 -08001001
1002 # Check first block of vendor partition for remount R/W only if
1003 # disk type is ext4
Tao Bao481bab82017-12-21 11:23:09 -08001004 vendor_partition = source_info["fstab"]["/vendor"]
Tao Baod8d14be2016-02-04 14:26:02 -08001005 check_first_block = vendor_partition.fs_type == "ext4"
Tao Bao293fd132016-06-11 12:19:23 -07001006 disable_imgdiff = vendor_partition.fs_type == "squashfs"
Doug Zongkerb34fcce2014-09-11 09:34:56 -07001007 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tianjie Xufc3422a2015-12-15 11:53:59 -08001008 check_first_block,
Tao Bao293fd132016-06-11 12:19:23 -07001009 version=blockimgdiff_version,
1010 disable_imgdiff=disable_imgdiff)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001011 else:
1012 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -08001013
Tao Baobcd1d162017-08-26 13:10:26 -07001014 AddCompatibilityArchiveIfTrebleEnabled(
Tao Bao481bab82017-12-21 11:23:09 -08001015 target_zip, output_zip, target_info, source_info)
Tao Baobcd1d162017-08-26 13:10:26 -07001016
Tao Bao481bab82017-12-21 11:23:09 -08001017 # Assertions (e.g. device properties check).
1018 target_info.WriteDeviceAssertions(script, OPTIONS.oem_no_mount)
Geremy Condra36bd3652014-02-06 19:45:10 -08001019 device_specific.IncrementalOTA_Assertions()
1020
1021 # Two-step incremental package strategy (in chronological order,
1022 # which is *not* the order in which the generated script has
1023 # things):
1024 #
1025 # if stage is not "2/3" or "3/3":
1026 # do verification on current system
1027 # write recovery image to boot partition
1028 # set stage to "2/3"
1029 # reboot to boot partition and restart recovery
1030 # else if stage is "2/3":
1031 # write recovery image to recovery partition
1032 # set stage to "3/3"
1033 # reboot to recovery partition and restart recovery
1034 # else:
1035 # (stage must be "3/3")
1036 # perform update:
1037 # patch system files, etc.
1038 # force full install of new boot image
1039 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001040 # complete script normally
1041 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -08001042
1043 if OPTIONS.two_step:
Tao Bao481bab82017-12-21 11:23:09 -08001044 if not source_info.get("multistage_support"):
Geremy Condra36bd3652014-02-06 19:45:10 -08001045 assert False, "two-step packages not supported by this build"
Tao Bao24604cc2018-02-01 16:25:44 -08001046 fs = source_info["fstab"]["/misc"]
Geremy Condra36bd3652014-02-06 19:45:10 -08001047 assert fs.fs_type.upper() == "EMMC", \
1048 "two-step packages only supported on devices with EMMC /misc partitions"
Tao Bao481bab82017-12-21 11:23:09 -08001049 bcb_dev = {"bcb_dev" : fs.device}
Geremy Condra36bd3652014-02-06 19:45:10 -08001050 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1051 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001052if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -08001053""" % bcb_dev)
Tao Baod42e97e2016-11-30 12:11:57 -08001054
1055 # Stage 2/3: Write recovery image to /recovery (currently running /boot).
1056 script.Comment("Stage 2/3")
Dan Albert8b72aef2015-03-23 19:13:21 -07001057 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -08001058 script.WriteRawImage("/recovery", "recovery.img")
1059 script.AppendExtra("""
1060set_stage("%(bcb_dev)s", "3/3");
1061reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001062else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -08001063""" % bcb_dev)
1064
Tao Baod42e97e2016-11-30 12:11:57 -08001065 # Stage 1/3: (a) Verify the current system.
1066 script.Comment("Stage 1/3")
1067
Tao Bao6c55a8a2015-04-08 15:30:27 -07001068 # Dump fingerprints
Tao Bao481bab82017-12-21 11:23:09 -08001069 script.Print("Source: {}".format(source_info.fingerprint))
1070 script.Print("Target: {}".format(target_info.fingerprint))
Tao Bao6c55a8a2015-04-08 15:30:27 -07001071
Geremy Condra36bd3652014-02-06 19:45:10 -08001072 script.Print("Verifying current system...")
1073
1074 device_specific.IncrementalOTA_VerifyBegin()
1075
Tao Bao481bab82017-12-21 11:23:09 -08001076 WriteFingerprintAssertion(script, target_info, source_info)
Geremy Condra36bd3652014-02-06 19:45:10 -08001077
Tao Baod8d14be2016-02-04 14:26:02 -08001078 # Check the required cache size (i.e. stashed blocks).
1079 size = []
1080 if system_diff:
1081 size.append(system_diff.required_cache)
1082 if vendor_diff:
1083 size.append(vendor_diff.required_cache)
1084
Geremy Condra36bd3652014-02-06 19:45:10 -08001085 if updating_boot:
Tao Bao481bab82017-12-21 11:23:09 -08001086 boot_type, boot_device = common.GetTypeAndDevice("/boot", source_info)
Geremy Condra36bd3652014-02-06 19:45:10 -08001087 d = common.Difference(target_boot, source_boot)
1088 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -07001089 if d is None:
1090 include_full_boot = True
1091 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1092 else:
1093 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -08001094
Tao Bao89fbb0f2017-01-10 10:47:58 -08001095 print("boot target: %d source: %d diff: %d" % (
1096 target_boot.size, source_boot.size, len(d)))
Geremy Condra36bd3652014-02-06 19:45:10 -08001097
Doug Zongkerf8340082014-08-05 10:39:37 -07001098 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -08001099
Doug Zongkerf8340082014-08-05 10:39:37 -07001100 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1101 (boot_type, boot_device,
1102 source_boot.size, source_boot.sha1,
1103 target_boot.size, target_boot.sha1))
Tao Baod8d14be2016-02-04 14:26:02 -08001104 size.append(target_boot.size)
1105
1106 if size:
1107 script.CacheFreeSpaceCheck(max(size))
Geremy Condra36bd3652014-02-06 19:45:10 -08001108
1109 device_specific.IncrementalOTA_VerifyEnd()
1110
1111 if OPTIONS.two_step:
Tao Baod42e97e2016-11-30 12:11:57 -08001112 # Stage 1/3: (b) Write recovery image to /boot.
1113 _WriteRecoveryImageToBoot(script, output_zip)
1114
Geremy Condra36bd3652014-02-06 19:45:10 -08001115 script.AppendExtra("""
1116set_stage("%(bcb_dev)s", "2/3");
1117reboot_now("%(bcb_dev)s", "");
1118else
1119""" % bcb_dev)
1120
Tao Baod42e97e2016-11-30 12:11:57 -08001121 # Stage 3/3: Make changes.
1122 script.Comment("Stage 3/3")
1123
Jesse Zhao75bcea02015-01-06 10:59:53 -08001124 # Verify the existing partitions.
Tao Baod522bdc2016-04-12 15:53:16 -07001125 system_diff.WriteVerifyScript(script, touched_blocks_only=True)
Jesse Zhao75bcea02015-01-06 10:59:53 -08001126 if vendor_diff:
Tao Baod522bdc2016-04-12 15:53:16 -07001127 vendor_diff.WriteVerifyScript(script, touched_blocks_only=True)
Jesse Zhao75bcea02015-01-06 10:59:53 -08001128
Geremy Condra36bd3652014-02-06 19:45:10 -08001129 script.Comment("---- start making changes here ----")
1130
1131 device_specific.IncrementalOTA_InstallBegin()
1132
Doug Zongkerab7ca1d2014-08-26 10:40:28 -07001133 system_diff.WriteScript(script, output_zip,
1134 progress=0.8 if vendor_diff else 0.9)
Tao Bao68658c02015-06-01 13:40:49 -07001135
Doug Zongkerfc44a512014-08-26 13:10:25 -07001136 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -07001137 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -08001138
1139 if OPTIONS.two_step:
1140 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1141 script.WriteRawImage("/boot", "boot.img")
Tao Bao89fbb0f2017-01-10 10:47:58 -08001142 print("writing full boot image (forced by two-step mode)")
Geremy Condra36bd3652014-02-06 19:45:10 -08001143
1144 if not OPTIONS.two_step:
1145 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -07001146 if include_full_boot:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001147 print("boot image changed; including full.")
Doug Zongkerf8340082014-08-05 10:39:37 -07001148 script.Print("Installing boot image...")
1149 script.WriteRawImage("/boot", "boot.img")
1150 else:
1151 # Produce the boot image by applying a patch to the current
1152 # contents of the boot partition, and write it back to the
1153 # partition.
Tao Bao89fbb0f2017-01-10 10:47:58 -08001154 print("boot image changed; including patch.")
Doug Zongkerf8340082014-08-05 10:39:37 -07001155 script.Print("Patching boot image...")
1156 script.ShowProgress(0.1, 10)
1157 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1158 % (boot_type, boot_device,
1159 source_boot.size, source_boot.sha1,
1160 target_boot.size, target_boot.sha1),
1161 "-",
1162 target_boot.size, target_boot.sha1,
1163 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -08001164 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001165 print("boot image unchanged; skipping.")
Geremy Condra36bd3652014-02-06 19:45:10 -08001166
1167 # Do device-specific installation (eg, write radio image).
1168 device_specific.IncrementalOTA_InstallEnd()
1169
1170 if OPTIONS.extra_script is not None:
1171 script.AppendExtra(OPTIONS.extra_script)
1172
Doug Zongker922206e2014-03-04 13:16:24 -08001173 if OPTIONS.wipe_user_data:
1174 script.Print("Erasing user data...")
1175 script.FormatPartition("/data")
1176
Geremy Condra36bd3652014-02-06 19:45:10 -08001177 if OPTIONS.two_step:
1178 script.AppendExtra("""
1179set_stage("%(bcb_dev)s", "");
1180endif;
1181endif;
1182""" % bcb_dev)
1183
1184 script.SetProgress(1)
Tao Bao4996cf02016-03-08 17:53:39 -08001185 # For downgrade OTAs, we prefer to use the update-binary in the source
1186 # build that is actually newer than the one in the target build.
1187 if OPTIONS.downgrade:
1188 script.AddToZip(source_zip, output_zip, input_path=OPTIONS.updater_binary)
1189 else:
1190 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -08001191 metadata["ota-required-cache"] = str(script.required_cache)
Geremy Condra36bd3652014-02-06 19:45:10 -08001192 WriteMetadata(metadata, output_zip)
1193
Doug Zongker32b527d2014-03-04 10:03:02 -08001194
Tao Baof7140c02018-01-30 17:09:24 -08001195def GetTargetFilesZipForSecondaryImages(input_file):
1196 """Returns a target-files.zip file for generating secondary payload.
1197
1198 Although the original target-files.zip already contains secondary slot
1199 images (i.e. IMAGES/system_other.img), we need to rename the files to the
1200 ones without _other suffix. Note that we cannot instead modify the names in
1201 META/ab_partitions.txt, because there are no matching partitions on device.
1202
1203 For the partitions that don't have secondary images, the ones for primary
1204 slot will be used. This is to ensure that we always have valid boot, vbmeta,
1205 bootloader images in the inactive slot.
1206
1207 Args:
1208 input_file: The input target-files.zip file.
1209
1210 Returns:
1211 The filename of the target-files.zip for generating secondary payload.
1212 """
1213 target_file = common.MakeTempFile(prefix="targetfiles-", suffix=".zip")
1214 target_zip = zipfile.ZipFile(target_file, 'w', allowZip64=True)
1215
1216 input_tmp, input_zip = common.UnzipTemp(input_file, UNZIP_PATTERN)
1217 for info in input_zip.infolist():
1218 unzipped_file = os.path.join(input_tmp, *info.filename.split('/'))
1219 if info.filename == 'IMAGES/system_other.img':
1220 common.ZipWrite(target_zip, unzipped_file, arcname='IMAGES/system.img')
1221
1222 # Primary images and friends need to be skipped explicitly.
1223 elif info.filename in ('IMAGES/system.img',
1224 'IMAGES/system.map'):
1225 pass
1226
1227 elif info.filename.startswith(('META/', 'IMAGES/')):
1228 common.ZipWrite(target_zip, unzipped_file, arcname=info.filename)
1229
1230 common.ZipClose(input_zip)
1231 common.ZipClose(target_zip)
1232
1233 return target_file
1234
1235
Tao Baoc098e9e2016-01-07 13:03:56 -08001236def WriteABOTAPackageWithBrilloScript(target_file, output_file,
1237 source_file=None):
1238 """Generate an Android OTA package that has A/B update payload."""
1239
Tao Bao2dd1c482017-02-03 16:49:39 -08001240 def ComputeStreamingMetadata(zip_file, reserve_space=False,
1241 expected_length=None):
1242 """Compute the streaming metadata for a given zip.
1243
1244 When 'reserve_space' is True, we reserve extra space for the offset and
1245 length of the metadata entry itself, although we don't know the final
1246 values until the package gets signed. This function will be called again
1247 after signing. We then write the actual values and pad the string to the
1248 length we set earlier. Note that we can't use the actual length of the
1249 metadata entry in the second run. Otherwise the offsets for other entries
1250 will be changing again.
1251 """
Tao Baoc96316c2017-01-24 22:10:49 -08001252
1253 def ComputeEntryOffsetSize(name):
1254 """Compute the zip entry offset and size."""
1255 info = zip_file.getinfo(name)
1256 offset = info.header_offset + len(info.FileHeader())
1257 size = info.file_size
Tao Bao2dd1c482017-02-03 16:49:39 -08001258 return '%s:%d:%d' % (os.path.basename(name), offset, size)
Tao Baoc96316c2017-01-24 22:10:49 -08001259
1260 # payload.bin and payload_properties.txt must exist.
1261 offsets = [ComputeEntryOffsetSize('payload.bin'),
1262 ComputeEntryOffsetSize('payload_properties.txt')]
1263
1264 # care_map.txt is available only if dm-verity is enabled.
1265 if 'care_map.txt' in zip_file.namelist():
1266 offsets.append(ComputeEntryOffsetSize('care_map.txt'))
Tao Bao2dd1c482017-02-03 16:49:39 -08001267
Tao Bao21803d32017-04-19 10:16:09 -07001268 if 'compatibility.zip' in zip_file.namelist():
1269 offsets.append(ComputeEntryOffsetSize('compatibility.zip'))
1270
Tao Bao2dd1c482017-02-03 16:49:39 -08001271 # 'META-INF/com/android/metadata' is required. We don't know its actual
1272 # offset and length (as well as the values for other entries). So we
1273 # reserve 10-byte as a placeholder, which is to cover the space for metadata
1274 # entry ('xx:xxx', since it's ZIP_STORED which should appear at the
1275 # beginning of the zip), as well as the possible value changes in other
1276 # entries.
1277 if reserve_space:
1278 offsets.append('metadata:' + ' ' * 10)
1279 else:
1280 offsets.append(ComputeEntryOffsetSize(METADATA_NAME))
1281
1282 value = ','.join(offsets)
1283 if expected_length is not None:
1284 assert len(value) <= expected_length, \
1285 'Insufficient reserved space: reserved=%d, actual=%d' % (
1286 expected_length, len(value))
1287 value += ' ' * (expected_length - len(value))
1288 return value
Tao Baoc96316c2017-01-24 22:10:49 -08001289
Tao Baodea0f8b2016-06-20 17:55:06 -07001290 # Stage the output zip package for package signing.
Tao Baoc098e9e2016-01-07 13:03:56 -08001291 temp_zip_file = tempfile.NamedTemporaryFile()
1292 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1293 compression=zipfile.ZIP_DEFLATED)
1294
Tao Bao481bab82017-12-21 11:23:09 -08001295 if source_file is not None:
1296 target_info = BuildInfo(OPTIONS.target_info_dict, OPTIONS.oem_dicts)
1297 source_info = BuildInfo(OPTIONS.source_info_dict, OPTIONS.oem_dicts)
1298 else:
1299 target_info = BuildInfo(OPTIONS.info_dict, OPTIONS.oem_dicts)
1300 source_info = None
Tao Baoc098e9e2016-01-07 13:03:56 -08001301
Tao Bao481bab82017-12-21 11:23:09 -08001302 # Metadata to comply with Android OTA package format.
Tao Baodf3a48b2018-01-10 16:30:43 -08001303 metadata = GetPackageMetadata(target_info, source_info)
Tao Baob31892e2017-02-07 11:21:17 -08001304
Tao Baoc7b403a2018-01-30 18:19:04 -08001305 # Generate payload.
1306 payload = Payload()
1307 payload.Generate(target_file, source_file)
Tao Baoc098e9e2016-01-07 13:03:56 -08001308
Tao Baoc7b403a2018-01-30 18:19:04 -08001309 # Sign the payload.
Tao Baof7140c02018-01-30 17:09:24 -08001310 payload_signer = PayloadSigner()
1311 payload.Sign(payload_signer)
Tao Baoc098e9e2016-01-07 13:03:56 -08001312
Tao Baoc7b403a2018-01-30 18:19:04 -08001313 # Write the payload into output zip.
1314 payload.WriteToZip(output_zip)
Tao Baoc098e9e2016-01-07 13:03:56 -08001315
Tao Baof7140c02018-01-30 17:09:24 -08001316 # Generate and include the secondary payload that installs secondary images
1317 # (e.g. system_other.img).
1318 if OPTIONS.include_secondary:
1319 # We always include a full payload for the secondary slot, even when
1320 # building an incremental OTA. See the comments for "--include_secondary".
1321 secondary_target_file = GetTargetFilesZipForSecondaryImages(target_file)
1322 secondary_payload = Payload()
1323 secondary_payload.Generate(secondary_target_file)
1324 secondary_payload.Sign(payload_signer)
1325 secondary_payload.WriteToZip(output_zip, secondary=True)
1326
Tianjie Xucfa86222016-03-07 16:31:19 -08001327 # If dm-verity is supported for the device, copy contents of care_map
1328 # into A/B OTA package.
Tao Bao21803d32017-04-19 10:16:09 -07001329 target_zip = zipfile.ZipFile(target_file, "r")
Tao Bao481bab82017-12-21 11:23:09 -08001330 if (target_info.get("verity") == "true" or
1331 target_info.get("avb_enable") == "true"):
Tianjie Xucfa86222016-03-07 16:31:19 -08001332 care_map_path = "META/care_map.txt"
1333 namelist = target_zip.namelist()
1334 if care_map_path in namelist:
1335 care_map_data = target_zip.read(care_map_path)
Tao Baoc7b403a2018-01-30 18:19:04 -08001336 # In order to support streaming, care_map.txt needs to be packed as
1337 # ZIP_STORED.
Tao Baoc96316c2017-01-24 22:10:49 -08001338 common.ZipWriteStr(output_zip, "care_map.txt", care_map_data,
Tao Bao481bab82017-12-21 11:23:09 -08001339 compress_type=zipfile.ZIP_STORED)
Tianjie Xucfa86222016-03-07 16:31:19 -08001340 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001341 print("Warning: cannot find care map file in target_file package")
Tao Bao21803d32017-04-19 10:16:09 -07001342
Tao Bao481bab82017-12-21 11:23:09 -08001343 # source_info must be None for full OTAs.
Tao Baobcd1d162017-08-26 13:10:26 -07001344 if source_file is None:
Tao Bao481bab82017-12-21 11:23:09 -08001345 assert source_info is None
Tao Bao21803d32017-04-19 10:16:09 -07001346
Tao Baobcd1d162017-08-26 13:10:26 -07001347 AddCompatibilityArchiveIfTrebleEnabled(
Tao Bao481bab82017-12-21 11:23:09 -08001348 target_zip, output_zip, target_info, source_info)
Tao Bao21803d32017-04-19 10:16:09 -07001349
Tao Bao21803d32017-04-19 10:16:09 -07001350 common.ZipClose(target_zip)
Tianjie Xucfa86222016-03-07 16:31:19 -08001351
Tao Bao2dd1c482017-02-03 16:49:39 -08001352 # Write the current metadata entry with placeholders.
Tao Baobfdcb122017-01-31 15:06:05 -08001353 metadata['ota-streaming-property-files'] = ComputeStreamingMetadata(
Tao Bao2dd1c482017-02-03 16:49:39 -08001354 output_zip, reserve_space=True)
Tao Baoc96316c2017-01-24 22:10:49 -08001355 WriteMetadata(metadata, output_zip)
1356 common.ZipClose(output_zip)
1357
Tao Bao2dd1c482017-02-03 16:49:39 -08001358 # SignOutput(), which in turn calls signapk.jar, will possibly reorder the
Tao Bao89d7ab22017-12-14 17:05:33 -08001359 # ZIP entries, as well as padding the entry headers. We do a preliminary
Tao Bao2dd1c482017-02-03 16:49:39 -08001360 # signing (with an incomplete metadata entry) to allow that to happen. Then
Tao Bao89d7ab22017-12-14 17:05:33 -08001361 # compute the ZIP entry offsets, write back the final metadata and do the
Tao Bao2dd1c482017-02-03 16:49:39 -08001362 # final signing.
Tao Bao89d7ab22017-12-14 17:05:33 -08001363 prelim_signing = common.MakeTempFile(suffix='.zip')
1364 SignOutput(temp_zip_file.name, prelim_signing)
Tao Bao2dd1c482017-02-03 16:49:39 -08001365 common.ZipClose(temp_zip_file)
Tao Baoc96316c2017-01-24 22:10:49 -08001366
Tao Bao2dd1c482017-02-03 16:49:39 -08001367 # Open the signed zip. Compute the final metadata that's needed for streaming.
Tao Bao89d7ab22017-12-14 17:05:33 -08001368 prelim_signing_zip = zipfile.ZipFile(prelim_signing, 'r')
Tao Bao2dd1c482017-02-03 16:49:39 -08001369 expected_length = len(metadata['ota-streaming-property-files'])
1370 metadata['ota-streaming-property-files'] = ComputeStreamingMetadata(
Tao Bao89d7ab22017-12-14 17:05:33 -08001371 prelim_signing_zip, reserve_space=False, expected_length=expected_length)
1372 common.ZipClose(prelim_signing_zip)
Tao Bao2dd1c482017-02-03 16:49:39 -08001373
Tao Bao89d7ab22017-12-14 17:05:33 -08001374 # Replace the METADATA entry.
1375 common.ZipDelete(prelim_signing, METADATA_NAME)
1376 output_zip = zipfile.ZipFile(prelim_signing, 'a',
Tao Bao2dd1c482017-02-03 16:49:39 -08001377 compression=zipfile.ZIP_DEFLATED)
Tao Bao2dd1c482017-02-03 16:49:39 -08001378 WriteMetadata(metadata, output_zip)
Tao Bao2dd1c482017-02-03 16:49:39 -08001379 common.ZipClose(output_zip)
1380
1381 # Re-sign the package after updating the metadata entry.
Tao Bao89d7ab22017-12-14 17:05:33 -08001382 SignOutput(prelim_signing, output_file)
Tao Bao2dd1c482017-02-03 16:49:39 -08001383
1384 # Reopen the final signed zip to double check the streaming metadata.
Tao Bao89d7ab22017-12-14 17:05:33 -08001385 output_zip = zipfile.ZipFile(output_file, 'r')
Tao Bao2dd1c482017-02-03 16:49:39 -08001386 actual = metadata['ota-streaming-property-files'].strip()
1387 expected = ComputeStreamingMetadata(output_zip)
1388 assert actual == expected, \
1389 "Mismatching streaming metadata: %s vs %s." % (actual, expected)
Tao Baoc96316c2017-01-24 22:10:49 -08001390 common.ZipClose(output_zip)
1391
Tao Baoc098e9e2016-01-07 13:03:56 -08001392
Doug Zongkereef39442009-04-02 12:14:19 -07001393def main(argv):
1394
1395 def option_handler(o, a):
Tao Bao4b76a0e2017-10-31 12:13:33 -07001396 if o in ("-k", "--package_key"):
Doug Zongkereef39442009-04-02 12:14:19 -07001397 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001398 elif o in ("-i", "--incremental_from"):
1399 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001400 elif o == "--full_radio":
1401 OPTIONS.full_radio = True
leozwangaa6c1a12015-08-14 10:57:58 -07001402 elif o == "--full_bootloader":
1403 OPTIONS.full_bootloader = True
Tao Bao337633f2017-12-06 15:20:19 -08001404 elif o == "--wipe_user_data":
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001405 OPTIONS.wipe_user_data = True
Tao Bao5d182562016-02-23 11:38:39 -08001406 elif o == "--downgrade":
1407 OPTIONS.downgrade = True
1408 OPTIONS.wipe_user_data = True
Tao Bao3e6161a2017-02-28 11:48:48 -08001409 elif o == "--override_timestamp":
1410 OPTIONS.timestamp = True
Michael Runge6e836112014-04-15 17:40:21 -07001411 elif o in ("-o", "--oem_settings"):
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -08001412 OPTIONS.oem_source = a.split(',')
Tao Bao8608cde2016-02-25 19:49:55 -08001413 elif o == "--oem_no_mount":
1414 OPTIONS.oem_no_mount = True
Doug Zongker1c390a22009-05-14 19:06:36 -07001415 elif o in ("-e", "--extra_script"):
1416 OPTIONS.extra_script = a
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001417 elif o in ("-t", "--worker_threads"):
1418 if a.isdigit():
1419 OPTIONS.worker_threads = int(a)
1420 else:
1421 raise ValueError("Cannot parse value %r for option %r - only "
1422 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001423 elif o in ("-2", "--two_step"):
1424 OPTIONS.two_step = True
Tao Baof7140c02018-01-30 17:09:24 -08001425 elif o == "--include_secondary":
1426 OPTIONS.include_secondary = True
Doug Zongker26e66192014-02-20 13:22:07 -08001427 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001428 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001429 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001430 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001431 elif o == "--block":
1432 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001433 elif o in ("-b", "--binary"):
1434 OPTIONS.updater_binary = a
Tao Bao8dcf7382015-05-21 14:09:49 -07001435 elif o == "--stash_threshold":
1436 try:
1437 OPTIONS.stash_threshold = float(a)
1438 except ValueError:
1439 raise ValueError("Cannot parse value %r for option %r - expecting "
1440 "a float" % (a, o))
Tao Baod62c6032015-11-30 09:40:20 -08001441 elif o == "--log_diff":
1442 OPTIONS.log_diff = a
Tao Baodea0f8b2016-06-20 17:55:06 -07001443 elif o == "--payload_signer":
1444 OPTIONS.payload_signer = a
Baligh Uddin2abbbd02016-06-22 12:14:16 -07001445 elif o == "--payload_signer_args":
1446 OPTIONS.payload_signer_args = shlex.split(a)
Dan Willemsencea5cd22017-03-21 14:44:27 -07001447 elif o == "--extracted_input_target_files":
1448 OPTIONS.extracted_input = a
Doug Zongkereef39442009-04-02 12:14:19 -07001449 else:
1450 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001451 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001452
1453 args = common.ParseOptions(argv, __doc__,
Tao Bao337633f2017-12-06 15:20:19 -08001454 extra_opts="b:k:i:d:e:t:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001455 extra_long_opts=[
Dan Albert8b72aef2015-03-23 19:13:21 -07001456 "package_key=",
1457 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001458 "full_radio",
leozwangaa6c1a12015-08-14 10:57:58 -07001459 "full_bootloader",
Dan Albert8b72aef2015-03-23 19:13:21 -07001460 "wipe_user_data",
Tao Bao5d182562016-02-23 11:38:39 -08001461 "downgrade",
Tao Bao3e6161a2017-02-28 11:48:48 -08001462 "override_timestamp",
Dan Albert8b72aef2015-03-23 19:13:21 -07001463 "extra_script=",
1464 "worker_threads=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001465 "two_step",
Tao Baof7140c02018-01-30 17:09:24 -08001466 "include_secondary",
Dan Albert8b72aef2015-03-23 19:13:21 -07001467 "no_signing",
1468 "block",
1469 "binary=",
1470 "oem_settings=",
Tao Bao8608cde2016-02-25 19:49:55 -08001471 "oem_no_mount",
Dan Albert8b72aef2015-03-23 19:13:21 -07001472 "verify",
Tao Bao8dcf7382015-05-21 14:09:49 -07001473 "stash_threshold=",
Tao Baod62c6032015-11-30 09:40:20 -08001474 "log_diff=",
Tao Baodea0f8b2016-06-20 17:55:06 -07001475 "payload_signer=",
Baligh Uddin2abbbd02016-06-22 12:14:16 -07001476 "payload_signer_args=",
Dan Willemsencea5cd22017-03-21 14:44:27 -07001477 "extracted_input_target_files=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001478 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001479
1480 if len(args) != 2:
1481 common.Usage(__doc__)
1482 sys.exit(1)
1483
Tao Bao5d182562016-02-23 11:38:39 -08001484 if OPTIONS.downgrade:
1485 # Sanity check to enforce a data wipe.
1486 if not OPTIONS.wipe_user_data:
1487 raise ValueError("Cannot downgrade without a data wipe")
1488
1489 # We should only allow downgrading incrementals (as opposed to full).
1490 # Otherwise the device may go back from arbitrary build with this full
1491 # OTA package.
1492 if OPTIONS.incremental_source is None:
Elliott Hughesd8a52f92016-06-20 14:35:47 -07001493 raise ValueError("Cannot generate downgradable full OTAs")
Tao Bao5d182562016-02-23 11:38:39 -08001494
Tao Bao3e6161a2017-02-28 11:48:48 -08001495 assert not (OPTIONS.downgrade and OPTIONS.timestamp), \
1496 "Cannot have --downgrade AND --override_timestamp both"
1497
Tao Bao2db13852018-01-08 22:28:57 -08001498 # Load the build info dicts from the zip directly or the extracted input
1499 # directory. We don't need to unzip the entire target-files zips, because they
1500 # won't be needed for A/B OTAs (brillo_update_payload does that on its own).
1501 # When loading the info dicts, we don't need to provide the second parameter
1502 # to common.LoadInfoDict(). Specifying the second parameter allows replacing
1503 # some properties with their actual paths, such as 'selinux_fc',
1504 # 'ramdisk_dir', which won't be used during OTA generation.
Dan Willemsencea5cd22017-03-21 14:44:27 -07001505 if OPTIONS.extracted_input is not None:
Tao Bao2db13852018-01-08 22:28:57 -08001506 OPTIONS.info_dict = common.LoadInfoDict(OPTIONS.extracted_input)
Dan Willemsencea5cd22017-03-21 14:44:27 -07001507 else:
Tao Bao2db13852018-01-08 22:28:57 -08001508 with zipfile.ZipFile(args[0], 'r') as input_zip:
1509 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Tao Baoc098e9e2016-01-07 13:03:56 -08001510
Tao Bao2db13852018-01-08 22:28:57 -08001511 if OPTIONS.verbose:
1512 print("--- target info ---")
1513 common.DumpInfoDict(OPTIONS.info_dict)
1514
1515 # Load the source build dict if applicable.
1516 if OPTIONS.incremental_source is not None:
1517 OPTIONS.target_info_dict = OPTIONS.info_dict
1518 with zipfile.ZipFile(OPTIONS.incremental_source, 'r') as source_zip:
1519 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1520
1521 if OPTIONS.verbose:
1522 print("--- source info ---")
1523 common.DumpInfoDict(OPTIONS.source_info_dict)
1524
1525 # Load OEM dicts if provided.
Tao Bao481bab82017-12-21 11:23:09 -08001526 OPTIONS.oem_dicts = _LoadOemDicts(OPTIONS.oem_source)
1527
Tao Baoc098e9e2016-01-07 13:03:56 -08001528 ab_update = OPTIONS.info_dict.get("ab_update") == "true"
1529
Christian Oderf63e2cd2017-05-01 22:30:15 +02001530 # Use the default key to sign the package if not specified with package_key.
1531 # package_keys are needed on ab_updates, so always define them if an
1532 # ab_update is getting created.
1533 if not OPTIONS.no_signing or ab_update:
1534 if OPTIONS.package_key is None:
1535 OPTIONS.package_key = OPTIONS.info_dict.get(
1536 "default_system_dev_certificate",
1537 "build/target/product/security/testkey")
1538 # Get signing keys
1539 OPTIONS.key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
1540
Tao Baoc098e9e2016-01-07 13:03:56 -08001541 if ab_update:
Tao Baoc098e9e2016-01-07 13:03:56 -08001542 WriteABOTAPackageWithBrilloScript(
1543 target_file=args[0],
1544 output_file=args[1],
1545 source_file=OPTIONS.incremental_source)
1546
Tao Bao89fbb0f2017-01-10 10:47:58 -08001547 print("done.")
Tao Baoc098e9e2016-01-07 13:03:56 -08001548 return
1549
Tao Bao2db13852018-01-08 22:28:57 -08001550 # Sanity check the loaded info dicts first.
1551 if OPTIONS.info_dict.get("no_recovery") == "true":
1552 raise common.ExternalError(
1553 "--- target build has specified no recovery ---")
1554
1555 # Non-A/B OTAs rely on /cache partition to store temporary files.
1556 cache_size = OPTIONS.info_dict.get("cache_size")
1557 if cache_size is None:
1558 print("--- can't determine the cache partition size ---")
1559 OPTIONS.cache_size = cache_size
1560
Doug Zongker1c390a22009-05-14 19:06:36 -07001561 if OPTIONS.extra_script is not None:
1562 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1563
Dan Willemsencea5cd22017-03-21 14:44:27 -07001564 if OPTIONS.extracted_input is not None:
1565 OPTIONS.input_tmp = OPTIONS.extracted_input
Dan Willemsencea5cd22017-03-21 14:44:27 -07001566 input_zip = zipfile.ZipFile(args[0], "r")
1567 else:
1568 print("unzipping target target-files...")
1569 OPTIONS.input_tmp, input_zip = common.UnzipTemp(
1570 args[0], UNZIP_PATTERN)
Tao Bao2db13852018-01-08 22:28:57 -08001571 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001572
Tao Bao2db13852018-01-08 22:28:57 -08001573 # If the caller explicitly specified the device-specific extensions path via
1574 # -s / --device_specific, use that. Otherwise, use META/releasetools.py if it
1575 # is present in the target target_files. Otherwise, take the path of the file
1576 # from 'tool_extensions' in the info dict and look for that in the local
1577 # filesystem, relative to the current directory.
Doug Zongker37974732010-09-16 17:44:38 -07001578 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001579 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1580 if os.path.exists(from_input):
Tao Bao89fbb0f2017-01-10 10:47:58 -08001581 print("(using device-specific extensions from target_files)")
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001582 OPTIONS.device_specific = from_input
1583 else:
Tao Bao2db13852018-01-08 22:28:57 -08001584 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions")
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001585
Doug Zongker37974732010-09-16 17:44:38 -07001586 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001587 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001588
Tao Bao767e3ac2015-11-10 12:19:19 -08001589 # Set up the output zip. Create a temporary zip file if signing is needed.
1590 if OPTIONS.no_signing:
1591 if os.path.exists(args[1]):
1592 os.unlink(args[1])
1593 output_zip = zipfile.ZipFile(args[1], "w",
1594 compression=zipfile.ZIP_DEFLATED)
1595 else:
1596 temp_zip_file = tempfile.NamedTemporaryFile()
1597 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1598 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001599
Tao Bao767e3ac2015-11-10 12:19:19 -08001600 # Generate a full OTA.
Tao Bao0c6a4142017-12-15 10:11:19 -08001601 if OPTIONS.incremental_source is None:
Tao Baoc098e9e2016-01-07 13:03:56 -08001602 WriteFullOTAPackage(input_zip, output_zip)
Tao Bao767e3ac2015-11-10 12:19:19 -08001603
Tao Bao32b80dc2018-01-08 22:50:47 -08001604 # Generate an incremental OTA.
Tao Bao767e3ac2015-11-10 12:19:19 -08001605 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001606 print("unzipping source target-files...")
Tao Bao767e3ac2015-11-10 12:19:19 -08001607 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
Tao Bao6b0b2f92017-03-05 11:38:11 -08001608 OPTIONS.incremental_source,
Tao Bao457cbf62017-03-06 09:56:01 -08001609 UNZIP_PATTERN)
Tao Bao32b80dc2018-01-08 22:50:47 -08001610
1611 WriteBlockIncrementalOTAPackage(input_zip, source_zip, output_zip)
1612
1613 if OPTIONS.log_diff:
1614 with open(OPTIONS.log_diff, 'w') as out_file:
Tao Baod62c6032015-11-30 09:40:20 -08001615 import target_files_diff
Tao Bao32b80dc2018-01-08 22:50:47 -08001616 target_files_diff.recursiveDiff(
1617 '', OPTIONS.source_tmp, OPTIONS.input_tmp, out_file)
Doug Zongker62d4f182014-08-04 16:06:43 -07001618
Tao Bao2db13852018-01-08 22:28:57 -08001619 common.ZipClose(input_zip)
Tao Bao767e3ac2015-11-10 12:19:19 -08001620 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001621
Tao Bao767e3ac2015-11-10 12:19:19 -08001622 # Sign the generated zip package unless no_signing is specified.
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001623 if not OPTIONS.no_signing:
1624 SignOutput(temp_zip_file.name, args[1])
1625 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001626
Tao Bao89fbb0f2017-01-10 10:47:58 -08001627 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001628
1629
1630if __name__ == '__main__':
1631 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001632 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001633 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001634 except common.ExternalError as e:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001635 print("\n ERROR: %s\n" % (e,))
Doug Zongkereef39442009-04-02 12:14:19 -07001636 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001637 finally:
1638 common.Cleanup()