blob: b59b38b75c4b404fca96500ec82fd9a3fd53615a [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
leozwanga1fcaf82015-09-15 08:44:12 -070045 --full_bootloader
46 When generating an incremental OTA, always include a full copy of
47 bootloader image. This option is only meaningful when -i is specified,
48 because a full bootloader is always included in a full OTA if applicable.
49
Michael Runge63f01de2014-10-28 19:24:19 -070050 -v (--verify)
51 Remount and verify the checksums of the files written to the
52 system and vendor (if used) partitions. Incremental builds only.
53
Michael Runge6e836112014-04-15 17:40:21 -070054 -o (--oem_settings) <file>
55 Use the file to specify the expected OEM-specific properties
56 on the OEM partition of the intended device.
57
Tao Baodf4cb0b2016-02-25 19:49:55 -080058 --oem_no_mount
59 For devices with OEM-specific properties but without an OEM partition,
60 do not mount the OEM partition in the updater-script. This should be
61 very rarely used, since it's expected to have a dedicated OEM partition
62 for OEM-specific properties. Only meaningful when -o is specified.
63
Doug Zongkerdbfaae52009-04-21 17:12:54 -070064 -w (--wipe_user_data)
65 Generate an OTA package that will wipe the user data partition
66 when installed.
67
Doug Zongker962069c2009-04-23 11:41:58 -070068 -n (--no_prereq)
69 Omit the timestamp prereq check normally included at the top of
70 the build scripts (used for developer OTA packages which
71 legitimately need to go back and forth).
72
Tao Bao177c6102016-02-23 11:38:39 -080073 --downgrade
74 Intentionally generate an incremental OTA that updates from a newer
75 build to an older one (based on timestamp comparison). "post-timestamp"
76 will be replaced by "ota-downgrade=yes" in the metadata file. A data
77 wipe will always be enforced, so "ota-wipe=yes" will also be included in
Tao Baofa41fb22016-03-08 17:53:39 -080078 the metadata file. The update-binary in the source build will be used in
79 the OTA package, unless --binary flag is specified.
Tao Bao177c6102016-02-23 11:38:39 -080080
Doug Zongker1c390a22009-05-14 19:06:36 -070081 -e (--extra_script) <file>
82 Insert the contents of file at the end of the update script.
83
Hristo Bojinovdafb0422010-08-26 14:35:16 -070084 -a (--aslr_mode) <on|off>
85 Specify whether to turn on ASLR for the package (on by default).
Stephen Smalley56882bf2012-02-09 13:36:21 -050086
Doug Zongker9b23f2c2013-11-25 14:44:12 -080087 -2 (--two_step)
88 Generate a 'two-step' OTA package, where recovery is updated
89 first, so that any changes made to the system partition are done
90 using the new recovery (new kernel, etc.).
91
Doug Zongker26e66192014-02-20 13:22:07 -080092 --block
93 Generate a block-based OTA if possible. Will fall back to a
94 file-based OTA if the target_files is older and doesn't support
95 block-based OTAs.
96
Doug Zongker25568482014-03-03 10:21:27 -080097 -b (--binary) <file>
98 Use the given binary as the update-binary in the output package,
99 instead of the binary in the build's target_files. Use for
100 development only.
101
Martin Blumenstingl374e1142014-05-31 20:42:55 +0200102 -t (--worker_threads) <int>
103 Specifies the number of worker-threads that will be used when
104 generating patches for incremental updates (defaults to 3).
105
Tao Baod47d8e12015-05-21 14:09:49 -0700106 --stash_threshold <float>
107 Specifies the threshold that will be used to compute the maximum
108 allowed stash size (defaults to 0.8).
Doug Zongkereef39442009-04-02 12:14:19 -0700109"""
110
111import sys
112
Doug Zongkercf6d5a92014-02-18 10:57:07 -0800113if sys.hexversion < 0x02070000:
114 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -0700115 sys.exit(1)
116
Doug Zongkerfc44a512014-08-26 13:10:25 -0700117import multiprocessing
Doug Zongkereef39442009-04-02 12:14:19 -0700118import os
Doug Zongkereef39442009-04-02 12:14:19 -0700119import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -0700120import zipfile
121
122import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700123import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -0700124import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700125
126OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700127OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700128OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700129OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700130OPTIONS.require_verbatim = set()
131OPTIONS.prohibit_verbatim = set(("system/build.prop",))
132OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700133OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700134OPTIONS.omit_prereq = False
Tao Bao177c6102016-02-23 11:38:39 -0800135OPTIONS.downgrade = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700136OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700137OPTIONS.aslr_mode = True
Doug Zongkerfc44a512014-08-26 13:10:25 -0700138OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
139if OPTIONS.worker_threads == 0:
140 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800141OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900142OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800143OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800144OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700145OPTIONS.oem_source = None
Tao Baodf4cb0b2016-02-25 19:49:55 -0800146OPTIONS.oem_no_mount = False
Doug Zongker62d4f182014-08-04 16:06:43 -0700147OPTIONS.fallback_to_full = True
Tao Bao43078aa2015-04-21 14:32:35 -0700148OPTIONS.full_radio = False
leozwanga1fcaf82015-09-15 08:44:12 -0700149OPTIONS.full_bootloader = False
Tao Baod47d8e12015-05-21 14:09:49 -0700150# Stash size cannot exceed cache_size * threshold.
151OPTIONS.cache_size = None
152OPTIONS.stash_threshold = 0.8
153
Doug Zongkereef39442009-04-02 12:14:19 -0700154def MostPopularKey(d, default):
155 """Given a dict, return the key corresponding to the largest
156 value. Returns 'default' if the dict is empty."""
157 x = [(v, k) for (k, v) in d.iteritems()]
Dan Albert8b72aef2015-03-23 19:13:21 -0700158 if not x:
159 return default
Doug Zongkereef39442009-04-02 12:14:19 -0700160 x.sort()
161 return x[-1][1]
162
163
164def IsSymlink(info):
165 """Return true if the zipfile.ZipInfo object passed in represents a
166 symlink."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700167 return (info.external_attr >> 16) == 0o120777
Doug Zongkereef39442009-04-02 12:14:19 -0700168
Hristo Bojinov96be7202010-08-02 10:26:17 -0700169def IsRegular(info):
170 """Return true if the zipfile.ZipInfo object passed in represents a
171 symlink."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700172 return (info.external_attr >> 28) == 0o10
Doug Zongkereef39442009-04-02 12:14:19 -0700173
Michael Runge4038aa82013-12-13 18:06:28 -0800174def ClosestFileMatch(src, tgtfiles, existing):
175 """Returns the closest file match between a source file and list
176 of potential matches. The exact filename match is preferred,
177 then the sha1 is searched for, and finally a file with the same
178 basename is evaluated. Rename support in the updater-binary is
179 required for the latter checks to be used."""
180
181 result = tgtfiles.get("path:" + src.name)
182 if result is not None:
183 return result
184
185 if not OPTIONS.target_info_dict.get("update_rename_support", False):
186 return None
187
188 if src.size < 1000:
189 return None
190
191 result = tgtfiles.get("sha1:" + src.sha1)
192 if result is not None and existing.get(result.name) is None:
193 return result
194 result = tgtfiles.get("file:" + src.name.split("/")[-1])
195 if result is not None and existing.get(result.name) is None:
196 return result
197 return None
198
Dan Albert8b72aef2015-03-23 19:13:21 -0700199class ItemSet(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700200 def __init__(self, partition, fs_config):
201 self.partition = partition
202 self.fs_config = fs_config
203 self.ITEMS = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700204
Dan Albert8b72aef2015-03-23 19:13:21 -0700205 def Get(self, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700206 if name not in self.ITEMS:
Dan Albert8b72aef2015-03-23 19:13:21 -0700207 self.ITEMS[name] = Item(self, name, is_dir=is_dir)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700208 return self.ITEMS[name]
Doug Zongkereef39442009-04-02 12:14:19 -0700209
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700210 def GetMetadata(self, input_zip):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700211 # The target_files contains a record of what the uid,
212 # gid, and mode are supposed to be.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700213 output = input_zip.read(self.fs_config)
Doug Zongkereef39442009-04-02 12:14:19 -0700214
215 for line in output.split("\n"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700216 if not line:
217 continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700218 columns = line.split()
219 name, uid, gid, mode = columns[:4]
220 selabel = None
221 capabilities = None
222
223 # After the first 4 columns, there are a series of key=value
224 # pairs. Extract out the fields we care about.
225 for element in columns[4:]:
226 key, value = element.split("=")
227 if key == "selabel":
228 selabel = value
229 if key == "capabilities":
230 capabilities = value
231
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700232 i = self.ITEMS.get(name, None)
Doug Zongker283e2a12010-03-15 17:52:32 -0700233 if i is not None:
234 i.uid = int(uid)
235 i.gid = int(gid)
236 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700237 i.selabel = selabel
238 i.capabilities = capabilities
Dan Albert8b72aef2015-03-23 19:13:21 -0700239 if i.is_dir:
Doug Zongker283e2a12010-03-15 17:52:32 -0700240 i.children.sort(key=lambda i: i.name)
241
242 # set metadata for the files generated by this script.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700243 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700244 if i:
245 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700246 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700247 if i:
248 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700249
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700250
Dan Albert8b72aef2015-03-23 19:13:21 -0700251class Item(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700252 """Items represent the metadata (user, group, mode) of files and
253 directories in the system image."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700254 def __init__(self, itemset, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700255 self.itemset = itemset
256 self.name = name
257 self.uid = None
258 self.gid = None
259 self.mode = None
260 self.selabel = None
261 self.capabilities = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700262 self.is_dir = is_dir
263 self.descendants = None
264 self.best_subtree = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700265
266 if name:
Dan Albert8b72aef2015-03-23 19:13:21 -0700267 self.parent = itemset.Get(os.path.dirname(name), is_dir=True)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700268 self.parent.children.append(self)
269 else:
270 self.parent = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700271 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700272 self.children = []
273
274 def Dump(self, indent=0):
275 if self.uid is not None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700276 print "%s%s %d %d %o" % (
277 " " * indent, self.name, self.uid, self.gid, self.mode)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700278 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700279 print "%s%s %s %s %s" % (
280 " " * indent, self.name, self.uid, self.gid, self.mode)
281 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700282 print "%s%s" % (" "*indent, self.descendants)
283 print "%s%s" % (" "*indent, self.best_subtree)
284 for i in self.children:
285 i.Dump(indent=indent+1)
286
Doug Zongkereef39442009-04-02 12:14:19 -0700287 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700288 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
Dan Albert8b72aef2015-03-23 19:13:21 -0700289 all children and determine the best strategy for using set_perm_recursive
290 and set_perm to correctly chown/chmod all the files to their desired
Doug Zongkereef39442009-04-02 12:14:19 -0700291 values. Recursively calls itself for all descendants.
292
Dan Albert8b72aef2015-03-23 19:13:21 -0700293 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count}
294 counting up all descendants of this node. (dmode or fmode may be None.)
295 Also sets the best_subtree of each directory Item to the (uid, gid, dmode,
296 fmode, selabel, capabilities) tuple that will match the most descendants of
297 that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700298 """
299
Dan Albert8b72aef2015-03-23 19:13:21 -0700300 assert self.is_dir
301 key = (self.uid, self.gid, self.mode, None, self.selabel,
302 self.capabilities)
303 self.descendants = {key: 1}
304 d = self.descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700305 for i in self.children:
Dan Albert8b72aef2015-03-23 19:13:21 -0700306 if i.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700307 for k, v in i.CountChildMetadata().iteritems():
308 d[k] = d.get(k, 0) + v
309 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700310 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700311 d[k] = d.get(k, 0) + 1
312
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700313 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
314 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700315
316 # First, find the (uid, gid) pair that matches the most
317 # descendants.
318 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700319 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700320 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
321 ug = MostPopularKey(ug, (0, 0))
322
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700323 # Now find the dmode, fmode, selabel, and capabilities that match
324 # the most descendants with that (uid, gid), and choose those.
Dan Albert8b72aef2015-03-23 19:13:21 -0700325 best_dmode = (0, 0o755)
326 best_fmode = (0, 0o644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700327 best_selabel = (0, None)
328 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700329 for k, count in d.iteritems():
Dan Albert8b72aef2015-03-23 19:13:21 -0700330 if k[:2] != ug:
331 continue
332 if k[2] is not None and count >= best_dmode[0]:
333 best_dmode = (count, k[2])
334 if k[3] is not None and count >= best_fmode[0]:
335 best_fmode = (count, k[3])
336 if k[4] is not None and count >= best_selabel[0]:
337 best_selabel = (count, k[4])
338 if k[5] is not None and count >= best_capabilities[0]:
339 best_capabilities = (count, k[5])
340 self.best_subtree = ug + (
341 best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700342
343 return d
344
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700345 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700346 """Append set_perm/set_perm_recursive commands to 'script' to
347 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700348 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700349
350 self.CountChildMetadata()
351
352 def recurse(item, current):
Dan Albert8b72aef2015-03-23 19:13:21 -0700353 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple
354 # that the current item (and all its children) have already been set to.
355 # We only need to issue set_perm/set_perm_recursive commands if we're
Doug Zongkereef39442009-04-02 12:14:19 -0700356 # supposed to be something different.
Dan Albert8b72aef2015-03-23 19:13:21 -0700357 if item.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700358 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700359 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700360 current = item.best_subtree
361
362 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700363 item.mode != current[2] or item.selabel != current[4] or \
364 item.capabilities != current[5]:
365 script.SetPermissions("/"+item.name, item.uid, item.gid,
366 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700367
368 for i in item.children:
369 recurse(i, current)
370 else:
371 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700372 item.mode != current[3] or item.selabel != current[4] or \
373 item.capabilities != current[5]:
374 script.SetPermissions("/"+item.name, item.uid, item.gid,
375 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700376
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700377 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700378
379
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700380def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
381 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700382 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800383 list of symlinks. output_zip may be None, in which case the copy is
384 skipped (but the other side effects still happen). substitute is an
385 optional dict of {output filename: contents} to be output instead of
386 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700387 """
388
389 symlinks = []
390
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700391 partition = itemset.partition
392
Doug Zongkereef39442009-04-02 12:14:19 -0700393 for info in input_zip.infolist():
Tao Baoeaf885b2015-03-23 16:01:17 -0700394 prefix = partition.upper() + "/"
395 if info.filename.startswith(prefix):
396 basefilename = info.filename[len(prefix):]
Doug Zongkereef39442009-04-02 12:14:19 -0700397 if IsSymlink(info):
398 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700399 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700400 else:
Tao Baof3282b42015-04-01 11:21:55 -0700401 import copy
Doug Zongkereef39442009-04-02 12:14:19 -0700402 info2 = copy.copy(info)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700403 fn = info2.filename = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700404 if substitute and fn in substitute and substitute[fn] is None:
405 continue
406 if output_zip is not None:
407 if substitute and fn in substitute:
408 data = substitute[fn]
409 else:
410 data = input_zip.read(info.filename)
Tao Baof3282b42015-04-01 11:21:55 -0700411 common.ZipWriteStr(output_zip, info2, data)
Doug Zongkereef39442009-04-02 12:14:19 -0700412 if fn.endswith("/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700413 itemset.Get(fn[:-1], is_dir=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700414 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700415 itemset.Get(fn)
Doug Zongkereef39442009-04-02 12:14:19 -0700416
417 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800418 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700419
420
Doug Zongkereef39442009-04-02 12:14:19 -0700421def SignOutput(temp_zip_name, output_zip_name):
422 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
423 pw = key_passwords[OPTIONS.package_key]
424
Doug Zongker951495f2009-08-14 12:44:19 -0700425 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
426 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700427
428
Dan Albert8b72aef2015-03-23 19:13:21 -0700429def AppendAssertions(script, info_dict, oem_dict=None):
Michael Runge6e836112014-04-15 17:40:21 -0700430 oem_props = info_dict.get("oem_fingerprint_properties")
Michael Runge560569a2014-09-18 15:12:45 -0700431 if oem_props is None or len(oem_props) == 0:
Michael Runge6e836112014-04-15 17:40:21 -0700432 device = GetBuildProp("ro.product.device", info_dict)
433 script.AssertDevice(device)
434 else:
435 if oem_dict is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700436 raise common.ExternalError(
437 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700438 for prop in oem_props.split():
439 if oem_dict.get(prop) is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700440 raise common.ExternalError(
441 "The OEM file is missing the property %s" % prop)
Michael Runge6e836112014-04-15 17:40:21 -0700442 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700443
Doug Zongkereef39442009-04-02 12:14:19 -0700444
Doug Zongkerc9253822014-02-04 12:17:58 -0800445def HasRecoveryPatch(target_files_zip):
446 try:
447 target_files_zip.getinfo("SYSTEM/recovery-from-boot.p")
448 return True
449 except KeyError:
450 return False
Doug Zongker73ef8252009-07-23 15:12:53 -0700451
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700452def HasVendorPartition(target_files_zip):
453 try:
454 target_files_zip.getinfo("VENDOR/")
455 return True
456 except KeyError:
457 return False
458
Michael Runge6e836112014-04-15 17:40:21 -0700459def GetOemProperty(name, oem_props, oem_dict, info_dict):
460 if oem_props is not None and name in oem_props:
461 return oem_dict[name]
462 return GetBuildProp(name, info_dict)
463
464
465def CalculateFingerprint(oem_props, oem_dict, info_dict):
466 if oem_props is None:
467 return GetBuildProp("ro.build.fingerprint", info_dict)
468 return "%s/%s/%s:%s" % (
Dan Albert8b72aef2015-03-23 19:13:21 -0700469 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
470 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
471 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
472 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700473
Doug Zongkerfc44a512014-08-26 13:10:25 -0700474
Doug Zongker3c84f562014-07-31 11:06:30 -0700475def GetImage(which, tmpdir, info_dict):
Doug Zongkerfc44a512014-08-26 13:10:25 -0700476 # Return an image object (suitable for passing to BlockImageDiff)
477 # for the 'which' partition (most be "system" or "vendor"). If a
478 # prebuilt image and file map are found in tmpdir they are used,
479 # otherwise they are reconstructed from the individual files.
Doug Zongker3c84f562014-07-31 11:06:30 -0700480
481 assert which in ("system", "vendor")
482
483 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700484 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
485 if os.path.exists(path) and os.path.exists(mappath):
Doug Zongker3c84f562014-07-31 11:06:30 -0700486 print "using %s.img from target-files" % (which,)
Doug Zongker3c84f562014-07-31 11:06:30 -0700487 # This is a 'new' target-files, which already has the image in it.
Doug Zongker3c84f562014-07-31 11:06:30 -0700488
489 else:
490 print "building %s.img from target-files" % (which,)
491
492 # This is an 'old' target-files, which does not contain images
493 # already built. Build them.
494
Doug Zongkerfc44a512014-08-26 13:10:25 -0700495 mappath = tempfile.mkstemp()[1]
496 OPTIONS.tempfiles.append(mappath)
497
Doug Zongker3c84f562014-07-31 11:06:30 -0700498 import add_img_to_target_files
499 if which == "system":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700500 path = add_img_to_target_files.BuildSystem(
501 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700502 elif which == "vendor":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700503 path = add_img_to_target_files.BuildVendor(
504 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700505
Tao Bao5ece99d2015-05-12 11:42:31 -0700506 # Bug: http://b/20939131
507 # In ext4 filesystems, block 0 might be changed even being mounted
508 # R/O. We add it to clobbered_blocks so that it will be written to the
509 # target unconditionally. Note that they are still part of care_map.
510 clobbered_blocks = "0"
511
512 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700513
514
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700515def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700516 # TODO: how to determine this? We don't know what version it will
Tao Baobebd3cf2015-06-22 19:17:41 -0700517 # be installed on top of. For now, we expect the API just won't
518 # change very often. Similarly for fstab, it might have changed
519 # in the target build.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700520 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700521
Michael Runge6e836112014-04-15 17:40:21 -0700522 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700523 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700524 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700525 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700526 if OPTIONS.oem_source is None:
527 raise common.ExternalError("OEM source required for this build")
Tao Baodf4cb0b2016-02-25 19:49:55 -0800528 if not OPTIONS.oem_no_mount:
529 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700530 oem_dict = common.LoadDictionaryFromLines(
531 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -0700532
Dan Albert8b72aef2015-03-23 19:13:21 -0700533 metadata = {
534 "post-build": CalculateFingerprint(oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700535 OPTIONS.info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700536 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
537 OPTIONS.info_dict),
538 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
539 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700540
Doug Zongker05d3dea2009-06-22 11:32:31 -0700541 device_specific = common.DeviceSpecificParams(
542 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700543 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700544 output_zip=output_zip,
545 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700546 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700547 metadata=metadata,
548 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700549
Doug Zongkerc9253822014-02-04 12:17:58 -0800550 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800551 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800552
Doug Zongker962069c2009-04-23 11:41:58 -0700553 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700554 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700555 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
556 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700557
Michael Runge6e836112014-04-15 17:40:21 -0700558 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700559 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800560
561 # Two-step package strategy (in chronological order, which is *not*
562 # the order in which the generated script has things):
563 #
564 # if stage is not "2/3" or "3/3":
565 # write recovery image to boot partition
566 # set stage to "2/3"
567 # reboot to boot partition and restart recovery
568 # else if stage is "2/3":
569 # write recovery image to recovery partition
570 # set stage to "3/3"
571 # reboot to recovery partition and restart recovery
572 # else:
573 # (stage must be "3/3")
574 # set stage to ""
575 # do normal full package installation:
576 # wipe and install system, boot image, etc.
577 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700578 # complete script normally
579 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800580
581 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
582 OPTIONS.input_tmp, "RECOVERY")
583 if OPTIONS.two_step:
584 if not OPTIONS.info_dict.get("multistage_support", None):
585 assert False, "two-step packages not supported by this build"
586 fs = OPTIONS.info_dict["fstab"]["/misc"]
587 assert fs.fs_type.upper() == "EMMC", \
588 "two-step packages only supported on devices with EMMC /misc partitions"
589 bcb_dev = {"bcb_dev": fs.device}
590 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
591 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700592if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800593""" % bcb_dev)
594 script.WriteRawImage("/recovery", "recovery.img")
595 script.AppendExtra("""
596set_stage("%(bcb_dev)s", "3/3");
597reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700598else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800599""" % bcb_dev)
600
Tao Bao6c55a8a2015-04-08 15:30:27 -0700601 # Dump fingerprints
602 script.Print("Target: %s" % CalculateFingerprint(
603 oem_props, oem_dict, OPTIONS.info_dict))
604
Doug Zongkere5ff5902012-01-17 10:55:37 -0800605 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700606
Doug Zongker01ce19c2014-02-04 13:48:15 -0800607 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700608
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700609 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800610 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700611 if HasVendorPartition(input_zip):
612 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700613
Kenny Rootf32dc712012-04-08 10:42:34 -0700614 if "selinux_fc" in OPTIONS.info_dict:
615 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500616
Michael Runge7cd99ba2014-10-22 17:21:48 -0700617 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
618
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700619 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700620 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800621
Doug Zongker26e66192014-02-20 13:22:07 -0800622 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700623 # Full OTA is done as an "incremental" against an empty source
624 # image. This has the effect of writing new data from the package
625 # to the entire partition, but lets us reuse the updater code that
626 # writes incrementals to do it.
627 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
628 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700629 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700630 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800631 else:
632 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700633 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800634 if not has_recovery_patch:
635 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800636 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700637
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700638 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800639 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700640
Doug Zongker55d93282011-01-25 17:03:34 -0800641 boot_img = common.GetBootableImage("boot.img", "boot.img",
642 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800643
Doug Zongker91a99c22014-05-09 13:15:01 -0700644 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800645 def output_sink(fn, data):
646 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700647 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800648
649 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
650 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700651
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700652 system_items.GetMetadata(input_zip)
653 system_items.Get("system").SetPermissions(script)
654
655 if HasVendorPartition(input_zip):
656 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
657 script.ShowProgress(0.1, 0)
658
659 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700660 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
661 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700662 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700663 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700664 else:
665 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700666 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700667 script.UnpackPackageDir("vendor", "/vendor")
668
669 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
670 script.MakeSymlinks(symlinks)
671
672 vendor_items.GetMetadata(input_zip)
673 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700674
Doug Zongker37974732010-09-16 17:44:38 -0700675 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700676 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700677
Doug Zongker01ce19c2014-02-04 13:48:15 -0800678 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700679 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700680
Doug Zongker01ce19c2014-02-04 13:48:15 -0800681 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700682 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700683
Doug Zongker1c390a22009-05-14 19:06:36 -0700684 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700685 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700686
Doug Zongker14833602010-02-02 13:12:04 -0800687 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800688
Doug Zongker922206e2014-03-04 13:16:24 -0800689 if OPTIONS.wipe_user_data:
690 script.ShowProgress(0.1, 10)
691 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700692
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800693 if OPTIONS.two_step:
694 script.AppendExtra("""
695set_stage("%(bcb_dev)s", "");
696""" % bcb_dev)
697 script.AppendExtra("else\n")
698 script.WriteRawImage("/boot", "recovery.img")
699 script.AppendExtra("""
700set_stage("%(bcb_dev)s", "2/3");
701reboot_now("%(bcb_dev)s", "");
702endif;
703endif;
704""" % bcb_dev)
Tao Bao177c6102016-02-23 11:38:39 -0800705
706 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800707 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700708 WriteMetadata(metadata, output_zip)
709
Doug Zongkerfc44a512014-08-26 13:10:25 -0700710
Dan Albert8e0178d2015-01-27 15:53:15 -0800711def WritePolicyConfig(file_name, output_zip):
712 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500713
Doug Zongker2ea21062010-04-28 16:05:21 -0700714
715def WriteMetadata(metadata, output_zip):
716 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
717 "".join(["%s=%s\n" % kv
718 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700719
Doug Zongkerfc44a512014-08-26 13:10:25 -0700720
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700721def LoadPartitionFiles(z, partition):
722 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700723 ZipFile, and return a dict of {filename: File object}."""
724 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700725 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700726 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700727 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700728 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700729 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700730 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700731 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800732 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700733
734
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700735def GetBuildProp(prop, info_dict):
736 """Return the fingerprint of the build of a given target-files info_dict."""
737 try:
738 return info_dict.get("build.prop", {})[prop]
739 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700740 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700741
Doug Zongkerfc44a512014-08-26 13:10:25 -0700742
Michael Runge4038aa82013-12-13 18:06:28 -0800743def AddToKnownPaths(filename, known_paths):
744 if filename[-1] == "/":
745 return
746 dirs = filename.split("/")[:-1]
747 while len(dirs) > 0:
748 path = "/".join(dirs)
749 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700750 break
Michael Runge4038aa82013-12-13 18:06:28 -0800751 known_paths.add(path)
752 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700753
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700754
Geremy Condra36bd3652014-02-06 19:45:10 -0800755def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
756 source_version = OPTIONS.source_info_dict["recovery_api_version"]
757 target_version = OPTIONS.target_info_dict["recovery_api_version"]
758
759 if source_version == 0:
760 print ("WARNING: generating edify script for a source that "
761 "can't install it.")
Tao Baobebd3cf2015-06-22 19:17:41 -0700762 script = edify_generator.EdifyGenerator(
763 source_version, OPTIONS.target_info_dict,
764 fstab=OPTIONS.source_info_dict["fstab"])
Geremy Condra36bd3652014-02-06 19:45:10 -0800765
Tao Baodf4cb0b2016-02-25 19:49:55 -0800766 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
767 recovery_mount_options = OPTIONS.source_info_dict.get(
768 "recovery_mount_options")
769 oem_dict = None
770 if oem_props is not None and len(oem_props) > 0:
771 if OPTIONS.oem_source is None:
772 raise common.ExternalError("OEM source required for this build")
773 if not OPTIONS.oem_no_mount:
774 script.Mount("/oem", recovery_mount_options)
775 oem_dict = common.LoadDictionaryFromLines(
776 open(OPTIONS.oem_source).readlines())
777
Dan Albert8b72aef2015-03-23 19:13:21 -0700778 metadata = {
Tao Bao177c6102016-02-23 11:38:39 -0800779 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
780 OPTIONS.source_info_dict),
781 "ota-type": "BLOCK",
Dan Albert8b72aef2015-03-23 19:13:21 -0700782 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800783
Tao Bao177c6102016-02-23 11:38:39 -0800784 post_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict)
785 pre_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
786 is_downgrade = long(post_timestamp) < long(pre_timestamp)
787
788 if OPTIONS.downgrade:
789 metadata["ota-downgrade"] = "yes"
790 if not is_downgrade:
791 raise RuntimeError("--downgrade specified but no downgrade detected: "
792 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
793 else:
794 if is_downgrade:
795 # Non-fatal here to allow generating such a package which may require
796 # manual work to adjust the post-timestamp. A legit use case is that we
797 # cut a new build C (after having A and B), but want to enfore the
798 # update path of A -> C -> B. Specifying --downgrade may not help since
799 # that would enforce a data wipe for C -> B update.
800 print("\nWARNING: downgrade detected: pre: %s, post: %s.\n"
801 "The package may not be deployed properly. "
802 "Try --downgrade?\n" % (pre_timestamp, post_timestamp))
803 metadata["post-timestamp"] = post_timestamp
804
Geremy Condra36bd3652014-02-06 19:45:10 -0800805 device_specific = common.DeviceSpecificParams(
806 source_zip=source_zip,
807 source_version=source_version,
808 target_zip=target_zip,
809 target_version=target_version,
810 output_zip=output_zip,
811 script=script,
812 metadata=metadata,
Tao Baoe09359a2015-10-13 16:37:12 -0700813 info_dict=OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800814
Tao Bao177c6102016-02-23 11:38:39 -0800815 target_fp = CalculateFingerprint(oem_props, oem_dict,
816 OPTIONS.target_info_dict)
817 source_fp = CalculateFingerprint(oem_props, oem_dict,
818 OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800819 metadata["pre-build"] = source_fp
820 metadata["post-build"] = target_fp
821
822 source_boot = common.GetBootableImage(
823 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
824 OPTIONS.source_info_dict)
825 target_boot = common.GetBootableImage(
826 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
827 updating_boot = (not OPTIONS.two_step and
828 (source_boot.data != target_boot.data))
829
Geremy Condra36bd3652014-02-06 19:45:10 -0800830 target_recovery = common.GetBootableImage(
831 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800832
Doug Zongkerfc44a512014-08-26 13:10:25 -0700833 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
834 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700835
836 blockimgdiff_version = 1
837 if OPTIONS.info_dict:
838 blockimgdiff_version = max(
839 int(i) for i in
840 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
841
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700842 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700843 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700844
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700845 if HasVendorPartition(target_zip):
846 if not HasVendorPartition(source_zip):
847 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700848 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
849 OPTIONS.source_info_dict)
850 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
851 OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700852 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700853 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700854 else:
855 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800856
Michael Rungec6e3afd2014-05-05 11:55:47 -0700857 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800858 device_specific.IncrementalOTA_Assertions()
859
860 # Two-step incremental package strategy (in chronological order,
861 # which is *not* the order in which the generated script has
862 # things):
863 #
864 # if stage is not "2/3" or "3/3":
865 # do verification on current system
866 # write recovery image to boot partition
867 # set stage to "2/3"
868 # reboot to boot partition and restart recovery
869 # else if stage is "2/3":
870 # write recovery image to recovery partition
871 # set stage to "3/3"
872 # reboot to recovery partition and restart recovery
873 # else:
874 # (stage must be "3/3")
875 # perform update:
876 # patch system files, etc.
877 # force full install of new boot image
878 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700879 # complete script normally
880 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800881
882 if OPTIONS.two_step:
Tao Baocce673b2015-07-29 14:09:23 -0700883 if not OPTIONS.source_info_dict.get("multistage_support", None):
Geremy Condra36bd3652014-02-06 19:45:10 -0800884 assert False, "two-step packages not supported by this build"
Tao Baocce673b2015-07-29 14:09:23 -0700885 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Geremy Condra36bd3652014-02-06 19:45:10 -0800886 assert fs.fs_type.upper() == "EMMC", \
887 "two-step packages only supported on devices with EMMC /misc partitions"
888 bcb_dev = {"bcb_dev": fs.device}
889 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
890 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700891if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800892""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -0700893 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800894 script.WriteRawImage("/recovery", "recovery.img")
895 script.AppendExtra("""
896set_stage("%(bcb_dev)s", "3/3");
897reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700898else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800899""" % bcb_dev)
900
Tao Bao6c55a8a2015-04-08 15:30:27 -0700901 # Dump fingerprints
902 script.Print("Source: %s" % CalculateFingerprint(
903 oem_props, oem_dict, OPTIONS.source_info_dict))
904 script.Print("Target: %s" % CalculateFingerprint(
905 oem_props, oem_dict, OPTIONS.target_info_dict))
906
Geremy Condra36bd3652014-02-06 19:45:10 -0800907 script.Print("Verifying current system...")
908
909 device_specific.IncrementalOTA_VerifyBegin()
910
Michael Rungec6e3afd2014-05-05 11:55:47 -0700911 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700912 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
913 # patching on a device that's already on the target build will damage the
914 # system. Because operations like move don't check the block state, they
915 # always apply the changes unconditionally.
916 if blockimgdiff_version <= 2:
917 script.AssertSomeFingerprint(source_fp)
918 else:
919 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700920 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700921 if blockimgdiff_version <= 2:
922 script.AssertSomeThumbprint(
923 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
924 else:
925 script.AssertSomeThumbprint(
926 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
927 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800928
929 if updating_boot:
Tao Baocce673b2015-07-29 14:09:23 -0700930 boot_type, boot_device = common.GetTypeAndDevice(
931 "/boot", OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800932 d = common.Difference(target_boot, source_boot)
933 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700934 if d is None:
935 include_full_boot = True
936 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
937 else:
938 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800939
Doug Zongkerf8340082014-08-05 10:39:37 -0700940 print "boot target: %d source: %d diff: %d" % (
941 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800942
Doug Zongkerf8340082014-08-05 10:39:37 -0700943 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800944
Doug Zongkerf8340082014-08-05 10:39:37 -0700945 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
946 (boot_type, boot_device,
947 source_boot.size, source_boot.sha1,
948 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800949
950 device_specific.IncrementalOTA_VerifyEnd()
951
952 if OPTIONS.two_step:
953 script.WriteRawImage("/boot", "recovery.img")
954 script.AppendExtra("""
955set_stage("%(bcb_dev)s", "2/3");
956reboot_now("%(bcb_dev)s", "");
957else
958""" % bcb_dev)
959
Jesse Zhao75bcea02015-01-06 10:59:53 -0800960 # Verify the existing partitions.
961 system_diff.WriteVerifyScript(script)
962 if vendor_diff:
963 vendor_diff.WriteVerifyScript(script)
964
Geremy Condra36bd3652014-02-06 19:45:10 -0800965 script.Comment("---- start making changes here ----")
966
967 device_specific.IncrementalOTA_InstallBegin()
968
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700969 system_diff.WriteScript(script, output_zip,
970 progress=0.8 if vendor_diff else 0.9)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700971 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700972 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800973
974 if OPTIONS.two_step:
975 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
976 script.WriteRawImage("/boot", "boot.img")
977 print "writing full boot image (forced by two-step mode)"
978
979 if not OPTIONS.two_step:
980 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700981 if include_full_boot:
982 print "boot image changed; including full."
983 script.Print("Installing boot image...")
984 script.WriteRawImage("/boot", "boot.img")
985 else:
986 # Produce the boot image by applying a patch to the current
987 # contents of the boot partition, and write it back to the
988 # partition.
989 print "boot image changed; including patch."
990 script.Print("Patching boot image...")
991 script.ShowProgress(0.1, 10)
992 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
993 % (boot_type, boot_device,
994 source_boot.size, source_boot.sha1,
995 target_boot.size, target_boot.sha1),
996 "-",
997 target_boot.size, target_boot.sha1,
998 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800999 else:
1000 print "boot image unchanged; skipping."
1001
1002 # Do device-specific installation (eg, write radio image).
1003 device_specific.IncrementalOTA_InstallEnd()
1004
1005 if OPTIONS.extra_script is not None:
1006 script.AppendExtra(OPTIONS.extra_script)
1007
Doug Zongker922206e2014-03-04 13:16:24 -08001008 if OPTIONS.wipe_user_data:
1009 script.Print("Erasing user data...")
1010 script.FormatPartition("/data")
Tao Bao177c6102016-02-23 11:38:39 -08001011 metadata["ota-wipe"] = "yes"
Doug Zongker922206e2014-03-04 13:16:24 -08001012
Geremy Condra36bd3652014-02-06 19:45:10 -08001013 if OPTIONS.two_step:
1014 script.AppendExtra("""
1015set_stage("%(bcb_dev)s", "");
1016endif;
1017endif;
1018""" % bcb_dev)
1019
1020 script.SetProgress(1)
Tao Baofa41fb22016-03-08 17:53:39 -08001021 # For downgrade OTAs, we prefer to use the update-binary in the source
1022 # build that is actually newer than the one in the target build.
1023 if OPTIONS.downgrade:
1024 script.AddToZip(source_zip, output_zip, input_path=OPTIONS.updater_binary)
1025 else:
1026 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -08001027 WriteMetadata(metadata, output_zip)
1028
Doug Zongker32b527d2014-03-04 10:03:02 -08001029
Dan Albert8b72aef2015-03-23 19:13:21 -07001030class FileDifference(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001031 def __init__(self, partition, source_zip, target_zip, output_zip):
Dan Albert8b72aef2015-03-23 19:13:21 -07001032 self.deferred_patch_list = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001033 print "Loading target..."
1034 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
1035 print "Loading source..."
1036 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
1037
1038 self.verbatim_targets = verbatim_targets = []
1039 self.patch_list = patch_list = []
1040 diffs = []
1041 self.renames = renames = {}
1042 known_paths = set()
1043 largest_source_size = 0
1044
1045 matching_file_cache = {}
1046 for fn, sf in source_data.items():
1047 assert fn == sf.name
1048 matching_file_cache["path:" + fn] = sf
1049 if fn in target_data.keys():
1050 AddToKnownPaths(fn, known_paths)
1051 # Only allow eligibility for filename/sha matching
1052 # if there isn't a perfect path match.
1053 if target_data.get(sf.name) is None:
1054 matching_file_cache["file:" + fn.split("/")[-1]] = sf
1055 matching_file_cache["sha:" + sf.sha1] = sf
1056
1057 for fn in sorted(target_data.keys()):
1058 tf = target_data[fn]
1059 assert fn == tf.name
1060 sf = ClosestFileMatch(tf, matching_file_cache, renames)
1061 if sf is not None and sf.name != tf.name:
1062 print "File has moved from " + sf.name + " to " + tf.name
1063 renames[sf.name] = tf
1064
1065 if sf is None or fn in OPTIONS.require_verbatim:
1066 # This file should be included verbatim
1067 if fn in OPTIONS.prohibit_verbatim:
1068 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
1069 print "send", fn, "verbatim"
1070 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001071 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001072 if fn in target_data.keys():
1073 AddToKnownPaths(fn, known_paths)
1074 elif tf.sha1 != sf.sha1:
1075 # File is different; consider sending as a patch
1076 diffs.append(common.Difference(tf, sf))
1077 else:
1078 # Target file data identical to source (may still be renamed)
1079 pass
1080
1081 common.ComputeDifferences(diffs)
1082
1083 for diff in diffs:
1084 tf, sf, d = diff.GetPatch()
1085 path = "/".join(tf.name.split("/")[:-1])
1086 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1087 path not in known_paths:
1088 # patch is almost as big as the file; don't bother patching
1089 # or a patch + rename cannot take place due to the target
1090 # directory not existing
1091 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001092 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001093 if sf.name in renames:
1094 del renames[sf.name]
1095 AddToKnownPaths(tf.name, known_paths)
1096 else:
1097 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1098 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1099 largest_source_size = max(largest_source_size, sf.size)
1100
1101 self.largest_source_size = largest_source_size
1102
1103 def EmitVerification(self, script):
1104 so_far = 0
Dan Albert8b72aef2015-03-23 19:13:21 -07001105 for tf, sf, _, _ in self.patch_list:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001106 if tf.name != sf.name:
1107 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1108 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1109 so_far += sf.size
1110 return so_far
1111
Michael Runge63f01de2014-10-28 19:24:19 -07001112 def EmitExplicitTargetVerification(self, script):
Dan Albert8b72aef2015-03-23 19:13:21 -07001113 for fn, _, sha1 in self.verbatim_targets:
1114 if fn[-1] != "/":
Michael Runge63f01de2014-10-28 19:24:19 -07001115 script.FileCheck("/"+fn, sha1)
1116 for tf, _, _, _ in self.patch_list:
1117 script.FileCheck(tf.name, tf.sha1)
1118
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001119 def RemoveUnneededFiles(self, script, extras=()):
Dan Albert8b72aef2015-03-23 19:13:21 -07001120 script.DeleteFiles(
1121 ["/" + i[0] for i in self.verbatim_targets] +
1122 ["/" + i for i in sorted(self.source_data)
1123 if i not in self.target_data and i not in self.renames] +
1124 list(extras))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001125
1126 def TotalPatchSize(self):
1127 return sum(i[1].size for i in self.patch_list)
1128
1129 def EmitPatches(self, script, total_patch_size, so_far):
1130 self.deferred_patch_list = deferred_patch_list = []
1131 for item in self.patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001132 tf, sf, _, _ = item
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001133 if tf.name == "system/build.prop":
1134 deferred_patch_list.append(item)
1135 continue
Dan Albert8b72aef2015-03-23 19:13:21 -07001136 if sf.name != tf.name:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001137 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
Dan Albert8b72aef2015-03-23 19:13:21 -07001138 script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1,
1139 "patch/" + sf.name + ".p")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001140 so_far += tf.size
1141 script.SetProgress(so_far / total_patch_size)
1142 return so_far
1143
1144 def EmitDeferredPatches(self, script):
1145 for item in self.deferred_patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001146 tf, sf, _, _ = item
1147 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1,
1148 "patch/" + sf.name + ".p")
1149 script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001150
1151 def EmitRenames(self, script):
1152 if len(self.renames) > 0:
1153 script.Print("Renaming files...")
1154 for src, tgt in self.renames.iteritems():
1155 print "Renaming " + src + " to " + tgt.name
1156 script.RenameFile(src, tgt.name)
1157
1158
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001159def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001160 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1161 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1162
Doug Zongker26e66192014-02-20 13:22:07 -08001163 if (OPTIONS.block_based and
1164 target_has_recovery_patch and
1165 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001166 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1167
Doug Zongker37974732010-09-16 17:44:38 -07001168 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1169 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001170
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001171 if source_version == 0:
1172 print ("WARNING: generating edify script for a source that "
1173 "can't install it.")
Tao Baobebd3cf2015-06-22 19:17:41 -07001174 script = edify_generator.EdifyGenerator(
1175 source_version, OPTIONS.target_info_dict,
1176 fstab=OPTIONS.source_info_dict["fstab"])
Doug Zongkereef39442009-04-02 12:14:19 -07001177
Michael Runge6e836112014-04-15 17:40:21 -07001178 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Tao Baobebd3cf2015-06-22 19:17:41 -07001179 recovery_mount_options = OPTIONS.source_info_dict.get(
1180 "recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001181 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001182 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001183 if OPTIONS.oem_source is None:
1184 raise common.ExternalError("OEM source required for this build")
Tao Baobd25fcd2016-03-07 21:24:40 -08001185 if not OPTIONS.oem_no_mount:
1186 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001187 oem_dict = common.LoadDictionaryFromLines(
1188 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001189
Dan Albert8b72aef2015-03-23 19:13:21 -07001190 metadata = {
1191 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1192 OPTIONS.source_info_dict),
Tao Bao177c6102016-02-23 11:38:39 -08001193 "ota-type": "FILE",
Dan Albert8b72aef2015-03-23 19:13:21 -07001194 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001195
Tao Bao177c6102016-02-23 11:38:39 -08001196 post_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict)
1197 pre_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
1198 is_downgrade = long(post_timestamp) < long(pre_timestamp)
1199
1200 if OPTIONS.downgrade:
1201 metadata["ota-downgrade"] = "yes"
1202 if not is_downgrade:
1203 raise RuntimeError("--downgrade specified but no downgrade detected: "
1204 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
1205 else:
1206 if is_downgrade:
1207 # Non-fatal here to allow generating such a package which may require
1208 # manual work to adjust the post-timestamp. A legit use case is that we
1209 # cut a new build C (after having A and B), but want to enfore the
1210 # update path of A -> C -> B. Specifying --downgrade may not help since
1211 # that would enforce a data wipe for C -> B update.
1212 print("\nWARNING: downgrade detected: pre: %s, post: %s.\n"
1213 "The package may not be deployed properly. "
1214 "Try --downgrade?\n" % (pre_timestamp, post_timestamp))
1215 metadata["post-timestamp"] = post_timestamp
1216
Doug Zongker05d3dea2009-06-22 11:32:31 -07001217 device_specific = common.DeviceSpecificParams(
1218 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001219 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001220 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001221 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001222 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001223 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001224 metadata=metadata,
Tao Baoe09359a2015-10-13 16:37:12 -07001225 info_dict=OPTIONS.source_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001226
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001227 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001228 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001229 if HasVendorPartition(target_zip):
1230 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001231 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001232 else:
1233 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001234
Dan Albert8b72aef2015-03-23 19:13:21 -07001235 target_fp = CalculateFingerprint(oem_props, oem_dict,
1236 OPTIONS.target_info_dict)
1237 source_fp = CalculateFingerprint(oem_props, oem_dict,
1238 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001239
1240 if oem_props is None:
1241 script.AssertSomeFingerprint(source_fp, target_fp)
1242 else:
1243 script.AssertSomeThumbprint(
1244 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1245 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1246
Doug Zongker2ea21062010-04-28 16:05:21 -07001247 metadata["pre-build"] = source_fp
1248 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001249
Doug Zongker55d93282011-01-25 17:03:34 -08001250 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001251 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1252 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001253 target_boot = common.GetBootableImage(
1254 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001255 updating_boot = (not OPTIONS.two_step and
1256 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001257
Doug Zongker55d93282011-01-25 17:03:34 -08001258 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001259 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1260 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001261 target_recovery = common.GetBootableImage(
1262 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001263 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001264
Doug Zongker881dd402009-09-20 14:03:55 -07001265 # Here's how we divide up the progress bar:
1266 # 0.1 for verifying the start state (PatchCheck calls)
1267 # 0.8 for applying patches (ApplyPatch calls)
1268 # 0.1 for unpacking verbatim files, symlinking, and doing the
1269 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001270
Michael Runge6e836112014-04-15 17:40:21 -07001271 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001272 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001273
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001274 # Two-step incremental package strategy (in chronological order,
1275 # which is *not* the order in which the generated script has
1276 # things):
1277 #
1278 # if stage is not "2/3" or "3/3":
1279 # do verification on current system
1280 # write recovery image to boot partition
1281 # set stage to "2/3"
1282 # reboot to boot partition and restart recovery
1283 # else if stage is "2/3":
1284 # write recovery image to recovery partition
1285 # set stage to "3/3"
1286 # reboot to recovery partition and restart recovery
1287 # else:
1288 # (stage must be "3/3")
1289 # perform update:
1290 # patch system files, etc.
1291 # force full install of new boot image
1292 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001293 # complete script normally
1294 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001295
1296 if OPTIONS.two_step:
Tao Baocce673b2015-07-29 14:09:23 -07001297 if not OPTIONS.source_info_dict.get("multistage_support", None):
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001298 assert False, "two-step packages not supported by this build"
Tao Baocce673b2015-07-29 14:09:23 -07001299 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001300 assert fs.fs_type.upper() == "EMMC", \
1301 "two-step packages only supported on devices with EMMC /misc partitions"
1302 bcb_dev = {"bcb_dev": fs.device}
1303 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1304 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001305if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001306""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001307 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001308 script.WriteRawImage("/recovery", "recovery.img")
1309 script.AppendExtra("""
1310set_stage("%(bcb_dev)s", "3/3");
1311reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001312else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001313""" % bcb_dev)
1314
Tao Bao6c55a8a2015-04-08 15:30:27 -07001315 # Dump fingerprints
1316 script.Print("Source: %s" % (source_fp,))
1317 script.Print("Target: %s" % (target_fp,))
1318
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001319 script.Print("Verifying current system...")
1320
Doug Zongkere5ff5902012-01-17 10:55:37 -08001321 device_specific.IncrementalOTA_VerifyBegin()
1322
Doug Zongker881dd402009-09-20 14:03:55 -07001323 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001324 so_far = system_diff.EmitVerification(script)
1325 if vendor_diff:
1326 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001327
Doug Zongker5da317e2009-06-02 13:38:17 -07001328 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001329 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001330 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001331 print "boot target: %d source: %d diff: %d" % (
1332 target_boot.size, source_boot.size, len(d))
1333
Doug Zongker048e7ca2009-06-15 14:31:53 -07001334 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001335
Tao Baocce673b2015-07-29 14:09:23 -07001336 boot_type, boot_device = common.GetTypeAndDevice(
1337 "/boot", OPTIONS.source_info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001338
1339 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1340 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001341 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001342 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001343 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001344
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001345 size = []
Dan Albert8b72aef2015-03-23 19:13:21 -07001346 if system_diff.patch_list:
1347 size.append(system_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001348 if vendor_diff:
Dan Albert8b72aef2015-03-23 19:13:21 -07001349 if vendor_diff.patch_list:
1350 size.append(vendor_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001351 if size or updating_recovery or updating_boot:
1352 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001353
Doug Zongker05d3dea2009-06-22 11:32:31 -07001354 device_specific.IncrementalOTA_VerifyEnd()
1355
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001356 if OPTIONS.two_step:
1357 script.WriteRawImage("/boot", "recovery.img")
1358 script.AppendExtra("""
1359set_stage("%(bcb_dev)s", "2/3");
1360reboot_now("%(bcb_dev)s", "");
1361else
1362""" % bcb_dev)
1363
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001364 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001365
Doug Zongkere5ff5902012-01-17 10:55:37 -08001366 device_specific.IncrementalOTA_InstallBegin()
1367
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001368 if OPTIONS.two_step:
1369 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1370 script.WriteRawImage("/boot", "boot.img")
1371 print "writing full boot image (forced by two-step mode)"
1372
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001373 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001374 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1375 if vendor_diff:
1376 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001377
Doug Zongker881dd402009-09-20 14:03:55 -07001378 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001379 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1380 if vendor_diff:
1381 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001382 if updating_boot:
1383 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001384
1385 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001386 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1387 if vendor_diff:
1388 script.Print("Patching vendor files...")
1389 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001390
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001391 if not OPTIONS.two_step:
1392 if updating_boot:
1393 # Produce the boot image by applying a patch to the current
1394 # contents of the boot partition, and write it back to the
1395 # partition.
1396 script.Print("Patching boot image...")
1397 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1398 % (boot_type, boot_device,
1399 source_boot.size, source_boot.sha1,
1400 target_boot.size, target_boot.sha1),
1401 "-",
1402 target_boot.size, target_boot.sha1,
1403 source_boot.sha1, "patch/boot.img.p")
1404 so_far += target_boot.size
1405 script.SetProgress(so_far / total_patch_size)
1406 print "boot image changed; including."
1407 else:
1408 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001409
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001410 system_items = ItemSet("system", "META/filesystem_config.txt")
1411 if vendor_diff:
1412 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1413
Doug Zongkereef39442009-04-02 12:14:19 -07001414 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001415 # Recovery is generated as a patch using both the boot image
1416 # (which contains the same linux kernel as recovery) and the file
1417 # /system/etc/recovery-resource.dat (which contains all the images
1418 # used in the recovery UI) as sources. This lets us minimize the
1419 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001420 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001421 # For older builds where recovery-resource.dat is not present, we
1422 # use only the boot image as the source.
1423
Doug Zongkerc9253822014-02-04 12:17:58 -08001424 if not target_has_recovery_patch:
1425 def output_sink(fn, data):
1426 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001427 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001428
1429 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1430 target_recovery, target_boot)
1431 script.DeleteFiles(["/system/recovery-from-boot.p",
1432 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001433 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001434 else:
1435 print "recovery image unchanged; skipping."
1436
Doug Zongker881dd402009-09-20 14:03:55 -07001437 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001438
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001439 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1440 if vendor_diff:
1441 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1442
1443 temp_script = script.MakeTemporary()
1444 system_items.GetMetadata(target_zip)
1445 system_items.Get("system").SetPermissions(temp_script)
1446 if vendor_diff:
1447 vendor_items.GetMetadata(target_zip)
1448 vendor_items.Get("vendor").SetPermissions(temp_script)
1449
1450 # Note that this call will mess up the trees of Items, so make sure
1451 # we're done with them.
1452 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1453 if vendor_diff:
1454 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001455
1456 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001457 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1458
1459 # Delete all the symlinks in source that aren't in target. This
1460 # needs to happen before verbatim files are unpacked, in case a
1461 # symlink in the source is replaced by a real file in the target.
Tao Bao39c322c2015-09-02 10:28:08 -07001462
1463 # If a symlink in the source will be replaced by a regular file, we cannot
1464 # delete the symlink/file in case the package gets applied again. For such
1465 # a symlink, we prepend a sha1_check() to detect if it has been updated.
1466 # (Bug: 23646151)
1467 replaced_symlinks = dict()
1468 if system_diff:
1469 for i in system_diff.verbatim_targets:
1470 replaced_symlinks["/%s" % (i[0],)] = i[2]
1471 if vendor_diff:
1472 for i in vendor_diff.verbatim_targets:
1473 replaced_symlinks["/%s" % (i[0],)] = i[2]
1474
1475 if system_diff:
1476 for tf in system_diff.renames.values():
1477 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1478 if vendor_diff:
1479 for tf in vendor_diff.renames.values():
1480 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1481
1482 always_delete = []
1483 may_delete = []
Doug Zongkereef39442009-04-02 12:14:19 -07001484 for dest, link in source_symlinks:
1485 if link not in target_symlinks_d:
Tao Bao39c322c2015-09-02 10:28:08 -07001486 if link in replaced_symlinks:
1487 may_delete.append((link, replaced_symlinks[link]))
1488 else:
1489 always_delete.append(link)
1490 script.DeleteFiles(always_delete)
1491 script.DeleteFilesIfNotMatching(may_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001492
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001493 if system_diff.verbatim_targets:
1494 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001495 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001496 if vendor_diff and vendor_diff.verbatim_targets:
1497 script.Print("Unpacking new vendor files...")
1498 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001499
Doug Zongkerc9253822014-02-04 12:17:58 -08001500 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001501 script.Print("Unpacking new recovery...")
1502 script.UnpackPackageDir("recovery", "/system")
1503
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001504 system_diff.EmitRenames(script)
1505 if vendor_diff:
1506 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001507
Doug Zongker05d3dea2009-06-22 11:32:31 -07001508 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001509
1510 # Create all the symlinks that don't already exist, or point to
1511 # somewhere different than what we want. Delete each symlink before
1512 # creating it, since the 'symlink' command won't overwrite.
1513 to_create = []
1514 for dest, link in target_symlinks:
1515 if link in source_symlinks_d:
1516 if dest != source_symlinks_d[link]:
1517 to_create.append((dest, link))
1518 else:
1519 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001520 script.DeleteFiles([i[1] for i in to_create])
1521 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001522
1523 # Now that the symlinks are created, we can set all the
1524 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001525 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001526
Doug Zongker881dd402009-09-20 14:03:55 -07001527 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001528 device_specific.IncrementalOTA_InstallEnd()
1529
Doug Zongker1c390a22009-05-14 19:06:36 -07001530 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001531 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001532
Doug Zongkere92f15a2011-08-26 13:46:40 -07001533 # Patch the build.prop file last, so if something fails but the
1534 # device can still come up, it appears to be the old build and will
1535 # get set the OTA package again to retry.
1536 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001537 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001538
Doug Zongker922206e2014-03-04 13:16:24 -08001539 if OPTIONS.wipe_user_data:
1540 script.Print("Erasing user data...")
1541 script.FormatPartition("/data")
Tao Bao177c6102016-02-23 11:38:39 -08001542 metadata["ota-wipe"] = "yes"
Doug Zongker922206e2014-03-04 13:16:24 -08001543
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001544 if OPTIONS.two_step:
1545 script.AppendExtra("""
1546set_stage("%(bcb_dev)s", "");
1547endif;
1548endif;
1549""" % bcb_dev)
1550
Michael Runge63f01de2014-10-28 19:24:19 -07001551 if OPTIONS.verify and system_diff:
1552 script.Print("Remounting and verifying system partition files...")
1553 script.Unmount("/system")
1554 script.Mount("/system")
1555 system_diff.EmitExplicitTargetVerification(script)
1556
1557 if OPTIONS.verify and vendor_diff:
1558 script.Print("Remounting and verifying vendor partition files...")
1559 script.Unmount("/vendor")
1560 script.Mount("/vendor")
1561 vendor_diff.EmitExplicitTargetVerification(script)
Tao Baofa41fb22016-03-08 17:53:39 -08001562
1563 # For downgrade OTAs, we prefer to use the update-binary in the source
1564 # build that is actually newer than the one in the target build.
1565 if OPTIONS.downgrade:
1566 script.AddToZip(source_zip, output_zip, input_path=OPTIONS.updater_binary)
1567 else:
1568 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001569
Doug Zongker2ea21062010-04-28 16:05:21 -07001570 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001571
1572
1573def main(argv):
1574
1575 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001576 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001577 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001578 elif o in ("-k", "--package_key"):
1579 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001580 elif o in ("-i", "--incremental_from"):
1581 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001582 elif o == "--full_radio":
1583 OPTIONS.full_radio = True
leozwanga1fcaf82015-09-15 08:44:12 -07001584 elif o == "--full_bootloader":
1585 OPTIONS.full_bootloader = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001586 elif o in ("-w", "--wipe_user_data"):
1587 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001588 elif o in ("-n", "--no_prereq"):
1589 OPTIONS.omit_prereq = True
Tao Bao177c6102016-02-23 11:38:39 -08001590 elif o == "--downgrade":
1591 OPTIONS.downgrade = True
1592 OPTIONS.wipe_user_data = True
Michael Runge6e836112014-04-15 17:40:21 -07001593 elif o in ("-o", "--oem_settings"):
1594 OPTIONS.oem_source = a
Tao Baodf4cb0b2016-02-25 19:49:55 -08001595 elif o == "--oem_no_mount":
1596 OPTIONS.oem_no_mount = True
Doug Zongker1c390a22009-05-14 19:06:36 -07001597 elif o in ("-e", "--extra_script"):
1598 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001599 elif o in ("-a", "--aslr_mode"):
1600 if a in ("on", "On", "true", "True", "yes", "Yes"):
1601 OPTIONS.aslr_mode = True
1602 else:
1603 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001604 elif o in ("-t", "--worker_threads"):
1605 if a.isdigit():
1606 OPTIONS.worker_threads = int(a)
1607 else:
1608 raise ValueError("Cannot parse value %r for option %r - only "
1609 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001610 elif o in ("-2", "--two_step"):
1611 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001612 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001613 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001614 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001615 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001616 elif o == "--block":
1617 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001618 elif o in ("-b", "--binary"):
1619 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001620 elif o in ("--no_fallback_to_full",):
1621 OPTIONS.fallback_to_full = False
Tao Baod47d8e12015-05-21 14:09:49 -07001622 elif o == "--stash_threshold":
1623 try:
1624 OPTIONS.stash_threshold = float(a)
1625 except ValueError:
1626 raise ValueError("Cannot parse value %r for option %r - expecting "
1627 "a float" % (a, o))
Doug Zongkereef39442009-04-02 12:14:19 -07001628 else:
1629 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001630 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001631
1632 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001633 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001634 extra_long_opts=[
1635 "board_config=",
1636 "package_key=",
1637 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001638 "full_radio",
leozwanga1fcaf82015-09-15 08:44:12 -07001639 "full_bootloader",
Dan Albert8b72aef2015-03-23 19:13:21 -07001640 "wipe_user_data",
1641 "no_prereq",
Tao Bao177c6102016-02-23 11:38:39 -08001642 "downgrade",
Dan Albert8b72aef2015-03-23 19:13:21 -07001643 "extra_script=",
1644 "worker_threads=",
1645 "aslr_mode=",
1646 "two_step",
1647 "no_signing",
1648 "block",
1649 "binary=",
1650 "oem_settings=",
Tao Baodf4cb0b2016-02-25 19:49:55 -08001651 "oem_no_mount",
Dan Albert8b72aef2015-03-23 19:13:21 -07001652 "verify",
1653 "no_fallback_to_full",
Tao Baod47d8e12015-05-21 14:09:49 -07001654 "stash_threshold=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001655 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001656
1657 if len(args) != 2:
1658 common.Usage(__doc__)
1659 sys.exit(1)
1660
Tao Bao177c6102016-02-23 11:38:39 -08001661 if OPTIONS.downgrade:
1662 # Sanity check to enforce a data wipe.
1663 if not OPTIONS.wipe_user_data:
1664 raise ValueError("Cannot downgrade without a data wipe")
1665
1666 # We should only allow downgrading incrementals (as opposed to full).
1667 # Otherwise the device may go back from arbitrary build with this full
1668 # OTA package.
1669 if OPTIONS.incremental_source is None:
1670 raise ValueError("Cannot generate downgradable full OTAs - consider"
1671 "using --omit_prereq?")
1672
Doug Zongker1c390a22009-05-14 19:06:36 -07001673 if OPTIONS.extra_script is not None:
1674 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1675
Doug Zongkereef39442009-04-02 12:14:19 -07001676 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001677 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001678
Doug Zongkereef39442009-04-02 12:14:19 -07001679 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001680 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001681
1682 # If this image was originally labelled with SELinux contexts, make sure we
1683 # also apply the labels in our new image. During building, the "file_contexts"
1684 # is in the out/ directory tree, but for repacking from target-files.zip it's
1685 # in the root directory of the ramdisk.
1686 if "selinux_fc" in OPTIONS.info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001687 OPTIONS.info_dict["selinux_fc"] = os.path.join(
1688 OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")
Kenny Roote2e9f612013-05-29 12:59:35 -07001689
Doug Zongker37974732010-09-16 17:44:38 -07001690 if OPTIONS.verbose:
1691 print "--- target info ---"
1692 common.DumpInfoDict(OPTIONS.info_dict)
1693
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001694 # If the caller explicitly specified the device-specific extensions
1695 # path via -s/--device_specific, use that. Otherwise, use
1696 # META/releasetools.py if it is present in the target target_files.
1697 # Otherwise, take the path of the file from 'tool_extensions' in the
1698 # info dict and look for that in the local filesystem, relative to
1699 # the current directory.
1700
Doug Zongker37974732010-09-16 17:44:38 -07001701 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001702 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1703 if os.path.exists(from_input):
1704 print "(using device-specific extensions from target_files)"
1705 OPTIONS.device_specific = from_input
1706 else:
1707 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1708
Doug Zongker37974732010-09-16 17:44:38 -07001709 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001710 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001711
Doug Zongker62d4f182014-08-04 16:06:43 -07001712 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001713
Doug Zongker62d4f182014-08-04 16:06:43 -07001714 if OPTIONS.no_signing:
Dan Albert8b72aef2015-03-23 19:13:21 -07001715 if os.path.exists(args[1]):
1716 os.unlink(args[1])
1717 output_zip = zipfile.ZipFile(args[1], "w",
1718 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001719 else:
1720 temp_zip_file = tempfile.NamedTemporaryFile()
1721 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1722 compression=zipfile.ZIP_DEFLATED)
1723
Tao Baod47d8e12015-05-21 14:09:49 -07001724 cache_size = OPTIONS.info_dict.get("cache_size", None)
1725 if cache_size is None:
1726 raise RuntimeError("can't determine the cache partition size")
1727 OPTIONS.cache_size = cache_size
1728
Doug Zongker62d4f182014-08-04 16:06:43 -07001729 if OPTIONS.incremental_source is None:
1730 WriteFullOTAPackage(input_zip, output_zip)
1731 if OPTIONS.package_key is None:
1732 OPTIONS.package_key = OPTIONS.info_dict.get(
1733 "default_system_dev_certificate",
1734 "build/target/product/security/testkey")
Tao Baof3282b42015-04-01 11:21:55 -07001735 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001736 break
1737
1738 else:
1739 print "unzipping source target-files..."
Dan Albert8b72aef2015-03-23 19:13:21 -07001740 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
1741 OPTIONS.incremental_source)
Doug Zongker62d4f182014-08-04 16:06:43 -07001742 OPTIONS.target_info_dict = OPTIONS.info_dict
1743 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1744 if "selinux_fc" in OPTIONS.source_info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001745 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(
1746 OPTIONS.source_tmp, "BOOT", "RAMDISK", "file_contexts")
Doug Zongker62d4f182014-08-04 16:06:43 -07001747 if OPTIONS.package_key is None:
1748 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1749 "default_system_dev_certificate",
1750 "build/target/product/security/testkey")
1751 if OPTIONS.verbose:
1752 print "--- source info ---"
1753 common.DumpInfoDict(OPTIONS.source_info_dict)
1754 try:
1755 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Baof3282b42015-04-01 11:21:55 -07001756 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001757 break
1758 except ValueError:
Dan Albert8b72aef2015-03-23 19:13:21 -07001759 if not OPTIONS.fallback_to_full:
1760 raise
Doug Zongker62d4f182014-08-04 16:06:43 -07001761 print "--- failed to build incremental; falling back to full ---"
1762 OPTIONS.incremental_source = None
Tao Baof3282b42015-04-01 11:21:55 -07001763 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001764
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001765 if not OPTIONS.no_signing:
1766 SignOutput(temp_zip_file.name, args[1])
1767 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001768
Doug Zongkereef39442009-04-02 12:14:19 -07001769 print "done."
1770
1771
1772if __name__ == '__main__':
1773 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001774 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001775 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001776 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07001777 print
1778 print " ERROR: %s" % (e,)
1779 print
1780 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001781 finally:
1782 common.Cleanup()