blob: fd57b9398e4404608e20dc1e9d3ad8e93464a4d7 [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).
Tao Bao9bc6bb22015-11-09 16:58:28 -080094
95 --gen_verify
96 Generate an OTA package that verifies the partitions.
Doug Zongkereef39442009-04-02 12:14:19 -070097"""
98
99import sys
100
Doug Zongkercf6d5a92014-02-18 10:57:07 -0800101if sys.hexversion < 0x02070000:
102 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -0700103 sys.exit(1)
104
Doug Zongkerfc44a512014-08-26 13:10:25 -0700105import multiprocessing
Doug Zongkereef39442009-04-02 12:14:19 -0700106import os
Doug Zongkereef39442009-04-02 12:14:19 -0700107import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -0700108import zipfile
109
110import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700111import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -0700112import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700113
114OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700115OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700116OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700117OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700118OPTIONS.require_verbatim = set()
119OPTIONS.prohibit_verbatim = set(("system/build.prop",))
120OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700121OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700122OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700123OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700124OPTIONS.aslr_mode = True
Doug Zongkerfc44a512014-08-26 13:10:25 -0700125OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
126if OPTIONS.worker_threads == 0:
127 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800128OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900129OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800130OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800131OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700132OPTIONS.oem_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -0700133OPTIONS.fallback_to_full = True
Tao Bao43078aa2015-04-21 14:32:35 -0700134OPTIONS.full_radio = False
leozwangaa6c1a12015-08-14 10:57:58 -0700135OPTIONS.full_bootloader = False
Tao Baod47d8e12015-05-21 14:09:49 -0700136# Stash size cannot exceed cache_size * threshold.
137OPTIONS.cache_size = None
138OPTIONS.stash_threshold = 0.8
Tao Bao9bc6bb22015-11-09 16:58:28 -0800139OPTIONS.gen_verify = False
Tao Bao8dcf7382015-05-21 14:09:49 -0700140
Doug Zongkereef39442009-04-02 12:14:19 -0700141def MostPopularKey(d, default):
142 """Given a dict, return the key corresponding to the largest
143 value. Returns 'default' if the dict is empty."""
144 x = [(v, k) for (k, v) in d.iteritems()]
Dan Albert8b72aef2015-03-23 19:13:21 -0700145 if not x:
146 return default
Doug Zongkereef39442009-04-02 12:14:19 -0700147 x.sort()
148 return x[-1][1]
149
150
151def IsSymlink(info):
152 """Return true if the zipfile.ZipInfo object passed in represents a
153 symlink."""
Ying Wang2ffb3142015-07-06 14:02:01 -0700154 return (info.external_attr >> 16) & 0o770000 == 0o120000
Doug Zongkereef39442009-04-02 12:14:19 -0700155
Hristo Bojinov96be7202010-08-02 10:26:17 -0700156def IsRegular(info):
157 """Return true if the zipfile.ZipInfo object passed in represents a
Ying Wang2ffb3142015-07-06 14:02:01 -0700158 regular file."""
159 return (info.external_attr >> 16) & 0o770000 == 0o100000
Doug Zongkereef39442009-04-02 12:14:19 -0700160
Michael Runge4038aa82013-12-13 18:06:28 -0800161def ClosestFileMatch(src, tgtfiles, existing):
162 """Returns the closest file match between a source file and list
163 of potential matches. The exact filename match is preferred,
164 then the sha1 is searched for, and finally a file with the same
165 basename is evaluated. Rename support in the updater-binary is
166 required for the latter checks to be used."""
167
168 result = tgtfiles.get("path:" + src.name)
169 if result is not None:
170 return result
171
172 if not OPTIONS.target_info_dict.get("update_rename_support", False):
173 return None
174
175 if src.size < 1000:
176 return None
177
178 result = tgtfiles.get("sha1:" + src.sha1)
179 if result is not None and existing.get(result.name) is None:
180 return result
181 result = tgtfiles.get("file:" + src.name.split("/")[-1])
182 if result is not None and existing.get(result.name) is None:
183 return result
184 return None
185
Dan Albert8b72aef2015-03-23 19:13:21 -0700186class ItemSet(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700187 def __init__(self, partition, fs_config):
188 self.partition = partition
189 self.fs_config = fs_config
190 self.ITEMS = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700191
Dan Albert8b72aef2015-03-23 19:13:21 -0700192 def Get(self, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700193 if name not in self.ITEMS:
Dan Albert8b72aef2015-03-23 19:13:21 -0700194 self.ITEMS[name] = Item(self, name, is_dir=is_dir)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700195 return self.ITEMS[name]
Doug Zongkereef39442009-04-02 12:14:19 -0700196
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700197 def GetMetadata(self, input_zip):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700198 # The target_files contains a record of what the uid,
199 # gid, and mode are supposed to be.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700200 output = input_zip.read(self.fs_config)
Doug Zongkereef39442009-04-02 12:14:19 -0700201
202 for line in output.split("\n"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700203 if not line:
204 continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700205 columns = line.split()
206 name, uid, gid, mode = columns[:4]
207 selabel = None
208 capabilities = None
209
210 # After the first 4 columns, there are a series of key=value
211 # pairs. Extract out the fields we care about.
212 for element in columns[4:]:
213 key, value = element.split("=")
214 if key == "selabel":
215 selabel = value
216 if key == "capabilities":
217 capabilities = value
218
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700219 i = self.ITEMS.get(name, None)
Doug Zongker283e2a12010-03-15 17:52:32 -0700220 if i is not None:
221 i.uid = int(uid)
222 i.gid = int(gid)
223 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700224 i.selabel = selabel
225 i.capabilities = capabilities
Dan Albert8b72aef2015-03-23 19:13:21 -0700226 if i.is_dir:
Doug Zongker283e2a12010-03-15 17:52:32 -0700227 i.children.sort(key=lambda i: i.name)
228
Tao Baof2cffbd2015-07-22 12:33:18 -0700229 # Set metadata for the files generated by this script. For full recovery
230 # image at system/etc/recovery.img, it will be taken care by fs_config.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700231 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700232 if i:
233 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700234 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700235 if i:
236 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700237
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700238
Dan Albert8b72aef2015-03-23 19:13:21 -0700239class Item(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700240 """Items represent the metadata (user, group, mode) of files and
241 directories in the system image."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700242 def __init__(self, itemset, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700243 self.itemset = itemset
244 self.name = name
245 self.uid = None
246 self.gid = None
247 self.mode = None
248 self.selabel = None
249 self.capabilities = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700250 self.is_dir = is_dir
251 self.descendants = None
252 self.best_subtree = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700253
254 if name:
Dan Albert8b72aef2015-03-23 19:13:21 -0700255 self.parent = itemset.Get(os.path.dirname(name), is_dir=True)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700256 self.parent.children.append(self)
257 else:
258 self.parent = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700259 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700260 self.children = []
261
262 def Dump(self, indent=0):
263 if self.uid is not None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700264 print "%s%s %d %d %o" % (
265 " " * indent, self.name, self.uid, self.gid, self.mode)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700266 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700267 print "%s%s %s %s %s" % (
268 " " * indent, self.name, self.uid, self.gid, self.mode)
269 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700270 print "%s%s" % (" "*indent, self.descendants)
271 print "%s%s" % (" "*indent, self.best_subtree)
272 for i in self.children:
273 i.Dump(indent=indent+1)
274
Doug Zongkereef39442009-04-02 12:14:19 -0700275 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700276 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
Dan Albert8b72aef2015-03-23 19:13:21 -0700277 all children and determine the best strategy for using set_perm_recursive
278 and set_perm to correctly chown/chmod all the files to their desired
Doug Zongkereef39442009-04-02 12:14:19 -0700279 values. Recursively calls itself for all descendants.
280
Dan Albert8b72aef2015-03-23 19:13:21 -0700281 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count}
282 counting up all descendants of this node. (dmode or fmode may be None.)
283 Also sets the best_subtree of each directory Item to the (uid, gid, dmode,
284 fmode, selabel, capabilities) tuple that will match the most descendants of
285 that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700286 """
287
Dan Albert8b72aef2015-03-23 19:13:21 -0700288 assert self.is_dir
289 key = (self.uid, self.gid, self.mode, None, self.selabel,
290 self.capabilities)
291 self.descendants = {key: 1}
292 d = self.descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700293 for i in self.children:
Dan Albert8b72aef2015-03-23 19:13:21 -0700294 if i.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700295 for k, v in i.CountChildMetadata().iteritems():
296 d[k] = d.get(k, 0) + v
297 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700298 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700299 d[k] = d.get(k, 0) + 1
300
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700301 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
302 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700303
304 # First, find the (uid, gid) pair that matches the most
305 # descendants.
306 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700307 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700308 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
309 ug = MostPopularKey(ug, (0, 0))
310
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700311 # Now find the dmode, fmode, selabel, and capabilities that match
312 # the most descendants with that (uid, gid), and choose those.
Dan Albert8b72aef2015-03-23 19:13:21 -0700313 best_dmode = (0, 0o755)
314 best_fmode = (0, 0o644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700315 best_selabel = (0, None)
316 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700317 for k, count in d.iteritems():
Dan Albert8b72aef2015-03-23 19:13:21 -0700318 if k[:2] != ug:
319 continue
320 if k[2] is not None and count >= best_dmode[0]:
321 best_dmode = (count, k[2])
322 if k[3] is not None and count >= best_fmode[0]:
323 best_fmode = (count, k[3])
324 if k[4] is not None and count >= best_selabel[0]:
325 best_selabel = (count, k[4])
326 if k[5] is not None and count >= best_capabilities[0]:
327 best_capabilities = (count, k[5])
328 self.best_subtree = ug + (
329 best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700330
331 return d
332
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700333 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700334 """Append set_perm/set_perm_recursive commands to 'script' to
335 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700336 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700337
338 self.CountChildMetadata()
339
340 def recurse(item, current):
Dan Albert8b72aef2015-03-23 19:13:21 -0700341 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple
342 # that the current item (and all its children) have already been set to.
343 # We only need to issue set_perm/set_perm_recursive commands if we're
Doug Zongkereef39442009-04-02 12:14:19 -0700344 # supposed to be something different.
Dan Albert8b72aef2015-03-23 19:13:21 -0700345 if item.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700346 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700347 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700348 current = item.best_subtree
349
350 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700351 item.mode != current[2] or item.selabel != current[4] or \
352 item.capabilities != current[5]:
353 script.SetPermissions("/"+item.name, item.uid, item.gid,
354 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700355
356 for i in item.children:
357 recurse(i, current)
358 else:
359 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700360 item.mode != current[3] or item.selabel != current[4] or \
361 item.capabilities != current[5]:
362 script.SetPermissions("/"+item.name, item.uid, item.gid,
363 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700364
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700365 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700366
367
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700368def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
369 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700370 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800371 list of symlinks. output_zip may be None, in which case the copy is
372 skipped (but the other side effects still happen). substitute is an
373 optional dict of {output filename: contents} to be output instead of
374 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700375 """
376
377 symlinks = []
378
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700379 partition = itemset.partition
380
Doug Zongkereef39442009-04-02 12:14:19 -0700381 for info in input_zip.infolist():
Tao Baoeaf885b2015-03-23 16:01:17 -0700382 prefix = partition.upper() + "/"
383 if info.filename.startswith(prefix):
384 basefilename = info.filename[len(prefix):]
Doug Zongkereef39442009-04-02 12:14:19 -0700385 if IsSymlink(info):
386 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700387 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700388 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700389 import copy
Doug Zongkereef39442009-04-02 12:14:19 -0700390 info2 = copy.copy(info)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700391 fn = info2.filename = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700392 if substitute and fn in substitute and substitute[fn] is None:
393 continue
394 if output_zip is not None:
395 if substitute and fn in substitute:
396 data = substitute[fn]
397 else:
398 data = input_zip.read(info.filename)
Tao Bao2ed665a2015-04-01 11:21:55 -0700399 common.ZipWriteStr(output_zip, info2, data)
Doug Zongkereef39442009-04-02 12:14:19 -0700400 if fn.endswith("/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700401 itemset.Get(fn[:-1], is_dir=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700402 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700403 itemset.Get(fn)
Doug Zongkereef39442009-04-02 12:14:19 -0700404
405 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800406 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700407
408
Doug Zongkereef39442009-04-02 12:14:19 -0700409def SignOutput(temp_zip_name, output_zip_name):
410 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
411 pw = key_passwords[OPTIONS.package_key]
412
Doug Zongker951495f2009-08-14 12:44:19 -0700413 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
414 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700415
416
Dan Albert8b72aef2015-03-23 19:13:21 -0700417def AppendAssertions(script, info_dict, oem_dict=None):
Michael Runge6e836112014-04-15 17:40:21 -0700418 oem_props = info_dict.get("oem_fingerprint_properties")
Michael Runge560569a2014-09-18 15:12:45 -0700419 if oem_props is None or len(oem_props) == 0:
Michael Runge6e836112014-04-15 17:40:21 -0700420 device = GetBuildProp("ro.product.device", info_dict)
421 script.AssertDevice(device)
422 else:
423 if oem_dict is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700424 raise common.ExternalError(
425 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700426 for prop in oem_props.split():
427 if oem_dict.get(prop) is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700428 raise common.ExternalError(
429 "The OEM file is missing the property %s" % prop)
Michael Runge6e836112014-04-15 17:40:21 -0700430 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700431
Doug Zongkereef39442009-04-02 12:14:19 -0700432
Doug Zongkerc9253822014-02-04 12:17:58 -0800433def HasRecoveryPatch(target_files_zip):
Tao Baof2cffbd2015-07-22 12:33:18 -0700434 namelist = [name for name in target_files_zip.namelist()]
435 return ("SYSTEM/recovery-from-boot.p" in namelist or
436 "SYSTEM/etc/recovery.img" in namelist)
Doug Zongker73ef8252009-07-23 15:12:53 -0700437
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700438def HasVendorPartition(target_files_zip):
439 try:
440 target_files_zip.getinfo("VENDOR/")
441 return True
442 except KeyError:
443 return False
444
Michael Runge6e836112014-04-15 17:40:21 -0700445def GetOemProperty(name, oem_props, oem_dict, info_dict):
446 if oem_props is not None and name in oem_props:
447 return oem_dict[name]
448 return GetBuildProp(name, info_dict)
449
450
451def CalculateFingerprint(oem_props, oem_dict, info_dict):
452 if oem_props is None:
453 return GetBuildProp("ro.build.fingerprint", info_dict)
454 return "%s/%s/%s:%s" % (
Dan Albert8b72aef2015-03-23 19:13:21 -0700455 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
456 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
457 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
458 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700459
Doug Zongkerfc44a512014-08-26 13:10:25 -0700460
Doug Zongker3c84f562014-07-31 11:06:30 -0700461def GetImage(which, tmpdir, info_dict):
Doug Zongkerfc44a512014-08-26 13:10:25 -0700462 # Return an image object (suitable for passing to BlockImageDiff)
463 # for the 'which' partition (most be "system" or "vendor"). If a
464 # prebuilt image and file map are found in tmpdir they are used,
465 # otherwise they are reconstructed from the individual files.
Doug Zongker3c84f562014-07-31 11:06:30 -0700466
467 assert which in ("system", "vendor")
468
469 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700470 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
471 if os.path.exists(path) and os.path.exists(mappath):
Doug Zongker3c84f562014-07-31 11:06:30 -0700472 print "using %s.img from target-files" % (which,)
Doug Zongker3c84f562014-07-31 11:06:30 -0700473 # This is a 'new' target-files, which already has the image in it.
Doug Zongker3c84f562014-07-31 11:06:30 -0700474
475 else:
476 print "building %s.img from target-files" % (which,)
477
478 # This is an 'old' target-files, which does not contain images
479 # already built. Build them.
480
Doug Zongkerfc44a512014-08-26 13:10:25 -0700481 mappath = tempfile.mkstemp()[1]
482 OPTIONS.tempfiles.append(mappath)
483
Doug Zongker3c84f562014-07-31 11:06:30 -0700484 import add_img_to_target_files
485 if which == "system":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700486 path = add_img_to_target_files.BuildSystem(
487 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700488 elif which == "vendor":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700489 path = add_img_to_target_files.BuildVendor(
490 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700491
Tao Baoff777812015-05-12 11:42:31 -0700492 # Bug: http://b/20939131
493 # In ext4 filesystems, block 0 might be changed even being mounted
494 # R/O. We add it to clobbered_blocks so that it will be written to the
495 # target unconditionally. Note that they are still part of care_map.
496 clobbered_blocks = "0"
497
498 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700499
500
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700501def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700502 # TODO: how to determine this? We don't know what version it will
Tao Bao34b47bf2015-06-22 19:17:41 -0700503 # be installed on top of. For now, we expect the API just won't
504 # change very often. Similarly for fstab, it might have changed
505 # in the target build.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700506 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700507
Michael Runge6e836112014-04-15 17:40:21 -0700508 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700509 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700510 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700511 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700512 if OPTIONS.oem_source is None:
513 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700514 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700515 oem_dict = common.LoadDictionaryFromLines(
516 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -0700517
Dan Albert8b72aef2015-03-23 19:13:21 -0700518 metadata = {
519 "post-build": CalculateFingerprint(oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700520 OPTIONS.info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700521 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
522 OPTIONS.info_dict),
523 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
524 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700525
Doug Zongker05d3dea2009-06-22 11:32:31 -0700526 device_specific = common.DeviceSpecificParams(
527 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700528 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700529 output_zip=output_zip,
530 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700531 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700532 metadata=metadata,
533 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700534
Doug Zongkerc9253822014-02-04 12:17:58 -0800535 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800536 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800537
Doug Zongker962069c2009-04-23 11:41:58 -0700538 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700539 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700540 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
541 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700542
Michael Runge6e836112014-04-15 17:40:21 -0700543 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700544 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800545
546 # Two-step package strategy (in chronological order, which is *not*
547 # the order in which the generated script has things):
548 #
549 # if stage is not "2/3" or "3/3":
550 # write recovery image to boot partition
551 # set stage to "2/3"
552 # reboot to boot partition and restart recovery
553 # else if stage is "2/3":
554 # write recovery image to recovery partition
555 # set stage to "3/3"
556 # reboot to recovery partition and restart recovery
557 # else:
558 # (stage must be "3/3")
559 # set stage to ""
560 # do normal full package installation:
561 # wipe and install system, boot image, etc.
562 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700563 # complete script normally
564 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800565
566 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
567 OPTIONS.input_tmp, "RECOVERY")
568 if OPTIONS.two_step:
569 if not OPTIONS.info_dict.get("multistage_support", None):
570 assert False, "two-step packages not supported by this build"
571 fs = OPTIONS.info_dict["fstab"]["/misc"]
572 assert fs.fs_type.upper() == "EMMC", \
573 "two-step packages only supported on devices with EMMC /misc partitions"
574 bcb_dev = {"bcb_dev": fs.device}
575 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
576 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700577if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800578""" % bcb_dev)
579 script.WriteRawImage("/recovery", "recovery.img")
580 script.AppendExtra("""
581set_stage("%(bcb_dev)s", "3/3");
582reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700583else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800584""" % bcb_dev)
585
Tao Bao6c55a8a2015-04-08 15:30:27 -0700586 # Dump fingerprints
587 script.Print("Target: %s" % CalculateFingerprint(
588 oem_props, oem_dict, OPTIONS.info_dict))
589
Doug Zongkere5ff5902012-01-17 10:55:37 -0800590 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700591
Doug Zongker01ce19c2014-02-04 13:48:15 -0800592 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700593
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700594 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800595 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700596 if HasVendorPartition(input_zip):
597 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700598
Stephen Smalleyd3a803e2015-08-04 14:59:06 -0400599 # Place a copy of file_contexts.bin into the OTA package which will be used
600 # by the recovery program.
Kenny Rootf32dc712012-04-08 10:42:34 -0700601 if "selinux_fc" in OPTIONS.info_dict:
602 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500603
Michael Runge7cd99ba2014-10-22 17:21:48 -0700604 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
605
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700606 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700607 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800608
Doug Zongker26e66192014-02-20 13:22:07 -0800609 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700610 # Full OTA is done as an "incremental" against an empty source
611 # image. This has the effect of writing new data from the package
612 # to the entire partition, but lets us reuse the updater code that
613 # writes incrementals to do it.
614 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
615 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700616 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700617 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800618 else:
619 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700620 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800621 if not has_recovery_patch:
622 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800623 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700624
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700625 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800626 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700627
Tao Bao7a5bf8a2015-07-21 18:01:20 -0700628 boot_img = common.GetBootableImage(
629 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800630
Doug Zongker91a99c22014-05-09 13:15:01 -0700631 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800632 def output_sink(fn, data):
633 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700634 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800635
636 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
637 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700638
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700639 system_items.GetMetadata(input_zip)
640 system_items.Get("system").SetPermissions(script)
641
642 if HasVendorPartition(input_zip):
643 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
644 script.ShowProgress(0.1, 0)
645
646 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700647 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
648 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700649 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700650 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700651 else:
652 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700653 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700654 script.UnpackPackageDir("vendor", "/vendor")
655
656 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
657 script.MakeSymlinks(symlinks)
658
659 vendor_items.GetMetadata(input_zip)
660 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700661
Doug Zongker37974732010-09-16 17:44:38 -0700662 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700663 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700664
Doug Zongker01ce19c2014-02-04 13:48:15 -0800665 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700666 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700667
Doug Zongker01ce19c2014-02-04 13:48:15 -0800668 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700669 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700670
Doug Zongker1c390a22009-05-14 19:06:36 -0700671 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700672 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700673
Doug Zongker14833602010-02-02 13:12:04 -0800674 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800675
Doug Zongker922206e2014-03-04 13:16:24 -0800676 if OPTIONS.wipe_user_data:
677 script.ShowProgress(0.1, 10)
678 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700679
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800680 if OPTIONS.two_step:
681 script.AppendExtra("""
682set_stage("%(bcb_dev)s", "");
683""" % bcb_dev)
684 script.AppendExtra("else\n")
685 script.WriteRawImage("/boot", "recovery.img")
686 script.AppendExtra("""
687set_stage("%(bcb_dev)s", "2/3");
688reboot_now("%(bcb_dev)s", "");
689endif;
690endif;
691""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800692 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700693 WriteMetadata(metadata, output_zip)
694
Doug Zongkerfc44a512014-08-26 13:10:25 -0700695
Dan Albert8e0178d2015-01-27 15:53:15 -0800696def WritePolicyConfig(file_name, output_zip):
697 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500698
Doug Zongker2ea21062010-04-28 16:05:21 -0700699
700def WriteMetadata(metadata, output_zip):
701 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
702 "".join(["%s=%s\n" % kv
703 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700704
Doug Zongkerfc44a512014-08-26 13:10:25 -0700705
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700706def LoadPartitionFiles(z, partition):
707 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700708 ZipFile, and return a dict of {filename: File object}."""
709 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700710 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700711 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700712 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700713 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700714 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700715 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700716 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800717 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700718
719
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700720def GetBuildProp(prop, info_dict):
721 """Return the fingerprint of the build of a given target-files info_dict."""
722 try:
723 return info_dict.get("build.prop", {})[prop]
724 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700725 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700726
Doug Zongkerfc44a512014-08-26 13:10:25 -0700727
Michael Runge4038aa82013-12-13 18:06:28 -0800728def AddToKnownPaths(filename, known_paths):
729 if filename[-1] == "/":
730 return
731 dirs = filename.split("/")[:-1]
732 while len(dirs) > 0:
733 path = "/".join(dirs)
734 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700735 break
Michael Runge4038aa82013-12-13 18:06:28 -0800736 known_paths.add(path)
737 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700738
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700739
Geremy Condra36bd3652014-02-06 19:45:10 -0800740def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
Tao Bao3806c232015-07-05 21:08:33 -0700741 # TODO(tbao): We should factor out the common parts between
742 # WriteBlockIncrementalOTAPackage() and WriteIncrementalOTAPackage().
Geremy Condra36bd3652014-02-06 19:45:10 -0800743 source_version = OPTIONS.source_info_dict["recovery_api_version"]
744 target_version = OPTIONS.target_info_dict["recovery_api_version"]
745
746 if source_version == 0:
747 print ("WARNING: generating edify script for a source that "
748 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -0700749 script = edify_generator.EdifyGenerator(
750 source_version, OPTIONS.target_info_dict,
751 fstab=OPTIONS.source_info_dict["fstab"])
Geremy Condra36bd3652014-02-06 19:45:10 -0800752
Tao Bao3806c232015-07-05 21:08:33 -0700753 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
754 recovery_mount_options = OPTIONS.source_info_dict.get(
755 "recovery_mount_options")
756 oem_dict = None
757 if oem_props is not None and len(oem_props) > 0:
758 if OPTIONS.oem_source is None:
759 raise common.ExternalError("OEM source required for this build")
760 script.Mount("/oem", recovery_mount_options)
761 oem_dict = common.LoadDictionaryFromLines(
762 open(OPTIONS.oem_source).readlines())
763
Dan Albert8b72aef2015-03-23 19:13:21 -0700764 metadata = {
Tao Bao3806c232015-07-05 21:08:33 -0700765 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
766 OPTIONS.source_info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700767 "post-timestamp": GetBuildProp("ro.build.date.utc",
768 OPTIONS.target_info_dict),
769 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800770
771 device_specific = common.DeviceSpecificParams(
772 source_zip=source_zip,
773 source_version=source_version,
774 target_zip=target_zip,
775 target_version=target_version,
776 output_zip=output_zip,
777 script=script,
778 metadata=metadata,
Tao Bao6f0b2192015-10-13 16:37:12 -0700779 info_dict=OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800780
Tao Bao3806c232015-07-05 21:08:33 -0700781 source_fp = CalculateFingerprint(oem_props, oem_dict,
782 OPTIONS.source_info_dict)
783 target_fp = CalculateFingerprint(oem_props, oem_dict,
784 OPTIONS.target_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800785 metadata["pre-build"] = source_fp
786 metadata["post-build"] = target_fp
787
788 source_boot = common.GetBootableImage(
789 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
790 OPTIONS.source_info_dict)
791 target_boot = common.GetBootableImage(
792 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
793 updating_boot = (not OPTIONS.two_step and
794 (source_boot.data != target_boot.data))
795
Geremy Condra36bd3652014-02-06 19:45:10 -0800796 target_recovery = common.GetBootableImage(
797 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800798
Doug Zongkerfc44a512014-08-26 13:10:25 -0700799 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
800 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700801
802 blockimgdiff_version = 1
803 if OPTIONS.info_dict:
804 blockimgdiff_version = max(
805 int(i) for i in
806 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
807
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700808 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700809 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700810
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700811 if HasVendorPartition(target_zip):
812 if not HasVendorPartition(source_zip):
813 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700814 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
815 OPTIONS.source_info_dict)
816 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
817 OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700818 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700819 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700820 else:
821 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800822
Michael Rungec6e3afd2014-05-05 11:55:47 -0700823 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800824 device_specific.IncrementalOTA_Assertions()
825
826 # Two-step incremental package strategy (in chronological order,
827 # which is *not* the order in which the generated script has
828 # things):
829 #
830 # if stage is not "2/3" or "3/3":
831 # do verification on current system
832 # write recovery image to boot partition
833 # set stage to "2/3"
834 # reboot to boot partition and restart recovery
835 # else if stage is "2/3":
836 # write recovery image to recovery partition
837 # set stage to "3/3"
838 # reboot to recovery partition and restart recovery
839 # else:
840 # (stage must be "3/3")
841 # perform update:
842 # patch system files, etc.
843 # force full install of new boot image
844 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700845 # complete script normally
846 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800847
848 if OPTIONS.two_step:
Tao Baodd24da92015-07-29 14:09:23 -0700849 if not OPTIONS.source_info_dict.get("multistage_support", None):
Geremy Condra36bd3652014-02-06 19:45:10 -0800850 assert False, "two-step packages not supported by this build"
Tao Baodd24da92015-07-29 14:09:23 -0700851 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Geremy Condra36bd3652014-02-06 19:45:10 -0800852 assert fs.fs_type.upper() == "EMMC", \
853 "two-step packages only supported on devices with EMMC /misc partitions"
854 bcb_dev = {"bcb_dev": fs.device}
855 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
856 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700857if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800858""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -0700859 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800860 script.WriteRawImage("/recovery", "recovery.img")
861 script.AppendExtra("""
862set_stage("%(bcb_dev)s", "3/3");
863reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700864else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800865""" % bcb_dev)
866
Tao Bao6c55a8a2015-04-08 15:30:27 -0700867 # Dump fingerprints
868 script.Print("Source: %s" % CalculateFingerprint(
869 oem_props, oem_dict, OPTIONS.source_info_dict))
870 script.Print("Target: %s" % CalculateFingerprint(
871 oem_props, oem_dict, OPTIONS.target_info_dict))
872
Geremy Condra36bd3652014-02-06 19:45:10 -0800873 script.Print("Verifying current system...")
874
875 device_specific.IncrementalOTA_VerifyBegin()
876
Michael Rungec6e3afd2014-05-05 11:55:47 -0700877 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700878 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
879 # patching on a device that's already on the target build will damage the
880 # system. Because operations like move don't check the block state, they
881 # always apply the changes unconditionally.
882 if blockimgdiff_version <= 2:
883 script.AssertSomeFingerprint(source_fp)
884 else:
885 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700886 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700887 if blockimgdiff_version <= 2:
888 script.AssertSomeThumbprint(
889 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
890 else:
891 script.AssertSomeThumbprint(
892 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
893 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800894
895 if updating_boot:
Tao Baodd24da92015-07-29 14:09:23 -0700896 boot_type, boot_device = common.GetTypeAndDevice(
897 "/boot", OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800898 d = common.Difference(target_boot, source_boot)
899 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700900 if d is None:
901 include_full_boot = True
902 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
903 else:
904 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800905
Doug Zongkerf8340082014-08-05 10:39:37 -0700906 print "boot target: %d source: %d diff: %d" % (
907 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800908
Doug Zongkerf8340082014-08-05 10:39:37 -0700909 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800910
Doug Zongkerf8340082014-08-05 10:39:37 -0700911 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
912 (boot_type, boot_device,
913 source_boot.size, source_boot.sha1,
914 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800915
916 device_specific.IncrementalOTA_VerifyEnd()
917
918 if OPTIONS.two_step:
919 script.WriteRawImage("/boot", "recovery.img")
920 script.AppendExtra("""
921set_stage("%(bcb_dev)s", "2/3");
922reboot_now("%(bcb_dev)s", "");
923else
924""" % bcb_dev)
925
Jesse Zhao75bcea02015-01-06 10:59:53 -0800926 # Verify the existing partitions.
927 system_diff.WriteVerifyScript(script)
928 if vendor_diff:
929 vendor_diff.WriteVerifyScript(script)
930
Geremy Condra36bd3652014-02-06 19:45:10 -0800931 script.Comment("---- start making changes here ----")
932
933 device_specific.IncrementalOTA_InstallBegin()
934
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700935 system_diff.WriteScript(script, output_zip,
936 progress=0.8 if vendor_diff else 0.9)
Tao Bao68658c02015-06-01 13:40:49 -0700937
Doug Zongkerfc44a512014-08-26 13:10:25 -0700938 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700939 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800940
941 if OPTIONS.two_step:
942 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
943 script.WriteRawImage("/boot", "boot.img")
944 print "writing full boot image (forced by two-step mode)"
945
946 if not OPTIONS.two_step:
947 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700948 if include_full_boot:
949 print "boot image changed; including full."
950 script.Print("Installing boot image...")
951 script.WriteRawImage("/boot", "boot.img")
952 else:
953 # Produce the boot image by applying a patch to the current
954 # contents of the boot partition, and write it back to the
955 # partition.
956 print "boot image changed; including patch."
957 script.Print("Patching boot image...")
958 script.ShowProgress(0.1, 10)
959 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
960 % (boot_type, boot_device,
961 source_boot.size, source_boot.sha1,
962 target_boot.size, target_boot.sha1),
963 "-",
964 target_boot.size, target_boot.sha1,
965 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800966 else:
967 print "boot image unchanged; skipping."
968
969 # Do device-specific installation (eg, write radio image).
970 device_specific.IncrementalOTA_InstallEnd()
971
972 if OPTIONS.extra_script is not None:
973 script.AppendExtra(OPTIONS.extra_script)
974
Doug Zongker922206e2014-03-04 13:16:24 -0800975 if OPTIONS.wipe_user_data:
976 script.Print("Erasing user data...")
977 script.FormatPartition("/data")
978
Geremy Condra36bd3652014-02-06 19:45:10 -0800979 if OPTIONS.two_step:
980 script.AppendExtra("""
981set_stage("%(bcb_dev)s", "");
982endif;
983endif;
984""" % bcb_dev)
985
986 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800987 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800988 WriteMetadata(metadata, output_zip)
989
Doug Zongker32b527d2014-03-04 10:03:02 -0800990
Tao Bao9bc6bb22015-11-09 16:58:28 -0800991def WriteVerifyPackage(input_zip, output_zip):
992 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
993
994 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
995 recovery_mount_options = OPTIONS.info_dict.get(
996 "recovery_mount_options")
997 oem_dict = None
998 if oem_props is not None and len(oem_props) > 0:
999 if OPTIONS.oem_source is None:
1000 raise common.ExternalError("OEM source required for this build")
1001 script.Mount("/oem", recovery_mount_options)
1002 oem_dict = common.LoadDictionaryFromLines(
1003 open(OPTIONS.oem_source).readlines())
1004
1005 target_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.info_dict)
1006 metadata = {
1007 "post-build": target_fp,
1008 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1009 OPTIONS.info_dict),
1010 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
1011 }
1012
1013 device_specific = common.DeviceSpecificParams(
1014 input_zip=input_zip,
1015 input_version=OPTIONS.info_dict["recovery_api_version"],
1016 output_zip=output_zip,
1017 script=script,
1018 input_tmp=OPTIONS.input_tmp,
1019 metadata=metadata,
1020 info_dict=OPTIONS.info_dict)
1021
1022 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
1023
1024 script.Print("Verifying device images against %s..." % target_fp)
1025 script.AppendExtra("")
1026
1027 script.Print("Verifying boot...")
1028 boot_img = common.GetBootableImage(
1029 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
1030 boot_type, boot_device = common.GetTypeAndDevice(
1031 "/boot", OPTIONS.info_dict)
1032 script.Verify("%s:%s:%d:%s" % (
1033 boot_type, boot_device, boot_img.size, boot_img.sha1))
1034 script.AppendExtra("")
1035
1036 script.Print("Verifying recovery...")
1037 recovery_img = common.GetBootableImage(
1038 "recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
1039 recovery_type, recovery_device = common.GetTypeAndDevice(
1040 "/recovery", OPTIONS.info_dict)
1041 script.Verify("%s:%s:%d:%s" % (
1042 recovery_type, recovery_device, recovery_img.size, recovery_img.sha1))
1043 script.AppendExtra("")
1044
1045 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
1046 system_tgt.ResetFileMap()
1047 system_diff = common.BlockDifference("system", system_tgt, src=None)
1048 system_diff.WriteStrictVerifyScript(script)
1049
1050 if HasVendorPartition(input_zip):
1051 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
1052 vendor_tgt.ResetFileMap()
1053 vendor_diff = common.BlockDifference("vendor", vendor_tgt, src=None)
1054 vendor_diff.WriteStrictVerifyScript(script)
1055
1056 # Device specific partitions, such as radio, bootloader and etc.
1057 device_specific.VerifyOTA_Assertions()
1058
1059 script.SetProgress(1.0)
1060 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
1061 WriteMetadata(metadata, output_zip)
1062
1063
Dan Albert8b72aef2015-03-23 19:13:21 -07001064class FileDifference(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001065 def __init__(self, partition, source_zip, target_zip, output_zip):
Dan Albert8b72aef2015-03-23 19:13:21 -07001066 self.deferred_patch_list = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001067 print "Loading target..."
1068 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
1069 print "Loading source..."
1070 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
1071
1072 self.verbatim_targets = verbatim_targets = []
1073 self.patch_list = patch_list = []
1074 diffs = []
1075 self.renames = renames = {}
1076 known_paths = set()
1077 largest_source_size = 0
1078
1079 matching_file_cache = {}
1080 for fn, sf in source_data.items():
1081 assert fn == sf.name
1082 matching_file_cache["path:" + fn] = sf
1083 if fn in target_data.keys():
1084 AddToKnownPaths(fn, known_paths)
1085 # Only allow eligibility for filename/sha matching
1086 # if there isn't a perfect path match.
1087 if target_data.get(sf.name) is None:
1088 matching_file_cache["file:" + fn.split("/")[-1]] = sf
1089 matching_file_cache["sha:" + sf.sha1] = sf
1090
1091 for fn in sorted(target_data.keys()):
1092 tf = target_data[fn]
1093 assert fn == tf.name
1094 sf = ClosestFileMatch(tf, matching_file_cache, renames)
1095 if sf is not None and sf.name != tf.name:
1096 print "File has moved from " + sf.name + " to " + tf.name
1097 renames[sf.name] = tf
1098
1099 if sf is None or fn in OPTIONS.require_verbatim:
1100 # This file should be included verbatim
1101 if fn in OPTIONS.prohibit_verbatim:
1102 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
1103 print "send", fn, "verbatim"
1104 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001105 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001106 if fn in target_data.keys():
1107 AddToKnownPaths(fn, known_paths)
1108 elif tf.sha1 != sf.sha1:
1109 # File is different; consider sending as a patch
1110 diffs.append(common.Difference(tf, sf))
1111 else:
1112 # Target file data identical to source (may still be renamed)
1113 pass
1114
1115 common.ComputeDifferences(diffs)
1116
1117 for diff in diffs:
1118 tf, sf, d = diff.GetPatch()
1119 path = "/".join(tf.name.split("/")[:-1])
1120 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1121 path not in known_paths:
1122 # patch is almost as big as the file; don't bother patching
1123 # or a patch + rename cannot take place due to the target
1124 # directory not existing
1125 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001126 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001127 if sf.name in renames:
1128 del renames[sf.name]
1129 AddToKnownPaths(tf.name, known_paths)
1130 else:
1131 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1132 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1133 largest_source_size = max(largest_source_size, sf.size)
1134
1135 self.largest_source_size = largest_source_size
1136
1137 def EmitVerification(self, script):
1138 so_far = 0
Dan Albert8b72aef2015-03-23 19:13:21 -07001139 for tf, sf, _, _ in self.patch_list:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001140 if tf.name != sf.name:
1141 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1142 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1143 so_far += sf.size
1144 return so_far
1145
Michael Runge63f01de2014-10-28 19:24:19 -07001146 def EmitExplicitTargetVerification(self, script):
Dan Albert8b72aef2015-03-23 19:13:21 -07001147 for fn, _, sha1 in self.verbatim_targets:
1148 if fn[-1] != "/":
Michael Runge63f01de2014-10-28 19:24:19 -07001149 script.FileCheck("/"+fn, sha1)
1150 for tf, _, _, _ in self.patch_list:
1151 script.FileCheck(tf.name, tf.sha1)
1152
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001153 def RemoveUnneededFiles(self, script, extras=()):
Tao Baoa77d41e2015-09-03 21:17:37 -07001154 file_list = ["/" + i[0] for i in self.verbatim_targets]
1155 file_list += ["/" + i for i in self.source_data
1156 if i not in self.target_data and i not in self.renames]
1157 file_list += list(extras)
1158 # Sort the list in descending order, which removes all the files first
1159 # before attempting to remove the folder. (Bug: 22960996)
1160 script.DeleteFiles(sorted(file_list, reverse=True))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001161
1162 def TotalPatchSize(self):
1163 return sum(i[1].size for i in self.patch_list)
1164
1165 def EmitPatches(self, script, total_patch_size, so_far):
1166 self.deferred_patch_list = deferred_patch_list = []
1167 for item in self.patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001168 tf, sf, _, _ = item
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001169 if tf.name == "system/build.prop":
1170 deferred_patch_list.append(item)
1171 continue
Dan Albert8b72aef2015-03-23 19:13:21 -07001172 if sf.name != tf.name:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001173 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
Dan Albert8b72aef2015-03-23 19:13:21 -07001174 script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1,
1175 "patch/" + sf.name + ".p")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001176 so_far += tf.size
1177 script.SetProgress(so_far / total_patch_size)
1178 return so_far
1179
1180 def EmitDeferredPatches(self, script):
1181 for item in self.deferred_patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001182 tf, sf, _, _ = item
1183 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1,
1184 "patch/" + sf.name + ".p")
1185 script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001186
1187 def EmitRenames(self, script):
1188 if len(self.renames) > 0:
1189 script.Print("Renaming files...")
1190 for src, tgt in self.renames.iteritems():
1191 print "Renaming " + src + " to " + tgt.name
1192 script.RenameFile(src, tgt.name)
1193
1194
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001195def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001196 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1197 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1198
Doug Zongker26e66192014-02-20 13:22:07 -08001199 if (OPTIONS.block_based and
1200 target_has_recovery_patch and
1201 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001202 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1203
Doug Zongker37974732010-09-16 17:44:38 -07001204 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1205 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001206
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001207 if source_version == 0:
1208 print ("WARNING: generating edify script for a source that "
1209 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -07001210 script = edify_generator.EdifyGenerator(
1211 source_version, OPTIONS.target_info_dict,
1212 fstab=OPTIONS.source_info_dict["fstab"])
Doug Zongkereef39442009-04-02 12:14:19 -07001213
Michael Runge6e836112014-04-15 17:40:21 -07001214 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Tao Bao34b47bf2015-06-22 19:17:41 -07001215 recovery_mount_options = OPTIONS.source_info_dict.get(
1216 "recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001217 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001218 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001219 if OPTIONS.oem_source is None:
1220 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001221 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001222 oem_dict = common.LoadDictionaryFromLines(
1223 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001224
Dan Albert8b72aef2015-03-23 19:13:21 -07001225 metadata = {
1226 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1227 OPTIONS.source_info_dict),
1228 "post-timestamp": GetBuildProp("ro.build.date.utc",
1229 OPTIONS.target_info_dict),
1230 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001231
Doug Zongker05d3dea2009-06-22 11:32:31 -07001232 device_specific = common.DeviceSpecificParams(
1233 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001234 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001235 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001236 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001237 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001238 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001239 metadata=metadata,
Tao Bao6f0b2192015-10-13 16:37:12 -07001240 info_dict=OPTIONS.source_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001241
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001242 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001243 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001244 if HasVendorPartition(target_zip):
1245 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001246 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001247 else:
1248 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001249
Dan Albert8b72aef2015-03-23 19:13:21 -07001250 target_fp = CalculateFingerprint(oem_props, oem_dict,
1251 OPTIONS.target_info_dict)
1252 source_fp = CalculateFingerprint(oem_props, oem_dict,
1253 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001254
1255 if oem_props is None:
1256 script.AssertSomeFingerprint(source_fp, target_fp)
1257 else:
1258 script.AssertSomeThumbprint(
1259 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1260 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1261
Doug Zongker2ea21062010-04-28 16:05:21 -07001262 metadata["pre-build"] = source_fp
1263 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001264
Doug Zongker55d93282011-01-25 17:03:34 -08001265 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001266 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1267 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001268 target_boot = common.GetBootableImage(
1269 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001270 updating_boot = (not OPTIONS.two_step and
1271 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001272
Doug Zongker55d93282011-01-25 17:03:34 -08001273 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001274 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1275 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001276 target_recovery = common.GetBootableImage(
1277 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001278 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001279
Doug Zongker881dd402009-09-20 14:03:55 -07001280 # Here's how we divide up the progress bar:
1281 # 0.1 for verifying the start state (PatchCheck calls)
1282 # 0.8 for applying patches (ApplyPatch calls)
1283 # 0.1 for unpacking verbatim files, symlinking, and doing the
1284 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001285
Michael Runge6e836112014-04-15 17:40:21 -07001286 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001287 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001288
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001289 # Two-step incremental package strategy (in chronological order,
1290 # which is *not* the order in which the generated script has
1291 # things):
1292 #
1293 # if stage is not "2/3" or "3/3":
1294 # do verification on current system
1295 # write recovery image to boot partition
1296 # set stage to "2/3"
1297 # reboot to boot partition and restart recovery
1298 # else if stage is "2/3":
1299 # write recovery image to recovery partition
1300 # set stage to "3/3"
1301 # reboot to recovery partition and restart recovery
1302 # else:
1303 # (stage must be "3/3")
1304 # perform update:
1305 # patch system files, etc.
1306 # force full install of new boot image
1307 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001308 # complete script normally
1309 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001310
1311 if OPTIONS.two_step:
Tao Baodd24da92015-07-29 14:09:23 -07001312 if not OPTIONS.source_info_dict.get("multistage_support", None):
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001313 assert False, "two-step packages not supported by this build"
Tao Baodd24da92015-07-29 14:09:23 -07001314 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001315 assert fs.fs_type.upper() == "EMMC", \
1316 "two-step packages only supported on devices with EMMC /misc partitions"
1317 bcb_dev = {"bcb_dev": fs.device}
1318 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1319 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001320if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001321""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001322 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001323 script.WriteRawImage("/recovery", "recovery.img")
1324 script.AppendExtra("""
1325set_stage("%(bcb_dev)s", "3/3");
1326reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001327else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001328""" % bcb_dev)
1329
Tao Bao6c55a8a2015-04-08 15:30:27 -07001330 # Dump fingerprints
1331 script.Print("Source: %s" % (source_fp,))
1332 script.Print("Target: %s" % (target_fp,))
1333
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001334 script.Print("Verifying current system...")
1335
Doug Zongkere5ff5902012-01-17 10:55:37 -08001336 device_specific.IncrementalOTA_VerifyBegin()
1337
Doug Zongker881dd402009-09-20 14:03:55 -07001338 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001339 so_far = system_diff.EmitVerification(script)
1340 if vendor_diff:
1341 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001342
Doug Zongker5da317e2009-06-02 13:38:17 -07001343 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001344 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001345 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001346 print "boot target: %d source: %d diff: %d" % (
1347 target_boot.size, source_boot.size, len(d))
1348
Doug Zongker048e7ca2009-06-15 14:31:53 -07001349 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001350
Tao Baodd24da92015-07-29 14:09:23 -07001351 boot_type, boot_device = common.GetTypeAndDevice(
1352 "/boot", OPTIONS.source_info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001353
1354 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1355 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001356 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001357 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001358 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001359
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001360 size = []
Dan Albert8b72aef2015-03-23 19:13:21 -07001361 if system_diff.patch_list:
1362 size.append(system_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001363 if vendor_diff:
Dan Albert8b72aef2015-03-23 19:13:21 -07001364 if vendor_diff.patch_list:
1365 size.append(vendor_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001366 if size or updating_recovery or updating_boot:
1367 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001368
Doug Zongker05d3dea2009-06-22 11:32:31 -07001369 device_specific.IncrementalOTA_VerifyEnd()
1370
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001371 if OPTIONS.two_step:
1372 script.WriteRawImage("/boot", "recovery.img")
1373 script.AppendExtra("""
1374set_stage("%(bcb_dev)s", "2/3");
1375reboot_now("%(bcb_dev)s", "");
1376else
1377""" % bcb_dev)
1378
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001379 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001380
Doug Zongkere5ff5902012-01-17 10:55:37 -08001381 device_specific.IncrementalOTA_InstallBegin()
1382
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001383 if OPTIONS.two_step:
1384 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1385 script.WriteRawImage("/boot", "boot.img")
1386 print "writing full boot image (forced by two-step mode)"
1387
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001388 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001389 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1390 if vendor_diff:
1391 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001392
Doug Zongker881dd402009-09-20 14:03:55 -07001393 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001394 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1395 if vendor_diff:
1396 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001397 if updating_boot:
1398 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001399
1400 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001401 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1402 if vendor_diff:
1403 script.Print("Patching vendor files...")
1404 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001405
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001406 if not OPTIONS.two_step:
1407 if updating_boot:
1408 # Produce the boot image by applying a patch to the current
1409 # contents of the boot partition, and write it back to the
1410 # partition.
1411 script.Print("Patching boot image...")
1412 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1413 % (boot_type, boot_device,
1414 source_boot.size, source_boot.sha1,
1415 target_boot.size, target_boot.sha1),
1416 "-",
1417 target_boot.size, target_boot.sha1,
1418 source_boot.sha1, "patch/boot.img.p")
1419 so_far += target_boot.size
1420 script.SetProgress(so_far / total_patch_size)
1421 print "boot image changed; including."
1422 else:
1423 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001424
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001425 system_items = ItemSet("system", "META/filesystem_config.txt")
1426 if vendor_diff:
1427 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1428
Doug Zongkereef39442009-04-02 12:14:19 -07001429 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001430 # Recovery is generated as a patch using both the boot image
1431 # (which contains the same linux kernel as recovery) and the file
1432 # /system/etc/recovery-resource.dat (which contains all the images
1433 # used in the recovery UI) as sources. This lets us minimize the
1434 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001435 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001436 # For older builds where recovery-resource.dat is not present, we
1437 # use only the boot image as the source.
1438
Doug Zongkerc9253822014-02-04 12:17:58 -08001439 if not target_has_recovery_patch:
1440 def output_sink(fn, data):
1441 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001442 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001443
1444 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1445 target_recovery, target_boot)
1446 script.DeleteFiles(["/system/recovery-from-boot.p",
Tao Baof2cffbd2015-07-22 12:33:18 -07001447 "/system/etc/recovery.img",
Doug Zongkerc9253822014-02-04 12:17:58 -08001448 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001449 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001450 else:
1451 print "recovery image unchanged; skipping."
1452
Doug Zongker881dd402009-09-20 14:03:55 -07001453 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001454
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001455 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1456 if vendor_diff:
1457 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1458
1459 temp_script = script.MakeTemporary()
1460 system_items.GetMetadata(target_zip)
1461 system_items.Get("system").SetPermissions(temp_script)
1462 if vendor_diff:
1463 vendor_items.GetMetadata(target_zip)
1464 vendor_items.Get("vendor").SetPermissions(temp_script)
1465
1466 # Note that this call will mess up the trees of Items, so make sure
1467 # we're done with them.
1468 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1469 if vendor_diff:
1470 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001471
1472 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001473 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1474
1475 # Delete all the symlinks in source that aren't in target. This
1476 # needs to happen before verbatim files are unpacked, in case a
1477 # symlink in the source is replaced by a real file in the target.
Tao Bao84006ea2015-09-02 10:28:08 -07001478
1479 # If a symlink in the source will be replaced by a regular file, we cannot
1480 # delete the symlink/file in case the package gets applied again. For such
1481 # a symlink, we prepend a sha1_check() to detect if it has been updated.
1482 # (Bug: 23646151)
1483 replaced_symlinks = dict()
1484 if system_diff:
1485 for i in system_diff.verbatim_targets:
1486 replaced_symlinks["/%s" % (i[0],)] = i[2]
1487 if vendor_diff:
1488 for i in vendor_diff.verbatim_targets:
1489 replaced_symlinks["/%s" % (i[0],)] = i[2]
1490
1491 if system_diff:
1492 for tf in system_diff.renames.values():
1493 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1494 if vendor_diff:
1495 for tf in vendor_diff.renames.values():
1496 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1497
1498 always_delete = []
1499 may_delete = []
Doug Zongkereef39442009-04-02 12:14:19 -07001500 for dest, link in source_symlinks:
1501 if link not in target_symlinks_d:
Tao Bao84006ea2015-09-02 10:28:08 -07001502 if link in replaced_symlinks:
1503 may_delete.append((link, replaced_symlinks[link]))
1504 else:
1505 always_delete.append(link)
1506 script.DeleteFiles(always_delete)
1507 script.DeleteFilesIfNotMatching(may_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001508
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001509 if system_diff.verbatim_targets:
1510 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001511 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001512 if vendor_diff and vendor_diff.verbatim_targets:
1513 script.Print("Unpacking new vendor files...")
1514 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001515
Doug Zongkerc9253822014-02-04 12:17:58 -08001516 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001517 script.Print("Unpacking new recovery...")
1518 script.UnpackPackageDir("recovery", "/system")
1519
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001520 system_diff.EmitRenames(script)
1521 if vendor_diff:
1522 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001523
Doug Zongker05d3dea2009-06-22 11:32:31 -07001524 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001525
1526 # Create all the symlinks that don't already exist, or point to
1527 # somewhere different than what we want. Delete each symlink before
1528 # creating it, since the 'symlink' command won't overwrite.
1529 to_create = []
1530 for dest, link in target_symlinks:
1531 if link in source_symlinks_d:
1532 if dest != source_symlinks_d[link]:
1533 to_create.append((dest, link))
1534 else:
1535 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001536 script.DeleteFiles([i[1] for i in to_create])
1537 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001538
1539 # Now that the symlinks are created, we can set all the
1540 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001541 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001542
Doug Zongker881dd402009-09-20 14:03:55 -07001543 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001544 device_specific.IncrementalOTA_InstallEnd()
1545
Doug Zongker1c390a22009-05-14 19:06:36 -07001546 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001547 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001548
Doug Zongkere92f15a2011-08-26 13:46:40 -07001549 # Patch the build.prop file last, so if something fails but the
1550 # device can still come up, it appears to be the old build and will
1551 # get set the OTA package again to retry.
1552 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001553 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001554
Doug Zongker922206e2014-03-04 13:16:24 -08001555 if OPTIONS.wipe_user_data:
1556 script.Print("Erasing user data...")
1557 script.FormatPartition("/data")
1558
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001559 if OPTIONS.two_step:
1560 script.AppendExtra("""
1561set_stage("%(bcb_dev)s", "");
1562endif;
1563endif;
1564""" % bcb_dev)
1565
Michael Runge63f01de2014-10-28 19:24:19 -07001566 if OPTIONS.verify and system_diff:
1567 script.Print("Remounting and verifying system partition files...")
1568 script.Unmount("/system")
1569 script.Mount("/system")
1570 system_diff.EmitExplicitTargetVerification(script)
1571
1572 if OPTIONS.verify and vendor_diff:
1573 script.Print("Remounting and verifying vendor partition files...")
1574 script.Unmount("/vendor")
1575 script.Mount("/vendor")
1576 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001577 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001578
Doug Zongker2ea21062010-04-28 16:05:21 -07001579 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001580
1581
1582def main(argv):
1583
1584 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001585 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001586 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001587 elif o in ("-k", "--package_key"):
1588 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001589 elif o in ("-i", "--incremental_from"):
1590 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001591 elif o == "--full_radio":
1592 OPTIONS.full_radio = True
leozwangaa6c1a12015-08-14 10:57:58 -07001593 elif o == "--full_bootloader":
1594 OPTIONS.full_bootloader = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001595 elif o in ("-w", "--wipe_user_data"):
1596 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001597 elif o in ("-n", "--no_prereq"):
1598 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001599 elif o in ("-o", "--oem_settings"):
1600 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001601 elif o in ("-e", "--extra_script"):
1602 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001603 elif o in ("-a", "--aslr_mode"):
1604 if a in ("on", "On", "true", "True", "yes", "Yes"):
1605 OPTIONS.aslr_mode = True
1606 else:
1607 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001608 elif o in ("-t", "--worker_threads"):
1609 if a.isdigit():
1610 OPTIONS.worker_threads = int(a)
1611 else:
1612 raise ValueError("Cannot parse value %r for option %r - only "
1613 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001614 elif o in ("-2", "--two_step"):
1615 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001616 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001617 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001618 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001619 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001620 elif o == "--block":
1621 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001622 elif o in ("-b", "--binary"):
1623 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001624 elif o in ("--no_fallback_to_full",):
1625 OPTIONS.fallback_to_full = False
Tao Bao8dcf7382015-05-21 14:09:49 -07001626 elif o == "--stash_threshold":
1627 try:
1628 OPTIONS.stash_threshold = float(a)
1629 except ValueError:
1630 raise ValueError("Cannot parse value %r for option %r - expecting "
1631 "a float" % (a, o))
Tao Bao9bc6bb22015-11-09 16:58:28 -08001632 elif o == "--gen_verify":
1633 OPTIONS.gen_verify = True
Doug Zongkereef39442009-04-02 12:14:19 -07001634 else:
1635 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001636 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001637
1638 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001639 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001640 extra_long_opts=[
1641 "board_config=",
1642 "package_key=",
1643 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001644 "full_radio",
leozwangaa6c1a12015-08-14 10:57:58 -07001645 "full_bootloader",
Dan Albert8b72aef2015-03-23 19:13:21 -07001646 "wipe_user_data",
1647 "no_prereq",
1648 "extra_script=",
1649 "worker_threads=",
1650 "aslr_mode=",
1651 "two_step",
1652 "no_signing",
1653 "block",
1654 "binary=",
1655 "oem_settings=",
1656 "verify",
1657 "no_fallback_to_full",
Tao Bao8dcf7382015-05-21 14:09:49 -07001658 "stash_threshold=",
Tao Bao9bc6bb22015-11-09 16:58:28 -08001659 "gen_verify"
Dan Albert8b72aef2015-03-23 19:13:21 -07001660 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001661
1662 if len(args) != 2:
1663 common.Usage(__doc__)
1664 sys.exit(1)
1665
Doug Zongker1c390a22009-05-14 19:06:36 -07001666 if OPTIONS.extra_script is not None:
1667 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1668
Doug Zongkereef39442009-04-02 12:14:19 -07001669 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001670 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001671
Doug Zongkereef39442009-04-02 12:14:19 -07001672 OPTIONS.target_tmp = OPTIONS.input_tmp
Tao Bao2c15d9e2015-07-09 11:51:16 -07001673 OPTIONS.info_dict = common.LoadInfoDict(input_zip, OPTIONS.target_tmp)
Kenny Roote2e9f612013-05-29 12:59:35 -07001674
Doug Zongker37974732010-09-16 17:44:38 -07001675 if OPTIONS.verbose:
1676 print "--- target info ---"
1677 common.DumpInfoDict(OPTIONS.info_dict)
1678
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001679 # If the caller explicitly specified the device-specific extensions
1680 # path via -s/--device_specific, use that. Otherwise, use
1681 # META/releasetools.py if it is present in the target target_files.
1682 # Otherwise, take the path of the file from 'tool_extensions' in the
1683 # info dict and look for that in the local filesystem, relative to
1684 # the current directory.
1685
Doug Zongker37974732010-09-16 17:44:38 -07001686 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001687 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1688 if os.path.exists(from_input):
1689 print "(using device-specific extensions from target_files)"
1690 OPTIONS.device_specific = from_input
1691 else:
1692 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1693
Doug Zongker37974732010-09-16 17:44:38 -07001694 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001695 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001696
Tao Baodb45efa2015-10-27 19:25:18 -07001697 if OPTIONS.info_dict.get("no_recovery") == "true":
1698 raise common.ExternalError(
1699 "--- target build has specified no recovery ---")
1700
Tao Bao767e3ac2015-11-10 12:19:19 -08001701 # Use the default key to sign the package if not specified with package_key.
1702 if not OPTIONS.no_signing:
1703 if OPTIONS.package_key is None:
1704 OPTIONS.package_key = OPTIONS.info_dict.get(
1705 "default_system_dev_certificate",
1706 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -07001707
Tao Bao767e3ac2015-11-10 12:19:19 -08001708 # Set up the output zip. Create a temporary zip file if signing is needed.
1709 if OPTIONS.no_signing:
1710 if os.path.exists(args[1]):
1711 os.unlink(args[1])
1712 output_zip = zipfile.ZipFile(args[1], "w",
1713 compression=zipfile.ZIP_DEFLATED)
1714 else:
1715 temp_zip_file = tempfile.NamedTemporaryFile()
1716 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1717 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001718
Tao Bao767e3ac2015-11-10 12:19:19 -08001719 cache_size = OPTIONS.info_dict.get("cache_size", None)
1720 if cache_size is None:
1721 print "--- can't determine the cache partition size ---"
1722 OPTIONS.cache_size = cache_size
Tao Bao8dcf7382015-05-21 14:09:49 -07001723
Tao Bao9bc6bb22015-11-09 16:58:28 -08001724 # Generate a verify package.
1725 if OPTIONS.gen_verify:
1726 WriteVerifyPackage(input_zip, output_zip)
1727
Tao Bao767e3ac2015-11-10 12:19:19 -08001728 # Generate a full OTA.
Tao Bao9bc6bb22015-11-09 16:58:28 -08001729 elif OPTIONS.incremental_source is None:
Tao Bao767e3ac2015-11-10 12:19:19 -08001730 WriteFullOTAPackage(input_zip, output_zip)
1731
1732 # Generate an incremental OTA. It will fall back to generate a full OTA on
1733 # failure unless no_fallback_to_full is specified.
1734 else:
1735 print "unzipping source target-files..."
1736 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
1737 OPTIONS.incremental_source)
1738 OPTIONS.target_info_dict = OPTIONS.info_dict
1739 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip,
1740 OPTIONS.source_tmp)
1741 if OPTIONS.verbose:
1742 print "--- source info ---"
1743 common.DumpInfoDict(OPTIONS.source_info_dict)
1744 try:
1745 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
1746 except ValueError:
1747 if not OPTIONS.fallback_to_full:
1748 raise
1749 print "--- failed to build incremental; falling back to full ---"
1750 OPTIONS.incremental_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -07001751 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001752
Tao Bao767e3ac2015-11-10 12:19:19 -08001753 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001754
Tao Bao767e3ac2015-11-10 12:19:19 -08001755 # Sign the generated zip package unless no_signing is specified.
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001756 if not OPTIONS.no_signing:
1757 SignOutput(temp_zip_file.name, args[1])
1758 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001759
Doug Zongkereef39442009-04-02 12:14:19 -07001760 print "done."
1761
1762
1763if __name__ == '__main__':
1764 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001765 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001766 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001767 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07001768 print
1769 print " ERROR: %s" % (e,)
1770 print
1771 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001772 finally:
1773 common.Cleanup()