blob: d50f086baf87d4772372197922eddadc1137b202 [file] [log] [blame]
Doug Zongkereef39442009-04-02 12:14:19 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2008 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""
18Given a target-files zipfile, produces an OTA package that installs
19that build. An incremental OTA is produced if -i is given, otherwise
20a full OTA is produced.
21
22Usage: ota_from_target_files [flags] input_target_files output_ota_package
23
Doug Zongker25568482014-03-03 10:21:27 -080024 --board_config <file>
Doug Zongkerfdd8e692009-08-03 17:27:48 -070025 Deprecated.
Doug Zongkereef39442009-04-02 12:14:19 -070026
Doug Zongkerafb32ea2011-09-22 10:28:04 -070027 -k (--package_key) <key> Key to use to sign the package (default is
28 the value of default_system_dev_certificate from the input
29 target-files's META/misc_info.txt, or
30 "build/target/product/security/testkey" if that value is not
31 specified).
32
33 For incremental OTAs, the default value is based on the source
34 target-file, not the target build.
Doug Zongkereef39442009-04-02 12:14:19 -070035
36 -i (--incremental_from) <file>
37 Generate an incremental OTA using the given target-files zip as
38 the starting build.
39
Tao Bao43078aa2015-04-21 14:32:35 -070040 --full_radio
41 When generating an incremental OTA, always include a full copy of
42 radio image. This option is only meaningful when -i is specified,
43 because a full radio is always included in a full OTA if applicable.
44
leozwanga1fcaf82015-09-15 08:44:12 -070045 --full_bootloader
46 When generating an incremental OTA, always include a full copy of
47 bootloader image. This option is only meaningful when -i is specified,
48 because a full bootloader is always included in a full OTA if applicable.
49
Michael Runge63f01de2014-10-28 19:24:19 -070050 -v (--verify)
51 Remount and verify the checksums of the files written to the
52 system and vendor (if used) partitions. Incremental builds only.
53
Michael Runge6e836112014-04-15 17:40:21 -070054 -o (--oem_settings) <file>
55 Use the file to specify the expected OEM-specific properties
56 on the OEM partition of the intended device.
57
Tao Baodf4cb0b2016-02-25 19:49:55 -080058 --oem_no_mount
59 For devices with OEM-specific properties but without an OEM partition,
60 do not mount the OEM partition in the updater-script. This should be
61 very rarely used, since it's expected to have a dedicated OEM partition
62 for OEM-specific properties. Only meaningful when -o is specified.
63
Doug Zongkerdbfaae52009-04-21 17:12:54 -070064 -w (--wipe_user_data)
65 Generate an OTA package that will wipe the user data partition
66 when installed.
67
Doug Zongker962069c2009-04-23 11:41:58 -070068 -n (--no_prereq)
69 Omit the timestamp prereq check normally included at the top of
70 the build scripts (used for developer OTA packages which
71 legitimately need to go back and forth).
72
Tao Bao177c6102016-02-23 11:38:39 -080073 --downgrade
74 Intentionally generate an incremental OTA that updates from a newer
75 build to an older one (based on timestamp comparison). "post-timestamp"
76 will be replaced by "ota-downgrade=yes" in the metadata file. A data
77 wipe will always be enforced, so "ota-wipe=yes" will also be included in
78 the metadata file.
79
Doug Zongker1c390a22009-05-14 19:06:36 -070080 -e (--extra_script) <file>
81 Insert the contents of file at the end of the update script.
82
Hristo Bojinovdafb0422010-08-26 14:35:16 -070083 -a (--aslr_mode) <on|off>
84 Specify whether to turn on ASLR for the package (on by default).
Stephen Smalley56882bf2012-02-09 13:36:21 -050085
Doug Zongker9b23f2c2013-11-25 14:44:12 -080086 -2 (--two_step)
87 Generate a 'two-step' OTA package, where recovery is updated
88 first, so that any changes made to the system partition are done
89 using the new recovery (new kernel, etc.).
90
Doug Zongker26e66192014-02-20 13:22:07 -080091 --block
92 Generate a block-based OTA if possible. Will fall back to a
93 file-based OTA if the target_files is older and doesn't support
94 block-based OTAs.
95
Doug Zongker25568482014-03-03 10:21:27 -080096 -b (--binary) <file>
97 Use the given binary as the update-binary in the output package,
98 instead of the binary in the build's target_files. Use for
99 development only.
100
Martin Blumenstingl374e1142014-05-31 20:42:55 +0200101 -t (--worker_threads) <int>
102 Specifies the number of worker-threads that will be used when
103 generating patches for incremental updates (defaults to 3).
104
Tao Baod47d8e12015-05-21 14:09:49 -0700105 --stash_threshold <float>
106 Specifies the threshold that will be used to compute the maximum
107 allowed stash size (defaults to 0.8).
Doug Zongkereef39442009-04-02 12:14:19 -0700108"""
109
110import sys
111
Doug Zongkercf6d5a92014-02-18 10:57:07 -0800112if sys.hexversion < 0x02070000:
113 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -0700114 sys.exit(1)
115
Doug Zongkerfc44a512014-08-26 13:10:25 -0700116import multiprocessing
Doug Zongkereef39442009-04-02 12:14:19 -0700117import os
Doug Zongkereef39442009-04-02 12:14:19 -0700118import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -0700119import zipfile
120
121import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700122import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -0700123import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700124
125OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700126OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700127OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700128OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700129OPTIONS.require_verbatim = set()
130OPTIONS.prohibit_verbatim = set(("system/build.prop",))
131OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700132OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700133OPTIONS.omit_prereq = False
Tao Bao177c6102016-02-23 11:38:39 -0800134OPTIONS.downgrade = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700135OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700136OPTIONS.aslr_mode = True
Doug Zongkerfc44a512014-08-26 13:10:25 -0700137OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
138if OPTIONS.worker_threads == 0:
139 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800140OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900141OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800142OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800143OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700144OPTIONS.oem_source = None
Tao Baodf4cb0b2016-02-25 19:49:55 -0800145OPTIONS.oem_no_mount = False
Doug Zongker62d4f182014-08-04 16:06:43 -0700146OPTIONS.fallback_to_full = True
Tao Bao43078aa2015-04-21 14:32:35 -0700147OPTIONS.full_radio = False
leozwanga1fcaf82015-09-15 08:44:12 -0700148OPTIONS.full_bootloader = False
Tao Baod47d8e12015-05-21 14:09:49 -0700149# Stash size cannot exceed cache_size * threshold.
150OPTIONS.cache_size = None
151OPTIONS.stash_threshold = 0.8
152
Doug Zongkereef39442009-04-02 12:14:19 -0700153def MostPopularKey(d, default):
154 """Given a dict, return the key corresponding to the largest
155 value. Returns 'default' if the dict is empty."""
156 x = [(v, k) for (k, v) in d.iteritems()]
Dan Albert8b72aef2015-03-23 19:13:21 -0700157 if not x:
158 return default
Doug Zongkereef39442009-04-02 12:14:19 -0700159 x.sort()
160 return x[-1][1]
161
162
163def IsSymlink(info):
164 """Return true if the zipfile.ZipInfo object passed in represents a
165 symlink."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700166 return (info.external_attr >> 16) == 0o120777
Doug Zongkereef39442009-04-02 12:14:19 -0700167
Hristo Bojinov96be7202010-08-02 10:26:17 -0700168def IsRegular(info):
169 """Return true if the zipfile.ZipInfo object passed in represents a
170 symlink."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700171 return (info.external_attr >> 28) == 0o10
Doug Zongkereef39442009-04-02 12:14:19 -0700172
Michael Runge4038aa82013-12-13 18:06:28 -0800173def ClosestFileMatch(src, tgtfiles, existing):
174 """Returns the closest file match between a source file and list
175 of potential matches. The exact filename match is preferred,
176 then the sha1 is searched for, and finally a file with the same
177 basename is evaluated. Rename support in the updater-binary is
178 required for the latter checks to be used."""
179
180 result = tgtfiles.get("path:" + src.name)
181 if result is not None:
182 return result
183
184 if not OPTIONS.target_info_dict.get("update_rename_support", False):
185 return None
186
187 if src.size < 1000:
188 return None
189
190 result = tgtfiles.get("sha1:" + src.sha1)
191 if result is not None and existing.get(result.name) is None:
192 return result
193 result = tgtfiles.get("file:" + src.name.split("/")[-1])
194 if result is not None and existing.get(result.name) is None:
195 return result
196 return None
197
Dan Albert8b72aef2015-03-23 19:13:21 -0700198class ItemSet(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700199 def __init__(self, partition, fs_config):
200 self.partition = partition
201 self.fs_config = fs_config
202 self.ITEMS = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700203
Dan Albert8b72aef2015-03-23 19:13:21 -0700204 def Get(self, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700205 if name not in self.ITEMS:
Dan Albert8b72aef2015-03-23 19:13:21 -0700206 self.ITEMS[name] = Item(self, name, is_dir=is_dir)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700207 return self.ITEMS[name]
Doug Zongkereef39442009-04-02 12:14:19 -0700208
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700209 def GetMetadata(self, input_zip):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700210 # The target_files contains a record of what the uid,
211 # gid, and mode are supposed to be.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700212 output = input_zip.read(self.fs_config)
Doug Zongkereef39442009-04-02 12:14:19 -0700213
214 for line in output.split("\n"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700215 if not line:
216 continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700217 columns = line.split()
218 name, uid, gid, mode = columns[:4]
219 selabel = None
220 capabilities = None
221
222 # After the first 4 columns, there are a series of key=value
223 # pairs. Extract out the fields we care about.
224 for element in columns[4:]:
225 key, value = element.split("=")
226 if key == "selabel":
227 selabel = value
228 if key == "capabilities":
229 capabilities = value
230
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700231 i = self.ITEMS.get(name, None)
Doug Zongker283e2a12010-03-15 17:52:32 -0700232 if i is not None:
233 i.uid = int(uid)
234 i.gid = int(gid)
235 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700236 i.selabel = selabel
237 i.capabilities = capabilities
Dan Albert8b72aef2015-03-23 19:13:21 -0700238 if i.is_dir:
Doug Zongker283e2a12010-03-15 17:52:32 -0700239 i.children.sort(key=lambda i: i.name)
240
241 # set metadata for the files generated by this script.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700242 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700243 if i:
244 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700245 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700246 if i:
247 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700248
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700249
Dan Albert8b72aef2015-03-23 19:13:21 -0700250class Item(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700251 """Items represent the metadata (user, group, mode) of files and
252 directories in the system image."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700253 def __init__(self, itemset, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700254 self.itemset = itemset
255 self.name = name
256 self.uid = None
257 self.gid = None
258 self.mode = None
259 self.selabel = None
260 self.capabilities = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700261 self.is_dir = is_dir
262 self.descendants = None
263 self.best_subtree = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700264
265 if name:
Dan Albert8b72aef2015-03-23 19:13:21 -0700266 self.parent = itemset.Get(os.path.dirname(name), is_dir=True)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700267 self.parent.children.append(self)
268 else:
269 self.parent = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700270 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700271 self.children = []
272
273 def Dump(self, indent=0):
274 if self.uid is not None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700275 print "%s%s %d %d %o" % (
276 " " * indent, self.name, self.uid, self.gid, self.mode)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700277 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700278 print "%s%s %s %s %s" % (
279 " " * indent, self.name, self.uid, self.gid, self.mode)
280 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700281 print "%s%s" % (" "*indent, self.descendants)
282 print "%s%s" % (" "*indent, self.best_subtree)
283 for i in self.children:
284 i.Dump(indent=indent+1)
285
Doug Zongkereef39442009-04-02 12:14:19 -0700286 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700287 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
Dan Albert8b72aef2015-03-23 19:13:21 -0700288 all children and determine the best strategy for using set_perm_recursive
289 and set_perm to correctly chown/chmod all the files to their desired
Doug Zongkereef39442009-04-02 12:14:19 -0700290 values. Recursively calls itself for all descendants.
291
Dan Albert8b72aef2015-03-23 19:13:21 -0700292 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count}
293 counting up all descendants of this node. (dmode or fmode may be None.)
294 Also sets the best_subtree of each directory Item to the (uid, gid, dmode,
295 fmode, selabel, capabilities) tuple that will match the most descendants of
296 that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700297 """
298
Dan Albert8b72aef2015-03-23 19:13:21 -0700299 assert self.is_dir
300 key = (self.uid, self.gid, self.mode, None, self.selabel,
301 self.capabilities)
302 self.descendants = {key: 1}
303 d = self.descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700304 for i in self.children:
Dan Albert8b72aef2015-03-23 19:13:21 -0700305 if i.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700306 for k, v in i.CountChildMetadata().iteritems():
307 d[k] = d.get(k, 0) + v
308 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700309 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700310 d[k] = d.get(k, 0) + 1
311
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700312 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
313 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700314
315 # First, find the (uid, gid) pair that matches the most
316 # descendants.
317 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700318 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700319 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
320 ug = MostPopularKey(ug, (0, 0))
321
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700322 # Now find the dmode, fmode, selabel, and capabilities that match
323 # the most descendants with that (uid, gid), and choose those.
Dan Albert8b72aef2015-03-23 19:13:21 -0700324 best_dmode = (0, 0o755)
325 best_fmode = (0, 0o644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700326 best_selabel = (0, None)
327 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700328 for k, count in d.iteritems():
Dan Albert8b72aef2015-03-23 19:13:21 -0700329 if k[:2] != ug:
330 continue
331 if k[2] is not None and count >= best_dmode[0]:
332 best_dmode = (count, k[2])
333 if k[3] is not None and count >= best_fmode[0]:
334 best_fmode = (count, k[3])
335 if k[4] is not None and count >= best_selabel[0]:
336 best_selabel = (count, k[4])
337 if k[5] is not None and count >= best_capabilities[0]:
338 best_capabilities = (count, k[5])
339 self.best_subtree = ug + (
340 best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700341
342 return d
343
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700344 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700345 """Append set_perm/set_perm_recursive commands to 'script' to
346 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700347 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700348
349 self.CountChildMetadata()
350
351 def recurse(item, current):
Dan Albert8b72aef2015-03-23 19:13:21 -0700352 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple
353 # that the current item (and all its children) have already been set to.
354 # We only need to issue set_perm/set_perm_recursive commands if we're
Doug Zongkereef39442009-04-02 12:14:19 -0700355 # supposed to be something different.
Dan Albert8b72aef2015-03-23 19:13:21 -0700356 if item.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700357 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700358 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700359 current = item.best_subtree
360
361 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700362 item.mode != current[2] or item.selabel != current[4] or \
363 item.capabilities != current[5]:
364 script.SetPermissions("/"+item.name, item.uid, item.gid,
365 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700366
367 for i in item.children:
368 recurse(i, current)
369 else:
370 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700371 item.mode != current[3] or item.selabel != current[4] or \
372 item.capabilities != current[5]:
373 script.SetPermissions("/"+item.name, item.uid, item.gid,
374 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700375
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700376 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700377
378
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700379def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
380 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700381 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800382 list of symlinks. output_zip may be None, in which case the copy is
383 skipped (but the other side effects still happen). substitute is an
384 optional dict of {output filename: contents} to be output instead of
385 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700386 """
387
388 symlinks = []
389
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700390 partition = itemset.partition
391
Doug Zongkereef39442009-04-02 12:14:19 -0700392 for info in input_zip.infolist():
Tao Baoeaf885b2015-03-23 16:01:17 -0700393 prefix = partition.upper() + "/"
394 if info.filename.startswith(prefix):
395 basefilename = info.filename[len(prefix):]
Doug Zongkereef39442009-04-02 12:14:19 -0700396 if IsSymlink(info):
397 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700398 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700399 else:
Tao Baof3282b42015-04-01 11:21:55 -0700400 import copy
Doug Zongkereef39442009-04-02 12:14:19 -0700401 info2 = copy.copy(info)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700402 fn = info2.filename = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700403 if substitute and fn in substitute and substitute[fn] is None:
404 continue
405 if output_zip is not None:
406 if substitute and fn in substitute:
407 data = substitute[fn]
408 else:
409 data = input_zip.read(info.filename)
Tao Baof3282b42015-04-01 11:21:55 -0700410 common.ZipWriteStr(output_zip, info2, data)
Doug Zongkereef39442009-04-02 12:14:19 -0700411 if fn.endswith("/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700412 itemset.Get(fn[:-1], is_dir=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700413 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700414 itemset.Get(fn)
Doug Zongkereef39442009-04-02 12:14:19 -0700415
416 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800417 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700418
419
Doug Zongkereef39442009-04-02 12:14:19 -0700420def SignOutput(temp_zip_name, output_zip_name):
421 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
422 pw = key_passwords[OPTIONS.package_key]
423
Doug Zongker951495f2009-08-14 12:44:19 -0700424 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
425 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700426
427
Dan Albert8b72aef2015-03-23 19:13:21 -0700428def AppendAssertions(script, info_dict, oem_dict=None):
Michael Runge6e836112014-04-15 17:40:21 -0700429 oem_props = info_dict.get("oem_fingerprint_properties")
Michael Runge560569a2014-09-18 15:12:45 -0700430 if oem_props is None or len(oem_props) == 0:
Michael Runge6e836112014-04-15 17:40:21 -0700431 device = GetBuildProp("ro.product.device", info_dict)
432 script.AssertDevice(device)
433 else:
434 if oem_dict is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700435 raise common.ExternalError(
436 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700437 for prop in oem_props.split():
438 if oem_dict.get(prop) is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700439 raise common.ExternalError(
440 "The OEM file is missing the property %s" % prop)
Michael Runge6e836112014-04-15 17:40:21 -0700441 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700442
Doug Zongkereef39442009-04-02 12:14:19 -0700443
Doug Zongkerc9253822014-02-04 12:17:58 -0800444def HasRecoveryPatch(target_files_zip):
445 try:
446 target_files_zip.getinfo("SYSTEM/recovery-from-boot.p")
447 return True
448 except KeyError:
449 return False
Doug Zongker73ef8252009-07-23 15:12:53 -0700450
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700451def HasVendorPartition(target_files_zip):
452 try:
453 target_files_zip.getinfo("VENDOR/")
454 return True
455 except KeyError:
456 return False
457
Michael Runge6e836112014-04-15 17:40:21 -0700458def GetOemProperty(name, oem_props, oem_dict, info_dict):
459 if oem_props is not None and name in oem_props:
460 return oem_dict[name]
461 return GetBuildProp(name, info_dict)
462
463
464def CalculateFingerprint(oem_props, oem_dict, info_dict):
465 if oem_props is None:
466 return GetBuildProp("ro.build.fingerprint", info_dict)
467 return "%s/%s/%s:%s" % (
Dan Albert8b72aef2015-03-23 19:13:21 -0700468 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
469 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
470 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
471 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700472
Doug Zongkerfc44a512014-08-26 13:10:25 -0700473
Doug Zongker3c84f562014-07-31 11:06:30 -0700474def GetImage(which, tmpdir, info_dict):
Doug Zongkerfc44a512014-08-26 13:10:25 -0700475 # Return an image object (suitable for passing to BlockImageDiff)
476 # for the 'which' partition (most be "system" or "vendor"). If a
477 # prebuilt image and file map are found in tmpdir they are used,
478 # otherwise they are reconstructed from the individual files.
Doug Zongker3c84f562014-07-31 11:06:30 -0700479
480 assert which in ("system", "vendor")
481
482 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700483 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
484 if os.path.exists(path) and os.path.exists(mappath):
Doug Zongker3c84f562014-07-31 11:06:30 -0700485 print "using %s.img from target-files" % (which,)
Doug Zongker3c84f562014-07-31 11:06:30 -0700486 # This is a 'new' target-files, which already has the image in it.
Doug Zongker3c84f562014-07-31 11:06:30 -0700487
488 else:
489 print "building %s.img from target-files" % (which,)
490
491 # This is an 'old' target-files, which does not contain images
492 # already built. Build them.
493
Doug Zongkerfc44a512014-08-26 13:10:25 -0700494 mappath = tempfile.mkstemp()[1]
495 OPTIONS.tempfiles.append(mappath)
496
Doug Zongker3c84f562014-07-31 11:06:30 -0700497 import add_img_to_target_files
498 if which == "system":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700499 path = add_img_to_target_files.BuildSystem(
500 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700501 elif which == "vendor":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700502 path = add_img_to_target_files.BuildVendor(
503 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700504
Tao Bao5ece99d2015-05-12 11:42:31 -0700505 # Bug: http://b/20939131
506 # In ext4 filesystems, block 0 might be changed even being mounted
507 # R/O. We add it to clobbered_blocks so that it will be written to the
508 # target unconditionally. Note that they are still part of care_map.
509 clobbered_blocks = "0"
510
511 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700512
513
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700514def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700515 # TODO: how to determine this? We don't know what version it will
Tao Baobebd3cf2015-06-22 19:17:41 -0700516 # be installed on top of. For now, we expect the API just won't
517 # change very often. Similarly for fstab, it might have changed
518 # in the target build.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700519 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700520
Michael Runge6e836112014-04-15 17:40:21 -0700521 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700522 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700523 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700524 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700525 if OPTIONS.oem_source is None:
526 raise common.ExternalError("OEM source required for this build")
Tao Baodf4cb0b2016-02-25 19:49:55 -0800527 if not OPTIONS.oem_no_mount:
528 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700529 oem_dict = common.LoadDictionaryFromLines(
530 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -0700531
Dan Albert8b72aef2015-03-23 19:13:21 -0700532 metadata = {
533 "post-build": CalculateFingerprint(oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700534 OPTIONS.info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700535 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
536 OPTIONS.info_dict),
537 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
538 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700539
Doug Zongker05d3dea2009-06-22 11:32:31 -0700540 device_specific = common.DeviceSpecificParams(
541 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700542 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700543 output_zip=output_zip,
544 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700545 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700546 metadata=metadata,
547 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700548
Doug Zongkerc9253822014-02-04 12:17:58 -0800549 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800550 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800551
Doug Zongker962069c2009-04-23 11:41:58 -0700552 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700553 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700554 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
555 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700556
Michael Runge6e836112014-04-15 17:40:21 -0700557 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700558 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800559
560 # Two-step package strategy (in chronological order, which is *not*
561 # the order in which the generated script has things):
562 #
563 # if stage is not "2/3" or "3/3":
564 # write recovery image to boot partition
565 # set stage to "2/3"
566 # reboot to boot partition and restart recovery
567 # else if stage is "2/3":
568 # write recovery image to recovery partition
569 # set stage to "3/3"
570 # reboot to recovery partition and restart recovery
571 # else:
572 # (stage must be "3/3")
573 # set stage to ""
574 # do normal full package installation:
575 # wipe and install system, boot image, etc.
576 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700577 # complete script normally
578 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800579
580 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
581 OPTIONS.input_tmp, "RECOVERY")
582 if OPTIONS.two_step:
583 if not OPTIONS.info_dict.get("multistage_support", None):
584 assert False, "two-step packages not supported by this build"
585 fs = OPTIONS.info_dict["fstab"]["/misc"]
586 assert fs.fs_type.upper() == "EMMC", \
587 "two-step packages only supported on devices with EMMC /misc partitions"
588 bcb_dev = {"bcb_dev": fs.device}
589 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
590 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700591if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800592""" % bcb_dev)
593 script.WriteRawImage("/recovery", "recovery.img")
594 script.AppendExtra("""
595set_stage("%(bcb_dev)s", "3/3");
596reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700597else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800598""" % bcb_dev)
599
Tao Bao6c55a8a2015-04-08 15:30:27 -0700600 # Dump fingerprints
601 script.Print("Target: %s" % CalculateFingerprint(
602 oem_props, oem_dict, OPTIONS.info_dict))
603
Doug Zongkere5ff5902012-01-17 10:55:37 -0800604 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700605
Doug Zongker01ce19c2014-02-04 13:48:15 -0800606 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700607
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700608 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800609 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700610 if HasVendorPartition(input_zip):
611 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700612
Kenny Rootf32dc712012-04-08 10:42:34 -0700613 if "selinux_fc" in OPTIONS.info_dict:
614 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500615
Michael Runge7cd99ba2014-10-22 17:21:48 -0700616 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
617
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700618 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700619 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800620
Doug Zongker26e66192014-02-20 13:22:07 -0800621 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700622 # Full OTA is done as an "incremental" against an empty source
623 # image. This has the effect of writing new data from the package
624 # to the entire partition, but lets us reuse the updater code that
625 # writes incrementals to do it.
626 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
627 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700628 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700629 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800630 else:
631 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700632 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800633 if not has_recovery_patch:
634 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800635 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700636
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700637 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800638 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700639
Doug Zongker55d93282011-01-25 17:03:34 -0800640 boot_img = common.GetBootableImage("boot.img", "boot.img",
641 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800642
Doug Zongker91a99c22014-05-09 13:15:01 -0700643 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800644 def output_sink(fn, data):
645 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700646 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800647
648 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
649 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700650
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700651 system_items.GetMetadata(input_zip)
652 system_items.Get("system").SetPermissions(script)
653
654 if HasVendorPartition(input_zip):
655 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
656 script.ShowProgress(0.1, 0)
657
658 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700659 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
660 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700661 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700662 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700663 else:
664 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700665 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700666 script.UnpackPackageDir("vendor", "/vendor")
667
668 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
669 script.MakeSymlinks(symlinks)
670
671 vendor_items.GetMetadata(input_zip)
672 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700673
Doug Zongker37974732010-09-16 17:44:38 -0700674 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700675 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700676
Doug Zongker01ce19c2014-02-04 13:48:15 -0800677 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700678 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700679
Doug Zongker01ce19c2014-02-04 13:48:15 -0800680 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700681 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700682
Doug Zongker1c390a22009-05-14 19:06:36 -0700683 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700684 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700685
Doug Zongker14833602010-02-02 13:12:04 -0800686 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800687
Doug Zongker922206e2014-03-04 13:16:24 -0800688 if OPTIONS.wipe_user_data:
689 script.ShowProgress(0.1, 10)
690 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700691
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800692 if OPTIONS.two_step:
693 script.AppendExtra("""
694set_stage("%(bcb_dev)s", "");
695""" % bcb_dev)
696 script.AppendExtra("else\n")
697 script.WriteRawImage("/boot", "recovery.img")
698 script.AppendExtra("""
699set_stage("%(bcb_dev)s", "2/3");
700reboot_now("%(bcb_dev)s", "");
701endif;
702endif;
703""" % bcb_dev)
Tao Bao177c6102016-02-23 11:38:39 -0800704
705 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800706 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700707 WriteMetadata(metadata, output_zip)
708
Doug Zongkerfc44a512014-08-26 13:10:25 -0700709
Dan Albert8e0178d2015-01-27 15:53:15 -0800710def WritePolicyConfig(file_name, output_zip):
711 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500712
Doug Zongker2ea21062010-04-28 16:05:21 -0700713
714def WriteMetadata(metadata, output_zip):
715 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
716 "".join(["%s=%s\n" % kv
717 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700718
Doug Zongkerfc44a512014-08-26 13:10:25 -0700719
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700720def LoadPartitionFiles(z, partition):
721 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700722 ZipFile, and return a dict of {filename: File object}."""
723 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700724 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700725 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700726 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700727 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700728 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700729 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700730 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800731 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700732
733
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700734def GetBuildProp(prop, info_dict):
735 """Return the fingerprint of the build of a given target-files info_dict."""
736 try:
737 return info_dict.get("build.prop", {})[prop]
738 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700739 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700740
Doug Zongkerfc44a512014-08-26 13:10:25 -0700741
Michael Runge4038aa82013-12-13 18:06:28 -0800742def AddToKnownPaths(filename, known_paths):
743 if filename[-1] == "/":
744 return
745 dirs = filename.split("/")[:-1]
746 while len(dirs) > 0:
747 path = "/".join(dirs)
748 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700749 break
Michael Runge4038aa82013-12-13 18:06:28 -0800750 known_paths.add(path)
751 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700752
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700753
Geremy Condra36bd3652014-02-06 19:45:10 -0800754def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
755 source_version = OPTIONS.source_info_dict["recovery_api_version"]
756 target_version = OPTIONS.target_info_dict["recovery_api_version"]
757
758 if source_version == 0:
759 print ("WARNING: generating edify script for a source that "
760 "can't install it.")
Tao Baobebd3cf2015-06-22 19:17:41 -0700761 script = edify_generator.EdifyGenerator(
762 source_version, OPTIONS.target_info_dict,
763 fstab=OPTIONS.source_info_dict["fstab"])
Geremy Condra36bd3652014-02-06 19:45:10 -0800764
Tao Baodf4cb0b2016-02-25 19:49:55 -0800765 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
766 recovery_mount_options = OPTIONS.source_info_dict.get(
767 "recovery_mount_options")
768 oem_dict = None
769 if oem_props is not None and len(oem_props) > 0:
770 if OPTIONS.oem_source is None:
771 raise common.ExternalError("OEM source required for this build")
772 if not OPTIONS.oem_no_mount:
773 script.Mount("/oem", recovery_mount_options)
774 oem_dict = common.LoadDictionaryFromLines(
775 open(OPTIONS.oem_source).readlines())
776
Dan Albert8b72aef2015-03-23 19:13:21 -0700777 metadata = {
Tao Bao177c6102016-02-23 11:38:39 -0800778 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
779 OPTIONS.source_info_dict),
780 "ota-type": "BLOCK",
Dan Albert8b72aef2015-03-23 19:13:21 -0700781 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800782
Tao Bao177c6102016-02-23 11:38:39 -0800783 post_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict)
784 pre_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
785 is_downgrade = long(post_timestamp) < long(pre_timestamp)
786
787 if OPTIONS.downgrade:
788 metadata["ota-downgrade"] = "yes"
789 if not is_downgrade:
790 raise RuntimeError("--downgrade specified but no downgrade detected: "
791 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
792 else:
793 if is_downgrade:
794 # Non-fatal here to allow generating such a package which may require
795 # manual work to adjust the post-timestamp. A legit use case is that we
796 # cut a new build C (after having A and B), but want to enfore the
797 # update path of A -> C -> B. Specifying --downgrade may not help since
798 # that would enforce a data wipe for C -> B update.
799 print("\nWARNING: downgrade detected: pre: %s, post: %s.\n"
800 "The package may not be deployed properly. "
801 "Try --downgrade?\n" % (pre_timestamp, post_timestamp))
802 metadata["post-timestamp"] = post_timestamp
803
Geremy Condra36bd3652014-02-06 19:45:10 -0800804 device_specific = common.DeviceSpecificParams(
805 source_zip=source_zip,
806 source_version=source_version,
807 target_zip=target_zip,
808 target_version=target_version,
809 output_zip=output_zip,
810 script=script,
811 metadata=metadata,
Tao Baoe09359a2015-10-13 16:37:12 -0700812 info_dict=OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800813
Tao Bao177c6102016-02-23 11:38:39 -0800814 target_fp = CalculateFingerprint(oem_props, oem_dict,
815 OPTIONS.target_info_dict)
816 source_fp = CalculateFingerprint(oem_props, oem_dict,
817 OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800818 metadata["pre-build"] = source_fp
819 metadata["post-build"] = target_fp
820
821 source_boot = common.GetBootableImage(
822 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
823 OPTIONS.source_info_dict)
824 target_boot = common.GetBootableImage(
825 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
826 updating_boot = (not OPTIONS.two_step and
827 (source_boot.data != target_boot.data))
828
Geremy Condra36bd3652014-02-06 19:45:10 -0800829 target_recovery = common.GetBootableImage(
830 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800831
Doug Zongkerfc44a512014-08-26 13:10:25 -0700832 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
833 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700834
835 blockimgdiff_version = 1
836 if OPTIONS.info_dict:
837 blockimgdiff_version = max(
838 int(i) for i in
839 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
840
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700841 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700842 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700843
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700844 if HasVendorPartition(target_zip):
845 if not HasVendorPartition(source_zip):
846 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700847 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
848 OPTIONS.source_info_dict)
849 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
850 OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700851 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700852 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700853 else:
854 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800855
Michael Rungec6e3afd2014-05-05 11:55:47 -0700856 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800857 device_specific.IncrementalOTA_Assertions()
858
859 # Two-step incremental package strategy (in chronological order,
860 # which is *not* the order in which the generated script has
861 # things):
862 #
863 # if stage is not "2/3" or "3/3":
864 # do verification on current system
865 # write recovery image to boot partition
866 # set stage to "2/3"
867 # reboot to boot partition and restart recovery
868 # else if stage is "2/3":
869 # write recovery image to recovery partition
870 # set stage to "3/3"
871 # reboot to recovery partition and restart recovery
872 # else:
873 # (stage must be "3/3")
874 # perform update:
875 # patch system files, etc.
876 # force full install of new boot image
877 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700878 # complete script normally
879 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800880
881 if OPTIONS.two_step:
Tao Baocce673b2015-07-29 14:09:23 -0700882 if not OPTIONS.source_info_dict.get("multistage_support", None):
Geremy Condra36bd3652014-02-06 19:45:10 -0800883 assert False, "two-step packages not supported by this build"
Tao Baocce673b2015-07-29 14:09:23 -0700884 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Geremy Condra36bd3652014-02-06 19:45:10 -0800885 assert fs.fs_type.upper() == "EMMC", \
886 "two-step packages only supported on devices with EMMC /misc partitions"
887 bcb_dev = {"bcb_dev": fs.device}
888 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
889 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700890if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800891""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -0700892 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800893 script.WriteRawImage("/recovery", "recovery.img")
894 script.AppendExtra("""
895set_stage("%(bcb_dev)s", "3/3");
896reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700897else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800898""" % bcb_dev)
899
Tao Bao6c55a8a2015-04-08 15:30:27 -0700900 # Dump fingerprints
901 script.Print("Source: %s" % CalculateFingerprint(
902 oem_props, oem_dict, OPTIONS.source_info_dict))
903 script.Print("Target: %s" % CalculateFingerprint(
904 oem_props, oem_dict, OPTIONS.target_info_dict))
905
Geremy Condra36bd3652014-02-06 19:45:10 -0800906 script.Print("Verifying current system...")
907
908 device_specific.IncrementalOTA_VerifyBegin()
909
Michael Rungec6e3afd2014-05-05 11:55:47 -0700910 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700911 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
912 # patching on a device that's already on the target build will damage the
913 # system. Because operations like move don't check the block state, they
914 # always apply the changes unconditionally.
915 if blockimgdiff_version <= 2:
916 script.AssertSomeFingerprint(source_fp)
917 else:
918 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700919 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700920 if blockimgdiff_version <= 2:
921 script.AssertSomeThumbprint(
922 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
923 else:
924 script.AssertSomeThumbprint(
925 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
926 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800927
928 if updating_boot:
Tao Baocce673b2015-07-29 14:09:23 -0700929 boot_type, boot_device = common.GetTypeAndDevice(
930 "/boot", OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800931 d = common.Difference(target_boot, source_boot)
932 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700933 if d is None:
934 include_full_boot = True
935 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
936 else:
937 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800938
Doug Zongkerf8340082014-08-05 10:39:37 -0700939 print "boot target: %d source: %d diff: %d" % (
940 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800941
Doug Zongkerf8340082014-08-05 10:39:37 -0700942 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800943
Doug Zongkerf8340082014-08-05 10:39:37 -0700944 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
945 (boot_type, boot_device,
946 source_boot.size, source_boot.sha1,
947 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800948
949 device_specific.IncrementalOTA_VerifyEnd()
950
951 if OPTIONS.two_step:
952 script.WriteRawImage("/boot", "recovery.img")
953 script.AppendExtra("""
954set_stage("%(bcb_dev)s", "2/3");
955reboot_now("%(bcb_dev)s", "");
956else
957""" % bcb_dev)
958
Jesse Zhao75bcea02015-01-06 10:59:53 -0800959 # Verify the existing partitions.
960 system_diff.WriteVerifyScript(script)
961 if vendor_diff:
962 vendor_diff.WriteVerifyScript(script)
963
Geremy Condra36bd3652014-02-06 19:45:10 -0800964 script.Comment("---- start making changes here ----")
965
966 device_specific.IncrementalOTA_InstallBegin()
967
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700968 system_diff.WriteScript(script, output_zip,
969 progress=0.8 if vendor_diff else 0.9)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700970 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700971 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800972
973 if OPTIONS.two_step:
974 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
975 script.WriteRawImage("/boot", "boot.img")
976 print "writing full boot image (forced by two-step mode)"
977
978 if not OPTIONS.two_step:
979 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700980 if include_full_boot:
981 print "boot image changed; including full."
982 script.Print("Installing boot image...")
983 script.WriteRawImage("/boot", "boot.img")
984 else:
985 # Produce the boot image by applying a patch to the current
986 # contents of the boot partition, and write it back to the
987 # partition.
988 print "boot image changed; including patch."
989 script.Print("Patching boot image...")
990 script.ShowProgress(0.1, 10)
991 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
992 % (boot_type, boot_device,
993 source_boot.size, source_boot.sha1,
994 target_boot.size, target_boot.sha1),
995 "-",
996 target_boot.size, target_boot.sha1,
997 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800998 else:
999 print "boot image unchanged; skipping."
1000
1001 # Do device-specific installation (eg, write radio image).
1002 device_specific.IncrementalOTA_InstallEnd()
1003
1004 if OPTIONS.extra_script is not None:
1005 script.AppendExtra(OPTIONS.extra_script)
1006
Doug Zongker922206e2014-03-04 13:16:24 -08001007 if OPTIONS.wipe_user_data:
1008 script.Print("Erasing user data...")
1009 script.FormatPartition("/data")
Tao Bao177c6102016-02-23 11:38:39 -08001010 metadata["ota-wipe"] = "yes"
Doug Zongker922206e2014-03-04 13:16:24 -08001011
Geremy Condra36bd3652014-02-06 19:45:10 -08001012 if OPTIONS.two_step:
1013 script.AppendExtra("""
1014set_stage("%(bcb_dev)s", "");
1015endif;
1016endif;
1017""" % bcb_dev)
1018
1019 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -08001020 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -08001021 WriteMetadata(metadata, output_zip)
1022
Doug Zongker32b527d2014-03-04 10:03:02 -08001023
Dan Albert8b72aef2015-03-23 19:13:21 -07001024class FileDifference(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001025 def __init__(self, partition, source_zip, target_zip, output_zip):
Dan Albert8b72aef2015-03-23 19:13:21 -07001026 self.deferred_patch_list = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001027 print "Loading target..."
1028 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
1029 print "Loading source..."
1030 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
1031
1032 self.verbatim_targets = verbatim_targets = []
1033 self.patch_list = patch_list = []
1034 diffs = []
1035 self.renames = renames = {}
1036 known_paths = set()
1037 largest_source_size = 0
1038
1039 matching_file_cache = {}
1040 for fn, sf in source_data.items():
1041 assert fn == sf.name
1042 matching_file_cache["path:" + fn] = sf
1043 if fn in target_data.keys():
1044 AddToKnownPaths(fn, known_paths)
1045 # Only allow eligibility for filename/sha matching
1046 # if there isn't a perfect path match.
1047 if target_data.get(sf.name) is None:
1048 matching_file_cache["file:" + fn.split("/")[-1]] = sf
1049 matching_file_cache["sha:" + sf.sha1] = sf
1050
1051 for fn in sorted(target_data.keys()):
1052 tf = target_data[fn]
1053 assert fn == tf.name
1054 sf = ClosestFileMatch(tf, matching_file_cache, renames)
1055 if sf is not None and sf.name != tf.name:
1056 print "File has moved from " + sf.name + " to " + tf.name
1057 renames[sf.name] = tf
1058
1059 if sf is None or fn in OPTIONS.require_verbatim:
1060 # This file should be included verbatim
1061 if fn in OPTIONS.prohibit_verbatim:
1062 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
1063 print "send", fn, "verbatim"
1064 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001065 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001066 if fn in target_data.keys():
1067 AddToKnownPaths(fn, known_paths)
1068 elif tf.sha1 != sf.sha1:
1069 # File is different; consider sending as a patch
1070 diffs.append(common.Difference(tf, sf))
1071 else:
1072 # Target file data identical to source (may still be renamed)
1073 pass
1074
1075 common.ComputeDifferences(diffs)
1076
1077 for diff in diffs:
1078 tf, sf, d = diff.GetPatch()
1079 path = "/".join(tf.name.split("/")[:-1])
1080 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1081 path not in known_paths:
1082 # patch is almost as big as the file; don't bother patching
1083 # or a patch + rename cannot take place due to the target
1084 # directory not existing
1085 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001086 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001087 if sf.name in renames:
1088 del renames[sf.name]
1089 AddToKnownPaths(tf.name, known_paths)
1090 else:
1091 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1092 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1093 largest_source_size = max(largest_source_size, sf.size)
1094
1095 self.largest_source_size = largest_source_size
1096
1097 def EmitVerification(self, script):
1098 so_far = 0
Dan Albert8b72aef2015-03-23 19:13:21 -07001099 for tf, sf, _, _ in self.patch_list:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001100 if tf.name != sf.name:
1101 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1102 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1103 so_far += sf.size
1104 return so_far
1105
Michael Runge63f01de2014-10-28 19:24:19 -07001106 def EmitExplicitTargetVerification(self, script):
Dan Albert8b72aef2015-03-23 19:13:21 -07001107 for fn, _, sha1 in self.verbatim_targets:
1108 if fn[-1] != "/":
Michael Runge63f01de2014-10-28 19:24:19 -07001109 script.FileCheck("/"+fn, sha1)
1110 for tf, _, _, _ in self.patch_list:
1111 script.FileCheck(tf.name, tf.sha1)
1112
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001113 def RemoveUnneededFiles(self, script, extras=()):
Dan Albert8b72aef2015-03-23 19:13:21 -07001114 script.DeleteFiles(
1115 ["/" + i[0] for i in self.verbatim_targets] +
1116 ["/" + i for i in sorted(self.source_data)
1117 if i not in self.target_data and i not in self.renames] +
1118 list(extras))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001119
1120 def TotalPatchSize(self):
1121 return sum(i[1].size for i in self.patch_list)
1122
1123 def EmitPatches(self, script, total_patch_size, so_far):
1124 self.deferred_patch_list = deferred_patch_list = []
1125 for item in self.patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001126 tf, sf, _, _ = item
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001127 if tf.name == "system/build.prop":
1128 deferred_patch_list.append(item)
1129 continue
Dan Albert8b72aef2015-03-23 19:13:21 -07001130 if sf.name != tf.name:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001131 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
Dan Albert8b72aef2015-03-23 19:13:21 -07001132 script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1,
1133 "patch/" + sf.name + ".p")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001134 so_far += tf.size
1135 script.SetProgress(so_far / total_patch_size)
1136 return so_far
1137
1138 def EmitDeferredPatches(self, script):
1139 for item in self.deferred_patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001140 tf, sf, _, _ = item
1141 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1,
1142 "patch/" + sf.name + ".p")
1143 script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001144
1145 def EmitRenames(self, script):
1146 if len(self.renames) > 0:
1147 script.Print("Renaming files...")
1148 for src, tgt in self.renames.iteritems():
1149 print "Renaming " + src + " to " + tgt.name
1150 script.RenameFile(src, tgt.name)
1151
1152
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001153def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001154 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1155 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1156
Doug Zongker26e66192014-02-20 13:22:07 -08001157 if (OPTIONS.block_based and
1158 target_has_recovery_patch and
1159 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001160 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1161
Doug Zongker37974732010-09-16 17:44:38 -07001162 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1163 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001164
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001165 if source_version == 0:
1166 print ("WARNING: generating edify script for a source that "
1167 "can't install it.")
Tao Baobebd3cf2015-06-22 19:17:41 -07001168 script = edify_generator.EdifyGenerator(
1169 source_version, OPTIONS.target_info_dict,
1170 fstab=OPTIONS.source_info_dict["fstab"])
Doug Zongkereef39442009-04-02 12:14:19 -07001171
Michael Runge6e836112014-04-15 17:40:21 -07001172 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Tao Baobebd3cf2015-06-22 19:17:41 -07001173 recovery_mount_options = OPTIONS.source_info_dict.get(
1174 "recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001175 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001176 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001177 if OPTIONS.oem_source is None:
1178 raise common.ExternalError("OEM source required for this build")
Tao Baobd25fcd2016-03-07 21:24:40 -08001179 if not OPTIONS.oem_no_mount:
1180 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001181 oem_dict = common.LoadDictionaryFromLines(
1182 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001183
Dan Albert8b72aef2015-03-23 19:13:21 -07001184 metadata = {
1185 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1186 OPTIONS.source_info_dict),
Tao Bao177c6102016-02-23 11:38:39 -08001187 "ota-type": "FILE",
Dan Albert8b72aef2015-03-23 19:13:21 -07001188 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001189
Tao Bao177c6102016-02-23 11:38:39 -08001190 post_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict)
1191 pre_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
1192 is_downgrade = long(post_timestamp) < long(pre_timestamp)
1193
1194 if OPTIONS.downgrade:
1195 metadata["ota-downgrade"] = "yes"
1196 if not is_downgrade:
1197 raise RuntimeError("--downgrade specified but no downgrade detected: "
1198 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
1199 else:
1200 if is_downgrade:
1201 # Non-fatal here to allow generating such a package which may require
1202 # manual work to adjust the post-timestamp. A legit use case is that we
1203 # cut a new build C (after having A and B), but want to enfore the
1204 # update path of A -> C -> B. Specifying --downgrade may not help since
1205 # that would enforce a data wipe for C -> B update.
1206 print("\nWARNING: downgrade detected: pre: %s, post: %s.\n"
1207 "The package may not be deployed properly. "
1208 "Try --downgrade?\n" % (pre_timestamp, post_timestamp))
1209 metadata["post-timestamp"] = post_timestamp
1210
Doug Zongker05d3dea2009-06-22 11:32:31 -07001211 device_specific = common.DeviceSpecificParams(
1212 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001213 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001214 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001215 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001216 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001217 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001218 metadata=metadata,
Tao Baoe09359a2015-10-13 16:37:12 -07001219 info_dict=OPTIONS.source_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001220
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001221 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001222 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001223 if HasVendorPartition(target_zip):
1224 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001225 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001226 else:
1227 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001228
Dan Albert8b72aef2015-03-23 19:13:21 -07001229 target_fp = CalculateFingerprint(oem_props, oem_dict,
1230 OPTIONS.target_info_dict)
1231 source_fp = CalculateFingerprint(oem_props, oem_dict,
1232 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001233
1234 if oem_props is None:
1235 script.AssertSomeFingerprint(source_fp, target_fp)
1236 else:
1237 script.AssertSomeThumbprint(
1238 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1239 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1240
Doug Zongker2ea21062010-04-28 16:05:21 -07001241 metadata["pre-build"] = source_fp
1242 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001243
Doug Zongker55d93282011-01-25 17:03:34 -08001244 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001245 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1246 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001247 target_boot = common.GetBootableImage(
1248 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001249 updating_boot = (not OPTIONS.two_step and
1250 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001251
Doug Zongker55d93282011-01-25 17:03:34 -08001252 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001253 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1254 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001255 target_recovery = common.GetBootableImage(
1256 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001257 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001258
Doug Zongker881dd402009-09-20 14:03:55 -07001259 # Here's how we divide up the progress bar:
1260 # 0.1 for verifying the start state (PatchCheck calls)
1261 # 0.8 for applying patches (ApplyPatch calls)
1262 # 0.1 for unpacking verbatim files, symlinking, and doing the
1263 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001264
Michael Runge6e836112014-04-15 17:40:21 -07001265 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001266 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001267
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001268 # Two-step incremental package strategy (in chronological order,
1269 # which is *not* the order in which the generated script has
1270 # things):
1271 #
1272 # if stage is not "2/3" or "3/3":
1273 # do verification on current system
1274 # write recovery image to boot partition
1275 # set stage to "2/3"
1276 # reboot to boot partition and restart recovery
1277 # else if stage is "2/3":
1278 # write recovery image to recovery partition
1279 # set stage to "3/3"
1280 # reboot to recovery partition and restart recovery
1281 # else:
1282 # (stage must be "3/3")
1283 # perform update:
1284 # patch system files, etc.
1285 # force full install of new boot image
1286 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001287 # complete script normally
1288 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001289
1290 if OPTIONS.two_step:
Tao Baocce673b2015-07-29 14:09:23 -07001291 if not OPTIONS.source_info_dict.get("multistage_support", None):
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001292 assert False, "two-step packages not supported by this build"
Tao Baocce673b2015-07-29 14:09:23 -07001293 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001294 assert fs.fs_type.upper() == "EMMC", \
1295 "two-step packages only supported on devices with EMMC /misc partitions"
1296 bcb_dev = {"bcb_dev": fs.device}
1297 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1298 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001299if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001300""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001301 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001302 script.WriteRawImage("/recovery", "recovery.img")
1303 script.AppendExtra("""
1304set_stage("%(bcb_dev)s", "3/3");
1305reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001306else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001307""" % bcb_dev)
1308
Tao Bao6c55a8a2015-04-08 15:30:27 -07001309 # Dump fingerprints
1310 script.Print("Source: %s" % (source_fp,))
1311 script.Print("Target: %s" % (target_fp,))
1312
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001313 script.Print("Verifying current system...")
1314
Doug Zongkere5ff5902012-01-17 10:55:37 -08001315 device_specific.IncrementalOTA_VerifyBegin()
1316
Doug Zongker881dd402009-09-20 14:03:55 -07001317 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001318 so_far = system_diff.EmitVerification(script)
1319 if vendor_diff:
1320 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001321
Doug Zongker5da317e2009-06-02 13:38:17 -07001322 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001323 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001324 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001325 print "boot target: %d source: %d diff: %d" % (
1326 target_boot.size, source_boot.size, len(d))
1327
Doug Zongker048e7ca2009-06-15 14:31:53 -07001328 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001329
Tao Baocce673b2015-07-29 14:09:23 -07001330 boot_type, boot_device = common.GetTypeAndDevice(
1331 "/boot", OPTIONS.source_info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001332
1333 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1334 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001335 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001336 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001337 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001338
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001339 size = []
Dan Albert8b72aef2015-03-23 19:13:21 -07001340 if system_diff.patch_list:
1341 size.append(system_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001342 if vendor_diff:
Dan Albert8b72aef2015-03-23 19:13:21 -07001343 if vendor_diff.patch_list:
1344 size.append(vendor_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001345 if size or updating_recovery or updating_boot:
1346 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001347
Doug Zongker05d3dea2009-06-22 11:32:31 -07001348 device_specific.IncrementalOTA_VerifyEnd()
1349
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001350 if OPTIONS.two_step:
1351 script.WriteRawImage("/boot", "recovery.img")
1352 script.AppendExtra("""
1353set_stage("%(bcb_dev)s", "2/3");
1354reboot_now("%(bcb_dev)s", "");
1355else
1356""" % bcb_dev)
1357
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001358 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001359
Doug Zongkere5ff5902012-01-17 10:55:37 -08001360 device_specific.IncrementalOTA_InstallBegin()
1361
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001362 if OPTIONS.two_step:
1363 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1364 script.WriteRawImage("/boot", "boot.img")
1365 print "writing full boot image (forced by two-step mode)"
1366
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001367 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001368 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1369 if vendor_diff:
1370 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001371
Doug Zongker881dd402009-09-20 14:03:55 -07001372 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001373 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1374 if vendor_diff:
1375 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001376 if updating_boot:
1377 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001378
1379 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001380 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1381 if vendor_diff:
1382 script.Print("Patching vendor files...")
1383 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001384
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001385 if not OPTIONS.two_step:
1386 if updating_boot:
1387 # Produce the boot image by applying a patch to the current
1388 # contents of the boot partition, and write it back to the
1389 # partition.
1390 script.Print("Patching boot image...")
1391 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1392 % (boot_type, boot_device,
1393 source_boot.size, source_boot.sha1,
1394 target_boot.size, target_boot.sha1),
1395 "-",
1396 target_boot.size, target_boot.sha1,
1397 source_boot.sha1, "patch/boot.img.p")
1398 so_far += target_boot.size
1399 script.SetProgress(so_far / total_patch_size)
1400 print "boot image changed; including."
1401 else:
1402 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001403
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001404 system_items = ItemSet("system", "META/filesystem_config.txt")
1405 if vendor_diff:
1406 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1407
Doug Zongkereef39442009-04-02 12:14:19 -07001408 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001409 # Recovery is generated as a patch using both the boot image
1410 # (which contains the same linux kernel as recovery) and the file
1411 # /system/etc/recovery-resource.dat (which contains all the images
1412 # used in the recovery UI) as sources. This lets us minimize the
1413 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001414 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001415 # For older builds where recovery-resource.dat is not present, we
1416 # use only the boot image as the source.
1417
Doug Zongkerc9253822014-02-04 12:17:58 -08001418 if not target_has_recovery_patch:
1419 def output_sink(fn, data):
1420 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001421 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001422
1423 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1424 target_recovery, target_boot)
1425 script.DeleteFiles(["/system/recovery-from-boot.p",
1426 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001427 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001428 else:
1429 print "recovery image unchanged; skipping."
1430
Doug Zongker881dd402009-09-20 14:03:55 -07001431 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001432
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001433 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1434 if vendor_diff:
1435 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1436
1437 temp_script = script.MakeTemporary()
1438 system_items.GetMetadata(target_zip)
1439 system_items.Get("system").SetPermissions(temp_script)
1440 if vendor_diff:
1441 vendor_items.GetMetadata(target_zip)
1442 vendor_items.Get("vendor").SetPermissions(temp_script)
1443
1444 # Note that this call will mess up the trees of Items, so make sure
1445 # we're done with them.
1446 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1447 if vendor_diff:
1448 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001449
1450 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001451 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1452
1453 # Delete all the symlinks in source that aren't in target. This
1454 # needs to happen before verbatim files are unpacked, in case a
1455 # symlink in the source is replaced by a real file in the target.
Tao Bao39c322c2015-09-02 10:28:08 -07001456
1457 # If a symlink in the source will be replaced by a regular file, we cannot
1458 # delete the symlink/file in case the package gets applied again. For such
1459 # a symlink, we prepend a sha1_check() to detect if it has been updated.
1460 # (Bug: 23646151)
1461 replaced_symlinks = dict()
1462 if system_diff:
1463 for i in system_diff.verbatim_targets:
1464 replaced_symlinks["/%s" % (i[0],)] = i[2]
1465 if vendor_diff:
1466 for i in vendor_diff.verbatim_targets:
1467 replaced_symlinks["/%s" % (i[0],)] = i[2]
1468
1469 if system_diff:
1470 for tf in system_diff.renames.values():
1471 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1472 if vendor_diff:
1473 for tf in vendor_diff.renames.values():
1474 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1475
1476 always_delete = []
1477 may_delete = []
Doug Zongkereef39442009-04-02 12:14:19 -07001478 for dest, link in source_symlinks:
1479 if link not in target_symlinks_d:
Tao Bao39c322c2015-09-02 10:28:08 -07001480 if link in replaced_symlinks:
1481 may_delete.append((link, replaced_symlinks[link]))
1482 else:
1483 always_delete.append(link)
1484 script.DeleteFiles(always_delete)
1485 script.DeleteFilesIfNotMatching(may_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001486
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001487 if system_diff.verbatim_targets:
1488 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001489 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001490 if vendor_diff and vendor_diff.verbatim_targets:
1491 script.Print("Unpacking new vendor files...")
1492 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001493
Doug Zongkerc9253822014-02-04 12:17:58 -08001494 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001495 script.Print("Unpacking new recovery...")
1496 script.UnpackPackageDir("recovery", "/system")
1497
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001498 system_diff.EmitRenames(script)
1499 if vendor_diff:
1500 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001501
Doug Zongker05d3dea2009-06-22 11:32:31 -07001502 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001503
1504 # Create all the symlinks that don't already exist, or point to
1505 # somewhere different than what we want. Delete each symlink before
1506 # creating it, since the 'symlink' command won't overwrite.
1507 to_create = []
1508 for dest, link in target_symlinks:
1509 if link in source_symlinks_d:
1510 if dest != source_symlinks_d[link]:
1511 to_create.append((dest, link))
1512 else:
1513 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001514 script.DeleteFiles([i[1] for i in to_create])
1515 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001516
1517 # Now that the symlinks are created, we can set all the
1518 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001519 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001520
Doug Zongker881dd402009-09-20 14:03:55 -07001521 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001522 device_specific.IncrementalOTA_InstallEnd()
1523
Doug Zongker1c390a22009-05-14 19:06:36 -07001524 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001525 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001526
Doug Zongkere92f15a2011-08-26 13:46:40 -07001527 # Patch the build.prop file last, so if something fails but the
1528 # device can still come up, it appears to be the old build and will
1529 # get set the OTA package again to retry.
1530 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001531 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001532
Doug Zongker922206e2014-03-04 13:16:24 -08001533 if OPTIONS.wipe_user_data:
1534 script.Print("Erasing user data...")
1535 script.FormatPartition("/data")
Tao Bao177c6102016-02-23 11:38:39 -08001536 metadata["ota-wipe"] = "yes"
Doug Zongker922206e2014-03-04 13:16:24 -08001537
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001538 if OPTIONS.two_step:
1539 script.AppendExtra("""
1540set_stage("%(bcb_dev)s", "");
1541endif;
1542endif;
1543""" % bcb_dev)
1544
Michael Runge63f01de2014-10-28 19:24:19 -07001545 if OPTIONS.verify and system_diff:
1546 script.Print("Remounting and verifying system partition files...")
1547 script.Unmount("/system")
1548 script.Mount("/system")
1549 system_diff.EmitExplicitTargetVerification(script)
1550
1551 if OPTIONS.verify and vendor_diff:
1552 script.Print("Remounting and verifying vendor partition files...")
1553 script.Unmount("/vendor")
1554 script.Mount("/vendor")
1555 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001556 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001557
Doug Zongker2ea21062010-04-28 16:05:21 -07001558 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001559
1560
1561def main(argv):
1562
1563 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001564 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001565 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001566 elif o in ("-k", "--package_key"):
1567 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001568 elif o in ("-i", "--incremental_from"):
1569 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001570 elif o == "--full_radio":
1571 OPTIONS.full_radio = True
leozwanga1fcaf82015-09-15 08:44:12 -07001572 elif o == "--full_bootloader":
1573 OPTIONS.full_bootloader = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001574 elif o in ("-w", "--wipe_user_data"):
1575 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001576 elif o in ("-n", "--no_prereq"):
1577 OPTIONS.omit_prereq = True
Tao Bao177c6102016-02-23 11:38:39 -08001578 elif o == "--downgrade":
1579 OPTIONS.downgrade = True
1580 OPTIONS.wipe_user_data = True
Michael Runge6e836112014-04-15 17:40:21 -07001581 elif o in ("-o", "--oem_settings"):
1582 OPTIONS.oem_source = a
Tao Baodf4cb0b2016-02-25 19:49:55 -08001583 elif o == "--oem_no_mount":
1584 OPTIONS.oem_no_mount = True
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=",
Tao Baodf4cb0b2016-02-25 19:49:55 -08001639 "oem_no_mount",
Dan Albert8b72aef2015-03-23 19:13:21 -07001640 "verify",
1641 "no_fallback_to_full",
Tao Baod47d8e12015-05-21 14:09:49 -07001642 "stash_threshold=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001643 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001644
1645 if len(args) != 2:
1646 common.Usage(__doc__)
1647 sys.exit(1)
1648
Tao Bao177c6102016-02-23 11:38:39 -08001649 if OPTIONS.downgrade:
1650 # Sanity check to enforce a data wipe.
1651 if not OPTIONS.wipe_user_data:
1652 raise ValueError("Cannot downgrade without a data wipe")
1653
1654 # We should only allow downgrading incrementals (as opposed to full).
1655 # Otherwise the device may go back from arbitrary build with this full
1656 # OTA package.
1657 if OPTIONS.incremental_source is None:
1658 raise ValueError("Cannot generate downgradable full OTAs - consider"
1659 "using --omit_prereq?")
1660
Doug Zongker1c390a22009-05-14 19:06:36 -07001661 if OPTIONS.extra_script is not None:
1662 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1663
Doug Zongkereef39442009-04-02 12:14:19 -07001664 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001665 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001666
Doug Zongkereef39442009-04-02 12:14:19 -07001667 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001668 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001669
1670 # If this image was originally labelled with SELinux contexts, make sure we
1671 # also apply the labels in our new image. During building, the "file_contexts"
1672 # is in the out/ directory tree, but for repacking from target-files.zip it's
1673 # in the root directory of the ramdisk.
1674 if "selinux_fc" in OPTIONS.info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001675 OPTIONS.info_dict["selinux_fc"] = os.path.join(
1676 OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")
Kenny Roote2e9f612013-05-29 12:59:35 -07001677
Doug Zongker37974732010-09-16 17:44:38 -07001678 if OPTIONS.verbose:
1679 print "--- target info ---"
1680 common.DumpInfoDict(OPTIONS.info_dict)
1681
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001682 # If the caller explicitly specified the device-specific extensions
1683 # path via -s/--device_specific, use that. Otherwise, use
1684 # META/releasetools.py if it is present in the target target_files.
1685 # Otherwise, take the path of the file from 'tool_extensions' in the
1686 # info dict and look for that in the local filesystem, relative to
1687 # the current directory.
1688
Doug Zongker37974732010-09-16 17:44:38 -07001689 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001690 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1691 if os.path.exists(from_input):
1692 print "(using device-specific extensions from target_files)"
1693 OPTIONS.device_specific = from_input
1694 else:
1695 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1696
Doug Zongker37974732010-09-16 17:44:38 -07001697 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001698 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001699
Doug Zongker62d4f182014-08-04 16:06:43 -07001700 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001701
Doug Zongker62d4f182014-08-04 16:06:43 -07001702 if OPTIONS.no_signing:
Dan Albert8b72aef2015-03-23 19:13:21 -07001703 if os.path.exists(args[1]):
1704 os.unlink(args[1])
1705 output_zip = zipfile.ZipFile(args[1], "w",
1706 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001707 else:
1708 temp_zip_file = tempfile.NamedTemporaryFile()
1709 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1710 compression=zipfile.ZIP_DEFLATED)
1711
Tao Baod47d8e12015-05-21 14:09:49 -07001712 cache_size = OPTIONS.info_dict.get("cache_size", None)
1713 if cache_size is None:
1714 raise RuntimeError("can't determine the cache partition size")
1715 OPTIONS.cache_size = cache_size
1716
Doug Zongker62d4f182014-08-04 16:06:43 -07001717 if OPTIONS.incremental_source is None:
1718 WriteFullOTAPackage(input_zip, output_zip)
1719 if OPTIONS.package_key is None:
1720 OPTIONS.package_key = OPTIONS.info_dict.get(
1721 "default_system_dev_certificate",
1722 "build/target/product/security/testkey")
Tao Baof3282b42015-04-01 11:21:55 -07001723 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001724 break
1725
1726 else:
1727 print "unzipping source target-files..."
Dan Albert8b72aef2015-03-23 19:13:21 -07001728 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
1729 OPTIONS.incremental_source)
Doug Zongker62d4f182014-08-04 16:06:43 -07001730 OPTIONS.target_info_dict = OPTIONS.info_dict
1731 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1732 if "selinux_fc" in OPTIONS.source_info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001733 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(
1734 OPTIONS.source_tmp, "BOOT", "RAMDISK", "file_contexts")
Doug Zongker62d4f182014-08-04 16:06:43 -07001735 if OPTIONS.package_key is None:
1736 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1737 "default_system_dev_certificate",
1738 "build/target/product/security/testkey")
1739 if OPTIONS.verbose:
1740 print "--- source info ---"
1741 common.DumpInfoDict(OPTIONS.source_info_dict)
1742 try:
1743 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Baof3282b42015-04-01 11:21:55 -07001744 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001745 break
1746 except ValueError:
Dan Albert8b72aef2015-03-23 19:13:21 -07001747 if not OPTIONS.fallback_to_full:
1748 raise
Doug Zongker62d4f182014-08-04 16:06:43 -07001749 print "--- failed to build incremental; falling back to full ---"
1750 OPTIONS.incremental_source = None
Tao Baof3282b42015-04-01 11:21:55 -07001751 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001752
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001753 if not OPTIONS.no_signing:
1754 SignOutput(temp_zip_file.name, args[1])
1755 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001756
Doug Zongkereef39442009-04-02 12:14:19 -07001757 print "done."
1758
1759
1760if __name__ == '__main__':
1761 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001762 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001763 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001764 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07001765 print
1766 print " ERROR: %s" % (e,)
1767 print
1768 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001769 finally:
1770 common.Cleanup()