blob: e61c64f57d5e397c84131370ed4528e9ea93bf6a [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
Doug Zongkerdbfaae52009-04-21 17:12:54 -070058 -w (--wipe_user_data)
59 Generate an OTA package that will wipe the user data partition
60 when installed.
61
Doug Zongker962069c2009-04-23 11:41:58 -070062 -n (--no_prereq)
63 Omit the timestamp prereq check normally included at the top of
64 the build scripts (used for developer OTA packages which
65 legitimately need to go back and forth).
66
Tao Bao177c6102016-02-23 11:38:39 -080067 --downgrade
68 Intentionally generate an incremental OTA that updates from a newer
69 build to an older one (based on timestamp comparison). "post-timestamp"
70 will be replaced by "ota-downgrade=yes" in the metadata file. A data
71 wipe will always be enforced, so "ota-wipe=yes" will also be included in
Tao Baofa41fb22016-03-08 17:53:39 -080072 the metadata file. The update-binary in the source build will be used in
73 the OTA package, unless --binary flag is specified.
Tao Bao177c6102016-02-23 11:38:39 -080074
Doug Zongker1c390a22009-05-14 19:06:36 -070075 -e (--extra_script) <file>
76 Insert the contents of file at the end of the update script.
77
Hristo Bojinovdafb0422010-08-26 14:35:16 -070078 -a (--aslr_mode) <on|off>
79 Specify whether to turn on ASLR for the package (on by default).
Stephen Smalley56882bf2012-02-09 13:36:21 -050080
Doug Zongker9b23f2c2013-11-25 14:44:12 -080081 -2 (--two_step)
82 Generate a 'two-step' OTA package, where recovery is updated
83 first, so that any changes made to the system partition are done
84 using the new recovery (new kernel, etc.).
85
Doug Zongker26e66192014-02-20 13:22:07 -080086 --block
87 Generate a block-based OTA if possible. Will fall back to a
88 file-based OTA if the target_files is older and doesn't support
89 block-based OTAs.
90
Doug Zongker25568482014-03-03 10:21:27 -080091 -b (--binary) <file>
92 Use the given binary as the update-binary in the output package,
93 instead of the binary in the build's target_files. Use for
94 development only.
95
Martin Blumenstingl374e1142014-05-31 20:42:55 +020096 -t (--worker_threads) <int>
97 Specifies the number of worker-threads that will be used when
98 generating patches for incremental updates (defaults to 3).
99
Tao Baod47d8e12015-05-21 14:09:49 -0700100 --stash_threshold <float>
101 Specifies the threshold that will be used to compute the maximum
102 allowed stash size (defaults to 0.8).
Doug Zongkereef39442009-04-02 12:14:19 -0700103"""
104
105import sys
106
Doug Zongkercf6d5a92014-02-18 10:57:07 -0800107if sys.hexversion < 0x02070000:
108 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -0700109 sys.exit(1)
110
Doug Zongkerfc44a512014-08-26 13:10:25 -0700111import multiprocessing
Doug Zongkereef39442009-04-02 12:14:19 -0700112import os
Doug Zongkereef39442009-04-02 12:14:19 -0700113import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -0700114import zipfile
115
116import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700117import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -0700118import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700119
120OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700121OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700122OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700123OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700124OPTIONS.require_verbatim = set()
125OPTIONS.prohibit_verbatim = set(("system/build.prop",))
126OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700127OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700128OPTIONS.omit_prereq = False
Tao Bao177c6102016-02-23 11:38:39 -0800129OPTIONS.downgrade = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700130OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700131OPTIONS.aslr_mode = True
Doug Zongkerfc44a512014-08-26 13:10:25 -0700132OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
133if OPTIONS.worker_threads == 0:
134 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800135OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900136OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800137OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800138OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700139OPTIONS.oem_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -0700140OPTIONS.fallback_to_full = True
Tao Bao43078aa2015-04-21 14:32:35 -0700141OPTIONS.full_radio = False
leozwanga1fcaf82015-09-15 08:44:12 -0700142OPTIONS.full_bootloader = False
Tao Baod47d8e12015-05-21 14:09:49 -0700143# Stash size cannot exceed cache_size * threshold.
144OPTIONS.cache_size = None
145OPTIONS.stash_threshold = 0.8
146
Doug Zongkereef39442009-04-02 12:14:19 -0700147def MostPopularKey(d, default):
148 """Given a dict, return the key corresponding to the largest
149 value. Returns 'default' if the dict is empty."""
150 x = [(v, k) for (k, v) in d.iteritems()]
Dan Albert8b72aef2015-03-23 19:13:21 -0700151 if not x:
152 return default
Doug Zongkereef39442009-04-02 12:14:19 -0700153 x.sort()
154 return x[-1][1]
155
156
157def IsSymlink(info):
158 """Return true if the zipfile.ZipInfo object passed in represents a
159 symlink."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700160 return (info.external_attr >> 16) == 0o120777
Doug Zongkereef39442009-04-02 12:14:19 -0700161
Hristo Bojinov96be7202010-08-02 10:26:17 -0700162def IsRegular(info):
163 """Return true if the zipfile.ZipInfo object passed in represents a
164 symlink."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700165 return (info.external_attr >> 28) == 0o10
Doug Zongkereef39442009-04-02 12:14:19 -0700166
Michael Runge4038aa82013-12-13 18:06:28 -0800167def ClosestFileMatch(src, tgtfiles, existing):
168 """Returns the closest file match between a source file and list
169 of potential matches. The exact filename match is preferred,
170 then the sha1 is searched for, and finally a file with the same
171 basename is evaluated. Rename support in the updater-binary is
172 required for the latter checks to be used."""
173
174 result = tgtfiles.get("path:" + src.name)
175 if result is not None:
176 return result
177
178 if not OPTIONS.target_info_dict.get("update_rename_support", False):
179 return None
180
181 if src.size < 1000:
182 return None
183
184 result = tgtfiles.get("sha1:" + src.sha1)
185 if result is not None and existing.get(result.name) is None:
186 return result
187 result = tgtfiles.get("file:" + src.name.split("/")[-1])
188 if result is not None and existing.get(result.name) is None:
189 return result
190 return None
191
Dan Albert8b72aef2015-03-23 19:13:21 -0700192class ItemSet(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700193 def __init__(self, partition, fs_config):
194 self.partition = partition
195 self.fs_config = fs_config
196 self.ITEMS = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700197
Dan Albert8b72aef2015-03-23 19:13:21 -0700198 def Get(self, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700199 if name not in self.ITEMS:
Dan Albert8b72aef2015-03-23 19:13:21 -0700200 self.ITEMS[name] = Item(self, name, is_dir=is_dir)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700201 return self.ITEMS[name]
Doug Zongkereef39442009-04-02 12:14:19 -0700202
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700203 def GetMetadata(self, input_zip):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700204 # The target_files contains a record of what the uid,
205 # gid, and mode are supposed to be.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700206 output = input_zip.read(self.fs_config)
Doug Zongkereef39442009-04-02 12:14:19 -0700207
208 for line in output.split("\n"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700209 if not line:
210 continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700211 columns = line.split()
212 name, uid, gid, mode = columns[:4]
213 selabel = None
214 capabilities = None
215
216 # After the first 4 columns, there are a series of key=value
217 # pairs. Extract out the fields we care about.
218 for element in columns[4:]:
219 key, value = element.split("=")
220 if key == "selabel":
221 selabel = value
222 if key == "capabilities":
223 capabilities = value
224
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700225 i = self.ITEMS.get(name, None)
Doug Zongker283e2a12010-03-15 17:52:32 -0700226 if i is not None:
227 i.uid = int(uid)
228 i.gid = int(gid)
229 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700230 i.selabel = selabel
231 i.capabilities = capabilities
Dan Albert8b72aef2015-03-23 19:13:21 -0700232 if i.is_dir:
Doug Zongker283e2a12010-03-15 17:52:32 -0700233 i.children.sort(key=lambda i: i.name)
234
235 # set metadata for the files generated by this script.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700236 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700237 if i:
238 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700239 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700240 if i:
241 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700242
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700243
Dan Albert8b72aef2015-03-23 19:13:21 -0700244class Item(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700245 """Items represent the metadata (user, group, mode) of files and
246 directories in the system image."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700247 def __init__(self, itemset, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700248 self.itemset = itemset
249 self.name = name
250 self.uid = None
251 self.gid = None
252 self.mode = None
253 self.selabel = None
254 self.capabilities = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700255 self.is_dir = is_dir
256 self.descendants = None
257 self.best_subtree = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700258
259 if name:
Dan Albert8b72aef2015-03-23 19:13:21 -0700260 self.parent = itemset.Get(os.path.dirname(name), is_dir=True)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700261 self.parent.children.append(self)
262 else:
263 self.parent = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700264 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700265 self.children = []
266
267 def Dump(self, indent=0):
268 if self.uid is not None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700269 print "%s%s %d %d %o" % (
270 " " * indent, self.name, self.uid, self.gid, self.mode)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700271 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700272 print "%s%s %s %s %s" % (
273 " " * indent, self.name, self.uid, self.gid, self.mode)
274 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700275 print "%s%s" % (" "*indent, self.descendants)
276 print "%s%s" % (" "*indent, self.best_subtree)
277 for i in self.children:
278 i.Dump(indent=indent+1)
279
Doug Zongkereef39442009-04-02 12:14:19 -0700280 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700281 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
Dan Albert8b72aef2015-03-23 19:13:21 -0700282 all children and determine the best strategy for using set_perm_recursive
283 and set_perm to correctly chown/chmod all the files to their desired
Doug Zongkereef39442009-04-02 12:14:19 -0700284 values. Recursively calls itself for all descendants.
285
Dan Albert8b72aef2015-03-23 19:13:21 -0700286 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count}
287 counting up all descendants of this node. (dmode or fmode may be None.)
288 Also sets the best_subtree of each directory Item to the (uid, gid, dmode,
289 fmode, selabel, capabilities) tuple that will match the most descendants of
290 that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700291 """
292
Dan Albert8b72aef2015-03-23 19:13:21 -0700293 assert self.is_dir
294 key = (self.uid, self.gid, self.mode, None, self.selabel,
295 self.capabilities)
296 self.descendants = {key: 1}
297 d = self.descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700298 for i in self.children:
Dan Albert8b72aef2015-03-23 19:13:21 -0700299 if i.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700300 for k, v in i.CountChildMetadata().iteritems():
301 d[k] = d.get(k, 0) + v
302 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700303 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700304 d[k] = d.get(k, 0) + 1
305
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700306 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
307 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700308
309 # First, find the (uid, gid) pair that matches the most
310 # descendants.
311 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700312 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700313 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
314 ug = MostPopularKey(ug, (0, 0))
315
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700316 # Now find the dmode, fmode, selabel, and capabilities that match
317 # the most descendants with that (uid, gid), and choose those.
Dan Albert8b72aef2015-03-23 19:13:21 -0700318 best_dmode = (0, 0o755)
319 best_fmode = (0, 0o644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700320 best_selabel = (0, None)
321 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700322 for k, count in d.iteritems():
Dan Albert8b72aef2015-03-23 19:13:21 -0700323 if k[:2] != ug:
324 continue
325 if k[2] is not None and count >= best_dmode[0]:
326 best_dmode = (count, k[2])
327 if k[3] is not None and count >= best_fmode[0]:
328 best_fmode = (count, k[3])
329 if k[4] is not None and count >= best_selabel[0]:
330 best_selabel = (count, k[4])
331 if k[5] is not None and count >= best_capabilities[0]:
332 best_capabilities = (count, k[5])
333 self.best_subtree = ug + (
334 best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700335
336 return d
337
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700338 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700339 """Append set_perm/set_perm_recursive commands to 'script' to
340 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700341 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700342
343 self.CountChildMetadata()
344
345 def recurse(item, current):
Dan Albert8b72aef2015-03-23 19:13:21 -0700346 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple
347 # that the current item (and all its children) have already been set to.
348 # We only need to issue set_perm/set_perm_recursive commands if we're
Doug Zongkereef39442009-04-02 12:14:19 -0700349 # supposed to be something different.
Dan Albert8b72aef2015-03-23 19:13:21 -0700350 if item.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700351 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700352 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700353 current = item.best_subtree
354
355 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700356 item.mode != current[2] or item.selabel != current[4] or \
357 item.capabilities != current[5]:
358 script.SetPermissions("/"+item.name, item.uid, item.gid,
359 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700360
361 for i in item.children:
362 recurse(i, current)
363 else:
364 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700365 item.mode != current[3] or item.selabel != current[4] or \
366 item.capabilities != current[5]:
367 script.SetPermissions("/"+item.name, item.uid, item.gid,
368 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700369
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700370 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700371
372
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700373def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
374 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700375 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800376 list of symlinks. output_zip may be None, in which case the copy is
377 skipped (but the other side effects still happen). substitute is an
378 optional dict of {output filename: contents} to be output instead of
379 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700380 """
381
382 symlinks = []
383
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700384 partition = itemset.partition
385
Doug Zongkereef39442009-04-02 12:14:19 -0700386 for info in input_zip.infolist():
Tao Baoeaf885b2015-03-23 16:01:17 -0700387 prefix = partition.upper() + "/"
388 if info.filename.startswith(prefix):
389 basefilename = info.filename[len(prefix):]
Doug Zongkereef39442009-04-02 12:14:19 -0700390 if IsSymlink(info):
391 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700392 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700393 else:
Tao Baof3282b42015-04-01 11:21:55 -0700394 import copy
Doug Zongkereef39442009-04-02 12:14:19 -0700395 info2 = copy.copy(info)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700396 fn = info2.filename = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700397 if substitute and fn in substitute and substitute[fn] is None:
398 continue
399 if output_zip is not None:
400 if substitute and fn in substitute:
401 data = substitute[fn]
402 else:
403 data = input_zip.read(info.filename)
Tao Baof3282b42015-04-01 11:21:55 -0700404 common.ZipWriteStr(output_zip, info2, data)
Doug Zongkereef39442009-04-02 12:14:19 -0700405 if fn.endswith("/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700406 itemset.Get(fn[:-1], is_dir=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700407 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700408 itemset.Get(fn)
Doug Zongkereef39442009-04-02 12:14:19 -0700409
410 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800411 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700412
413
Doug Zongkereef39442009-04-02 12:14:19 -0700414def SignOutput(temp_zip_name, output_zip_name):
415 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
416 pw = key_passwords[OPTIONS.package_key]
417
Doug Zongker951495f2009-08-14 12:44:19 -0700418 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
419 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700420
421
Dan Albert8b72aef2015-03-23 19:13:21 -0700422def AppendAssertions(script, info_dict, oem_dict=None):
Michael Runge6e836112014-04-15 17:40:21 -0700423 oem_props = info_dict.get("oem_fingerprint_properties")
Michael Runge560569a2014-09-18 15:12:45 -0700424 if oem_props is None or len(oem_props) == 0:
Michael Runge6e836112014-04-15 17:40:21 -0700425 device = GetBuildProp("ro.product.device", info_dict)
426 script.AssertDevice(device)
427 else:
428 if oem_dict is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700429 raise common.ExternalError(
430 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700431 for prop in oem_props.split():
432 if oem_dict.get(prop) is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700433 raise common.ExternalError(
434 "The OEM file is missing the property %s" % prop)
Michael Runge6e836112014-04-15 17:40:21 -0700435 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700436
Doug Zongkereef39442009-04-02 12:14:19 -0700437
Doug Zongkerc9253822014-02-04 12:17:58 -0800438def HasRecoveryPatch(target_files_zip):
439 try:
440 target_files_zip.getinfo("SYSTEM/recovery-from-boot.p")
441 return True
442 except KeyError:
443 return False
Doug Zongker73ef8252009-07-23 15:12:53 -0700444
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700445def HasVendorPartition(target_files_zip):
446 try:
447 target_files_zip.getinfo("VENDOR/")
448 return True
449 except KeyError:
450 return False
451
Michael Runge6e836112014-04-15 17:40:21 -0700452def GetOemProperty(name, oem_props, oem_dict, info_dict):
453 if oem_props is not None and name in oem_props:
454 return oem_dict[name]
455 return GetBuildProp(name, info_dict)
456
457
458def CalculateFingerprint(oem_props, oem_dict, info_dict):
459 if oem_props is None:
460 return GetBuildProp("ro.build.fingerprint", info_dict)
461 return "%s/%s/%s:%s" % (
Dan Albert8b72aef2015-03-23 19:13:21 -0700462 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
463 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
464 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
465 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700466
Doug Zongkerfc44a512014-08-26 13:10:25 -0700467
Doug Zongker3c84f562014-07-31 11:06:30 -0700468def GetImage(which, tmpdir, info_dict):
Doug Zongkerfc44a512014-08-26 13:10:25 -0700469 # Return an image object (suitable for passing to BlockImageDiff)
470 # for the 'which' partition (most be "system" or "vendor"). If a
471 # prebuilt image and file map are found in tmpdir they are used,
472 # otherwise they are reconstructed from the individual files.
Doug Zongker3c84f562014-07-31 11:06:30 -0700473
474 assert which in ("system", "vendor")
475
476 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700477 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
478 if os.path.exists(path) and os.path.exists(mappath):
Doug Zongker3c84f562014-07-31 11:06:30 -0700479 print "using %s.img from target-files" % (which,)
Doug Zongker3c84f562014-07-31 11:06:30 -0700480 # This is a 'new' target-files, which already has the image in it.
Doug Zongker3c84f562014-07-31 11:06:30 -0700481
482 else:
483 print "building %s.img from target-files" % (which,)
484
485 # This is an 'old' target-files, which does not contain images
486 # already built. Build them.
487
Doug Zongkerfc44a512014-08-26 13:10:25 -0700488 mappath = tempfile.mkstemp()[1]
489 OPTIONS.tempfiles.append(mappath)
490
Doug Zongker3c84f562014-07-31 11:06:30 -0700491 import add_img_to_target_files
492 if which == "system":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700493 path = add_img_to_target_files.BuildSystem(
494 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700495 elif which == "vendor":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700496 path = add_img_to_target_files.BuildVendor(
497 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700498
Tao Bao5ece99d2015-05-12 11:42:31 -0700499 # Bug: http://b/20939131
500 # In ext4 filesystems, block 0 might be changed even being mounted
501 # R/O. We add it to clobbered_blocks so that it will be written to the
502 # target unconditionally. Note that they are still part of care_map.
503 clobbered_blocks = "0"
504
505 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700506
507
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700508def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700509 # TODO: how to determine this? We don't know what version it will
Tao Baobebd3cf2015-06-22 19:17:41 -0700510 # be installed on top of. For now, we expect the API just won't
511 # change very often. Similarly for fstab, it might have changed
512 # in the target build.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700513 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700514
Michael Runge6e836112014-04-15 17:40:21 -0700515 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700516 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700517 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700518 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700519 if OPTIONS.oem_source is None:
520 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700521 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700522 oem_dict = common.LoadDictionaryFromLines(
523 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -0700524
Dan Albert8b72aef2015-03-23 19:13:21 -0700525 metadata = {
526 "post-build": CalculateFingerprint(oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700527 OPTIONS.info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700528 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
529 OPTIONS.info_dict),
530 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
531 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700532
Doug Zongker05d3dea2009-06-22 11:32:31 -0700533 device_specific = common.DeviceSpecificParams(
534 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700535 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700536 output_zip=output_zip,
537 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700538 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700539 metadata=metadata,
540 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700541
Doug Zongkerc9253822014-02-04 12:17:58 -0800542 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800543 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800544
Doug Zongker962069c2009-04-23 11:41:58 -0700545 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700546 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700547 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
548 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700549
Michael Runge6e836112014-04-15 17:40:21 -0700550 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700551 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800552
553 # Two-step package strategy (in chronological order, which is *not*
554 # the order in which the generated script has things):
555 #
556 # if stage is not "2/3" or "3/3":
557 # write recovery image to boot partition
558 # set stage to "2/3"
559 # reboot to boot partition and restart recovery
560 # else if stage is "2/3":
561 # write recovery image to recovery partition
562 # set stage to "3/3"
563 # reboot to recovery partition and restart recovery
564 # else:
565 # (stage must be "3/3")
566 # set stage to ""
567 # do normal full package installation:
568 # wipe and install system, boot image, etc.
569 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700570 # complete script normally
571 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800572
573 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
574 OPTIONS.input_tmp, "RECOVERY")
575 if OPTIONS.two_step:
576 if not OPTIONS.info_dict.get("multistage_support", None):
577 assert False, "two-step packages not supported by this build"
578 fs = OPTIONS.info_dict["fstab"]["/misc"]
579 assert fs.fs_type.upper() == "EMMC", \
580 "two-step packages only supported on devices with EMMC /misc partitions"
581 bcb_dev = {"bcb_dev": fs.device}
582 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
583 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700584if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800585""" % bcb_dev)
586 script.WriteRawImage("/recovery", "recovery.img")
587 script.AppendExtra("""
588set_stage("%(bcb_dev)s", "3/3");
589reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700590else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800591""" % bcb_dev)
592
Tao Bao6c55a8a2015-04-08 15:30:27 -0700593 # Dump fingerprints
594 script.Print("Target: %s" % CalculateFingerprint(
595 oem_props, oem_dict, OPTIONS.info_dict))
596
Doug Zongkere5ff5902012-01-17 10:55:37 -0800597 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700598
Doug Zongker01ce19c2014-02-04 13:48:15 -0800599 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700600
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700601 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800602 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700603 if HasVendorPartition(input_zip):
604 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700605
Kenny Rootf32dc712012-04-08 10:42:34 -0700606 if "selinux_fc" in OPTIONS.info_dict:
607 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500608
Michael Runge7cd99ba2014-10-22 17:21:48 -0700609 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
610
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700611 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700612 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800613
Doug Zongker26e66192014-02-20 13:22:07 -0800614 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700615 # Full OTA is done as an "incremental" against an empty source
616 # image. This has the effect of writing new data from the package
617 # to the entire partition, but lets us reuse the updater code that
618 # writes incrementals to do it.
619 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
620 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700621 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700622 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800623 else:
624 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700625 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800626 if not has_recovery_patch:
627 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800628 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700629
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700630 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800631 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700632
Doug Zongker55d93282011-01-25 17:03:34 -0800633 boot_img = common.GetBootableImage("boot.img", "boot.img",
634 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800635
Doug Zongker91a99c22014-05-09 13:15:01 -0700636 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800637 def output_sink(fn, data):
638 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700639 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800640
641 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
642 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700643
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700644 system_items.GetMetadata(input_zip)
645 system_items.Get("system").SetPermissions(script)
646
647 if HasVendorPartition(input_zip):
648 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
649 script.ShowProgress(0.1, 0)
650
651 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700652 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
653 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700654 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700655 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700656 else:
657 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700658 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700659 script.UnpackPackageDir("vendor", "/vendor")
660
661 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
662 script.MakeSymlinks(symlinks)
663
664 vendor_items.GetMetadata(input_zip)
665 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700666
Doug Zongker37974732010-09-16 17:44:38 -0700667 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700668 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700669
Doug Zongker01ce19c2014-02-04 13:48:15 -0800670 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700671 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700672
Doug Zongker01ce19c2014-02-04 13:48:15 -0800673 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700674 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700675
Doug Zongker1c390a22009-05-14 19:06:36 -0700676 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700677 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700678
Doug Zongker14833602010-02-02 13:12:04 -0800679 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800680
Doug Zongker922206e2014-03-04 13:16:24 -0800681 if OPTIONS.wipe_user_data:
682 script.ShowProgress(0.1, 10)
683 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700684
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800685 if OPTIONS.two_step:
686 script.AppendExtra("""
687set_stage("%(bcb_dev)s", "");
688""" % bcb_dev)
689 script.AppendExtra("else\n")
690 script.WriteRawImage("/boot", "recovery.img")
691 script.AppendExtra("""
692set_stage("%(bcb_dev)s", "2/3");
693reboot_now("%(bcb_dev)s", "");
694endif;
695endif;
696""" % bcb_dev)
Tao Bao177c6102016-02-23 11:38:39 -0800697
698 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800699 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700700 WriteMetadata(metadata, output_zip)
701
Doug Zongkerfc44a512014-08-26 13:10:25 -0700702
Dan Albert8e0178d2015-01-27 15:53:15 -0800703def WritePolicyConfig(file_name, output_zip):
704 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500705
Doug Zongker2ea21062010-04-28 16:05:21 -0700706
707def WriteMetadata(metadata, output_zip):
708 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
709 "".join(["%s=%s\n" % kv
710 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700711
Doug Zongkerfc44a512014-08-26 13:10:25 -0700712
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700713def LoadPartitionFiles(z, partition):
714 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700715 ZipFile, and return a dict of {filename: File object}."""
716 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700717 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700718 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700719 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700720 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700721 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700722 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700723 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800724 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700725
726
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700727def GetBuildProp(prop, info_dict):
728 """Return the fingerprint of the build of a given target-files info_dict."""
729 try:
730 return info_dict.get("build.prop", {})[prop]
731 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700732 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700733
Doug Zongkerfc44a512014-08-26 13:10:25 -0700734
Michael Runge4038aa82013-12-13 18:06:28 -0800735def AddToKnownPaths(filename, known_paths):
736 if filename[-1] == "/":
737 return
738 dirs = filename.split("/")[:-1]
739 while len(dirs) > 0:
740 path = "/".join(dirs)
741 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700742 break
Michael Runge4038aa82013-12-13 18:06:28 -0800743 known_paths.add(path)
744 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700745
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700746
Geremy Condra36bd3652014-02-06 19:45:10 -0800747def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
748 source_version = OPTIONS.source_info_dict["recovery_api_version"]
749 target_version = OPTIONS.target_info_dict["recovery_api_version"]
750
751 if source_version == 0:
752 print ("WARNING: generating edify script for a source that "
753 "can't install it.")
Tao Baobebd3cf2015-06-22 19:17:41 -0700754 script = edify_generator.EdifyGenerator(
755 source_version, OPTIONS.target_info_dict,
756 fstab=OPTIONS.source_info_dict["fstab"])
Geremy Condra36bd3652014-02-06 19:45:10 -0800757
Tao Bao177c6102016-02-23 11:38:39 -0800758 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
759 recovery_mount_options = OPTIONS.source_info_dict.get(
760 "recovery_mount_options")
761 oem_dict = None
762 if oem_props is not None and len(oem_props) > 0:
763 if OPTIONS.oem_source is None:
764 raise common.ExternalError("OEM source required for this build")
765 script.Mount("/oem", recovery_mount_options)
766 oem_dict = common.LoadDictionaryFromLines(
767 open(OPTIONS.oem_source).readlines())
768
Dan Albert8b72aef2015-03-23 19:13:21 -0700769 metadata = {
Tao Bao177c6102016-02-23 11:38:39 -0800770 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
771 OPTIONS.source_info_dict),
772 "ota-type": "BLOCK",
Dan Albert8b72aef2015-03-23 19:13:21 -0700773 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800774
Tao Bao177c6102016-02-23 11:38:39 -0800775 post_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict)
776 pre_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
777 is_downgrade = long(post_timestamp) < long(pre_timestamp)
778
779 if OPTIONS.downgrade:
780 metadata["ota-downgrade"] = "yes"
781 if not is_downgrade:
782 raise RuntimeError("--downgrade specified but no downgrade detected: "
783 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
784 else:
785 if is_downgrade:
786 # Non-fatal here to allow generating such a package which may require
787 # manual work to adjust the post-timestamp. A legit use case is that we
788 # cut a new build C (after having A and B), but want to enfore the
789 # update path of A -> C -> B. Specifying --downgrade may not help since
790 # that would enforce a data wipe for C -> B update.
791 print("\nWARNING: downgrade detected: pre: %s, post: %s.\n"
792 "The package may not be deployed properly. "
793 "Try --downgrade?\n" % (pre_timestamp, post_timestamp))
794 metadata["post-timestamp"] = post_timestamp
795
Geremy Condra36bd3652014-02-06 19:45:10 -0800796 device_specific = common.DeviceSpecificParams(
797 source_zip=source_zip,
798 source_version=source_version,
799 target_zip=target_zip,
800 target_version=target_version,
801 output_zip=output_zip,
802 script=script,
803 metadata=metadata,
Tao Baoe09359a2015-10-13 16:37:12 -0700804 info_dict=OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800805
Tao Bao177c6102016-02-23 11:38:39 -0800806 target_fp = CalculateFingerprint(oem_props, oem_dict,
807 OPTIONS.target_info_dict)
808 source_fp = CalculateFingerprint(oem_props, oem_dict,
809 OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800810 metadata["pre-build"] = source_fp
811 metadata["post-build"] = target_fp
812
813 source_boot = common.GetBootableImage(
814 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
815 OPTIONS.source_info_dict)
816 target_boot = common.GetBootableImage(
817 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
818 updating_boot = (not OPTIONS.two_step and
819 (source_boot.data != target_boot.data))
820
Geremy Condra36bd3652014-02-06 19:45:10 -0800821 target_recovery = common.GetBootableImage(
822 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800823
Doug Zongkerfc44a512014-08-26 13:10:25 -0700824 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
825 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700826
827 blockimgdiff_version = 1
828 if OPTIONS.info_dict:
829 blockimgdiff_version = max(
830 int(i) for i in
831 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
832
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700833 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700834 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700835
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700836 if HasVendorPartition(target_zip):
837 if not HasVendorPartition(source_zip):
838 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700839 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
840 OPTIONS.source_info_dict)
841 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
842 OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700843 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700844 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700845 else:
846 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800847
Michael Rungec6e3afd2014-05-05 11:55:47 -0700848 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800849 device_specific.IncrementalOTA_Assertions()
850
851 # Two-step incremental package strategy (in chronological order,
852 # which is *not* the order in which the generated script has
853 # things):
854 #
855 # if stage is not "2/3" or "3/3":
856 # do verification on current system
857 # write recovery image to boot partition
858 # set stage to "2/3"
859 # reboot to boot partition and restart recovery
860 # else if stage is "2/3":
861 # write recovery image to recovery partition
862 # set stage to "3/3"
863 # reboot to recovery partition and restart recovery
864 # else:
865 # (stage must be "3/3")
866 # perform update:
867 # patch system files, etc.
868 # force full install of new boot image
869 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700870 # complete script normally
871 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800872
873 if OPTIONS.two_step:
Tao Baocce673b2015-07-29 14:09:23 -0700874 if not OPTIONS.source_info_dict.get("multistage_support", None):
Geremy Condra36bd3652014-02-06 19:45:10 -0800875 assert False, "two-step packages not supported by this build"
Tao Baocce673b2015-07-29 14:09:23 -0700876 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Geremy Condra36bd3652014-02-06 19:45:10 -0800877 assert fs.fs_type.upper() == "EMMC", \
878 "two-step packages only supported on devices with EMMC /misc partitions"
879 bcb_dev = {"bcb_dev": fs.device}
880 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
881 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700882if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800883""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -0700884 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800885 script.WriteRawImage("/recovery", "recovery.img")
886 script.AppendExtra("""
887set_stage("%(bcb_dev)s", "3/3");
888reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700889else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800890""" % bcb_dev)
891
Tao Bao6c55a8a2015-04-08 15:30:27 -0700892 # Dump fingerprints
893 script.Print("Source: %s" % CalculateFingerprint(
894 oem_props, oem_dict, OPTIONS.source_info_dict))
895 script.Print("Target: %s" % CalculateFingerprint(
896 oem_props, oem_dict, OPTIONS.target_info_dict))
897
Geremy Condra36bd3652014-02-06 19:45:10 -0800898 script.Print("Verifying current system...")
899
900 device_specific.IncrementalOTA_VerifyBegin()
901
Michael Rungec6e3afd2014-05-05 11:55:47 -0700902 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700903 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
904 # patching on a device that's already on the target build will damage the
905 # system. Because operations like move don't check the block state, they
906 # always apply the changes unconditionally.
907 if blockimgdiff_version <= 2:
908 script.AssertSomeFingerprint(source_fp)
909 else:
910 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700911 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700912 if blockimgdiff_version <= 2:
913 script.AssertSomeThumbprint(
914 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
915 else:
916 script.AssertSomeThumbprint(
917 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
918 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800919
920 if updating_boot:
Tao Baocce673b2015-07-29 14:09:23 -0700921 boot_type, boot_device = common.GetTypeAndDevice(
922 "/boot", OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800923 d = common.Difference(target_boot, source_boot)
924 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700925 if d is None:
926 include_full_boot = True
927 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
928 else:
929 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800930
Doug Zongkerf8340082014-08-05 10:39:37 -0700931 print "boot target: %d source: %d diff: %d" % (
932 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800933
Doug Zongkerf8340082014-08-05 10:39:37 -0700934 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800935
Doug Zongkerf8340082014-08-05 10:39:37 -0700936 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
937 (boot_type, boot_device,
938 source_boot.size, source_boot.sha1,
939 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800940
941 device_specific.IncrementalOTA_VerifyEnd()
942
943 if OPTIONS.two_step:
944 script.WriteRawImage("/boot", "recovery.img")
945 script.AppendExtra("""
946set_stage("%(bcb_dev)s", "2/3");
947reboot_now("%(bcb_dev)s", "");
948else
949""" % bcb_dev)
950
Jesse Zhao75bcea02015-01-06 10:59:53 -0800951 # Verify the existing partitions.
952 system_diff.WriteVerifyScript(script)
953 if vendor_diff:
954 vendor_diff.WriteVerifyScript(script)
955
Geremy Condra36bd3652014-02-06 19:45:10 -0800956 script.Comment("---- start making changes here ----")
957
958 device_specific.IncrementalOTA_InstallBegin()
959
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700960 system_diff.WriteScript(script, output_zip,
961 progress=0.8 if vendor_diff else 0.9)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700962 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700963 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800964
965 if OPTIONS.two_step:
966 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
967 script.WriteRawImage("/boot", "boot.img")
968 print "writing full boot image (forced by two-step mode)"
969
970 if not OPTIONS.two_step:
971 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700972 if include_full_boot:
973 print "boot image changed; including full."
974 script.Print("Installing boot image...")
975 script.WriteRawImage("/boot", "boot.img")
976 else:
977 # Produce the boot image by applying a patch to the current
978 # contents of the boot partition, and write it back to the
979 # partition.
980 print "boot image changed; including patch."
981 script.Print("Patching boot image...")
982 script.ShowProgress(0.1, 10)
983 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
984 % (boot_type, boot_device,
985 source_boot.size, source_boot.sha1,
986 target_boot.size, target_boot.sha1),
987 "-",
988 target_boot.size, target_boot.sha1,
989 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800990 else:
991 print "boot image unchanged; skipping."
992
993 # Do device-specific installation (eg, write radio image).
994 device_specific.IncrementalOTA_InstallEnd()
995
996 if OPTIONS.extra_script is not None:
997 script.AppendExtra(OPTIONS.extra_script)
998
Doug Zongker922206e2014-03-04 13:16:24 -0800999 if OPTIONS.wipe_user_data:
1000 script.Print("Erasing user data...")
1001 script.FormatPartition("/data")
Tao Bao177c6102016-02-23 11:38:39 -08001002 metadata["ota-wipe"] = "yes"
Doug Zongker922206e2014-03-04 13:16:24 -08001003
Geremy Condra36bd3652014-02-06 19:45:10 -08001004 if OPTIONS.two_step:
1005 script.AppendExtra("""
1006set_stage("%(bcb_dev)s", "");
1007endif;
1008endif;
1009""" % bcb_dev)
1010
1011 script.SetProgress(1)
Tao Baofa41fb22016-03-08 17:53:39 -08001012 # For downgrade OTAs, we prefer to use the update-binary in the source
1013 # build that is actually newer than the one in the target build.
1014 if OPTIONS.downgrade:
1015 script.AddToZip(source_zip, output_zip, input_path=OPTIONS.updater_binary)
1016 else:
1017 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -08001018 WriteMetadata(metadata, output_zip)
1019
Doug Zongker32b527d2014-03-04 10:03:02 -08001020
Dan Albert8b72aef2015-03-23 19:13:21 -07001021class FileDifference(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001022 def __init__(self, partition, source_zip, target_zip, output_zip):
Dan Albert8b72aef2015-03-23 19:13:21 -07001023 self.deferred_patch_list = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001024 print "Loading target..."
1025 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
1026 print "Loading source..."
1027 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
1028
1029 self.verbatim_targets = verbatim_targets = []
1030 self.patch_list = patch_list = []
1031 diffs = []
1032 self.renames = renames = {}
1033 known_paths = set()
1034 largest_source_size = 0
1035
1036 matching_file_cache = {}
1037 for fn, sf in source_data.items():
1038 assert fn == sf.name
1039 matching_file_cache["path:" + fn] = sf
1040 if fn in target_data.keys():
1041 AddToKnownPaths(fn, known_paths)
1042 # Only allow eligibility for filename/sha matching
1043 # if there isn't a perfect path match.
1044 if target_data.get(sf.name) is None:
1045 matching_file_cache["file:" + fn.split("/")[-1]] = sf
1046 matching_file_cache["sha:" + sf.sha1] = sf
1047
1048 for fn in sorted(target_data.keys()):
1049 tf = target_data[fn]
1050 assert fn == tf.name
1051 sf = ClosestFileMatch(tf, matching_file_cache, renames)
1052 if sf is not None and sf.name != tf.name:
1053 print "File has moved from " + sf.name + " to " + tf.name
1054 renames[sf.name] = tf
1055
1056 if sf is None or fn in OPTIONS.require_verbatim:
1057 # This file should be included verbatim
1058 if fn in OPTIONS.prohibit_verbatim:
1059 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
1060 print "send", fn, "verbatim"
1061 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001062 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001063 if fn in target_data.keys():
1064 AddToKnownPaths(fn, known_paths)
1065 elif tf.sha1 != sf.sha1:
1066 # File is different; consider sending as a patch
1067 diffs.append(common.Difference(tf, sf))
1068 else:
1069 # Target file data identical to source (may still be renamed)
1070 pass
1071
1072 common.ComputeDifferences(diffs)
1073
1074 for diff in diffs:
1075 tf, sf, d = diff.GetPatch()
1076 path = "/".join(tf.name.split("/")[:-1])
1077 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1078 path not in known_paths:
1079 # patch is almost as big as the file; don't bother patching
1080 # or a patch + rename cannot take place due to the target
1081 # directory not existing
1082 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001083 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001084 if sf.name in renames:
1085 del renames[sf.name]
1086 AddToKnownPaths(tf.name, known_paths)
1087 else:
1088 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1089 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1090 largest_source_size = max(largest_source_size, sf.size)
1091
1092 self.largest_source_size = largest_source_size
1093
1094 def EmitVerification(self, script):
1095 so_far = 0
Dan Albert8b72aef2015-03-23 19:13:21 -07001096 for tf, sf, _, _ in self.patch_list:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001097 if tf.name != sf.name:
1098 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1099 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1100 so_far += sf.size
1101 return so_far
1102
Michael Runge63f01de2014-10-28 19:24:19 -07001103 def EmitExplicitTargetVerification(self, script):
Dan Albert8b72aef2015-03-23 19:13:21 -07001104 for fn, _, sha1 in self.verbatim_targets:
1105 if fn[-1] != "/":
Michael Runge63f01de2014-10-28 19:24:19 -07001106 script.FileCheck("/"+fn, sha1)
1107 for tf, _, _, _ in self.patch_list:
1108 script.FileCheck(tf.name, tf.sha1)
1109
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001110 def RemoveUnneededFiles(self, script, extras=()):
Dan Albert8b72aef2015-03-23 19:13:21 -07001111 script.DeleteFiles(
1112 ["/" + i[0] for i in self.verbatim_targets] +
1113 ["/" + i for i in sorted(self.source_data)
1114 if i not in self.target_data and i not in self.renames] +
1115 list(extras))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001116
1117 def TotalPatchSize(self):
1118 return sum(i[1].size for i in self.patch_list)
1119
1120 def EmitPatches(self, script, total_patch_size, so_far):
1121 self.deferred_patch_list = deferred_patch_list = []
1122 for item in self.patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001123 tf, sf, _, _ = item
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001124 if tf.name == "system/build.prop":
1125 deferred_patch_list.append(item)
1126 continue
Dan Albert8b72aef2015-03-23 19:13:21 -07001127 if sf.name != tf.name:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001128 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
Dan Albert8b72aef2015-03-23 19:13:21 -07001129 script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1,
1130 "patch/" + sf.name + ".p")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001131 so_far += tf.size
1132 script.SetProgress(so_far / total_patch_size)
1133 return so_far
1134
1135 def EmitDeferredPatches(self, script):
1136 for item in self.deferred_patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001137 tf, sf, _, _ = item
1138 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1,
1139 "patch/" + sf.name + ".p")
1140 script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001141
1142 def EmitRenames(self, script):
1143 if len(self.renames) > 0:
1144 script.Print("Renaming files...")
1145 for src, tgt in self.renames.iteritems():
1146 print "Renaming " + src + " to " + tgt.name
1147 script.RenameFile(src, tgt.name)
1148
1149
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001150def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001151 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1152 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1153
Doug Zongker26e66192014-02-20 13:22:07 -08001154 if (OPTIONS.block_based and
1155 target_has_recovery_patch and
1156 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001157 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1158
Doug Zongker37974732010-09-16 17:44:38 -07001159 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1160 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001161
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001162 if source_version == 0:
1163 print ("WARNING: generating edify script for a source that "
1164 "can't install it.")
Tao Baobebd3cf2015-06-22 19:17:41 -07001165 script = edify_generator.EdifyGenerator(
1166 source_version, OPTIONS.target_info_dict,
1167 fstab=OPTIONS.source_info_dict["fstab"])
Doug Zongkereef39442009-04-02 12:14:19 -07001168
Michael Runge6e836112014-04-15 17:40:21 -07001169 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Tao Baobebd3cf2015-06-22 19:17:41 -07001170 recovery_mount_options = OPTIONS.source_info_dict.get(
1171 "recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001172 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001173 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001174 if OPTIONS.oem_source is None:
1175 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001176 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001177 oem_dict = common.LoadDictionaryFromLines(
1178 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001179
Dan Albert8b72aef2015-03-23 19:13:21 -07001180 metadata = {
1181 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1182 OPTIONS.source_info_dict),
Tao Bao177c6102016-02-23 11:38:39 -08001183 "ota-type": "FILE",
Dan Albert8b72aef2015-03-23 19:13:21 -07001184 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001185
Tao Bao177c6102016-02-23 11:38:39 -08001186 post_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict)
1187 pre_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
1188 is_downgrade = long(post_timestamp) < long(pre_timestamp)
1189
1190 if OPTIONS.downgrade:
1191 metadata["ota-downgrade"] = "yes"
1192 if not is_downgrade:
1193 raise RuntimeError("--downgrade specified but no downgrade detected: "
1194 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
1195 else:
1196 if is_downgrade:
1197 # Non-fatal here to allow generating such a package which may require
1198 # manual work to adjust the post-timestamp. A legit use case is that we
1199 # cut a new build C (after having A and B), but want to enfore the
1200 # update path of A -> C -> B. Specifying --downgrade may not help since
1201 # that would enforce a data wipe for C -> B update.
1202 print("\nWARNING: downgrade detected: pre: %s, post: %s.\n"
1203 "The package may not be deployed properly. "
1204 "Try --downgrade?\n" % (pre_timestamp, post_timestamp))
1205 metadata["post-timestamp"] = post_timestamp
1206
Doug Zongker05d3dea2009-06-22 11:32:31 -07001207 device_specific = common.DeviceSpecificParams(
1208 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001209 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001210 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001211 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001212 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001213 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001214 metadata=metadata,
Tao Baoe09359a2015-10-13 16:37:12 -07001215 info_dict=OPTIONS.source_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001216
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001217 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001218 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001219 if HasVendorPartition(target_zip):
1220 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001221 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001222 else:
1223 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001224
Dan Albert8b72aef2015-03-23 19:13:21 -07001225 target_fp = CalculateFingerprint(oem_props, oem_dict,
1226 OPTIONS.target_info_dict)
1227 source_fp = CalculateFingerprint(oem_props, oem_dict,
1228 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001229
1230 if oem_props is None:
1231 script.AssertSomeFingerprint(source_fp, target_fp)
1232 else:
1233 script.AssertSomeThumbprint(
1234 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1235 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1236
Doug Zongker2ea21062010-04-28 16:05:21 -07001237 metadata["pre-build"] = source_fp
1238 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001239
Doug Zongker55d93282011-01-25 17:03:34 -08001240 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001241 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1242 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001243 target_boot = common.GetBootableImage(
1244 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001245 updating_boot = (not OPTIONS.two_step and
1246 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001247
Doug Zongker55d93282011-01-25 17:03:34 -08001248 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001249 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1250 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001251 target_recovery = common.GetBootableImage(
1252 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001253 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001254
Doug Zongker881dd402009-09-20 14:03:55 -07001255 # Here's how we divide up the progress bar:
1256 # 0.1 for verifying the start state (PatchCheck calls)
1257 # 0.8 for applying patches (ApplyPatch calls)
1258 # 0.1 for unpacking verbatim files, symlinking, and doing the
1259 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001260
Michael Runge6e836112014-04-15 17:40:21 -07001261 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001262 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001263
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001264 # Two-step incremental package strategy (in chronological order,
1265 # which is *not* the order in which the generated script has
1266 # things):
1267 #
1268 # if stage is not "2/3" or "3/3":
1269 # do verification on current system
1270 # write recovery image to boot partition
1271 # set stage to "2/3"
1272 # reboot to boot partition and restart recovery
1273 # else if stage is "2/3":
1274 # write recovery image to recovery partition
1275 # set stage to "3/3"
1276 # reboot to recovery partition and restart recovery
1277 # else:
1278 # (stage must be "3/3")
1279 # perform update:
1280 # patch system files, etc.
1281 # force full install of new boot image
1282 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001283 # complete script normally
1284 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001285
1286 if OPTIONS.two_step:
Tao Baocce673b2015-07-29 14:09:23 -07001287 if not OPTIONS.source_info_dict.get("multistage_support", None):
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001288 assert False, "two-step packages not supported by this build"
Tao Baocce673b2015-07-29 14:09:23 -07001289 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001290 assert fs.fs_type.upper() == "EMMC", \
1291 "two-step packages only supported on devices with EMMC /misc partitions"
1292 bcb_dev = {"bcb_dev": fs.device}
1293 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1294 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001295if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001296""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001297 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001298 script.WriteRawImage("/recovery", "recovery.img")
1299 script.AppendExtra("""
1300set_stage("%(bcb_dev)s", "3/3");
1301reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001302else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001303""" % bcb_dev)
1304
Tao Bao6c55a8a2015-04-08 15:30:27 -07001305 # Dump fingerprints
1306 script.Print("Source: %s" % (source_fp,))
1307 script.Print("Target: %s" % (target_fp,))
1308
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001309 script.Print("Verifying current system...")
1310
Doug Zongkere5ff5902012-01-17 10:55:37 -08001311 device_specific.IncrementalOTA_VerifyBegin()
1312
Doug Zongker881dd402009-09-20 14:03:55 -07001313 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001314 so_far = system_diff.EmitVerification(script)
1315 if vendor_diff:
1316 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001317
Doug Zongker5da317e2009-06-02 13:38:17 -07001318 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001319 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001320 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001321 print "boot target: %d source: %d diff: %d" % (
1322 target_boot.size, source_boot.size, len(d))
1323
Doug Zongker048e7ca2009-06-15 14:31:53 -07001324 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001325
Tao Baocce673b2015-07-29 14:09:23 -07001326 boot_type, boot_device = common.GetTypeAndDevice(
1327 "/boot", OPTIONS.source_info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001328
1329 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1330 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001331 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001332 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001333 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001334
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001335 size = []
Dan Albert8b72aef2015-03-23 19:13:21 -07001336 if system_diff.patch_list:
1337 size.append(system_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001338 if vendor_diff:
Dan Albert8b72aef2015-03-23 19:13:21 -07001339 if vendor_diff.patch_list:
1340 size.append(vendor_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001341 if size or updating_recovery or updating_boot:
1342 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001343
Doug Zongker05d3dea2009-06-22 11:32:31 -07001344 device_specific.IncrementalOTA_VerifyEnd()
1345
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001346 if OPTIONS.two_step:
1347 script.WriteRawImage("/boot", "recovery.img")
1348 script.AppendExtra("""
1349set_stage("%(bcb_dev)s", "2/3");
1350reboot_now("%(bcb_dev)s", "");
1351else
1352""" % bcb_dev)
1353
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001354 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001355
Doug Zongkere5ff5902012-01-17 10:55:37 -08001356 device_specific.IncrementalOTA_InstallBegin()
1357
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001358 if OPTIONS.two_step:
1359 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1360 script.WriteRawImage("/boot", "boot.img")
1361 print "writing full boot image (forced by two-step mode)"
1362
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001363 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001364 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1365 if vendor_diff:
1366 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001367
Doug Zongker881dd402009-09-20 14:03:55 -07001368 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001369 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1370 if vendor_diff:
1371 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001372 if updating_boot:
1373 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001374
1375 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001376 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1377 if vendor_diff:
1378 script.Print("Patching vendor files...")
1379 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001380
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001381 if not OPTIONS.two_step:
1382 if updating_boot:
1383 # Produce the boot image by applying a patch to the current
1384 # contents of the boot partition, and write it back to the
1385 # partition.
1386 script.Print("Patching boot image...")
1387 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1388 % (boot_type, boot_device,
1389 source_boot.size, source_boot.sha1,
1390 target_boot.size, target_boot.sha1),
1391 "-",
1392 target_boot.size, target_boot.sha1,
1393 source_boot.sha1, "patch/boot.img.p")
1394 so_far += target_boot.size
1395 script.SetProgress(so_far / total_patch_size)
1396 print "boot image changed; including."
1397 else:
1398 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001399
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001400 system_items = ItemSet("system", "META/filesystem_config.txt")
1401 if vendor_diff:
1402 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1403
Doug Zongkereef39442009-04-02 12:14:19 -07001404 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001405 # Recovery is generated as a patch using both the boot image
1406 # (which contains the same linux kernel as recovery) and the file
1407 # /system/etc/recovery-resource.dat (which contains all the images
1408 # used in the recovery UI) as sources. This lets us minimize the
1409 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001410 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001411 # For older builds where recovery-resource.dat is not present, we
1412 # use only the boot image as the source.
1413
Doug Zongkerc9253822014-02-04 12:17:58 -08001414 if not target_has_recovery_patch:
1415 def output_sink(fn, data):
1416 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001417 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001418
1419 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1420 target_recovery, target_boot)
1421 script.DeleteFiles(["/system/recovery-from-boot.p",
1422 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001423 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001424 else:
1425 print "recovery image unchanged; skipping."
1426
Doug Zongker881dd402009-09-20 14:03:55 -07001427 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001428
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001429 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1430 if vendor_diff:
1431 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1432
1433 temp_script = script.MakeTemporary()
1434 system_items.GetMetadata(target_zip)
1435 system_items.Get("system").SetPermissions(temp_script)
1436 if vendor_diff:
1437 vendor_items.GetMetadata(target_zip)
1438 vendor_items.Get("vendor").SetPermissions(temp_script)
1439
1440 # Note that this call will mess up the trees of Items, so make sure
1441 # we're done with them.
1442 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1443 if vendor_diff:
1444 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001445
1446 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001447 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1448
1449 # Delete all the symlinks in source that aren't in target. This
1450 # needs to happen before verbatim files are unpacked, in case a
1451 # symlink in the source is replaced by a real file in the target.
Tao Bao39c322c2015-09-02 10:28:08 -07001452
1453 # If a symlink in the source will be replaced by a regular file, we cannot
1454 # delete the symlink/file in case the package gets applied again. For such
1455 # a symlink, we prepend a sha1_check() to detect if it has been updated.
1456 # (Bug: 23646151)
1457 replaced_symlinks = dict()
1458 if system_diff:
1459 for i in system_diff.verbatim_targets:
1460 replaced_symlinks["/%s" % (i[0],)] = i[2]
1461 if vendor_diff:
1462 for i in vendor_diff.verbatim_targets:
1463 replaced_symlinks["/%s" % (i[0],)] = i[2]
1464
1465 if system_diff:
1466 for tf in system_diff.renames.values():
1467 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1468 if vendor_diff:
1469 for tf in vendor_diff.renames.values():
1470 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1471
1472 always_delete = []
1473 may_delete = []
Doug Zongkereef39442009-04-02 12:14:19 -07001474 for dest, link in source_symlinks:
1475 if link not in target_symlinks_d:
Tao Bao39c322c2015-09-02 10:28:08 -07001476 if link in replaced_symlinks:
1477 may_delete.append((link, replaced_symlinks[link]))
1478 else:
1479 always_delete.append(link)
1480 script.DeleteFiles(always_delete)
1481 script.DeleteFilesIfNotMatching(may_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001482
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001483 if system_diff.verbatim_targets:
1484 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001485 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001486 if vendor_diff and vendor_diff.verbatim_targets:
1487 script.Print("Unpacking new vendor files...")
1488 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001489
Doug Zongkerc9253822014-02-04 12:17:58 -08001490 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001491 script.Print("Unpacking new recovery...")
1492 script.UnpackPackageDir("recovery", "/system")
1493
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001494 system_diff.EmitRenames(script)
1495 if vendor_diff:
1496 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001497
Doug Zongker05d3dea2009-06-22 11:32:31 -07001498 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001499
1500 # Create all the symlinks that don't already exist, or point to
1501 # somewhere different than what we want. Delete each symlink before
1502 # creating it, since the 'symlink' command won't overwrite.
1503 to_create = []
1504 for dest, link in target_symlinks:
1505 if link in source_symlinks_d:
1506 if dest != source_symlinks_d[link]:
1507 to_create.append((dest, link))
1508 else:
1509 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001510 script.DeleteFiles([i[1] for i in to_create])
1511 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001512
1513 # Now that the symlinks are created, we can set all the
1514 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001515 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001516
Doug Zongker881dd402009-09-20 14:03:55 -07001517 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001518 device_specific.IncrementalOTA_InstallEnd()
1519
Doug Zongker1c390a22009-05-14 19:06:36 -07001520 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001521 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001522
Doug Zongkere92f15a2011-08-26 13:46:40 -07001523 # Patch the build.prop file last, so if something fails but the
1524 # device can still come up, it appears to be the old build and will
1525 # get set the OTA package again to retry.
1526 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001527 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001528
Doug Zongker922206e2014-03-04 13:16:24 -08001529 if OPTIONS.wipe_user_data:
1530 script.Print("Erasing user data...")
1531 script.FormatPartition("/data")
Tao Bao177c6102016-02-23 11:38:39 -08001532 metadata["ota-wipe"] = "yes"
Doug Zongker922206e2014-03-04 13:16:24 -08001533
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001534 if OPTIONS.two_step:
1535 script.AppendExtra("""
1536set_stage("%(bcb_dev)s", "");
1537endif;
1538endif;
1539""" % bcb_dev)
1540
Michael Runge63f01de2014-10-28 19:24:19 -07001541 if OPTIONS.verify and system_diff:
1542 script.Print("Remounting and verifying system partition files...")
1543 script.Unmount("/system")
1544 script.Mount("/system")
1545 system_diff.EmitExplicitTargetVerification(script)
1546
1547 if OPTIONS.verify and vendor_diff:
1548 script.Print("Remounting and verifying vendor partition files...")
1549 script.Unmount("/vendor")
1550 script.Mount("/vendor")
1551 vendor_diff.EmitExplicitTargetVerification(script)
Tao Baofa41fb22016-03-08 17:53:39 -08001552
1553 # For downgrade OTAs, we prefer to use the update-binary in the source
1554 # build that is actually newer than the one in the target build.
1555 if OPTIONS.downgrade:
1556 script.AddToZip(source_zip, output_zip, input_path=OPTIONS.updater_binary)
1557 else:
1558 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001559
Doug Zongker2ea21062010-04-28 16:05:21 -07001560 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001561
1562
1563def main(argv):
1564
1565 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001566 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001567 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001568 elif o in ("-k", "--package_key"):
1569 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001570 elif o in ("-i", "--incremental_from"):
1571 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001572 elif o == "--full_radio":
1573 OPTIONS.full_radio = True
leozwanga1fcaf82015-09-15 08:44:12 -07001574 elif o == "--full_bootloader":
1575 OPTIONS.full_bootloader = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001576 elif o in ("-w", "--wipe_user_data"):
1577 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001578 elif o in ("-n", "--no_prereq"):
1579 OPTIONS.omit_prereq = True
Tao Bao177c6102016-02-23 11:38:39 -08001580 elif o == "--downgrade":
1581 OPTIONS.downgrade = True
1582 OPTIONS.wipe_user_data = True
Michael Runge6e836112014-04-15 17:40:21 -07001583 elif o in ("-o", "--oem_settings"):
1584 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001585 elif o in ("-e", "--extra_script"):
1586 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001587 elif o in ("-a", "--aslr_mode"):
1588 if a in ("on", "On", "true", "True", "yes", "Yes"):
1589 OPTIONS.aslr_mode = True
1590 else:
1591 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001592 elif o in ("-t", "--worker_threads"):
1593 if a.isdigit():
1594 OPTIONS.worker_threads = int(a)
1595 else:
1596 raise ValueError("Cannot parse value %r for option %r - only "
1597 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001598 elif o in ("-2", "--two_step"):
1599 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001600 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001601 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001602 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001603 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001604 elif o == "--block":
1605 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001606 elif o in ("-b", "--binary"):
1607 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001608 elif o in ("--no_fallback_to_full",):
1609 OPTIONS.fallback_to_full = False
Tao Baod47d8e12015-05-21 14:09:49 -07001610 elif o == "--stash_threshold":
1611 try:
1612 OPTIONS.stash_threshold = float(a)
1613 except ValueError:
1614 raise ValueError("Cannot parse value %r for option %r - expecting "
1615 "a float" % (a, o))
Doug Zongkereef39442009-04-02 12:14:19 -07001616 else:
1617 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001618 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001619
1620 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001621 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001622 extra_long_opts=[
1623 "board_config=",
1624 "package_key=",
1625 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001626 "full_radio",
leozwanga1fcaf82015-09-15 08:44:12 -07001627 "full_bootloader",
Dan Albert8b72aef2015-03-23 19:13:21 -07001628 "wipe_user_data",
1629 "no_prereq",
Tao Bao177c6102016-02-23 11:38:39 -08001630 "downgrade",
Dan Albert8b72aef2015-03-23 19:13:21 -07001631 "extra_script=",
1632 "worker_threads=",
1633 "aslr_mode=",
1634 "two_step",
1635 "no_signing",
1636 "block",
1637 "binary=",
1638 "oem_settings=",
1639 "verify",
1640 "no_fallback_to_full",
Tao Baod47d8e12015-05-21 14:09:49 -07001641 "stash_threshold=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001642 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001643
1644 if len(args) != 2:
1645 common.Usage(__doc__)
1646 sys.exit(1)
1647
Tao Bao177c6102016-02-23 11:38:39 -08001648 if OPTIONS.downgrade:
1649 # Sanity check to enforce a data wipe.
1650 if not OPTIONS.wipe_user_data:
1651 raise ValueError("Cannot downgrade without a data wipe")
1652
1653 # We should only allow downgrading incrementals (as opposed to full).
1654 # Otherwise the device may go back from arbitrary build with this full
1655 # OTA package.
1656 if OPTIONS.incremental_source is None:
1657 raise ValueError("Cannot generate downgradable full OTAs - consider"
1658 "using --omit_prereq?")
1659
Doug Zongker1c390a22009-05-14 19:06:36 -07001660 if OPTIONS.extra_script is not None:
1661 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1662
Doug Zongkereef39442009-04-02 12:14:19 -07001663 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001664 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001665
Doug Zongkereef39442009-04-02 12:14:19 -07001666 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001667 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001668
1669 # If this image was originally labelled with SELinux contexts, make sure we
1670 # also apply the labels in our new image. During building, the "file_contexts"
1671 # is in the out/ directory tree, but for repacking from target-files.zip it's
1672 # in the root directory of the ramdisk.
1673 if "selinux_fc" in OPTIONS.info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001674 OPTIONS.info_dict["selinux_fc"] = os.path.join(
1675 OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")
Kenny Roote2e9f612013-05-29 12:59:35 -07001676
Doug Zongker37974732010-09-16 17:44:38 -07001677 if OPTIONS.verbose:
1678 print "--- target info ---"
1679 common.DumpInfoDict(OPTIONS.info_dict)
1680
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001681 # If the caller explicitly specified the device-specific extensions
1682 # path via -s/--device_specific, use that. Otherwise, use
1683 # META/releasetools.py if it is present in the target target_files.
1684 # Otherwise, take the path of the file from 'tool_extensions' in the
1685 # info dict and look for that in the local filesystem, relative to
1686 # the current directory.
1687
Doug Zongker37974732010-09-16 17:44:38 -07001688 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001689 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1690 if os.path.exists(from_input):
1691 print "(using device-specific extensions from target_files)"
1692 OPTIONS.device_specific = from_input
1693 else:
1694 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1695
Doug Zongker37974732010-09-16 17:44:38 -07001696 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001697 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001698
Doug Zongker62d4f182014-08-04 16:06:43 -07001699 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001700
Doug Zongker62d4f182014-08-04 16:06:43 -07001701 if OPTIONS.no_signing:
Dan Albert8b72aef2015-03-23 19:13:21 -07001702 if os.path.exists(args[1]):
1703 os.unlink(args[1])
1704 output_zip = zipfile.ZipFile(args[1], "w",
1705 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001706 else:
1707 temp_zip_file = tempfile.NamedTemporaryFile()
1708 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1709 compression=zipfile.ZIP_DEFLATED)
1710
Tao Baod47d8e12015-05-21 14:09:49 -07001711 cache_size = OPTIONS.info_dict.get("cache_size", None)
1712 if cache_size is None:
1713 raise RuntimeError("can't determine the cache partition size")
1714 OPTIONS.cache_size = cache_size
1715
Doug Zongker62d4f182014-08-04 16:06:43 -07001716 if OPTIONS.incremental_source is None:
1717 WriteFullOTAPackage(input_zip, output_zip)
1718 if OPTIONS.package_key is None:
1719 OPTIONS.package_key = OPTIONS.info_dict.get(
1720 "default_system_dev_certificate",
1721 "build/target/product/security/testkey")
Tao Baof3282b42015-04-01 11:21:55 -07001722 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001723 break
1724
1725 else:
1726 print "unzipping source target-files..."
Dan Albert8b72aef2015-03-23 19:13:21 -07001727 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
1728 OPTIONS.incremental_source)
Doug Zongker62d4f182014-08-04 16:06:43 -07001729 OPTIONS.target_info_dict = OPTIONS.info_dict
1730 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1731 if "selinux_fc" in OPTIONS.source_info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001732 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(
1733 OPTIONS.source_tmp, "BOOT", "RAMDISK", "file_contexts")
Doug Zongker62d4f182014-08-04 16:06:43 -07001734 if OPTIONS.package_key is None:
1735 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1736 "default_system_dev_certificate",
1737 "build/target/product/security/testkey")
1738 if OPTIONS.verbose:
1739 print "--- source info ---"
1740 common.DumpInfoDict(OPTIONS.source_info_dict)
1741 try:
1742 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Baof3282b42015-04-01 11:21:55 -07001743 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001744 break
1745 except ValueError:
Dan Albert8b72aef2015-03-23 19:13:21 -07001746 if not OPTIONS.fallback_to_full:
1747 raise
Doug Zongker62d4f182014-08-04 16:06:43 -07001748 print "--- failed to build incremental; falling back to full ---"
1749 OPTIONS.incremental_source = None
Tao Baof3282b42015-04-01 11:21:55 -07001750 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001751
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001752 if not OPTIONS.no_signing:
1753 SignOutput(temp_zip_file.name, args[1])
1754 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001755
Doug Zongkereef39442009-04-02 12:14:19 -07001756 print "done."
1757
1758
1759if __name__ == '__main__':
1760 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001761 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001762 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001763 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07001764 print
1765 print " ERROR: %s" % (e,)
1766 print
1767 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001768 finally:
1769 common.Cleanup()