blob: 9ca6bdecd029d4e711005b3a7f98053d9029febd [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 Zongker25568482014-03-03 10:21:27 -080024 --board_config <file>
Doug Zongkerfdd8e692009-08-03 17:27:48 -070025 Deprecated.
Doug Zongkereef39442009-04-02 12:14:19 -070026
Doug Zongkerafb32ea2011-09-22 10:28:04 -070027 -k (--package_key) <key> Key to use to sign the package (default is
28 the value of default_system_dev_certificate from the input
29 target-files's META/misc_info.txt, or
30 "build/target/product/security/testkey" if that value is not
31 specified).
32
33 For incremental OTAs, the default value is based on the source
34 target-file, not the target build.
Doug Zongkereef39442009-04-02 12:14:19 -070035
36 -i (--incremental_from) <file>
37 Generate an incremental OTA using the given target-files zip as
38 the starting build.
39
Tao Bao43078aa2015-04-21 14:32:35 -070040 --full_radio
41 When generating an incremental OTA, always include a full copy of
42 radio image. This option is only meaningful when -i is specified,
43 because a full radio is always included in a full OTA if applicable.
44
leozwangaa6c1a12015-08-14 10:57:58 -070045 --full_bootloader
46 Similar to --full_radio. When generating an incremental OTA, always
47 include a full copy of bootloader image.
48
Michael Runge63f01de2014-10-28 19:24:19 -070049 -v (--verify)
50 Remount and verify the checksums of the files written to the
51 system and vendor (if used) partitions. Incremental builds only.
52
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -080053 -o (--oem_settings) <main_file[,additional_files...]>
54 Comma seperated list of files used to specify the expected OEM-specific
55 properties on the OEM partition of the intended device.
56 Multiple expected values can be used by providing multiple files.
57
Tao Bao8608cde2016-02-25 19:49:55 -080058 --oem_no_mount
59 For devices with OEM-specific properties but without an OEM partition,
60 do not mount the OEM partition in the updater-script. This should be
61 very rarely used, since it's expected to have a dedicated OEM partition
62 for OEM-specific properties. Only meaningful when -o is specified.
63
Doug Zongkerdbfaae52009-04-21 17:12:54 -070064 -w (--wipe_user_data)
65 Generate an OTA package that will wipe the user data partition
66 when installed.
67
Tao Bao5d182562016-02-23 11:38:39 -080068 --downgrade
69 Intentionally generate an incremental OTA that updates from a newer
70 build to an older one (based on timestamp comparison). "post-timestamp"
71 will be replaced by "ota-downgrade=yes" in the metadata file. A data
72 wipe will always be enforced, so "ota-wipe=yes" will also be included in
Tao Bao4996cf02016-03-08 17:53:39 -080073 the metadata file. The update-binary in the source build will be used in
Tao Bao3e6161a2017-02-28 11:48:48 -080074 the OTA package, unless --binary flag is specified. Please also check the
75 doc for --override_timestamp below.
76
77 --override_timestamp
78 Intentionally generate an incremental OTA that updates from a newer
79 build to an older one (based on timestamp comparison), by overriding the
80 timestamp in package metadata. This differs from --downgrade flag: we
81 know for sure this is NOT an actual downgrade case, but two builds are
82 cut in a reverse order. A legit use case is that we cut a new build C
83 (after having A and B), but want to enfore an update path of A -> C -> B.
84 Specifying --downgrade may not help since that would enforce a data wipe
85 for C -> B update. The value of "post-timestamp" will be set to the newer
86 timestamp plus one, so that the package can be pushed and applied.
Tao Bao5d182562016-02-23 11:38:39 -080087
Doug Zongker1c390a22009-05-14 19:06:36 -070088 -e (--extra_script) <file>
89 Insert the contents of file at the end of the update script.
90
Doug Zongker9b23f2c2013-11-25 14:44:12 -080091 -2 (--two_step)
92 Generate a 'two-step' OTA package, where recovery is updated
93 first, so that any changes made to the system partition are done
94 using the new recovery (new kernel, etc.).
95
Doug Zongker26e66192014-02-20 13:22:07 -080096 --block
Tao Bao457cbf62017-03-06 09:56:01 -080097 Generate a block-based OTA for non-A/B device. We have deprecated the
98 support for file-based OTA since O. Block-based OTA will be used by
99 default for all non-A/B devices. Keeping this flag here to not break
100 existing callers.
Doug Zongker26e66192014-02-20 13:22:07 -0800101
Doug Zongker25568482014-03-03 10:21:27 -0800102 -b (--binary) <file>
103 Use the given binary as the update-binary in the output package,
104 instead of the binary in the build's target_files. Use for
105 development only.
106
Martin Blumenstingl374e1142014-05-31 20:42:55 +0200107 -t (--worker_threads) <int>
108 Specifies the number of worker-threads that will be used when
109 generating patches for incremental updates (defaults to 3).
110
Tao Bao8dcf7382015-05-21 14:09:49 -0700111 --stash_threshold <float>
112 Specifies the threshold that will be used to compute the maximum
113 allowed stash size (defaults to 0.8).
Tao Bao9bc6bb22015-11-09 16:58:28 -0800114
115 --gen_verify
116 Generate an OTA package that verifies the partitions.
Tao Baod62c6032015-11-30 09:40:20 -0800117
118 --log_diff <file>
119 Generate a log file that shows the differences in the source and target
120 builds for an incremental package. This option is only meaningful when
121 -i is specified.
Tao Baodea0f8b2016-06-20 17:55:06 -0700122
123 --payload_signer <signer>
124 Specify the signer when signing the payload and metadata for A/B OTAs.
125 By default (i.e. without this flag), it calls 'openssl pkeyutl' to sign
126 with the package private key. If the private key cannot be accessed
127 directly, a payload signer that knows how to do that should be specified.
128 The signer will be supplied with "-inkey <path_to_key>",
129 "-in <input_file>" and "-out <output_file>" parameters.
Baligh Uddin2abbbd02016-06-22 12:14:16 -0700130
131 --payload_signer_args <args>
132 Specify the arguments needed for payload signer.
Doug Zongkereef39442009-04-02 12:14:19 -0700133"""
134
Tao Bao89fbb0f2017-01-10 10:47:58 -0800135from __future__ import print_function
136
Doug Zongkereef39442009-04-02 12:14:19 -0700137import sys
138
Doug Zongkercf6d5a92014-02-18 10:57:07 -0800139if sys.hexversion < 0x02070000:
Tao Bao89fbb0f2017-01-10 10:47:58 -0800140 print("Python 2.7 or newer is required.", file=sys.stderr)
Doug Zongkereef39442009-04-02 12:14:19 -0700141 sys.exit(1)
142
Tao Bao2dd1c482017-02-03 16:49:39 -0800143import copy
Doug Zongkerfc44a512014-08-26 13:10:25 -0700144import multiprocessing
Tao Bao2dd1c482017-02-03 16:49:39 -0800145import os.path
Tao Baoc098e9e2016-01-07 13:03:56 -0800146import subprocess
Baligh Uddin2abbbd02016-06-22 12:14:16 -0700147import shlex
Doug Zongkereef39442009-04-02 12:14:19 -0700148import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -0700149import zipfile
150
151import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700152import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -0700153import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700154
155OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700156OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700157OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700158OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700159OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700160OPTIONS.wipe_user_data = False
Tao Bao5d182562016-02-23 11:38:39 -0800161OPTIONS.downgrade = False
Tao Bao3e6161a2017-02-28 11:48:48 -0800162OPTIONS.timestamp = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700163OPTIONS.extra_script = None
Doug Zongkerfc44a512014-08-26 13:10:25 -0700164OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
165if OPTIONS.worker_threads == 0:
166 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800167OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900168OPTIONS.no_signing = False
Tao Bao457cbf62017-03-06 09:56:01 -0800169OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -0800170OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700171OPTIONS.oem_source = None
Tao Bao8608cde2016-02-25 19:49:55 -0800172OPTIONS.oem_no_mount = False
Doug Zongker62d4f182014-08-04 16:06:43 -0700173OPTIONS.fallback_to_full = True
Tao Bao43078aa2015-04-21 14:32:35 -0700174OPTIONS.full_radio = False
leozwangaa6c1a12015-08-14 10:57:58 -0700175OPTIONS.full_bootloader = False
Tao Baod47d8e12015-05-21 14:09:49 -0700176# Stash size cannot exceed cache_size * threshold.
177OPTIONS.cache_size = None
178OPTIONS.stash_threshold = 0.8
Tao Bao9bc6bb22015-11-09 16:58:28 -0800179OPTIONS.gen_verify = False
Tao Baod62c6032015-11-30 09:40:20 -0800180OPTIONS.log_diff = None
Tao Baodea0f8b2016-06-20 17:55:06 -0700181OPTIONS.payload_signer = None
Baligh Uddin2abbbd02016-06-22 12:14:16 -0700182OPTIONS.payload_signer_args = []
Tao Bao5f8ff932017-03-21 22:35:00 -0700183OPTIONS.extracted_input = None
Christian Oderf63e2cd2017-05-01 22:30:15 +0200184OPTIONS.key_passwords = []
Tao Bao8dcf7382015-05-21 14:09:49 -0700185
Tao Bao2dd1c482017-02-03 16:49:39 -0800186METADATA_NAME = 'META-INF/com/android/metadata'
Tao Bao6b0b2f92017-03-05 11:38:11 -0800187UNZIP_PATTERN = ['IMAGES/*', 'META/*']
188
Tao Bao2dd1c482017-02-03 16:49:39 -0800189
Doug Zongkereef39442009-04-02 12:14:19 -0700190def SignOutput(temp_zip_name, output_zip_name):
Christian Oderf63e2cd2017-05-01 22:30:15 +0200191 pw = OPTIONS.key_passwords[OPTIONS.package_key]
Doug Zongkereef39442009-04-02 12:14:19 -0700192
Doug Zongker951495f2009-08-14 12:44:19 -0700193 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
194 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700195
196
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800197def AppendAssertions(script, info_dict, oem_dicts=None):
Michael Runge6e836112014-04-15 17:40:21 -0700198 oem_props = info_dict.get("oem_fingerprint_properties")
Tao Bao3e30d972016-03-15 13:20:19 -0700199 if not oem_props:
Michael Runge6e836112014-04-15 17:40:21 -0700200 device = GetBuildProp("ro.product.device", info_dict)
201 script.AssertDevice(device)
202 else:
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800203 if not oem_dicts:
Dan Albert8b72aef2015-03-23 19:13:21 -0700204 raise common.ExternalError(
205 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700206 for prop in oem_props.split():
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800207 values = []
208 for oem_dict in oem_dicts:
209 if oem_dict.get(prop):
210 values.append(oem_dict[prop])
211 if not values:
Dan Albert8b72aef2015-03-23 19:13:21 -0700212 raise common.ExternalError(
213 "The OEM file is missing the property %s" % prop)
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800214 script.AssertOemProperty(prop, values)
215
216
Tao Baoebce6972017-03-06 10:22:20 -0800217def _LoadOemDicts(script, recovery_mount_options=None):
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800218 """Returns the list of loaded OEM properties dict."""
219 oem_dicts = None
220 if OPTIONS.oem_source is None:
221 raise common.ExternalError("OEM source required for this build")
Tao Baoebce6972017-03-06 10:22:20 -0800222 if not OPTIONS.oem_no_mount and script:
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800223 script.Mount("/oem", recovery_mount_options)
224 oem_dicts = []
225 for oem_file in OPTIONS.oem_source:
226 oem_dicts.append(common.LoadDictionaryFromLines(
227 open(oem_file).readlines()))
228 return oem_dicts
Doug Zongkereef39442009-04-02 12:14:19 -0700229
Doug Zongkereef39442009-04-02 12:14:19 -0700230
Tao Baod42e97e2016-11-30 12:11:57 -0800231def _WriteRecoveryImageToBoot(script, output_zip):
232 """Find and write recovery image to /boot in two-step OTA.
233
234 In two-step OTAs, we write recovery image to /boot as the first step so that
235 we can reboot to there and install a new recovery image to /recovery.
236 A special "recovery-two-step.img" will be preferred, which encodes the correct
237 path of "/boot". Otherwise the device may show "device is corrupt" message
238 when booting into /boot.
239
240 Fall back to using the regular recovery.img if the two-step recovery image
241 doesn't exist. Note that rebuilding the special image at this point may be
242 infeasible, because we don't have the desired boot signer and keys when
243 calling ota_from_target_files.py.
244 """
245
246 recovery_two_step_img_name = "recovery-two-step.img"
247 recovery_two_step_img_path = os.path.join(
248 OPTIONS.input_tmp, "IMAGES", recovery_two_step_img_name)
249 if os.path.exists(recovery_two_step_img_path):
250 recovery_two_step_img = common.GetBootableImage(
251 recovery_two_step_img_name, recovery_two_step_img_name,
252 OPTIONS.input_tmp, "RECOVERY")
253 common.ZipWriteStr(
254 output_zip, recovery_two_step_img_name, recovery_two_step_img.data)
Tao Bao89fbb0f2017-01-10 10:47:58 -0800255 print("two-step package: using %s in stage 1/3" % (
256 recovery_two_step_img_name,))
Tao Baod42e97e2016-11-30 12:11:57 -0800257 script.WriteRawImage("/boot", recovery_two_step_img_name)
258 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -0800259 print("two-step package: using recovery.img in stage 1/3")
Tao Baod42e97e2016-11-30 12:11:57 -0800260 # The "recovery.img" entry has been written into package earlier.
261 script.WriteRawImage("/boot", "recovery.img")
262
263
Doug Zongkerc9253822014-02-04 12:17:58 -0800264def HasRecoveryPatch(target_files_zip):
Tao Baof2cffbd2015-07-22 12:33:18 -0700265 namelist = [name for name in target_files_zip.namelist()]
266 return ("SYSTEM/recovery-from-boot.p" in namelist or
267 "SYSTEM/etc/recovery.img" in namelist)
Doug Zongker73ef8252009-07-23 15:12:53 -0700268
Tao Bao457cbf62017-03-06 09:56:01 -0800269
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700270def HasVendorPartition(target_files_zip):
271 try:
272 target_files_zip.getinfo("VENDOR/")
273 return True
274 except KeyError:
275 return False
276
Tao Bao457cbf62017-03-06 09:56:01 -0800277
Tao Baobcd1d162017-08-26 13:10:26 -0700278def HasTrebleEnabled(target_files_zip, info_dict):
279 return (HasVendorPartition(target_files_zip) and
280 GetBuildProp("ro.treble.enabled", info_dict) == "true")
281
282
Michael Runge6e836112014-04-15 17:40:21 -0700283def GetOemProperty(name, oem_props, oem_dict, info_dict):
284 if oem_props is not None and name in oem_props:
285 return oem_dict[name]
286 return GetBuildProp(name, info_dict)
287
288
289def CalculateFingerprint(oem_props, oem_dict, info_dict):
290 if oem_props is None:
291 return GetBuildProp("ro.build.fingerprint", info_dict)
292 return "%s/%s/%s:%s" % (
Dan Albert8b72aef2015-03-23 19:13:21 -0700293 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
294 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
295 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
296 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700297
Doug Zongkerfc44a512014-08-26 13:10:25 -0700298
Tao Bao7e0f1602017-03-06 15:50:08 -0800299def GetImage(which, tmpdir):
300 """Returns an image object suitable for passing to BlockImageDiff.
301
302 'which' partition must be "system" or "vendor". A prebuilt image and file
303 map must already exist in tmpdir.
304 """
Doug Zongker3c84f562014-07-31 11:06:30 -0700305
306 assert which in ("system", "vendor")
307
308 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700309 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
Doug Zongker3c84f562014-07-31 11:06:30 -0700310
Tao Bao7e0f1602017-03-06 15:50:08 -0800311 # The image and map files must have been created prior to calling
312 # ota_from_target_files.py (since LMP).
313 assert os.path.exists(path) and os.path.exists(mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700314
Tao Baoff777812015-05-12 11:42:31 -0700315 # Bug: http://b/20939131
316 # In ext4 filesystems, block 0 might be changed even being mounted
317 # R/O. We add it to clobbered_blocks so that it will be written to the
318 # target unconditionally. Note that they are still part of care_map.
319 clobbered_blocks = "0"
320
321 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700322
323
Tao Baobcd1d162017-08-26 13:10:26 -0700324def AddCompatibilityArchiveIfTrebleEnabled(target_zip, output_zip,
325 target_info_dict,
326 source_info_dict=None):
327 """Adds compatibility info into the output zip if it's Treble-enabled target.
Tao Bao21803d32017-04-19 10:16:09 -0700328
329 Metadata used for on-device compatibility verification is retrieved from
330 target_zip then added to compatibility.zip which is added to the output_zip
331 archive.
332
Tao Baobcd1d162017-08-26 13:10:26 -0700333 Compatibility archive should only be included for devices that have enabled
334 Treble support.
Tao Bao21803d32017-04-19 10:16:09 -0700335
336 Args:
337 target_zip: Zip file containing the source files to be included for OTA.
338 output_zip: Zip file that will be sent for OTA.
Tao Baobcd1d162017-08-26 13:10:26 -0700339 target_info_dict: The dict that holds the target build info.
340 source_info_dict: The dict that holds the source build info, if generating
341 an incremental OTA; None otherwise.
Tao Bao21803d32017-04-19 10:16:09 -0700342 """
343
Tao Baobcd1d162017-08-26 13:10:26 -0700344 def AddCompatibilityArchive(system_updated, vendor_updated):
345 """Adds compatibility info based on system/vendor update status.
Tao Bao21803d32017-04-19 10:16:09 -0700346
Tao Baobcd1d162017-08-26 13:10:26 -0700347 Args:
348 system_updated: If True, the system image will be updated and therefore
349 its metadata should be included.
350 vendor_updated: If True, the vendor image will be updated and therefore
351 its metadata should be included.
352 """
353 # Determine what metadata we need. Files are names relative to META/.
354 compatibility_files = []
355 vendor_metadata = ("vendor_manifest.xml", "vendor_matrix.xml")
356 system_metadata = ("system_manifest.xml", "system_matrix.xml")
357 if vendor_updated:
358 compatibility_files += vendor_metadata
359 if system_updated:
360 compatibility_files += system_metadata
Tao Bao21803d32017-04-19 10:16:09 -0700361
Tao Baobcd1d162017-08-26 13:10:26 -0700362 # Create new archive.
363 compatibility_archive = tempfile.NamedTemporaryFile()
364 compatibility_archive_zip = zipfile.ZipFile(compatibility_archive, "w",
365 compression=zipfile.ZIP_DEFLATED)
Tao Bao21803d32017-04-19 10:16:09 -0700366
Tao Baobcd1d162017-08-26 13:10:26 -0700367 # Add metadata.
368 for file_name in compatibility_files:
369 target_file_name = "META/" + file_name
Tao Bao21803d32017-04-19 10:16:09 -0700370
Tao Baobcd1d162017-08-26 13:10:26 -0700371 if target_file_name in target_zip.namelist():
372 data = target_zip.read(target_file_name)
373 common.ZipWriteStr(compatibility_archive_zip, file_name, data)
Tao Bao21803d32017-04-19 10:16:09 -0700374
Tao Baobcd1d162017-08-26 13:10:26 -0700375 # Ensure files are written before we copy into output_zip.
376 compatibility_archive_zip.close()
377
378 # Only add the archive if we have any compatibility info.
379 if compatibility_archive_zip.namelist():
380 common.ZipWrite(output_zip, compatibility_archive.name,
381 arcname="compatibility.zip",
382 compress_type=zipfile.ZIP_STORED)
383
384 # Will only proceed if the target has enabled the Treble support (as well as
385 # having a /vendor partition).
386 if not HasTrebleEnabled(target_zip, target_info_dict):
387 return
388
389 # We don't support OEM thumbprint in Treble world (which calculates
390 # fingerprints in a different way as shown in CalculateFingerprint()).
391 assert not target_info_dict.get("oem_fingerprint_properties")
392
393 # Full OTA carries the info for system/vendor both.
394 if source_info_dict is None:
395 AddCompatibilityArchive(True, True)
396 return
397
398 assert not source_info_dict.get("oem_fingerprint_properties")
399
400 source_fp = GetBuildProp("ro.build.fingerprint", source_info_dict)
401 target_fp = GetBuildProp("ro.build.fingerprint", target_info_dict)
402 system_updated = source_fp != target_fp
403
404 source_fp_vendor = GetVendorBuildProp("ro.vendor.build.fingerprint",
405 source_info_dict)
406 target_fp_vendor = GetVendorBuildProp("ro.vendor.build.fingerprint",
407 target_info_dict)
408 vendor_updated = source_fp_vendor != target_fp_vendor
409
410 AddCompatibilityArchive(system_updated, vendor_updated)
Tao Bao21803d32017-04-19 10:16:09 -0700411
412
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700413def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700414 # TODO: how to determine this? We don't know what version it will
Tao Bao34b47bf2015-06-22 19:17:41 -0700415 # be installed on top of. For now, we expect the API just won't
416 # change very often. Similarly for fstab, it might have changed
417 # in the target build.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700418 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700419
Tao Bao838c68f2016-03-15 19:16:18 +0000420 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Tao Bao3e30d972016-03-15 13:20:19 -0700421 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800422 oem_dicts = None
Tao Bao3e30d972016-03-15 13:20:19 -0700423 if oem_props:
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800424 oem_dicts = _LoadOemDicts(script, recovery_mount_options)
Michael Runge6e836112014-04-15 17:40:21 -0700425
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800426 target_fp = CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
427 OPTIONS.info_dict)
Dan Albert8b72aef2015-03-23 19:13:21 -0700428 metadata = {
Tao Bao39f3eaf2017-03-09 15:01:11 -0800429 "post-build": target_fp,
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800430 "pre-device": GetOemProperty("ro.product.device", oem_props,
431 oem_dicts and oem_dicts[0],
Dan Albert8b72aef2015-03-23 19:13:21 -0700432 OPTIONS.info_dict),
433 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
434 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700435
Doug Zongker05d3dea2009-06-22 11:32:31 -0700436 device_specific = common.DeviceSpecificParams(
437 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700438 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700439 output_zip=output_zip,
440 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700441 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700442 metadata=metadata,
443 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700444
Tao Bao457cbf62017-03-06 09:56:01 -0800445 assert HasRecoveryPatch(input_zip)
Doug Zongkerc9253822014-02-04 12:17:58 -0800446
Tao Bao457cbf62017-03-06 09:56:01 -0800447 metadata["ota-type"] = "BLOCK"
Tao Baod8d14be2016-02-04 14:26:02 -0800448
Elliott Hughesd8a52f92016-06-20 14:35:47 -0700449 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
450 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
451 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700452
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800453 AppendAssertions(script, OPTIONS.info_dict, oem_dicts)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700454 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800455
456 # Two-step package strategy (in chronological order, which is *not*
457 # the order in which the generated script has things):
458 #
459 # if stage is not "2/3" or "3/3":
460 # write recovery image to boot partition
461 # set stage to "2/3"
462 # reboot to boot partition and restart recovery
463 # else if stage is "2/3":
464 # write recovery image to recovery partition
465 # set stage to "3/3"
466 # reboot to recovery partition and restart recovery
467 # else:
468 # (stage must be "3/3")
469 # set stage to ""
470 # do normal full package installation:
471 # wipe and install system, boot image, etc.
472 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700473 # complete script normally
474 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800475
476 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
477 OPTIONS.input_tmp, "RECOVERY")
478 if OPTIONS.two_step:
479 if not OPTIONS.info_dict.get("multistage_support", None):
480 assert False, "two-step packages not supported by this build"
481 fs = OPTIONS.info_dict["fstab"]["/misc"]
482 assert fs.fs_type.upper() == "EMMC", \
483 "two-step packages only supported on devices with EMMC /misc partitions"
484 bcb_dev = {"bcb_dev": fs.device}
485 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
486 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700487if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800488""" % bcb_dev)
Tao Baod42e97e2016-11-30 12:11:57 -0800489
490 # Stage 2/3: Write recovery image to /recovery (currently running /boot).
491 script.Comment("Stage 2/3")
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800492 script.WriteRawImage("/recovery", "recovery.img")
493 script.AppendExtra("""
494set_stage("%(bcb_dev)s", "3/3");
495reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700496else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800497""" % bcb_dev)
498
Tao Baod42e97e2016-11-30 12:11:57 -0800499 # Stage 3/3: Make changes.
500 script.Comment("Stage 3/3")
501
Tao Bao6c55a8a2015-04-08 15:30:27 -0700502 # Dump fingerprints
Tao Bao3e30d972016-03-15 13:20:19 -0700503 script.Print("Target: %s" % target_fp)
Tao Bao6c55a8a2015-04-08 15:30:27 -0700504
Doug Zongkere5ff5902012-01-17 10:55:37 -0800505 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700506
Doug Zongker01ce19c2014-02-04 13:48:15 -0800507 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700508
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700509 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800510 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700511 if HasVendorPartition(input_zip):
512 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700513
Michael Runge7cd99ba2014-10-22 17:21:48 -0700514 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
515
Doug Zongker4b9596f2014-06-09 14:15:45 -0700516 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800517
Tao Bao457cbf62017-03-06 09:56:01 -0800518 # Full OTA is done as an "incremental" against an empty source image. This
519 # has the effect of writing new data from the package to the entire
520 # partition, but lets us reuse the updater code that writes incrementals to
521 # do it.
522 system_tgt = GetImage("system", OPTIONS.input_tmp)
523 system_tgt.ResetFileMap()
524 system_diff = common.BlockDifference("system", system_tgt, src=None)
525 system_diff.WriteScript(script, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700526
Tao Bao7a5bf8a2015-07-21 18:01:20 -0700527 boot_img = common.GetBootableImage(
528 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800529
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700530 if HasVendorPartition(input_zip):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700531 script.ShowProgress(0.1, 0)
532
Tao Bao457cbf62017-03-06 09:56:01 -0800533 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp)
534 vendor_tgt.ResetFileMap()
535 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
536 vendor_diff.WriteScript(script, output_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700537
Tao Baobcd1d162017-08-26 13:10:26 -0700538 AddCompatibilityArchiveIfTrebleEnabled(input_zip, output_zip,
539 OPTIONS.info_dict)
540
Doug Zongker37974732010-09-16 17:44:38 -0700541 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700542 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700543
Doug Zongker01ce19c2014-02-04 13:48:15 -0800544 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700545 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700546
Doug Zongker01ce19c2014-02-04 13:48:15 -0800547 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700548 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700549
Doug Zongker1c390a22009-05-14 19:06:36 -0700550 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700551 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700552
Doug Zongker14833602010-02-02 13:12:04 -0800553 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800554
Doug Zongker922206e2014-03-04 13:16:24 -0800555 if OPTIONS.wipe_user_data:
556 script.ShowProgress(0.1, 10)
557 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700558
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800559 if OPTIONS.two_step:
560 script.AppendExtra("""
561set_stage("%(bcb_dev)s", "");
562""" % bcb_dev)
563 script.AppendExtra("else\n")
Tao Baod42e97e2016-11-30 12:11:57 -0800564
565 # Stage 1/3: Nothing to verify for full OTA. Write recovery image to /boot.
566 script.Comment("Stage 1/3")
567 _WriteRecoveryImageToBoot(script, output_zip)
568
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800569 script.AppendExtra("""
570set_stage("%(bcb_dev)s", "2/3");
571reboot_now("%(bcb_dev)s", "");
572endif;
573endif;
574""" % bcb_dev)
Tao Baod8d14be2016-02-04 14:26:02 -0800575
Tao Bao5d182562016-02-23 11:38:39 -0800576 script.SetProgress(1)
577 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -0800578 metadata["ota-required-cache"] = str(script.required_cache)
Doug Zongker2ea21062010-04-28 16:05:21 -0700579 WriteMetadata(metadata, output_zip)
580
Doug Zongkerfc44a512014-08-26 13:10:25 -0700581
Doug Zongker2ea21062010-04-28 16:05:21 -0700582def WriteMetadata(metadata, output_zip):
Tao Bao2dd1c482017-02-03 16:49:39 -0800583 value = "".join(["%s=%s\n" % kv for kv in sorted(metadata.iteritems())])
584 common.ZipWriteStr(output_zip, METADATA_NAME, value,
585 compress_type=zipfile.ZIP_STORED)
Doug Zongkereef39442009-04-02 12:14:19 -0700586
Doug Zongkerfc44a512014-08-26 13:10:25 -0700587
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700588def GetBuildProp(prop, info_dict):
Tao Baobcd1d162017-08-26 13:10:26 -0700589 """Returns the inquired build property from a given info_dict."""
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700590 try:
591 return info_dict.get("build.prop", {})[prop]
592 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700593 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700594
Doug Zongkerfc44a512014-08-26 13:10:25 -0700595
Tao Baobcd1d162017-08-26 13:10:26 -0700596def GetVendorBuildProp(prop, info_dict):
597 """Returns the inquired vendor build property from a given info_dict."""
598 try:
599 return info_dict.get("vendor.build.prop", {})[prop]
600 except KeyError:
601 raise common.ExternalError(
602 "couldn't find %s in vendor.build.prop" % (prop,))
603
604
Tao Baob31892e2017-02-07 11:21:17 -0800605def HandleDowngradeMetadata(metadata):
606 # Only incremental OTAs are allowed to reach here.
607 assert OPTIONS.incremental_source is not None
608
609 post_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict)
610 pre_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
611 is_downgrade = long(post_timestamp) < long(pre_timestamp)
612
613 if OPTIONS.downgrade:
Tao Baob31892e2017-02-07 11:21:17 -0800614 if not is_downgrade:
615 raise RuntimeError("--downgrade specified but no downgrade detected: "
616 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
Tao Bao3e6161a2017-02-28 11:48:48 -0800617 metadata["ota-downgrade"] = "yes"
618 elif OPTIONS.timestamp:
619 if not is_downgrade:
620 raise RuntimeError("--timestamp specified but no timestamp hack needed: "
621 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
622 metadata["post-timestamp"] = str(long(pre_timestamp) + 1)
Tao Baob31892e2017-02-07 11:21:17 -0800623 else:
624 if is_downgrade:
Tao Bao3e6161a2017-02-28 11:48:48 -0800625 raise RuntimeError("Downgrade detected based on timestamp check: "
626 "pre: %s, post: %s. Need to specify --timestamp OR "
627 "--downgrade to allow building the incremental." % (
628 pre_timestamp, post_timestamp))
Tao Baob31892e2017-02-07 11:21:17 -0800629 metadata["post-timestamp"] = post_timestamp
630
631
Geremy Condra36bd3652014-02-06 19:45:10 -0800632def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
633 source_version = OPTIONS.source_info_dict["recovery_api_version"]
634 target_version = OPTIONS.target_info_dict["recovery_api_version"]
635
636 if source_version == 0:
Tao Bao3e30d972016-03-15 13:20:19 -0700637 print("WARNING: generating edify script for a source that "
638 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -0700639 script = edify_generator.EdifyGenerator(
640 source_version, OPTIONS.target_info_dict,
641 fstab=OPTIONS.source_info_dict["fstab"])
Geremy Condra36bd3652014-02-06 19:45:10 -0800642
Tao Bao3806c232015-07-05 21:08:33 -0700643 recovery_mount_options = OPTIONS.source_info_dict.get(
644 "recovery_mount_options")
Tao Bao3e30d972016-03-15 13:20:19 -0700645 source_oem_props = OPTIONS.source_info_dict.get("oem_fingerprint_properties")
646 target_oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800647 oem_dicts = None
648 if source_oem_props and target_oem_props:
649 oem_dicts = _LoadOemDicts(script, recovery_mount_options)
Tao Bao3806c232015-07-05 21:08:33 -0700650
Dan Albert8b72aef2015-03-23 19:13:21 -0700651 metadata = {
Tao Bao3e30d972016-03-15 13:20:19 -0700652 "pre-device": GetOemProperty("ro.product.device", source_oem_props,
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800653 oem_dicts and oem_dicts[0],
654 OPTIONS.source_info_dict),
Tao Baod8d14be2016-02-04 14:26:02 -0800655 "ota-type": "BLOCK",
Dan Albert8b72aef2015-03-23 19:13:21 -0700656 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800657
Tao Baob31892e2017-02-07 11:21:17 -0800658 HandleDowngradeMetadata(metadata)
Tao Bao5d182562016-02-23 11:38:39 -0800659
Geremy Condra36bd3652014-02-06 19:45:10 -0800660 device_specific = common.DeviceSpecificParams(
661 source_zip=source_zip,
662 source_version=source_version,
663 target_zip=target_zip,
664 target_version=target_version,
665 output_zip=output_zip,
666 script=script,
667 metadata=metadata,
Tao Bao6f0b2192015-10-13 16:37:12 -0700668 info_dict=OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800669
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800670 source_fp = CalculateFingerprint(source_oem_props, oem_dicts and oem_dicts[0],
Tao Bao3806c232015-07-05 21:08:33 -0700671 OPTIONS.source_info_dict)
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800672 target_fp = CalculateFingerprint(target_oem_props, oem_dicts and oem_dicts[0],
Tao Bao3806c232015-07-05 21:08:33 -0700673 OPTIONS.target_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800674 metadata["pre-build"] = source_fp
675 metadata["post-build"] = target_fp
Tianjie Xud06f07e2016-06-09 14:18:45 -0700676 metadata["pre-build-incremental"] = GetBuildProp(
677 "ro.build.version.incremental", OPTIONS.source_info_dict)
678 metadata["post-build-incremental"] = GetBuildProp(
679 "ro.build.version.incremental", OPTIONS.target_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800680
681 source_boot = common.GetBootableImage(
682 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
683 OPTIONS.source_info_dict)
684 target_boot = common.GetBootableImage(
685 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
686 updating_boot = (not OPTIONS.two_step and
687 (source_boot.data != target_boot.data))
688
Geremy Condra36bd3652014-02-06 19:45:10 -0800689 target_recovery = common.GetBootableImage(
690 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800691
Tao Bao7e0f1602017-03-06 15:50:08 -0800692 system_src = GetImage("system", OPTIONS.source_tmp)
693 system_tgt = GetImage("system", OPTIONS.target_tmp)
Tao Baodd2a5892015-03-12 12:32:37 -0700694
695 blockimgdiff_version = 1
696 if OPTIONS.info_dict:
697 blockimgdiff_version = max(
698 int(i) for i in
699 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
700
Tao Baof8acad12016-07-07 09:09:58 -0700701 # Check the first block of the source system partition for remount R/W only
702 # if the filesystem is ext4.
703 system_src_partition = OPTIONS.source_info_dict["fstab"]["/system"]
704 check_first_block = system_src_partition.fs_type == "ext4"
Tao Bao293fd132016-06-11 12:19:23 -0700705 # Disable using imgdiff for squashfs. 'imgdiff -z' expects input files to be
706 # in zip formats. However with squashfs, a) all files are compressed in LZ4;
707 # b) the blocks listed in block map may not contain all the bytes for a given
708 # file (because they're rounded to be 4K-aligned).
Tao Baof8acad12016-07-07 09:09:58 -0700709 system_tgt_partition = OPTIONS.target_info_dict["fstab"]["/system"]
710 disable_imgdiff = (system_src_partition.fs_type == "squashfs" or
711 system_tgt_partition.fs_type == "squashfs")
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700712 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tianjie Xufc3422a2015-12-15 11:53:59 -0800713 check_first_block,
Tao Bao293fd132016-06-11 12:19:23 -0700714 version=blockimgdiff_version,
715 disable_imgdiff=disable_imgdiff)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700716
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700717 if HasVendorPartition(target_zip):
718 if not HasVendorPartition(source_zip):
719 raise RuntimeError("can't generate incremental that adds /vendor")
Tao Bao7e0f1602017-03-06 15:50:08 -0800720 vendor_src = GetImage("vendor", OPTIONS.source_tmp)
721 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp)
Tianjie Xufc3422a2015-12-15 11:53:59 -0800722
723 # Check first block of vendor partition for remount R/W only if
724 # disk type is ext4
725 vendor_partition = OPTIONS.source_info_dict["fstab"]["/vendor"]
Tao Baod8d14be2016-02-04 14:26:02 -0800726 check_first_block = vendor_partition.fs_type == "ext4"
Tao Bao293fd132016-06-11 12:19:23 -0700727 disable_imgdiff = vendor_partition.fs_type == "squashfs"
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700728 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tianjie Xufc3422a2015-12-15 11:53:59 -0800729 check_first_block,
Tao Bao293fd132016-06-11 12:19:23 -0700730 version=blockimgdiff_version,
731 disable_imgdiff=disable_imgdiff)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700732 else:
733 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800734
Tao Baobcd1d162017-08-26 13:10:26 -0700735 AddCompatibilityArchiveIfTrebleEnabled(
736 target_zip, output_zip, OPTIONS.target_info_dict,
737 OPTIONS.source_info_dict)
738
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800739 AppendAssertions(script, OPTIONS.target_info_dict, oem_dicts)
Geremy Condra36bd3652014-02-06 19:45:10 -0800740 device_specific.IncrementalOTA_Assertions()
741
742 # Two-step incremental package strategy (in chronological order,
743 # which is *not* the order in which the generated script has
744 # things):
745 #
746 # if stage is not "2/3" or "3/3":
747 # do verification on current system
748 # write recovery image to boot partition
749 # set stage to "2/3"
750 # reboot to boot partition and restart recovery
751 # else if stage is "2/3":
752 # write recovery image to recovery partition
753 # set stage to "3/3"
754 # reboot to recovery partition and restart recovery
755 # else:
756 # (stage must be "3/3")
757 # perform update:
758 # patch system files, etc.
759 # force full install of new boot image
760 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700761 # complete script normally
762 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800763
764 if OPTIONS.two_step:
Tao Baodd24da92015-07-29 14:09:23 -0700765 if not OPTIONS.source_info_dict.get("multistage_support", None):
Geremy Condra36bd3652014-02-06 19:45:10 -0800766 assert False, "two-step packages not supported by this build"
Tao Baodd24da92015-07-29 14:09:23 -0700767 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Geremy Condra36bd3652014-02-06 19:45:10 -0800768 assert fs.fs_type.upper() == "EMMC", \
769 "two-step packages only supported on devices with EMMC /misc partitions"
770 bcb_dev = {"bcb_dev": fs.device}
771 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
772 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700773if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800774""" % bcb_dev)
Tao Baod42e97e2016-11-30 12:11:57 -0800775
776 # Stage 2/3: Write recovery image to /recovery (currently running /boot).
777 script.Comment("Stage 2/3")
Dan Albert8b72aef2015-03-23 19:13:21 -0700778 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800779 script.WriteRawImage("/recovery", "recovery.img")
780 script.AppendExtra("""
781set_stage("%(bcb_dev)s", "3/3");
782reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700783else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800784""" % bcb_dev)
785
Tao Baod42e97e2016-11-30 12:11:57 -0800786 # Stage 1/3: (a) Verify the current system.
787 script.Comment("Stage 1/3")
788
Tao Bao6c55a8a2015-04-08 15:30:27 -0700789 # Dump fingerprints
Tao Baof9023852016-12-14 11:53:38 -0800790 script.Print("Source: %s" % (source_fp,))
791 script.Print("Target: %s" % (target_fp,))
Tao Bao6c55a8a2015-04-08 15:30:27 -0700792
Geremy Condra36bd3652014-02-06 19:45:10 -0800793 script.Print("Verifying current system...")
794
795 device_specific.IncrementalOTA_VerifyBegin()
796
Tao Bao3e30d972016-03-15 13:20:19 -0700797 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
798 # patching on a device that's already on the target build will damage the
799 # system. Because operations like move don't check the block state, they
800 # always apply the changes unconditionally.
801 if blockimgdiff_version <= 2:
802 if source_oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700803 script.AssertSomeFingerprint(source_fp)
804 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700805 script.AssertSomeThumbprint(
806 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Tao Bao3e30d972016-03-15 13:20:19 -0700807
808 else: # blockimgdiff_version > 2
809 if source_oem_props is None and target_oem_props is None:
810 script.AssertSomeFingerprint(source_fp, target_fp)
811 elif source_oem_props is not None and target_oem_props is not None:
Tao Baodd2a5892015-03-12 12:32:37 -0700812 script.AssertSomeThumbprint(
813 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
814 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Tao Bao3e30d972016-03-15 13:20:19 -0700815 elif source_oem_props is None and target_oem_props is not None:
816 script.AssertFingerprintOrThumbprint(
817 source_fp,
818 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict))
819 else:
820 script.AssertFingerprintOrThumbprint(
821 target_fp,
822 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800823
Tao Baod8d14be2016-02-04 14:26:02 -0800824 # Check the required cache size (i.e. stashed blocks).
825 size = []
826 if system_diff:
827 size.append(system_diff.required_cache)
828 if vendor_diff:
829 size.append(vendor_diff.required_cache)
830
Geremy Condra36bd3652014-02-06 19:45:10 -0800831 if updating_boot:
Tao Baodd24da92015-07-29 14:09:23 -0700832 boot_type, boot_device = common.GetTypeAndDevice(
833 "/boot", OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800834 d = common.Difference(target_boot, source_boot)
835 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700836 if d is None:
837 include_full_boot = True
838 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
839 else:
840 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800841
Tao Bao89fbb0f2017-01-10 10:47:58 -0800842 print("boot target: %d source: %d diff: %d" % (
843 target_boot.size, source_boot.size, len(d)))
Geremy Condra36bd3652014-02-06 19:45:10 -0800844
Doug Zongkerf8340082014-08-05 10:39:37 -0700845 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800846
Doug Zongkerf8340082014-08-05 10:39:37 -0700847 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
848 (boot_type, boot_device,
849 source_boot.size, source_boot.sha1,
850 target_boot.size, target_boot.sha1))
Tao Baod8d14be2016-02-04 14:26:02 -0800851 size.append(target_boot.size)
852
853 if size:
854 script.CacheFreeSpaceCheck(max(size))
Geremy Condra36bd3652014-02-06 19:45:10 -0800855
856 device_specific.IncrementalOTA_VerifyEnd()
857
858 if OPTIONS.two_step:
Tao Baod42e97e2016-11-30 12:11:57 -0800859 # Stage 1/3: (b) Write recovery image to /boot.
860 _WriteRecoveryImageToBoot(script, output_zip)
861
Geremy Condra36bd3652014-02-06 19:45:10 -0800862 script.AppendExtra("""
863set_stage("%(bcb_dev)s", "2/3");
864reboot_now("%(bcb_dev)s", "");
865else
866""" % bcb_dev)
867
Tao Baod42e97e2016-11-30 12:11:57 -0800868 # Stage 3/3: Make changes.
869 script.Comment("Stage 3/3")
870
Jesse Zhao75bcea02015-01-06 10:59:53 -0800871 # Verify the existing partitions.
Tao Baod522bdc2016-04-12 15:53:16 -0700872 system_diff.WriteVerifyScript(script, touched_blocks_only=True)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800873 if vendor_diff:
Tao Baod522bdc2016-04-12 15:53:16 -0700874 vendor_diff.WriteVerifyScript(script, touched_blocks_only=True)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800875
Geremy Condra36bd3652014-02-06 19:45:10 -0800876 script.Comment("---- start making changes here ----")
877
878 device_specific.IncrementalOTA_InstallBegin()
879
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700880 system_diff.WriteScript(script, output_zip,
881 progress=0.8 if vendor_diff else 0.9)
Tao Bao68658c02015-06-01 13:40:49 -0700882
Doug Zongkerfc44a512014-08-26 13:10:25 -0700883 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700884 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800885
886 if OPTIONS.two_step:
887 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
888 script.WriteRawImage("/boot", "boot.img")
Tao Bao89fbb0f2017-01-10 10:47:58 -0800889 print("writing full boot image (forced by two-step mode)")
Geremy Condra36bd3652014-02-06 19:45:10 -0800890
891 if not OPTIONS.two_step:
892 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700893 if include_full_boot:
Tao Bao89fbb0f2017-01-10 10:47:58 -0800894 print("boot image changed; including full.")
Doug Zongkerf8340082014-08-05 10:39:37 -0700895 script.Print("Installing boot image...")
896 script.WriteRawImage("/boot", "boot.img")
897 else:
898 # Produce the boot image by applying a patch to the current
899 # contents of the boot partition, and write it back to the
900 # partition.
Tao Bao89fbb0f2017-01-10 10:47:58 -0800901 print("boot image changed; including patch.")
Doug Zongkerf8340082014-08-05 10:39:37 -0700902 script.Print("Patching boot image...")
903 script.ShowProgress(0.1, 10)
904 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
905 % (boot_type, boot_device,
906 source_boot.size, source_boot.sha1,
907 target_boot.size, target_boot.sha1),
908 "-",
909 target_boot.size, target_boot.sha1,
910 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800911 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -0800912 print("boot image unchanged; skipping.")
Geremy Condra36bd3652014-02-06 19:45:10 -0800913
914 # Do device-specific installation (eg, write radio image).
915 device_specific.IncrementalOTA_InstallEnd()
916
917 if OPTIONS.extra_script is not None:
918 script.AppendExtra(OPTIONS.extra_script)
919
Doug Zongker922206e2014-03-04 13:16:24 -0800920 if OPTIONS.wipe_user_data:
921 script.Print("Erasing user data...")
922 script.FormatPartition("/data")
Tao Bao5d182562016-02-23 11:38:39 -0800923 metadata["ota-wipe"] = "yes"
Doug Zongker922206e2014-03-04 13:16:24 -0800924
Geremy Condra36bd3652014-02-06 19:45:10 -0800925 if OPTIONS.two_step:
926 script.AppendExtra("""
927set_stage("%(bcb_dev)s", "");
928endif;
929endif;
930""" % bcb_dev)
931
932 script.SetProgress(1)
Tao Bao4996cf02016-03-08 17:53:39 -0800933 # For downgrade OTAs, we prefer to use the update-binary in the source
934 # build that is actually newer than the one in the target build.
935 if OPTIONS.downgrade:
936 script.AddToZip(source_zip, output_zip, input_path=OPTIONS.updater_binary)
937 else:
938 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -0800939 metadata["ota-required-cache"] = str(script.required_cache)
Geremy Condra36bd3652014-02-06 19:45:10 -0800940 WriteMetadata(metadata, output_zip)
941
Doug Zongker32b527d2014-03-04 10:03:02 -0800942
Tao Bao9bc6bb22015-11-09 16:58:28 -0800943def WriteVerifyPackage(input_zip, output_zip):
944 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
945
946 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
947 recovery_mount_options = OPTIONS.info_dict.get(
948 "recovery_mount_options")
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800949 oem_dicts = None
Tao Bao3e30d972016-03-15 13:20:19 -0700950 if oem_props:
Tao Baoebce6972017-03-06 10:22:20 -0800951 oem_dicts = _LoadOemDicts(script, recovery_mount_options)
Tao Bao9bc6bb22015-11-09 16:58:28 -0800952
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800953 target_fp = CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
954 OPTIONS.info_dict)
Tao Bao9bc6bb22015-11-09 16:58:28 -0800955 metadata = {
956 "post-build": target_fp,
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800957 "pre-device": GetOemProperty("ro.product.device", oem_props,
958 oem_dicts and oem_dicts[0],
Tao Bao9bc6bb22015-11-09 16:58:28 -0800959 OPTIONS.info_dict),
960 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
961 }
962
963 device_specific = common.DeviceSpecificParams(
964 input_zip=input_zip,
965 input_version=OPTIONS.info_dict["recovery_api_version"],
966 output_zip=output_zip,
967 script=script,
968 input_tmp=OPTIONS.input_tmp,
969 metadata=metadata,
970 info_dict=OPTIONS.info_dict)
971
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -0800972 AppendAssertions(script, OPTIONS.info_dict, oem_dicts)
Tao Bao9bc6bb22015-11-09 16:58:28 -0800973
974 script.Print("Verifying device images against %s..." % target_fp)
975 script.AppendExtra("")
976
977 script.Print("Verifying boot...")
978 boot_img = common.GetBootableImage(
979 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
980 boot_type, boot_device = common.GetTypeAndDevice(
981 "/boot", OPTIONS.info_dict)
982 script.Verify("%s:%s:%d:%s" % (
983 boot_type, boot_device, boot_img.size, boot_img.sha1))
984 script.AppendExtra("")
985
986 script.Print("Verifying recovery...")
987 recovery_img = common.GetBootableImage(
988 "recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
989 recovery_type, recovery_device = common.GetTypeAndDevice(
990 "/recovery", OPTIONS.info_dict)
991 script.Verify("%s:%s:%d:%s" % (
992 recovery_type, recovery_device, recovery_img.size, recovery_img.sha1))
993 script.AppendExtra("")
994
Tao Bao7e0f1602017-03-06 15:50:08 -0800995 system_tgt = GetImage("system", OPTIONS.input_tmp)
Tao Bao9bc6bb22015-11-09 16:58:28 -0800996 system_tgt.ResetFileMap()
997 system_diff = common.BlockDifference("system", system_tgt, src=None)
998 system_diff.WriteStrictVerifyScript(script)
999
1000 if HasVendorPartition(input_zip):
Tao Bao7e0f1602017-03-06 15:50:08 -08001001 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp)
Tao Bao9bc6bb22015-11-09 16:58:28 -08001002 vendor_tgt.ResetFileMap()
1003 vendor_diff = common.BlockDifference("vendor", vendor_tgt, src=None)
1004 vendor_diff.WriteStrictVerifyScript(script)
1005
1006 # Device specific partitions, such as radio, bootloader and etc.
1007 device_specific.VerifyOTA_Assertions()
1008
1009 script.SetProgress(1.0)
1010 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -08001011 metadata["ota-required-cache"] = str(script.required_cache)
Tao Bao9bc6bb22015-11-09 16:58:28 -08001012 WriteMetadata(metadata, output_zip)
1013
1014
Tao Baoc098e9e2016-01-07 13:03:56 -08001015def WriteABOTAPackageWithBrilloScript(target_file, output_file,
1016 source_file=None):
1017 """Generate an Android OTA package that has A/B update payload."""
1018
Tao Bao2dd1c482017-02-03 16:49:39 -08001019 def ComputeStreamingMetadata(zip_file, reserve_space=False,
1020 expected_length=None):
1021 """Compute the streaming metadata for a given zip.
1022
1023 When 'reserve_space' is True, we reserve extra space for the offset and
1024 length of the metadata entry itself, although we don't know the final
1025 values until the package gets signed. This function will be called again
1026 after signing. We then write the actual values and pad the string to the
1027 length we set earlier. Note that we can't use the actual length of the
1028 metadata entry in the second run. Otherwise the offsets for other entries
1029 will be changing again.
1030 """
Tao Baoc96316c2017-01-24 22:10:49 -08001031
1032 def ComputeEntryOffsetSize(name):
1033 """Compute the zip entry offset and size."""
1034 info = zip_file.getinfo(name)
1035 offset = info.header_offset + len(info.FileHeader())
1036 size = info.file_size
Tao Bao2dd1c482017-02-03 16:49:39 -08001037 return '%s:%d:%d' % (os.path.basename(name), offset, size)
Tao Baoc96316c2017-01-24 22:10:49 -08001038
1039 # payload.bin and payload_properties.txt must exist.
1040 offsets = [ComputeEntryOffsetSize('payload.bin'),
1041 ComputeEntryOffsetSize('payload_properties.txt')]
1042
1043 # care_map.txt is available only if dm-verity is enabled.
1044 if 'care_map.txt' in zip_file.namelist():
1045 offsets.append(ComputeEntryOffsetSize('care_map.txt'))
Tao Bao2dd1c482017-02-03 16:49:39 -08001046
Tao Bao21803d32017-04-19 10:16:09 -07001047 if 'compatibility.zip' in zip_file.namelist():
1048 offsets.append(ComputeEntryOffsetSize('compatibility.zip'))
1049
Tao Bao2dd1c482017-02-03 16:49:39 -08001050 # 'META-INF/com/android/metadata' is required. We don't know its actual
1051 # offset and length (as well as the values for other entries). So we
1052 # reserve 10-byte as a placeholder, which is to cover the space for metadata
1053 # entry ('xx:xxx', since it's ZIP_STORED which should appear at the
1054 # beginning of the zip), as well as the possible value changes in other
1055 # entries.
1056 if reserve_space:
1057 offsets.append('metadata:' + ' ' * 10)
1058 else:
1059 offsets.append(ComputeEntryOffsetSize(METADATA_NAME))
1060
1061 value = ','.join(offsets)
1062 if expected_length is not None:
1063 assert len(value) <= expected_length, \
1064 'Insufficient reserved space: reserved=%d, actual=%d' % (
1065 expected_length, len(value))
1066 value += ' ' * (expected_length - len(value))
1067 return value
Tao Baoc96316c2017-01-24 22:10:49 -08001068
Alex Deymod8d96ec2016-06-10 16:38:31 -07001069 # The place where the output from the subprocess should go.
1070 log_file = sys.stdout if OPTIONS.verbose else subprocess.PIPE
1071
Tao Baodea0f8b2016-06-20 17:55:06 -07001072 # A/B updater expects a signing key in RSA format. Gets the key ready for
1073 # later use in step 3, unless a payload_signer has been specified.
1074 if OPTIONS.payload_signer is None:
1075 cmd = ["openssl", "pkcs8",
1076 "-in", OPTIONS.package_key + OPTIONS.private_key_suffix,
Christian Oderf63e2cd2017-05-01 22:30:15 +02001077 "-inform", "DER"]
1078 pw = OPTIONS.key_passwords[OPTIONS.package_key]
1079 cmd.extend(["-passin", "pass:" + pw] if pw else ["-nocrypt"])
Tao Baodea0f8b2016-06-20 17:55:06 -07001080 rsa_key = common.MakeTempFile(prefix="key-", suffix=".key")
1081 cmd.extend(["-out", rsa_key])
Christian Oderf63e2cd2017-05-01 22:30:15 +02001082 p1 = common.Run(cmd, verbose=False, stdout=log_file, stderr=subprocess.STDOUT)
Tao Bao6047c242016-06-21 13:35:26 -07001083 p1.communicate()
Tao Baodea0f8b2016-06-20 17:55:06 -07001084 assert p1.returncode == 0, "openssl pkcs8 failed"
Tao Baoc098e9e2016-01-07 13:03:56 -08001085
Tao Baodea0f8b2016-06-20 17:55:06 -07001086 # Stage the output zip package for package signing.
Tao Baoc098e9e2016-01-07 13:03:56 -08001087 temp_zip_file = tempfile.NamedTemporaryFile()
1088 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1089 compression=zipfile.ZIP_DEFLATED)
1090
1091 # Metadata to comply with Android OTA package format.
1092 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties", None)
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -08001093 oem_dicts = None
Tao Baoc098e9e2016-01-07 13:03:56 -08001094 if oem_props:
Tao Baoebce6972017-03-06 10:22:20 -08001095 oem_dicts = _LoadOemDicts(None)
Tao Baoc098e9e2016-01-07 13:03:56 -08001096
1097 metadata = {
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -08001098 "post-build": CalculateFingerprint(oem_props, oem_dicts and oem_dicts[0],
Tao Baoc098e9e2016-01-07 13:03:56 -08001099 OPTIONS.info_dict),
Tianjie Xud06f07e2016-06-09 14:18:45 -07001100 "post-build-incremental" : GetBuildProp("ro.build.version.incremental",
1101 OPTIONS.info_dict),
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -08001102 "pre-device": GetOemProperty("ro.product.device", oem_props,
1103 oem_dicts and oem_dicts[0],
Tao Baoc098e9e2016-01-07 13:03:56 -08001104 OPTIONS.info_dict),
Tao Baod8d14be2016-02-04 14:26:02 -08001105 "ota-required-cache": "0",
1106 "ota-type": "AB",
Tao Baoc098e9e2016-01-07 13:03:56 -08001107 }
1108
1109 if source_file is not None:
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -08001110 metadata["pre-build"] = CalculateFingerprint(oem_props,
1111 oem_dicts and oem_dicts[0],
Tao Baoc098e9e2016-01-07 13:03:56 -08001112 OPTIONS.source_info_dict)
Tianjie Xud06f07e2016-06-09 14:18:45 -07001113 metadata["pre-build-incremental"] = GetBuildProp(
1114 "ro.build.version.incremental", OPTIONS.source_info_dict)
Tao Baoc098e9e2016-01-07 13:03:56 -08001115
Tao Baob31892e2017-02-07 11:21:17 -08001116 HandleDowngradeMetadata(metadata)
1117 else:
1118 metadata["post-timestamp"] = GetBuildProp(
1119 "ro.build.date.utc", OPTIONS.info_dict)
1120
Tao Baoc098e9e2016-01-07 13:03:56 -08001121 # 1. Generate payload.
1122 payload_file = common.MakeTempFile(prefix="payload-", suffix=".bin")
1123 cmd = ["brillo_update_payload", "generate",
1124 "--payload", payload_file,
1125 "--target_image", target_file]
1126 if source_file is not None:
1127 cmd.extend(["--source_image", source_file])
Tao Baoff1b86e2017-10-03 14:17:57 -07001128 if OPTIONS.downgrade:
1129 max_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
1130 else:
1131 max_timestamp = metadata["post-timestamp"]
1132 cmd.extend(["--max_timestamp", max_timestamp])
Alex Deymod8d96ec2016-06-10 16:38:31 -07001133 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1134 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001135 assert p1.returncode == 0, "brillo_update_payload generate failed"
1136
1137 # 2. Generate hashes of the payload and metadata files.
1138 payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
1139 metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
1140 cmd = ["brillo_update_payload", "hash",
1141 "--unsigned_payload", payload_file,
1142 "--signature_size", "256",
1143 "--metadata_hash_file", metadata_sig_file,
1144 "--payload_hash_file", payload_sig_file]
Alex Deymod8d96ec2016-06-10 16:38:31 -07001145 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1146 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001147 assert p1.returncode == 0, "brillo_update_payload hash failed"
1148
1149 # 3. Sign the hashes and insert them back into the payload file.
1150 signed_payload_sig_file = common.MakeTempFile(prefix="signed-sig-",
1151 suffix=".bin")
1152 signed_metadata_sig_file = common.MakeTempFile(prefix="signed-sig-",
1153 suffix=".bin")
1154 # 3a. Sign the payload hash.
Tao Baodea0f8b2016-06-20 17:55:06 -07001155 if OPTIONS.payload_signer is not None:
Baligh Uddin2abbbd02016-06-22 12:14:16 -07001156 cmd = [OPTIONS.payload_signer]
1157 cmd.extend(OPTIONS.payload_signer_args)
Tao Baodea0f8b2016-06-20 17:55:06 -07001158 else:
1159 cmd = ["openssl", "pkeyutl", "-sign",
1160 "-inkey", rsa_key,
1161 "-pkeyopt", "digest:sha256"]
1162 cmd.extend(["-in", payload_sig_file,
1163 "-out", signed_payload_sig_file])
Alex Deymod8d96ec2016-06-10 16:38:31 -07001164 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1165 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001166 assert p1.returncode == 0, "openssl sign payload failed"
1167
1168 # 3b. Sign the metadata hash.
Tao Baodea0f8b2016-06-20 17:55:06 -07001169 if OPTIONS.payload_signer is not None:
Baligh Uddin2abbbd02016-06-22 12:14:16 -07001170 cmd = [OPTIONS.payload_signer]
1171 cmd.extend(OPTIONS.payload_signer_args)
Tao Baodea0f8b2016-06-20 17:55:06 -07001172 else:
1173 cmd = ["openssl", "pkeyutl", "-sign",
1174 "-inkey", rsa_key,
1175 "-pkeyopt", "digest:sha256"]
1176 cmd.extend(["-in", metadata_sig_file,
1177 "-out", signed_metadata_sig_file])
Alex Deymod8d96ec2016-06-10 16:38:31 -07001178 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1179 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001180 assert p1.returncode == 0, "openssl sign metadata failed"
1181
1182 # 3c. Insert the signatures back into the payload file.
1183 signed_payload_file = common.MakeTempFile(prefix="signed-payload-",
1184 suffix=".bin")
1185 cmd = ["brillo_update_payload", "sign",
1186 "--unsigned_payload", payload_file,
1187 "--payload", signed_payload_file,
1188 "--signature_size", "256",
1189 "--metadata_signature_file", signed_metadata_sig_file,
1190 "--payload_signature_file", signed_payload_sig_file]
Alex Deymod8d96ec2016-06-10 16:38:31 -07001191 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1192 p1.communicate()
Tao Baoc098e9e2016-01-07 13:03:56 -08001193 assert p1.returncode == 0, "brillo_update_payload sign failed"
1194
Alex Deymo19241c12016-02-04 22:29:29 -08001195 # 4. Dump the signed payload properties.
1196 properties_file = common.MakeTempFile(prefix="payload-properties-",
1197 suffix=".txt")
1198 cmd = ["brillo_update_payload", "properties",
1199 "--payload", signed_payload_file,
1200 "--properties_file", properties_file]
Alex Deymod8d96ec2016-06-10 16:38:31 -07001201 p1 = common.Run(cmd, stdout=log_file, stderr=subprocess.STDOUT)
1202 p1.communicate()
Alex Deymo19241c12016-02-04 22:29:29 -08001203 assert p1.returncode == 0, "brillo_update_payload properties failed"
1204
Tao Bao7c5dc572016-06-14 17:48:11 -07001205 if OPTIONS.wipe_user_data:
1206 with open(properties_file, "a") as f:
1207 f.write("POWERWASH=1\n")
1208 metadata["ota-wipe"] = "yes"
1209
Tao Baoc96316c2017-01-24 22:10:49 -08001210 # Add the signed payload file and properties into the zip. In order to
1211 # support streaming, we pack payload.bin, payload_properties.txt and
1212 # care_map.txt as ZIP_STORED. So these entries can be read directly with
1213 # the offset and length pairs.
Tao Baoc098e9e2016-01-07 13:03:56 -08001214 common.ZipWrite(output_zip, signed_payload_file, arcname="payload.bin",
1215 compress_type=zipfile.ZIP_STORED)
Tao Baoc96316c2017-01-24 22:10:49 -08001216 common.ZipWrite(output_zip, properties_file,
1217 arcname="payload_properties.txt",
1218 compress_type=zipfile.ZIP_STORED)
Tao Baoc098e9e2016-01-07 13:03:56 -08001219
Tianjie Xucfa86222016-03-07 16:31:19 -08001220 # If dm-verity is supported for the device, copy contents of care_map
1221 # into A/B OTA package.
Tao Bao21803d32017-04-19 10:16:09 -07001222 target_zip = zipfile.ZipFile(target_file, "r")
Tianjie Xu6b2e1552017-06-01 11:32:32 -07001223 if (OPTIONS.info_dict.get("verity") == "true" or
Bowgo Tsai3e599ea2017-05-26 18:30:04 +08001224 OPTIONS.info_dict.get("avb_enable") == "true"):
Tianjie Xucfa86222016-03-07 16:31:19 -08001225 care_map_path = "META/care_map.txt"
1226 namelist = target_zip.namelist()
1227 if care_map_path in namelist:
1228 care_map_data = target_zip.read(care_map_path)
Tao Baoc96316c2017-01-24 22:10:49 -08001229 common.ZipWriteStr(output_zip, "care_map.txt", care_map_data,
1230 compress_type=zipfile.ZIP_STORED)
Tianjie Xucfa86222016-03-07 16:31:19 -08001231 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001232 print("Warning: cannot find care map file in target_file package")
Tao Bao21803d32017-04-19 10:16:09 -07001233
Tao Baobcd1d162017-08-26 13:10:26 -07001234 # OPTIONS.source_info_dict must be None for incrementals.
1235 if source_file is None:
1236 assert OPTIONS.source_info_dict is None
Tao Bao21803d32017-04-19 10:16:09 -07001237
Tao Baobcd1d162017-08-26 13:10:26 -07001238 AddCompatibilityArchiveIfTrebleEnabled(
1239 target_zip, output_zip, OPTIONS.info_dict, OPTIONS.source_info_dict)
Tao Bao21803d32017-04-19 10:16:09 -07001240
Tao Bao21803d32017-04-19 10:16:09 -07001241 common.ZipClose(target_zip)
Tianjie Xucfa86222016-03-07 16:31:19 -08001242
Tao Bao2dd1c482017-02-03 16:49:39 -08001243 # Write the current metadata entry with placeholders.
Tao Baobfdcb122017-01-31 15:06:05 -08001244 metadata['ota-streaming-property-files'] = ComputeStreamingMetadata(
Tao Bao2dd1c482017-02-03 16:49:39 -08001245 output_zip, reserve_space=True)
Tao Baoc96316c2017-01-24 22:10:49 -08001246 WriteMetadata(metadata, output_zip)
1247 common.ZipClose(output_zip)
1248
Tao Bao2dd1c482017-02-03 16:49:39 -08001249 # SignOutput(), which in turn calls signapk.jar, will possibly reorder the
1250 # zip entries, as well as padding the entry headers. We do a preliminary
1251 # signing (with an incomplete metadata entry) to allow that to happen. Then
1252 # compute the zip entry offsets, write back the final metadata and do the
1253 # final signing.
1254 prelim_signing = tempfile.NamedTemporaryFile()
1255 SignOutput(temp_zip_file.name, prelim_signing.name)
1256 common.ZipClose(temp_zip_file)
Tao Baoc96316c2017-01-24 22:10:49 -08001257
Tao Bao2dd1c482017-02-03 16:49:39 -08001258 # Open the signed zip. Compute the final metadata that's needed for streaming.
1259 prelim_zip = zipfile.ZipFile(prelim_signing, "r",
1260 compression=zipfile.ZIP_DEFLATED)
1261 expected_length = len(metadata['ota-streaming-property-files'])
1262 metadata['ota-streaming-property-files'] = ComputeStreamingMetadata(
1263 prelim_zip, reserve_space=False, expected_length=expected_length)
1264
1265 # Copy the zip entries, as we cannot update / delete entries with zipfile.
1266 final_signing = tempfile.NamedTemporaryFile()
1267 output_zip = zipfile.ZipFile(final_signing, "w",
1268 compression=zipfile.ZIP_DEFLATED)
1269 for item in prelim_zip.infolist():
1270 if item.filename == METADATA_NAME:
1271 continue
1272
1273 data = prelim_zip.read(item.filename)
1274 out_info = copy.copy(item)
1275 common.ZipWriteStr(output_zip, out_info, data)
1276
1277 # Now write the final metadata entry.
1278 WriteMetadata(metadata, output_zip)
1279 common.ZipClose(prelim_zip)
1280 common.ZipClose(output_zip)
1281
1282 # Re-sign the package after updating the metadata entry.
1283 SignOutput(final_signing.name, output_file)
1284 final_signing.close()
1285
1286 # Reopen the final signed zip to double check the streaming metadata.
Tao Baoc96316c2017-01-24 22:10:49 -08001287 output_zip = zipfile.ZipFile(output_file, "r")
Tao Bao2dd1c482017-02-03 16:49:39 -08001288 actual = metadata['ota-streaming-property-files'].strip()
1289 expected = ComputeStreamingMetadata(output_zip)
1290 assert actual == expected, \
1291 "Mismatching streaming metadata: %s vs %s." % (actual, expected)
Tao Baoc96316c2017-01-24 22:10:49 -08001292 common.ZipClose(output_zip)
1293
Tao Baoc098e9e2016-01-07 13:03:56 -08001294
Doug Zongkereef39442009-04-02 12:14:19 -07001295def main(argv):
1296
1297 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001298 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001299 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001300 elif o in ("-k", "--package_key"):
1301 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001302 elif o in ("-i", "--incremental_from"):
1303 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001304 elif o == "--full_radio":
1305 OPTIONS.full_radio = True
leozwangaa6c1a12015-08-14 10:57:58 -07001306 elif o == "--full_bootloader":
1307 OPTIONS.full_bootloader = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001308 elif o in ("-w", "--wipe_user_data"):
1309 OPTIONS.wipe_user_data = True
Tao Bao5d182562016-02-23 11:38:39 -08001310 elif o == "--downgrade":
1311 OPTIONS.downgrade = True
1312 OPTIONS.wipe_user_data = True
Tao Bao3e6161a2017-02-28 11:48:48 -08001313 elif o == "--override_timestamp":
1314 OPTIONS.timestamp = True
Michael Runge6e836112014-04-15 17:40:21 -07001315 elif o in ("-o", "--oem_settings"):
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -08001316 OPTIONS.oem_source = a.split(',')
Tao Bao8608cde2016-02-25 19:49:55 -08001317 elif o == "--oem_no_mount":
1318 OPTIONS.oem_no_mount = True
Doug Zongker1c390a22009-05-14 19:06:36 -07001319 elif o in ("-e", "--extra_script"):
1320 OPTIONS.extra_script = a
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001321 elif o in ("-t", "--worker_threads"):
1322 if a.isdigit():
1323 OPTIONS.worker_threads = int(a)
1324 else:
1325 raise ValueError("Cannot parse value %r for option %r - only "
1326 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001327 elif o in ("-2", "--two_step"):
1328 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001329 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001330 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001331 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001332 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001333 elif o == "--block":
1334 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001335 elif o in ("-b", "--binary"):
1336 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001337 elif o in ("--no_fallback_to_full",):
1338 OPTIONS.fallback_to_full = False
Tao Bao8dcf7382015-05-21 14:09:49 -07001339 elif o == "--stash_threshold":
1340 try:
1341 OPTIONS.stash_threshold = float(a)
1342 except ValueError:
1343 raise ValueError("Cannot parse value %r for option %r - expecting "
1344 "a float" % (a, o))
Tao Bao9bc6bb22015-11-09 16:58:28 -08001345 elif o == "--gen_verify":
1346 OPTIONS.gen_verify = True
Tao Baod62c6032015-11-30 09:40:20 -08001347 elif o == "--log_diff":
1348 OPTIONS.log_diff = a
Tao Baodea0f8b2016-06-20 17:55:06 -07001349 elif o == "--payload_signer":
1350 OPTIONS.payload_signer = a
Baligh Uddin2abbbd02016-06-22 12:14:16 -07001351 elif o == "--payload_signer_args":
1352 OPTIONS.payload_signer_args = shlex.split(a)
Dan Willemsencea5cd22017-03-21 14:44:27 -07001353 elif o == "--extracted_input_target_files":
1354 OPTIONS.extracted_input = a
Doug Zongkereef39442009-04-02 12:14:19 -07001355 else:
1356 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001357 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001358
1359 args = common.ParseOptions(argv, __doc__,
Tao Bao2a0d1da2017-01-13 11:56:54 -08001360 extra_opts="b:k:i:d:we:t:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001361 extra_long_opts=[
1362 "board_config=",
1363 "package_key=",
1364 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001365 "full_radio",
leozwangaa6c1a12015-08-14 10:57:58 -07001366 "full_bootloader",
Dan Albert8b72aef2015-03-23 19:13:21 -07001367 "wipe_user_data",
Tao Bao5d182562016-02-23 11:38:39 -08001368 "downgrade",
Tao Bao3e6161a2017-02-28 11:48:48 -08001369 "override_timestamp",
Dan Albert8b72aef2015-03-23 19:13:21 -07001370 "extra_script=",
1371 "worker_threads=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001372 "two_step",
1373 "no_signing",
1374 "block",
1375 "binary=",
1376 "oem_settings=",
Tao Bao8608cde2016-02-25 19:49:55 -08001377 "oem_no_mount",
Dan Albert8b72aef2015-03-23 19:13:21 -07001378 "verify",
1379 "no_fallback_to_full",
Tao Bao8dcf7382015-05-21 14:09:49 -07001380 "stash_threshold=",
Tao Baod62c6032015-11-30 09:40:20 -08001381 "gen_verify",
1382 "log_diff=",
Tao Baodea0f8b2016-06-20 17:55:06 -07001383 "payload_signer=",
Baligh Uddin2abbbd02016-06-22 12:14:16 -07001384 "payload_signer_args=",
Dan Willemsencea5cd22017-03-21 14:44:27 -07001385 "extracted_input_target_files=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001386 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001387
1388 if len(args) != 2:
1389 common.Usage(__doc__)
1390 sys.exit(1)
1391
Tao Bao5d182562016-02-23 11:38:39 -08001392 if OPTIONS.downgrade:
1393 # Sanity check to enforce a data wipe.
1394 if not OPTIONS.wipe_user_data:
1395 raise ValueError("Cannot downgrade without a data wipe")
1396
1397 # We should only allow downgrading incrementals (as opposed to full).
1398 # Otherwise the device may go back from arbitrary build with this full
1399 # OTA package.
1400 if OPTIONS.incremental_source is None:
Elliott Hughesd8a52f92016-06-20 14:35:47 -07001401 raise ValueError("Cannot generate downgradable full OTAs")
Tao Bao5d182562016-02-23 11:38:39 -08001402
Tao Bao3e6161a2017-02-28 11:48:48 -08001403 assert not (OPTIONS.downgrade and OPTIONS.timestamp), \
1404 "Cannot have --downgrade AND --override_timestamp both"
1405
Tao Baoc098e9e2016-01-07 13:03:56 -08001406 # Load the dict file from the zip directly to have a peek at the OTA type.
1407 # For packages using A/B update, unzipping is not needed.
Dan Willemsencea5cd22017-03-21 14:44:27 -07001408 if OPTIONS.extracted_input is not None:
1409 OPTIONS.info_dict = common.LoadInfoDict(OPTIONS.extracted_input, OPTIONS.extracted_input)
1410 else:
1411 input_zip = zipfile.ZipFile(args[0], "r")
1412 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
1413 common.ZipClose(input_zip)
Tao Baoc098e9e2016-01-07 13:03:56 -08001414
1415 ab_update = OPTIONS.info_dict.get("ab_update") == "true"
1416
Christian Oderf63e2cd2017-05-01 22:30:15 +02001417 # Use the default key to sign the package if not specified with package_key.
1418 # package_keys are needed on ab_updates, so always define them if an
1419 # ab_update is getting created.
1420 if not OPTIONS.no_signing or ab_update:
1421 if OPTIONS.package_key is None:
1422 OPTIONS.package_key = OPTIONS.info_dict.get(
1423 "default_system_dev_certificate",
1424 "build/target/product/security/testkey")
1425 # Get signing keys
1426 OPTIONS.key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
1427
Tao Baoc098e9e2016-01-07 13:03:56 -08001428 if ab_update:
1429 if OPTIONS.incremental_source is not None:
1430 OPTIONS.target_info_dict = OPTIONS.info_dict
1431 source_zip = zipfile.ZipFile(OPTIONS.incremental_source, "r")
1432 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1433 common.ZipClose(source_zip)
1434
1435 if OPTIONS.verbose:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001436 print("--- target info ---")
Tao Baoc098e9e2016-01-07 13:03:56 -08001437 common.DumpInfoDict(OPTIONS.info_dict)
1438
1439 if OPTIONS.incremental_source is not None:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001440 print("--- source info ---")
Tao Baoc098e9e2016-01-07 13:03:56 -08001441 common.DumpInfoDict(OPTIONS.source_info_dict)
1442
1443 WriteABOTAPackageWithBrilloScript(
1444 target_file=args[0],
1445 output_file=args[1],
1446 source_file=OPTIONS.incremental_source)
1447
Tao Bao89fbb0f2017-01-10 10:47:58 -08001448 print("done.")
Tao Baoc098e9e2016-01-07 13:03:56 -08001449 return
1450
Doug Zongker1c390a22009-05-14 19:06:36 -07001451 if OPTIONS.extra_script is not None:
1452 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1453
Dan Willemsencea5cd22017-03-21 14:44:27 -07001454 if OPTIONS.extracted_input is not None:
1455 OPTIONS.input_tmp = OPTIONS.extracted_input
1456 OPTIONS.target_tmp = OPTIONS.input_tmp
1457 OPTIONS.info_dict = common.LoadInfoDict(OPTIONS.input_tmp, OPTIONS.input_tmp)
1458 input_zip = zipfile.ZipFile(args[0], "r")
1459 else:
1460 print("unzipping target target-files...")
1461 OPTIONS.input_tmp, input_zip = common.UnzipTemp(
1462 args[0], UNZIP_PATTERN)
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001463
Dan Willemsencea5cd22017-03-21 14:44:27 -07001464 OPTIONS.target_tmp = OPTIONS.input_tmp
1465 OPTIONS.info_dict = common.LoadInfoDict(input_zip, OPTIONS.target_tmp)
Kenny Roote2e9f612013-05-29 12:59:35 -07001466
Doug Zongker37974732010-09-16 17:44:38 -07001467 if OPTIONS.verbose:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001468 print("--- target info ---")
Doug Zongker37974732010-09-16 17:44:38 -07001469 common.DumpInfoDict(OPTIONS.info_dict)
1470
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001471 # If the caller explicitly specified the device-specific extensions
1472 # path via -s/--device_specific, use that. Otherwise, use
1473 # META/releasetools.py if it is present in the target target_files.
1474 # Otherwise, take the path of the file from 'tool_extensions' in the
1475 # info dict and look for that in the local filesystem, relative to
1476 # the current directory.
1477
Doug Zongker37974732010-09-16 17:44:38 -07001478 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001479 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1480 if os.path.exists(from_input):
Tao Bao89fbb0f2017-01-10 10:47:58 -08001481 print("(using device-specific extensions from target_files)")
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001482 OPTIONS.device_specific = from_input
1483 else:
1484 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1485
Doug Zongker37974732010-09-16 17:44:38 -07001486 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001487 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001488
Tao Baoc098e9e2016-01-07 13:03:56 -08001489 if OPTIONS.info_dict.get("no_recovery") == "true":
Tao Baodb45efa2015-10-27 19:25:18 -07001490 raise common.ExternalError(
1491 "--- target build has specified no recovery ---")
1492
Tao Bao767e3ac2015-11-10 12:19:19 -08001493 # Set up the output zip. Create a temporary zip file if signing is needed.
1494 if OPTIONS.no_signing:
1495 if os.path.exists(args[1]):
1496 os.unlink(args[1])
1497 output_zip = zipfile.ZipFile(args[1], "w",
1498 compression=zipfile.ZIP_DEFLATED)
1499 else:
1500 temp_zip_file = tempfile.NamedTemporaryFile()
1501 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1502 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001503
Daniel Rosenberg40ef35b2015-11-10 19:21:34 -08001504 # Non A/B OTAs rely on /cache partition to store temporary files.
Tao Bao767e3ac2015-11-10 12:19:19 -08001505 cache_size = OPTIONS.info_dict.get("cache_size", None)
Tao Baoc098e9e2016-01-07 13:03:56 -08001506 if cache_size is None:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001507 print("--- can't determine the cache partition size ---")
Tao Bao767e3ac2015-11-10 12:19:19 -08001508 OPTIONS.cache_size = cache_size
Tao Bao8dcf7382015-05-21 14:09:49 -07001509
Tao Bao9bc6bb22015-11-09 16:58:28 -08001510 # Generate a verify package.
1511 if OPTIONS.gen_verify:
1512 WriteVerifyPackage(input_zip, output_zip)
1513
Tao Bao767e3ac2015-11-10 12:19:19 -08001514 # Generate a full OTA.
Tao Bao9bc6bb22015-11-09 16:58:28 -08001515 elif OPTIONS.incremental_source is None:
Tao Baoc098e9e2016-01-07 13:03:56 -08001516 WriteFullOTAPackage(input_zip, output_zip)
Tao Bao767e3ac2015-11-10 12:19:19 -08001517
1518 # Generate an incremental OTA. It will fall back to generate a full OTA on
1519 # failure unless no_fallback_to_full is specified.
1520 else:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001521 print("unzipping source target-files...")
Tao Bao767e3ac2015-11-10 12:19:19 -08001522 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
Tao Bao6b0b2f92017-03-05 11:38:11 -08001523 OPTIONS.incremental_source,
Tao Bao457cbf62017-03-06 09:56:01 -08001524 UNZIP_PATTERN)
Tao Bao767e3ac2015-11-10 12:19:19 -08001525 OPTIONS.target_info_dict = OPTIONS.info_dict
1526 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip,
1527 OPTIONS.source_tmp)
1528 if OPTIONS.verbose:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001529 print("--- source info ---")
Tao Bao767e3ac2015-11-10 12:19:19 -08001530 common.DumpInfoDict(OPTIONS.source_info_dict)
1531 try:
Tao Bao457cbf62017-03-06 09:56:01 -08001532 WriteBlockIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Baod62c6032015-11-30 09:40:20 -08001533 if OPTIONS.log_diff:
1534 out_file = open(OPTIONS.log_diff, 'w')
1535 import target_files_diff
1536 target_files_diff.recursiveDiff('',
1537 OPTIONS.source_tmp,
1538 OPTIONS.input_tmp,
1539 out_file)
1540 out_file.close()
Tao Bao767e3ac2015-11-10 12:19:19 -08001541 except ValueError:
1542 if not OPTIONS.fallback_to_full:
1543 raise
Tao Bao89fbb0f2017-01-10 10:47:58 -08001544 print("--- failed to build incremental; falling back to full ---")
Tao Bao767e3ac2015-11-10 12:19:19 -08001545 OPTIONS.incremental_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -07001546 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001547
Tao Bao767e3ac2015-11-10 12:19:19 -08001548 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001549
Tao Bao767e3ac2015-11-10 12:19:19 -08001550 # Sign the generated zip package unless no_signing is specified.
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001551 if not OPTIONS.no_signing:
1552 SignOutput(temp_zip_file.name, args[1])
1553 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001554
Tao Bao89fbb0f2017-01-10 10:47:58 -08001555 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001556
1557
1558if __name__ == '__main__':
1559 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001560 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001561 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001562 except common.ExternalError as e:
Tao Bao89fbb0f2017-01-10 10:47:58 -08001563 print("\n ERROR: %s\n" % (e,))
Doug Zongkereef39442009-04-02 12:14:19 -07001564 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001565 finally:
1566 common.Cleanup()