blob: 17b56da1c9260178ad22e31c4b92f2926f104bbb [file] [log] [blame]
Doug Zongkereef39442009-04-02 12:14:19 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2008 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""
18Given a target-files zipfile, produces an OTA package that installs
19that build. An incremental OTA is produced if -i is given, otherwise
20a full OTA is produced.
21
22Usage: ota_from_target_files [flags] input_target_files output_ota_package
23
Doug Zongker25568482014-03-03 10:21:27 -080024 --board_config <file>
Doug Zongkerfdd8e692009-08-03 17:27:48 -070025 Deprecated.
Doug Zongkereef39442009-04-02 12:14:19 -070026
Doug Zongkerafb32ea2011-09-22 10:28:04 -070027 -k (--package_key) <key> Key to use to sign the package (default is
28 the value of default_system_dev_certificate from the input
29 target-files's META/misc_info.txt, or
30 "build/target/product/security/testkey" if that value is not
31 specified).
32
33 For incremental OTAs, the default value is based on the source
34 target-file, not the target build.
Doug Zongkereef39442009-04-02 12:14:19 -070035
36 -i (--incremental_from) <file>
37 Generate an incremental OTA using the given target-files zip as
38 the starting build.
39
Tao Bao43078aa2015-04-21 14:32:35 -070040 --full_radio
41 When generating an incremental OTA, always include a full copy of
42 radio image. This option is only meaningful when -i is specified,
43 because a full radio is always included in a full OTA if applicable.
44
leozwanga1fcaf82015-09-15 08:44:12 -070045 --full_bootloader
46 When generating an incremental OTA, always include a full copy of
47 bootloader image. This option is only meaningful when -i is specified,
48 because a full bootloader is always included in a full OTA if applicable.
49
Michael Runge63f01de2014-10-28 19:24:19 -070050 -v (--verify)
51 Remount and verify the checksums of the files written to the
52 system and vendor (if used) partitions. Incremental builds only.
53
Michael Runge6e836112014-04-15 17:40:21 -070054 -o (--oem_settings) <file>
55 Use the file to specify the expected OEM-specific properties
56 on the OEM partition of the intended device.
57
Doug Zongkerdbfaae52009-04-21 17:12:54 -070058 -w (--wipe_user_data)
59 Generate an OTA package that will wipe the user data partition
60 when installed.
61
Doug Zongker962069c2009-04-23 11:41:58 -070062 -n (--no_prereq)
63 Omit the timestamp prereq check normally included at the top of
64 the build scripts (used for developer OTA packages which
65 legitimately need to go back and forth).
66
Tao Bao177c6102016-02-23 11:38:39 -080067 --downgrade
68 Intentionally generate an incremental OTA that updates from a newer
69 build to an older one (based on timestamp comparison). "post-timestamp"
70 will be replaced by "ota-downgrade=yes" in the metadata file. A data
71 wipe will always be enforced, so "ota-wipe=yes" will also be included in
72 the metadata file.
73
Doug Zongker1c390a22009-05-14 19:06:36 -070074 -e (--extra_script) <file>
75 Insert the contents of file at the end of the update script.
76
Hristo Bojinovdafb0422010-08-26 14:35:16 -070077 -a (--aslr_mode) <on|off>
78 Specify whether to turn on ASLR for the package (on by default).
Stephen Smalley56882bf2012-02-09 13:36:21 -050079
Doug Zongker9b23f2c2013-11-25 14:44:12 -080080 -2 (--two_step)
81 Generate a 'two-step' OTA package, where recovery is updated
82 first, so that any changes made to the system partition are done
83 using the new recovery (new kernel, etc.).
84
Doug Zongker26e66192014-02-20 13:22:07 -080085 --block
86 Generate a block-based OTA if possible. Will fall back to a
87 file-based OTA if the target_files is older and doesn't support
88 block-based OTAs.
89
Doug Zongker25568482014-03-03 10:21:27 -080090 -b (--binary) <file>
91 Use the given binary as the update-binary in the output package,
92 instead of the binary in the build's target_files. Use for
93 development only.
94
Martin Blumenstingl374e1142014-05-31 20:42:55 +020095 -t (--worker_threads) <int>
96 Specifies the number of worker-threads that will be used when
97 generating patches for incremental updates (defaults to 3).
98
Tao Baod47d8e12015-05-21 14:09:49 -070099 --stash_threshold <float>
100 Specifies the threshold that will be used to compute the maximum
101 allowed stash size (defaults to 0.8).
Doug Zongkereef39442009-04-02 12:14:19 -0700102"""
103
104import sys
105
Doug Zongkercf6d5a92014-02-18 10:57:07 -0800106if sys.hexversion < 0x02070000:
107 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -0700108 sys.exit(1)
109
Doug Zongkerfc44a512014-08-26 13:10:25 -0700110import multiprocessing
Doug Zongkereef39442009-04-02 12:14:19 -0700111import os
Doug Zongkereef39442009-04-02 12:14:19 -0700112import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -0700113import zipfile
114
115import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700116import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -0700117import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700118
119OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700120OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700121OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700122OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700123OPTIONS.require_verbatim = set()
124OPTIONS.prohibit_verbatim = set(("system/build.prop",))
125OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700126OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700127OPTIONS.omit_prereq = False
Tao Bao177c6102016-02-23 11:38:39 -0800128OPTIONS.downgrade = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700129OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700130OPTIONS.aslr_mode = True
Doug Zongkerfc44a512014-08-26 13:10:25 -0700131OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
132if OPTIONS.worker_threads == 0:
133 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800134OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900135OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800136OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800137OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700138OPTIONS.oem_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -0700139OPTIONS.fallback_to_full = True
Tao Bao43078aa2015-04-21 14:32:35 -0700140OPTIONS.full_radio = False
leozwanga1fcaf82015-09-15 08:44:12 -0700141OPTIONS.full_bootloader = False
Tao Baod47d8e12015-05-21 14:09:49 -0700142# Stash size cannot exceed cache_size * threshold.
143OPTIONS.cache_size = None
144OPTIONS.stash_threshold = 0.8
145
Doug Zongkereef39442009-04-02 12:14:19 -0700146def MostPopularKey(d, default):
147 """Given a dict, return the key corresponding to the largest
148 value. Returns 'default' if the dict is empty."""
149 x = [(v, k) for (k, v) in d.iteritems()]
Dan Albert8b72aef2015-03-23 19:13:21 -0700150 if not x:
151 return default
Doug Zongkereef39442009-04-02 12:14:19 -0700152 x.sort()
153 return x[-1][1]
154
155
156def IsSymlink(info):
157 """Return true if the zipfile.ZipInfo object passed in represents a
158 symlink."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700159 return (info.external_attr >> 16) == 0o120777
Doug Zongkereef39442009-04-02 12:14:19 -0700160
Hristo Bojinov96be7202010-08-02 10:26:17 -0700161def IsRegular(info):
162 """Return true if the zipfile.ZipInfo object passed in represents a
163 symlink."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700164 return (info.external_attr >> 28) == 0o10
Doug Zongkereef39442009-04-02 12:14:19 -0700165
Michael Runge4038aa82013-12-13 18:06:28 -0800166def ClosestFileMatch(src, tgtfiles, existing):
167 """Returns the closest file match between a source file and list
168 of potential matches. The exact filename match is preferred,
169 then the sha1 is searched for, and finally a file with the same
170 basename is evaluated. Rename support in the updater-binary is
171 required for the latter checks to be used."""
172
173 result = tgtfiles.get("path:" + src.name)
174 if result is not None:
175 return result
176
177 if not OPTIONS.target_info_dict.get("update_rename_support", False):
178 return None
179
180 if src.size < 1000:
181 return None
182
183 result = tgtfiles.get("sha1:" + src.sha1)
184 if result is not None and existing.get(result.name) is None:
185 return result
186 result = tgtfiles.get("file:" + src.name.split("/")[-1])
187 if result is not None and existing.get(result.name) is None:
188 return result
189 return None
190
Dan Albert8b72aef2015-03-23 19:13:21 -0700191class ItemSet(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700192 def __init__(self, partition, fs_config):
193 self.partition = partition
194 self.fs_config = fs_config
195 self.ITEMS = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700196
Dan Albert8b72aef2015-03-23 19:13:21 -0700197 def Get(self, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700198 if name not in self.ITEMS:
Dan Albert8b72aef2015-03-23 19:13:21 -0700199 self.ITEMS[name] = Item(self, name, is_dir=is_dir)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700200 return self.ITEMS[name]
Doug Zongkereef39442009-04-02 12:14:19 -0700201
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700202 def GetMetadata(self, input_zip):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700203 # The target_files contains a record of what the uid,
204 # gid, and mode are supposed to be.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700205 output = input_zip.read(self.fs_config)
Doug Zongkereef39442009-04-02 12:14:19 -0700206
207 for line in output.split("\n"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700208 if not line:
209 continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700210 columns = line.split()
211 name, uid, gid, mode = columns[:4]
212 selabel = None
213 capabilities = None
214
215 # After the first 4 columns, there are a series of key=value
216 # pairs. Extract out the fields we care about.
217 for element in columns[4:]:
218 key, value = element.split("=")
219 if key == "selabel":
220 selabel = value
221 if key == "capabilities":
222 capabilities = value
223
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700224 i = self.ITEMS.get(name, None)
Doug Zongker283e2a12010-03-15 17:52:32 -0700225 if i is not None:
226 i.uid = int(uid)
227 i.gid = int(gid)
228 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700229 i.selabel = selabel
230 i.capabilities = capabilities
Dan Albert8b72aef2015-03-23 19:13:21 -0700231 if i.is_dir:
Doug Zongker283e2a12010-03-15 17:52:32 -0700232 i.children.sort(key=lambda i: i.name)
233
234 # set metadata for the files generated by this script.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700235 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700236 if i:
237 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700238 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700239 if i:
240 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700241
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700242
Dan Albert8b72aef2015-03-23 19:13:21 -0700243class Item(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700244 """Items represent the metadata (user, group, mode) of files and
245 directories in the system image."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700246 def __init__(self, itemset, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700247 self.itemset = itemset
248 self.name = name
249 self.uid = None
250 self.gid = None
251 self.mode = None
252 self.selabel = None
253 self.capabilities = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700254 self.is_dir = is_dir
255 self.descendants = None
256 self.best_subtree = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700257
258 if name:
Dan Albert8b72aef2015-03-23 19:13:21 -0700259 self.parent = itemset.Get(os.path.dirname(name), is_dir=True)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700260 self.parent.children.append(self)
261 else:
262 self.parent = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700263 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700264 self.children = []
265
266 def Dump(self, indent=0):
267 if self.uid is not None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700268 print "%s%s %d %d %o" % (
269 " " * indent, self.name, self.uid, self.gid, self.mode)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700270 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700271 print "%s%s %s %s %s" % (
272 " " * indent, self.name, self.uid, self.gid, self.mode)
273 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700274 print "%s%s" % (" "*indent, self.descendants)
275 print "%s%s" % (" "*indent, self.best_subtree)
276 for i in self.children:
277 i.Dump(indent=indent+1)
278
Doug Zongkereef39442009-04-02 12:14:19 -0700279 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700280 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
Dan Albert8b72aef2015-03-23 19:13:21 -0700281 all children and determine the best strategy for using set_perm_recursive
282 and set_perm to correctly chown/chmod all the files to their desired
Doug Zongkereef39442009-04-02 12:14:19 -0700283 values. Recursively calls itself for all descendants.
284
Dan Albert8b72aef2015-03-23 19:13:21 -0700285 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count}
286 counting up all descendants of this node. (dmode or fmode may be None.)
287 Also sets the best_subtree of each directory Item to the (uid, gid, dmode,
288 fmode, selabel, capabilities) tuple that will match the most descendants of
289 that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700290 """
291
Dan Albert8b72aef2015-03-23 19:13:21 -0700292 assert self.is_dir
293 key = (self.uid, self.gid, self.mode, None, self.selabel,
294 self.capabilities)
295 self.descendants = {key: 1}
296 d = self.descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700297 for i in self.children:
Dan Albert8b72aef2015-03-23 19:13:21 -0700298 if i.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700299 for k, v in i.CountChildMetadata().iteritems():
300 d[k] = d.get(k, 0) + v
301 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700302 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700303 d[k] = d.get(k, 0) + 1
304
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700305 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
306 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700307
308 # First, find the (uid, gid) pair that matches the most
309 # descendants.
310 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700311 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700312 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
313 ug = MostPopularKey(ug, (0, 0))
314
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700315 # Now find the dmode, fmode, selabel, and capabilities that match
316 # the most descendants with that (uid, gid), and choose those.
Dan Albert8b72aef2015-03-23 19:13:21 -0700317 best_dmode = (0, 0o755)
318 best_fmode = (0, 0o644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700319 best_selabel = (0, None)
320 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700321 for k, count in d.iteritems():
Dan Albert8b72aef2015-03-23 19:13:21 -0700322 if k[:2] != ug:
323 continue
324 if k[2] is not None and count >= best_dmode[0]:
325 best_dmode = (count, k[2])
326 if k[3] is not None and count >= best_fmode[0]:
327 best_fmode = (count, k[3])
328 if k[4] is not None and count >= best_selabel[0]:
329 best_selabel = (count, k[4])
330 if k[5] is not None and count >= best_capabilities[0]:
331 best_capabilities = (count, k[5])
332 self.best_subtree = ug + (
333 best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700334
335 return d
336
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700337 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700338 """Append set_perm/set_perm_recursive commands to 'script' to
339 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700340 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700341
342 self.CountChildMetadata()
343
344 def recurse(item, current):
Dan Albert8b72aef2015-03-23 19:13:21 -0700345 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple
346 # that the current item (and all its children) have already been set to.
347 # We only need to issue set_perm/set_perm_recursive commands if we're
Doug Zongkereef39442009-04-02 12:14:19 -0700348 # supposed to be something different.
Dan Albert8b72aef2015-03-23 19:13:21 -0700349 if item.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700350 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700351 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700352 current = item.best_subtree
353
354 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700355 item.mode != current[2] or item.selabel != current[4] or \
356 item.capabilities != current[5]:
357 script.SetPermissions("/"+item.name, item.uid, item.gid,
358 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700359
360 for i in item.children:
361 recurse(i, current)
362 else:
363 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700364 item.mode != current[3] or item.selabel != current[4] or \
365 item.capabilities != current[5]:
366 script.SetPermissions("/"+item.name, item.uid, item.gid,
367 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700368
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700369 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700370
371
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700372def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
373 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700374 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800375 list of symlinks. output_zip may be None, in which case the copy is
376 skipped (but the other side effects still happen). substitute is an
377 optional dict of {output filename: contents} to be output instead of
378 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700379 """
380
381 symlinks = []
382
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700383 partition = itemset.partition
384
Doug Zongkereef39442009-04-02 12:14:19 -0700385 for info in input_zip.infolist():
Tao Baoeaf885b2015-03-23 16:01:17 -0700386 prefix = partition.upper() + "/"
387 if info.filename.startswith(prefix):
388 basefilename = info.filename[len(prefix):]
Doug Zongkereef39442009-04-02 12:14:19 -0700389 if IsSymlink(info):
390 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700391 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700392 else:
Tao Baof3282b42015-04-01 11:21:55 -0700393 import copy
Doug Zongkereef39442009-04-02 12:14:19 -0700394 info2 = copy.copy(info)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700395 fn = info2.filename = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700396 if substitute and fn in substitute and substitute[fn] is None:
397 continue
398 if output_zip is not None:
399 if substitute and fn in substitute:
400 data = substitute[fn]
401 else:
402 data = input_zip.read(info.filename)
Tao Baof3282b42015-04-01 11:21:55 -0700403 common.ZipWriteStr(output_zip, info2, data)
Doug Zongkereef39442009-04-02 12:14:19 -0700404 if fn.endswith("/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700405 itemset.Get(fn[:-1], is_dir=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700406 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700407 itemset.Get(fn)
Doug Zongkereef39442009-04-02 12:14:19 -0700408
409 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800410 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700411
412
Doug Zongkereef39442009-04-02 12:14:19 -0700413def SignOutput(temp_zip_name, output_zip_name):
414 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
415 pw = key_passwords[OPTIONS.package_key]
416
Doug Zongker951495f2009-08-14 12:44:19 -0700417 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
418 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700419
420
Dan Albert8b72aef2015-03-23 19:13:21 -0700421def AppendAssertions(script, info_dict, oem_dict=None):
Michael Runge6e836112014-04-15 17:40:21 -0700422 oem_props = info_dict.get("oem_fingerprint_properties")
Michael Runge560569a2014-09-18 15:12:45 -0700423 if oem_props is None or len(oem_props) == 0:
Michael Runge6e836112014-04-15 17:40:21 -0700424 device = GetBuildProp("ro.product.device", info_dict)
425 script.AssertDevice(device)
426 else:
427 if oem_dict is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700428 raise common.ExternalError(
429 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700430 for prop in oem_props.split():
431 if oem_dict.get(prop) is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700432 raise common.ExternalError(
433 "The OEM file is missing the property %s" % prop)
Michael Runge6e836112014-04-15 17:40:21 -0700434 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700435
Doug Zongkereef39442009-04-02 12:14:19 -0700436
Doug Zongkerc9253822014-02-04 12:17:58 -0800437def HasRecoveryPatch(target_files_zip):
438 try:
439 target_files_zip.getinfo("SYSTEM/recovery-from-boot.p")
440 return True
441 except KeyError:
442 return False
Doug Zongker73ef8252009-07-23 15:12:53 -0700443
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700444def HasVendorPartition(target_files_zip):
445 try:
446 target_files_zip.getinfo("VENDOR/")
447 return True
448 except KeyError:
449 return False
450
Michael Runge6e836112014-04-15 17:40:21 -0700451def GetOemProperty(name, oem_props, oem_dict, info_dict):
452 if oem_props is not None and name in oem_props:
453 return oem_dict[name]
454 return GetBuildProp(name, info_dict)
455
456
457def CalculateFingerprint(oem_props, oem_dict, info_dict):
458 if oem_props is None:
459 return GetBuildProp("ro.build.fingerprint", info_dict)
460 return "%s/%s/%s:%s" % (
Dan Albert8b72aef2015-03-23 19:13:21 -0700461 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
462 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
463 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
464 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700465
Doug Zongkerfc44a512014-08-26 13:10:25 -0700466
Doug Zongker3c84f562014-07-31 11:06:30 -0700467def GetImage(which, tmpdir, info_dict):
Doug Zongkerfc44a512014-08-26 13:10:25 -0700468 # Return an image object (suitable for passing to BlockImageDiff)
469 # for the 'which' partition (most be "system" or "vendor"). If a
470 # prebuilt image and file map are found in tmpdir they are used,
471 # otherwise they are reconstructed from the individual files.
Doug Zongker3c84f562014-07-31 11:06:30 -0700472
473 assert which in ("system", "vendor")
474
475 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700476 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
477 if os.path.exists(path) and os.path.exists(mappath):
Doug Zongker3c84f562014-07-31 11:06:30 -0700478 print "using %s.img from target-files" % (which,)
Doug Zongker3c84f562014-07-31 11:06:30 -0700479 # This is a 'new' target-files, which already has the image in it.
Doug Zongker3c84f562014-07-31 11:06:30 -0700480
481 else:
482 print "building %s.img from target-files" % (which,)
483
484 # This is an 'old' target-files, which does not contain images
485 # already built. Build them.
486
Doug Zongkerfc44a512014-08-26 13:10:25 -0700487 mappath = tempfile.mkstemp()[1]
488 OPTIONS.tempfiles.append(mappath)
489
Doug Zongker3c84f562014-07-31 11:06:30 -0700490 import add_img_to_target_files
491 if which == "system":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700492 path = add_img_to_target_files.BuildSystem(
493 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700494 elif which == "vendor":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700495 path = add_img_to_target_files.BuildVendor(
496 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700497
Tao Bao5ece99d2015-05-12 11:42:31 -0700498 # Bug: http://b/20939131
499 # In ext4 filesystems, block 0 might be changed even being mounted
500 # R/O. We add it to clobbered_blocks so that it will be written to the
501 # target unconditionally. Note that they are still part of care_map.
502 clobbered_blocks = "0"
503
504 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700505
506
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700507def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700508 # TODO: how to determine this? We don't know what version it will
Tao Baobebd3cf2015-06-22 19:17:41 -0700509 # be installed on top of. For now, we expect the API just won't
510 # change very often. Similarly for fstab, it might have changed
511 # in the target build.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700512 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700513
Michael Runge6e836112014-04-15 17:40:21 -0700514 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700515 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700516 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700517 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700518 if OPTIONS.oem_source is None:
519 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700520 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700521 oem_dict = common.LoadDictionaryFromLines(
522 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -0700523
Dan Albert8b72aef2015-03-23 19:13:21 -0700524 metadata = {
525 "post-build": CalculateFingerprint(oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700526 OPTIONS.info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700527 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
528 OPTIONS.info_dict),
529 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
530 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700531
Doug Zongker05d3dea2009-06-22 11:32:31 -0700532 device_specific = common.DeviceSpecificParams(
533 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700534 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700535 output_zip=output_zip,
536 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700537 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700538 metadata=metadata,
539 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700540
Doug Zongkerc9253822014-02-04 12:17:58 -0800541 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800542 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800543
Doug Zongker962069c2009-04-23 11:41:58 -0700544 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700545 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700546 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
547 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700548
Michael Runge6e836112014-04-15 17:40:21 -0700549 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700550 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800551
552 # Two-step package strategy (in chronological order, which is *not*
553 # the order in which the generated script has things):
554 #
555 # if stage is not "2/3" or "3/3":
556 # write recovery image to boot partition
557 # set stage to "2/3"
558 # reboot to boot partition and restart recovery
559 # else if stage is "2/3":
560 # write recovery image to recovery partition
561 # set stage to "3/3"
562 # reboot to recovery partition and restart recovery
563 # else:
564 # (stage must be "3/3")
565 # set stage to ""
566 # do normal full package installation:
567 # wipe and install system, boot image, etc.
568 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700569 # complete script normally
570 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800571
572 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
573 OPTIONS.input_tmp, "RECOVERY")
574 if OPTIONS.two_step:
575 if not OPTIONS.info_dict.get("multistage_support", None):
576 assert False, "two-step packages not supported by this build"
577 fs = OPTIONS.info_dict["fstab"]["/misc"]
578 assert fs.fs_type.upper() == "EMMC", \
579 "two-step packages only supported on devices with EMMC /misc partitions"
580 bcb_dev = {"bcb_dev": fs.device}
581 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
582 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700583if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800584""" % bcb_dev)
585 script.WriteRawImage("/recovery", "recovery.img")
586 script.AppendExtra("""
587set_stage("%(bcb_dev)s", "3/3");
588reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700589else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800590""" % bcb_dev)
591
Tao Bao6c55a8a2015-04-08 15:30:27 -0700592 # Dump fingerprints
593 script.Print("Target: %s" % CalculateFingerprint(
594 oem_props, oem_dict, OPTIONS.info_dict))
595
Doug Zongkere5ff5902012-01-17 10:55:37 -0800596 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700597
Doug Zongker01ce19c2014-02-04 13:48:15 -0800598 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700599
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700600 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800601 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700602 if HasVendorPartition(input_zip):
603 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700604
Kenny Rootf32dc712012-04-08 10:42:34 -0700605 if "selinux_fc" in OPTIONS.info_dict:
606 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500607
Michael Runge7cd99ba2014-10-22 17:21:48 -0700608 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
609
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700610 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700611 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800612
Doug Zongker26e66192014-02-20 13:22:07 -0800613 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700614 # Full OTA is done as an "incremental" against an empty source
615 # image. This has the effect of writing new data from the package
616 # to the entire partition, but lets us reuse the updater code that
617 # writes incrementals to do it.
618 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
619 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700620 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700621 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800622 else:
623 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700624 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800625 if not has_recovery_patch:
626 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800627 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700628
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700629 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800630 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700631
Doug Zongker55d93282011-01-25 17:03:34 -0800632 boot_img = common.GetBootableImage("boot.img", "boot.img",
633 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800634
Doug Zongker91a99c22014-05-09 13:15:01 -0700635 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800636 def output_sink(fn, data):
637 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700638 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800639
640 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
641 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700642
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700643 system_items.GetMetadata(input_zip)
644 system_items.Get("system").SetPermissions(script)
645
646 if HasVendorPartition(input_zip):
647 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
648 script.ShowProgress(0.1, 0)
649
650 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700651 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
652 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700653 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700654 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700655 else:
656 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700657 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700658 script.UnpackPackageDir("vendor", "/vendor")
659
660 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
661 script.MakeSymlinks(symlinks)
662
663 vendor_items.GetMetadata(input_zip)
664 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700665
Doug Zongker37974732010-09-16 17:44:38 -0700666 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700667 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700668
Doug Zongker01ce19c2014-02-04 13:48:15 -0800669 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700670 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700671
Doug Zongker01ce19c2014-02-04 13:48:15 -0800672 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700673 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700674
Doug Zongker1c390a22009-05-14 19:06:36 -0700675 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700676 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700677
Doug Zongker14833602010-02-02 13:12:04 -0800678 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800679
Doug Zongker922206e2014-03-04 13:16:24 -0800680 if OPTIONS.wipe_user_data:
681 script.ShowProgress(0.1, 10)
682 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700683
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800684 if OPTIONS.two_step:
685 script.AppendExtra("""
686set_stage("%(bcb_dev)s", "");
687""" % bcb_dev)
688 script.AppendExtra("else\n")
689 script.WriteRawImage("/boot", "recovery.img")
690 script.AppendExtra("""
691set_stage("%(bcb_dev)s", "2/3");
692reboot_now("%(bcb_dev)s", "");
693endif;
694endif;
695""" % bcb_dev)
Tao Bao177c6102016-02-23 11:38:39 -0800696
697 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800698 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700699 WriteMetadata(metadata, output_zip)
700
Doug Zongkerfc44a512014-08-26 13:10:25 -0700701
Dan Albert8e0178d2015-01-27 15:53:15 -0800702def WritePolicyConfig(file_name, output_zip):
703 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500704
Doug Zongker2ea21062010-04-28 16:05:21 -0700705
706def WriteMetadata(metadata, output_zip):
707 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
708 "".join(["%s=%s\n" % kv
709 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700710
Doug Zongkerfc44a512014-08-26 13:10:25 -0700711
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700712def LoadPartitionFiles(z, partition):
713 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700714 ZipFile, and return a dict of {filename: File object}."""
715 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700716 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700717 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700718 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700719 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700720 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700721 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700722 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800723 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700724
725
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700726def GetBuildProp(prop, info_dict):
727 """Return the fingerprint of the build of a given target-files info_dict."""
728 try:
729 return info_dict.get("build.prop", {})[prop]
730 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700731 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700732
Doug Zongkerfc44a512014-08-26 13:10:25 -0700733
Michael Runge4038aa82013-12-13 18:06:28 -0800734def AddToKnownPaths(filename, known_paths):
735 if filename[-1] == "/":
736 return
737 dirs = filename.split("/")[:-1]
738 while len(dirs) > 0:
739 path = "/".join(dirs)
740 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700741 break
Michael Runge4038aa82013-12-13 18:06:28 -0800742 known_paths.add(path)
743 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700744
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700745
Geremy Condra36bd3652014-02-06 19:45:10 -0800746def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
747 source_version = OPTIONS.source_info_dict["recovery_api_version"]
748 target_version = OPTIONS.target_info_dict["recovery_api_version"]
749
750 if source_version == 0:
751 print ("WARNING: generating edify script for a source that "
752 "can't install it.")
Tao Baobebd3cf2015-06-22 19:17:41 -0700753 script = edify_generator.EdifyGenerator(
754 source_version, OPTIONS.target_info_dict,
755 fstab=OPTIONS.source_info_dict["fstab"])
Geremy Condra36bd3652014-02-06 19:45:10 -0800756
Tao Bao177c6102016-02-23 11:38:39 -0800757 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
758 recovery_mount_options = OPTIONS.source_info_dict.get(
759 "recovery_mount_options")
760 oem_dict = None
761 if oem_props is not None and len(oem_props) > 0:
762 if OPTIONS.oem_source is None:
763 raise common.ExternalError("OEM source required for this build")
764 script.Mount("/oem", recovery_mount_options)
765 oem_dict = common.LoadDictionaryFromLines(
766 open(OPTIONS.oem_source).readlines())
767
Dan Albert8b72aef2015-03-23 19:13:21 -0700768 metadata = {
Tao Bao177c6102016-02-23 11:38:39 -0800769 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
770 OPTIONS.source_info_dict),
771 "ota-type": "BLOCK",
Dan Albert8b72aef2015-03-23 19:13:21 -0700772 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800773
Tao Bao177c6102016-02-23 11:38:39 -0800774 post_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict)
775 pre_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
776 is_downgrade = long(post_timestamp) < long(pre_timestamp)
777
778 if OPTIONS.downgrade:
779 metadata["ota-downgrade"] = "yes"
780 if not is_downgrade:
781 raise RuntimeError("--downgrade specified but no downgrade detected: "
782 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
783 else:
784 if is_downgrade:
785 # Non-fatal here to allow generating such a package which may require
786 # manual work to adjust the post-timestamp. A legit use case is that we
787 # cut a new build C (after having A and B), but want to enfore the
788 # update path of A -> C -> B. Specifying --downgrade may not help since
789 # that would enforce a data wipe for C -> B update.
790 print("\nWARNING: downgrade detected: pre: %s, post: %s.\n"
791 "The package may not be deployed properly. "
792 "Try --downgrade?\n" % (pre_timestamp, post_timestamp))
793 metadata["post-timestamp"] = post_timestamp
794
Geremy Condra36bd3652014-02-06 19:45:10 -0800795 device_specific = common.DeviceSpecificParams(
796 source_zip=source_zip,
797 source_version=source_version,
798 target_zip=target_zip,
799 target_version=target_version,
800 output_zip=output_zip,
801 script=script,
802 metadata=metadata,
Tao Baoe09359a2015-10-13 16:37:12 -0700803 info_dict=OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800804
Tao Bao177c6102016-02-23 11:38:39 -0800805 target_fp = CalculateFingerprint(oem_props, oem_dict,
806 OPTIONS.target_info_dict)
807 source_fp = CalculateFingerprint(oem_props, oem_dict,
808 OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800809 metadata["pre-build"] = source_fp
810 metadata["post-build"] = target_fp
811
812 source_boot = common.GetBootableImage(
813 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
814 OPTIONS.source_info_dict)
815 target_boot = common.GetBootableImage(
816 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
817 updating_boot = (not OPTIONS.two_step and
818 (source_boot.data != target_boot.data))
819
Geremy Condra36bd3652014-02-06 19:45:10 -0800820 target_recovery = common.GetBootableImage(
821 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800822
Doug Zongkerfc44a512014-08-26 13:10:25 -0700823 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
824 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700825
826 blockimgdiff_version = 1
827 if OPTIONS.info_dict:
828 blockimgdiff_version = max(
829 int(i) for i in
830 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
831
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700832 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700833 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700834
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700835 if HasVendorPartition(target_zip):
836 if not HasVendorPartition(source_zip):
837 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700838 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
839 OPTIONS.source_info_dict)
840 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
841 OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700842 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700843 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700844 else:
845 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800846
Michael Rungec6e3afd2014-05-05 11:55:47 -0700847 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800848 device_specific.IncrementalOTA_Assertions()
849
850 # Two-step incremental package strategy (in chronological order,
851 # which is *not* the order in which the generated script has
852 # things):
853 #
854 # if stage is not "2/3" or "3/3":
855 # do verification on current system
856 # write recovery image to boot partition
857 # set stage to "2/3"
858 # reboot to boot partition and restart recovery
859 # else if stage is "2/3":
860 # write recovery image to recovery partition
861 # set stage to "3/3"
862 # reboot to recovery partition and restart recovery
863 # else:
864 # (stage must be "3/3")
865 # perform update:
866 # patch system files, etc.
867 # force full install of new boot image
868 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700869 # complete script normally
870 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800871
872 if OPTIONS.two_step:
Tao Baocce673b2015-07-29 14:09:23 -0700873 if not OPTIONS.source_info_dict.get("multistage_support", None):
Geremy Condra36bd3652014-02-06 19:45:10 -0800874 assert False, "two-step packages not supported by this build"
Tao Baocce673b2015-07-29 14:09:23 -0700875 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Geremy Condra36bd3652014-02-06 19:45:10 -0800876 assert fs.fs_type.upper() == "EMMC", \
877 "two-step packages only supported on devices with EMMC /misc partitions"
878 bcb_dev = {"bcb_dev": fs.device}
879 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
880 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700881if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800882""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -0700883 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800884 script.WriteRawImage("/recovery", "recovery.img")
885 script.AppendExtra("""
886set_stage("%(bcb_dev)s", "3/3");
887reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700888else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800889""" % bcb_dev)
890
Tao Bao6c55a8a2015-04-08 15:30:27 -0700891 # Dump fingerprints
892 script.Print("Source: %s" % CalculateFingerprint(
893 oem_props, oem_dict, OPTIONS.source_info_dict))
894 script.Print("Target: %s" % CalculateFingerprint(
895 oem_props, oem_dict, OPTIONS.target_info_dict))
896
Geremy Condra36bd3652014-02-06 19:45:10 -0800897 script.Print("Verifying current system...")
898
899 device_specific.IncrementalOTA_VerifyBegin()
900
Michael Rungec6e3afd2014-05-05 11:55:47 -0700901 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700902 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
903 # patching on a device that's already on the target build will damage the
904 # system. Because operations like move don't check the block state, they
905 # always apply the changes unconditionally.
906 if blockimgdiff_version <= 2:
907 script.AssertSomeFingerprint(source_fp)
908 else:
909 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700910 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700911 if blockimgdiff_version <= 2:
912 script.AssertSomeThumbprint(
913 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
914 else:
915 script.AssertSomeThumbprint(
916 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
917 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800918
919 if updating_boot:
Tao Baocce673b2015-07-29 14:09:23 -0700920 boot_type, boot_device = common.GetTypeAndDevice(
921 "/boot", OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800922 d = common.Difference(target_boot, source_boot)
923 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700924 if d is None:
925 include_full_boot = True
926 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
927 else:
928 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800929
Doug Zongkerf8340082014-08-05 10:39:37 -0700930 print "boot target: %d source: %d diff: %d" % (
931 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800932
Doug Zongkerf8340082014-08-05 10:39:37 -0700933 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800934
Doug Zongkerf8340082014-08-05 10:39:37 -0700935 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
936 (boot_type, boot_device,
937 source_boot.size, source_boot.sha1,
938 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800939
940 device_specific.IncrementalOTA_VerifyEnd()
941
942 if OPTIONS.two_step:
943 script.WriteRawImage("/boot", "recovery.img")
944 script.AppendExtra("""
945set_stage("%(bcb_dev)s", "2/3");
946reboot_now("%(bcb_dev)s", "");
947else
948""" % bcb_dev)
949
Jesse Zhao75bcea02015-01-06 10:59:53 -0800950 # Verify the existing partitions.
951 system_diff.WriteVerifyScript(script)
952 if vendor_diff:
953 vendor_diff.WriteVerifyScript(script)
954
Geremy Condra36bd3652014-02-06 19:45:10 -0800955 script.Comment("---- start making changes here ----")
956
957 device_specific.IncrementalOTA_InstallBegin()
958
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700959 system_diff.WriteScript(script, output_zip,
960 progress=0.8 if vendor_diff else 0.9)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700961 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700962 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800963
964 if OPTIONS.two_step:
965 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
966 script.WriteRawImage("/boot", "boot.img")
967 print "writing full boot image (forced by two-step mode)"
968
969 if not OPTIONS.two_step:
970 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700971 if include_full_boot:
972 print "boot image changed; including full."
973 script.Print("Installing boot image...")
974 script.WriteRawImage("/boot", "boot.img")
975 else:
976 # Produce the boot image by applying a patch to the current
977 # contents of the boot partition, and write it back to the
978 # partition.
979 print "boot image changed; including patch."
980 script.Print("Patching boot image...")
981 script.ShowProgress(0.1, 10)
982 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
983 % (boot_type, boot_device,
984 source_boot.size, source_boot.sha1,
985 target_boot.size, target_boot.sha1),
986 "-",
987 target_boot.size, target_boot.sha1,
988 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800989 else:
990 print "boot image unchanged; skipping."
991
992 # Do device-specific installation (eg, write radio image).
993 device_specific.IncrementalOTA_InstallEnd()
994
995 if OPTIONS.extra_script is not None:
996 script.AppendExtra(OPTIONS.extra_script)
997
Doug Zongker922206e2014-03-04 13:16:24 -0800998 if OPTIONS.wipe_user_data:
999 script.Print("Erasing user data...")
1000 script.FormatPartition("/data")
Tao Bao177c6102016-02-23 11:38:39 -08001001 metadata["ota-wipe"] = "yes"
Doug Zongker922206e2014-03-04 13:16:24 -08001002
Geremy Condra36bd3652014-02-06 19:45:10 -08001003 if OPTIONS.two_step:
1004 script.AppendExtra("""
1005set_stage("%(bcb_dev)s", "");
1006endif;
1007endif;
1008""" % bcb_dev)
1009
1010 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -08001011 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -08001012 WriteMetadata(metadata, output_zip)
1013
Doug Zongker32b527d2014-03-04 10:03:02 -08001014
Dan Albert8b72aef2015-03-23 19:13:21 -07001015class FileDifference(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001016 def __init__(self, partition, source_zip, target_zip, output_zip):
Dan Albert8b72aef2015-03-23 19:13:21 -07001017 self.deferred_patch_list = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001018 print "Loading target..."
1019 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
1020 print "Loading source..."
1021 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
1022
1023 self.verbatim_targets = verbatim_targets = []
1024 self.patch_list = patch_list = []
1025 diffs = []
1026 self.renames = renames = {}
1027 known_paths = set()
1028 largest_source_size = 0
1029
1030 matching_file_cache = {}
1031 for fn, sf in source_data.items():
1032 assert fn == sf.name
1033 matching_file_cache["path:" + fn] = sf
1034 if fn in target_data.keys():
1035 AddToKnownPaths(fn, known_paths)
1036 # Only allow eligibility for filename/sha matching
1037 # if there isn't a perfect path match.
1038 if target_data.get(sf.name) is None:
1039 matching_file_cache["file:" + fn.split("/")[-1]] = sf
1040 matching_file_cache["sha:" + sf.sha1] = sf
1041
1042 for fn in sorted(target_data.keys()):
1043 tf = target_data[fn]
1044 assert fn == tf.name
1045 sf = ClosestFileMatch(tf, matching_file_cache, renames)
1046 if sf is not None and sf.name != tf.name:
1047 print "File has moved from " + sf.name + " to " + tf.name
1048 renames[sf.name] = tf
1049
1050 if sf is None or fn in OPTIONS.require_verbatim:
1051 # This file should be included verbatim
1052 if fn in OPTIONS.prohibit_verbatim:
1053 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
1054 print "send", fn, "verbatim"
1055 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001056 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001057 if fn in target_data.keys():
1058 AddToKnownPaths(fn, known_paths)
1059 elif tf.sha1 != sf.sha1:
1060 # File is different; consider sending as a patch
1061 diffs.append(common.Difference(tf, sf))
1062 else:
1063 # Target file data identical to source (may still be renamed)
1064 pass
1065
1066 common.ComputeDifferences(diffs)
1067
1068 for diff in diffs:
1069 tf, sf, d = diff.GetPatch()
1070 path = "/".join(tf.name.split("/")[:-1])
1071 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1072 path not in known_paths:
1073 # patch is almost as big as the file; don't bother patching
1074 # or a patch + rename cannot take place due to the target
1075 # directory not existing
1076 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001077 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001078 if sf.name in renames:
1079 del renames[sf.name]
1080 AddToKnownPaths(tf.name, known_paths)
1081 else:
1082 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1083 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1084 largest_source_size = max(largest_source_size, sf.size)
1085
1086 self.largest_source_size = largest_source_size
1087
1088 def EmitVerification(self, script):
1089 so_far = 0
Dan Albert8b72aef2015-03-23 19:13:21 -07001090 for tf, sf, _, _ in self.patch_list:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001091 if tf.name != sf.name:
1092 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1093 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1094 so_far += sf.size
1095 return so_far
1096
Michael Runge63f01de2014-10-28 19:24:19 -07001097 def EmitExplicitTargetVerification(self, script):
Dan Albert8b72aef2015-03-23 19:13:21 -07001098 for fn, _, sha1 in self.verbatim_targets:
1099 if fn[-1] != "/":
Michael Runge63f01de2014-10-28 19:24:19 -07001100 script.FileCheck("/"+fn, sha1)
1101 for tf, _, _, _ in self.patch_list:
1102 script.FileCheck(tf.name, tf.sha1)
1103
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001104 def RemoveUnneededFiles(self, script, extras=()):
Dan Albert8b72aef2015-03-23 19:13:21 -07001105 script.DeleteFiles(
1106 ["/" + i[0] for i in self.verbatim_targets] +
1107 ["/" + i for i in sorted(self.source_data)
1108 if i not in self.target_data and i not in self.renames] +
1109 list(extras))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001110
1111 def TotalPatchSize(self):
1112 return sum(i[1].size for i in self.patch_list)
1113
1114 def EmitPatches(self, script, total_patch_size, so_far):
1115 self.deferred_patch_list = deferred_patch_list = []
1116 for item in self.patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001117 tf, sf, _, _ = item
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001118 if tf.name == "system/build.prop":
1119 deferred_patch_list.append(item)
1120 continue
Dan Albert8b72aef2015-03-23 19:13:21 -07001121 if sf.name != tf.name:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001122 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
Dan Albert8b72aef2015-03-23 19:13:21 -07001123 script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1,
1124 "patch/" + sf.name + ".p")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001125 so_far += tf.size
1126 script.SetProgress(so_far / total_patch_size)
1127 return so_far
1128
1129 def EmitDeferredPatches(self, script):
1130 for item in self.deferred_patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001131 tf, sf, _, _ = item
1132 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1,
1133 "patch/" + sf.name + ".p")
1134 script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001135
1136 def EmitRenames(self, script):
1137 if len(self.renames) > 0:
1138 script.Print("Renaming files...")
1139 for src, tgt in self.renames.iteritems():
1140 print "Renaming " + src + " to " + tgt.name
1141 script.RenameFile(src, tgt.name)
1142
1143
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001144def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001145 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1146 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1147
Doug Zongker26e66192014-02-20 13:22:07 -08001148 if (OPTIONS.block_based and
1149 target_has_recovery_patch and
1150 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001151 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1152
Doug Zongker37974732010-09-16 17:44:38 -07001153 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1154 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001155
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001156 if source_version == 0:
1157 print ("WARNING: generating edify script for a source that "
1158 "can't install it.")
Tao Baobebd3cf2015-06-22 19:17:41 -07001159 script = edify_generator.EdifyGenerator(
1160 source_version, OPTIONS.target_info_dict,
1161 fstab=OPTIONS.source_info_dict["fstab"])
Doug Zongkereef39442009-04-02 12:14:19 -07001162
Michael Runge6e836112014-04-15 17:40:21 -07001163 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Tao Baobebd3cf2015-06-22 19:17:41 -07001164 recovery_mount_options = OPTIONS.source_info_dict.get(
1165 "recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001166 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001167 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001168 if OPTIONS.oem_source is None:
1169 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001170 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001171 oem_dict = common.LoadDictionaryFromLines(
1172 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001173
Dan Albert8b72aef2015-03-23 19:13:21 -07001174 metadata = {
1175 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1176 OPTIONS.source_info_dict),
Tao Bao177c6102016-02-23 11:38:39 -08001177 "ota-type": "FILE",
Dan Albert8b72aef2015-03-23 19:13:21 -07001178 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001179
Tao Bao177c6102016-02-23 11:38:39 -08001180 post_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict)
1181 pre_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
1182 is_downgrade = long(post_timestamp) < long(pre_timestamp)
1183
1184 if OPTIONS.downgrade:
1185 metadata["ota-downgrade"] = "yes"
1186 if not is_downgrade:
1187 raise RuntimeError("--downgrade specified but no downgrade detected: "
1188 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
1189 else:
1190 if is_downgrade:
1191 # Non-fatal here to allow generating such a package which may require
1192 # manual work to adjust the post-timestamp. A legit use case is that we
1193 # cut a new build C (after having A and B), but want to enfore the
1194 # update path of A -> C -> B. Specifying --downgrade may not help since
1195 # that would enforce a data wipe for C -> B update.
1196 print("\nWARNING: downgrade detected: pre: %s, post: %s.\n"
1197 "The package may not be deployed properly. "
1198 "Try --downgrade?\n" % (pre_timestamp, post_timestamp))
1199 metadata["post-timestamp"] = post_timestamp
1200
Doug Zongker05d3dea2009-06-22 11:32:31 -07001201 device_specific = common.DeviceSpecificParams(
1202 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001203 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001204 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001205 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001206 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001207 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001208 metadata=metadata,
Tao Baoe09359a2015-10-13 16:37:12 -07001209 info_dict=OPTIONS.source_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001210
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001211 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001212 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001213 if HasVendorPartition(target_zip):
1214 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001215 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001216 else:
1217 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001218
Dan Albert8b72aef2015-03-23 19:13:21 -07001219 target_fp = CalculateFingerprint(oem_props, oem_dict,
1220 OPTIONS.target_info_dict)
1221 source_fp = CalculateFingerprint(oem_props, oem_dict,
1222 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001223
1224 if oem_props is None:
1225 script.AssertSomeFingerprint(source_fp, target_fp)
1226 else:
1227 script.AssertSomeThumbprint(
1228 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1229 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1230
Doug Zongker2ea21062010-04-28 16:05:21 -07001231 metadata["pre-build"] = source_fp
1232 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001233
Doug Zongker55d93282011-01-25 17:03:34 -08001234 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001235 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1236 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001237 target_boot = common.GetBootableImage(
1238 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001239 updating_boot = (not OPTIONS.two_step and
1240 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001241
Doug Zongker55d93282011-01-25 17:03:34 -08001242 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001243 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1244 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001245 target_recovery = common.GetBootableImage(
1246 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001247 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001248
Doug Zongker881dd402009-09-20 14:03:55 -07001249 # Here's how we divide up the progress bar:
1250 # 0.1 for verifying the start state (PatchCheck calls)
1251 # 0.8 for applying patches (ApplyPatch calls)
1252 # 0.1 for unpacking verbatim files, symlinking, and doing the
1253 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001254
Michael Runge6e836112014-04-15 17:40:21 -07001255 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001256 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001257
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001258 # Two-step incremental package strategy (in chronological order,
1259 # which is *not* the order in which the generated script has
1260 # things):
1261 #
1262 # if stage is not "2/3" or "3/3":
1263 # do verification on current system
1264 # write recovery image to boot partition
1265 # set stage to "2/3"
1266 # reboot to boot partition and restart recovery
1267 # else if stage is "2/3":
1268 # write recovery image to recovery partition
1269 # set stage to "3/3"
1270 # reboot to recovery partition and restart recovery
1271 # else:
1272 # (stage must be "3/3")
1273 # perform update:
1274 # patch system files, etc.
1275 # force full install of new boot image
1276 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001277 # complete script normally
1278 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001279
1280 if OPTIONS.two_step:
Tao Baocce673b2015-07-29 14:09:23 -07001281 if not OPTIONS.source_info_dict.get("multistage_support", None):
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001282 assert False, "two-step packages not supported by this build"
Tao Baocce673b2015-07-29 14:09:23 -07001283 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001284 assert fs.fs_type.upper() == "EMMC", \
1285 "two-step packages only supported on devices with EMMC /misc partitions"
1286 bcb_dev = {"bcb_dev": fs.device}
1287 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1288 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001289if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001290""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001291 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001292 script.WriteRawImage("/recovery", "recovery.img")
1293 script.AppendExtra("""
1294set_stage("%(bcb_dev)s", "3/3");
1295reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001296else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001297""" % bcb_dev)
1298
Tao Bao6c55a8a2015-04-08 15:30:27 -07001299 # Dump fingerprints
1300 script.Print("Source: %s" % (source_fp,))
1301 script.Print("Target: %s" % (target_fp,))
1302
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001303 script.Print("Verifying current system...")
1304
Doug Zongkere5ff5902012-01-17 10:55:37 -08001305 device_specific.IncrementalOTA_VerifyBegin()
1306
Doug Zongker881dd402009-09-20 14:03:55 -07001307 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001308 so_far = system_diff.EmitVerification(script)
1309 if vendor_diff:
1310 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001311
Doug Zongker5da317e2009-06-02 13:38:17 -07001312 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001313 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001314 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001315 print "boot target: %d source: %d diff: %d" % (
1316 target_boot.size, source_boot.size, len(d))
1317
Doug Zongker048e7ca2009-06-15 14:31:53 -07001318 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001319
Tao Baocce673b2015-07-29 14:09:23 -07001320 boot_type, boot_device = common.GetTypeAndDevice(
1321 "/boot", OPTIONS.source_info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001322
1323 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1324 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001325 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001326 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001327 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001328
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001329 size = []
Dan Albert8b72aef2015-03-23 19:13:21 -07001330 if system_diff.patch_list:
1331 size.append(system_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001332 if vendor_diff:
Dan Albert8b72aef2015-03-23 19:13:21 -07001333 if vendor_diff.patch_list:
1334 size.append(vendor_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001335 if size or updating_recovery or updating_boot:
1336 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001337
Doug Zongker05d3dea2009-06-22 11:32:31 -07001338 device_specific.IncrementalOTA_VerifyEnd()
1339
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001340 if OPTIONS.two_step:
1341 script.WriteRawImage("/boot", "recovery.img")
1342 script.AppendExtra("""
1343set_stage("%(bcb_dev)s", "2/3");
1344reboot_now("%(bcb_dev)s", "");
1345else
1346""" % bcb_dev)
1347
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001348 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001349
Doug Zongkere5ff5902012-01-17 10:55:37 -08001350 device_specific.IncrementalOTA_InstallBegin()
1351
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001352 if OPTIONS.two_step:
1353 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1354 script.WriteRawImage("/boot", "boot.img")
1355 print "writing full boot image (forced by two-step mode)"
1356
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001357 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001358 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1359 if vendor_diff:
1360 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001361
Doug Zongker881dd402009-09-20 14:03:55 -07001362 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001363 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1364 if vendor_diff:
1365 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001366 if updating_boot:
1367 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001368
1369 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001370 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1371 if vendor_diff:
1372 script.Print("Patching vendor files...")
1373 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001374
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001375 if not OPTIONS.two_step:
1376 if updating_boot:
1377 # Produce the boot image by applying a patch to the current
1378 # contents of the boot partition, and write it back to the
1379 # partition.
1380 script.Print("Patching boot image...")
1381 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1382 % (boot_type, boot_device,
1383 source_boot.size, source_boot.sha1,
1384 target_boot.size, target_boot.sha1),
1385 "-",
1386 target_boot.size, target_boot.sha1,
1387 source_boot.sha1, "patch/boot.img.p")
1388 so_far += target_boot.size
1389 script.SetProgress(so_far / total_patch_size)
1390 print "boot image changed; including."
1391 else:
1392 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001393
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001394 system_items = ItemSet("system", "META/filesystem_config.txt")
1395 if vendor_diff:
1396 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1397
Doug Zongkereef39442009-04-02 12:14:19 -07001398 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001399 # Recovery is generated as a patch using both the boot image
1400 # (which contains the same linux kernel as recovery) and the file
1401 # /system/etc/recovery-resource.dat (which contains all the images
1402 # used in the recovery UI) as sources. This lets us minimize the
1403 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001404 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001405 # For older builds where recovery-resource.dat is not present, we
1406 # use only the boot image as the source.
1407
Doug Zongkerc9253822014-02-04 12:17:58 -08001408 if not target_has_recovery_patch:
1409 def output_sink(fn, data):
1410 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001411 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001412
1413 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1414 target_recovery, target_boot)
1415 script.DeleteFiles(["/system/recovery-from-boot.p",
1416 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001417 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001418 else:
1419 print "recovery image unchanged; skipping."
1420
Doug Zongker881dd402009-09-20 14:03:55 -07001421 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001422
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001423 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1424 if vendor_diff:
1425 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1426
1427 temp_script = script.MakeTemporary()
1428 system_items.GetMetadata(target_zip)
1429 system_items.Get("system").SetPermissions(temp_script)
1430 if vendor_diff:
1431 vendor_items.GetMetadata(target_zip)
1432 vendor_items.Get("vendor").SetPermissions(temp_script)
1433
1434 # Note that this call will mess up the trees of Items, so make sure
1435 # we're done with them.
1436 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1437 if vendor_diff:
1438 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001439
1440 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001441 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1442
1443 # Delete all the symlinks in source that aren't in target. This
1444 # needs to happen before verbatim files are unpacked, in case a
1445 # symlink in the source is replaced by a real file in the target.
Tao Bao39c322c2015-09-02 10:28:08 -07001446
1447 # If a symlink in the source will be replaced by a regular file, we cannot
1448 # delete the symlink/file in case the package gets applied again. For such
1449 # a symlink, we prepend a sha1_check() to detect if it has been updated.
1450 # (Bug: 23646151)
1451 replaced_symlinks = dict()
1452 if system_diff:
1453 for i in system_diff.verbatim_targets:
1454 replaced_symlinks["/%s" % (i[0],)] = i[2]
1455 if vendor_diff:
1456 for i in vendor_diff.verbatim_targets:
1457 replaced_symlinks["/%s" % (i[0],)] = i[2]
1458
1459 if system_diff:
1460 for tf in system_diff.renames.values():
1461 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1462 if vendor_diff:
1463 for tf in vendor_diff.renames.values():
1464 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1465
1466 always_delete = []
1467 may_delete = []
Doug Zongkereef39442009-04-02 12:14:19 -07001468 for dest, link in source_symlinks:
1469 if link not in target_symlinks_d:
Tao Bao39c322c2015-09-02 10:28:08 -07001470 if link in replaced_symlinks:
1471 may_delete.append((link, replaced_symlinks[link]))
1472 else:
1473 always_delete.append(link)
1474 script.DeleteFiles(always_delete)
1475 script.DeleteFilesIfNotMatching(may_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001476
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001477 if system_diff.verbatim_targets:
1478 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001479 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001480 if vendor_diff and vendor_diff.verbatim_targets:
1481 script.Print("Unpacking new vendor files...")
1482 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001483
Doug Zongkerc9253822014-02-04 12:17:58 -08001484 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001485 script.Print("Unpacking new recovery...")
1486 script.UnpackPackageDir("recovery", "/system")
1487
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001488 system_diff.EmitRenames(script)
1489 if vendor_diff:
1490 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001491
Doug Zongker05d3dea2009-06-22 11:32:31 -07001492 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001493
1494 # Create all the symlinks that don't already exist, or point to
1495 # somewhere different than what we want. Delete each symlink before
1496 # creating it, since the 'symlink' command won't overwrite.
1497 to_create = []
1498 for dest, link in target_symlinks:
1499 if link in source_symlinks_d:
1500 if dest != source_symlinks_d[link]:
1501 to_create.append((dest, link))
1502 else:
1503 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001504 script.DeleteFiles([i[1] for i in to_create])
1505 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001506
1507 # Now that the symlinks are created, we can set all the
1508 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001509 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001510
Doug Zongker881dd402009-09-20 14:03:55 -07001511 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001512 device_specific.IncrementalOTA_InstallEnd()
1513
Doug Zongker1c390a22009-05-14 19:06:36 -07001514 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001515 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001516
Doug Zongkere92f15a2011-08-26 13:46:40 -07001517 # Patch the build.prop file last, so if something fails but the
1518 # device can still come up, it appears to be the old build and will
1519 # get set the OTA package again to retry.
1520 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001521 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001522
Doug Zongker922206e2014-03-04 13:16:24 -08001523 if OPTIONS.wipe_user_data:
1524 script.Print("Erasing user data...")
1525 script.FormatPartition("/data")
Tao Bao177c6102016-02-23 11:38:39 -08001526 metadata["ota-wipe"] = "yes"
Doug Zongker922206e2014-03-04 13:16:24 -08001527
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001528 if OPTIONS.two_step:
1529 script.AppendExtra("""
1530set_stage("%(bcb_dev)s", "");
1531endif;
1532endif;
1533""" % bcb_dev)
1534
Michael Runge63f01de2014-10-28 19:24:19 -07001535 if OPTIONS.verify and system_diff:
1536 script.Print("Remounting and verifying system partition files...")
1537 script.Unmount("/system")
1538 script.Mount("/system")
1539 system_diff.EmitExplicitTargetVerification(script)
1540
1541 if OPTIONS.verify and vendor_diff:
1542 script.Print("Remounting and verifying vendor partition files...")
1543 script.Unmount("/vendor")
1544 script.Mount("/vendor")
1545 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001546 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001547
Doug Zongker2ea21062010-04-28 16:05:21 -07001548 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001549
1550
1551def main(argv):
1552
1553 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001554 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001555 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001556 elif o in ("-k", "--package_key"):
1557 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001558 elif o in ("-i", "--incremental_from"):
1559 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001560 elif o == "--full_radio":
1561 OPTIONS.full_radio = True
leozwanga1fcaf82015-09-15 08:44:12 -07001562 elif o == "--full_bootloader":
1563 OPTIONS.full_bootloader = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001564 elif o in ("-w", "--wipe_user_data"):
1565 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001566 elif o in ("-n", "--no_prereq"):
1567 OPTIONS.omit_prereq = True
Tao Bao177c6102016-02-23 11:38:39 -08001568 elif o == "--downgrade":
1569 OPTIONS.downgrade = True
1570 OPTIONS.wipe_user_data = True
Michael Runge6e836112014-04-15 17:40:21 -07001571 elif o in ("-o", "--oem_settings"):
1572 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001573 elif o in ("-e", "--extra_script"):
1574 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001575 elif o in ("-a", "--aslr_mode"):
1576 if a in ("on", "On", "true", "True", "yes", "Yes"):
1577 OPTIONS.aslr_mode = True
1578 else:
1579 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001580 elif o in ("-t", "--worker_threads"):
1581 if a.isdigit():
1582 OPTIONS.worker_threads = int(a)
1583 else:
1584 raise ValueError("Cannot parse value %r for option %r - only "
1585 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001586 elif o in ("-2", "--two_step"):
1587 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001588 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001589 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001590 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001591 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001592 elif o == "--block":
1593 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001594 elif o in ("-b", "--binary"):
1595 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001596 elif o in ("--no_fallback_to_full",):
1597 OPTIONS.fallback_to_full = False
Tao Baod47d8e12015-05-21 14:09:49 -07001598 elif o == "--stash_threshold":
1599 try:
1600 OPTIONS.stash_threshold = float(a)
1601 except ValueError:
1602 raise ValueError("Cannot parse value %r for option %r - expecting "
1603 "a float" % (a, o))
Doug Zongkereef39442009-04-02 12:14:19 -07001604 else:
1605 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001606 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001607
1608 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001609 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001610 extra_long_opts=[
1611 "board_config=",
1612 "package_key=",
1613 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001614 "full_radio",
leozwanga1fcaf82015-09-15 08:44:12 -07001615 "full_bootloader",
Dan Albert8b72aef2015-03-23 19:13:21 -07001616 "wipe_user_data",
1617 "no_prereq",
Tao Bao177c6102016-02-23 11:38:39 -08001618 "downgrade",
Dan Albert8b72aef2015-03-23 19:13:21 -07001619 "extra_script=",
1620 "worker_threads=",
1621 "aslr_mode=",
1622 "two_step",
1623 "no_signing",
1624 "block",
1625 "binary=",
1626 "oem_settings=",
1627 "verify",
1628 "no_fallback_to_full",
Tao Baod47d8e12015-05-21 14:09:49 -07001629 "stash_threshold=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001630 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001631
1632 if len(args) != 2:
1633 common.Usage(__doc__)
1634 sys.exit(1)
1635
Tao Bao177c6102016-02-23 11:38:39 -08001636 if OPTIONS.downgrade:
1637 # Sanity check to enforce a data wipe.
1638 if not OPTIONS.wipe_user_data:
1639 raise ValueError("Cannot downgrade without a data wipe")
1640
1641 # We should only allow downgrading incrementals (as opposed to full).
1642 # Otherwise the device may go back from arbitrary build with this full
1643 # OTA package.
1644 if OPTIONS.incremental_source is None:
1645 raise ValueError("Cannot generate downgradable full OTAs - consider"
1646 "using --omit_prereq?")
1647
Doug Zongker1c390a22009-05-14 19:06:36 -07001648 if OPTIONS.extra_script is not None:
1649 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1650
Doug Zongkereef39442009-04-02 12:14:19 -07001651 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001652 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001653
Doug Zongkereef39442009-04-02 12:14:19 -07001654 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001655 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001656
1657 # If this image was originally labelled with SELinux contexts, make sure we
1658 # also apply the labels in our new image. During building, the "file_contexts"
1659 # is in the out/ directory tree, but for repacking from target-files.zip it's
1660 # in the root directory of the ramdisk.
1661 if "selinux_fc" in OPTIONS.info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001662 OPTIONS.info_dict["selinux_fc"] = os.path.join(
1663 OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")
Kenny Roote2e9f612013-05-29 12:59:35 -07001664
Doug Zongker37974732010-09-16 17:44:38 -07001665 if OPTIONS.verbose:
1666 print "--- target info ---"
1667 common.DumpInfoDict(OPTIONS.info_dict)
1668
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001669 # If the caller explicitly specified the device-specific extensions
1670 # path via -s/--device_specific, use that. Otherwise, use
1671 # META/releasetools.py if it is present in the target target_files.
1672 # Otherwise, take the path of the file from 'tool_extensions' in the
1673 # info dict and look for that in the local filesystem, relative to
1674 # the current directory.
1675
Doug Zongker37974732010-09-16 17:44:38 -07001676 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001677 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1678 if os.path.exists(from_input):
1679 print "(using device-specific extensions from target_files)"
1680 OPTIONS.device_specific = from_input
1681 else:
1682 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1683
Doug Zongker37974732010-09-16 17:44:38 -07001684 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001685 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001686
Doug Zongker62d4f182014-08-04 16:06:43 -07001687 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001688
Doug Zongker62d4f182014-08-04 16:06:43 -07001689 if OPTIONS.no_signing:
Dan Albert8b72aef2015-03-23 19:13:21 -07001690 if os.path.exists(args[1]):
1691 os.unlink(args[1])
1692 output_zip = zipfile.ZipFile(args[1], "w",
1693 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001694 else:
1695 temp_zip_file = tempfile.NamedTemporaryFile()
1696 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1697 compression=zipfile.ZIP_DEFLATED)
1698
Tao Baod47d8e12015-05-21 14:09:49 -07001699 cache_size = OPTIONS.info_dict.get("cache_size", None)
1700 if cache_size is None:
1701 raise RuntimeError("can't determine the cache partition size")
1702 OPTIONS.cache_size = cache_size
1703
Doug Zongker62d4f182014-08-04 16:06:43 -07001704 if OPTIONS.incremental_source is None:
1705 WriteFullOTAPackage(input_zip, output_zip)
1706 if OPTIONS.package_key is None:
1707 OPTIONS.package_key = OPTIONS.info_dict.get(
1708 "default_system_dev_certificate",
1709 "build/target/product/security/testkey")
Tao Baof3282b42015-04-01 11:21:55 -07001710 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001711 break
1712
1713 else:
1714 print "unzipping source target-files..."
Dan Albert8b72aef2015-03-23 19:13:21 -07001715 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
1716 OPTIONS.incremental_source)
Doug Zongker62d4f182014-08-04 16:06:43 -07001717 OPTIONS.target_info_dict = OPTIONS.info_dict
1718 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1719 if "selinux_fc" in OPTIONS.source_info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001720 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(
1721 OPTIONS.source_tmp, "BOOT", "RAMDISK", "file_contexts")
Doug Zongker62d4f182014-08-04 16:06:43 -07001722 if OPTIONS.package_key is None:
1723 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1724 "default_system_dev_certificate",
1725 "build/target/product/security/testkey")
1726 if OPTIONS.verbose:
1727 print "--- source info ---"
1728 common.DumpInfoDict(OPTIONS.source_info_dict)
1729 try:
1730 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Baof3282b42015-04-01 11:21:55 -07001731 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001732 break
1733 except ValueError:
Dan Albert8b72aef2015-03-23 19:13:21 -07001734 if not OPTIONS.fallback_to_full:
1735 raise
Doug Zongker62d4f182014-08-04 16:06:43 -07001736 print "--- failed to build incremental; falling back to full ---"
1737 OPTIONS.incremental_source = None
Tao Baof3282b42015-04-01 11:21:55 -07001738 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001739
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001740 if not OPTIONS.no_signing:
1741 SignOutput(temp_zip_file.name, args[1])
1742 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001743
Doug Zongkereef39442009-04-02 12:14:19 -07001744 print "done."
1745
1746
1747if __name__ == '__main__':
1748 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001749 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001750 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001751 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07001752 print
1753 print " ERROR: %s" % (e,)
1754 print
1755 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001756 finally:
1757 common.Cleanup()