blob: 4e860659b34f6ef2675af321632345730140c77a [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
leozwangaa6c1a12015-08-14 10:57:58 -070045 --full_bootloader
46 Similar to --full_radio. When generating an incremental OTA, always
47 include a full copy of bootloader image.
48
Michael Runge63f01de2014-10-28 19:24:19 -070049 -v (--verify)
50 Remount and verify the checksums of the files written to the
51 system and vendor (if used) partitions. Incremental builds only.
52
Michael Runge6e836112014-04-15 17:40:21 -070053 -o (--oem_settings) <file>
54 Use the file to specify the expected OEM-specific properties
55 on the OEM partition of the intended device.
56
Doug Zongkerdbfaae52009-04-21 17:12:54 -070057 -w (--wipe_user_data)
58 Generate an OTA package that will wipe the user data partition
59 when installed.
60
Doug Zongker962069c2009-04-23 11:41:58 -070061 -n (--no_prereq)
62 Omit the timestamp prereq check normally included at the top of
63 the build scripts (used for developer OTA packages which
64 legitimately need to go back and forth).
65
Doug Zongker1c390a22009-05-14 19:06:36 -070066 -e (--extra_script) <file>
67 Insert the contents of file at the end of the update script.
68
Hristo Bojinovdafb0422010-08-26 14:35:16 -070069 -a (--aslr_mode) <on|off>
70 Specify whether to turn on ASLR for the package (on by default).
Stephen Smalley56882bf2012-02-09 13:36:21 -050071
Doug Zongker9b23f2c2013-11-25 14:44:12 -080072 -2 (--two_step)
73 Generate a 'two-step' OTA package, where recovery is updated
74 first, so that any changes made to the system partition are done
75 using the new recovery (new kernel, etc.).
76
Doug Zongker26e66192014-02-20 13:22:07 -080077 --block
78 Generate a block-based OTA if possible. Will fall back to a
79 file-based OTA if the target_files is older and doesn't support
80 block-based OTAs.
81
Doug Zongker25568482014-03-03 10:21:27 -080082 -b (--binary) <file>
83 Use the given binary as the update-binary in the output package,
84 instead of the binary in the build's target_files. Use for
85 development only.
86
Martin Blumenstingl374e1142014-05-31 20:42:55 +020087 -t (--worker_threads) <int>
88 Specifies the number of worker-threads that will be used when
89 generating patches for incremental updates (defaults to 3).
90
Tao Bao8dcf7382015-05-21 14:09:49 -070091 --stash_threshold <float>
92 Specifies the threshold that will be used to compute the maximum
93 allowed stash size (defaults to 0.8).
Doug Zongkereef39442009-04-02 12:14:19 -070094"""
95
96import sys
97
Doug Zongkercf6d5a92014-02-18 10:57:07 -080098if sys.hexversion < 0x02070000:
99 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -0700100 sys.exit(1)
101
Doug Zongkerfc44a512014-08-26 13:10:25 -0700102import multiprocessing
Doug Zongkereef39442009-04-02 12:14:19 -0700103import os
Doug Zongkereef39442009-04-02 12:14:19 -0700104import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -0700105import zipfile
106
107import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700108import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -0700109import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700110
111OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700112OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700113OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700114OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700115OPTIONS.require_verbatim = set()
116OPTIONS.prohibit_verbatim = set(("system/build.prop",))
117OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700118OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700119OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700120OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700121OPTIONS.aslr_mode = True
Doug Zongkerfc44a512014-08-26 13:10:25 -0700122OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
123if OPTIONS.worker_threads == 0:
124 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800125OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900126OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800127OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800128OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700129OPTIONS.oem_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -0700130OPTIONS.fallback_to_full = True
Tao Bao43078aa2015-04-21 14:32:35 -0700131OPTIONS.full_radio = False
leozwangaa6c1a12015-08-14 10:57:58 -0700132OPTIONS.full_bootloader = False
Tao Bao8dcf7382015-05-21 14:09:49 -0700133
Doug Zongkereef39442009-04-02 12:14:19 -0700134
135def MostPopularKey(d, default):
136 """Given a dict, return the key corresponding to the largest
137 value. Returns 'default' if the dict is empty."""
138 x = [(v, k) for (k, v) in d.iteritems()]
Dan Albert8b72aef2015-03-23 19:13:21 -0700139 if not x:
140 return default
Doug Zongkereef39442009-04-02 12:14:19 -0700141 x.sort()
142 return x[-1][1]
143
144
145def IsSymlink(info):
146 """Return true if the zipfile.ZipInfo object passed in represents a
147 symlink."""
Ying Wang2ffb3142015-07-06 14:02:01 -0700148 return (info.external_attr >> 16) & 0o770000 == 0o120000
Doug Zongkereef39442009-04-02 12:14:19 -0700149
Hristo Bojinov96be7202010-08-02 10:26:17 -0700150def IsRegular(info):
151 """Return true if the zipfile.ZipInfo object passed in represents a
Ying Wang2ffb3142015-07-06 14:02:01 -0700152 regular file."""
153 return (info.external_attr >> 16) & 0o770000 == 0o100000
Doug Zongkereef39442009-04-02 12:14:19 -0700154
Michael Runge4038aa82013-12-13 18:06:28 -0800155def ClosestFileMatch(src, tgtfiles, existing):
156 """Returns the closest file match between a source file and list
157 of potential matches. The exact filename match is preferred,
158 then the sha1 is searched for, and finally a file with the same
159 basename is evaluated. Rename support in the updater-binary is
160 required for the latter checks to be used."""
161
162 result = tgtfiles.get("path:" + src.name)
163 if result is not None:
164 return result
165
166 if not OPTIONS.target_info_dict.get("update_rename_support", False):
167 return None
168
169 if src.size < 1000:
170 return None
171
172 result = tgtfiles.get("sha1:" + src.sha1)
173 if result is not None and existing.get(result.name) is None:
174 return result
175 result = tgtfiles.get("file:" + src.name.split("/")[-1])
176 if result is not None and existing.get(result.name) is None:
177 return result
178 return None
179
Dan Albert8b72aef2015-03-23 19:13:21 -0700180class ItemSet(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700181 def __init__(self, partition, fs_config):
182 self.partition = partition
183 self.fs_config = fs_config
184 self.ITEMS = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700185
Dan Albert8b72aef2015-03-23 19:13:21 -0700186 def Get(self, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700187 if name not in self.ITEMS:
Dan Albert8b72aef2015-03-23 19:13:21 -0700188 self.ITEMS[name] = Item(self, name, is_dir=is_dir)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700189 return self.ITEMS[name]
Doug Zongkereef39442009-04-02 12:14:19 -0700190
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700191 def GetMetadata(self, input_zip):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700192 # The target_files contains a record of what the uid,
193 # gid, and mode are supposed to be.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700194 output = input_zip.read(self.fs_config)
Doug Zongkereef39442009-04-02 12:14:19 -0700195
196 for line in output.split("\n"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700197 if not line:
198 continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700199 columns = line.split()
200 name, uid, gid, mode = columns[:4]
201 selabel = None
202 capabilities = None
203
204 # After the first 4 columns, there are a series of key=value
205 # pairs. Extract out the fields we care about.
206 for element in columns[4:]:
207 key, value = element.split("=")
208 if key == "selabel":
209 selabel = value
210 if key == "capabilities":
211 capabilities = value
212
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700213 i = self.ITEMS.get(name, None)
Doug Zongker283e2a12010-03-15 17:52:32 -0700214 if i is not None:
215 i.uid = int(uid)
216 i.gid = int(gid)
217 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700218 i.selabel = selabel
219 i.capabilities = capabilities
Dan Albert8b72aef2015-03-23 19:13:21 -0700220 if i.is_dir:
Doug Zongker283e2a12010-03-15 17:52:32 -0700221 i.children.sort(key=lambda i: i.name)
222
Tao Baof2cffbd2015-07-22 12:33:18 -0700223 # Set metadata for the files generated by this script. For full recovery
224 # image at system/etc/recovery.img, it will be taken care by fs_config.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700225 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700226 if i:
227 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700228 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700229 if i:
230 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700231
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700232
Dan Albert8b72aef2015-03-23 19:13:21 -0700233class Item(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700234 """Items represent the metadata (user, group, mode) of files and
235 directories in the system image."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700236 def __init__(self, itemset, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700237 self.itemset = itemset
238 self.name = name
239 self.uid = None
240 self.gid = None
241 self.mode = None
242 self.selabel = None
243 self.capabilities = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700244 self.is_dir = is_dir
245 self.descendants = None
246 self.best_subtree = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700247
248 if name:
Dan Albert8b72aef2015-03-23 19:13:21 -0700249 self.parent = itemset.Get(os.path.dirname(name), is_dir=True)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700250 self.parent.children.append(self)
251 else:
252 self.parent = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700253 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700254 self.children = []
255
256 def Dump(self, indent=0):
257 if self.uid is not None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700258 print "%s%s %d %d %o" % (
259 " " * indent, self.name, self.uid, self.gid, self.mode)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700260 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700261 print "%s%s %s %s %s" % (
262 " " * indent, self.name, self.uid, self.gid, self.mode)
263 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700264 print "%s%s" % (" "*indent, self.descendants)
265 print "%s%s" % (" "*indent, self.best_subtree)
266 for i in self.children:
267 i.Dump(indent=indent+1)
268
Doug Zongkereef39442009-04-02 12:14:19 -0700269 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700270 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
Dan Albert8b72aef2015-03-23 19:13:21 -0700271 all children and determine the best strategy for using set_perm_recursive
272 and set_perm to correctly chown/chmod all the files to their desired
Doug Zongkereef39442009-04-02 12:14:19 -0700273 values. Recursively calls itself for all descendants.
274
Dan Albert8b72aef2015-03-23 19:13:21 -0700275 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count}
276 counting up all descendants of this node. (dmode or fmode may be None.)
277 Also sets the best_subtree of each directory Item to the (uid, gid, dmode,
278 fmode, selabel, capabilities) tuple that will match the most descendants of
279 that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700280 """
281
Dan Albert8b72aef2015-03-23 19:13:21 -0700282 assert self.is_dir
283 key = (self.uid, self.gid, self.mode, None, self.selabel,
284 self.capabilities)
285 self.descendants = {key: 1}
286 d = self.descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700287 for i in self.children:
Dan Albert8b72aef2015-03-23 19:13:21 -0700288 if i.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700289 for k, v in i.CountChildMetadata().iteritems():
290 d[k] = d.get(k, 0) + v
291 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700292 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700293 d[k] = d.get(k, 0) + 1
294
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700295 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
296 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700297
298 # First, find the (uid, gid) pair that matches the most
299 # descendants.
300 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700301 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700302 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
303 ug = MostPopularKey(ug, (0, 0))
304
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700305 # Now find the dmode, fmode, selabel, and capabilities that match
306 # the most descendants with that (uid, gid), and choose those.
Dan Albert8b72aef2015-03-23 19:13:21 -0700307 best_dmode = (0, 0o755)
308 best_fmode = (0, 0o644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700309 best_selabel = (0, None)
310 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700311 for k, count in d.iteritems():
Dan Albert8b72aef2015-03-23 19:13:21 -0700312 if k[:2] != ug:
313 continue
314 if k[2] is not None and count >= best_dmode[0]:
315 best_dmode = (count, k[2])
316 if k[3] is not None and count >= best_fmode[0]:
317 best_fmode = (count, k[3])
318 if k[4] is not None and count >= best_selabel[0]:
319 best_selabel = (count, k[4])
320 if k[5] is not None and count >= best_capabilities[0]:
321 best_capabilities = (count, k[5])
322 self.best_subtree = ug + (
323 best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700324
325 return d
326
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700327 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700328 """Append set_perm/set_perm_recursive commands to 'script' to
329 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700330 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700331
332 self.CountChildMetadata()
333
334 def recurse(item, current):
Dan Albert8b72aef2015-03-23 19:13:21 -0700335 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple
336 # that the current item (and all its children) have already been set to.
337 # We only need to issue set_perm/set_perm_recursive commands if we're
Doug Zongkereef39442009-04-02 12:14:19 -0700338 # supposed to be something different.
Dan Albert8b72aef2015-03-23 19:13:21 -0700339 if item.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700340 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700341 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700342 current = item.best_subtree
343
344 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700345 item.mode != current[2] or item.selabel != current[4] or \
346 item.capabilities != current[5]:
347 script.SetPermissions("/"+item.name, item.uid, item.gid,
348 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700349
350 for i in item.children:
351 recurse(i, current)
352 else:
353 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700354 item.mode != current[3] or item.selabel != current[4] or \
355 item.capabilities != current[5]:
356 script.SetPermissions("/"+item.name, item.uid, item.gid,
357 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700358
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700359 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700360
361
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700362def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
363 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700364 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800365 list of symlinks. output_zip may be None, in which case the copy is
366 skipped (but the other side effects still happen). substitute is an
367 optional dict of {output filename: contents} to be output instead of
368 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700369 """
370
371 symlinks = []
372
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700373 partition = itemset.partition
374
Doug Zongkereef39442009-04-02 12:14:19 -0700375 for info in input_zip.infolist():
Tao Baoeaf885b2015-03-23 16:01:17 -0700376 prefix = partition.upper() + "/"
377 if info.filename.startswith(prefix):
378 basefilename = info.filename[len(prefix):]
Doug Zongkereef39442009-04-02 12:14:19 -0700379 if IsSymlink(info):
380 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700381 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700382 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700383 import copy
Doug Zongkereef39442009-04-02 12:14:19 -0700384 info2 = copy.copy(info)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700385 fn = info2.filename = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700386 if substitute and fn in substitute and substitute[fn] is None:
387 continue
388 if output_zip is not None:
389 if substitute and fn in substitute:
390 data = substitute[fn]
391 else:
392 data = input_zip.read(info.filename)
Tao Bao2ed665a2015-04-01 11:21:55 -0700393 common.ZipWriteStr(output_zip, info2, data)
Doug Zongkereef39442009-04-02 12:14:19 -0700394 if fn.endswith("/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700395 itemset.Get(fn[:-1], is_dir=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700396 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700397 itemset.Get(fn)
Doug Zongkereef39442009-04-02 12:14:19 -0700398
399 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800400 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700401
402
Doug Zongkereef39442009-04-02 12:14:19 -0700403def SignOutput(temp_zip_name, output_zip_name):
404 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
405 pw = key_passwords[OPTIONS.package_key]
406
Doug Zongker951495f2009-08-14 12:44:19 -0700407 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
408 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700409
410
Dan Albert8b72aef2015-03-23 19:13:21 -0700411def AppendAssertions(script, info_dict, oem_dict=None):
Michael Runge6e836112014-04-15 17:40:21 -0700412 oem_props = info_dict.get("oem_fingerprint_properties")
Michael Runge560569a2014-09-18 15:12:45 -0700413 if oem_props is None or len(oem_props) == 0:
Michael Runge6e836112014-04-15 17:40:21 -0700414 device = GetBuildProp("ro.product.device", info_dict)
415 script.AssertDevice(device)
416 else:
417 if oem_dict is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700418 raise common.ExternalError(
419 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700420 for prop in oem_props.split():
421 if oem_dict.get(prop) is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700422 raise common.ExternalError(
423 "The OEM file is missing the property %s" % prop)
Michael Runge6e836112014-04-15 17:40:21 -0700424 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700425
Doug Zongkereef39442009-04-02 12:14:19 -0700426
Doug Zongkerc9253822014-02-04 12:17:58 -0800427def HasRecoveryPatch(target_files_zip):
Tao Baof2cffbd2015-07-22 12:33:18 -0700428 namelist = [name for name in target_files_zip.namelist()]
429 return ("SYSTEM/recovery-from-boot.p" in namelist or
430 "SYSTEM/etc/recovery.img" in namelist)
Doug Zongker73ef8252009-07-23 15:12:53 -0700431
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700432def HasVendorPartition(target_files_zip):
433 try:
434 target_files_zip.getinfo("VENDOR/")
435 return True
436 except KeyError:
437 return False
438
Michael Runge6e836112014-04-15 17:40:21 -0700439def GetOemProperty(name, oem_props, oem_dict, info_dict):
440 if oem_props is not None and name in oem_props:
441 return oem_dict[name]
442 return GetBuildProp(name, info_dict)
443
444
445def CalculateFingerprint(oem_props, oem_dict, info_dict):
446 if oem_props is None:
447 return GetBuildProp("ro.build.fingerprint", info_dict)
448 return "%s/%s/%s:%s" % (
Dan Albert8b72aef2015-03-23 19:13:21 -0700449 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
450 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
451 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
452 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700453
Doug Zongkerfc44a512014-08-26 13:10:25 -0700454
Doug Zongker3c84f562014-07-31 11:06:30 -0700455def GetImage(which, tmpdir, info_dict):
Doug Zongkerfc44a512014-08-26 13:10:25 -0700456 # Return an image object (suitable for passing to BlockImageDiff)
457 # for the 'which' partition (most be "system" or "vendor"). If a
458 # prebuilt image and file map are found in tmpdir they are used,
459 # otherwise they are reconstructed from the individual files.
Doug Zongker3c84f562014-07-31 11:06:30 -0700460
461 assert which in ("system", "vendor")
462
463 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700464 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
465 if os.path.exists(path) and os.path.exists(mappath):
Doug Zongker3c84f562014-07-31 11:06:30 -0700466 print "using %s.img from target-files" % (which,)
Doug Zongker3c84f562014-07-31 11:06:30 -0700467 # This is a 'new' target-files, which already has the image in it.
Doug Zongker3c84f562014-07-31 11:06:30 -0700468
469 else:
470 print "building %s.img from target-files" % (which,)
471
472 # This is an 'old' target-files, which does not contain images
473 # already built. Build them.
474
Doug Zongkerfc44a512014-08-26 13:10:25 -0700475 mappath = tempfile.mkstemp()[1]
476 OPTIONS.tempfiles.append(mappath)
477
Doug Zongker3c84f562014-07-31 11:06:30 -0700478 import add_img_to_target_files
479 if which == "system":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700480 path = add_img_to_target_files.BuildSystem(
481 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700482 elif which == "vendor":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700483 path = add_img_to_target_files.BuildVendor(
484 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700485
Tao Baoff777812015-05-12 11:42:31 -0700486 # Bug: http://b/20939131
487 # In ext4 filesystems, block 0 might be changed even being mounted
488 # R/O. We add it to clobbered_blocks so that it will be written to the
489 # target unconditionally. Note that they are still part of care_map.
490 clobbered_blocks = "0"
491
492 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700493
494
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700495def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700496 # TODO: how to determine this? We don't know what version it will
Tao Bao34b47bf2015-06-22 19:17:41 -0700497 # be installed on top of. For now, we expect the API just won't
498 # change very often. Similarly for fstab, it might have changed
499 # in the target build.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700500 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700501
Michael Runge6e836112014-04-15 17:40:21 -0700502 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700503 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700504 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700505 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700506 if OPTIONS.oem_source is None:
507 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700508 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700509 oem_dict = common.LoadDictionaryFromLines(
510 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -0700511
Dan Albert8b72aef2015-03-23 19:13:21 -0700512 metadata = {
513 "post-build": CalculateFingerprint(oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700514 OPTIONS.info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700515 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
516 OPTIONS.info_dict),
517 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
518 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700519
Doug Zongker05d3dea2009-06-22 11:32:31 -0700520 device_specific = common.DeviceSpecificParams(
521 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700522 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700523 output_zip=output_zip,
524 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700525 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700526 metadata=metadata,
527 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700528
Doug Zongkerc9253822014-02-04 12:17:58 -0800529 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800530 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800531
Doug Zongker962069c2009-04-23 11:41:58 -0700532 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700533 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700534 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
535 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700536
Michael Runge6e836112014-04-15 17:40:21 -0700537 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700538 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800539
540 # Two-step package strategy (in chronological order, which is *not*
541 # the order in which the generated script has things):
542 #
543 # if stage is not "2/3" or "3/3":
544 # write recovery image to boot partition
545 # set stage to "2/3"
546 # reboot to boot partition and restart recovery
547 # else if stage is "2/3":
548 # write recovery image to recovery partition
549 # set stage to "3/3"
550 # reboot to recovery partition and restart recovery
551 # else:
552 # (stage must be "3/3")
553 # set stage to ""
554 # do normal full package installation:
555 # wipe and install system, boot image, etc.
556 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700557 # complete script normally
558 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800559
560 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
561 OPTIONS.input_tmp, "RECOVERY")
562 if OPTIONS.two_step:
563 if not OPTIONS.info_dict.get("multistage_support", None):
564 assert False, "two-step packages not supported by this build"
565 fs = OPTIONS.info_dict["fstab"]["/misc"]
566 assert fs.fs_type.upper() == "EMMC", \
567 "two-step packages only supported on devices with EMMC /misc partitions"
568 bcb_dev = {"bcb_dev": fs.device}
569 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
570 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700571if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800572""" % bcb_dev)
573 script.WriteRawImage("/recovery", "recovery.img")
574 script.AppendExtra("""
575set_stage("%(bcb_dev)s", "3/3");
576reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700577else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800578""" % bcb_dev)
579
Tao Bao6c55a8a2015-04-08 15:30:27 -0700580 # Dump fingerprints
581 script.Print("Target: %s" % CalculateFingerprint(
582 oem_props, oem_dict, OPTIONS.info_dict))
583
Doug Zongkere5ff5902012-01-17 10:55:37 -0800584 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700585
Doug Zongker01ce19c2014-02-04 13:48:15 -0800586 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700587
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700588 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800589 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700590 if HasVendorPartition(input_zip):
591 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700592
Stephen Smalleyd3a803e2015-08-04 14:59:06 -0400593 # Place a copy of file_contexts.bin into the OTA package which will be used
594 # by the recovery program.
Kenny Rootf32dc712012-04-08 10:42:34 -0700595 if "selinux_fc" in OPTIONS.info_dict:
596 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500597
Michael Runge7cd99ba2014-10-22 17:21:48 -0700598 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
599
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700600 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700601 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800602
Doug Zongker26e66192014-02-20 13:22:07 -0800603 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700604 # Full OTA is done as an "incremental" against an empty source
605 # image. This has the effect of writing new data from the package
606 # to the entire partition, but lets us reuse the updater code that
607 # writes incrementals to do it.
608 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
609 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700610 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700611 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800612 else:
613 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700614 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800615 if not has_recovery_patch:
616 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800617 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700618
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700619 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800620 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700621
Tao Bao7a5bf8a2015-07-21 18:01:20 -0700622 boot_img = common.GetBootableImage(
623 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800624
Doug Zongker91a99c22014-05-09 13:15:01 -0700625 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800626 def output_sink(fn, data):
627 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700628 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800629
630 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
631 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700632
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700633 system_items.GetMetadata(input_zip)
634 system_items.Get("system").SetPermissions(script)
635
636 if HasVendorPartition(input_zip):
637 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
638 script.ShowProgress(0.1, 0)
639
640 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700641 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
642 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700643 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700644 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700645 else:
646 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700647 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700648 script.UnpackPackageDir("vendor", "/vendor")
649
650 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
651 script.MakeSymlinks(symlinks)
652
653 vendor_items.GetMetadata(input_zip)
654 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700655
Doug Zongker37974732010-09-16 17:44:38 -0700656 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700657 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700658
Doug Zongker01ce19c2014-02-04 13:48:15 -0800659 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700660 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700661
Doug Zongker01ce19c2014-02-04 13:48:15 -0800662 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700663 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700664
Doug Zongker1c390a22009-05-14 19:06:36 -0700665 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700666 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700667
Doug Zongker14833602010-02-02 13:12:04 -0800668 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800669
Doug Zongker922206e2014-03-04 13:16:24 -0800670 if OPTIONS.wipe_user_data:
671 script.ShowProgress(0.1, 10)
672 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700673
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800674 if OPTIONS.two_step:
675 script.AppendExtra("""
676set_stage("%(bcb_dev)s", "");
677""" % bcb_dev)
678 script.AppendExtra("else\n")
679 script.WriteRawImage("/boot", "recovery.img")
680 script.AppendExtra("""
681set_stage("%(bcb_dev)s", "2/3");
682reboot_now("%(bcb_dev)s", "");
683endif;
684endif;
685""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800686 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700687 WriteMetadata(metadata, output_zip)
688
Doug Zongkerfc44a512014-08-26 13:10:25 -0700689
Dan Albert8e0178d2015-01-27 15:53:15 -0800690def WritePolicyConfig(file_name, output_zip):
691 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500692
Doug Zongker2ea21062010-04-28 16:05:21 -0700693
694def WriteMetadata(metadata, output_zip):
695 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
696 "".join(["%s=%s\n" % kv
697 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700698
Doug Zongkerfc44a512014-08-26 13:10:25 -0700699
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700700def LoadPartitionFiles(z, partition):
701 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700702 ZipFile, and return a dict of {filename: File object}."""
703 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700704 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700705 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700706 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700707 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700708 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700709 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700710 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800711 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700712
713
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700714def GetBuildProp(prop, info_dict):
715 """Return the fingerprint of the build of a given target-files info_dict."""
716 try:
717 return info_dict.get("build.prop", {})[prop]
718 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700719 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700720
Doug Zongkerfc44a512014-08-26 13:10:25 -0700721
Michael Runge4038aa82013-12-13 18:06:28 -0800722def AddToKnownPaths(filename, known_paths):
723 if filename[-1] == "/":
724 return
725 dirs = filename.split("/")[:-1]
726 while len(dirs) > 0:
727 path = "/".join(dirs)
728 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700729 break
Michael Runge4038aa82013-12-13 18:06:28 -0800730 known_paths.add(path)
731 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700732
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700733
Geremy Condra36bd3652014-02-06 19:45:10 -0800734def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
Tao Bao3806c232015-07-05 21:08:33 -0700735 # TODO(tbao): We should factor out the common parts between
736 # WriteBlockIncrementalOTAPackage() and WriteIncrementalOTAPackage().
Geremy Condra36bd3652014-02-06 19:45:10 -0800737 source_version = OPTIONS.source_info_dict["recovery_api_version"]
738 target_version = OPTIONS.target_info_dict["recovery_api_version"]
739
740 if source_version == 0:
741 print ("WARNING: generating edify script for a source that "
742 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -0700743 script = edify_generator.EdifyGenerator(
744 source_version, OPTIONS.target_info_dict,
745 fstab=OPTIONS.source_info_dict["fstab"])
Geremy Condra36bd3652014-02-06 19:45:10 -0800746
Tao Bao3806c232015-07-05 21:08:33 -0700747 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
748 recovery_mount_options = OPTIONS.source_info_dict.get(
749 "recovery_mount_options")
750 oem_dict = None
751 if oem_props is not None and len(oem_props) > 0:
752 if OPTIONS.oem_source is None:
753 raise common.ExternalError("OEM source required for this build")
754 script.Mount("/oem", recovery_mount_options)
755 oem_dict = common.LoadDictionaryFromLines(
756 open(OPTIONS.oem_source).readlines())
757
Dan Albert8b72aef2015-03-23 19:13:21 -0700758 metadata = {
Tao Bao3806c232015-07-05 21:08:33 -0700759 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
760 OPTIONS.source_info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700761 "post-timestamp": GetBuildProp("ro.build.date.utc",
762 OPTIONS.target_info_dict),
763 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800764
765 device_specific = common.DeviceSpecificParams(
766 source_zip=source_zip,
767 source_version=source_version,
768 target_zip=target_zip,
769 target_version=target_version,
770 output_zip=output_zip,
771 script=script,
772 metadata=metadata,
Tao Bao6f0b2192015-10-13 16:37:12 -0700773 info_dict=OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800774
Tao Bao3806c232015-07-05 21:08:33 -0700775 source_fp = CalculateFingerprint(oem_props, oem_dict,
776 OPTIONS.source_info_dict)
777 target_fp = CalculateFingerprint(oem_props, oem_dict,
778 OPTIONS.target_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800779 metadata["pre-build"] = source_fp
780 metadata["post-build"] = target_fp
781
782 source_boot = common.GetBootableImage(
783 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
784 OPTIONS.source_info_dict)
785 target_boot = common.GetBootableImage(
786 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
787 updating_boot = (not OPTIONS.two_step and
788 (source_boot.data != target_boot.data))
789
Geremy Condra36bd3652014-02-06 19:45:10 -0800790 target_recovery = common.GetBootableImage(
791 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800792
Doug Zongkerfc44a512014-08-26 13:10:25 -0700793 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
794 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700795
796 blockimgdiff_version = 1
797 if OPTIONS.info_dict:
798 blockimgdiff_version = max(
799 int(i) for i in
800 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
801
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700802 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700803 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700804
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700805 if HasVendorPartition(target_zip):
806 if not HasVendorPartition(source_zip):
807 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700808 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
809 OPTIONS.source_info_dict)
810 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
811 OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700812 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700813 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700814 else:
815 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800816
Michael Rungec6e3afd2014-05-05 11:55:47 -0700817 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800818 device_specific.IncrementalOTA_Assertions()
819
820 # Two-step incremental package strategy (in chronological order,
821 # which is *not* the order in which the generated script has
822 # things):
823 #
824 # if stage is not "2/3" or "3/3":
825 # do verification on current system
826 # write recovery image to boot partition
827 # set stage to "2/3"
828 # reboot to boot partition and restart recovery
829 # else if stage is "2/3":
830 # write recovery image to recovery partition
831 # set stage to "3/3"
832 # reboot to recovery partition and restart recovery
833 # else:
834 # (stage must be "3/3")
835 # perform update:
836 # patch system files, etc.
837 # force full install of new boot image
838 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700839 # complete script normally
840 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800841
842 if OPTIONS.two_step:
Tao Baodd24da92015-07-29 14:09:23 -0700843 if not OPTIONS.source_info_dict.get("multistage_support", None):
Geremy Condra36bd3652014-02-06 19:45:10 -0800844 assert False, "two-step packages not supported by this build"
Tao Baodd24da92015-07-29 14:09:23 -0700845 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Geremy Condra36bd3652014-02-06 19:45:10 -0800846 assert fs.fs_type.upper() == "EMMC", \
847 "two-step packages only supported on devices with EMMC /misc partitions"
848 bcb_dev = {"bcb_dev": fs.device}
849 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
850 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700851if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800852""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -0700853 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800854 script.WriteRawImage("/recovery", "recovery.img")
855 script.AppendExtra("""
856set_stage("%(bcb_dev)s", "3/3");
857reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700858else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800859""" % bcb_dev)
860
Tao Bao6c55a8a2015-04-08 15:30:27 -0700861 # Dump fingerprints
862 script.Print("Source: %s" % CalculateFingerprint(
863 oem_props, oem_dict, OPTIONS.source_info_dict))
864 script.Print("Target: %s" % CalculateFingerprint(
865 oem_props, oem_dict, OPTIONS.target_info_dict))
866
Geremy Condra36bd3652014-02-06 19:45:10 -0800867 script.Print("Verifying current system...")
868
869 device_specific.IncrementalOTA_VerifyBegin()
870
Michael Rungec6e3afd2014-05-05 11:55:47 -0700871 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700872 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
873 # patching on a device that's already on the target build will damage the
874 # system. Because operations like move don't check the block state, they
875 # always apply the changes unconditionally.
876 if blockimgdiff_version <= 2:
877 script.AssertSomeFingerprint(source_fp)
878 else:
879 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700880 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700881 if blockimgdiff_version <= 2:
882 script.AssertSomeThumbprint(
883 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
884 else:
885 script.AssertSomeThumbprint(
886 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
887 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800888
889 if updating_boot:
Tao Baodd24da92015-07-29 14:09:23 -0700890 boot_type, boot_device = common.GetTypeAndDevice(
891 "/boot", OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800892 d = common.Difference(target_boot, source_boot)
893 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700894 if d is None:
895 include_full_boot = True
896 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
897 else:
898 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800899
Doug Zongkerf8340082014-08-05 10:39:37 -0700900 print "boot target: %d source: %d diff: %d" % (
901 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800902
Doug Zongkerf8340082014-08-05 10:39:37 -0700903 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800904
Doug Zongkerf8340082014-08-05 10:39:37 -0700905 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
906 (boot_type, boot_device,
907 source_boot.size, source_boot.sha1,
908 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800909
910 device_specific.IncrementalOTA_VerifyEnd()
911
912 if OPTIONS.two_step:
913 script.WriteRawImage("/boot", "recovery.img")
914 script.AppendExtra("""
915set_stage("%(bcb_dev)s", "2/3");
916reboot_now("%(bcb_dev)s", "");
917else
918""" % bcb_dev)
919
Jesse Zhao75bcea02015-01-06 10:59:53 -0800920 # Verify the existing partitions.
921 system_diff.WriteVerifyScript(script)
922 if vendor_diff:
923 vendor_diff.WriteVerifyScript(script)
924
Geremy Condra36bd3652014-02-06 19:45:10 -0800925 script.Comment("---- start making changes here ----")
926
927 device_specific.IncrementalOTA_InstallBegin()
928
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700929 system_diff.WriteScript(script, output_zip,
930 progress=0.8 if vendor_diff else 0.9)
Tao Bao68658c02015-06-01 13:40:49 -0700931
Doug Zongkerfc44a512014-08-26 13:10:25 -0700932 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700933 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800934
935 if OPTIONS.two_step:
936 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
937 script.WriteRawImage("/boot", "boot.img")
938 print "writing full boot image (forced by two-step mode)"
939
940 if not OPTIONS.two_step:
941 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700942 if include_full_boot:
943 print "boot image changed; including full."
944 script.Print("Installing boot image...")
945 script.WriteRawImage("/boot", "boot.img")
946 else:
947 # Produce the boot image by applying a patch to the current
948 # contents of the boot partition, and write it back to the
949 # partition.
950 print "boot image changed; including patch."
951 script.Print("Patching boot image...")
952 script.ShowProgress(0.1, 10)
953 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
954 % (boot_type, boot_device,
955 source_boot.size, source_boot.sha1,
956 target_boot.size, target_boot.sha1),
957 "-",
958 target_boot.size, target_boot.sha1,
959 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800960 else:
961 print "boot image unchanged; skipping."
962
963 # Do device-specific installation (eg, write radio image).
964 device_specific.IncrementalOTA_InstallEnd()
965
966 if OPTIONS.extra_script is not None:
967 script.AppendExtra(OPTIONS.extra_script)
968
Doug Zongker922206e2014-03-04 13:16:24 -0800969 if OPTIONS.wipe_user_data:
970 script.Print("Erasing user data...")
971 script.FormatPartition("/data")
972
Geremy Condra36bd3652014-02-06 19:45:10 -0800973 if OPTIONS.two_step:
974 script.AppendExtra("""
975set_stage("%(bcb_dev)s", "");
976endif;
977endif;
978""" % bcb_dev)
979
980 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800981 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800982 WriteMetadata(metadata, output_zip)
983
Doug Zongker32b527d2014-03-04 10:03:02 -0800984
Dan Albert8b72aef2015-03-23 19:13:21 -0700985class FileDifference(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700986 def __init__(self, partition, source_zip, target_zip, output_zip):
Dan Albert8b72aef2015-03-23 19:13:21 -0700987 self.deferred_patch_list = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700988 print "Loading target..."
989 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
990 print "Loading source..."
991 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
992
993 self.verbatim_targets = verbatim_targets = []
994 self.patch_list = patch_list = []
995 diffs = []
996 self.renames = renames = {}
997 known_paths = set()
998 largest_source_size = 0
999
1000 matching_file_cache = {}
1001 for fn, sf in source_data.items():
1002 assert fn == sf.name
1003 matching_file_cache["path:" + fn] = sf
1004 if fn in target_data.keys():
1005 AddToKnownPaths(fn, known_paths)
1006 # Only allow eligibility for filename/sha matching
1007 # if there isn't a perfect path match.
1008 if target_data.get(sf.name) is None:
1009 matching_file_cache["file:" + fn.split("/")[-1]] = sf
1010 matching_file_cache["sha:" + sf.sha1] = sf
1011
1012 for fn in sorted(target_data.keys()):
1013 tf = target_data[fn]
1014 assert fn == tf.name
1015 sf = ClosestFileMatch(tf, matching_file_cache, renames)
1016 if sf is not None and sf.name != tf.name:
1017 print "File has moved from " + sf.name + " to " + tf.name
1018 renames[sf.name] = tf
1019
1020 if sf is None or fn in OPTIONS.require_verbatim:
1021 # This file should be included verbatim
1022 if fn in OPTIONS.prohibit_verbatim:
1023 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
1024 print "send", fn, "verbatim"
1025 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001026 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001027 if fn in target_data.keys():
1028 AddToKnownPaths(fn, known_paths)
1029 elif tf.sha1 != sf.sha1:
1030 # File is different; consider sending as a patch
1031 diffs.append(common.Difference(tf, sf))
1032 else:
1033 # Target file data identical to source (may still be renamed)
1034 pass
1035
1036 common.ComputeDifferences(diffs)
1037
1038 for diff in diffs:
1039 tf, sf, d = diff.GetPatch()
1040 path = "/".join(tf.name.split("/")[:-1])
1041 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1042 path not in known_paths:
1043 # patch is almost as big as the file; don't bother patching
1044 # or a patch + rename cannot take place due to the target
1045 # directory not existing
1046 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001047 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001048 if sf.name in renames:
1049 del renames[sf.name]
1050 AddToKnownPaths(tf.name, known_paths)
1051 else:
1052 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1053 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1054 largest_source_size = max(largest_source_size, sf.size)
1055
1056 self.largest_source_size = largest_source_size
1057
1058 def EmitVerification(self, script):
1059 so_far = 0
Dan Albert8b72aef2015-03-23 19:13:21 -07001060 for tf, sf, _, _ in self.patch_list:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001061 if tf.name != sf.name:
1062 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1063 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1064 so_far += sf.size
1065 return so_far
1066
Michael Runge63f01de2014-10-28 19:24:19 -07001067 def EmitExplicitTargetVerification(self, script):
Dan Albert8b72aef2015-03-23 19:13:21 -07001068 for fn, _, sha1 in self.verbatim_targets:
1069 if fn[-1] != "/":
Michael Runge63f01de2014-10-28 19:24:19 -07001070 script.FileCheck("/"+fn, sha1)
1071 for tf, _, _, _ in self.patch_list:
1072 script.FileCheck(tf.name, tf.sha1)
1073
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001074 def RemoveUnneededFiles(self, script, extras=()):
Tao Baoa77d41e2015-09-03 21:17:37 -07001075 file_list = ["/" + i[0] for i in self.verbatim_targets]
1076 file_list += ["/" + i for i in self.source_data
1077 if i not in self.target_data and i not in self.renames]
1078 file_list += list(extras)
1079 # Sort the list in descending order, which removes all the files first
1080 # before attempting to remove the folder. (Bug: 22960996)
1081 script.DeleteFiles(sorted(file_list, reverse=True))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001082
1083 def TotalPatchSize(self):
1084 return sum(i[1].size for i in self.patch_list)
1085
1086 def EmitPatches(self, script, total_patch_size, so_far):
1087 self.deferred_patch_list = deferred_patch_list = []
1088 for item in self.patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001089 tf, sf, _, _ = item
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001090 if tf.name == "system/build.prop":
1091 deferred_patch_list.append(item)
1092 continue
Dan Albert8b72aef2015-03-23 19:13:21 -07001093 if sf.name != tf.name:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001094 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
Dan Albert8b72aef2015-03-23 19:13:21 -07001095 script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1,
1096 "patch/" + sf.name + ".p")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001097 so_far += tf.size
1098 script.SetProgress(so_far / total_patch_size)
1099 return so_far
1100
1101 def EmitDeferredPatches(self, script):
1102 for item in self.deferred_patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001103 tf, sf, _, _ = item
1104 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1,
1105 "patch/" + sf.name + ".p")
1106 script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001107
1108 def EmitRenames(self, script):
1109 if len(self.renames) > 0:
1110 script.Print("Renaming files...")
1111 for src, tgt in self.renames.iteritems():
1112 print "Renaming " + src + " to " + tgt.name
1113 script.RenameFile(src, tgt.name)
1114
1115
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001116def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001117 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1118 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1119
Doug Zongker26e66192014-02-20 13:22:07 -08001120 if (OPTIONS.block_based and
1121 target_has_recovery_patch and
1122 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001123 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1124
Doug Zongker37974732010-09-16 17:44:38 -07001125 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1126 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001127
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001128 if source_version == 0:
1129 print ("WARNING: generating edify script for a source that "
1130 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -07001131 script = edify_generator.EdifyGenerator(
1132 source_version, OPTIONS.target_info_dict,
1133 fstab=OPTIONS.source_info_dict["fstab"])
Doug Zongkereef39442009-04-02 12:14:19 -07001134
Michael Runge6e836112014-04-15 17:40:21 -07001135 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Tao Bao34b47bf2015-06-22 19:17:41 -07001136 recovery_mount_options = OPTIONS.source_info_dict.get(
1137 "recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001138 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001139 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001140 if OPTIONS.oem_source is None:
1141 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001142 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001143 oem_dict = common.LoadDictionaryFromLines(
1144 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001145
Dan Albert8b72aef2015-03-23 19:13:21 -07001146 metadata = {
1147 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1148 OPTIONS.source_info_dict),
1149 "post-timestamp": GetBuildProp("ro.build.date.utc",
1150 OPTIONS.target_info_dict),
1151 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001152
Doug Zongker05d3dea2009-06-22 11:32:31 -07001153 device_specific = common.DeviceSpecificParams(
1154 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001155 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001156 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001157 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001158 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001159 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001160 metadata=metadata,
Tao Bao6f0b2192015-10-13 16:37:12 -07001161 info_dict=OPTIONS.source_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001162
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001163 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001164 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001165 if HasVendorPartition(target_zip):
1166 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001167 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001168 else:
1169 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001170
Dan Albert8b72aef2015-03-23 19:13:21 -07001171 target_fp = CalculateFingerprint(oem_props, oem_dict,
1172 OPTIONS.target_info_dict)
1173 source_fp = CalculateFingerprint(oem_props, oem_dict,
1174 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001175
1176 if oem_props is None:
1177 script.AssertSomeFingerprint(source_fp, target_fp)
1178 else:
1179 script.AssertSomeThumbprint(
1180 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1181 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1182
Doug Zongker2ea21062010-04-28 16:05:21 -07001183 metadata["pre-build"] = source_fp
1184 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001185
Doug Zongker55d93282011-01-25 17:03:34 -08001186 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001187 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1188 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001189 target_boot = common.GetBootableImage(
1190 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001191 updating_boot = (not OPTIONS.two_step and
1192 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001193
Doug Zongker55d93282011-01-25 17:03:34 -08001194 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001195 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1196 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001197 target_recovery = common.GetBootableImage(
1198 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001199 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001200
Doug Zongker881dd402009-09-20 14:03:55 -07001201 # Here's how we divide up the progress bar:
1202 # 0.1 for verifying the start state (PatchCheck calls)
1203 # 0.8 for applying patches (ApplyPatch calls)
1204 # 0.1 for unpacking verbatim files, symlinking, and doing the
1205 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001206
Michael Runge6e836112014-04-15 17:40:21 -07001207 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001208 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001209
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001210 # Two-step incremental package strategy (in chronological order,
1211 # which is *not* the order in which the generated script has
1212 # things):
1213 #
1214 # if stage is not "2/3" or "3/3":
1215 # do verification on current system
1216 # write recovery image to boot partition
1217 # set stage to "2/3"
1218 # reboot to boot partition and restart recovery
1219 # else if stage is "2/3":
1220 # write recovery image to recovery partition
1221 # set stage to "3/3"
1222 # reboot to recovery partition and restart recovery
1223 # else:
1224 # (stage must be "3/3")
1225 # perform update:
1226 # patch system files, etc.
1227 # force full install of new boot image
1228 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001229 # complete script normally
1230 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001231
1232 if OPTIONS.two_step:
Tao Baodd24da92015-07-29 14:09:23 -07001233 if not OPTIONS.source_info_dict.get("multistage_support", None):
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001234 assert False, "two-step packages not supported by this build"
Tao Baodd24da92015-07-29 14:09:23 -07001235 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001236 assert fs.fs_type.upper() == "EMMC", \
1237 "two-step packages only supported on devices with EMMC /misc partitions"
1238 bcb_dev = {"bcb_dev": fs.device}
1239 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1240 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001241if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001242""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001243 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001244 script.WriteRawImage("/recovery", "recovery.img")
1245 script.AppendExtra("""
1246set_stage("%(bcb_dev)s", "3/3");
1247reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001248else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001249""" % bcb_dev)
1250
Tao Bao6c55a8a2015-04-08 15:30:27 -07001251 # Dump fingerprints
1252 script.Print("Source: %s" % (source_fp,))
1253 script.Print("Target: %s" % (target_fp,))
1254
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001255 script.Print("Verifying current system...")
1256
Doug Zongkere5ff5902012-01-17 10:55:37 -08001257 device_specific.IncrementalOTA_VerifyBegin()
1258
Doug Zongker881dd402009-09-20 14:03:55 -07001259 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001260 so_far = system_diff.EmitVerification(script)
1261 if vendor_diff:
1262 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001263
Doug Zongker5da317e2009-06-02 13:38:17 -07001264 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001265 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001266 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001267 print "boot target: %d source: %d diff: %d" % (
1268 target_boot.size, source_boot.size, len(d))
1269
Doug Zongker048e7ca2009-06-15 14:31:53 -07001270 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001271
Tao Baodd24da92015-07-29 14:09:23 -07001272 boot_type, boot_device = common.GetTypeAndDevice(
1273 "/boot", OPTIONS.source_info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001274
1275 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1276 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001277 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001278 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001279 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001280
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001281 size = []
Dan Albert8b72aef2015-03-23 19:13:21 -07001282 if system_diff.patch_list:
1283 size.append(system_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001284 if vendor_diff:
Dan Albert8b72aef2015-03-23 19:13:21 -07001285 if vendor_diff.patch_list:
1286 size.append(vendor_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001287 if size or updating_recovery or updating_boot:
1288 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001289
Doug Zongker05d3dea2009-06-22 11:32:31 -07001290 device_specific.IncrementalOTA_VerifyEnd()
1291
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001292 if OPTIONS.two_step:
1293 script.WriteRawImage("/boot", "recovery.img")
1294 script.AppendExtra("""
1295set_stage("%(bcb_dev)s", "2/3");
1296reboot_now("%(bcb_dev)s", "");
1297else
1298""" % bcb_dev)
1299
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001300 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001301
Doug Zongkere5ff5902012-01-17 10:55:37 -08001302 device_specific.IncrementalOTA_InstallBegin()
1303
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001304 if OPTIONS.two_step:
1305 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1306 script.WriteRawImage("/boot", "boot.img")
1307 print "writing full boot image (forced by two-step mode)"
1308
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001309 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001310 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1311 if vendor_diff:
1312 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001313
Doug Zongker881dd402009-09-20 14:03:55 -07001314 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001315 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1316 if vendor_diff:
1317 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001318 if updating_boot:
1319 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001320
1321 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001322 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1323 if vendor_diff:
1324 script.Print("Patching vendor files...")
1325 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001326
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001327 if not OPTIONS.two_step:
1328 if updating_boot:
1329 # Produce the boot image by applying a patch to the current
1330 # contents of the boot partition, and write it back to the
1331 # partition.
1332 script.Print("Patching boot image...")
1333 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1334 % (boot_type, boot_device,
1335 source_boot.size, source_boot.sha1,
1336 target_boot.size, target_boot.sha1),
1337 "-",
1338 target_boot.size, target_boot.sha1,
1339 source_boot.sha1, "patch/boot.img.p")
1340 so_far += target_boot.size
1341 script.SetProgress(so_far / total_patch_size)
1342 print "boot image changed; including."
1343 else:
1344 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001345
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001346 system_items = ItemSet("system", "META/filesystem_config.txt")
1347 if vendor_diff:
1348 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1349
Doug Zongkereef39442009-04-02 12:14:19 -07001350 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001351 # Recovery is generated as a patch using both the boot image
1352 # (which contains the same linux kernel as recovery) and the file
1353 # /system/etc/recovery-resource.dat (which contains all the images
1354 # used in the recovery UI) as sources. This lets us minimize the
1355 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001356 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001357 # For older builds where recovery-resource.dat is not present, we
1358 # use only the boot image as the source.
1359
Doug Zongkerc9253822014-02-04 12:17:58 -08001360 if not target_has_recovery_patch:
1361 def output_sink(fn, data):
1362 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001363 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001364
1365 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1366 target_recovery, target_boot)
1367 script.DeleteFiles(["/system/recovery-from-boot.p",
Tao Baof2cffbd2015-07-22 12:33:18 -07001368 "/system/etc/recovery.img",
Doug Zongkerc9253822014-02-04 12:17:58 -08001369 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001370 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001371 else:
1372 print "recovery image unchanged; skipping."
1373
Doug Zongker881dd402009-09-20 14:03:55 -07001374 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001375
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001376 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1377 if vendor_diff:
1378 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1379
1380 temp_script = script.MakeTemporary()
1381 system_items.GetMetadata(target_zip)
1382 system_items.Get("system").SetPermissions(temp_script)
1383 if vendor_diff:
1384 vendor_items.GetMetadata(target_zip)
1385 vendor_items.Get("vendor").SetPermissions(temp_script)
1386
1387 # Note that this call will mess up the trees of Items, so make sure
1388 # we're done with them.
1389 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1390 if vendor_diff:
1391 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001392
1393 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001394 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1395
1396 # Delete all the symlinks in source that aren't in target. This
1397 # needs to happen before verbatim files are unpacked, in case a
1398 # symlink in the source is replaced by a real file in the target.
Tao Bao84006ea2015-09-02 10:28:08 -07001399
1400 # If a symlink in the source will be replaced by a regular file, we cannot
1401 # delete the symlink/file in case the package gets applied again. For such
1402 # a symlink, we prepend a sha1_check() to detect if it has been updated.
1403 # (Bug: 23646151)
1404 replaced_symlinks = dict()
1405 if system_diff:
1406 for i in system_diff.verbatim_targets:
1407 replaced_symlinks["/%s" % (i[0],)] = i[2]
1408 if vendor_diff:
1409 for i in vendor_diff.verbatim_targets:
1410 replaced_symlinks["/%s" % (i[0],)] = i[2]
1411
1412 if system_diff:
1413 for tf in system_diff.renames.values():
1414 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1415 if vendor_diff:
1416 for tf in vendor_diff.renames.values():
1417 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1418
1419 always_delete = []
1420 may_delete = []
Doug Zongkereef39442009-04-02 12:14:19 -07001421 for dest, link in source_symlinks:
1422 if link not in target_symlinks_d:
Tao Bao84006ea2015-09-02 10:28:08 -07001423 if link in replaced_symlinks:
1424 may_delete.append((link, replaced_symlinks[link]))
1425 else:
1426 always_delete.append(link)
1427 script.DeleteFiles(always_delete)
1428 script.DeleteFilesIfNotMatching(may_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001429
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001430 if system_diff.verbatim_targets:
1431 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001432 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001433 if vendor_diff and vendor_diff.verbatim_targets:
1434 script.Print("Unpacking new vendor files...")
1435 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001436
Doug Zongkerc9253822014-02-04 12:17:58 -08001437 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001438 script.Print("Unpacking new recovery...")
1439 script.UnpackPackageDir("recovery", "/system")
1440
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001441 system_diff.EmitRenames(script)
1442 if vendor_diff:
1443 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001444
Doug Zongker05d3dea2009-06-22 11:32:31 -07001445 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001446
1447 # Create all the symlinks that don't already exist, or point to
1448 # somewhere different than what we want. Delete each symlink before
1449 # creating it, since the 'symlink' command won't overwrite.
1450 to_create = []
1451 for dest, link in target_symlinks:
1452 if link in source_symlinks_d:
1453 if dest != source_symlinks_d[link]:
1454 to_create.append((dest, link))
1455 else:
1456 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001457 script.DeleteFiles([i[1] for i in to_create])
1458 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001459
1460 # Now that the symlinks are created, we can set all the
1461 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001462 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001463
Doug Zongker881dd402009-09-20 14:03:55 -07001464 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001465 device_specific.IncrementalOTA_InstallEnd()
1466
Doug Zongker1c390a22009-05-14 19:06:36 -07001467 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001468 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001469
Doug Zongkere92f15a2011-08-26 13:46:40 -07001470 # Patch the build.prop file last, so if something fails but the
1471 # device can still come up, it appears to be the old build and will
1472 # get set the OTA package again to retry.
1473 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001474 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001475
Doug Zongker922206e2014-03-04 13:16:24 -08001476 if OPTIONS.wipe_user_data:
1477 script.Print("Erasing user data...")
1478 script.FormatPartition("/data")
1479
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001480 if OPTIONS.two_step:
1481 script.AppendExtra("""
1482set_stage("%(bcb_dev)s", "");
1483endif;
1484endif;
1485""" % bcb_dev)
1486
Michael Runge63f01de2014-10-28 19:24:19 -07001487 if OPTIONS.verify and system_diff:
1488 script.Print("Remounting and verifying system partition files...")
1489 script.Unmount("/system")
1490 script.Mount("/system")
1491 system_diff.EmitExplicitTargetVerification(script)
1492
1493 if OPTIONS.verify and vendor_diff:
1494 script.Print("Remounting and verifying vendor partition files...")
1495 script.Unmount("/vendor")
1496 script.Mount("/vendor")
1497 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001498 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001499
Doug Zongker2ea21062010-04-28 16:05:21 -07001500 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001501
1502
1503def main(argv):
1504
1505 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001506 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001507 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001508 elif o in ("-k", "--package_key"):
1509 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001510 elif o in ("-i", "--incremental_from"):
1511 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001512 elif o == "--full_radio":
1513 OPTIONS.full_radio = True
leozwangaa6c1a12015-08-14 10:57:58 -07001514 elif o == "--full_bootloader":
1515 OPTIONS.full_bootloader = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001516 elif o in ("-w", "--wipe_user_data"):
1517 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001518 elif o in ("-n", "--no_prereq"):
1519 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001520 elif o in ("-o", "--oem_settings"):
1521 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001522 elif o in ("-e", "--extra_script"):
1523 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001524 elif o in ("-a", "--aslr_mode"):
1525 if a in ("on", "On", "true", "True", "yes", "Yes"):
1526 OPTIONS.aslr_mode = True
1527 else:
1528 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001529 elif o in ("-t", "--worker_threads"):
1530 if a.isdigit():
1531 OPTIONS.worker_threads = int(a)
1532 else:
1533 raise ValueError("Cannot parse value %r for option %r - only "
1534 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001535 elif o in ("-2", "--two_step"):
1536 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001537 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001538 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001539 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001540 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001541 elif o == "--block":
1542 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001543 elif o in ("-b", "--binary"):
1544 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001545 elif o in ("--no_fallback_to_full",):
1546 OPTIONS.fallback_to_full = False
Tao Bao8dcf7382015-05-21 14:09:49 -07001547 elif o == "--stash_threshold":
1548 try:
1549 OPTIONS.stash_threshold = float(a)
1550 except ValueError:
1551 raise ValueError("Cannot parse value %r for option %r - expecting "
1552 "a float" % (a, o))
Doug Zongkereef39442009-04-02 12:14:19 -07001553 else:
1554 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001555 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001556
1557 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001558 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001559 extra_long_opts=[
1560 "board_config=",
1561 "package_key=",
1562 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001563 "full_radio",
leozwangaa6c1a12015-08-14 10:57:58 -07001564 "full_bootloader",
Dan Albert8b72aef2015-03-23 19:13:21 -07001565 "wipe_user_data",
1566 "no_prereq",
1567 "extra_script=",
1568 "worker_threads=",
1569 "aslr_mode=",
1570 "two_step",
1571 "no_signing",
1572 "block",
1573 "binary=",
1574 "oem_settings=",
1575 "verify",
1576 "no_fallback_to_full",
Tao Bao8dcf7382015-05-21 14:09:49 -07001577 "stash_threshold=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001578 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001579
1580 if len(args) != 2:
1581 common.Usage(__doc__)
1582 sys.exit(1)
1583
Doug Zongker1c390a22009-05-14 19:06:36 -07001584 if OPTIONS.extra_script is not None:
1585 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1586
Doug Zongkereef39442009-04-02 12:14:19 -07001587 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001588 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001589
Doug Zongkereef39442009-04-02 12:14:19 -07001590 OPTIONS.target_tmp = OPTIONS.input_tmp
Tao Bao2c15d9e2015-07-09 11:51:16 -07001591 OPTIONS.info_dict = common.LoadInfoDict(input_zip, OPTIONS.target_tmp)
Kenny Roote2e9f612013-05-29 12:59:35 -07001592
Doug Zongker37974732010-09-16 17:44:38 -07001593 if OPTIONS.verbose:
1594 print "--- target info ---"
1595 common.DumpInfoDict(OPTIONS.info_dict)
1596
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001597 # If the caller explicitly specified the device-specific extensions
1598 # path via -s/--device_specific, use that. Otherwise, use
1599 # META/releasetools.py if it is present in the target target_files.
1600 # Otherwise, take the path of the file from 'tool_extensions' in the
1601 # info dict and look for that in the local filesystem, relative to
1602 # the current directory.
1603
Doug Zongker37974732010-09-16 17:44:38 -07001604 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001605 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1606 if os.path.exists(from_input):
1607 print "(using device-specific extensions from target_files)"
1608 OPTIONS.device_specific = from_input
1609 else:
1610 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1611
Doug Zongker37974732010-09-16 17:44:38 -07001612 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001613 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001614
Tao Baodb45efa2015-10-27 19:25:18 -07001615 if OPTIONS.info_dict.get("no_recovery") == "true":
1616 raise common.ExternalError(
1617 "--- target build has specified no recovery ---")
1618
Doug Zongker62d4f182014-08-04 16:06:43 -07001619 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001620
Doug Zongker62d4f182014-08-04 16:06:43 -07001621 if OPTIONS.no_signing:
Dan Albert8b72aef2015-03-23 19:13:21 -07001622 if os.path.exists(args[1]):
1623 os.unlink(args[1])
1624 output_zip = zipfile.ZipFile(args[1], "w",
1625 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001626 else:
1627 temp_zip_file = tempfile.NamedTemporaryFile()
1628 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1629 compression=zipfile.ZIP_DEFLATED)
1630
Tao Bao8dcf7382015-05-21 14:09:49 -07001631 cache_size = OPTIONS.info_dict.get("cache_size", None)
1632 if cache_size is None:
Tao Bao575d68a2015-08-07 19:49:45 -07001633 print "--- can't determine the cache partition size ---"
Tao Bao8dcf7382015-05-21 14:09:49 -07001634 OPTIONS.cache_size = cache_size
1635
Doug Zongker62d4f182014-08-04 16:06:43 -07001636 if OPTIONS.incremental_source is None:
1637 WriteFullOTAPackage(input_zip, output_zip)
1638 if OPTIONS.package_key is None:
1639 OPTIONS.package_key = OPTIONS.info_dict.get(
1640 "default_system_dev_certificate",
1641 "build/target/product/security/testkey")
Tao Bao2ed665a2015-04-01 11:21:55 -07001642 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001643 break
1644
1645 else:
1646 print "unzipping source target-files..."
Dan Albert8b72aef2015-03-23 19:13:21 -07001647 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
1648 OPTIONS.incremental_source)
Doug Zongker62d4f182014-08-04 16:06:43 -07001649 OPTIONS.target_info_dict = OPTIONS.info_dict
Tao Bao2c15d9e2015-07-09 11:51:16 -07001650 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip,
1651 OPTIONS.source_tmp)
Doug Zongker62d4f182014-08-04 16:06:43 -07001652 if OPTIONS.package_key is None:
1653 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1654 "default_system_dev_certificate",
1655 "build/target/product/security/testkey")
1656 if OPTIONS.verbose:
1657 print "--- source info ---"
1658 common.DumpInfoDict(OPTIONS.source_info_dict)
1659 try:
1660 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Bao2ed665a2015-04-01 11:21:55 -07001661 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001662 break
1663 except ValueError:
Dan Albert8b72aef2015-03-23 19:13:21 -07001664 if not OPTIONS.fallback_to_full:
1665 raise
Doug Zongker62d4f182014-08-04 16:06:43 -07001666 print "--- failed to build incremental; falling back to full ---"
1667 OPTIONS.incremental_source = None
Tao Bao2ed665a2015-04-01 11:21:55 -07001668 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001669
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001670 if not OPTIONS.no_signing:
1671 SignOutput(temp_zip_file.name, args[1])
1672 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001673
Doug Zongkereef39442009-04-02 12:14:19 -07001674 print "done."
1675
1676
1677if __name__ == '__main__':
1678 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001679 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001680 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001681 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07001682 print
1683 print " ERROR: %s" % (e,)
1684 print
1685 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001686 finally:
1687 common.Cleanup()