blob: 8923a0532c653e06e2d18088652664bfd0a1482a [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
Michael Runge6e836112014-04-15 17:40:21 -070053 -o (--oem_settings) <file>
54 Use the file to specify the expected OEM-specific properties
55 on the OEM partition of the intended device.
56
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
Doug Zongkerdbfaae52009-04-21 17:12:54 -070063 -w (--wipe_user_data)
64 Generate an OTA package that will wipe the user data partition
65 when installed.
66
Doug Zongker962069c2009-04-23 11:41:58 -070067 -n (--no_prereq)
68 Omit the timestamp prereq check normally included at the top of
69 the build scripts (used for developer OTA packages which
70 legitimately need to go back and forth).
71
Tao Bao5d182562016-02-23 11:38:39 -080072 --downgrade
73 Intentionally generate an incremental OTA that updates from a newer
74 build to an older one (based on timestamp comparison). "post-timestamp"
75 will be replaced by "ota-downgrade=yes" in the metadata file. A data
76 wipe will always be enforced, so "ota-wipe=yes" will also be included in
77 the metadata file.
78
Doug Zongker1c390a22009-05-14 19:06:36 -070079 -e (--extra_script) <file>
80 Insert the contents of file at the end of the update script.
81
Hristo Bojinovdafb0422010-08-26 14:35:16 -070082 -a (--aslr_mode) <on|off>
83 Specify whether to turn on ASLR for the package (on by default).
Stephen Smalley56882bf2012-02-09 13:36:21 -050084
Doug Zongker9b23f2c2013-11-25 14:44:12 -080085 -2 (--two_step)
86 Generate a 'two-step' OTA package, where recovery is updated
87 first, so that any changes made to the system partition are done
88 using the new recovery (new kernel, etc.).
89
Doug Zongker26e66192014-02-20 13:22:07 -080090 --block
91 Generate a block-based OTA if possible. Will fall back to a
92 file-based OTA if the target_files is older and doesn't support
93 block-based OTAs.
94
Doug Zongker25568482014-03-03 10:21:27 -080095 -b (--binary) <file>
96 Use the given binary as the update-binary in the output package,
97 instead of the binary in the build's target_files. Use for
98 development only.
99
Martin Blumenstingl374e1142014-05-31 20:42:55 +0200100 -t (--worker_threads) <int>
101 Specifies the number of worker-threads that will be used when
102 generating patches for incremental updates (defaults to 3).
103
Tao Bao8dcf7382015-05-21 14:09:49 -0700104 --stash_threshold <float>
105 Specifies the threshold that will be used to compute the maximum
106 allowed stash size (defaults to 0.8).
Tao Bao9bc6bb22015-11-09 16:58:28 -0800107
108 --gen_verify
109 Generate an OTA package that verifies the partitions.
Tao Baod62c6032015-11-30 09:40:20 -0800110
111 --log_diff <file>
112 Generate a log file that shows the differences in the source and target
113 builds for an incremental package. This option is only meaningful when
114 -i is specified.
Doug Zongkereef39442009-04-02 12:14:19 -0700115"""
116
117import sys
118
Doug Zongkercf6d5a92014-02-18 10:57:07 -0800119if sys.hexversion < 0x02070000:
120 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -0700121 sys.exit(1)
122
Doug Zongkerfc44a512014-08-26 13:10:25 -0700123import multiprocessing
Doug Zongkereef39442009-04-02 12:14:19 -0700124import os
Tao Baoc098e9e2016-01-07 13:03:56 -0800125import subprocess
Doug Zongkereef39442009-04-02 12:14:19 -0700126import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -0700127import zipfile
128
129import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700130import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -0700131import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700132
133OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700134OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700135OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700136OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700137OPTIONS.require_verbatim = set()
138OPTIONS.prohibit_verbatim = set(("system/build.prop",))
139OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700140OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700141OPTIONS.omit_prereq = False
Tao Bao5d182562016-02-23 11:38:39 -0800142OPTIONS.downgrade = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700143OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700144OPTIONS.aslr_mode = True
Doug Zongkerfc44a512014-08-26 13:10:25 -0700145OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
146if OPTIONS.worker_threads == 0:
147 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800148OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900149OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800150OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800151OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700152OPTIONS.oem_source = None
Tao Bao8608cde2016-02-25 19:49:55 -0800153OPTIONS.oem_no_mount = False
Doug Zongker62d4f182014-08-04 16:06:43 -0700154OPTIONS.fallback_to_full = True
Tao Bao43078aa2015-04-21 14:32:35 -0700155OPTIONS.full_radio = False
leozwangaa6c1a12015-08-14 10:57:58 -0700156OPTIONS.full_bootloader = False
Tao Baod47d8e12015-05-21 14:09:49 -0700157# Stash size cannot exceed cache_size * threshold.
158OPTIONS.cache_size = None
159OPTIONS.stash_threshold = 0.8
Tao Bao9bc6bb22015-11-09 16:58:28 -0800160OPTIONS.gen_verify = False
Tao Baod62c6032015-11-30 09:40:20 -0800161OPTIONS.log_diff = None
Tao Bao8dcf7382015-05-21 14:09:49 -0700162
Doug Zongkereef39442009-04-02 12:14:19 -0700163def MostPopularKey(d, default):
164 """Given a dict, return the key corresponding to the largest
165 value. Returns 'default' if the dict is empty."""
166 x = [(v, k) for (k, v) in d.iteritems()]
Dan Albert8b72aef2015-03-23 19:13:21 -0700167 if not x:
168 return default
Doug Zongkereef39442009-04-02 12:14:19 -0700169 x.sort()
170 return x[-1][1]
171
172
173def IsSymlink(info):
174 """Return true if the zipfile.ZipInfo object passed in represents a
175 symlink."""
Ying Wang2ffb3142015-07-06 14:02:01 -0700176 return (info.external_attr >> 16) & 0o770000 == 0o120000
Doug Zongkereef39442009-04-02 12:14:19 -0700177
Hristo Bojinov96be7202010-08-02 10:26:17 -0700178def IsRegular(info):
179 """Return true if the zipfile.ZipInfo object passed in represents a
Ying Wang2ffb3142015-07-06 14:02:01 -0700180 regular file."""
181 return (info.external_attr >> 16) & 0o770000 == 0o100000
Doug Zongkereef39442009-04-02 12:14:19 -0700182
Michael Runge4038aa82013-12-13 18:06:28 -0800183def ClosestFileMatch(src, tgtfiles, existing):
184 """Returns the closest file match between a source file and list
185 of potential matches. The exact filename match is preferred,
186 then the sha1 is searched for, and finally a file with the same
187 basename is evaluated. Rename support in the updater-binary is
188 required for the latter checks to be used."""
189
190 result = tgtfiles.get("path:" + src.name)
191 if result is not None:
192 return result
193
194 if not OPTIONS.target_info_dict.get("update_rename_support", False):
195 return None
196
197 if src.size < 1000:
198 return None
199
200 result = tgtfiles.get("sha1:" + src.sha1)
201 if result is not None and existing.get(result.name) is None:
202 return result
203 result = tgtfiles.get("file:" + src.name.split("/")[-1])
204 if result is not None and existing.get(result.name) is None:
205 return result
206 return None
207
Dan Albert8b72aef2015-03-23 19:13:21 -0700208class ItemSet(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700209 def __init__(self, partition, fs_config):
210 self.partition = partition
211 self.fs_config = fs_config
212 self.ITEMS = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700213
Dan Albert8b72aef2015-03-23 19:13:21 -0700214 def Get(self, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700215 if name not in self.ITEMS:
Dan Albert8b72aef2015-03-23 19:13:21 -0700216 self.ITEMS[name] = Item(self, name, is_dir=is_dir)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700217 return self.ITEMS[name]
Doug Zongkereef39442009-04-02 12:14:19 -0700218
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700219 def GetMetadata(self, input_zip):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700220 # The target_files contains a record of what the uid,
221 # gid, and mode are supposed to be.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700222 output = input_zip.read(self.fs_config)
Doug Zongkereef39442009-04-02 12:14:19 -0700223
224 for line in output.split("\n"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700225 if not line:
226 continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700227 columns = line.split()
228 name, uid, gid, mode = columns[:4]
229 selabel = None
230 capabilities = None
231
232 # After the first 4 columns, there are a series of key=value
233 # pairs. Extract out the fields we care about.
234 for element in columns[4:]:
235 key, value = element.split("=")
236 if key == "selabel":
237 selabel = value
238 if key == "capabilities":
239 capabilities = value
240
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700241 i = self.ITEMS.get(name, None)
Doug Zongker283e2a12010-03-15 17:52:32 -0700242 if i is not None:
243 i.uid = int(uid)
244 i.gid = int(gid)
245 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700246 i.selabel = selabel
247 i.capabilities = capabilities
Dan Albert8b72aef2015-03-23 19:13:21 -0700248 if i.is_dir:
Doug Zongker283e2a12010-03-15 17:52:32 -0700249 i.children.sort(key=lambda i: i.name)
250
Tao Baof2cffbd2015-07-22 12:33:18 -0700251 # Set metadata for the files generated by this script. For full recovery
252 # image at system/etc/recovery.img, it will be taken care by fs_config.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700253 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700254 if i:
255 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700256 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700257 if i:
258 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700259
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700260
Dan Albert8b72aef2015-03-23 19:13:21 -0700261class Item(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700262 """Items represent the metadata (user, group, mode) of files and
263 directories in the system image."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700264 def __init__(self, itemset, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700265 self.itemset = itemset
266 self.name = name
267 self.uid = None
268 self.gid = None
269 self.mode = None
270 self.selabel = None
271 self.capabilities = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700272 self.is_dir = is_dir
273 self.descendants = None
274 self.best_subtree = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700275
276 if name:
Dan Albert8b72aef2015-03-23 19:13:21 -0700277 self.parent = itemset.Get(os.path.dirname(name), is_dir=True)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700278 self.parent.children.append(self)
279 else:
280 self.parent = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700281 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700282 self.children = []
283
284 def Dump(self, indent=0):
285 if self.uid is not None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700286 print "%s%s %d %d %o" % (
287 " " * indent, self.name, self.uid, self.gid, self.mode)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700288 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700289 print "%s%s %s %s %s" % (
290 " " * indent, self.name, self.uid, self.gid, self.mode)
291 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700292 print "%s%s" % (" "*indent, self.descendants)
293 print "%s%s" % (" "*indent, self.best_subtree)
294 for i in self.children:
295 i.Dump(indent=indent+1)
296
Doug Zongkereef39442009-04-02 12:14:19 -0700297 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700298 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
Dan Albert8b72aef2015-03-23 19:13:21 -0700299 all children and determine the best strategy for using set_perm_recursive
300 and set_perm to correctly chown/chmod all the files to their desired
Doug Zongkereef39442009-04-02 12:14:19 -0700301 values. Recursively calls itself for all descendants.
302
Dan Albert8b72aef2015-03-23 19:13:21 -0700303 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count}
304 counting up all descendants of this node. (dmode or fmode may be None.)
305 Also sets the best_subtree of each directory Item to the (uid, gid, dmode,
306 fmode, selabel, capabilities) tuple that will match the most descendants of
307 that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700308 """
309
Dan Albert8b72aef2015-03-23 19:13:21 -0700310 assert self.is_dir
311 key = (self.uid, self.gid, self.mode, None, self.selabel,
312 self.capabilities)
313 self.descendants = {key: 1}
314 d = self.descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700315 for i in self.children:
Dan Albert8b72aef2015-03-23 19:13:21 -0700316 if i.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700317 for k, v in i.CountChildMetadata().iteritems():
318 d[k] = d.get(k, 0) + v
319 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700320 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700321 d[k] = d.get(k, 0) + 1
322
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700323 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
324 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700325
326 # First, find the (uid, gid) pair that matches the most
327 # descendants.
328 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700329 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700330 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
331 ug = MostPopularKey(ug, (0, 0))
332
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700333 # Now find the dmode, fmode, selabel, and capabilities that match
334 # the most descendants with that (uid, gid), and choose those.
Dan Albert8b72aef2015-03-23 19:13:21 -0700335 best_dmode = (0, 0o755)
336 best_fmode = (0, 0o644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700337 best_selabel = (0, None)
338 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700339 for k, count in d.iteritems():
Dan Albert8b72aef2015-03-23 19:13:21 -0700340 if k[:2] != ug:
341 continue
342 if k[2] is not None and count >= best_dmode[0]:
343 best_dmode = (count, k[2])
344 if k[3] is not None and count >= best_fmode[0]:
345 best_fmode = (count, k[3])
346 if k[4] is not None and count >= best_selabel[0]:
347 best_selabel = (count, k[4])
348 if k[5] is not None and count >= best_capabilities[0]:
349 best_capabilities = (count, k[5])
350 self.best_subtree = ug + (
351 best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700352
353 return d
354
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700355 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700356 """Append set_perm/set_perm_recursive commands to 'script' to
357 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700358 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700359
360 self.CountChildMetadata()
361
362 def recurse(item, current):
Dan Albert8b72aef2015-03-23 19:13:21 -0700363 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple
364 # that the current item (and all its children) have already been set to.
365 # We only need to issue set_perm/set_perm_recursive commands if we're
Doug Zongkereef39442009-04-02 12:14:19 -0700366 # supposed to be something different.
Dan Albert8b72aef2015-03-23 19:13:21 -0700367 if item.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700368 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700369 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700370 current = item.best_subtree
371
372 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700373 item.mode != current[2] or item.selabel != current[4] or \
374 item.capabilities != current[5]:
375 script.SetPermissions("/"+item.name, item.uid, item.gid,
376 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700377
378 for i in item.children:
379 recurse(i, current)
380 else:
381 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700382 item.mode != current[3] or item.selabel != current[4] or \
383 item.capabilities != current[5]:
384 script.SetPermissions("/"+item.name, item.uid, item.gid,
385 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700386
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700387 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700388
389
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700390def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
391 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700392 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800393 list of symlinks. output_zip may be None, in which case the copy is
394 skipped (but the other side effects still happen). substitute is an
395 optional dict of {output filename: contents} to be output instead of
396 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700397 """
398
399 symlinks = []
400
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700401 partition = itemset.partition
402
Doug Zongkereef39442009-04-02 12:14:19 -0700403 for info in input_zip.infolist():
Tao Baoeaf885b2015-03-23 16:01:17 -0700404 prefix = partition.upper() + "/"
405 if info.filename.startswith(prefix):
406 basefilename = info.filename[len(prefix):]
Doug Zongkereef39442009-04-02 12:14:19 -0700407 if IsSymlink(info):
408 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700409 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700410 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700411 import copy
Doug Zongkereef39442009-04-02 12:14:19 -0700412 info2 = copy.copy(info)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700413 fn = info2.filename = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700414 if substitute and fn in substitute and substitute[fn] is None:
415 continue
416 if output_zip is not None:
417 if substitute and fn in substitute:
418 data = substitute[fn]
419 else:
420 data = input_zip.read(info.filename)
Tao Bao2ed665a2015-04-01 11:21:55 -0700421 common.ZipWriteStr(output_zip, info2, data)
Doug Zongkereef39442009-04-02 12:14:19 -0700422 if fn.endswith("/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700423 itemset.Get(fn[:-1], is_dir=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700424 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700425 itemset.Get(fn)
Doug Zongkereef39442009-04-02 12:14:19 -0700426
427 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800428 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700429
430
Doug Zongkereef39442009-04-02 12:14:19 -0700431def SignOutput(temp_zip_name, output_zip_name):
432 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
433 pw = key_passwords[OPTIONS.package_key]
434
Doug Zongker951495f2009-08-14 12:44:19 -0700435 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
436 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700437
438
Dan Albert8b72aef2015-03-23 19:13:21 -0700439def AppendAssertions(script, info_dict, oem_dict=None):
Michael Runge6e836112014-04-15 17:40:21 -0700440 oem_props = info_dict.get("oem_fingerprint_properties")
Michael Runge560569a2014-09-18 15:12:45 -0700441 if oem_props is None or len(oem_props) == 0:
Michael Runge6e836112014-04-15 17:40:21 -0700442 device = GetBuildProp("ro.product.device", info_dict)
443 script.AssertDevice(device)
444 else:
445 if oem_dict is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700446 raise common.ExternalError(
447 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700448 for prop in oem_props.split():
449 if oem_dict.get(prop) is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700450 raise common.ExternalError(
451 "The OEM file is missing the property %s" % prop)
Michael Runge6e836112014-04-15 17:40:21 -0700452 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700453
Doug Zongkereef39442009-04-02 12:14:19 -0700454
Doug Zongkerc9253822014-02-04 12:17:58 -0800455def HasRecoveryPatch(target_files_zip):
Tao Baof2cffbd2015-07-22 12:33:18 -0700456 namelist = [name for name in target_files_zip.namelist()]
457 return ("SYSTEM/recovery-from-boot.p" in namelist or
458 "SYSTEM/etc/recovery.img" in namelist)
Doug Zongker73ef8252009-07-23 15:12:53 -0700459
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700460def HasVendorPartition(target_files_zip):
461 try:
462 target_files_zip.getinfo("VENDOR/")
463 return True
464 except KeyError:
465 return False
466
Michael Runge6e836112014-04-15 17:40:21 -0700467def GetOemProperty(name, oem_props, oem_dict, info_dict):
468 if oem_props is not None and name in oem_props:
469 return oem_dict[name]
470 return GetBuildProp(name, info_dict)
471
472
473def CalculateFingerprint(oem_props, oem_dict, info_dict):
474 if oem_props is None:
475 return GetBuildProp("ro.build.fingerprint", info_dict)
476 return "%s/%s/%s:%s" % (
Dan Albert8b72aef2015-03-23 19:13:21 -0700477 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
478 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
479 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
480 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700481
Doug Zongkerfc44a512014-08-26 13:10:25 -0700482
Doug Zongker3c84f562014-07-31 11:06:30 -0700483def GetImage(which, tmpdir, info_dict):
Doug Zongkerfc44a512014-08-26 13:10:25 -0700484 # Return an image object (suitable for passing to BlockImageDiff)
485 # for the 'which' partition (most be "system" or "vendor"). If a
486 # prebuilt image and file map are found in tmpdir they are used,
487 # otherwise they are reconstructed from the individual files.
Doug Zongker3c84f562014-07-31 11:06:30 -0700488
489 assert which in ("system", "vendor")
490
491 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700492 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
493 if os.path.exists(path) and os.path.exists(mappath):
Doug Zongker3c84f562014-07-31 11:06:30 -0700494 print "using %s.img from target-files" % (which,)
Doug Zongker3c84f562014-07-31 11:06:30 -0700495 # This is a 'new' target-files, which already has the image in it.
Doug Zongker3c84f562014-07-31 11:06:30 -0700496
497 else:
498 print "building %s.img from target-files" % (which,)
499
500 # This is an 'old' target-files, which does not contain images
501 # already built. Build them.
502
Doug Zongkerfc44a512014-08-26 13:10:25 -0700503 mappath = tempfile.mkstemp()[1]
504 OPTIONS.tempfiles.append(mappath)
505
Doug Zongker3c84f562014-07-31 11:06:30 -0700506 import add_img_to_target_files
507 if which == "system":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700508 path = add_img_to_target_files.BuildSystem(
509 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700510 elif which == "vendor":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700511 path = add_img_to_target_files.BuildVendor(
512 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700513
Tao Baoff777812015-05-12 11:42:31 -0700514 # Bug: http://b/20939131
515 # In ext4 filesystems, block 0 might be changed even being mounted
516 # R/O. We add it to clobbered_blocks so that it will be written to the
517 # target unconditionally. Note that they are still part of care_map.
518 clobbered_blocks = "0"
519
520 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700521
522
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700523def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700524 # TODO: how to determine this? We don't know what version it will
Tao Bao34b47bf2015-06-22 19:17:41 -0700525 # be installed on top of. For now, we expect the API just won't
526 # change very often. Similarly for fstab, it might have changed
527 # in the target build.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700528 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700529
Michael Runge6e836112014-04-15 17:40:21 -0700530 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700531 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700532 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700533 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700534 if OPTIONS.oem_source is None:
535 raise common.ExternalError("OEM source required for this build")
Tao Bao8608cde2016-02-25 19:49:55 -0800536 if not OPTIONS.oem_no_mount:
537 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700538 oem_dict = common.LoadDictionaryFromLines(
539 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -0700540
Dan Albert8b72aef2015-03-23 19:13:21 -0700541 metadata = {
542 "post-build": CalculateFingerprint(oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700543 OPTIONS.info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700544 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
545 OPTIONS.info_dict),
546 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
547 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700548
Doug Zongker05d3dea2009-06-22 11:32:31 -0700549 device_specific = common.DeviceSpecificParams(
550 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700551 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700552 output_zip=output_zip,
553 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700554 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700555 metadata=metadata,
556 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700557
Doug Zongkerc9253822014-02-04 12:17:58 -0800558 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800559 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800560
Tao Baod8d14be2016-02-04 14:26:02 -0800561 metadata["ota-type"] = "BLOCK" if block_based else "FILE"
562
Doug Zongker962069c2009-04-23 11:41:58 -0700563 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700564 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700565 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
566 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700567
Michael Runge6e836112014-04-15 17:40:21 -0700568 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700569 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800570
571 # Two-step package strategy (in chronological order, which is *not*
572 # the order in which the generated script has things):
573 #
574 # if stage is not "2/3" or "3/3":
575 # write recovery image to boot partition
576 # set stage to "2/3"
577 # reboot to boot partition and restart recovery
578 # else if stage is "2/3":
579 # write recovery image to recovery partition
580 # set stage to "3/3"
581 # reboot to recovery partition and restart recovery
582 # else:
583 # (stage must be "3/3")
584 # set stage to ""
585 # do normal full package installation:
586 # wipe and install system, boot image, etc.
587 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700588 # complete script normally
589 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800590
591 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
592 OPTIONS.input_tmp, "RECOVERY")
593 if OPTIONS.two_step:
594 if not OPTIONS.info_dict.get("multistage_support", None):
595 assert False, "two-step packages not supported by this build"
596 fs = OPTIONS.info_dict["fstab"]["/misc"]
597 assert fs.fs_type.upper() == "EMMC", \
598 "two-step packages only supported on devices with EMMC /misc partitions"
599 bcb_dev = {"bcb_dev": fs.device}
600 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
601 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700602if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800603""" % bcb_dev)
604 script.WriteRawImage("/recovery", "recovery.img")
605 script.AppendExtra("""
606set_stage("%(bcb_dev)s", "3/3");
607reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700608else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800609""" % bcb_dev)
610
Tao Bao6c55a8a2015-04-08 15:30:27 -0700611 # Dump fingerprints
612 script.Print("Target: %s" % CalculateFingerprint(
613 oem_props, oem_dict, OPTIONS.info_dict))
614
Doug Zongkere5ff5902012-01-17 10:55:37 -0800615 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700616
Doug Zongker01ce19c2014-02-04 13:48:15 -0800617 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700618
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700619 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800620 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700621 if HasVendorPartition(input_zip):
622 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700623
Stephen Smalleyd3a803e2015-08-04 14:59:06 -0400624 # Place a copy of file_contexts.bin into the OTA package which will be used
625 # by the recovery program.
Kenny Rootf32dc712012-04-08 10:42:34 -0700626 if "selinux_fc" in OPTIONS.info_dict:
627 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500628
Michael Runge7cd99ba2014-10-22 17:21:48 -0700629 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
630
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700631 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700632 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800633
Doug Zongker26e66192014-02-20 13:22:07 -0800634 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700635 # Full OTA is done as an "incremental" against an empty source
636 # image. This has the effect of writing new data from the package
637 # to the entire partition, but lets us reuse the updater code that
638 # writes incrementals to do it.
639 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
640 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700641 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700642 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800643 else:
644 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700645 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800646 if not has_recovery_patch:
647 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800648 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700649
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700650 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800651 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700652
Tao Bao7a5bf8a2015-07-21 18:01:20 -0700653 boot_img = common.GetBootableImage(
654 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800655
Doug Zongker91a99c22014-05-09 13:15:01 -0700656 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800657 def output_sink(fn, data):
658 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700659 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800660
661 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
662 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700663
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700664 system_items.GetMetadata(input_zip)
665 system_items.Get("system").SetPermissions(script)
666
667 if HasVendorPartition(input_zip):
668 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
669 script.ShowProgress(0.1, 0)
670
671 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700672 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
673 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700674 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700675 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700676 else:
677 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700678 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700679 script.UnpackPackageDir("vendor", "/vendor")
680
681 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
682 script.MakeSymlinks(symlinks)
683
684 vendor_items.GetMetadata(input_zip)
685 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700686
Doug Zongker37974732010-09-16 17:44:38 -0700687 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700688 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700689
Doug Zongker01ce19c2014-02-04 13:48:15 -0800690 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700691 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700692
Doug Zongker01ce19c2014-02-04 13:48:15 -0800693 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700694 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700695
Doug Zongker1c390a22009-05-14 19:06:36 -0700696 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700697 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700698
Doug Zongker14833602010-02-02 13:12:04 -0800699 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800700
Doug Zongker922206e2014-03-04 13:16:24 -0800701 if OPTIONS.wipe_user_data:
702 script.ShowProgress(0.1, 10)
703 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700704
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800705 if OPTIONS.two_step:
706 script.AppendExtra("""
707set_stage("%(bcb_dev)s", "");
708""" % bcb_dev)
709 script.AppendExtra("else\n")
710 script.WriteRawImage("/boot", "recovery.img")
711 script.AppendExtra("""
712set_stage("%(bcb_dev)s", "2/3");
713reboot_now("%(bcb_dev)s", "");
714endif;
715endif;
716""" % bcb_dev)
Tao Baod8d14be2016-02-04 14:26:02 -0800717
Tao Bao5d182562016-02-23 11:38:39 -0800718 script.SetProgress(1)
719 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -0800720 metadata["ota-required-cache"] = str(script.required_cache)
Doug Zongker2ea21062010-04-28 16:05:21 -0700721 WriteMetadata(metadata, output_zip)
722
Doug Zongkerfc44a512014-08-26 13:10:25 -0700723
Dan Albert8e0178d2015-01-27 15:53:15 -0800724def WritePolicyConfig(file_name, output_zip):
725 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500726
Doug Zongker2ea21062010-04-28 16:05:21 -0700727
728def WriteMetadata(metadata, output_zip):
729 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
730 "".join(["%s=%s\n" % kv
731 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700732
Doug Zongkerfc44a512014-08-26 13:10:25 -0700733
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700734def LoadPartitionFiles(z, partition):
735 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700736 ZipFile, and return a dict of {filename: File object}."""
737 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700738 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700739 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700740 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700741 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700742 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700743 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700744 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800745 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700746
747
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700748def GetBuildProp(prop, info_dict):
749 """Return the fingerprint of the build of a given target-files info_dict."""
750 try:
751 return info_dict.get("build.prop", {})[prop]
752 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700753 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700754
Doug Zongkerfc44a512014-08-26 13:10:25 -0700755
Michael Runge4038aa82013-12-13 18:06:28 -0800756def AddToKnownPaths(filename, known_paths):
757 if filename[-1] == "/":
758 return
759 dirs = filename.split("/")[:-1]
760 while len(dirs) > 0:
761 path = "/".join(dirs)
762 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700763 break
Michael Runge4038aa82013-12-13 18:06:28 -0800764 known_paths.add(path)
765 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700766
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700767
Geremy Condra36bd3652014-02-06 19:45:10 -0800768def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
Tao Bao3806c232015-07-05 21:08:33 -0700769 # TODO(tbao): We should factor out the common parts between
770 # WriteBlockIncrementalOTAPackage() and WriteIncrementalOTAPackage().
Geremy Condra36bd3652014-02-06 19:45:10 -0800771 source_version = OPTIONS.source_info_dict["recovery_api_version"]
772 target_version = OPTIONS.target_info_dict["recovery_api_version"]
773
774 if source_version == 0:
775 print ("WARNING: generating edify script for a source that "
776 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -0700777 script = edify_generator.EdifyGenerator(
778 source_version, OPTIONS.target_info_dict,
779 fstab=OPTIONS.source_info_dict["fstab"])
Geremy Condra36bd3652014-02-06 19:45:10 -0800780
Tao Bao3806c232015-07-05 21:08:33 -0700781 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
782 recovery_mount_options = OPTIONS.source_info_dict.get(
783 "recovery_mount_options")
784 oem_dict = None
785 if oem_props is not None and len(oem_props) > 0:
786 if OPTIONS.oem_source is None:
787 raise common.ExternalError("OEM source required for this build")
Tao Bao8608cde2016-02-25 19:49:55 -0800788 if not OPTIONS.oem_no_mount:
789 script.Mount("/oem", recovery_mount_options)
Tao Bao3806c232015-07-05 21:08:33 -0700790 oem_dict = common.LoadDictionaryFromLines(
791 open(OPTIONS.oem_source).readlines())
792
Dan Albert8b72aef2015-03-23 19:13:21 -0700793 metadata = {
Tao Bao3806c232015-07-05 21:08:33 -0700794 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
795 OPTIONS.source_info_dict),
Tao Baod8d14be2016-02-04 14:26:02 -0800796 "ota-type": "BLOCK",
Dan Albert8b72aef2015-03-23 19:13:21 -0700797 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800798
Tao Bao5d182562016-02-23 11:38:39 -0800799 post_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict)
800 pre_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
801 is_downgrade = long(post_timestamp) < long(pre_timestamp)
802
803 if OPTIONS.downgrade:
804 metadata["ota-downgrade"] = "yes"
805 if not is_downgrade:
806 raise RuntimeError("--downgrade specified but no downgrade detected: "
807 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
808 else:
809 if is_downgrade:
810 # Non-fatal here to allow generating such a package which may require
811 # manual work to adjust the post-timestamp. A legit use case is that we
812 # cut a new build C (after having A and B), but want to enfore the
813 # update path of A -> C -> B. Specifying --downgrade may not help since
814 # that would enforce a data wipe for C -> B update.
815 print("\nWARNING: downgrade detected: pre: %s, post: %s.\n"
816 "The package may not be deployed properly. "
817 "Try --downgrade?\n" % (pre_timestamp, post_timestamp))
818 metadata["post-timestamp"] = post_timestamp
819
Geremy Condra36bd3652014-02-06 19:45:10 -0800820 device_specific = common.DeviceSpecificParams(
821 source_zip=source_zip,
822 source_version=source_version,
823 target_zip=target_zip,
824 target_version=target_version,
825 output_zip=output_zip,
826 script=script,
827 metadata=metadata,
Tao Bao6f0b2192015-10-13 16:37:12 -0700828 info_dict=OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800829
Tao Bao3806c232015-07-05 21:08:33 -0700830 source_fp = CalculateFingerprint(oem_props, oem_dict,
831 OPTIONS.source_info_dict)
832 target_fp = CalculateFingerprint(oem_props, oem_dict,
833 OPTIONS.target_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800834 metadata["pre-build"] = source_fp
835 metadata["post-build"] = target_fp
836
837 source_boot = common.GetBootableImage(
838 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
839 OPTIONS.source_info_dict)
840 target_boot = common.GetBootableImage(
841 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
842 updating_boot = (not OPTIONS.two_step and
843 (source_boot.data != target_boot.data))
844
Geremy Condra36bd3652014-02-06 19:45:10 -0800845 target_recovery = common.GetBootableImage(
846 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800847
Doug Zongkerfc44a512014-08-26 13:10:25 -0700848 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
849 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700850
851 blockimgdiff_version = 1
852 if OPTIONS.info_dict:
853 blockimgdiff_version = max(
854 int(i) for i in
855 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
856
Tianjie Xufc3422a2015-12-15 11:53:59 -0800857 # Check first block of system partition for remount R/W only if
858 # disk type is ext4
859 system_partition = OPTIONS.source_info_dict["fstab"]["/system"]
Tao Baod8d14be2016-02-04 14:26:02 -0800860 check_first_block = system_partition.fs_type == "ext4"
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700861 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tianjie Xufc3422a2015-12-15 11:53:59 -0800862 check_first_block,
Tao Baodd2a5892015-03-12 12:32:37 -0700863 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700864
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700865 if HasVendorPartition(target_zip):
866 if not HasVendorPartition(source_zip):
867 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700868 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
869 OPTIONS.source_info_dict)
870 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
871 OPTIONS.target_info_dict)
Tianjie Xufc3422a2015-12-15 11:53:59 -0800872
873 # Check first block of vendor partition for remount R/W only if
874 # disk type is ext4
875 vendor_partition = OPTIONS.source_info_dict["fstab"]["/vendor"]
Tao Baod8d14be2016-02-04 14:26:02 -0800876 check_first_block = vendor_partition.fs_type == "ext4"
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700877 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tianjie Xufc3422a2015-12-15 11:53:59 -0800878 check_first_block,
Tao Baodd2a5892015-03-12 12:32:37 -0700879 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700880 else:
881 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800882
Michael Rungec6e3afd2014-05-05 11:55:47 -0700883 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800884 device_specific.IncrementalOTA_Assertions()
885
886 # Two-step incremental package strategy (in chronological order,
887 # which is *not* the order in which the generated script has
888 # things):
889 #
890 # if stage is not "2/3" or "3/3":
891 # do verification on current system
892 # write recovery image to boot partition
893 # set stage to "2/3"
894 # reboot to boot partition and restart recovery
895 # else if stage is "2/3":
896 # write recovery image to recovery partition
897 # set stage to "3/3"
898 # reboot to recovery partition and restart recovery
899 # else:
900 # (stage must be "3/3")
901 # perform update:
902 # patch system files, etc.
903 # force full install of new boot image
904 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700905 # complete script normally
906 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800907
908 if OPTIONS.two_step:
Tao Baodd24da92015-07-29 14:09:23 -0700909 if not OPTIONS.source_info_dict.get("multistage_support", None):
Geremy Condra36bd3652014-02-06 19:45:10 -0800910 assert False, "two-step packages not supported by this build"
Tao Baodd24da92015-07-29 14:09:23 -0700911 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Geremy Condra36bd3652014-02-06 19:45:10 -0800912 assert fs.fs_type.upper() == "EMMC", \
913 "two-step packages only supported on devices with EMMC /misc partitions"
914 bcb_dev = {"bcb_dev": fs.device}
915 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
916 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700917if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800918""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -0700919 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800920 script.WriteRawImage("/recovery", "recovery.img")
921 script.AppendExtra("""
922set_stage("%(bcb_dev)s", "3/3");
923reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700924else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800925""" % bcb_dev)
926
Tao Bao6c55a8a2015-04-08 15:30:27 -0700927 # Dump fingerprints
928 script.Print("Source: %s" % CalculateFingerprint(
929 oem_props, oem_dict, OPTIONS.source_info_dict))
930 script.Print("Target: %s" % CalculateFingerprint(
931 oem_props, oem_dict, OPTIONS.target_info_dict))
932
Geremy Condra36bd3652014-02-06 19:45:10 -0800933 script.Print("Verifying current system...")
934
935 device_specific.IncrementalOTA_VerifyBegin()
936
Michael Rungec6e3afd2014-05-05 11:55:47 -0700937 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700938 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
939 # patching on a device that's already on the target build will damage the
940 # system. Because operations like move don't check the block state, they
941 # always apply the changes unconditionally.
942 if blockimgdiff_version <= 2:
943 script.AssertSomeFingerprint(source_fp)
944 else:
945 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700946 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700947 if blockimgdiff_version <= 2:
948 script.AssertSomeThumbprint(
949 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
950 else:
951 script.AssertSomeThumbprint(
952 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
953 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800954
Tao Baod8d14be2016-02-04 14:26:02 -0800955 # Check the required cache size (i.e. stashed blocks).
956 size = []
957 if system_diff:
958 size.append(system_diff.required_cache)
959 if vendor_diff:
960 size.append(vendor_diff.required_cache)
961
Geremy Condra36bd3652014-02-06 19:45:10 -0800962 if updating_boot:
Tao Baodd24da92015-07-29 14:09:23 -0700963 boot_type, boot_device = common.GetTypeAndDevice(
964 "/boot", OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800965 d = common.Difference(target_boot, source_boot)
966 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700967 if d is None:
968 include_full_boot = True
969 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
970 else:
971 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800972
Doug Zongkerf8340082014-08-05 10:39:37 -0700973 print "boot target: %d source: %d diff: %d" % (
974 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800975
Doug Zongkerf8340082014-08-05 10:39:37 -0700976 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800977
Doug Zongkerf8340082014-08-05 10:39:37 -0700978 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
979 (boot_type, boot_device,
980 source_boot.size, source_boot.sha1,
981 target_boot.size, target_boot.sha1))
Tao Baod8d14be2016-02-04 14:26:02 -0800982 size.append(target_boot.size)
983
984 if size:
985 script.CacheFreeSpaceCheck(max(size))
Geremy Condra36bd3652014-02-06 19:45:10 -0800986
987 device_specific.IncrementalOTA_VerifyEnd()
988
989 if OPTIONS.two_step:
990 script.WriteRawImage("/boot", "recovery.img")
991 script.AppendExtra("""
992set_stage("%(bcb_dev)s", "2/3");
993reboot_now("%(bcb_dev)s", "");
994else
995""" % bcb_dev)
996
Jesse Zhao75bcea02015-01-06 10:59:53 -0800997 # Verify the existing partitions.
998 system_diff.WriteVerifyScript(script)
999 if vendor_diff:
1000 vendor_diff.WriteVerifyScript(script)
1001
Geremy Condra36bd3652014-02-06 19:45:10 -08001002 script.Comment("---- start making changes here ----")
1003
1004 device_specific.IncrementalOTA_InstallBegin()
1005
Doug Zongkerab7ca1d2014-08-26 10:40:28 -07001006 system_diff.WriteScript(script, output_zip,
1007 progress=0.8 if vendor_diff else 0.9)
Tao Bao68658c02015-06-01 13:40:49 -07001008
Doug Zongkerfc44a512014-08-26 13:10:25 -07001009 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -07001010 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -08001011
1012 if OPTIONS.two_step:
1013 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1014 script.WriteRawImage("/boot", "boot.img")
1015 print "writing full boot image (forced by two-step mode)"
1016
1017 if not OPTIONS.two_step:
1018 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -07001019 if include_full_boot:
1020 print "boot image changed; including full."
1021 script.Print("Installing boot image...")
1022 script.WriteRawImage("/boot", "boot.img")
1023 else:
1024 # Produce the boot image by applying a patch to the current
1025 # contents of the boot partition, and write it back to the
1026 # partition.
1027 print "boot image changed; including patch."
1028 script.Print("Patching boot image...")
1029 script.ShowProgress(0.1, 10)
1030 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1031 % (boot_type, boot_device,
1032 source_boot.size, source_boot.sha1,
1033 target_boot.size, target_boot.sha1),
1034 "-",
1035 target_boot.size, target_boot.sha1,
1036 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -08001037 else:
1038 print "boot image unchanged; skipping."
1039
1040 # Do device-specific installation (eg, write radio image).
1041 device_specific.IncrementalOTA_InstallEnd()
1042
1043 if OPTIONS.extra_script is not None:
1044 script.AppendExtra(OPTIONS.extra_script)
1045
Doug Zongker922206e2014-03-04 13:16:24 -08001046 if OPTIONS.wipe_user_data:
1047 script.Print("Erasing user data...")
1048 script.FormatPartition("/data")
Tao Bao5d182562016-02-23 11:38:39 -08001049 metadata["ota-wipe"] = "yes"
Doug Zongker922206e2014-03-04 13:16:24 -08001050
Geremy Condra36bd3652014-02-06 19:45:10 -08001051 if OPTIONS.two_step:
1052 script.AppendExtra("""
1053set_stage("%(bcb_dev)s", "");
1054endif;
1055endif;
1056""" % bcb_dev)
1057
1058 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -08001059 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -08001060 metadata["ota-required-cache"] = str(script.required_cache)
Geremy Condra36bd3652014-02-06 19:45:10 -08001061 WriteMetadata(metadata, output_zip)
1062
Doug Zongker32b527d2014-03-04 10:03:02 -08001063
Tao Bao9bc6bb22015-11-09 16:58:28 -08001064def WriteVerifyPackage(input_zip, output_zip):
1065 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
1066
1067 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
1068 recovery_mount_options = OPTIONS.info_dict.get(
1069 "recovery_mount_options")
1070 oem_dict = None
1071 if oem_props is not None and len(oem_props) > 0:
1072 if OPTIONS.oem_source is None:
1073 raise common.ExternalError("OEM source required for this build")
Tao Bao8608cde2016-02-25 19:49:55 -08001074 if not OPTIONS.oem_no_mount:
1075 script.Mount("/oem", recovery_mount_options)
Tao Bao9bc6bb22015-11-09 16:58:28 -08001076 oem_dict = common.LoadDictionaryFromLines(
1077 open(OPTIONS.oem_source).readlines())
1078
1079 target_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.info_dict)
1080 metadata = {
1081 "post-build": target_fp,
1082 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1083 OPTIONS.info_dict),
1084 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
1085 }
1086
1087 device_specific = common.DeviceSpecificParams(
1088 input_zip=input_zip,
1089 input_version=OPTIONS.info_dict["recovery_api_version"],
1090 output_zip=output_zip,
1091 script=script,
1092 input_tmp=OPTIONS.input_tmp,
1093 metadata=metadata,
1094 info_dict=OPTIONS.info_dict)
1095
1096 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
1097
1098 script.Print("Verifying device images against %s..." % target_fp)
1099 script.AppendExtra("")
1100
1101 script.Print("Verifying boot...")
1102 boot_img = common.GetBootableImage(
1103 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
1104 boot_type, boot_device = common.GetTypeAndDevice(
1105 "/boot", OPTIONS.info_dict)
1106 script.Verify("%s:%s:%d:%s" % (
1107 boot_type, boot_device, boot_img.size, boot_img.sha1))
1108 script.AppendExtra("")
1109
1110 script.Print("Verifying recovery...")
1111 recovery_img = common.GetBootableImage(
1112 "recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
1113 recovery_type, recovery_device = common.GetTypeAndDevice(
1114 "/recovery", OPTIONS.info_dict)
1115 script.Verify("%s:%s:%d:%s" % (
1116 recovery_type, recovery_device, recovery_img.size, recovery_img.sha1))
1117 script.AppendExtra("")
1118
1119 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
1120 system_tgt.ResetFileMap()
1121 system_diff = common.BlockDifference("system", system_tgt, src=None)
1122 system_diff.WriteStrictVerifyScript(script)
1123
1124 if HasVendorPartition(input_zip):
1125 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
1126 vendor_tgt.ResetFileMap()
1127 vendor_diff = common.BlockDifference("vendor", vendor_tgt, src=None)
1128 vendor_diff.WriteStrictVerifyScript(script)
1129
1130 # Device specific partitions, such as radio, bootloader and etc.
1131 device_specific.VerifyOTA_Assertions()
1132
1133 script.SetProgress(1.0)
1134 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -08001135 metadata["ota-required-cache"] = str(script.required_cache)
Tao Bao9bc6bb22015-11-09 16:58:28 -08001136 WriteMetadata(metadata, output_zip)
1137
1138
Tao Baoc098e9e2016-01-07 13:03:56 -08001139def WriteABOTAPackageWithBrilloScript(target_file, output_file,
1140 source_file=None):
1141 """Generate an Android OTA package that has A/B update payload."""
1142
1143 # Setup signing keys.
1144 if OPTIONS.package_key is None:
1145 OPTIONS.package_key = OPTIONS.info_dict.get(
1146 "default_system_dev_certificate",
1147 "build/target/product/security/testkey")
1148
1149 # A/B updater expects key in RSA format.
1150 cmd = ["openssl", "pkcs8",
1151 "-in", OPTIONS.package_key + OPTIONS.private_key_suffix,
1152 "-inform", "DER", "-nocrypt"]
1153 rsa_key = common.MakeTempFile(prefix="key-", suffix=".key")
1154 cmd.extend(["-out", rsa_key])
1155 p1 = common.Run(cmd, stdout=subprocess.PIPE)
1156 p1.wait()
1157 assert p1.returncode == 0, "openssl pkcs8 failed"
1158
1159 # Stage the output zip package for signing.
1160 temp_zip_file = tempfile.NamedTemporaryFile()
1161 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1162 compression=zipfile.ZIP_DEFLATED)
1163
1164 # Metadata to comply with Android OTA package format.
1165 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties", None)
1166 oem_dict = None
1167 if oem_props:
1168 if OPTIONS.oem_source is None:
1169 raise common.ExternalError("OEM source required for this build")
1170 oem_dict = common.LoadDictionaryFromLines(
1171 open(OPTIONS.oem_source).readlines())
1172
1173 metadata = {
1174 "post-build": CalculateFingerprint(oem_props, oem_dict,
1175 OPTIONS.info_dict),
1176 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1177 OPTIONS.info_dict),
1178 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
Tao Baod8d14be2016-02-04 14:26:02 -08001179 "ota-required-cache": "0",
1180 "ota-type": "AB",
Tao Baoc098e9e2016-01-07 13:03:56 -08001181 }
1182
1183 if source_file is not None:
1184 metadata["pre-build"] = CalculateFingerprint(oem_props, oem_dict,
1185 OPTIONS.source_info_dict)
1186
1187 # 1. Generate payload.
1188 payload_file = common.MakeTempFile(prefix="payload-", suffix=".bin")
1189 cmd = ["brillo_update_payload", "generate",
1190 "--payload", payload_file,
1191 "--target_image", target_file]
1192 if source_file is not None:
1193 cmd.extend(["--source_image", source_file])
1194 p1 = common.Run(cmd, stdout=subprocess.PIPE)
1195 p1.wait()
1196 assert p1.returncode == 0, "brillo_update_payload generate failed"
1197
1198 # 2. Generate hashes of the payload and metadata files.
1199 payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
1200 metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
1201 cmd = ["brillo_update_payload", "hash",
1202 "--unsigned_payload", payload_file,
1203 "--signature_size", "256",
1204 "--metadata_hash_file", metadata_sig_file,
1205 "--payload_hash_file", payload_sig_file]
1206 p1 = common.Run(cmd, stdout=subprocess.PIPE)
1207 p1.wait()
1208 assert p1.returncode == 0, "brillo_update_payload hash failed"
1209
1210 # 3. Sign the hashes and insert them back into the payload file.
1211 signed_payload_sig_file = common.MakeTempFile(prefix="signed-sig-",
1212 suffix=".bin")
1213 signed_metadata_sig_file = common.MakeTempFile(prefix="signed-sig-",
1214 suffix=".bin")
1215 # 3a. Sign the payload hash.
1216 cmd = ["openssl", "pkeyutl", "-sign",
1217 "-inkey", rsa_key,
1218 "-pkeyopt", "digest:sha256",
1219 "-in", payload_sig_file,
1220 "-out", signed_payload_sig_file]
1221 p1 = common.Run(cmd, stdout=subprocess.PIPE)
1222 p1.wait()
1223 assert p1.returncode == 0, "openssl sign payload failed"
1224
1225 # 3b. Sign the metadata hash.
1226 cmd = ["openssl", "pkeyutl", "-sign",
1227 "-inkey", rsa_key,
1228 "-pkeyopt", "digest:sha256",
1229 "-in", metadata_sig_file,
1230 "-out", signed_metadata_sig_file]
1231 p1 = common.Run(cmd, stdout=subprocess.PIPE)
1232 p1.wait()
1233 assert p1.returncode == 0, "openssl sign metadata failed"
1234
1235 # 3c. Insert the signatures back into the payload file.
1236 signed_payload_file = common.MakeTempFile(prefix="signed-payload-",
1237 suffix=".bin")
1238 cmd = ["brillo_update_payload", "sign",
1239 "--unsigned_payload", payload_file,
1240 "--payload", signed_payload_file,
1241 "--signature_size", "256",
1242 "--metadata_signature_file", signed_metadata_sig_file,
1243 "--payload_signature_file", signed_payload_sig_file]
1244 p1 = common.Run(cmd, stdout=subprocess.PIPE)
1245 p1.wait()
1246 assert p1.returncode == 0, "brillo_update_payload sign failed"
1247
Alex Deymo19241c12016-02-04 22:29:29 -08001248 # 4. Dump the signed payload properties.
1249 properties_file = common.MakeTempFile(prefix="payload-properties-",
1250 suffix=".txt")
1251 cmd = ["brillo_update_payload", "properties",
1252 "--payload", signed_payload_file,
1253 "--properties_file", properties_file]
1254 p1 = common.Run(cmd, stdout=subprocess.PIPE)
1255 p1.wait()
1256 assert p1.returncode == 0, "brillo_update_payload properties failed"
1257
1258 # Add the signed payload file and properties into the zip.
1259 common.ZipWrite(output_zip, properties_file, arcname="payload_properties.txt")
Tao Baoc098e9e2016-01-07 13:03:56 -08001260 common.ZipWrite(output_zip, signed_payload_file, arcname="payload.bin",
1261 compress_type=zipfile.ZIP_STORED)
1262 WriteMetadata(metadata, output_zip)
1263
1264 # Sign the whole package to comply with the Android OTA package format.
1265 common.ZipClose(output_zip)
1266 SignOutput(temp_zip_file.name, output_file)
1267 temp_zip_file.close()
1268
1269
Dan Albert8b72aef2015-03-23 19:13:21 -07001270class FileDifference(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001271 def __init__(self, partition, source_zip, target_zip, output_zip):
Dan Albert8b72aef2015-03-23 19:13:21 -07001272 self.deferred_patch_list = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001273 print "Loading target..."
1274 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
1275 print "Loading source..."
1276 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
1277
1278 self.verbatim_targets = verbatim_targets = []
1279 self.patch_list = patch_list = []
1280 diffs = []
1281 self.renames = renames = {}
1282 known_paths = set()
1283 largest_source_size = 0
1284
1285 matching_file_cache = {}
1286 for fn, sf in source_data.items():
1287 assert fn == sf.name
1288 matching_file_cache["path:" + fn] = sf
1289 if fn in target_data.keys():
1290 AddToKnownPaths(fn, known_paths)
1291 # Only allow eligibility for filename/sha matching
1292 # if there isn't a perfect path match.
1293 if target_data.get(sf.name) is None:
1294 matching_file_cache["file:" + fn.split("/")[-1]] = sf
1295 matching_file_cache["sha:" + sf.sha1] = sf
1296
1297 for fn in sorted(target_data.keys()):
1298 tf = target_data[fn]
1299 assert fn == tf.name
1300 sf = ClosestFileMatch(tf, matching_file_cache, renames)
1301 if sf is not None and sf.name != tf.name:
1302 print "File has moved from " + sf.name + " to " + tf.name
1303 renames[sf.name] = tf
1304
1305 if sf is None or fn in OPTIONS.require_verbatim:
1306 # This file should be included verbatim
1307 if fn in OPTIONS.prohibit_verbatim:
1308 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
1309 print "send", fn, "verbatim"
1310 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001311 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001312 if fn in target_data.keys():
1313 AddToKnownPaths(fn, known_paths)
1314 elif tf.sha1 != sf.sha1:
1315 # File is different; consider sending as a patch
1316 diffs.append(common.Difference(tf, sf))
1317 else:
1318 # Target file data identical to source (may still be renamed)
1319 pass
1320
1321 common.ComputeDifferences(diffs)
1322
1323 for diff in diffs:
1324 tf, sf, d = diff.GetPatch()
1325 path = "/".join(tf.name.split("/")[:-1])
1326 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1327 path not in known_paths:
1328 # patch is almost as big as the file; don't bother patching
1329 # or a patch + rename cannot take place due to the target
1330 # directory not existing
1331 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001332 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001333 if sf.name in renames:
1334 del renames[sf.name]
1335 AddToKnownPaths(tf.name, known_paths)
1336 else:
1337 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1338 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1339 largest_source_size = max(largest_source_size, sf.size)
1340
1341 self.largest_source_size = largest_source_size
1342
1343 def EmitVerification(self, script):
1344 so_far = 0
Dan Albert8b72aef2015-03-23 19:13:21 -07001345 for tf, sf, _, _ in self.patch_list:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001346 if tf.name != sf.name:
1347 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1348 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1349 so_far += sf.size
1350 return so_far
1351
Michael Runge63f01de2014-10-28 19:24:19 -07001352 def EmitExplicitTargetVerification(self, script):
Dan Albert8b72aef2015-03-23 19:13:21 -07001353 for fn, _, sha1 in self.verbatim_targets:
1354 if fn[-1] != "/":
Michael Runge63f01de2014-10-28 19:24:19 -07001355 script.FileCheck("/"+fn, sha1)
1356 for tf, _, _, _ in self.patch_list:
1357 script.FileCheck(tf.name, tf.sha1)
1358
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001359 def RemoveUnneededFiles(self, script, extras=()):
Tao Baoa77d41e2015-09-03 21:17:37 -07001360 file_list = ["/" + i[0] for i in self.verbatim_targets]
1361 file_list += ["/" + i for i in self.source_data
1362 if i not in self.target_data and i not in self.renames]
1363 file_list += list(extras)
1364 # Sort the list in descending order, which removes all the files first
1365 # before attempting to remove the folder. (Bug: 22960996)
1366 script.DeleteFiles(sorted(file_list, reverse=True))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001367
1368 def TotalPatchSize(self):
1369 return sum(i[1].size for i in self.patch_list)
1370
1371 def EmitPatches(self, script, total_patch_size, so_far):
1372 self.deferred_patch_list = deferred_patch_list = []
1373 for item in self.patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001374 tf, sf, _, _ = item
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001375 if tf.name == "system/build.prop":
1376 deferred_patch_list.append(item)
1377 continue
Dan Albert8b72aef2015-03-23 19:13:21 -07001378 if sf.name != tf.name:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001379 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
Dan Albert8b72aef2015-03-23 19:13:21 -07001380 script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1,
1381 "patch/" + sf.name + ".p")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001382 so_far += tf.size
1383 script.SetProgress(so_far / total_patch_size)
1384 return so_far
1385
1386 def EmitDeferredPatches(self, script):
1387 for item in self.deferred_patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001388 tf, sf, _, _ = item
1389 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1,
1390 "patch/" + sf.name + ".p")
1391 script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001392
1393 def EmitRenames(self, script):
1394 if len(self.renames) > 0:
1395 script.Print("Renaming files...")
1396 for src, tgt in self.renames.iteritems():
1397 print "Renaming " + src + " to " + tgt.name
1398 script.RenameFile(src, tgt.name)
1399
1400
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001401def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001402 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1403 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1404
Doug Zongker26e66192014-02-20 13:22:07 -08001405 if (OPTIONS.block_based and
1406 target_has_recovery_patch and
1407 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001408 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1409
Doug Zongker37974732010-09-16 17:44:38 -07001410 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1411 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001412
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001413 if source_version == 0:
1414 print ("WARNING: generating edify script for a source that "
1415 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -07001416 script = edify_generator.EdifyGenerator(
1417 source_version, OPTIONS.target_info_dict,
1418 fstab=OPTIONS.source_info_dict["fstab"])
Doug Zongkereef39442009-04-02 12:14:19 -07001419
Michael Runge6e836112014-04-15 17:40:21 -07001420 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Tao Bao34b47bf2015-06-22 19:17:41 -07001421 recovery_mount_options = OPTIONS.source_info_dict.get(
1422 "recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001423 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001424 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001425 if OPTIONS.oem_source is None:
1426 raise common.ExternalError("OEM source required for this build")
Tao Bao1bb5a182016-03-04 09:45:03 -08001427 if not OPTIONS.oem_no_mount:
1428 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001429 oem_dict = common.LoadDictionaryFromLines(
1430 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001431
Dan Albert8b72aef2015-03-23 19:13:21 -07001432 metadata = {
1433 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1434 OPTIONS.source_info_dict),
Tao Baod8d14be2016-02-04 14:26:02 -08001435 "ota-type": "FILE",
Dan Albert8b72aef2015-03-23 19:13:21 -07001436 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001437
Tao Bao5d182562016-02-23 11:38:39 -08001438 post_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict)
1439 pre_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
1440 is_downgrade = long(post_timestamp) < long(pre_timestamp)
1441
1442 if OPTIONS.downgrade:
1443 metadata["ota-downgrade"] = "yes"
1444 if not is_downgrade:
1445 raise RuntimeError("--downgrade specified but no downgrade detected: "
1446 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
1447 else:
1448 if is_downgrade:
1449 # Non-fatal here to allow generating such a package which may require
1450 # manual work to adjust the post-timestamp. A legit use case is that we
1451 # cut a new build C (after having A and B), but want to enfore the
1452 # update path of A -> C -> B. Specifying --downgrade may not help since
1453 # that would enforce a data wipe for C -> B update.
1454 print("\nWARNING: downgrade detected: pre: %s, post: %s.\n"
1455 "The package may not be deployed properly. "
1456 "Try --downgrade?\n" % (pre_timestamp, post_timestamp))
1457 metadata["post-timestamp"] = post_timestamp
1458
Doug Zongker05d3dea2009-06-22 11:32:31 -07001459 device_specific = common.DeviceSpecificParams(
1460 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001461 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001462 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001463 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001464 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001465 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001466 metadata=metadata,
Tao Bao6f0b2192015-10-13 16:37:12 -07001467 info_dict=OPTIONS.source_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001468
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001469 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001470 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001471 if HasVendorPartition(target_zip):
1472 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001473 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001474 else:
1475 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001476
Dan Albert8b72aef2015-03-23 19:13:21 -07001477 target_fp = CalculateFingerprint(oem_props, oem_dict,
1478 OPTIONS.target_info_dict)
1479 source_fp = CalculateFingerprint(oem_props, oem_dict,
1480 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001481
1482 if oem_props is None:
1483 script.AssertSomeFingerprint(source_fp, target_fp)
1484 else:
1485 script.AssertSomeThumbprint(
1486 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1487 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1488
Doug Zongker2ea21062010-04-28 16:05:21 -07001489 metadata["pre-build"] = source_fp
1490 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001491
Doug Zongker55d93282011-01-25 17:03:34 -08001492 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001493 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1494 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001495 target_boot = common.GetBootableImage(
1496 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001497 updating_boot = (not OPTIONS.two_step and
1498 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001499
Doug Zongker55d93282011-01-25 17:03:34 -08001500 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001501 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1502 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001503 target_recovery = common.GetBootableImage(
1504 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001505 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001506
Doug Zongker881dd402009-09-20 14:03:55 -07001507 # Here's how we divide up the progress bar:
1508 # 0.1 for verifying the start state (PatchCheck calls)
1509 # 0.8 for applying patches (ApplyPatch calls)
1510 # 0.1 for unpacking verbatim files, symlinking, and doing the
1511 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001512
Michael Runge6e836112014-04-15 17:40:21 -07001513 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001514 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001515
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001516 # Two-step incremental package strategy (in chronological order,
1517 # which is *not* the order in which the generated script has
1518 # things):
1519 #
1520 # if stage is not "2/3" or "3/3":
1521 # do verification on current system
1522 # write recovery image to boot partition
1523 # set stage to "2/3"
1524 # reboot to boot partition and restart recovery
1525 # else if stage is "2/3":
1526 # write recovery image to recovery partition
1527 # set stage to "3/3"
1528 # reboot to recovery partition and restart recovery
1529 # else:
1530 # (stage must be "3/3")
1531 # perform update:
1532 # patch system files, etc.
1533 # force full install of new boot image
1534 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001535 # complete script normally
1536 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001537
1538 if OPTIONS.two_step:
Tao Baodd24da92015-07-29 14:09:23 -07001539 if not OPTIONS.source_info_dict.get("multistage_support", None):
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001540 assert False, "two-step packages not supported by this build"
Tao Baodd24da92015-07-29 14:09:23 -07001541 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001542 assert fs.fs_type.upper() == "EMMC", \
1543 "two-step packages only supported on devices with EMMC /misc partitions"
1544 bcb_dev = {"bcb_dev": fs.device}
1545 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1546 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001547if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001548""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001549 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001550 script.WriteRawImage("/recovery", "recovery.img")
1551 script.AppendExtra("""
1552set_stage("%(bcb_dev)s", "3/3");
1553reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001554else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001555""" % bcb_dev)
1556
Tao Bao6c55a8a2015-04-08 15:30:27 -07001557 # Dump fingerprints
1558 script.Print("Source: %s" % (source_fp,))
1559 script.Print("Target: %s" % (target_fp,))
1560
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001561 script.Print("Verifying current system...")
1562
Doug Zongkere5ff5902012-01-17 10:55:37 -08001563 device_specific.IncrementalOTA_VerifyBegin()
1564
Doug Zongker881dd402009-09-20 14:03:55 -07001565 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001566 so_far = system_diff.EmitVerification(script)
1567 if vendor_diff:
1568 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001569
Tao Baod8d14be2016-02-04 14:26:02 -08001570 size = []
1571 if system_diff.patch_list:
1572 size.append(system_diff.largest_source_size)
1573 if vendor_diff:
1574 if vendor_diff.patch_list:
1575 size.append(vendor_diff.largest_source_size)
1576
Doug Zongker5da317e2009-06-02 13:38:17 -07001577 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001578 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001579 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001580 print "boot target: %d source: %d diff: %d" % (
1581 target_boot.size, source_boot.size, len(d))
1582
Doug Zongker048e7ca2009-06-15 14:31:53 -07001583 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001584
Tao Baodd24da92015-07-29 14:09:23 -07001585 boot_type, boot_device = common.GetTypeAndDevice(
1586 "/boot", OPTIONS.source_info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001587
1588 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1589 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001590 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001591 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001592 so_far += source_boot.size
Tao Baod8d14be2016-02-04 14:26:02 -08001593 size.append(target_boot.size)
Doug Zongker5da317e2009-06-02 13:38:17 -07001594
Tao Baod8d14be2016-02-04 14:26:02 -08001595 if size:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001596 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001597
Doug Zongker05d3dea2009-06-22 11:32:31 -07001598 device_specific.IncrementalOTA_VerifyEnd()
1599
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001600 if OPTIONS.two_step:
1601 script.WriteRawImage("/boot", "recovery.img")
1602 script.AppendExtra("""
1603set_stage("%(bcb_dev)s", "2/3");
1604reboot_now("%(bcb_dev)s", "");
1605else
1606""" % bcb_dev)
1607
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001608 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001609
Doug Zongkere5ff5902012-01-17 10:55:37 -08001610 device_specific.IncrementalOTA_InstallBegin()
1611
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001612 if OPTIONS.two_step:
1613 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1614 script.WriteRawImage("/boot", "boot.img")
1615 print "writing full boot image (forced by two-step mode)"
1616
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001617 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001618 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1619 if vendor_diff:
1620 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001621
Doug Zongker881dd402009-09-20 14:03:55 -07001622 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001623 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1624 if vendor_diff:
1625 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001626 if updating_boot:
1627 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001628
1629 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001630 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1631 if vendor_diff:
1632 script.Print("Patching vendor files...")
1633 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001634
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001635 if not OPTIONS.two_step:
1636 if updating_boot:
1637 # Produce the boot image by applying a patch to the current
1638 # contents of the boot partition, and write it back to the
1639 # partition.
1640 script.Print("Patching boot image...")
1641 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1642 % (boot_type, boot_device,
1643 source_boot.size, source_boot.sha1,
1644 target_boot.size, target_boot.sha1),
1645 "-",
1646 target_boot.size, target_boot.sha1,
1647 source_boot.sha1, "patch/boot.img.p")
1648 so_far += target_boot.size
1649 script.SetProgress(so_far / total_patch_size)
1650 print "boot image changed; including."
1651 else:
1652 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001653
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001654 system_items = ItemSet("system", "META/filesystem_config.txt")
1655 if vendor_diff:
1656 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1657
Doug Zongkereef39442009-04-02 12:14:19 -07001658 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001659 # Recovery is generated as a patch using both the boot image
1660 # (which contains the same linux kernel as recovery) and the file
1661 # /system/etc/recovery-resource.dat (which contains all the images
1662 # used in the recovery UI) as sources. This lets us minimize the
1663 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001664 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001665 # For older builds where recovery-resource.dat is not present, we
1666 # use only the boot image as the source.
1667
Doug Zongkerc9253822014-02-04 12:17:58 -08001668 if not target_has_recovery_patch:
1669 def output_sink(fn, data):
1670 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001671 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001672
1673 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1674 target_recovery, target_boot)
1675 script.DeleteFiles(["/system/recovery-from-boot.p",
Tao Baof2cffbd2015-07-22 12:33:18 -07001676 "/system/etc/recovery.img",
Doug Zongkerc9253822014-02-04 12:17:58 -08001677 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001678 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001679 else:
1680 print "recovery image unchanged; skipping."
1681
Doug Zongker881dd402009-09-20 14:03:55 -07001682 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001683
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001684 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1685 if vendor_diff:
1686 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1687
1688 temp_script = script.MakeTemporary()
1689 system_items.GetMetadata(target_zip)
1690 system_items.Get("system").SetPermissions(temp_script)
1691 if vendor_diff:
1692 vendor_items.GetMetadata(target_zip)
1693 vendor_items.Get("vendor").SetPermissions(temp_script)
1694
1695 # Note that this call will mess up the trees of Items, so make sure
1696 # we're done with them.
1697 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1698 if vendor_diff:
1699 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001700
1701 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001702 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1703
1704 # Delete all the symlinks in source that aren't in target. This
1705 # needs to happen before verbatim files are unpacked, in case a
1706 # symlink in the source is replaced by a real file in the target.
Tao Bao84006ea2015-09-02 10:28:08 -07001707
1708 # If a symlink in the source will be replaced by a regular file, we cannot
1709 # delete the symlink/file in case the package gets applied again. For such
1710 # a symlink, we prepend a sha1_check() to detect if it has been updated.
1711 # (Bug: 23646151)
1712 replaced_symlinks = dict()
1713 if system_diff:
1714 for i in system_diff.verbatim_targets:
1715 replaced_symlinks["/%s" % (i[0],)] = i[2]
1716 if vendor_diff:
1717 for i in vendor_diff.verbatim_targets:
1718 replaced_symlinks["/%s" % (i[0],)] = i[2]
1719
1720 if system_diff:
1721 for tf in system_diff.renames.values():
1722 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1723 if vendor_diff:
1724 for tf in vendor_diff.renames.values():
1725 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1726
1727 always_delete = []
1728 may_delete = []
Doug Zongkereef39442009-04-02 12:14:19 -07001729 for dest, link in source_symlinks:
1730 if link not in target_symlinks_d:
Tao Bao84006ea2015-09-02 10:28:08 -07001731 if link in replaced_symlinks:
1732 may_delete.append((link, replaced_symlinks[link]))
1733 else:
1734 always_delete.append(link)
1735 script.DeleteFiles(always_delete)
1736 script.DeleteFilesIfNotMatching(may_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001737
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001738 if system_diff.verbatim_targets:
1739 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001740 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001741 if vendor_diff and vendor_diff.verbatim_targets:
1742 script.Print("Unpacking new vendor files...")
1743 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001744
Doug Zongkerc9253822014-02-04 12:17:58 -08001745 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001746 script.Print("Unpacking new recovery...")
1747 script.UnpackPackageDir("recovery", "/system")
1748
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001749 system_diff.EmitRenames(script)
1750 if vendor_diff:
1751 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001752
Doug Zongker05d3dea2009-06-22 11:32:31 -07001753 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001754
1755 # Create all the symlinks that don't already exist, or point to
1756 # somewhere different than what we want. Delete each symlink before
1757 # creating it, since the 'symlink' command won't overwrite.
1758 to_create = []
1759 for dest, link in target_symlinks:
1760 if link in source_symlinks_d:
1761 if dest != source_symlinks_d[link]:
1762 to_create.append((dest, link))
1763 else:
1764 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001765 script.DeleteFiles([i[1] for i in to_create])
1766 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001767
1768 # Now that the symlinks are created, we can set all the
1769 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001770 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001771
Doug Zongker881dd402009-09-20 14:03:55 -07001772 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001773 device_specific.IncrementalOTA_InstallEnd()
1774
Doug Zongker1c390a22009-05-14 19:06:36 -07001775 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001776 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001777
Doug Zongkere92f15a2011-08-26 13:46:40 -07001778 # Patch the build.prop file last, so if something fails but the
1779 # device can still come up, it appears to be the old build and will
1780 # get set the OTA package again to retry.
1781 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001782 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001783
Doug Zongker922206e2014-03-04 13:16:24 -08001784 if OPTIONS.wipe_user_data:
1785 script.Print("Erasing user data...")
1786 script.FormatPartition("/data")
Tao Bao5d182562016-02-23 11:38:39 -08001787 metadata["ota-wipe"] = "yes"
Doug Zongker922206e2014-03-04 13:16:24 -08001788
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001789 if OPTIONS.two_step:
1790 script.AppendExtra("""
1791set_stage("%(bcb_dev)s", "");
1792endif;
1793endif;
1794""" % bcb_dev)
1795
Michael Runge63f01de2014-10-28 19:24:19 -07001796 if OPTIONS.verify and system_diff:
1797 script.Print("Remounting and verifying system partition files...")
1798 script.Unmount("/system")
Tao Bao269d7852015-12-02 15:49:13 -08001799 script.Mount("/system", recovery_mount_options)
Michael Runge63f01de2014-10-28 19:24:19 -07001800 system_diff.EmitExplicitTargetVerification(script)
1801
1802 if OPTIONS.verify and vendor_diff:
1803 script.Print("Remounting and verifying vendor partition files...")
1804 script.Unmount("/vendor")
Tao Bao269d7852015-12-02 15:49:13 -08001805 script.Mount("/vendor", recovery_mount_options)
Michael Runge63f01de2014-10-28 19:24:19 -07001806 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001807 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001808
Tao Baod8d14be2016-02-04 14:26:02 -08001809 metadata["ota-required-cache"] = str(script.required_cache)
Doug Zongker2ea21062010-04-28 16:05:21 -07001810 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001811
1812
1813def main(argv):
1814
1815 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001816 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001817 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001818 elif o in ("-k", "--package_key"):
1819 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001820 elif o in ("-i", "--incremental_from"):
1821 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001822 elif o == "--full_radio":
1823 OPTIONS.full_radio = True
leozwangaa6c1a12015-08-14 10:57:58 -07001824 elif o == "--full_bootloader":
1825 OPTIONS.full_bootloader = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001826 elif o in ("-w", "--wipe_user_data"):
1827 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001828 elif o in ("-n", "--no_prereq"):
1829 OPTIONS.omit_prereq = True
Tao Bao5d182562016-02-23 11:38:39 -08001830 elif o == "--downgrade":
1831 OPTIONS.downgrade = True
1832 OPTIONS.wipe_user_data = True
Michael Runge6e836112014-04-15 17:40:21 -07001833 elif o in ("-o", "--oem_settings"):
1834 OPTIONS.oem_source = a
Tao Bao8608cde2016-02-25 19:49:55 -08001835 elif o == "--oem_no_mount":
1836 OPTIONS.oem_no_mount = True
Doug Zongker1c390a22009-05-14 19:06:36 -07001837 elif o in ("-e", "--extra_script"):
1838 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001839 elif o in ("-a", "--aslr_mode"):
1840 if a in ("on", "On", "true", "True", "yes", "Yes"):
1841 OPTIONS.aslr_mode = True
1842 else:
1843 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001844 elif o in ("-t", "--worker_threads"):
1845 if a.isdigit():
1846 OPTIONS.worker_threads = int(a)
1847 else:
1848 raise ValueError("Cannot parse value %r for option %r - only "
1849 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001850 elif o in ("-2", "--two_step"):
1851 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001852 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001853 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001854 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001855 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001856 elif o == "--block":
1857 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001858 elif o in ("-b", "--binary"):
1859 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001860 elif o in ("--no_fallback_to_full",):
1861 OPTIONS.fallback_to_full = False
Tao Bao8dcf7382015-05-21 14:09:49 -07001862 elif o == "--stash_threshold":
1863 try:
1864 OPTIONS.stash_threshold = float(a)
1865 except ValueError:
1866 raise ValueError("Cannot parse value %r for option %r - expecting "
1867 "a float" % (a, o))
Tao Bao9bc6bb22015-11-09 16:58:28 -08001868 elif o == "--gen_verify":
1869 OPTIONS.gen_verify = True
Tao Baod62c6032015-11-30 09:40:20 -08001870 elif o == "--log_diff":
1871 OPTIONS.log_diff = a
Doug Zongkereef39442009-04-02 12:14:19 -07001872 else:
1873 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001874 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001875
1876 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001877 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001878 extra_long_opts=[
1879 "board_config=",
1880 "package_key=",
1881 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001882 "full_radio",
leozwangaa6c1a12015-08-14 10:57:58 -07001883 "full_bootloader",
Dan Albert8b72aef2015-03-23 19:13:21 -07001884 "wipe_user_data",
1885 "no_prereq",
Tao Bao5d182562016-02-23 11:38:39 -08001886 "downgrade",
Dan Albert8b72aef2015-03-23 19:13:21 -07001887 "extra_script=",
1888 "worker_threads=",
1889 "aslr_mode=",
1890 "two_step",
1891 "no_signing",
1892 "block",
1893 "binary=",
1894 "oem_settings=",
Tao Bao8608cde2016-02-25 19:49:55 -08001895 "oem_no_mount",
Dan Albert8b72aef2015-03-23 19:13:21 -07001896 "verify",
1897 "no_fallback_to_full",
Tao Bao8dcf7382015-05-21 14:09:49 -07001898 "stash_threshold=",
Tao Baod62c6032015-11-30 09:40:20 -08001899 "gen_verify",
1900 "log_diff=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001901 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001902
1903 if len(args) != 2:
1904 common.Usage(__doc__)
1905 sys.exit(1)
1906
Tao Bao5d182562016-02-23 11:38:39 -08001907 if OPTIONS.downgrade:
1908 # Sanity check to enforce a data wipe.
1909 if not OPTIONS.wipe_user_data:
1910 raise ValueError("Cannot downgrade without a data wipe")
1911
1912 # We should only allow downgrading incrementals (as opposed to full).
1913 # Otherwise the device may go back from arbitrary build with this full
1914 # OTA package.
1915 if OPTIONS.incremental_source is None:
1916 raise ValueError("Cannot generate downgradable full OTAs - consider"
1917 "using --omit_prereq?")
1918
Tao Baoc098e9e2016-01-07 13:03:56 -08001919 # Load the dict file from the zip directly to have a peek at the OTA type.
1920 # For packages using A/B update, unzipping is not needed.
1921 input_zip = zipfile.ZipFile(args[0], "r")
1922 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
1923 common.ZipClose(input_zip)
1924
1925 ab_update = OPTIONS.info_dict.get("ab_update") == "true"
1926
1927 if ab_update:
1928 if OPTIONS.incremental_source is not None:
1929 OPTIONS.target_info_dict = OPTIONS.info_dict
1930 source_zip = zipfile.ZipFile(OPTIONS.incremental_source, "r")
1931 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1932 common.ZipClose(source_zip)
1933
1934 if OPTIONS.verbose:
1935 print "--- target info ---"
1936 common.DumpInfoDict(OPTIONS.info_dict)
1937
1938 if OPTIONS.incremental_source is not None:
1939 print "--- source info ---"
1940 common.DumpInfoDict(OPTIONS.source_info_dict)
1941
1942 WriteABOTAPackageWithBrilloScript(
1943 target_file=args[0],
1944 output_file=args[1],
1945 source_file=OPTIONS.incremental_source)
1946
1947 print "done."
1948 return
1949
Doug Zongker1c390a22009-05-14 19:06:36 -07001950 if OPTIONS.extra_script is not None:
1951 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1952
Doug Zongkereef39442009-04-02 12:14:19 -07001953 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001954 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001955
Doug Zongkereef39442009-04-02 12:14:19 -07001956 OPTIONS.target_tmp = OPTIONS.input_tmp
Tao Bao2c15d9e2015-07-09 11:51:16 -07001957 OPTIONS.info_dict = common.LoadInfoDict(input_zip, OPTIONS.target_tmp)
Kenny Roote2e9f612013-05-29 12:59:35 -07001958
Doug Zongker37974732010-09-16 17:44:38 -07001959 if OPTIONS.verbose:
1960 print "--- target info ---"
1961 common.DumpInfoDict(OPTIONS.info_dict)
1962
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001963 # If the caller explicitly specified the device-specific extensions
1964 # path via -s/--device_specific, use that. Otherwise, use
1965 # META/releasetools.py if it is present in the target target_files.
1966 # Otherwise, take the path of the file from 'tool_extensions' in the
1967 # info dict and look for that in the local filesystem, relative to
1968 # the current directory.
1969
Doug Zongker37974732010-09-16 17:44:38 -07001970 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001971 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1972 if os.path.exists(from_input):
1973 print "(using device-specific extensions from target_files)"
1974 OPTIONS.device_specific = from_input
1975 else:
1976 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1977
Doug Zongker37974732010-09-16 17:44:38 -07001978 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001979 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001980
Tao Baoc098e9e2016-01-07 13:03:56 -08001981 if OPTIONS.info_dict.get("no_recovery") == "true":
Tao Baodb45efa2015-10-27 19:25:18 -07001982 raise common.ExternalError(
1983 "--- target build has specified no recovery ---")
1984
Tao Bao767e3ac2015-11-10 12:19:19 -08001985 # Use the default key to sign the package if not specified with package_key.
1986 if not OPTIONS.no_signing:
1987 if OPTIONS.package_key is None:
1988 OPTIONS.package_key = OPTIONS.info_dict.get(
1989 "default_system_dev_certificate",
1990 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -07001991
Tao Bao767e3ac2015-11-10 12:19:19 -08001992 # Set up the output zip. Create a temporary zip file if signing is needed.
1993 if OPTIONS.no_signing:
1994 if os.path.exists(args[1]):
1995 os.unlink(args[1])
1996 output_zip = zipfile.ZipFile(args[1], "w",
1997 compression=zipfile.ZIP_DEFLATED)
1998 else:
1999 temp_zip_file = tempfile.NamedTemporaryFile()
2000 output_zip = zipfile.ZipFile(temp_zip_file, "w",
2001 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07002002
Daniel Rosenberg40ef35b2015-11-10 19:21:34 -08002003 # Non A/B OTAs rely on /cache partition to store temporary files.
Tao Bao767e3ac2015-11-10 12:19:19 -08002004 cache_size = OPTIONS.info_dict.get("cache_size", None)
Tao Baoc098e9e2016-01-07 13:03:56 -08002005 if cache_size is None:
Tao Bao767e3ac2015-11-10 12:19:19 -08002006 print "--- can't determine the cache partition size ---"
2007 OPTIONS.cache_size = cache_size
Tao Bao8dcf7382015-05-21 14:09:49 -07002008
Tao Bao9bc6bb22015-11-09 16:58:28 -08002009 # Generate a verify package.
2010 if OPTIONS.gen_verify:
2011 WriteVerifyPackage(input_zip, output_zip)
2012
Tao Bao767e3ac2015-11-10 12:19:19 -08002013 # Generate a full OTA.
Tao Bao9bc6bb22015-11-09 16:58:28 -08002014 elif OPTIONS.incremental_source is None:
Tao Baoc098e9e2016-01-07 13:03:56 -08002015 WriteFullOTAPackage(input_zip, output_zip)
Tao Bao767e3ac2015-11-10 12:19:19 -08002016
2017 # Generate an incremental OTA. It will fall back to generate a full OTA on
2018 # failure unless no_fallback_to_full is specified.
2019 else:
2020 print "unzipping source target-files..."
2021 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
2022 OPTIONS.incremental_source)
2023 OPTIONS.target_info_dict = OPTIONS.info_dict
2024 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip,
2025 OPTIONS.source_tmp)
2026 if OPTIONS.verbose:
2027 print "--- source info ---"
2028 common.DumpInfoDict(OPTIONS.source_info_dict)
2029 try:
2030 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Baod62c6032015-11-30 09:40:20 -08002031 if OPTIONS.log_diff:
2032 out_file = open(OPTIONS.log_diff, 'w')
2033 import target_files_diff
2034 target_files_diff.recursiveDiff('',
2035 OPTIONS.source_tmp,
2036 OPTIONS.input_tmp,
2037 out_file)
2038 out_file.close()
Tao Bao767e3ac2015-11-10 12:19:19 -08002039 except ValueError:
2040 if not OPTIONS.fallback_to_full:
2041 raise
2042 print "--- failed to build incremental; falling back to full ---"
2043 OPTIONS.incremental_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -07002044 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07002045
Tao Bao767e3ac2015-11-10 12:19:19 -08002046 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07002047
Tao Bao767e3ac2015-11-10 12:19:19 -08002048 # Sign the generated zip package unless no_signing is specified.
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09002049 if not OPTIONS.no_signing:
2050 SignOutput(temp_zip_file.name, args[1])
2051 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07002052
Doug Zongkereef39442009-04-02 12:14:19 -07002053 print "done."
2054
2055
2056if __name__ == '__main__':
2057 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08002058 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07002059 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07002060 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07002061 print
2062 print " ERROR: %s" % (e,)
2063 print
2064 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07002065 finally:
2066 common.Cleanup()