blob: 9ab8cb330cae034f069d1809a649ee5ca8daedaf [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
Michael Runge63f01de2014-10-28 19:24:19 -070045 -v (--verify)
46 Remount and verify the checksums of the files written to the
47 system and vendor (if used) partitions. Incremental builds only.
48
Michael Runge6e836112014-04-15 17:40:21 -070049 -o (--oem_settings) <file>
50 Use the file to specify the expected OEM-specific properties
51 on the OEM partition of the intended device.
52
Doug Zongkerdbfaae52009-04-21 17:12:54 -070053 -w (--wipe_user_data)
54 Generate an OTA package that will wipe the user data partition
55 when installed.
56
Doug Zongker962069c2009-04-23 11:41:58 -070057 -n (--no_prereq)
58 Omit the timestamp prereq check normally included at the top of
59 the build scripts (used for developer OTA packages which
60 legitimately need to go back and forth).
61
Doug Zongker1c390a22009-05-14 19:06:36 -070062 -e (--extra_script) <file>
63 Insert the contents of file at the end of the update script.
64
Hristo Bojinovdafb0422010-08-26 14:35:16 -070065 -a (--aslr_mode) <on|off>
66 Specify whether to turn on ASLR for the package (on by default).
Stephen Smalley56882bf2012-02-09 13:36:21 -050067
Doug Zongker9b23f2c2013-11-25 14:44:12 -080068 -2 (--two_step)
69 Generate a 'two-step' OTA package, where recovery is updated
70 first, so that any changes made to the system partition are done
71 using the new recovery (new kernel, etc.).
72
Doug Zongker26e66192014-02-20 13:22:07 -080073 --block
74 Generate a block-based OTA if possible. Will fall back to a
75 file-based OTA if the target_files is older and doesn't support
76 block-based OTAs.
77
Doug Zongker25568482014-03-03 10:21:27 -080078 -b (--binary) <file>
79 Use the given binary as the update-binary in the output package,
80 instead of the binary in the build's target_files. Use for
81 development only.
82
Martin Blumenstingl374e1142014-05-31 20:42:55 +020083 -t (--worker_threads) <int>
84 Specifies the number of worker-threads that will be used when
85 generating patches for incremental updates (defaults to 3).
86
Tao Bao8dcf7382015-05-21 14:09:49 -070087 --stash_threshold <float>
88 Specifies the threshold that will be used to compute the maximum
89 allowed stash size (defaults to 0.8).
Doug Zongkereef39442009-04-02 12:14:19 -070090"""
91
92import sys
93
Doug Zongkercf6d5a92014-02-18 10:57:07 -080094if sys.hexversion < 0x02070000:
95 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -070096 sys.exit(1)
97
Doug Zongkerfc44a512014-08-26 13:10:25 -070098import multiprocessing
Doug Zongkereef39442009-04-02 12:14:19 -070099import os
Doug Zongkereef39442009-04-02 12:14:19 -0700100import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -0700101import zipfile
102
103import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700104import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -0700105import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700106
107OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700108OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700109OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700110OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700111OPTIONS.require_verbatim = set()
112OPTIONS.prohibit_verbatim = set(("system/build.prop",))
113OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700114OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700115OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700116OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700117OPTIONS.aslr_mode = True
Doug Zongkerfc44a512014-08-26 13:10:25 -0700118OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
119if OPTIONS.worker_threads == 0:
120 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800121OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900122OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800123OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800124OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700125OPTIONS.oem_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -0700126OPTIONS.fallback_to_full = True
Tao Bao43078aa2015-04-21 14:32:35 -0700127OPTIONS.full_radio = False
Tao Bao8dcf7382015-05-21 14:09:49 -0700128
Doug Zongkereef39442009-04-02 12:14:19 -0700129
130def MostPopularKey(d, default):
131 """Given a dict, return the key corresponding to the largest
132 value. Returns 'default' if the dict is empty."""
133 x = [(v, k) for (k, v) in d.iteritems()]
Dan Albert8b72aef2015-03-23 19:13:21 -0700134 if not x:
135 return default
Doug Zongkereef39442009-04-02 12:14:19 -0700136 x.sort()
137 return x[-1][1]
138
139
140def IsSymlink(info):
141 """Return true if the zipfile.ZipInfo object passed in represents a
142 symlink."""
Ying Wang2ffb3142015-07-06 14:02:01 -0700143 return (info.external_attr >> 16) & 0o770000 == 0o120000
Doug Zongkereef39442009-04-02 12:14:19 -0700144
Hristo Bojinov96be7202010-08-02 10:26:17 -0700145def IsRegular(info):
146 """Return true if the zipfile.ZipInfo object passed in represents a
Ying Wang2ffb3142015-07-06 14:02:01 -0700147 regular file."""
148 return (info.external_attr >> 16) & 0o770000 == 0o100000
Doug Zongkereef39442009-04-02 12:14:19 -0700149
Michael Runge4038aa82013-12-13 18:06:28 -0800150def ClosestFileMatch(src, tgtfiles, existing):
151 """Returns the closest file match between a source file and list
152 of potential matches. The exact filename match is preferred,
153 then the sha1 is searched for, and finally a file with the same
154 basename is evaluated. Rename support in the updater-binary is
155 required for the latter checks to be used."""
156
157 result = tgtfiles.get("path:" + src.name)
158 if result is not None:
159 return result
160
161 if not OPTIONS.target_info_dict.get("update_rename_support", False):
162 return None
163
164 if src.size < 1000:
165 return None
166
167 result = tgtfiles.get("sha1:" + src.sha1)
168 if result is not None and existing.get(result.name) is None:
169 return result
170 result = tgtfiles.get("file:" + src.name.split("/")[-1])
171 if result is not None and existing.get(result.name) is None:
172 return result
173 return None
174
Dan Albert8b72aef2015-03-23 19:13:21 -0700175class ItemSet(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700176 def __init__(self, partition, fs_config):
177 self.partition = partition
178 self.fs_config = fs_config
179 self.ITEMS = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700180
Dan Albert8b72aef2015-03-23 19:13:21 -0700181 def Get(self, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700182 if name not in self.ITEMS:
Dan Albert8b72aef2015-03-23 19:13:21 -0700183 self.ITEMS[name] = Item(self, name, is_dir=is_dir)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700184 return self.ITEMS[name]
Doug Zongkereef39442009-04-02 12:14:19 -0700185
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700186 def GetMetadata(self, input_zip):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700187 # The target_files contains a record of what the uid,
188 # gid, and mode are supposed to be.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700189 output = input_zip.read(self.fs_config)
Doug Zongkereef39442009-04-02 12:14:19 -0700190
191 for line in output.split("\n"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700192 if not line:
193 continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700194 columns = line.split()
195 name, uid, gid, mode = columns[:4]
196 selabel = None
197 capabilities = None
198
199 # After the first 4 columns, there are a series of key=value
200 # pairs. Extract out the fields we care about.
201 for element in columns[4:]:
202 key, value = element.split("=")
203 if key == "selabel":
204 selabel = value
205 if key == "capabilities":
206 capabilities = value
207
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700208 i = self.ITEMS.get(name, None)
Doug Zongker283e2a12010-03-15 17:52:32 -0700209 if i is not None:
210 i.uid = int(uid)
211 i.gid = int(gid)
212 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700213 i.selabel = selabel
214 i.capabilities = capabilities
Dan Albert8b72aef2015-03-23 19:13:21 -0700215 if i.is_dir:
Doug Zongker283e2a12010-03-15 17:52:32 -0700216 i.children.sort(key=lambda i: i.name)
217
Tao Baof2cffbd2015-07-22 12:33:18 -0700218 # Set metadata for the files generated by this script. For full recovery
219 # image at system/etc/recovery.img, it will be taken care by fs_config.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700220 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700221 if i:
222 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700223 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700224 if i:
225 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700226
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700227
Dan Albert8b72aef2015-03-23 19:13:21 -0700228class Item(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700229 """Items represent the metadata (user, group, mode) of files and
230 directories in the system image."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700231 def __init__(self, itemset, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700232 self.itemset = itemset
233 self.name = name
234 self.uid = None
235 self.gid = None
236 self.mode = None
237 self.selabel = None
238 self.capabilities = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700239 self.is_dir = is_dir
240 self.descendants = None
241 self.best_subtree = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700242
243 if name:
Dan Albert8b72aef2015-03-23 19:13:21 -0700244 self.parent = itemset.Get(os.path.dirname(name), is_dir=True)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700245 self.parent.children.append(self)
246 else:
247 self.parent = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700248 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700249 self.children = []
250
251 def Dump(self, indent=0):
252 if self.uid is not None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700253 print "%s%s %d %d %o" % (
254 " " * indent, self.name, self.uid, self.gid, self.mode)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700255 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700256 print "%s%s %s %s %s" % (
257 " " * indent, self.name, self.uid, self.gid, self.mode)
258 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700259 print "%s%s" % (" "*indent, self.descendants)
260 print "%s%s" % (" "*indent, self.best_subtree)
261 for i in self.children:
262 i.Dump(indent=indent+1)
263
Doug Zongkereef39442009-04-02 12:14:19 -0700264 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700265 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
Dan Albert8b72aef2015-03-23 19:13:21 -0700266 all children and determine the best strategy for using set_perm_recursive
267 and set_perm to correctly chown/chmod all the files to their desired
Doug Zongkereef39442009-04-02 12:14:19 -0700268 values. Recursively calls itself for all descendants.
269
Dan Albert8b72aef2015-03-23 19:13:21 -0700270 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count}
271 counting up all descendants of this node. (dmode or fmode may be None.)
272 Also sets the best_subtree of each directory Item to the (uid, gid, dmode,
273 fmode, selabel, capabilities) tuple that will match the most descendants of
274 that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700275 """
276
Dan Albert8b72aef2015-03-23 19:13:21 -0700277 assert self.is_dir
278 key = (self.uid, self.gid, self.mode, None, self.selabel,
279 self.capabilities)
280 self.descendants = {key: 1}
281 d = self.descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700282 for i in self.children:
Dan Albert8b72aef2015-03-23 19:13:21 -0700283 if i.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700284 for k, v in i.CountChildMetadata().iteritems():
285 d[k] = d.get(k, 0) + v
286 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700287 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700288 d[k] = d.get(k, 0) + 1
289
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700290 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
291 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700292
293 # First, find the (uid, gid) pair that matches the most
294 # descendants.
295 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700296 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700297 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
298 ug = MostPopularKey(ug, (0, 0))
299
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700300 # Now find the dmode, fmode, selabel, and capabilities that match
301 # the most descendants with that (uid, gid), and choose those.
Dan Albert8b72aef2015-03-23 19:13:21 -0700302 best_dmode = (0, 0o755)
303 best_fmode = (0, 0o644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700304 best_selabel = (0, None)
305 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700306 for k, count in d.iteritems():
Dan Albert8b72aef2015-03-23 19:13:21 -0700307 if k[:2] != ug:
308 continue
309 if k[2] is not None and count >= best_dmode[0]:
310 best_dmode = (count, k[2])
311 if k[3] is not None and count >= best_fmode[0]:
312 best_fmode = (count, k[3])
313 if k[4] is not None and count >= best_selabel[0]:
314 best_selabel = (count, k[4])
315 if k[5] is not None and count >= best_capabilities[0]:
316 best_capabilities = (count, k[5])
317 self.best_subtree = ug + (
318 best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700319
320 return d
321
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700322 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700323 """Append set_perm/set_perm_recursive commands to 'script' to
324 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700325 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700326
327 self.CountChildMetadata()
328
329 def recurse(item, current):
Dan Albert8b72aef2015-03-23 19:13:21 -0700330 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple
331 # that the current item (and all its children) have already been set to.
332 # We only need to issue set_perm/set_perm_recursive commands if we're
Doug Zongkereef39442009-04-02 12:14:19 -0700333 # supposed to be something different.
Dan Albert8b72aef2015-03-23 19:13:21 -0700334 if item.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700335 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700336 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700337 current = item.best_subtree
338
339 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700340 item.mode != current[2] or item.selabel != current[4] or \
341 item.capabilities != current[5]:
342 script.SetPermissions("/"+item.name, item.uid, item.gid,
343 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700344
345 for i in item.children:
346 recurse(i, current)
347 else:
348 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700349 item.mode != current[3] or item.selabel != current[4] or \
350 item.capabilities != current[5]:
351 script.SetPermissions("/"+item.name, item.uid, item.gid,
352 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700353
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700354 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700355
356
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700357def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
358 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700359 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800360 list of symlinks. output_zip may be None, in which case the copy is
361 skipped (but the other side effects still happen). substitute is an
362 optional dict of {output filename: contents} to be output instead of
363 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700364 """
365
366 symlinks = []
367
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700368 partition = itemset.partition
369
Doug Zongkereef39442009-04-02 12:14:19 -0700370 for info in input_zip.infolist():
Tao Baoeaf885b2015-03-23 16:01:17 -0700371 prefix = partition.upper() + "/"
372 if info.filename.startswith(prefix):
373 basefilename = info.filename[len(prefix):]
Doug Zongkereef39442009-04-02 12:14:19 -0700374 if IsSymlink(info):
375 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700376 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700377 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700378 import copy
Doug Zongkereef39442009-04-02 12:14:19 -0700379 info2 = copy.copy(info)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700380 fn = info2.filename = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700381 if substitute and fn in substitute and substitute[fn] is None:
382 continue
383 if output_zip is not None:
384 if substitute and fn in substitute:
385 data = substitute[fn]
386 else:
387 data = input_zip.read(info.filename)
Tao Bao2ed665a2015-04-01 11:21:55 -0700388 common.ZipWriteStr(output_zip, info2, data)
Doug Zongkereef39442009-04-02 12:14:19 -0700389 if fn.endswith("/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700390 itemset.Get(fn[:-1], is_dir=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700391 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700392 itemset.Get(fn)
Doug Zongkereef39442009-04-02 12:14:19 -0700393
394 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800395 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700396
397
Doug Zongkereef39442009-04-02 12:14:19 -0700398def SignOutput(temp_zip_name, output_zip_name):
399 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
400 pw = key_passwords[OPTIONS.package_key]
401
Doug Zongker951495f2009-08-14 12:44:19 -0700402 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
403 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700404
405
Dan Albert8b72aef2015-03-23 19:13:21 -0700406def AppendAssertions(script, info_dict, oem_dict=None):
Michael Runge6e836112014-04-15 17:40:21 -0700407 oem_props = info_dict.get("oem_fingerprint_properties")
Michael Runge560569a2014-09-18 15:12:45 -0700408 if oem_props is None or len(oem_props) == 0:
Michael Runge6e836112014-04-15 17:40:21 -0700409 device = GetBuildProp("ro.product.device", info_dict)
410 script.AssertDevice(device)
411 else:
412 if oem_dict is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700413 raise common.ExternalError(
414 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700415 for prop in oem_props.split():
416 if oem_dict.get(prop) is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700417 raise common.ExternalError(
418 "The OEM file is missing the property %s" % prop)
Michael Runge6e836112014-04-15 17:40:21 -0700419 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700420
Doug Zongkereef39442009-04-02 12:14:19 -0700421
Doug Zongkerc9253822014-02-04 12:17:58 -0800422def HasRecoveryPatch(target_files_zip):
Tao Baof2cffbd2015-07-22 12:33:18 -0700423 namelist = [name for name in target_files_zip.namelist()]
424 return ("SYSTEM/recovery-from-boot.p" in namelist or
425 "SYSTEM/etc/recovery.img" in namelist)
Doug Zongker73ef8252009-07-23 15:12:53 -0700426
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700427def HasVendorPartition(target_files_zip):
428 try:
429 target_files_zip.getinfo("VENDOR/")
430 return True
431 except KeyError:
432 return False
433
Michael Runge6e836112014-04-15 17:40:21 -0700434def GetOemProperty(name, oem_props, oem_dict, info_dict):
435 if oem_props is not None and name in oem_props:
436 return oem_dict[name]
437 return GetBuildProp(name, info_dict)
438
439
440def CalculateFingerprint(oem_props, oem_dict, info_dict):
441 if oem_props is None:
442 return GetBuildProp("ro.build.fingerprint", info_dict)
443 return "%s/%s/%s:%s" % (
Dan Albert8b72aef2015-03-23 19:13:21 -0700444 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
445 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
446 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
447 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700448
Doug Zongkerfc44a512014-08-26 13:10:25 -0700449
Doug Zongker3c84f562014-07-31 11:06:30 -0700450def GetImage(which, tmpdir, info_dict):
Doug Zongkerfc44a512014-08-26 13:10:25 -0700451 # Return an image object (suitable for passing to BlockImageDiff)
452 # for the 'which' partition (most be "system" or "vendor"). If a
453 # prebuilt image and file map are found in tmpdir they are used,
454 # otherwise they are reconstructed from the individual files.
Doug Zongker3c84f562014-07-31 11:06:30 -0700455
456 assert which in ("system", "vendor")
457
458 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700459 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
460 if os.path.exists(path) and os.path.exists(mappath):
Doug Zongker3c84f562014-07-31 11:06:30 -0700461 print "using %s.img from target-files" % (which,)
Doug Zongker3c84f562014-07-31 11:06:30 -0700462 # This is a 'new' target-files, which already has the image in it.
Doug Zongker3c84f562014-07-31 11:06:30 -0700463
464 else:
465 print "building %s.img from target-files" % (which,)
466
467 # This is an 'old' target-files, which does not contain images
468 # already built. Build them.
469
Doug Zongkerfc44a512014-08-26 13:10:25 -0700470 mappath = tempfile.mkstemp()[1]
471 OPTIONS.tempfiles.append(mappath)
472
Doug Zongker3c84f562014-07-31 11:06:30 -0700473 import add_img_to_target_files
474 if which == "system":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700475 path = add_img_to_target_files.BuildSystem(
476 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700477 elif which == "vendor":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700478 path = add_img_to_target_files.BuildVendor(
479 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700480
Tao Baoff777812015-05-12 11:42:31 -0700481 # Bug: http://b/20939131
482 # In ext4 filesystems, block 0 might be changed even being mounted
483 # R/O. We add it to clobbered_blocks so that it will be written to the
484 # target unconditionally. Note that they are still part of care_map.
485 clobbered_blocks = "0"
486
487 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700488
489
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700490def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700491 # TODO: how to determine this? We don't know what version it will
Tao Bao34b47bf2015-06-22 19:17:41 -0700492 # be installed on top of. For now, we expect the API just won't
493 # change very often. Similarly for fstab, it might have changed
494 # in the target build.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700495 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700496
Michael Runge6e836112014-04-15 17:40:21 -0700497 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700498 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700499 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700500 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700501 if OPTIONS.oem_source is None:
502 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700503 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700504 oem_dict = common.LoadDictionaryFromLines(
505 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -0700506
Dan Albert8b72aef2015-03-23 19:13:21 -0700507 metadata = {
508 "post-build": CalculateFingerprint(oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700509 OPTIONS.info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700510 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
511 OPTIONS.info_dict),
512 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
513 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700514
Doug Zongker05d3dea2009-06-22 11:32:31 -0700515 device_specific = common.DeviceSpecificParams(
516 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700517 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700518 output_zip=output_zip,
519 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700520 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700521 metadata=metadata,
522 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700523
Doug Zongkerc9253822014-02-04 12:17:58 -0800524 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800525 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800526
Doug Zongker962069c2009-04-23 11:41:58 -0700527 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700528 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700529 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
530 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700531
Michael Runge6e836112014-04-15 17:40:21 -0700532 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700533 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800534
535 # Two-step package strategy (in chronological order, which is *not*
536 # the order in which the generated script has things):
537 #
538 # if stage is not "2/3" or "3/3":
539 # write recovery image to boot partition
540 # set stage to "2/3"
541 # reboot to boot partition and restart recovery
542 # else if stage is "2/3":
543 # write recovery image to recovery partition
544 # set stage to "3/3"
545 # reboot to recovery partition and restart recovery
546 # else:
547 # (stage must be "3/3")
548 # set stage to ""
549 # do normal full package installation:
550 # wipe and install system, boot image, etc.
551 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700552 # complete script normally
553 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800554
555 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
556 OPTIONS.input_tmp, "RECOVERY")
557 if OPTIONS.two_step:
558 if not OPTIONS.info_dict.get("multistage_support", None):
559 assert False, "two-step packages not supported by this build"
560 fs = OPTIONS.info_dict["fstab"]["/misc"]
561 assert fs.fs_type.upper() == "EMMC", \
562 "two-step packages only supported on devices with EMMC /misc partitions"
563 bcb_dev = {"bcb_dev": fs.device}
564 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
565 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700566if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800567""" % bcb_dev)
568 script.WriteRawImage("/recovery", "recovery.img")
569 script.AppendExtra("""
570set_stage("%(bcb_dev)s", "3/3");
571reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700572else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800573""" % bcb_dev)
574
Tao Bao6c55a8a2015-04-08 15:30:27 -0700575 # Dump fingerprints
576 script.Print("Target: %s" % CalculateFingerprint(
577 oem_props, oem_dict, OPTIONS.info_dict))
578
Doug Zongkere5ff5902012-01-17 10:55:37 -0800579 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700580
Doug Zongker01ce19c2014-02-04 13:48:15 -0800581 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700582
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700583 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800584 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700585 if HasVendorPartition(input_zip):
586 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700587
Stephen Smalleyd3a803e2015-08-04 14:59:06 -0400588 # Place a copy of file_contexts.bin into the OTA package which will be used
589 # by the recovery program.
Kenny Rootf32dc712012-04-08 10:42:34 -0700590 if "selinux_fc" in OPTIONS.info_dict:
591 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500592
Michael Runge7cd99ba2014-10-22 17:21:48 -0700593 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
594
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700595 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700596 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800597
Doug Zongker26e66192014-02-20 13:22:07 -0800598 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700599 # Full OTA is done as an "incremental" against an empty source
600 # image. This has the effect of writing new data from the package
601 # to the entire partition, but lets us reuse the updater code that
602 # writes incrementals to do it.
603 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
604 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700605 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700606 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800607 else:
608 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700609 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800610 if not has_recovery_patch:
611 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800612 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700613
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700614 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800615 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700616
Tao Bao7a5bf8a2015-07-21 18:01:20 -0700617 boot_img = common.GetBootableImage(
618 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800619
Doug Zongker91a99c22014-05-09 13:15:01 -0700620 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800621 def output_sink(fn, data):
622 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700623 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800624
625 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
626 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700627
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700628 system_items.GetMetadata(input_zip)
629 system_items.Get("system").SetPermissions(script)
630
631 if HasVendorPartition(input_zip):
632 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
633 script.ShowProgress(0.1, 0)
634
635 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700636 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
637 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700638 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700639 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700640 else:
641 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700642 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700643 script.UnpackPackageDir("vendor", "/vendor")
644
645 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
646 script.MakeSymlinks(symlinks)
647
648 vendor_items.GetMetadata(input_zip)
649 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700650
Doug Zongker37974732010-09-16 17:44:38 -0700651 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700652 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700653
Doug Zongker01ce19c2014-02-04 13:48:15 -0800654 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700655 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700656
Doug Zongker01ce19c2014-02-04 13:48:15 -0800657 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700658 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700659
Doug Zongker1c390a22009-05-14 19:06:36 -0700660 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700661 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700662
Doug Zongker14833602010-02-02 13:12:04 -0800663 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800664
Doug Zongker922206e2014-03-04 13:16:24 -0800665 if OPTIONS.wipe_user_data:
666 script.ShowProgress(0.1, 10)
667 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700668
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800669 if OPTIONS.two_step:
670 script.AppendExtra("""
671set_stage("%(bcb_dev)s", "");
672""" % bcb_dev)
673 script.AppendExtra("else\n")
674 script.WriteRawImage("/boot", "recovery.img")
675 script.AppendExtra("""
676set_stage("%(bcb_dev)s", "2/3");
677reboot_now("%(bcb_dev)s", "");
678endif;
679endif;
680""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800681 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700682 WriteMetadata(metadata, output_zip)
683
Doug Zongkerfc44a512014-08-26 13:10:25 -0700684
Dan Albert8e0178d2015-01-27 15:53:15 -0800685def WritePolicyConfig(file_name, output_zip):
686 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500687
Doug Zongker2ea21062010-04-28 16:05:21 -0700688
689def WriteMetadata(metadata, output_zip):
690 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
691 "".join(["%s=%s\n" % kv
692 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700693
Doug Zongkerfc44a512014-08-26 13:10:25 -0700694
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700695def LoadPartitionFiles(z, partition):
696 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700697 ZipFile, and return a dict of {filename: File object}."""
698 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700699 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700700 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700701 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700702 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700703 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700704 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700705 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800706 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700707
708
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700709def GetBuildProp(prop, info_dict):
710 """Return the fingerprint of the build of a given target-files info_dict."""
711 try:
712 return info_dict.get("build.prop", {})[prop]
713 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700714 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700715
Doug Zongkerfc44a512014-08-26 13:10:25 -0700716
Michael Runge4038aa82013-12-13 18:06:28 -0800717def AddToKnownPaths(filename, known_paths):
718 if filename[-1] == "/":
719 return
720 dirs = filename.split("/")[:-1]
721 while len(dirs) > 0:
722 path = "/".join(dirs)
723 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700724 break
Michael Runge4038aa82013-12-13 18:06:28 -0800725 known_paths.add(path)
726 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700727
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700728
Geremy Condra36bd3652014-02-06 19:45:10 -0800729def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
Tao Bao3806c232015-07-05 21:08:33 -0700730 # TODO(tbao): We should factor out the common parts between
731 # WriteBlockIncrementalOTAPackage() and WriteIncrementalOTAPackage().
Geremy Condra36bd3652014-02-06 19:45:10 -0800732 source_version = OPTIONS.source_info_dict["recovery_api_version"]
733 target_version = OPTIONS.target_info_dict["recovery_api_version"]
734
735 if source_version == 0:
736 print ("WARNING: generating edify script for a source that "
737 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -0700738 script = edify_generator.EdifyGenerator(
739 source_version, OPTIONS.target_info_dict,
740 fstab=OPTIONS.source_info_dict["fstab"])
Geremy Condra36bd3652014-02-06 19:45:10 -0800741
Tao Bao3806c232015-07-05 21:08:33 -0700742 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
743 recovery_mount_options = OPTIONS.source_info_dict.get(
744 "recovery_mount_options")
745 oem_dict = None
746 if oem_props is not None and len(oem_props) > 0:
747 if OPTIONS.oem_source is None:
748 raise common.ExternalError("OEM source required for this build")
749 script.Mount("/oem", recovery_mount_options)
750 oem_dict = common.LoadDictionaryFromLines(
751 open(OPTIONS.oem_source).readlines())
752
Dan Albert8b72aef2015-03-23 19:13:21 -0700753 metadata = {
Tao Bao3806c232015-07-05 21:08:33 -0700754 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
755 OPTIONS.source_info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700756 "post-timestamp": GetBuildProp("ro.build.date.utc",
757 OPTIONS.target_info_dict),
758 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800759
760 device_specific = common.DeviceSpecificParams(
761 source_zip=source_zip,
762 source_version=source_version,
763 target_zip=target_zip,
764 target_version=target_version,
765 output_zip=output_zip,
766 script=script,
767 metadata=metadata,
768 info_dict=OPTIONS.info_dict)
769
Tao Bao3806c232015-07-05 21:08:33 -0700770 source_fp = CalculateFingerprint(oem_props, oem_dict,
771 OPTIONS.source_info_dict)
772 target_fp = CalculateFingerprint(oem_props, oem_dict,
773 OPTIONS.target_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800774 metadata["pre-build"] = source_fp
775 metadata["post-build"] = target_fp
776
777 source_boot = common.GetBootableImage(
778 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
779 OPTIONS.source_info_dict)
780 target_boot = common.GetBootableImage(
781 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
782 updating_boot = (not OPTIONS.two_step and
783 (source_boot.data != target_boot.data))
784
Geremy Condra36bd3652014-02-06 19:45:10 -0800785 target_recovery = common.GetBootableImage(
786 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800787
Doug Zongkerfc44a512014-08-26 13:10:25 -0700788 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
789 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700790
791 blockimgdiff_version = 1
792 if OPTIONS.info_dict:
793 blockimgdiff_version = max(
794 int(i) for i in
795 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
796
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700797 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700798 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700799
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700800 if HasVendorPartition(target_zip):
801 if not HasVendorPartition(source_zip):
802 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700803 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
804 OPTIONS.source_info_dict)
805 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
806 OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700807 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700808 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700809 else:
810 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800811
Michael Rungec6e3afd2014-05-05 11:55:47 -0700812 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800813 device_specific.IncrementalOTA_Assertions()
814
815 # Two-step incremental package strategy (in chronological order,
816 # which is *not* the order in which the generated script has
817 # things):
818 #
819 # if stage is not "2/3" or "3/3":
820 # do verification on current system
821 # write recovery image to boot partition
822 # set stage to "2/3"
823 # reboot to boot partition and restart recovery
824 # else if stage is "2/3":
825 # write recovery image to recovery partition
826 # set stage to "3/3"
827 # reboot to recovery partition and restart recovery
828 # else:
829 # (stage must be "3/3")
830 # perform update:
831 # patch system files, etc.
832 # force full install of new boot image
833 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700834 # complete script normally
835 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800836
837 if OPTIONS.two_step:
Tao Baodd24da92015-07-29 14:09:23 -0700838 if not OPTIONS.source_info_dict.get("multistage_support", None):
Geremy Condra36bd3652014-02-06 19:45:10 -0800839 assert False, "two-step packages not supported by this build"
Tao Baodd24da92015-07-29 14:09:23 -0700840 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Geremy Condra36bd3652014-02-06 19:45:10 -0800841 assert fs.fs_type.upper() == "EMMC", \
842 "two-step packages only supported on devices with EMMC /misc partitions"
843 bcb_dev = {"bcb_dev": fs.device}
844 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
845 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700846if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800847""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -0700848 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800849 script.WriteRawImage("/recovery", "recovery.img")
850 script.AppendExtra("""
851set_stage("%(bcb_dev)s", "3/3");
852reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700853else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800854""" % bcb_dev)
855
Tao Bao6c55a8a2015-04-08 15:30:27 -0700856 # Dump fingerprints
857 script.Print("Source: %s" % CalculateFingerprint(
858 oem_props, oem_dict, OPTIONS.source_info_dict))
859 script.Print("Target: %s" % CalculateFingerprint(
860 oem_props, oem_dict, OPTIONS.target_info_dict))
861
Geremy Condra36bd3652014-02-06 19:45:10 -0800862 script.Print("Verifying current system...")
863
864 device_specific.IncrementalOTA_VerifyBegin()
865
Michael Rungec6e3afd2014-05-05 11:55:47 -0700866 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700867 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
868 # patching on a device that's already on the target build will damage the
869 # system. Because operations like move don't check the block state, they
870 # always apply the changes unconditionally.
871 if blockimgdiff_version <= 2:
872 script.AssertSomeFingerprint(source_fp)
873 else:
874 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700875 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700876 if blockimgdiff_version <= 2:
877 script.AssertSomeThumbprint(
878 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
879 else:
880 script.AssertSomeThumbprint(
881 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
882 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800883
884 if updating_boot:
Tao Baodd24da92015-07-29 14:09:23 -0700885 boot_type, boot_device = common.GetTypeAndDevice(
886 "/boot", OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800887 d = common.Difference(target_boot, source_boot)
888 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700889 if d is None:
890 include_full_boot = True
891 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
892 else:
893 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800894
Doug Zongkerf8340082014-08-05 10:39:37 -0700895 print "boot target: %d source: %d diff: %d" % (
896 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800897
Doug Zongkerf8340082014-08-05 10:39:37 -0700898 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800899
Doug Zongkerf8340082014-08-05 10:39:37 -0700900 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
901 (boot_type, boot_device,
902 source_boot.size, source_boot.sha1,
903 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800904
905 device_specific.IncrementalOTA_VerifyEnd()
906
907 if OPTIONS.two_step:
908 script.WriteRawImage("/boot", "recovery.img")
909 script.AppendExtra("""
910set_stage("%(bcb_dev)s", "2/3");
911reboot_now("%(bcb_dev)s", "");
912else
913""" % bcb_dev)
914
Jesse Zhao75bcea02015-01-06 10:59:53 -0800915 # Verify the existing partitions.
916 system_diff.WriteVerifyScript(script)
917 if vendor_diff:
918 vendor_diff.WriteVerifyScript(script)
919
Geremy Condra36bd3652014-02-06 19:45:10 -0800920 script.Comment("---- start making changes here ----")
921
922 device_specific.IncrementalOTA_InstallBegin()
923
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700924 system_diff.WriteScript(script, output_zip,
925 progress=0.8 if vendor_diff else 0.9)
Tao Bao68658c02015-06-01 13:40:49 -0700926
Doug Zongkerfc44a512014-08-26 13:10:25 -0700927 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700928 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800929
930 if OPTIONS.two_step:
931 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
932 script.WriteRawImage("/boot", "boot.img")
933 print "writing full boot image (forced by two-step mode)"
934
935 if not OPTIONS.two_step:
936 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700937 if include_full_boot:
938 print "boot image changed; including full."
939 script.Print("Installing boot image...")
940 script.WriteRawImage("/boot", "boot.img")
941 else:
942 # Produce the boot image by applying a patch to the current
943 # contents of the boot partition, and write it back to the
944 # partition.
945 print "boot image changed; including patch."
946 script.Print("Patching boot image...")
947 script.ShowProgress(0.1, 10)
948 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
949 % (boot_type, boot_device,
950 source_boot.size, source_boot.sha1,
951 target_boot.size, target_boot.sha1),
952 "-",
953 target_boot.size, target_boot.sha1,
954 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800955 else:
956 print "boot image unchanged; skipping."
957
958 # Do device-specific installation (eg, write radio image).
959 device_specific.IncrementalOTA_InstallEnd()
960
961 if OPTIONS.extra_script is not None:
962 script.AppendExtra(OPTIONS.extra_script)
963
Doug Zongker922206e2014-03-04 13:16:24 -0800964 if OPTIONS.wipe_user_data:
965 script.Print("Erasing user data...")
966 script.FormatPartition("/data")
967
Geremy Condra36bd3652014-02-06 19:45:10 -0800968 if OPTIONS.two_step:
969 script.AppendExtra("""
970set_stage("%(bcb_dev)s", "");
971endif;
972endif;
973""" % bcb_dev)
974
975 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800976 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800977 WriteMetadata(metadata, output_zip)
978
Doug Zongker32b527d2014-03-04 10:03:02 -0800979
Dan Albert8b72aef2015-03-23 19:13:21 -0700980class FileDifference(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700981 def __init__(self, partition, source_zip, target_zip, output_zip):
Dan Albert8b72aef2015-03-23 19:13:21 -0700982 self.deferred_patch_list = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700983 print "Loading target..."
984 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
985 print "Loading source..."
986 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
987
988 self.verbatim_targets = verbatim_targets = []
989 self.patch_list = patch_list = []
990 diffs = []
991 self.renames = renames = {}
992 known_paths = set()
993 largest_source_size = 0
994
995 matching_file_cache = {}
996 for fn, sf in source_data.items():
997 assert fn == sf.name
998 matching_file_cache["path:" + fn] = sf
999 if fn in target_data.keys():
1000 AddToKnownPaths(fn, known_paths)
1001 # Only allow eligibility for filename/sha matching
1002 # if there isn't a perfect path match.
1003 if target_data.get(sf.name) is None:
1004 matching_file_cache["file:" + fn.split("/")[-1]] = sf
1005 matching_file_cache["sha:" + sf.sha1] = sf
1006
1007 for fn in sorted(target_data.keys()):
1008 tf = target_data[fn]
1009 assert fn == tf.name
1010 sf = ClosestFileMatch(tf, matching_file_cache, renames)
1011 if sf is not None and sf.name != tf.name:
1012 print "File has moved from " + sf.name + " to " + tf.name
1013 renames[sf.name] = tf
1014
1015 if sf is None or fn in OPTIONS.require_verbatim:
1016 # This file should be included verbatim
1017 if fn in OPTIONS.prohibit_verbatim:
1018 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
1019 print "send", fn, "verbatim"
1020 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001021 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001022 if fn in target_data.keys():
1023 AddToKnownPaths(fn, known_paths)
1024 elif tf.sha1 != sf.sha1:
1025 # File is different; consider sending as a patch
1026 diffs.append(common.Difference(tf, sf))
1027 else:
1028 # Target file data identical to source (may still be renamed)
1029 pass
1030
1031 common.ComputeDifferences(diffs)
1032
1033 for diff in diffs:
1034 tf, sf, d = diff.GetPatch()
1035 path = "/".join(tf.name.split("/")[:-1])
1036 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1037 path not in known_paths:
1038 # patch is almost as big as the file; don't bother patching
1039 # or a patch + rename cannot take place due to the target
1040 # directory not existing
1041 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001042 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001043 if sf.name in renames:
1044 del renames[sf.name]
1045 AddToKnownPaths(tf.name, known_paths)
1046 else:
1047 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1048 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1049 largest_source_size = max(largest_source_size, sf.size)
1050
1051 self.largest_source_size = largest_source_size
1052
1053 def EmitVerification(self, script):
1054 so_far = 0
Dan Albert8b72aef2015-03-23 19:13:21 -07001055 for tf, sf, _, _ in self.patch_list:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001056 if tf.name != sf.name:
1057 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1058 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1059 so_far += sf.size
1060 return so_far
1061
Michael Runge63f01de2014-10-28 19:24:19 -07001062 def EmitExplicitTargetVerification(self, script):
Dan Albert8b72aef2015-03-23 19:13:21 -07001063 for fn, _, sha1 in self.verbatim_targets:
1064 if fn[-1] != "/":
Michael Runge63f01de2014-10-28 19:24:19 -07001065 script.FileCheck("/"+fn, sha1)
1066 for tf, _, _, _ in self.patch_list:
1067 script.FileCheck(tf.name, tf.sha1)
1068
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001069 def RemoveUnneededFiles(self, script, extras=()):
Dan Albert8b72aef2015-03-23 19:13:21 -07001070 script.DeleteFiles(
1071 ["/" + i[0] for i in self.verbatim_targets] +
1072 ["/" + i for i in sorted(self.source_data)
1073 if i not in self.target_data and i not in self.renames] +
1074 list(extras))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001075
1076 def TotalPatchSize(self):
1077 return sum(i[1].size for i in self.patch_list)
1078
1079 def EmitPatches(self, script, total_patch_size, so_far):
1080 self.deferred_patch_list = deferred_patch_list = []
1081 for item in self.patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001082 tf, sf, _, _ = item
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001083 if tf.name == "system/build.prop":
1084 deferred_patch_list.append(item)
1085 continue
Dan Albert8b72aef2015-03-23 19:13:21 -07001086 if sf.name != tf.name:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001087 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
Dan Albert8b72aef2015-03-23 19:13:21 -07001088 script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1,
1089 "patch/" + sf.name + ".p")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001090 so_far += tf.size
1091 script.SetProgress(so_far / total_patch_size)
1092 return so_far
1093
1094 def EmitDeferredPatches(self, script):
1095 for item in self.deferred_patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001096 tf, sf, _, _ = item
1097 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1,
1098 "patch/" + sf.name + ".p")
1099 script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001100
1101 def EmitRenames(self, script):
1102 if len(self.renames) > 0:
1103 script.Print("Renaming files...")
1104 for src, tgt in self.renames.iteritems():
1105 print "Renaming " + src + " to " + tgt.name
1106 script.RenameFile(src, tgt.name)
1107
1108
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001109def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001110 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1111 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1112
Doug Zongker26e66192014-02-20 13:22:07 -08001113 if (OPTIONS.block_based and
1114 target_has_recovery_patch and
1115 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001116 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1117
Doug Zongker37974732010-09-16 17:44:38 -07001118 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1119 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001120
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001121 if source_version == 0:
1122 print ("WARNING: generating edify script for a source that "
1123 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -07001124 script = edify_generator.EdifyGenerator(
1125 source_version, OPTIONS.target_info_dict,
1126 fstab=OPTIONS.source_info_dict["fstab"])
Doug Zongkereef39442009-04-02 12:14:19 -07001127
Michael Runge6e836112014-04-15 17:40:21 -07001128 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Tao Bao34b47bf2015-06-22 19:17:41 -07001129 recovery_mount_options = OPTIONS.source_info_dict.get(
1130 "recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001131 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001132 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001133 if OPTIONS.oem_source is None:
1134 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001135 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001136 oem_dict = common.LoadDictionaryFromLines(
1137 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001138
Dan Albert8b72aef2015-03-23 19:13:21 -07001139 metadata = {
1140 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1141 OPTIONS.source_info_dict),
1142 "post-timestamp": GetBuildProp("ro.build.date.utc",
1143 OPTIONS.target_info_dict),
1144 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001145
Doug Zongker05d3dea2009-06-22 11:32:31 -07001146 device_specific = common.DeviceSpecificParams(
1147 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001148 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001149 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001150 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001151 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001152 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001153 metadata=metadata,
1154 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001155
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001156 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001157 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001158 if HasVendorPartition(target_zip):
1159 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001160 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001161 else:
1162 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001163
Dan Albert8b72aef2015-03-23 19:13:21 -07001164 target_fp = CalculateFingerprint(oem_props, oem_dict,
1165 OPTIONS.target_info_dict)
1166 source_fp = CalculateFingerprint(oem_props, oem_dict,
1167 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001168
1169 if oem_props is None:
1170 script.AssertSomeFingerprint(source_fp, target_fp)
1171 else:
1172 script.AssertSomeThumbprint(
1173 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1174 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1175
Doug Zongker2ea21062010-04-28 16:05:21 -07001176 metadata["pre-build"] = source_fp
1177 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001178
Doug Zongker55d93282011-01-25 17:03:34 -08001179 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001180 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1181 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001182 target_boot = common.GetBootableImage(
1183 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001184 updating_boot = (not OPTIONS.two_step and
1185 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001186
Doug Zongker55d93282011-01-25 17:03:34 -08001187 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001188 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1189 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001190 target_recovery = common.GetBootableImage(
1191 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001192 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001193
Doug Zongker881dd402009-09-20 14:03:55 -07001194 # Here's how we divide up the progress bar:
1195 # 0.1 for verifying the start state (PatchCheck calls)
1196 # 0.8 for applying patches (ApplyPatch calls)
1197 # 0.1 for unpacking verbatim files, symlinking, and doing the
1198 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001199
Michael Runge6e836112014-04-15 17:40:21 -07001200 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001201 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001202
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001203 # Two-step incremental package strategy (in chronological order,
1204 # which is *not* the order in which the generated script has
1205 # things):
1206 #
1207 # if stage is not "2/3" or "3/3":
1208 # do verification on current system
1209 # write recovery image to boot partition
1210 # set stage to "2/3"
1211 # reboot to boot partition and restart recovery
1212 # else if stage is "2/3":
1213 # write recovery image to recovery partition
1214 # set stage to "3/3"
1215 # reboot to recovery partition and restart recovery
1216 # else:
1217 # (stage must be "3/3")
1218 # perform update:
1219 # patch system files, etc.
1220 # force full install of new boot image
1221 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001222 # complete script normally
1223 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001224
1225 if OPTIONS.two_step:
Tao Baodd24da92015-07-29 14:09:23 -07001226 if not OPTIONS.source_info_dict.get("multistage_support", None):
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001227 assert False, "two-step packages not supported by this build"
Tao Baodd24da92015-07-29 14:09:23 -07001228 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001229 assert fs.fs_type.upper() == "EMMC", \
1230 "two-step packages only supported on devices with EMMC /misc partitions"
1231 bcb_dev = {"bcb_dev": fs.device}
1232 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1233 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001234if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001235""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001236 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001237 script.WriteRawImage("/recovery", "recovery.img")
1238 script.AppendExtra("""
1239set_stage("%(bcb_dev)s", "3/3");
1240reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001241else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001242""" % bcb_dev)
1243
Tao Bao6c55a8a2015-04-08 15:30:27 -07001244 # Dump fingerprints
1245 script.Print("Source: %s" % (source_fp,))
1246 script.Print("Target: %s" % (target_fp,))
1247
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001248 script.Print("Verifying current system...")
1249
Doug Zongkere5ff5902012-01-17 10:55:37 -08001250 device_specific.IncrementalOTA_VerifyBegin()
1251
Doug Zongker881dd402009-09-20 14:03:55 -07001252 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001253 so_far = system_diff.EmitVerification(script)
1254 if vendor_diff:
1255 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001256
Doug Zongker5da317e2009-06-02 13:38:17 -07001257 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001258 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001259 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001260 print "boot target: %d source: %d diff: %d" % (
1261 target_boot.size, source_boot.size, len(d))
1262
Doug Zongker048e7ca2009-06-15 14:31:53 -07001263 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001264
Tao Baodd24da92015-07-29 14:09:23 -07001265 boot_type, boot_device = common.GetTypeAndDevice(
1266 "/boot", OPTIONS.source_info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001267
1268 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1269 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001270 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001271 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001272 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001273
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001274 size = []
Dan Albert8b72aef2015-03-23 19:13:21 -07001275 if system_diff.patch_list:
1276 size.append(system_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001277 if vendor_diff:
Dan Albert8b72aef2015-03-23 19:13:21 -07001278 if vendor_diff.patch_list:
1279 size.append(vendor_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001280 if size or updating_recovery or updating_boot:
1281 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001282
Doug Zongker05d3dea2009-06-22 11:32:31 -07001283 device_specific.IncrementalOTA_VerifyEnd()
1284
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001285 if OPTIONS.two_step:
1286 script.WriteRawImage("/boot", "recovery.img")
1287 script.AppendExtra("""
1288set_stage("%(bcb_dev)s", "2/3");
1289reboot_now("%(bcb_dev)s", "");
1290else
1291""" % bcb_dev)
1292
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001293 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001294
Doug Zongkere5ff5902012-01-17 10:55:37 -08001295 device_specific.IncrementalOTA_InstallBegin()
1296
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001297 if OPTIONS.two_step:
1298 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1299 script.WriteRawImage("/boot", "boot.img")
1300 print "writing full boot image (forced by two-step mode)"
1301
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001302 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001303 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1304 if vendor_diff:
1305 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001306
Doug Zongker881dd402009-09-20 14:03:55 -07001307 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001308 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1309 if vendor_diff:
1310 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001311 if updating_boot:
1312 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001313
1314 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001315 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1316 if vendor_diff:
1317 script.Print("Patching vendor files...")
1318 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001319
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001320 if not OPTIONS.two_step:
1321 if updating_boot:
1322 # Produce the boot image by applying a patch to the current
1323 # contents of the boot partition, and write it back to the
1324 # partition.
1325 script.Print("Patching boot image...")
1326 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1327 % (boot_type, boot_device,
1328 source_boot.size, source_boot.sha1,
1329 target_boot.size, target_boot.sha1),
1330 "-",
1331 target_boot.size, target_boot.sha1,
1332 source_boot.sha1, "patch/boot.img.p")
1333 so_far += target_boot.size
1334 script.SetProgress(so_far / total_patch_size)
1335 print "boot image changed; including."
1336 else:
1337 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001338
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001339 system_items = ItemSet("system", "META/filesystem_config.txt")
1340 if vendor_diff:
1341 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1342
Doug Zongkereef39442009-04-02 12:14:19 -07001343 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001344 # Recovery is generated as a patch using both the boot image
1345 # (which contains the same linux kernel as recovery) and the file
1346 # /system/etc/recovery-resource.dat (which contains all the images
1347 # used in the recovery UI) as sources. This lets us minimize the
1348 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001349 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001350 # For older builds where recovery-resource.dat is not present, we
1351 # use only the boot image as the source.
1352
Doug Zongkerc9253822014-02-04 12:17:58 -08001353 if not target_has_recovery_patch:
1354 def output_sink(fn, data):
1355 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001356 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001357
1358 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1359 target_recovery, target_boot)
1360 script.DeleteFiles(["/system/recovery-from-boot.p",
Tao Baof2cffbd2015-07-22 12:33:18 -07001361 "/system/etc/recovery.img",
Doug Zongkerc9253822014-02-04 12:17:58 -08001362 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001363 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001364 else:
1365 print "recovery image unchanged; skipping."
1366
Doug Zongker881dd402009-09-20 14:03:55 -07001367 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001368
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001369 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1370 if vendor_diff:
1371 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1372
1373 temp_script = script.MakeTemporary()
1374 system_items.GetMetadata(target_zip)
1375 system_items.Get("system").SetPermissions(temp_script)
1376 if vendor_diff:
1377 vendor_items.GetMetadata(target_zip)
1378 vendor_items.Get("vendor").SetPermissions(temp_script)
1379
1380 # Note that this call will mess up the trees of Items, so make sure
1381 # we're done with them.
1382 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1383 if vendor_diff:
1384 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001385
1386 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001387 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1388
1389 # Delete all the symlinks in source that aren't in target. This
1390 # needs to happen before verbatim files are unpacked, in case a
1391 # symlink in the source is replaced by a real file in the target.
1392 to_delete = []
1393 for dest, link in source_symlinks:
1394 if link not in target_symlinks_d:
1395 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001396 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001397
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001398 if system_diff.verbatim_targets:
1399 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001400 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001401 if vendor_diff and vendor_diff.verbatim_targets:
1402 script.Print("Unpacking new vendor files...")
1403 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001404
Doug Zongkerc9253822014-02-04 12:17:58 -08001405 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001406 script.Print("Unpacking new recovery...")
1407 script.UnpackPackageDir("recovery", "/system")
1408
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001409 system_diff.EmitRenames(script)
1410 if vendor_diff:
1411 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001412
Doug Zongker05d3dea2009-06-22 11:32:31 -07001413 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001414
1415 # Create all the symlinks that don't already exist, or point to
1416 # somewhere different than what we want. Delete each symlink before
1417 # creating it, since the 'symlink' command won't overwrite.
1418 to_create = []
1419 for dest, link in target_symlinks:
1420 if link in source_symlinks_d:
1421 if dest != source_symlinks_d[link]:
1422 to_create.append((dest, link))
1423 else:
1424 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001425 script.DeleteFiles([i[1] for i in to_create])
1426 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001427
1428 # Now that the symlinks are created, we can set all the
1429 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001430 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001431
Doug Zongker881dd402009-09-20 14:03:55 -07001432 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001433 device_specific.IncrementalOTA_InstallEnd()
1434
Doug Zongker1c390a22009-05-14 19:06:36 -07001435 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001436 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001437
Doug Zongkere92f15a2011-08-26 13:46:40 -07001438 # Patch the build.prop file last, so if something fails but the
1439 # device can still come up, it appears to be the old build and will
1440 # get set the OTA package again to retry.
1441 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001442 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001443
Doug Zongker922206e2014-03-04 13:16:24 -08001444 if OPTIONS.wipe_user_data:
1445 script.Print("Erasing user data...")
1446 script.FormatPartition("/data")
1447
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001448 if OPTIONS.two_step:
1449 script.AppendExtra("""
1450set_stage("%(bcb_dev)s", "");
1451endif;
1452endif;
1453""" % bcb_dev)
1454
Michael Runge63f01de2014-10-28 19:24:19 -07001455 if OPTIONS.verify and system_diff:
1456 script.Print("Remounting and verifying system partition files...")
1457 script.Unmount("/system")
1458 script.Mount("/system")
1459 system_diff.EmitExplicitTargetVerification(script)
1460
1461 if OPTIONS.verify and vendor_diff:
1462 script.Print("Remounting and verifying vendor partition files...")
1463 script.Unmount("/vendor")
1464 script.Mount("/vendor")
1465 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001466 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001467
Doug Zongker2ea21062010-04-28 16:05:21 -07001468 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001469
1470
1471def main(argv):
1472
1473 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001474 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001475 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001476 elif o in ("-k", "--package_key"):
1477 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001478 elif o in ("-i", "--incremental_from"):
1479 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001480 elif o == "--full_radio":
1481 OPTIONS.full_radio = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001482 elif o in ("-w", "--wipe_user_data"):
1483 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001484 elif o in ("-n", "--no_prereq"):
1485 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001486 elif o in ("-o", "--oem_settings"):
1487 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001488 elif o in ("-e", "--extra_script"):
1489 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001490 elif o in ("-a", "--aslr_mode"):
1491 if a in ("on", "On", "true", "True", "yes", "Yes"):
1492 OPTIONS.aslr_mode = True
1493 else:
1494 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001495 elif o in ("-t", "--worker_threads"):
1496 if a.isdigit():
1497 OPTIONS.worker_threads = int(a)
1498 else:
1499 raise ValueError("Cannot parse value %r for option %r - only "
1500 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001501 elif o in ("-2", "--two_step"):
1502 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001503 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001504 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001505 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001506 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001507 elif o == "--block":
1508 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001509 elif o in ("-b", "--binary"):
1510 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001511 elif o in ("--no_fallback_to_full",):
1512 OPTIONS.fallback_to_full = False
Tao Bao8dcf7382015-05-21 14:09:49 -07001513 elif o == "--stash_threshold":
1514 try:
1515 OPTIONS.stash_threshold = float(a)
1516 except ValueError:
1517 raise ValueError("Cannot parse value %r for option %r - expecting "
1518 "a float" % (a, o))
Doug Zongkereef39442009-04-02 12:14:19 -07001519 else:
1520 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001521 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001522
1523 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001524 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001525 extra_long_opts=[
1526 "board_config=",
1527 "package_key=",
1528 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001529 "full_radio",
Dan Albert8b72aef2015-03-23 19:13:21 -07001530 "wipe_user_data",
1531 "no_prereq",
1532 "extra_script=",
1533 "worker_threads=",
1534 "aslr_mode=",
1535 "two_step",
1536 "no_signing",
1537 "block",
1538 "binary=",
1539 "oem_settings=",
1540 "verify",
1541 "no_fallback_to_full",
Tao Bao8dcf7382015-05-21 14:09:49 -07001542 "stash_threshold=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001543 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001544
1545 if len(args) != 2:
1546 common.Usage(__doc__)
1547 sys.exit(1)
1548
Doug Zongker1c390a22009-05-14 19:06:36 -07001549 if OPTIONS.extra_script is not None:
1550 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1551
Doug Zongkereef39442009-04-02 12:14:19 -07001552 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001553 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001554
Doug Zongkereef39442009-04-02 12:14:19 -07001555 OPTIONS.target_tmp = OPTIONS.input_tmp
Tao Bao2c15d9e2015-07-09 11:51:16 -07001556 OPTIONS.info_dict = common.LoadInfoDict(input_zip, OPTIONS.target_tmp)
Kenny Roote2e9f612013-05-29 12:59:35 -07001557
Doug Zongker37974732010-09-16 17:44:38 -07001558 if OPTIONS.verbose:
1559 print "--- target info ---"
1560 common.DumpInfoDict(OPTIONS.info_dict)
1561
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001562 # If the caller explicitly specified the device-specific extensions
1563 # path via -s/--device_specific, use that. Otherwise, use
1564 # META/releasetools.py if it is present in the target target_files.
1565 # Otherwise, take the path of the file from 'tool_extensions' in the
1566 # info dict and look for that in the local filesystem, relative to
1567 # the current directory.
1568
Doug Zongker37974732010-09-16 17:44:38 -07001569 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001570 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1571 if os.path.exists(from_input):
1572 print "(using device-specific extensions from target_files)"
1573 OPTIONS.device_specific = from_input
1574 else:
1575 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1576
Doug Zongker37974732010-09-16 17:44:38 -07001577 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001578 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001579
Doug Zongker62d4f182014-08-04 16:06:43 -07001580 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001581
Doug Zongker62d4f182014-08-04 16:06:43 -07001582 if OPTIONS.no_signing:
Dan Albert8b72aef2015-03-23 19:13:21 -07001583 if os.path.exists(args[1]):
1584 os.unlink(args[1])
1585 output_zip = zipfile.ZipFile(args[1], "w",
1586 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001587 else:
1588 temp_zip_file = tempfile.NamedTemporaryFile()
1589 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1590 compression=zipfile.ZIP_DEFLATED)
1591
Tao Bao8dcf7382015-05-21 14:09:49 -07001592 cache_size = OPTIONS.info_dict.get("cache_size", None)
1593 if cache_size is None:
Tao Bao575d68a2015-08-07 19:49:45 -07001594 print "--- can't determine the cache partition size ---"
Tao Bao8dcf7382015-05-21 14:09:49 -07001595 OPTIONS.cache_size = cache_size
1596
Doug Zongker62d4f182014-08-04 16:06:43 -07001597 if OPTIONS.incremental_source is None:
1598 WriteFullOTAPackage(input_zip, output_zip)
1599 if OPTIONS.package_key is None:
1600 OPTIONS.package_key = OPTIONS.info_dict.get(
1601 "default_system_dev_certificate",
1602 "build/target/product/security/testkey")
Tao Bao2ed665a2015-04-01 11:21:55 -07001603 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001604 break
1605
1606 else:
1607 print "unzipping source target-files..."
Dan Albert8b72aef2015-03-23 19:13:21 -07001608 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
1609 OPTIONS.incremental_source)
Doug Zongker62d4f182014-08-04 16:06:43 -07001610 OPTIONS.target_info_dict = OPTIONS.info_dict
Tao Bao2c15d9e2015-07-09 11:51:16 -07001611 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip,
1612 OPTIONS.source_tmp)
Doug Zongker62d4f182014-08-04 16:06:43 -07001613 if OPTIONS.package_key is None:
1614 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1615 "default_system_dev_certificate",
1616 "build/target/product/security/testkey")
1617 if OPTIONS.verbose:
1618 print "--- source info ---"
1619 common.DumpInfoDict(OPTIONS.source_info_dict)
1620 try:
1621 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Bao2ed665a2015-04-01 11:21:55 -07001622 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001623 break
1624 except ValueError:
Dan Albert8b72aef2015-03-23 19:13:21 -07001625 if not OPTIONS.fallback_to_full:
1626 raise
Doug Zongker62d4f182014-08-04 16:06:43 -07001627 print "--- failed to build incremental; falling back to full ---"
1628 OPTIONS.incremental_source = None
Tao Bao2ed665a2015-04-01 11:21:55 -07001629 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001630
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001631 if not OPTIONS.no_signing:
1632 SignOutput(temp_zip_file.name, args[1])
1633 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001634
Doug Zongkereef39442009-04-02 12:14:19 -07001635 print "done."
1636
1637
1638if __name__ == '__main__':
1639 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001640 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001641 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001642 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07001643 print
1644 print " ERROR: %s" % (e,)
1645 print
1646 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001647 finally:
1648 common.Cleanup()