blob: f51920a1526a5a4420eec9d98c6f985cab6f20cc [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")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001427 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001428 oem_dict = common.LoadDictionaryFromLines(
1429 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001430
Dan Albert8b72aef2015-03-23 19:13:21 -07001431 metadata = {
1432 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1433 OPTIONS.source_info_dict),
Tao Baod8d14be2016-02-04 14:26:02 -08001434 "ota-type": "FILE",
Dan Albert8b72aef2015-03-23 19:13:21 -07001435 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001436
Tao Bao5d182562016-02-23 11:38:39 -08001437 post_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict)
1438 pre_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
1439 is_downgrade = long(post_timestamp) < long(pre_timestamp)
1440
1441 if OPTIONS.downgrade:
1442 metadata["ota-downgrade"] = "yes"
1443 if not is_downgrade:
1444 raise RuntimeError("--downgrade specified but no downgrade detected: "
1445 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
1446 else:
1447 if is_downgrade:
1448 # Non-fatal here to allow generating such a package which may require
1449 # manual work to adjust the post-timestamp. A legit use case is that we
1450 # cut a new build C (after having A and B), but want to enfore the
1451 # update path of A -> C -> B. Specifying --downgrade may not help since
1452 # that would enforce a data wipe for C -> B update.
1453 print("\nWARNING: downgrade detected: pre: %s, post: %s.\n"
1454 "The package may not be deployed properly. "
1455 "Try --downgrade?\n" % (pre_timestamp, post_timestamp))
1456 metadata["post-timestamp"] = post_timestamp
1457
Doug Zongker05d3dea2009-06-22 11:32:31 -07001458 device_specific = common.DeviceSpecificParams(
1459 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001460 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001461 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001462 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001463 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001464 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001465 metadata=metadata,
Tao Bao6f0b2192015-10-13 16:37:12 -07001466 info_dict=OPTIONS.source_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001467
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001468 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001469 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001470 if HasVendorPartition(target_zip):
1471 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001472 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001473 else:
1474 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001475
Dan Albert8b72aef2015-03-23 19:13:21 -07001476 target_fp = CalculateFingerprint(oem_props, oem_dict,
1477 OPTIONS.target_info_dict)
1478 source_fp = CalculateFingerprint(oem_props, oem_dict,
1479 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001480
1481 if oem_props is None:
1482 script.AssertSomeFingerprint(source_fp, target_fp)
1483 else:
1484 script.AssertSomeThumbprint(
1485 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1486 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1487
Doug Zongker2ea21062010-04-28 16:05:21 -07001488 metadata["pre-build"] = source_fp
1489 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001490
Doug Zongker55d93282011-01-25 17:03:34 -08001491 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001492 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1493 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001494 target_boot = common.GetBootableImage(
1495 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001496 updating_boot = (not OPTIONS.two_step and
1497 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001498
Doug Zongker55d93282011-01-25 17:03:34 -08001499 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001500 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1501 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001502 target_recovery = common.GetBootableImage(
1503 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001504 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001505
Doug Zongker881dd402009-09-20 14:03:55 -07001506 # Here's how we divide up the progress bar:
1507 # 0.1 for verifying the start state (PatchCheck calls)
1508 # 0.8 for applying patches (ApplyPatch calls)
1509 # 0.1 for unpacking verbatim files, symlinking, and doing the
1510 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001511
Michael Runge6e836112014-04-15 17:40:21 -07001512 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001513 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001514
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001515 # Two-step incremental package strategy (in chronological order,
1516 # which is *not* the order in which the generated script has
1517 # things):
1518 #
1519 # if stage is not "2/3" or "3/3":
1520 # do verification on current system
1521 # write recovery image to boot partition
1522 # set stage to "2/3"
1523 # reboot to boot partition and restart recovery
1524 # else if stage is "2/3":
1525 # write recovery image to recovery partition
1526 # set stage to "3/3"
1527 # reboot to recovery partition and restart recovery
1528 # else:
1529 # (stage must be "3/3")
1530 # perform update:
1531 # patch system files, etc.
1532 # force full install of new boot image
1533 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001534 # complete script normally
1535 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001536
1537 if OPTIONS.two_step:
Tao Baodd24da92015-07-29 14:09:23 -07001538 if not OPTIONS.source_info_dict.get("multistage_support", None):
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001539 assert False, "two-step packages not supported by this build"
Tao Baodd24da92015-07-29 14:09:23 -07001540 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001541 assert fs.fs_type.upper() == "EMMC", \
1542 "two-step packages only supported on devices with EMMC /misc partitions"
1543 bcb_dev = {"bcb_dev": fs.device}
1544 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1545 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001546if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001547""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001548 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001549 script.WriteRawImage("/recovery", "recovery.img")
1550 script.AppendExtra("""
1551set_stage("%(bcb_dev)s", "3/3");
1552reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001553else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001554""" % bcb_dev)
1555
Tao Bao6c55a8a2015-04-08 15:30:27 -07001556 # Dump fingerprints
1557 script.Print("Source: %s" % (source_fp,))
1558 script.Print("Target: %s" % (target_fp,))
1559
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001560 script.Print("Verifying current system...")
1561
Doug Zongkere5ff5902012-01-17 10:55:37 -08001562 device_specific.IncrementalOTA_VerifyBegin()
1563
Doug Zongker881dd402009-09-20 14:03:55 -07001564 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001565 so_far = system_diff.EmitVerification(script)
1566 if vendor_diff:
1567 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001568
Tao Baod8d14be2016-02-04 14:26:02 -08001569 size = []
1570 if system_diff.patch_list:
1571 size.append(system_diff.largest_source_size)
1572 if vendor_diff:
1573 if vendor_diff.patch_list:
1574 size.append(vendor_diff.largest_source_size)
1575
Doug Zongker5da317e2009-06-02 13:38:17 -07001576 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001577 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001578 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001579 print "boot target: %d source: %d diff: %d" % (
1580 target_boot.size, source_boot.size, len(d))
1581
Doug Zongker048e7ca2009-06-15 14:31:53 -07001582 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001583
Tao Baodd24da92015-07-29 14:09:23 -07001584 boot_type, boot_device = common.GetTypeAndDevice(
1585 "/boot", OPTIONS.source_info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001586
1587 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1588 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001589 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001590 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001591 so_far += source_boot.size
Tao Baod8d14be2016-02-04 14:26:02 -08001592 size.append(target_boot.size)
Doug Zongker5da317e2009-06-02 13:38:17 -07001593
Tao Baod8d14be2016-02-04 14:26:02 -08001594 if size:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001595 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001596
Doug Zongker05d3dea2009-06-22 11:32:31 -07001597 device_specific.IncrementalOTA_VerifyEnd()
1598
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001599 if OPTIONS.two_step:
1600 script.WriteRawImage("/boot", "recovery.img")
1601 script.AppendExtra("""
1602set_stage("%(bcb_dev)s", "2/3");
1603reboot_now("%(bcb_dev)s", "");
1604else
1605""" % bcb_dev)
1606
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001607 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001608
Doug Zongkere5ff5902012-01-17 10:55:37 -08001609 device_specific.IncrementalOTA_InstallBegin()
1610
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001611 if OPTIONS.two_step:
1612 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1613 script.WriteRawImage("/boot", "boot.img")
1614 print "writing full boot image (forced by two-step mode)"
1615
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001616 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001617 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1618 if vendor_diff:
1619 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001620
Doug Zongker881dd402009-09-20 14:03:55 -07001621 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001622 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1623 if vendor_diff:
1624 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001625 if updating_boot:
1626 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001627
1628 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001629 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1630 if vendor_diff:
1631 script.Print("Patching vendor files...")
1632 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001633
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001634 if not OPTIONS.two_step:
1635 if updating_boot:
1636 # Produce the boot image by applying a patch to the current
1637 # contents of the boot partition, and write it back to the
1638 # partition.
1639 script.Print("Patching boot image...")
1640 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1641 % (boot_type, boot_device,
1642 source_boot.size, source_boot.sha1,
1643 target_boot.size, target_boot.sha1),
1644 "-",
1645 target_boot.size, target_boot.sha1,
1646 source_boot.sha1, "patch/boot.img.p")
1647 so_far += target_boot.size
1648 script.SetProgress(so_far / total_patch_size)
1649 print "boot image changed; including."
1650 else:
1651 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001652
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001653 system_items = ItemSet("system", "META/filesystem_config.txt")
1654 if vendor_diff:
1655 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1656
Doug Zongkereef39442009-04-02 12:14:19 -07001657 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001658 # Recovery is generated as a patch using both the boot image
1659 # (which contains the same linux kernel as recovery) and the file
1660 # /system/etc/recovery-resource.dat (which contains all the images
1661 # used in the recovery UI) as sources. This lets us minimize the
1662 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001663 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001664 # For older builds where recovery-resource.dat is not present, we
1665 # use only the boot image as the source.
1666
Doug Zongkerc9253822014-02-04 12:17:58 -08001667 if not target_has_recovery_patch:
1668 def output_sink(fn, data):
1669 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001670 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001671
1672 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1673 target_recovery, target_boot)
1674 script.DeleteFiles(["/system/recovery-from-boot.p",
Tao Baof2cffbd2015-07-22 12:33:18 -07001675 "/system/etc/recovery.img",
Doug Zongkerc9253822014-02-04 12:17:58 -08001676 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001677 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001678 else:
1679 print "recovery image unchanged; skipping."
1680
Doug Zongker881dd402009-09-20 14:03:55 -07001681 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001682
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001683 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1684 if vendor_diff:
1685 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1686
1687 temp_script = script.MakeTemporary()
1688 system_items.GetMetadata(target_zip)
1689 system_items.Get("system").SetPermissions(temp_script)
1690 if vendor_diff:
1691 vendor_items.GetMetadata(target_zip)
1692 vendor_items.Get("vendor").SetPermissions(temp_script)
1693
1694 # Note that this call will mess up the trees of Items, so make sure
1695 # we're done with them.
1696 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1697 if vendor_diff:
1698 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001699
1700 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001701 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1702
1703 # Delete all the symlinks in source that aren't in target. This
1704 # needs to happen before verbatim files are unpacked, in case a
1705 # symlink in the source is replaced by a real file in the target.
Tao Bao84006ea2015-09-02 10:28:08 -07001706
1707 # If a symlink in the source will be replaced by a regular file, we cannot
1708 # delete the symlink/file in case the package gets applied again. For such
1709 # a symlink, we prepend a sha1_check() to detect if it has been updated.
1710 # (Bug: 23646151)
1711 replaced_symlinks = dict()
1712 if system_diff:
1713 for i in system_diff.verbatim_targets:
1714 replaced_symlinks["/%s" % (i[0],)] = i[2]
1715 if vendor_diff:
1716 for i in vendor_diff.verbatim_targets:
1717 replaced_symlinks["/%s" % (i[0],)] = i[2]
1718
1719 if system_diff:
1720 for tf in system_diff.renames.values():
1721 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1722 if vendor_diff:
1723 for tf in vendor_diff.renames.values():
1724 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1725
1726 always_delete = []
1727 may_delete = []
Doug Zongkereef39442009-04-02 12:14:19 -07001728 for dest, link in source_symlinks:
1729 if link not in target_symlinks_d:
Tao Bao84006ea2015-09-02 10:28:08 -07001730 if link in replaced_symlinks:
1731 may_delete.append((link, replaced_symlinks[link]))
1732 else:
1733 always_delete.append(link)
1734 script.DeleteFiles(always_delete)
1735 script.DeleteFilesIfNotMatching(may_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001736
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001737 if system_diff.verbatim_targets:
1738 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001739 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001740 if vendor_diff and vendor_diff.verbatim_targets:
1741 script.Print("Unpacking new vendor files...")
1742 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001743
Doug Zongkerc9253822014-02-04 12:17:58 -08001744 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001745 script.Print("Unpacking new recovery...")
1746 script.UnpackPackageDir("recovery", "/system")
1747
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001748 system_diff.EmitRenames(script)
1749 if vendor_diff:
1750 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001751
Doug Zongker05d3dea2009-06-22 11:32:31 -07001752 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001753
1754 # Create all the symlinks that don't already exist, or point to
1755 # somewhere different than what we want. Delete each symlink before
1756 # creating it, since the 'symlink' command won't overwrite.
1757 to_create = []
1758 for dest, link in target_symlinks:
1759 if link in source_symlinks_d:
1760 if dest != source_symlinks_d[link]:
1761 to_create.append((dest, link))
1762 else:
1763 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001764 script.DeleteFiles([i[1] for i in to_create])
1765 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001766
1767 # Now that the symlinks are created, we can set all the
1768 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001769 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001770
Doug Zongker881dd402009-09-20 14:03:55 -07001771 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001772 device_specific.IncrementalOTA_InstallEnd()
1773
Doug Zongker1c390a22009-05-14 19:06:36 -07001774 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001775 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001776
Doug Zongkere92f15a2011-08-26 13:46:40 -07001777 # Patch the build.prop file last, so if something fails but the
1778 # device can still come up, it appears to be the old build and will
1779 # get set the OTA package again to retry.
1780 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001781 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001782
Doug Zongker922206e2014-03-04 13:16:24 -08001783 if OPTIONS.wipe_user_data:
1784 script.Print("Erasing user data...")
1785 script.FormatPartition("/data")
Tao Bao5d182562016-02-23 11:38:39 -08001786 metadata["ota-wipe"] = "yes"
Doug Zongker922206e2014-03-04 13:16:24 -08001787
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001788 if OPTIONS.two_step:
1789 script.AppendExtra("""
1790set_stage("%(bcb_dev)s", "");
1791endif;
1792endif;
1793""" % bcb_dev)
1794
Michael Runge63f01de2014-10-28 19:24:19 -07001795 if OPTIONS.verify and system_diff:
1796 script.Print("Remounting and verifying system partition files...")
1797 script.Unmount("/system")
Tao Bao269d7852015-12-02 15:49:13 -08001798 script.Mount("/system", recovery_mount_options)
Michael Runge63f01de2014-10-28 19:24:19 -07001799 system_diff.EmitExplicitTargetVerification(script)
1800
1801 if OPTIONS.verify and vendor_diff:
1802 script.Print("Remounting and verifying vendor partition files...")
1803 script.Unmount("/vendor")
Tao Bao269d7852015-12-02 15:49:13 -08001804 script.Mount("/vendor", recovery_mount_options)
Michael Runge63f01de2014-10-28 19:24:19 -07001805 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001806 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001807
Tao Baod8d14be2016-02-04 14:26:02 -08001808 metadata["ota-required-cache"] = str(script.required_cache)
Doug Zongker2ea21062010-04-28 16:05:21 -07001809 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001810
1811
1812def main(argv):
1813
1814 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001815 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001816 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001817 elif o in ("-k", "--package_key"):
1818 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001819 elif o in ("-i", "--incremental_from"):
1820 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001821 elif o == "--full_radio":
1822 OPTIONS.full_radio = True
leozwangaa6c1a12015-08-14 10:57:58 -07001823 elif o == "--full_bootloader":
1824 OPTIONS.full_bootloader = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001825 elif o in ("-w", "--wipe_user_data"):
1826 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001827 elif o in ("-n", "--no_prereq"):
1828 OPTIONS.omit_prereq = True
Tao Bao5d182562016-02-23 11:38:39 -08001829 elif o == "--downgrade":
1830 OPTIONS.downgrade = True
1831 OPTIONS.wipe_user_data = True
Michael Runge6e836112014-04-15 17:40:21 -07001832 elif o in ("-o", "--oem_settings"):
1833 OPTIONS.oem_source = a
Tao Bao8608cde2016-02-25 19:49:55 -08001834 elif o == "--oem_no_mount":
1835 OPTIONS.oem_no_mount = True
Doug Zongker1c390a22009-05-14 19:06:36 -07001836 elif o in ("-e", "--extra_script"):
1837 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001838 elif o in ("-a", "--aslr_mode"):
1839 if a in ("on", "On", "true", "True", "yes", "Yes"):
1840 OPTIONS.aslr_mode = True
1841 else:
1842 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001843 elif o in ("-t", "--worker_threads"):
1844 if a.isdigit():
1845 OPTIONS.worker_threads = int(a)
1846 else:
1847 raise ValueError("Cannot parse value %r for option %r - only "
1848 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001849 elif o in ("-2", "--two_step"):
1850 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001851 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001852 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001853 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001854 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001855 elif o == "--block":
1856 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001857 elif o in ("-b", "--binary"):
1858 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001859 elif o in ("--no_fallback_to_full",):
1860 OPTIONS.fallback_to_full = False
Tao Bao8dcf7382015-05-21 14:09:49 -07001861 elif o == "--stash_threshold":
1862 try:
1863 OPTIONS.stash_threshold = float(a)
1864 except ValueError:
1865 raise ValueError("Cannot parse value %r for option %r - expecting "
1866 "a float" % (a, o))
Tao Bao9bc6bb22015-11-09 16:58:28 -08001867 elif o == "--gen_verify":
1868 OPTIONS.gen_verify = True
Tao Baod62c6032015-11-30 09:40:20 -08001869 elif o == "--log_diff":
1870 OPTIONS.log_diff = a
Doug Zongkereef39442009-04-02 12:14:19 -07001871 else:
1872 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001873 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001874
1875 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001876 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001877 extra_long_opts=[
1878 "board_config=",
1879 "package_key=",
1880 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001881 "full_radio",
leozwangaa6c1a12015-08-14 10:57:58 -07001882 "full_bootloader",
Dan Albert8b72aef2015-03-23 19:13:21 -07001883 "wipe_user_data",
1884 "no_prereq",
Tao Bao5d182562016-02-23 11:38:39 -08001885 "downgrade",
Dan Albert8b72aef2015-03-23 19:13:21 -07001886 "extra_script=",
1887 "worker_threads=",
1888 "aslr_mode=",
1889 "two_step",
1890 "no_signing",
1891 "block",
1892 "binary=",
1893 "oem_settings=",
Tao Bao8608cde2016-02-25 19:49:55 -08001894 "oem_no_mount",
Dan Albert8b72aef2015-03-23 19:13:21 -07001895 "verify",
1896 "no_fallback_to_full",
Tao Bao8dcf7382015-05-21 14:09:49 -07001897 "stash_threshold=",
Tao Baod62c6032015-11-30 09:40:20 -08001898 "gen_verify",
1899 "log_diff=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001900 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001901
1902 if len(args) != 2:
1903 common.Usage(__doc__)
1904 sys.exit(1)
1905
Tao Bao5d182562016-02-23 11:38:39 -08001906 if OPTIONS.downgrade:
1907 # Sanity check to enforce a data wipe.
1908 if not OPTIONS.wipe_user_data:
1909 raise ValueError("Cannot downgrade without a data wipe")
1910
1911 # We should only allow downgrading incrementals (as opposed to full).
1912 # Otherwise the device may go back from arbitrary build with this full
1913 # OTA package.
1914 if OPTIONS.incremental_source is None:
1915 raise ValueError("Cannot generate downgradable full OTAs - consider"
1916 "using --omit_prereq?")
1917
Tao Baoc098e9e2016-01-07 13:03:56 -08001918 # Load the dict file from the zip directly to have a peek at the OTA type.
1919 # For packages using A/B update, unzipping is not needed.
1920 input_zip = zipfile.ZipFile(args[0], "r")
1921 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
1922 common.ZipClose(input_zip)
1923
1924 ab_update = OPTIONS.info_dict.get("ab_update") == "true"
1925
1926 if ab_update:
1927 if OPTIONS.incremental_source is not None:
1928 OPTIONS.target_info_dict = OPTIONS.info_dict
1929 source_zip = zipfile.ZipFile(OPTIONS.incremental_source, "r")
1930 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1931 common.ZipClose(source_zip)
1932
1933 if OPTIONS.verbose:
1934 print "--- target info ---"
1935 common.DumpInfoDict(OPTIONS.info_dict)
1936
1937 if OPTIONS.incremental_source is not None:
1938 print "--- source info ---"
1939 common.DumpInfoDict(OPTIONS.source_info_dict)
1940
1941 WriteABOTAPackageWithBrilloScript(
1942 target_file=args[0],
1943 output_file=args[1],
1944 source_file=OPTIONS.incremental_source)
1945
1946 print "done."
1947 return
1948
Doug Zongker1c390a22009-05-14 19:06:36 -07001949 if OPTIONS.extra_script is not None:
1950 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1951
Doug Zongkereef39442009-04-02 12:14:19 -07001952 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001953 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001954
Doug Zongkereef39442009-04-02 12:14:19 -07001955 OPTIONS.target_tmp = OPTIONS.input_tmp
Tao Bao2c15d9e2015-07-09 11:51:16 -07001956 OPTIONS.info_dict = common.LoadInfoDict(input_zip, OPTIONS.target_tmp)
Kenny Roote2e9f612013-05-29 12:59:35 -07001957
Doug Zongker37974732010-09-16 17:44:38 -07001958 if OPTIONS.verbose:
1959 print "--- target info ---"
1960 common.DumpInfoDict(OPTIONS.info_dict)
1961
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001962 # If the caller explicitly specified the device-specific extensions
1963 # path via -s/--device_specific, use that. Otherwise, use
1964 # META/releasetools.py if it is present in the target target_files.
1965 # Otherwise, take the path of the file from 'tool_extensions' in the
1966 # info dict and look for that in the local filesystem, relative to
1967 # the current directory.
1968
Doug Zongker37974732010-09-16 17:44:38 -07001969 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001970 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1971 if os.path.exists(from_input):
1972 print "(using device-specific extensions from target_files)"
1973 OPTIONS.device_specific = from_input
1974 else:
1975 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1976
Doug Zongker37974732010-09-16 17:44:38 -07001977 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001978 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001979
Tao Baoc098e9e2016-01-07 13:03:56 -08001980 if OPTIONS.info_dict.get("no_recovery") == "true":
Tao Baodb45efa2015-10-27 19:25:18 -07001981 raise common.ExternalError(
1982 "--- target build has specified no recovery ---")
1983
Tao Bao767e3ac2015-11-10 12:19:19 -08001984 # Use the default key to sign the package if not specified with package_key.
1985 if not OPTIONS.no_signing:
1986 if OPTIONS.package_key is None:
1987 OPTIONS.package_key = OPTIONS.info_dict.get(
1988 "default_system_dev_certificate",
1989 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -07001990
Tao Bao767e3ac2015-11-10 12:19:19 -08001991 # Set up the output zip. Create a temporary zip file if signing is needed.
1992 if OPTIONS.no_signing:
1993 if os.path.exists(args[1]):
1994 os.unlink(args[1])
1995 output_zip = zipfile.ZipFile(args[1], "w",
1996 compression=zipfile.ZIP_DEFLATED)
1997 else:
1998 temp_zip_file = tempfile.NamedTemporaryFile()
1999 output_zip = zipfile.ZipFile(temp_zip_file, "w",
2000 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07002001
Daniel Rosenberg40ef35b2015-11-10 19:21:34 -08002002 # Non A/B OTAs rely on /cache partition to store temporary files.
Tao Bao767e3ac2015-11-10 12:19:19 -08002003 cache_size = OPTIONS.info_dict.get("cache_size", None)
Tao Baoc098e9e2016-01-07 13:03:56 -08002004 if cache_size is None:
Tao Bao767e3ac2015-11-10 12:19:19 -08002005 print "--- can't determine the cache partition size ---"
2006 OPTIONS.cache_size = cache_size
Tao Bao8dcf7382015-05-21 14:09:49 -07002007
Tao Bao9bc6bb22015-11-09 16:58:28 -08002008 # Generate a verify package.
2009 if OPTIONS.gen_verify:
2010 WriteVerifyPackage(input_zip, output_zip)
2011
Tao Bao767e3ac2015-11-10 12:19:19 -08002012 # Generate a full OTA.
Tao Bao9bc6bb22015-11-09 16:58:28 -08002013 elif OPTIONS.incremental_source is None:
Tao Baoc098e9e2016-01-07 13:03:56 -08002014 WriteFullOTAPackage(input_zip, output_zip)
Tao Bao767e3ac2015-11-10 12:19:19 -08002015
2016 # Generate an incremental OTA. It will fall back to generate a full OTA on
2017 # failure unless no_fallback_to_full is specified.
2018 else:
2019 print "unzipping source target-files..."
2020 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
2021 OPTIONS.incremental_source)
2022 OPTIONS.target_info_dict = OPTIONS.info_dict
2023 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip,
2024 OPTIONS.source_tmp)
2025 if OPTIONS.verbose:
2026 print "--- source info ---"
2027 common.DumpInfoDict(OPTIONS.source_info_dict)
2028 try:
2029 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Baod62c6032015-11-30 09:40:20 -08002030 if OPTIONS.log_diff:
2031 out_file = open(OPTIONS.log_diff, 'w')
2032 import target_files_diff
2033 target_files_diff.recursiveDiff('',
2034 OPTIONS.source_tmp,
2035 OPTIONS.input_tmp,
2036 out_file)
2037 out_file.close()
Tao Bao767e3ac2015-11-10 12:19:19 -08002038 except ValueError:
2039 if not OPTIONS.fallback_to_full:
2040 raise
2041 print "--- failed to build incremental; falling back to full ---"
2042 OPTIONS.incremental_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -07002043 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07002044
Tao Bao767e3ac2015-11-10 12:19:19 -08002045 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07002046
Tao Bao767e3ac2015-11-10 12:19:19 -08002047 # Sign the generated zip package unless no_signing is specified.
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09002048 if not OPTIONS.no_signing:
2049 SignOutput(temp_zip_file.name, args[1])
2050 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07002051
Doug Zongkereef39442009-04-02 12:14:19 -07002052 print "done."
2053
2054
2055if __name__ == '__main__':
2056 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08002057 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07002058 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07002059 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07002060 print
2061 print " ERROR: %s" % (e,)
2062 print
2063 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07002064 finally:
2065 common.Cleanup()