blob: e019b1e277e1005bd6b56e20214d95df50b7209f [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 Baod47d8e12015-05-21 14:09:49 -0700133# Stash size cannot exceed cache_size * threshold.
134OPTIONS.cache_size = None
135OPTIONS.stash_threshold = 0.8
Tao Bao8dcf7382015-05-21 14:09:49 -0700136
Doug Zongkereef39442009-04-02 12:14:19 -0700137def MostPopularKey(d, default):
138 """Given a dict, return the key corresponding to the largest
139 value. Returns 'default' if the dict is empty."""
140 x = [(v, k) for (k, v) in d.iteritems()]
Dan Albert8b72aef2015-03-23 19:13:21 -0700141 if not x:
142 return default
Doug Zongkereef39442009-04-02 12:14:19 -0700143 x.sort()
144 return x[-1][1]
145
146
147def IsSymlink(info):
148 """Return true if the zipfile.ZipInfo object passed in represents a
149 symlink."""
Ying Wang2ffb3142015-07-06 14:02:01 -0700150 return (info.external_attr >> 16) & 0o770000 == 0o120000
Doug Zongkereef39442009-04-02 12:14:19 -0700151
Hristo Bojinov96be7202010-08-02 10:26:17 -0700152def IsRegular(info):
153 """Return true if the zipfile.ZipInfo object passed in represents a
Ying Wang2ffb3142015-07-06 14:02:01 -0700154 regular file."""
155 return (info.external_attr >> 16) & 0o770000 == 0o100000
Doug Zongkereef39442009-04-02 12:14:19 -0700156
Michael Runge4038aa82013-12-13 18:06:28 -0800157def ClosestFileMatch(src, tgtfiles, existing):
158 """Returns the closest file match between a source file and list
159 of potential matches. The exact filename match is preferred,
160 then the sha1 is searched for, and finally a file with the same
161 basename is evaluated. Rename support in the updater-binary is
162 required for the latter checks to be used."""
163
164 result = tgtfiles.get("path:" + src.name)
165 if result is not None:
166 return result
167
168 if not OPTIONS.target_info_dict.get("update_rename_support", False):
169 return None
170
171 if src.size < 1000:
172 return None
173
174 result = tgtfiles.get("sha1:" + src.sha1)
175 if result is not None and existing.get(result.name) is None:
176 return result
177 result = tgtfiles.get("file:" + src.name.split("/")[-1])
178 if result is not None and existing.get(result.name) is None:
179 return result
180 return None
181
Dan Albert8b72aef2015-03-23 19:13:21 -0700182class ItemSet(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700183 def __init__(self, partition, fs_config):
184 self.partition = partition
185 self.fs_config = fs_config
186 self.ITEMS = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700187
Dan Albert8b72aef2015-03-23 19:13:21 -0700188 def Get(self, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700189 if name not in self.ITEMS:
Dan Albert8b72aef2015-03-23 19:13:21 -0700190 self.ITEMS[name] = Item(self, name, is_dir=is_dir)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700191 return self.ITEMS[name]
Doug Zongkereef39442009-04-02 12:14:19 -0700192
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700193 def GetMetadata(self, input_zip):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700194 # The target_files contains a record of what the uid,
195 # gid, and mode are supposed to be.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700196 output = input_zip.read(self.fs_config)
Doug Zongkereef39442009-04-02 12:14:19 -0700197
198 for line in output.split("\n"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700199 if not line:
200 continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700201 columns = line.split()
202 name, uid, gid, mode = columns[:4]
203 selabel = None
204 capabilities = None
205
206 # After the first 4 columns, there are a series of key=value
207 # pairs. Extract out the fields we care about.
208 for element in columns[4:]:
209 key, value = element.split("=")
210 if key == "selabel":
211 selabel = value
212 if key == "capabilities":
213 capabilities = value
214
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700215 i = self.ITEMS.get(name, None)
Doug Zongker283e2a12010-03-15 17:52:32 -0700216 if i is not None:
217 i.uid = int(uid)
218 i.gid = int(gid)
219 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700220 i.selabel = selabel
221 i.capabilities = capabilities
Dan Albert8b72aef2015-03-23 19:13:21 -0700222 if i.is_dir:
Doug Zongker283e2a12010-03-15 17:52:32 -0700223 i.children.sort(key=lambda i: i.name)
224
Tao Baof2cffbd2015-07-22 12:33:18 -0700225 # Set metadata for the files generated by this script. For full recovery
226 # image at system/etc/recovery.img, it will be taken care by fs_config.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700227 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700228 if i:
229 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700230 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700231 if i:
232 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700233
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700234
Dan Albert8b72aef2015-03-23 19:13:21 -0700235class Item(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700236 """Items represent the metadata (user, group, mode) of files and
237 directories in the system image."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700238 def __init__(self, itemset, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700239 self.itemset = itemset
240 self.name = name
241 self.uid = None
242 self.gid = None
243 self.mode = None
244 self.selabel = None
245 self.capabilities = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700246 self.is_dir = is_dir
247 self.descendants = None
248 self.best_subtree = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700249
250 if name:
Dan Albert8b72aef2015-03-23 19:13:21 -0700251 self.parent = itemset.Get(os.path.dirname(name), is_dir=True)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700252 self.parent.children.append(self)
253 else:
254 self.parent = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700255 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700256 self.children = []
257
258 def Dump(self, indent=0):
259 if self.uid is not None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700260 print "%s%s %d %d %o" % (
261 " " * indent, self.name, self.uid, self.gid, self.mode)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700262 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700263 print "%s%s %s %s %s" % (
264 " " * indent, self.name, self.uid, self.gid, self.mode)
265 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700266 print "%s%s" % (" "*indent, self.descendants)
267 print "%s%s" % (" "*indent, self.best_subtree)
268 for i in self.children:
269 i.Dump(indent=indent+1)
270
Doug Zongkereef39442009-04-02 12:14:19 -0700271 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700272 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
Dan Albert8b72aef2015-03-23 19:13:21 -0700273 all children and determine the best strategy for using set_perm_recursive
274 and set_perm to correctly chown/chmod all the files to their desired
Doug Zongkereef39442009-04-02 12:14:19 -0700275 values. Recursively calls itself for all descendants.
276
Dan Albert8b72aef2015-03-23 19:13:21 -0700277 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count}
278 counting up all descendants of this node. (dmode or fmode may be None.)
279 Also sets the best_subtree of each directory Item to the (uid, gid, dmode,
280 fmode, selabel, capabilities) tuple that will match the most descendants of
281 that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700282 """
283
Dan Albert8b72aef2015-03-23 19:13:21 -0700284 assert self.is_dir
285 key = (self.uid, self.gid, self.mode, None, self.selabel,
286 self.capabilities)
287 self.descendants = {key: 1}
288 d = self.descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700289 for i in self.children:
Dan Albert8b72aef2015-03-23 19:13:21 -0700290 if i.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700291 for k, v in i.CountChildMetadata().iteritems():
292 d[k] = d.get(k, 0) + v
293 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700294 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700295 d[k] = d.get(k, 0) + 1
296
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700297 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
298 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700299
300 # First, find the (uid, gid) pair that matches the most
301 # descendants.
302 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700303 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700304 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
305 ug = MostPopularKey(ug, (0, 0))
306
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700307 # Now find the dmode, fmode, selabel, and capabilities that match
308 # the most descendants with that (uid, gid), and choose those.
Dan Albert8b72aef2015-03-23 19:13:21 -0700309 best_dmode = (0, 0o755)
310 best_fmode = (0, 0o644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700311 best_selabel = (0, None)
312 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700313 for k, count in d.iteritems():
Dan Albert8b72aef2015-03-23 19:13:21 -0700314 if k[:2] != ug:
315 continue
316 if k[2] is not None and count >= best_dmode[0]:
317 best_dmode = (count, k[2])
318 if k[3] is not None and count >= best_fmode[0]:
319 best_fmode = (count, k[3])
320 if k[4] is not None and count >= best_selabel[0]:
321 best_selabel = (count, k[4])
322 if k[5] is not None and count >= best_capabilities[0]:
323 best_capabilities = (count, k[5])
324 self.best_subtree = ug + (
325 best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700326
327 return d
328
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700329 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700330 """Append set_perm/set_perm_recursive commands to 'script' to
331 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700332 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700333
334 self.CountChildMetadata()
335
336 def recurse(item, current):
Dan Albert8b72aef2015-03-23 19:13:21 -0700337 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple
338 # that the current item (and all its children) have already been set to.
339 # We only need to issue set_perm/set_perm_recursive commands if we're
Doug Zongkereef39442009-04-02 12:14:19 -0700340 # supposed to be something different.
Dan Albert8b72aef2015-03-23 19:13:21 -0700341 if item.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700342 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700343 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700344 current = item.best_subtree
345
346 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700347 item.mode != current[2] or item.selabel != current[4] or \
348 item.capabilities != current[5]:
349 script.SetPermissions("/"+item.name, item.uid, item.gid,
350 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700351
352 for i in item.children:
353 recurse(i, current)
354 else:
355 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700356 item.mode != current[3] or item.selabel != current[4] or \
357 item.capabilities != current[5]:
358 script.SetPermissions("/"+item.name, item.uid, item.gid,
359 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700360
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700361 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700362
363
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700364def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
365 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700366 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800367 list of symlinks. output_zip may be None, in which case the copy is
368 skipped (but the other side effects still happen). substitute is an
369 optional dict of {output filename: contents} to be output instead of
370 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700371 """
372
373 symlinks = []
374
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700375 partition = itemset.partition
376
Doug Zongkereef39442009-04-02 12:14:19 -0700377 for info in input_zip.infolist():
Tao Baoeaf885b2015-03-23 16:01:17 -0700378 prefix = partition.upper() + "/"
379 if info.filename.startswith(prefix):
380 basefilename = info.filename[len(prefix):]
Doug Zongkereef39442009-04-02 12:14:19 -0700381 if IsSymlink(info):
382 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700383 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700384 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700385 import copy
Doug Zongkereef39442009-04-02 12:14:19 -0700386 info2 = copy.copy(info)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700387 fn = info2.filename = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700388 if substitute and fn in substitute and substitute[fn] is None:
389 continue
390 if output_zip is not None:
391 if substitute and fn in substitute:
392 data = substitute[fn]
393 else:
394 data = input_zip.read(info.filename)
Tao Bao2ed665a2015-04-01 11:21:55 -0700395 common.ZipWriteStr(output_zip, info2, data)
Doug Zongkereef39442009-04-02 12:14:19 -0700396 if fn.endswith("/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700397 itemset.Get(fn[:-1], is_dir=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700398 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700399 itemset.Get(fn)
Doug Zongkereef39442009-04-02 12:14:19 -0700400
401 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800402 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700403
404
Doug Zongkereef39442009-04-02 12:14:19 -0700405def SignOutput(temp_zip_name, output_zip_name):
406 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
407 pw = key_passwords[OPTIONS.package_key]
408
Doug Zongker951495f2009-08-14 12:44:19 -0700409 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
410 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700411
412
Dan Albert8b72aef2015-03-23 19:13:21 -0700413def AppendAssertions(script, info_dict, oem_dict=None):
Michael Runge6e836112014-04-15 17:40:21 -0700414 oem_props = info_dict.get("oem_fingerprint_properties")
Michael Runge560569a2014-09-18 15:12:45 -0700415 if oem_props is None or len(oem_props) == 0:
Michael Runge6e836112014-04-15 17:40:21 -0700416 device = GetBuildProp("ro.product.device", info_dict)
417 script.AssertDevice(device)
418 else:
419 if oem_dict is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700420 raise common.ExternalError(
421 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700422 for prop in oem_props.split():
423 if oem_dict.get(prop) is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700424 raise common.ExternalError(
425 "The OEM file is missing the property %s" % prop)
Michael Runge6e836112014-04-15 17:40:21 -0700426 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700427
Doug Zongkereef39442009-04-02 12:14:19 -0700428
Doug Zongkerc9253822014-02-04 12:17:58 -0800429def HasRecoveryPatch(target_files_zip):
Tao Baof2cffbd2015-07-22 12:33:18 -0700430 namelist = [name for name in target_files_zip.namelist()]
431 return ("SYSTEM/recovery-from-boot.p" in namelist or
432 "SYSTEM/etc/recovery.img" in namelist)
Doug Zongker73ef8252009-07-23 15:12:53 -0700433
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700434def HasVendorPartition(target_files_zip):
435 try:
436 target_files_zip.getinfo("VENDOR/")
437 return True
438 except KeyError:
439 return False
440
Michael Runge6e836112014-04-15 17:40:21 -0700441def GetOemProperty(name, oem_props, oem_dict, info_dict):
442 if oem_props is not None and name in oem_props:
443 return oem_dict[name]
444 return GetBuildProp(name, info_dict)
445
446
447def CalculateFingerprint(oem_props, oem_dict, info_dict):
448 if oem_props is None:
449 return GetBuildProp("ro.build.fingerprint", info_dict)
450 return "%s/%s/%s:%s" % (
Dan Albert8b72aef2015-03-23 19:13:21 -0700451 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
452 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
453 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
454 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700455
Doug Zongkerfc44a512014-08-26 13:10:25 -0700456
Doug Zongker3c84f562014-07-31 11:06:30 -0700457def GetImage(which, tmpdir, info_dict):
Doug Zongkerfc44a512014-08-26 13:10:25 -0700458 # Return an image object (suitable for passing to BlockImageDiff)
459 # for the 'which' partition (most be "system" or "vendor"). If a
460 # prebuilt image and file map are found in tmpdir they are used,
461 # otherwise they are reconstructed from the individual files.
Doug Zongker3c84f562014-07-31 11:06:30 -0700462
463 assert which in ("system", "vendor")
464
465 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700466 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
467 if os.path.exists(path) and os.path.exists(mappath):
Doug Zongker3c84f562014-07-31 11:06:30 -0700468 print "using %s.img from target-files" % (which,)
Doug Zongker3c84f562014-07-31 11:06:30 -0700469 # This is a 'new' target-files, which already has the image in it.
Doug Zongker3c84f562014-07-31 11:06:30 -0700470
471 else:
472 print "building %s.img from target-files" % (which,)
473
474 # This is an 'old' target-files, which does not contain images
475 # already built. Build them.
476
Doug Zongkerfc44a512014-08-26 13:10:25 -0700477 mappath = tempfile.mkstemp()[1]
478 OPTIONS.tempfiles.append(mappath)
479
Doug Zongker3c84f562014-07-31 11:06:30 -0700480 import add_img_to_target_files
481 if which == "system":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700482 path = add_img_to_target_files.BuildSystem(
483 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700484 elif which == "vendor":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700485 path = add_img_to_target_files.BuildVendor(
486 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700487
Tao Baoff777812015-05-12 11:42:31 -0700488 # Bug: http://b/20939131
489 # In ext4 filesystems, block 0 might be changed even being mounted
490 # R/O. We add it to clobbered_blocks so that it will be written to the
491 # target unconditionally. Note that they are still part of care_map.
492 clobbered_blocks = "0"
493
494 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700495
496
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700497def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700498 # TODO: how to determine this? We don't know what version it will
Tao Bao34b47bf2015-06-22 19:17:41 -0700499 # be installed on top of. For now, we expect the API just won't
500 # change very often. Similarly for fstab, it might have changed
501 # in the target build.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700502 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700503
Michael Runge6e836112014-04-15 17:40:21 -0700504 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700505 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700506 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700507 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700508 if OPTIONS.oem_source is None:
509 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700510 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700511 oem_dict = common.LoadDictionaryFromLines(
512 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -0700513
Dan Albert8b72aef2015-03-23 19:13:21 -0700514 metadata = {
515 "post-build": CalculateFingerprint(oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700516 OPTIONS.info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700517 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
518 OPTIONS.info_dict),
519 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
520 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700521
Doug Zongker05d3dea2009-06-22 11:32:31 -0700522 device_specific = common.DeviceSpecificParams(
523 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700524 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700525 output_zip=output_zip,
526 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700527 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700528 metadata=metadata,
529 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700530
Doug Zongkerc9253822014-02-04 12:17:58 -0800531 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800532 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800533
Doug Zongker962069c2009-04-23 11:41:58 -0700534 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700535 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700536 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
537 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700538
Michael Runge6e836112014-04-15 17:40:21 -0700539 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700540 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800541
542 # Two-step package strategy (in chronological order, which is *not*
543 # the order in which the generated script has things):
544 #
545 # if stage is not "2/3" or "3/3":
546 # write recovery image to boot partition
547 # set stage to "2/3"
548 # reboot to boot partition and restart recovery
549 # else if stage is "2/3":
550 # write recovery image to recovery partition
551 # set stage to "3/3"
552 # reboot to recovery partition and restart recovery
553 # else:
554 # (stage must be "3/3")
555 # set stage to ""
556 # do normal full package installation:
557 # wipe and install system, boot image, etc.
558 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700559 # complete script normally
560 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800561
562 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
563 OPTIONS.input_tmp, "RECOVERY")
564 if OPTIONS.two_step:
565 if not OPTIONS.info_dict.get("multistage_support", None):
566 assert False, "two-step packages not supported by this build"
567 fs = OPTIONS.info_dict["fstab"]["/misc"]
568 assert fs.fs_type.upper() == "EMMC", \
569 "two-step packages only supported on devices with EMMC /misc partitions"
570 bcb_dev = {"bcb_dev": fs.device}
571 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
572 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700573if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800574""" % bcb_dev)
575 script.WriteRawImage("/recovery", "recovery.img")
576 script.AppendExtra("""
577set_stage("%(bcb_dev)s", "3/3");
578reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700579else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800580""" % bcb_dev)
581
Tao Bao6c55a8a2015-04-08 15:30:27 -0700582 # Dump fingerprints
583 script.Print("Target: %s" % CalculateFingerprint(
584 oem_props, oem_dict, OPTIONS.info_dict))
585
Doug Zongkere5ff5902012-01-17 10:55:37 -0800586 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700587
Doug Zongker01ce19c2014-02-04 13:48:15 -0800588 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700589
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700590 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800591 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700592 if HasVendorPartition(input_zip):
593 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700594
Stephen Smalleyd3a803e2015-08-04 14:59:06 -0400595 # Place a copy of file_contexts.bin into the OTA package which will be used
596 # by the recovery program.
Kenny Rootf32dc712012-04-08 10:42:34 -0700597 if "selinux_fc" in OPTIONS.info_dict:
598 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500599
Michael Runge7cd99ba2014-10-22 17:21:48 -0700600 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
601
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700602 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700603 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800604
Doug Zongker26e66192014-02-20 13:22:07 -0800605 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700606 # Full OTA is done as an "incremental" against an empty source
607 # image. This has the effect of writing new data from the package
608 # to the entire partition, but lets us reuse the updater code that
609 # writes incrementals to do it.
610 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
611 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700612 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700613 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800614 else:
615 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700616 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800617 if not has_recovery_patch:
618 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800619 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700620
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700621 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800622 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700623
Tao Bao7a5bf8a2015-07-21 18:01:20 -0700624 boot_img = common.GetBootableImage(
625 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800626
Doug Zongker91a99c22014-05-09 13:15:01 -0700627 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800628 def output_sink(fn, data):
629 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700630 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800631
632 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
633 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700634
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700635 system_items.GetMetadata(input_zip)
636 system_items.Get("system").SetPermissions(script)
637
638 if HasVendorPartition(input_zip):
639 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
640 script.ShowProgress(0.1, 0)
641
642 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700643 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
644 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700645 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700646 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700647 else:
648 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700649 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700650 script.UnpackPackageDir("vendor", "/vendor")
651
652 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
653 script.MakeSymlinks(symlinks)
654
655 vendor_items.GetMetadata(input_zip)
656 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700657
Doug Zongker37974732010-09-16 17:44:38 -0700658 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700659 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700660
Doug Zongker01ce19c2014-02-04 13:48:15 -0800661 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700662 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700663
Doug Zongker01ce19c2014-02-04 13:48:15 -0800664 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700665 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700666
Doug Zongker1c390a22009-05-14 19:06:36 -0700667 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700668 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700669
Doug Zongker14833602010-02-02 13:12:04 -0800670 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800671
Doug Zongker922206e2014-03-04 13:16:24 -0800672 if OPTIONS.wipe_user_data:
673 script.ShowProgress(0.1, 10)
674 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700675
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800676 if OPTIONS.two_step:
677 script.AppendExtra("""
678set_stage("%(bcb_dev)s", "");
679""" % bcb_dev)
680 script.AppendExtra("else\n")
681 script.WriteRawImage("/boot", "recovery.img")
682 script.AppendExtra("""
683set_stage("%(bcb_dev)s", "2/3");
684reboot_now("%(bcb_dev)s", "");
685endif;
686endif;
687""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800688 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700689 WriteMetadata(metadata, output_zip)
690
Doug Zongkerfc44a512014-08-26 13:10:25 -0700691
Dan Albert8e0178d2015-01-27 15:53:15 -0800692def WritePolicyConfig(file_name, output_zip):
693 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500694
Doug Zongker2ea21062010-04-28 16:05:21 -0700695
696def WriteMetadata(metadata, output_zip):
697 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
698 "".join(["%s=%s\n" % kv
699 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700700
Doug Zongkerfc44a512014-08-26 13:10:25 -0700701
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700702def LoadPartitionFiles(z, partition):
703 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700704 ZipFile, and return a dict of {filename: File object}."""
705 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700706 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700707 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700708 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700709 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700710 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700711 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700712 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800713 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700714
715
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700716def GetBuildProp(prop, info_dict):
717 """Return the fingerprint of the build of a given target-files info_dict."""
718 try:
719 return info_dict.get("build.prop", {})[prop]
720 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700721 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700722
Doug Zongkerfc44a512014-08-26 13:10:25 -0700723
Michael Runge4038aa82013-12-13 18:06:28 -0800724def AddToKnownPaths(filename, known_paths):
725 if filename[-1] == "/":
726 return
727 dirs = filename.split("/")[:-1]
728 while len(dirs) > 0:
729 path = "/".join(dirs)
730 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700731 break
Michael Runge4038aa82013-12-13 18:06:28 -0800732 known_paths.add(path)
733 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700734
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700735
Geremy Condra36bd3652014-02-06 19:45:10 -0800736def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
Tao Bao3806c232015-07-05 21:08:33 -0700737 # TODO(tbao): We should factor out the common parts between
738 # WriteBlockIncrementalOTAPackage() and WriteIncrementalOTAPackage().
Geremy Condra36bd3652014-02-06 19:45:10 -0800739 source_version = OPTIONS.source_info_dict["recovery_api_version"]
740 target_version = OPTIONS.target_info_dict["recovery_api_version"]
741
742 if source_version == 0:
743 print ("WARNING: generating edify script for a source that "
744 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -0700745 script = edify_generator.EdifyGenerator(
746 source_version, OPTIONS.target_info_dict,
747 fstab=OPTIONS.source_info_dict["fstab"])
Geremy Condra36bd3652014-02-06 19:45:10 -0800748
Tao Bao3806c232015-07-05 21:08:33 -0700749 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
750 recovery_mount_options = OPTIONS.source_info_dict.get(
751 "recovery_mount_options")
752 oem_dict = None
753 if oem_props is not None and len(oem_props) > 0:
754 if OPTIONS.oem_source is None:
755 raise common.ExternalError("OEM source required for this build")
756 script.Mount("/oem", recovery_mount_options)
757 oem_dict = common.LoadDictionaryFromLines(
758 open(OPTIONS.oem_source).readlines())
759
Dan Albert8b72aef2015-03-23 19:13:21 -0700760 metadata = {
Tao Bao3806c232015-07-05 21:08:33 -0700761 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
762 OPTIONS.source_info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700763 "post-timestamp": GetBuildProp("ro.build.date.utc",
764 OPTIONS.target_info_dict),
765 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800766
767 device_specific = common.DeviceSpecificParams(
768 source_zip=source_zip,
769 source_version=source_version,
770 target_zip=target_zip,
771 target_version=target_version,
772 output_zip=output_zip,
773 script=script,
774 metadata=metadata,
Tao Bao6f0b2192015-10-13 16:37:12 -0700775 info_dict=OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800776
Tao Bao3806c232015-07-05 21:08:33 -0700777 source_fp = CalculateFingerprint(oem_props, oem_dict,
778 OPTIONS.source_info_dict)
779 target_fp = CalculateFingerprint(oem_props, oem_dict,
780 OPTIONS.target_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800781 metadata["pre-build"] = source_fp
782 metadata["post-build"] = target_fp
783
784 source_boot = common.GetBootableImage(
785 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
786 OPTIONS.source_info_dict)
787 target_boot = common.GetBootableImage(
788 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
789 updating_boot = (not OPTIONS.two_step and
790 (source_boot.data != target_boot.data))
791
Geremy Condra36bd3652014-02-06 19:45:10 -0800792 target_recovery = common.GetBootableImage(
793 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800794
Doug Zongkerfc44a512014-08-26 13:10:25 -0700795 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
796 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700797
798 blockimgdiff_version = 1
799 if OPTIONS.info_dict:
800 blockimgdiff_version = max(
801 int(i) for i in
802 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
803
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700804 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700805 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700806
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700807 if HasVendorPartition(target_zip):
808 if not HasVendorPartition(source_zip):
809 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700810 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
811 OPTIONS.source_info_dict)
812 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
813 OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700814 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700815 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700816 else:
817 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800818
Michael Rungec6e3afd2014-05-05 11:55:47 -0700819 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800820 device_specific.IncrementalOTA_Assertions()
821
822 # Two-step incremental package strategy (in chronological order,
823 # which is *not* the order in which the generated script has
824 # things):
825 #
826 # if stage is not "2/3" or "3/3":
827 # do verification on current system
828 # write recovery image to boot partition
829 # set stage to "2/3"
830 # reboot to boot partition and restart recovery
831 # else if stage is "2/3":
832 # write recovery image to recovery partition
833 # set stage to "3/3"
834 # reboot to recovery partition and restart recovery
835 # else:
836 # (stage must be "3/3")
837 # perform update:
838 # patch system files, etc.
839 # force full install of new boot image
840 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700841 # complete script normally
842 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800843
844 if OPTIONS.two_step:
Tao Baodd24da92015-07-29 14:09:23 -0700845 if not OPTIONS.source_info_dict.get("multistage_support", None):
Geremy Condra36bd3652014-02-06 19:45:10 -0800846 assert False, "two-step packages not supported by this build"
Tao Baodd24da92015-07-29 14:09:23 -0700847 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Geremy Condra36bd3652014-02-06 19:45:10 -0800848 assert fs.fs_type.upper() == "EMMC", \
849 "two-step packages only supported on devices with EMMC /misc partitions"
850 bcb_dev = {"bcb_dev": fs.device}
851 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
852 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700853if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800854""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -0700855 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800856 script.WriteRawImage("/recovery", "recovery.img")
857 script.AppendExtra("""
858set_stage("%(bcb_dev)s", "3/3");
859reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700860else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800861""" % bcb_dev)
862
Tao Bao6c55a8a2015-04-08 15:30:27 -0700863 # Dump fingerprints
864 script.Print("Source: %s" % CalculateFingerprint(
865 oem_props, oem_dict, OPTIONS.source_info_dict))
866 script.Print("Target: %s" % CalculateFingerprint(
867 oem_props, oem_dict, OPTIONS.target_info_dict))
868
Geremy Condra36bd3652014-02-06 19:45:10 -0800869 script.Print("Verifying current system...")
870
871 device_specific.IncrementalOTA_VerifyBegin()
872
Michael Rungec6e3afd2014-05-05 11:55:47 -0700873 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700874 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
875 # patching on a device that's already on the target build will damage the
876 # system. Because operations like move don't check the block state, they
877 # always apply the changes unconditionally.
878 if blockimgdiff_version <= 2:
879 script.AssertSomeFingerprint(source_fp)
880 else:
881 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700882 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700883 if blockimgdiff_version <= 2:
884 script.AssertSomeThumbprint(
885 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
886 else:
887 script.AssertSomeThumbprint(
888 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
889 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800890
891 if updating_boot:
Tao Baodd24da92015-07-29 14:09:23 -0700892 boot_type, boot_device = common.GetTypeAndDevice(
893 "/boot", OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800894 d = common.Difference(target_boot, source_boot)
895 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700896 if d is None:
897 include_full_boot = True
898 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
899 else:
900 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800901
Doug Zongkerf8340082014-08-05 10:39:37 -0700902 print "boot target: %d source: %d diff: %d" % (
903 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800904
Doug Zongkerf8340082014-08-05 10:39:37 -0700905 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800906
Doug Zongkerf8340082014-08-05 10:39:37 -0700907 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
908 (boot_type, boot_device,
909 source_boot.size, source_boot.sha1,
910 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800911
912 device_specific.IncrementalOTA_VerifyEnd()
913
914 if OPTIONS.two_step:
915 script.WriteRawImage("/boot", "recovery.img")
916 script.AppendExtra("""
917set_stage("%(bcb_dev)s", "2/3");
918reboot_now("%(bcb_dev)s", "");
919else
920""" % bcb_dev)
921
Jesse Zhao75bcea02015-01-06 10:59:53 -0800922 # Verify the existing partitions.
923 system_diff.WriteVerifyScript(script)
924 if vendor_diff:
925 vendor_diff.WriteVerifyScript(script)
926
Geremy Condra36bd3652014-02-06 19:45:10 -0800927 script.Comment("---- start making changes here ----")
928
929 device_specific.IncrementalOTA_InstallBegin()
930
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700931 system_diff.WriteScript(script, output_zip,
932 progress=0.8 if vendor_diff else 0.9)
Tao Bao68658c02015-06-01 13:40:49 -0700933
Doug Zongkerfc44a512014-08-26 13:10:25 -0700934 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700935 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800936
937 if OPTIONS.two_step:
938 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
939 script.WriteRawImage("/boot", "boot.img")
940 print "writing full boot image (forced by two-step mode)"
941
942 if not OPTIONS.two_step:
943 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700944 if include_full_boot:
945 print "boot image changed; including full."
946 script.Print("Installing boot image...")
947 script.WriteRawImage("/boot", "boot.img")
948 else:
949 # Produce the boot image by applying a patch to the current
950 # contents of the boot partition, and write it back to the
951 # partition.
952 print "boot image changed; including patch."
953 script.Print("Patching boot image...")
954 script.ShowProgress(0.1, 10)
955 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
956 % (boot_type, boot_device,
957 source_boot.size, source_boot.sha1,
958 target_boot.size, target_boot.sha1),
959 "-",
960 target_boot.size, target_boot.sha1,
961 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800962 else:
963 print "boot image unchanged; skipping."
964
965 # Do device-specific installation (eg, write radio image).
966 device_specific.IncrementalOTA_InstallEnd()
967
968 if OPTIONS.extra_script is not None:
969 script.AppendExtra(OPTIONS.extra_script)
970
Doug Zongker922206e2014-03-04 13:16:24 -0800971 if OPTIONS.wipe_user_data:
972 script.Print("Erasing user data...")
973 script.FormatPartition("/data")
974
Geremy Condra36bd3652014-02-06 19:45:10 -0800975 if OPTIONS.two_step:
976 script.AppendExtra("""
977set_stage("%(bcb_dev)s", "");
978endif;
979endif;
980""" % bcb_dev)
981
982 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800983 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800984 WriteMetadata(metadata, output_zip)
985
Doug Zongker32b527d2014-03-04 10:03:02 -0800986
Dan Albert8b72aef2015-03-23 19:13:21 -0700987class FileDifference(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700988 def __init__(self, partition, source_zip, target_zip, output_zip):
Dan Albert8b72aef2015-03-23 19:13:21 -0700989 self.deferred_patch_list = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700990 print "Loading target..."
991 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
992 print "Loading source..."
993 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
994
995 self.verbatim_targets = verbatim_targets = []
996 self.patch_list = patch_list = []
997 diffs = []
998 self.renames = renames = {}
999 known_paths = set()
1000 largest_source_size = 0
1001
1002 matching_file_cache = {}
1003 for fn, sf in source_data.items():
1004 assert fn == sf.name
1005 matching_file_cache["path:" + fn] = sf
1006 if fn in target_data.keys():
1007 AddToKnownPaths(fn, known_paths)
1008 # Only allow eligibility for filename/sha matching
1009 # if there isn't a perfect path match.
1010 if target_data.get(sf.name) is None:
1011 matching_file_cache["file:" + fn.split("/")[-1]] = sf
1012 matching_file_cache["sha:" + sf.sha1] = sf
1013
1014 for fn in sorted(target_data.keys()):
1015 tf = target_data[fn]
1016 assert fn == tf.name
1017 sf = ClosestFileMatch(tf, matching_file_cache, renames)
1018 if sf is not None and sf.name != tf.name:
1019 print "File has moved from " + sf.name + " to " + tf.name
1020 renames[sf.name] = tf
1021
1022 if sf is None or fn in OPTIONS.require_verbatim:
1023 # This file should be included verbatim
1024 if fn in OPTIONS.prohibit_verbatim:
1025 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
1026 print "send", fn, "verbatim"
1027 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001028 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001029 if fn in target_data.keys():
1030 AddToKnownPaths(fn, known_paths)
1031 elif tf.sha1 != sf.sha1:
1032 # File is different; consider sending as a patch
1033 diffs.append(common.Difference(tf, sf))
1034 else:
1035 # Target file data identical to source (may still be renamed)
1036 pass
1037
1038 common.ComputeDifferences(diffs)
1039
1040 for diff in diffs:
1041 tf, sf, d = diff.GetPatch()
1042 path = "/".join(tf.name.split("/")[:-1])
1043 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1044 path not in known_paths:
1045 # patch is almost as big as the file; don't bother patching
1046 # or a patch + rename cannot take place due to the target
1047 # directory not existing
1048 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001049 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001050 if sf.name in renames:
1051 del renames[sf.name]
1052 AddToKnownPaths(tf.name, known_paths)
1053 else:
1054 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1055 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1056 largest_source_size = max(largest_source_size, sf.size)
1057
1058 self.largest_source_size = largest_source_size
1059
1060 def EmitVerification(self, script):
1061 so_far = 0
Dan Albert8b72aef2015-03-23 19:13:21 -07001062 for tf, sf, _, _ in self.patch_list:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001063 if tf.name != sf.name:
1064 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1065 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1066 so_far += sf.size
1067 return so_far
1068
Michael Runge63f01de2014-10-28 19:24:19 -07001069 def EmitExplicitTargetVerification(self, script):
Dan Albert8b72aef2015-03-23 19:13:21 -07001070 for fn, _, sha1 in self.verbatim_targets:
1071 if fn[-1] != "/":
Michael Runge63f01de2014-10-28 19:24:19 -07001072 script.FileCheck("/"+fn, sha1)
1073 for tf, _, _, _ in self.patch_list:
1074 script.FileCheck(tf.name, tf.sha1)
1075
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001076 def RemoveUnneededFiles(self, script, extras=()):
Tao Baoa77d41e2015-09-03 21:17:37 -07001077 file_list = ["/" + i[0] for i in self.verbatim_targets]
1078 file_list += ["/" + i for i in self.source_data
1079 if i not in self.target_data and i not in self.renames]
1080 file_list += list(extras)
1081 # Sort the list in descending order, which removes all the files first
1082 # before attempting to remove the folder. (Bug: 22960996)
1083 script.DeleteFiles(sorted(file_list, reverse=True))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001084
1085 def TotalPatchSize(self):
1086 return sum(i[1].size for i in self.patch_list)
1087
1088 def EmitPatches(self, script, total_patch_size, so_far):
1089 self.deferred_patch_list = deferred_patch_list = []
1090 for item in self.patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001091 tf, sf, _, _ = item
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001092 if tf.name == "system/build.prop":
1093 deferred_patch_list.append(item)
1094 continue
Dan Albert8b72aef2015-03-23 19:13:21 -07001095 if sf.name != tf.name:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001096 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
Dan Albert8b72aef2015-03-23 19:13:21 -07001097 script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1,
1098 "patch/" + sf.name + ".p")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001099 so_far += tf.size
1100 script.SetProgress(so_far / total_patch_size)
1101 return so_far
1102
1103 def EmitDeferredPatches(self, script):
1104 for item in self.deferred_patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001105 tf, sf, _, _ = item
1106 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1,
1107 "patch/" + sf.name + ".p")
1108 script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001109
1110 def EmitRenames(self, script):
1111 if len(self.renames) > 0:
1112 script.Print("Renaming files...")
1113 for src, tgt in self.renames.iteritems():
1114 print "Renaming " + src + " to " + tgt.name
1115 script.RenameFile(src, tgt.name)
1116
1117
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001118def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001119 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1120 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1121
Doug Zongker26e66192014-02-20 13:22:07 -08001122 if (OPTIONS.block_based and
1123 target_has_recovery_patch and
1124 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001125 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1126
Doug Zongker37974732010-09-16 17:44:38 -07001127 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1128 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001129
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001130 if source_version == 0:
1131 print ("WARNING: generating edify script for a source that "
1132 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -07001133 script = edify_generator.EdifyGenerator(
1134 source_version, OPTIONS.target_info_dict,
1135 fstab=OPTIONS.source_info_dict["fstab"])
Doug Zongkereef39442009-04-02 12:14:19 -07001136
Michael Runge6e836112014-04-15 17:40:21 -07001137 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Tao Bao34b47bf2015-06-22 19:17:41 -07001138 recovery_mount_options = OPTIONS.source_info_dict.get(
1139 "recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001140 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001141 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001142 if OPTIONS.oem_source is None:
1143 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001144 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001145 oem_dict = common.LoadDictionaryFromLines(
1146 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001147
Dan Albert8b72aef2015-03-23 19:13:21 -07001148 metadata = {
1149 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1150 OPTIONS.source_info_dict),
1151 "post-timestamp": GetBuildProp("ro.build.date.utc",
1152 OPTIONS.target_info_dict),
1153 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001154
Doug Zongker05d3dea2009-06-22 11:32:31 -07001155 device_specific = common.DeviceSpecificParams(
1156 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001157 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001158 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001159 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001160 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001161 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001162 metadata=metadata,
Tao Bao6f0b2192015-10-13 16:37:12 -07001163 info_dict=OPTIONS.source_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001164
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001165 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001166 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001167 if HasVendorPartition(target_zip):
1168 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001169 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001170 else:
1171 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001172
Dan Albert8b72aef2015-03-23 19:13:21 -07001173 target_fp = CalculateFingerprint(oem_props, oem_dict,
1174 OPTIONS.target_info_dict)
1175 source_fp = CalculateFingerprint(oem_props, oem_dict,
1176 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001177
1178 if oem_props is None:
1179 script.AssertSomeFingerprint(source_fp, target_fp)
1180 else:
1181 script.AssertSomeThumbprint(
1182 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1183 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1184
Doug Zongker2ea21062010-04-28 16:05:21 -07001185 metadata["pre-build"] = source_fp
1186 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001187
Doug Zongker55d93282011-01-25 17:03:34 -08001188 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001189 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1190 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001191 target_boot = common.GetBootableImage(
1192 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001193 updating_boot = (not OPTIONS.two_step and
1194 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001195
Doug Zongker55d93282011-01-25 17:03:34 -08001196 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001197 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1198 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001199 target_recovery = common.GetBootableImage(
1200 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001201 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001202
Doug Zongker881dd402009-09-20 14:03:55 -07001203 # Here's how we divide up the progress bar:
1204 # 0.1 for verifying the start state (PatchCheck calls)
1205 # 0.8 for applying patches (ApplyPatch calls)
1206 # 0.1 for unpacking verbatim files, symlinking, and doing the
1207 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001208
Michael Runge6e836112014-04-15 17:40:21 -07001209 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001210 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001211
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001212 # Two-step incremental package strategy (in chronological order,
1213 # which is *not* the order in which the generated script has
1214 # things):
1215 #
1216 # if stage is not "2/3" or "3/3":
1217 # do verification on current system
1218 # write recovery image to boot partition
1219 # set stage to "2/3"
1220 # reboot to boot partition and restart recovery
1221 # else if stage is "2/3":
1222 # write recovery image to recovery partition
1223 # set stage to "3/3"
1224 # reboot to recovery partition and restart recovery
1225 # else:
1226 # (stage must be "3/3")
1227 # perform update:
1228 # patch system files, etc.
1229 # force full install of new boot image
1230 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001231 # complete script normally
1232 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001233
1234 if OPTIONS.two_step:
Tao Baodd24da92015-07-29 14:09:23 -07001235 if not OPTIONS.source_info_dict.get("multistage_support", None):
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001236 assert False, "two-step packages not supported by this build"
Tao Baodd24da92015-07-29 14:09:23 -07001237 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001238 assert fs.fs_type.upper() == "EMMC", \
1239 "two-step packages only supported on devices with EMMC /misc partitions"
1240 bcb_dev = {"bcb_dev": fs.device}
1241 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1242 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001243if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001244""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001245 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001246 script.WriteRawImage("/recovery", "recovery.img")
1247 script.AppendExtra("""
1248set_stage("%(bcb_dev)s", "3/3");
1249reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001250else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001251""" % bcb_dev)
1252
Tao Bao6c55a8a2015-04-08 15:30:27 -07001253 # Dump fingerprints
1254 script.Print("Source: %s" % (source_fp,))
1255 script.Print("Target: %s" % (target_fp,))
1256
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001257 script.Print("Verifying current system...")
1258
Doug Zongkere5ff5902012-01-17 10:55:37 -08001259 device_specific.IncrementalOTA_VerifyBegin()
1260
Doug Zongker881dd402009-09-20 14:03:55 -07001261 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001262 so_far = system_diff.EmitVerification(script)
1263 if vendor_diff:
1264 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001265
Doug Zongker5da317e2009-06-02 13:38:17 -07001266 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001267 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001268 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001269 print "boot target: %d source: %d diff: %d" % (
1270 target_boot.size, source_boot.size, len(d))
1271
Doug Zongker048e7ca2009-06-15 14:31:53 -07001272 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001273
Tao Baodd24da92015-07-29 14:09:23 -07001274 boot_type, boot_device = common.GetTypeAndDevice(
1275 "/boot", OPTIONS.source_info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001276
1277 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1278 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001279 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001280 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001281 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001282
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001283 size = []
Dan Albert8b72aef2015-03-23 19:13:21 -07001284 if system_diff.patch_list:
1285 size.append(system_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001286 if vendor_diff:
Dan Albert8b72aef2015-03-23 19:13:21 -07001287 if vendor_diff.patch_list:
1288 size.append(vendor_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001289 if size or updating_recovery or updating_boot:
1290 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001291
Doug Zongker05d3dea2009-06-22 11:32:31 -07001292 device_specific.IncrementalOTA_VerifyEnd()
1293
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001294 if OPTIONS.two_step:
1295 script.WriteRawImage("/boot", "recovery.img")
1296 script.AppendExtra("""
1297set_stage("%(bcb_dev)s", "2/3");
1298reboot_now("%(bcb_dev)s", "");
1299else
1300""" % bcb_dev)
1301
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001302 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001303
Doug Zongkere5ff5902012-01-17 10:55:37 -08001304 device_specific.IncrementalOTA_InstallBegin()
1305
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001306 if OPTIONS.two_step:
1307 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1308 script.WriteRawImage("/boot", "boot.img")
1309 print "writing full boot image (forced by two-step mode)"
1310
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001311 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001312 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1313 if vendor_diff:
1314 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001315
Doug Zongker881dd402009-09-20 14:03:55 -07001316 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001317 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1318 if vendor_diff:
1319 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001320 if updating_boot:
1321 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001322
1323 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001324 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1325 if vendor_diff:
1326 script.Print("Patching vendor files...")
1327 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001328
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001329 if not OPTIONS.two_step:
1330 if updating_boot:
1331 # Produce the boot image by applying a patch to the current
1332 # contents of the boot partition, and write it back to the
1333 # partition.
1334 script.Print("Patching boot image...")
1335 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1336 % (boot_type, boot_device,
1337 source_boot.size, source_boot.sha1,
1338 target_boot.size, target_boot.sha1),
1339 "-",
1340 target_boot.size, target_boot.sha1,
1341 source_boot.sha1, "patch/boot.img.p")
1342 so_far += target_boot.size
1343 script.SetProgress(so_far / total_patch_size)
1344 print "boot image changed; including."
1345 else:
1346 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001347
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001348 system_items = ItemSet("system", "META/filesystem_config.txt")
1349 if vendor_diff:
1350 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1351
Doug Zongkereef39442009-04-02 12:14:19 -07001352 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001353 # Recovery is generated as a patch using both the boot image
1354 # (which contains the same linux kernel as recovery) and the file
1355 # /system/etc/recovery-resource.dat (which contains all the images
1356 # used in the recovery UI) as sources. This lets us minimize the
1357 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001358 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001359 # For older builds where recovery-resource.dat is not present, we
1360 # use only the boot image as the source.
1361
Doug Zongkerc9253822014-02-04 12:17:58 -08001362 if not target_has_recovery_patch:
1363 def output_sink(fn, data):
1364 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001365 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001366
1367 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1368 target_recovery, target_boot)
1369 script.DeleteFiles(["/system/recovery-from-boot.p",
Tao Baof2cffbd2015-07-22 12:33:18 -07001370 "/system/etc/recovery.img",
Doug Zongkerc9253822014-02-04 12:17:58 -08001371 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001372 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001373 else:
1374 print "recovery image unchanged; skipping."
1375
Doug Zongker881dd402009-09-20 14:03:55 -07001376 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001377
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001378 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1379 if vendor_diff:
1380 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1381
1382 temp_script = script.MakeTemporary()
1383 system_items.GetMetadata(target_zip)
1384 system_items.Get("system").SetPermissions(temp_script)
1385 if vendor_diff:
1386 vendor_items.GetMetadata(target_zip)
1387 vendor_items.Get("vendor").SetPermissions(temp_script)
1388
1389 # Note that this call will mess up the trees of Items, so make sure
1390 # we're done with them.
1391 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1392 if vendor_diff:
1393 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001394
1395 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001396 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1397
1398 # Delete all the symlinks in source that aren't in target. This
1399 # needs to happen before verbatim files are unpacked, in case a
1400 # symlink in the source is replaced by a real file in the target.
Tao Bao84006ea2015-09-02 10:28:08 -07001401
1402 # If a symlink in the source will be replaced by a regular file, we cannot
1403 # delete the symlink/file in case the package gets applied again. For such
1404 # a symlink, we prepend a sha1_check() to detect if it has been updated.
1405 # (Bug: 23646151)
1406 replaced_symlinks = dict()
1407 if system_diff:
1408 for i in system_diff.verbatim_targets:
1409 replaced_symlinks["/%s" % (i[0],)] = i[2]
1410 if vendor_diff:
1411 for i in vendor_diff.verbatim_targets:
1412 replaced_symlinks["/%s" % (i[0],)] = i[2]
1413
1414 if system_diff:
1415 for tf in system_diff.renames.values():
1416 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1417 if vendor_diff:
1418 for tf in vendor_diff.renames.values():
1419 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1420
1421 always_delete = []
1422 may_delete = []
Doug Zongkereef39442009-04-02 12:14:19 -07001423 for dest, link in source_symlinks:
1424 if link not in target_symlinks_d:
Tao Bao84006ea2015-09-02 10:28:08 -07001425 if link in replaced_symlinks:
1426 may_delete.append((link, replaced_symlinks[link]))
1427 else:
1428 always_delete.append(link)
1429 script.DeleteFiles(always_delete)
1430 script.DeleteFilesIfNotMatching(may_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001431
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001432 if system_diff.verbatim_targets:
1433 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001434 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001435 if vendor_diff and vendor_diff.verbatim_targets:
1436 script.Print("Unpacking new vendor files...")
1437 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001438
Doug Zongkerc9253822014-02-04 12:17:58 -08001439 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001440 script.Print("Unpacking new recovery...")
1441 script.UnpackPackageDir("recovery", "/system")
1442
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001443 system_diff.EmitRenames(script)
1444 if vendor_diff:
1445 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001446
Doug Zongker05d3dea2009-06-22 11:32:31 -07001447 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001448
1449 # Create all the symlinks that don't already exist, or point to
1450 # somewhere different than what we want. Delete each symlink before
1451 # creating it, since the 'symlink' command won't overwrite.
1452 to_create = []
1453 for dest, link in target_symlinks:
1454 if link in source_symlinks_d:
1455 if dest != source_symlinks_d[link]:
1456 to_create.append((dest, link))
1457 else:
1458 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001459 script.DeleteFiles([i[1] for i in to_create])
1460 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001461
1462 # Now that the symlinks are created, we can set all the
1463 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001464 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001465
Doug Zongker881dd402009-09-20 14:03:55 -07001466 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001467 device_specific.IncrementalOTA_InstallEnd()
1468
Doug Zongker1c390a22009-05-14 19:06:36 -07001469 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001470 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001471
Doug Zongkere92f15a2011-08-26 13:46:40 -07001472 # Patch the build.prop file last, so if something fails but the
1473 # device can still come up, it appears to be the old build and will
1474 # get set the OTA package again to retry.
1475 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001476 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001477
Doug Zongker922206e2014-03-04 13:16:24 -08001478 if OPTIONS.wipe_user_data:
1479 script.Print("Erasing user data...")
1480 script.FormatPartition("/data")
1481
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001482 if OPTIONS.two_step:
1483 script.AppendExtra("""
1484set_stage("%(bcb_dev)s", "");
1485endif;
1486endif;
1487""" % bcb_dev)
1488
Michael Runge63f01de2014-10-28 19:24:19 -07001489 if OPTIONS.verify and system_diff:
1490 script.Print("Remounting and verifying system partition files...")
1491 script.Unmount("/system")
1492 script.Mount("/system")
1493 system_diff.EmitExplicitTargetVerification(script)
1494
1495 if OPTIONS.verify and vendor_diff:
1496 script.Print("Remounting and verifying vendor partition files...")
1497 script.Unmount("/vendor")
1498 script.Mount("/vendor")
1499 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001500 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001501
Doug Zongker2ea21062010-04-28 16:05:21 -07001502 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001503
1504
1505def main(argv):
1506
1507 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001508 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001509 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001510 elif o in ("-k", "--package_key"):
1511 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001512 elif o in ("-i", "--incremental_from"):
1513 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001514 elif o == "--full_radio":
1515 OPTIONS.full_radio = True
leozwangaa6c1a12015-08-14 10:57:58 -07001516 elif o == "--full_bootloader":
1517 OPTIONS.full_bootloader = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001518 elif o in ("-w", "--wipe_user_data"):
1519 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001520 elif o in ("-n", "--no_prereq"):
1521 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001522 elif o in ("-o", "--oem_settings"):
1523 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001524 elif o in ("-e", "--extra_script"):
1525 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001526 elif o in ("-a", "--aslr_mode"):
1527 if a in ("on", "On", "true", "True", "yes", "Yes"):
1528 OPTIONS.aslr_mode = True
1529 else:
1530 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001531 elif o in ("-t", "--worker_threads"):
1532 if a.isdigit():
1533 OPTIONS.worker_threads = int(a)
1534 else:
1535 raise ValueError("Cannot parse value %r for option %r - only "
1536 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001537 elif o in ("-2", "--two_step"):
1538 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001539 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001540 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001541 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001542 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001543 elif o == "--block":
1544 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001545 elif o in ("-b", "--binary"):
1546 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001547 elif o in ("--no_fallback_to_full",):
1548 OPTIONS.fallback_to_full = False
Tao Bao8dcf7382015-05-21 14:09:49 -07001549 elif o == "--stash_threshold":
1550 try:
1551 OPTIONS.stash_threshold = float(a)
1552 except ValueError:
1553 raise ValueError("Cannot parse value %r for option %r - expecting "
1554 "a float" % (a, o))
Doug Zongkereef39442009-04-02 12:14:19 -07001555 else:
1556 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001557 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001558
1559 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001560 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001561 extra_long_opts=[
1562 "board_config=",
1563 "package_key=",
1564 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001565 "full_radio",
leozwangaa6c1a12015-08-14 10:57:58 -07001566 "full_bootloader",
Dan Albert8b72aef2015-03-23 19:13:21 -07001567 "wipe_user_data",
1568 "no_prereq",
1569 "extra_script=",
1570 "worker_threads=",
1571 "aslr_mode=",
1572 "two_step",
1573 "no_signing",
1574 "block",
1575 "binary=",
1576 "oem_settings=",
1577 "verify",
1578 "no_fallback_to_full",
Tao Bao8dcf7382015-05-21 14:09:49 -07001579 "stash_threshold=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001580 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001581
1582 if len(args) != 2:
1583 common.Usage(__doc__)
1584 sys.exit(1)
1585
Doug Zongker1c390a22009-05-14 19:06:36 -07001586 if OPTIONS.extra_script is not None:
1587 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1588
Doug Zongkereef39442009-04-02 12:14:19 -07001589 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001590 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001591
Doug Zongkereef39442009-04-02 12:14:19 -07001592 OPTIONS.target_tmp = OPTIONS.input_tmp
Tao Bao2c15d9e2015-07-09 11:51:16 -07001593 OPTIONS.info_dict = common.LoadInfoDict(input_zip, OPTIONS.target_tmp)
Kenny Roote2e9f612013-05-29 12:59:35 -07001594
Doug Zongker37974732010-09-16 17:44:38 -07001595 if OPTIONS.verbose:
1596 print "--- target info ---"
1597 common.DumpInfoDict(OPTIONS.info_dict)
1598
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001599 # If the caller explicitly specified the device-specific extensions
1600 # path via -s/--device_specific, use that. Otherwise, use
1601 # META/releasetools.py if it is present in the target target_files.
1602 # Otherwise, take the path of the file from 'tool_extensions' in the
1603 # info dict and look for that in the local filesystem, relative to
1604 # the current directory.
1605
Doug Zongker37974732010-09-16 17:44:38 -07001606 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001607 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1608 if os.path.exists(from_input):
1609 print "(using device-specific extensions from target_files)"
1610 OPTIONS.device_specific = from_input
1611 else:
1612 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1613
Doug Zongker37974732010-09-16 17:44:38 -07001614 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001615 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001616
Tao Baodb45efa2015-10-27 19:25:18 -07001617 if OPTIONS.info_dict.get("no_recovery") == "true":
1618 raise common.ExternalError(
1619 "--- target build has specified no recovery ---")
1620
Doug Zongker62d4f182014-08-04 16:06:43 -07001621 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001622
Doug Zongker62d4f182014-08-04 16:06:43 -07001623 if OPTIONS.no_signing:
Dan Albert8b72aef2015-03-23 19:13:21 -07001624 if os.path.exists(args[1]):
1625 os.unlink(args[1])
1626 output_zip = zipfile.ZipFile(args[1], "w",
1627 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001628 else:
1629 temp_zip_file = tempfile.NamedTemporaryFile()
1630 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1631 compression=zipfile.ZIP_DEFLATED)
1632
Tao Bao8dcf7382015-05-21 14:09:49 -07001633 cache_size = OPTIONS.info_dict.get("cache_size", None)
1634 if cache_size is None:
Tao Bao575d68a2015-08-07 19:49:45 -07001635 print "--- can't determine the cache partition size ---"
Tao Bao8dcf7382015-05-21 14:09:49 -07001636 OPTIONS.cache_size = cache_size
1637
Doug Zongker62d4f182014-08-04 16:06:43 -07001638 if OPTIONS.incremental_source is None:
1639 WriteFullOTAPackage(input_zip, output_zip)
1640 if OPTIONS.package_key is None:
1641 OPTIONS.package_key = OPTIONS.info_dict.get(
1642 "default_system_dev_certificate",
1643 "build/target/product/security/testkey")
Tao Bao2ed665a2015-04-01 11:21:55 -07001644 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001645 break
1646
1647 else:
1648 print "unzipping source target-files..."
Dan Albert8b72aef2015-03-23 19:13:21 -07001649 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
1650 OPTIONS.incremental_source)
Doug Zongker62d4f182014-08-04 16:06:43 -07001651 OPTIONS.target_info_dict = OPTIONS.info_dict
Tao Bao2c15d9e2015-07-09 11:51:16 -07001652 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip,
1653 OPTIONS.source_tmp)
Doug Zongker62d4f182014-08-04 16:06:43 -07001654 if OPTIONS.package_key is None:
1655 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1656 "default_system_dev_certificate",
1657 "build/target/product/security/testkey")
1658 if OPTIONS.verbose:
1659 print "--- source info ---"
1660 common.DumpInfoDict(OPTIONS.source_info_dict)
1661 try:
1662 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Bao2ed665a2015-04-01 11:21:55 -07001663 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001664 break
1665 except ValueError:
Dan Albert8b72aef2015-03-23 19:13:21 -07001666 if not OPTIONS.fallback_to_full:
1667 raise
Doug Zongker62d4f182014-08-04 16:06:43 -07001668 print "--- failed to build incremental; falling back to full ---"
1669 OPTIONS.incremental_source = None
Tao Bao2ed665a2015-04-01 11:21:55 -07001670 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001671
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001672 if not OPTIONS.no_signing:
1673 SignOutput(temp_zip_file.name, args[1])
1674 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001675
Doug Zongkereef39442009-04-02 12:14:19 -07001676 print "done."
1677
1678
1679if __name__ == '__main__':
1680 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001681 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001682 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001683 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07001684 print
1685 print " ERROR: %s" % (e,)
1686 print
1687 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001688 finally:
1689 common.Cleanup()