blob: 73f7e33607721954c93133247837951396dd35ff [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
Tao Bao5d182562016-02-23 11:38:39 -080066 --downgrade
67 Intentionally generate an incremental OTA that updates from a newer
68 build to an older one (based on timestamp comparison). "post-timestamp"
69 will be replaced by "ota-downgrade=yes" in the metadata file. A data
70 wipe will always be enforced, so "ota-wipe=yes" will also be included in
71 the metadata file.
72
Doug Zongker1c390a22009-05-14 19:06:36 -070073 -e (--extra_script) <file>
74 Insert the contents of file at the end of the update script.
75
Hristo Bojinovdafb0422010-08-26 14:35:16 -070076 -a (--aslr_mode) <on|off>
77 Specify whether to turn on ASLR for the package (on by default).
Stephen Smalley56882bf2012-02-09 13:36:21 -050078
Doug Zongker9b23f2c2013-11-25 14:44:12 -080079 -2 (--two_step)
80 Generate a 'two-step' OTA package, where recovery is updated
81 first, so that any changes made to the system partition are done
82 using the new recovery (new kernel, etc.).
83
Doug Zongker26e66192014-02-20 13:22:07 -080084 --block
85 Generate a block-based OTA if possible. Will fall back to a
86 file-based OTA if the target_files is older and doesn't support
87 block-based OTAs.
88
Doug Zongker25568482014-03-03 10:21:27 -080089 -b (--binary) <file>
90 Use the given binary as the update-binary in the output package,
91 instead of the binary in the build's target_files. Use for
92 development only.
93
Martin Blumenstingl374e1142014-05-31 20:42:55 +020094 -t (--worker_threads) <int>
95 Specifies the number of worker-threads that will be used when
96 generating patches for incremental updates (defaults to 3).
97
Tao Bao8dcf7382015-05-21 14:09:49 -070098 --stash_threshold <float>
99 Specifies the threshold that will be used to compute the maximum
100 allowed stash size (defaults to 0.8).
Tao Bao9bc6bb22015-11-09 16:58:28 -0800101
102 --gen_verify
103 Generate an OTA package that verifies the partitions.
Tao Baod62c6032015-11-30 09:40:20 -0800104
105 --log_diff <file>
106 Generate a log file that shows the differences in the source and target
107 builds for an incremental package. This option is only meaningful when
108 -i is specified.
Doug Zongkereef39442009-04-02 12:14:19 -0700109"""
110
111import sys
112
Doug Zongkercf6d5a92014-02-18 10:57:07 -0800113if sys.hexversion < 0x02070000:
114 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -0700115 sys.exit(1)
116
Doug Zongkerfc44a512014-08-26 13:10:25 -0700117import multiprocessing
Doug Zongkereef39442009-04-02 12:14:19 -0700118import os
Tao Baoc098e9e2016-01-07 13:03:56 -0800119import subprocess
Doug Zongkereef39442009-04-02 12:14:19 -0700120import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -0700121import zipfile
122
123import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700124import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -0700125import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700126
127OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700128OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700129OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700130OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700131OPTIONS.require_verbatim = set()
132OPTIONS.prohibit_verbatim = set(("system/build.prop",))
133OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700134OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700135OPTIONS.omit_prereq = False
Tao Bao5d182562016-02-23 11:38:39 -0800136OPTIONS.downgrade = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700137OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700138OPTIONS.aslr_mode = True
Doug Zongkerfc44a512014-08-26 13:10:25 -0700139OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
140if OPTIONS.worker_threads == 0:
141 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800142OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900143OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800144OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800145OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700146OPTIONS.oem_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -0700147OPTIONS.fallback_to_full = True
Tao Bao43078aa2015-04-21 14:32:35 -0700148OPTIONS.full_radio = False
leozwangaa6c1a12015-08-14 10:57:58 -0700149OPTIONS.full_bootloader = False
Tao Baod47d8e12015-05-21 14:09:49 -0700150# Stash size cannot exceed cache_size * threshold.
151OPTIONS.cache_size = None
152OPTIONS.stash_threshold = 0.8
Tao Bao9bc6bb22015-11-09 16:58:28 -0800153OPTIONS.gen_verify = False
Tao Baod62c6032015-11-30 09:40:20 -0800154OPTIONS.log_diff = None
Tao Bao8dcf7382015-05-21 14:09:49 -0700155
Doug Zongkereef39442009-04-02 12:14:19 -0700156def MostPopularKey(d, default):
157 """Given a dict, return the key corresponding to the largest
158 value. Returns 'default' if the dict is empty."""
159 x = [(v, k) for (k, v) in d.iteritems()]
Dan Albert8b72aef2015-03-23 19:13:21 -0700160 if not x:
161 return default
Doug Zongkereef39442009-04-02 12:14:19 -0700162 x.sort()
163 return x[-1][1]
164
165
166def IsSymlink(info):
167 """Return true if the zipfile.ZipInfo object passed in represents a
168 symlink."""
Ying Wang2ffb3142015-07-06 14:02:01 -0700169 return (info.external_attr >> 16) & 0o770000 == 0o120000
Doug Zongkereef39442009-04-02 12:14:19 -0700170
Hristo Bojinov96be7202010-08-02 10:26:17 -0700171def IsRegular(info):
172 """Return true if the zipfile.ZipInfo object passed in represents a
Ying Wang2ffb3142015-07-06 14:02:01 -0700173 regular file."""
174 return (info.external_attr >> 16) & 0o770000 == 0o100000
Doug Zongkereef39442009-04-02 12:14:19 -0700175
Michael Runge4038aa82013-12-13 18:06:28 -0800176def ClosestFileMatch(src, tgtfiles, existing):
177 """Returns the closest file match between a source file and list
178 of potential matches. The exact filename match is preferred,
179 then the sha1 is searched for, and finally a file with the same
180 basename is evaluated. Rename support in the updater-binary is
181 required for the latter checks to be used."""
182
183 result = tgtfiles.get("path:" + src.name)
184 if result is not None:
185 return result
186
187 if not OPTIONS.target_info_dict.get("update_rename_support", False):
188 return None
189
190 if src.size < 1000:
191 return None
192
193 result = tgtfiles.get("sha1:" + src.sha1)
194 if result is not None and existing.get(result.name) is None:
195 return result
196 result = tgtfiles.get("file:" + src.name.split("/")[-1])
197 if result is not None and existing.get(result.name) is None:
198 return result
199 return None
200
Dan Albert8b72aef2015-03-23 19:13:21 -0700201class ItemSet(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700202 def __init__(self, partition, fs_config):
203 self.partition = partition
204 self.fs_config = fs_config
205 self.ITEMS = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700206
Dan Albert8b72aef2015-03-23 19:13:21 -0700207 def Get(self, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700208 if name not in self.ITEMS:
Dan Albert8b72aef2015-03-23 19:13:21 -0700209 self.ITEMS[name] = Item(self, name, is_dir=is_dir)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700210 return self.ITEMS[name]
Doug Zongkereef39442009-04-02 12:14:19 -0700211
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700212 def GetMetadata(self, input_zip):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700213 # The target_files contains a record of what the uid,
214 # gid, and mode are supposed to be.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700215 output = input_zip.read(self.fs_config)
Doug Zongkereef39442009-04-02 12:14:19 -0700216
217 for line in output.split("\n"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700218 if not line:
219 continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700220 columns = line.split()
221 name, uid, gid, mode = columns[:4]
222 selabel = None
223 capabilities = None
224
225 # After the first 4 columns, there are a series of key=value
226 # pairs. Extract out the fields we care about.
227 for element in columns[4:]:
228 key, value = element.split("=")
229 if key == "selabel":
230 selabel = value
231 if key == "capabilities":
232 capabilities = value
233
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700234 i = self.ITEMS.get(name, None)
Doug Zongker283e2a12010-03-15 17:52:32 -0700235 if i is not None:
236 i.uid = int(uid)
237 i.gid = int(gid)
238 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700239 i.selabel = selabel
240 i.capabilities = capabilities
Dan Albert8b72aef2015-03-23 19:13:21 -0700241 if i.is_dir:
Doug Zongker283e2a12010-03-15 17:52:32 -0700242 i.children.sort(key=lambda i: i.name)
243
Tao Baof2cffbd2015-07-22 12:33:18 -0700244 # Set metadata for the files generated by this script. For full recovery
245 # image at system/etc/recovery.img, it will be taken care by fs_config.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700246 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700247 if i:
248 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700249 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700250 if i:
251 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700252
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700253
Dan Albert8b72aef2015-03-23 19:13:21 -0700254class Item(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700255 """Items represent the metadata (user, group, mode) of files and
256 directories in the system image."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700257 def __init__(self, itemset, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700258 self.itemset = itemset
259 self.name = name
260 self.uid = None
261 self.gid = None
262 self.mode = None
263 self.selabel = None
264 self.capabilities = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700265 self.is_dir = is_dir
266 self.descendants = None
267 self.best_subtree = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700268
269 if name:
Dan Albert8b72aef2015-03-23 19:13:21 -0700270 self.parent = itemset.Get(os.path.dirname(name), is_dir=True)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700271 self.parent.children.append(self)
272 else:
273 self.parent = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700274 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700275 self.children = []
276
277 def Dump(self, indent=0):
278 if self.uid is not None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700279 print "%s%s %d %d %o" % (
280 " " * indent, self.name, self.uid, self.gid, self.mode)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700281 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700282 print "%s%s %s %s %s" % (
283 " " * indent, self.name, self.uid, self.gid, self.mode)
284 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700285 print "%s%s" % (" "*indent, self.descendants)
286 print "%s%s" % (" "*indent, self.best_subtree)
287 for i in self.children:
288 i.Dump(indent=indent+1)
289
Doug Zongkereef39442009-04-02 12:14:19 -0700290 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700291 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
Dan Albert8b72aef2015-03-23 19:13:21 -0700292 all children and determine the best strategy for using set_perm_recursive
293 and set_perm to correctly chown/chmod all the files to their desired
Doug Zongkereef39442009-04-02 12:14:19 -0700294 values. Recursively calls itself for all descendants.
295
Dan Albert8b72aef2015-03-23 19:13:21 -0700296 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count}
297 counting up all descendants of this node. (dmode or fmode may be None.)
298 Also sets the best_subtree of each directory Item to the (uid, gid, dmode,
299 fmode, selabel, capabilities) tuple that will match the most descendants of
300 that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700301 """
302
Dan Albert8b72aef2015-03-23 19:13:21 -0700303 assert self.is_dir
304 key = (self.uid, self.gid, self.mode, None, self.selabel,
305 self.capabilities)
306 self.descendants = {key: 1}
307 d = self.descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700308 for i in self.children:
Dan Albert8b72aef2015-03-23 19:13:21 -0700309 if i.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700310 for k, v in i.CountChildMetadata().iteritems():
311 d[k] = d.get(k, 0) + v
312 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700313 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700314 d[k] = d.get(k, 0) + 1
315
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700316 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
317 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700318
319 # First, find the (uid, gid) pair that matches the most
320 # descendants.
321 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700322 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700323 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
324 ug = MostPopularKey(ug, (0, 0))
325
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700326 # Now find the dmode, fmode, selabel, and capabilities that match
327 # the most descendants with that (uid, gid), and choose those.
Dan Albert8b72aef2015-03-23 19:13:21 -0700328 best_dmode = (0, 0o755)
329 best_fmode = (0, 0o644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700330 best_selabel = (0, None)
331 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700332 for k, count in d.iteritems():
Dan Albert8b72aef2015-03-23 19:13:21 -0700333 if k[:2] != ug:
334 continue
335 if k[2] is not None and count >= best_dmode[0]:
336 best_dmode = (count, k[2])
337 if k[3] is not None and count >= best_fmode[0]:
338 best_fmode = (count, k[3])
339 if k[4] is not None and count >= best_selabel[0]:
340 best_selabel = (count, k[4])
341 if k[5] is not None and count >= best_capabilities[0]:
342 best_capabilities = (count, k[5])
343 self.best_subtree = ug + (
344 best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700345
346 return d
347
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700348 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700349 """Append set_perm/set_perm_recursive commands to 'script' to
350 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700351 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700352
353 self.CountChildMetadata()
354
355 def recurse(item, current):
Dan Albert8b72aef2015-03-23 19:13:21 -0700356 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple
357 # that the current item (and all its children) have already been set to.
358 # We only need to issue set_perm/set_perm_recursive commands if we're
Doug Zongkereef39442009-04-02 12:14:19 -0700359 # supposed to be something different.
Dan Albert8b72aef2015-03-23 19:13:21 -0700360 if item.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700361 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700362 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700363 current = item.best_subtree
364
365 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700366 item.mode != current[2] or item.selabel != current[4] or \
367 item.capabilities != current[5]:
368 script.SetPermissions("/"+item.name, item.uid, item.gid,
369 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700370
371 for i in item.children:
372 recurse(i, current)
373 else:
374 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700375 item.mode != current[3] or item.selabel != current[4] or \
376 item.capabilities != current[5]:
377 script.SetPermissions("/"+item.name, item.uid, item.gid,
378 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700379
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700380 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700381
382
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700383def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
384 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700385 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800386 list of symlinks. output_zip may be None, in which case the copy is
387 skipped (but the other side effects still happen). substitute is an
388 optional dict of {output filename: contents} to be output instead of
389 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700390 """
391
392 symlinks = []
393
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700394 partition = itemset.partition
395
Doug Zongkereef39442009-04-02 12:14:19 -0700396 for info in input_zip.infolist():
Tao Baoeaf885b2015-03-23 16:01:17 -0700397 prefix = partition.upper() + "/"
398 if info.filename.startswith(prefix):
399 basefilename = info.filename[len(prefix):]
Doug Zongkereef39442009-04-02 12:14:19 -0700400 if IsSymlink(info):
401 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700402 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700403 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700404 import copy
Doug Zongkereef39442009-04-02 12:14:19 -0700405 info2 = copy.copy(info)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700406 fn = info2.filename = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700407 if substitute and fn in substitute and substitute[fn] is None:
408 continue
409 if output_zip is not None:
410 if substitute and fn in substitute:
411 data = substitute[fn]
412 else:
413 data = input_zip.read(info.filename)
Tao Bao2ed665a2015-04-01 11:21:55 -0700414 common.ZipWriteStr(output_zip, info2, data)
Doug Zongkereef39442009-04-02 12:14:19 -0700415 if fn.endswith("/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700416 itemset.Get(fn[:-1], is_dir=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700417 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700418 itemset.Get(fn)
Doug Zongkereef39442009-04-02 12:14:19 -0700419
420 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800421 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700422
423
Doug Zongkereef39442009-04-02 12:14:19 -0700424def SignOutput(temp_zip_name, output_zip_name):
425 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
426 pw = key_passwords[OPTIONS.package_key]
427
Doug Zongker951495f2009-08-14 12:44:19 -0700428 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
429 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700430
431
Dan Albert8b72aef2015-03-23 19:13:21 -0700432def AppendAssertions(script, info_dict, oem_dict=None):
Michael Runge6e836112014-04-15 17:40:21 -0700433 oem_props = info_dict.get("oem_fingerprint_properties")
Michael Runge560569a2014-09-18 15:12:45 -0700434 if oem_props is None or len(oem_props) == 0:
Michael Runge6e836112014-04-15 17:40:21 -0700435 device = GetBuildProp("ro.product.device", info_dict)
436 script.AssertDevice(device)
437 else:
438 if oem_dict is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700439 raise common.ExternalError(
440 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700441 for prop in oem_props.split():
442 if oem_dict.get(prop) is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700443 raise common.ExternalError(
444 "The OEM file is missing the property %s" % prop)
Michael Runge6e836112014-04-15 17:40:21 -0700445 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700446
Doug Zongkereef39442009-04-02 12:14:19 -0700447
Doug Zongkerc9253822014-02-04 12:17:58 -0800448def HasRecoveryPatch(target_files_zip):
Tao Baof2cffbd2015-07-22 12:33:18 -0700449 namelist = [name for name in target_files_zip.namelist()]
450 return ("SYSTEM/recovery-from-boot.p" in namelist or
451 "SYSTEM/etc/recovery.img" in namelist)
Doug Zongker73ef8252009-07-23 15:12:53 -0700452
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700453def HasVendorPartition(target_files_zip):
454 try:
455 target_files_zip.getinfo("VENDOR/")
456 return True
457 except KeyError:
458 return False
459
Michael Runge6e836112014-04-15 17:40:21 -0700460def GetOemProperty(name, oem_props, oem_dict, info_dict):
461 if oem_props is not None and name in oem_props:
462 return oem_dict[name]
463 return GetBuildProp(name, info_dict)
464
465
466def CalculateFingerprint(oem_props, oem_dict, info_dict):
467 if oem_props is None:
468 return GetBuildProp("ro.build.fingerprint", info_dict)
469 return "%s/%s/%s:%s" % (
Dan Albert8b72aef2015-03-23 19:13:21 -0700470 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
471 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
472 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
473 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700474
Doug Zongkerfc44a512014-08-26 13:10:25 -0700475
Doug Zongker3c84f562014-07-31 11:06:30 -0700476def GetImage(which, tmpdir, info_dict):
Doug Zongkerfc44a512014-08-26 13:10:25 -0700477 # Return an image object (suitable for passing to BlockImageDiff)
478 # for the 'which' partition (most be "system" or "vendor"). If a
479 # prebuilt image and file map are found in tmpdir they are used,
480 # otherwise they are reconstructed from the individual files.
Doug Zongker3c84f562014-07-31 11:06:30 -0700481
482 assert which in ("system", "vendor")
483
484 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700485 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
486 if os.path.exists(path) and os.path.exists(mappath):
Doug Zongker3c84f562014-07-31 11:06:30 -0700487 print "using %s.img from target-files" % (which,)
Doug Zongker3c84f562014-07-31 11:06:30 -0700488 # This is a 'new' target-files, which already has the image in it.
Doug Zongker3c84f562014-07-31 11:06:30 -0700489
490 else:
491 print "building %s.img from target-files" % (which,)
492
493 # This is an 'old' target-files, which does not contain images
494 # already built. Build them.
495
Doug Zongkerfc44a512014-08-26 13:10:25 -0700496 mappath = tempfile.mkstemp()[1]
497 OPTIONS.tempfiles.append(mappath)
498
Doug Zongker3c84f562014-07-31 11:06:30 -0700499 import add_img_to_target_files
500 if which == "system":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700501 path = add_img_to_target_files.BuildSystem(
502 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700503 elif which == "vendor":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700504 path = add_img_to_target_files.BuildVendor(
505 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700506
Tao Baoff777812015-05-12 11:42:31 -0700507 # Bug: http://b/20939131
508 # In ext4 filesystems, block 0 might be changed even being mounted
509 # R/O. We add it to clobbered_blocks so that it will be written to the
510 # target unconditionally. Note that they are still part of care_map.
511 clobbered_blocks = "0"
512
513 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700514
515
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700516def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700517 # TODO: how to determine this? We don't know what version it will
Tao Bao34b47bf2015-06-22 19:17:41 -0700518 # be installed on top of. For now, we expect the API just won't
519 # change very often. Similarly for fstab, it might have changed
520 # in the target build.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700521 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700522
Michael Runge6e836112014-04-15 17:40:21 -0700523 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700524 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700525 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700526 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700527 if OPTIONS.oem_source is None:
528 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700529 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700530 oem_dict = common.LoadDictionaryFromLines(
531 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -0700532
Dan Albert8b72aef2015-03-23 19:13:21 -0700533 metadata = {
534 "post-build": CalculateFingerprint(oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700535 OPTIONS.info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700536 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
537 OPTIONS.info_dict),
538 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
539 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700540
Doug Zongker05d3dea2009-06-22 11:32:31 -0700541 device_specific = common.DeviceSpecificParams(
542 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700543 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700544 output_zip=output_zip,
545 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700546 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700547 metadata=metadata,
548 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700549
Doug Zongkerc9253822014-02-04 12:17:58 -0800550 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800551 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800552
Tao Baod8d14be2016-02-04 14:26:02 -0800553 metadata["ota-type"] = "BLOCK" if block_based else "FILE"
554
Doug Zongker962069c2009-04-23 11:41:58 -0700555 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700556 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700557 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
558 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700559
Michael Runge6e836112014-04-15 17:40:21 -0700560 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700561 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800562
563 # Two-step package strategy (in chronological order, which is *not*
564 # the order in which the generated script has things):
565 #
566 # if stage is not "2/3" or "3/3":
567 # write recovery image to boot partition
568 # set stage to "2/3"
569 # reboot to boot partition and restart recovery
570 # else if stage is "2/3":
571 # write recovery image to recovery partition
572 # set stage to "3/3"
573 # reboot to recovery partition and restart recovery
574 # else:
575 # (stage must be "3/3")
576 # set stage to ""
577 # do normal full package installation:
578 # wipe and install system, boot image, etc.
579 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700580 # complete script normally
581 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800582
583 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
584 OPTIONS.input_tmp, "RECOVERY")
585 if OPTIONS.two_step:
586 if not OPTIONS.info_dict.get("multistage_support", None):
587 assert False, "two-step packages not supported by this build"
588 fs = OPTIONS.info_dict["fstab"]["/misc"]
589 assert fs.fs_type.upper() == "EMMC", \
590 "two-step packages only supported on devices with EMMC /misc partitions"
591 bcb_dev = {"bcb_dev": fs.device}
592 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
593 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700594if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800595""" % bcb_dev)
596 script.WriteRawImage("/recovery", "recovery.img")
597 script.AppendExtra("""
598set_stage("%(bcb_dev)s", "3/3");
599reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700600else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800601""" % bcb_dev)
602
Tao Bao6c55a8a2015-04-08 15:30:27 -0700603 # Dump fingerprints
604 script.Print("Target: %s" % CalculateFingerprint(
605 oem_props, oem_dict, OPTIONS.info_dict))
606
Doug Zongkere5ff5902012-01-17 10:55:37 -0800607 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700608
Doug Zongker01ce19c2014-02-04 13:48:15 -0800609 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700610
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700611 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800612 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700613 if HasVendorPartition(input_zip):
614 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700615
Stephen Smalleyd3a803e2015-08-04 14:59:06 -0400616 # Place a copy of file_contexts.bin into the OTA package which will be used
617 # by the recovery program.
Kenny Rootf32dc712012-04-08 10:42:34 -0700618 if "selinux_fc" in OPTIONS.info_dict:
619 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500620
Michael Runge7cd99ba2014-10-22 17:21:48 -0700621 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
622
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700623 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700624 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800625
Doug Zongker26e66192014-02-20 13:22:07 -0800626 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700627 # Full OTA is done as an "incremental" against an empty source
628 # image. This has the effect of writing new data from the package
629 # to the entire partition, but lets us reuse the updater code that
630 # writes incrementals to do it.
631 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
632 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700633 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700634 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800635 else:
636 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700637 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800638 if not has_recovery_patch:
639 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800640 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700641
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700642 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800643 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700644
Tao Bao7a5bf8a2015-07-21 18:01:20 -0700645 boot_img = common.GetBootableImage(
646 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800647
Doug Zongker91a99c22014-05-09 13:15:01 -0700648 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800649 def output_sink(fn, data):
650 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700651 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800652
653 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
654 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700655
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700656 system_items.GetMetadata(input_zip)
657 system_items.Get("system").SetPermissions(script)
658
659 if HasVendorPartition(input_zip):
660 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
661 script.ShowProgress(0.1, 0)
662
663 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700664 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
665 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700666 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700667 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700668 else:
669 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700670 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700671 script.UnpackPackageDir("vendor", "/vendor")
672
673 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
674 script.MakeSymlinks(symlinks)
675
676 vendor_items.GetMetadata(input_zip)
677 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700678
Doug Zongker37974732010-09-16 17:44:38 -0700679 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700680 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700681
Doug Zongker01ce19c2014-02-04 13:48:15 -0800682 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700683 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700684
Doug Zongker01ce19c2014-02-04 13:48:15 -0800685 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700686 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700687
Doug Zongker1c390a22009-05-14 19:06:36 -0700688 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700689 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700690
Doug Zongker14833602010-02-02 13:12:04 -0800691 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800692
Doug Zongker922206e2014-03-04 13:16:24 -0800693 if OPTIONS.wipe_user_data:
694 script.ShowProgress(0.1, 10)
695 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700696
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800697 if OPTIONS.two_step:
698 script.AppendExtra("""
699set_stage("%(bcb_dev)s", "");
700""" % bcb_dev)
701 script.AppendExtra("else\n")
702 script.WriteRawImage("/boot", "recovery.img")
703 script.AppendExtra("""
704set_stage("%(bcb_dev)s", "2/3");
705reboot_now("%(bcb_dev)s", "");
706endif;
707endif;
708""" % bcb_dev)
Tao Baod8d14be2016-02-04 14:26:02 -0800709
Tao Bao5d182562016-02-23 11:38:39 -0800710 script.SetProgress(1)
711 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -0800712 metadata["ota-required-cache"] = str(script.required_cache)
Doug Zongker2ea21062010-04-28 16:05:21 -0700713 WriteMetadata(metadata, output_zip)
714
Doug Zongkerfc44a512014-08-26 13:10:25 -0700715
Dan Albert8e0178d2015-01-27 15:53:15 -0800716def WritePolicyConfig(file_name, output_zip):
717 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500718
Doug Zongker2ea21062010-04-28 16:05:21 -0700719
720def WriteMetadata(metadata, output_zip):
721 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
722 "".join(["%s=%s\n" % kv
723 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700724
Doug Zongkerfc44a512014-08-26 13:10:25 -0700725
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700726def LoadPartitionFiles(z, partition):
727 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700728 ZipFile, and return a dict of {filename: File object}."""
729 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700730 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700731 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700732 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700733 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700734 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700735 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700736 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800737 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700738
739
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700740def GetBuildProp(prop, info_dict):
741 """Return the fingerprint of the build of a given target-files info_dict."""
742 try:
743 return info_dict.get("build.prop", {})[prop]
744 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700745 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700746
Doug Zongkerfc44a512014-08-26 13:10:25 -0700747
Michael Runge4038aa82013-12-13 18:06:28 -0800748def AddToKnownPaths(filename, known_paths):
749 if filename[-1] == "/":
750 return
751 dirs = filename.split("/")[:-1]
752 while len(dirs) > 0:
753 path = "/".join(dirs)
754 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700755 break
Michael Runge4038aa82013-12-13 18:06:28 -0800756 known_paths.add(path)
757 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700758
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700759
Geremy Condra36bd3652014-02-06 19:45:10 -0800760def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
Tao Bao3806c232015-07-05 21:08:33 -0700761 # TODO(tbao): We should factor out the common parts between
762 # WriteBlockIncrementalOTAPackage() and WriteIncrementalOTAPackage().
Geremy Condra36bd3652014-02-06 19:45:10 -0800763 source_version = OPTIONS.source_info_dict["recovery_api_version"]
764 target_version = OPTIONS.target_info_dict["recovery_api_version"]
765
766 if source_version == 0:
767 print ("WARNING: generating edify script for a source that "
768 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -0700769 script = edify_generator.EdifyGenerator(
770 source_version, OPTIONS.target_info_dict,
771 fstab=OPTIONS.source_info_dict["fstab"])
Geremy Condra36bd3652014-02-06 19:45:10 -0800772
Tao Bao3806c232015-07-05 21:08:33 -0700773 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
774 recovery_mount_options = OPTIONS.source_info_dict.get(
775 "recovery_mount_options")
776 oem_dict = None
777 if oem_props is not None and len(oem_props) > 0:
778 if OPTIONS.oem_source is None:
779 raise common.ExternalError("OEM source required for this build")
780 script.Mount("/oem", recovery_mount_options)
781 oem_dict = common.LoadDictionaryFromLines(
782 open(OPTIONS.oem_source).readlines())
783
Dan Albert8b72aef2015-03-23 19:13:21 -0700784 metadata = {
Tao Bao3806c232015-07-05 21:08:33 -0700785 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
786 OPTIONS.source_info_dict),
Tao Baod8d14be2016-02-04 14:26:02 -0800787 "ota-type": "BLOCK",
Dan Albert8b72aef2015-03-23 19:13:21 -0700788 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800789
Tao Bao5d182562016-02-23 11:38:39 -0800790 post_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict)
791 pre_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
792 is_downgrade = long(post_timestamp) < long(pre_timestamp)
793
794 if OPTIONS.downgrade:
795 metadata["ota-downgrade"] = "yes"
796 if not is_downgrade:
797 raise RuntimeError("--downgrade specified but no downgrade detected: "
798 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
799 else:
800 if is_downgrade:
801 # Non-fatal here to allow generating such a package which may require
802 # manual work to adjust the post-timestamp. A legit use case is that we
803 # cut a new build C (after having A and B), but want to enfore the
804 # update path of A -> C -> B. Specifying --downgrade may not help since
805 # that would enforce a data wipe for C -> B update.
806 print("\nWARNING: downgrade detected: pre: %s, post: %s.\n"
807 "The package may not be deployed properly. "
808 "Try --downgrade?\n" % (pre_timestamp, post_timestamp))
809 metadata["post-timestamp"] = post_timestamp
810
Geremy Condra36bd3652014-02-06 19:45:10 -0800811 device_specific = common.DeviceSpecificParams(
812 source_zip=source_zip,
813 source_version=source_version,
814 target_zip=target_zip,
815 target_version=target_version,
816 output_zip=output_zip,
817 script=script,
818 metadata=metadata,
Tao Bao6f0b2192015-10-13 16:37:12 -0700819 info_dict=OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800820
Tao Bao3806c232015-07-05 21:08:33 -0700821 source_fp = CalculateFingerprint(oem_props, oem_dict,
822 OPTIONS.source_info_dict)
823 target_fp = CalculateFingerprint(oem_props, oem_dict,
824 OPTIONS.target_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800825 metadata["pre-build"] = source_fp
826 metadata["post-build"] = target_fp
827
828 source_boot = common.GetBootableImage(
829 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
830 OPTIONS.source_info_dict)
831 target_boot = common.GetBootableImage(
832 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
833 updating_boot = (not OPTIONS.two_step and
834 (source_boot.data != target_boot.data))
835
Geremy Condra36bd3652014-02-06 19:45:10 -0800836 target_recovery = common.GetBootableImage(
837 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800838
Doug Zongkerfc44a512014-08-26 13:10:25 -0700839 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
840 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700841
842 blockimgdiff_version = 1
843 if OPTIONS.info_dict:
844 blockimgdiff_version = max(
845 int(i) for i in
846 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
847
Tianjie Xufc3422a2015-12-15 11:53:59 -0800848 # Check first block of system partition for remount R/W only if
849 # disk type is ext4
850 system_partition = OPTIONS.source_info_dict["fstab"]["/system"]
Tao Baod8d14be2016-02-04 14:26:02 -0800851 check_first_block = system_partition.fs_type == "ext4"
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700852 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tianjie Xufc3422a2015-12-15 11:53:59 -0800853 check_first_block,
Tao Baodd2a5892015-03-12 12:32:37 -0700854 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700855
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700856 if HasVendorPartition(target_zip):
857 if not HasVendorPartition(source_zip):
858 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700859 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
860 OPTIONS.source_info_dict)
861 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
862 OPTIONS.target_info_dict)
Tianjie Xufc3422a2015-12-15 11:53:59 -0800863
864 # Check first block of vendor partition for remount R/W only if
865 # disk type is ext4
866 vendor_partition = OPTIONS.source_info_dict["fstab"]["/vendor"]
Tao Baod8d14be2016-02-04 14:26:02 -0800867 check_first_block = vendor_partition.fs_type == "ext4"
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700868 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tianjie Xufc3422a2015-12-15 11:53:59 -0800869 check_first_block,
Tao Baodd2a5892015-03-12 12:32:37 -0700870 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700871 else:
872 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800873
Michael Rungec6e3afd2014-05-05 11:55:47 -0700874 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800875 device_specific.IncrementalOTA_Assertions()
876
877 # Two-step incremental package strategy (in chronological order,
878 # which is *not* the order in which the generated script has
879 # things):
880 #
881 # if stage is not "2/3" or "3/3":
882 # do verification on current system
883 # write recovery image to boot partition
884 # set stage to "2/3"
885 # reboot to boot partition and restart recovery
886 # else if stage is "2/3":
887 # write recovery image to recovery partition
888 # set stage to "3/3"
889 # reboot to recovery partition and restart recovery
890 # else:
891 # (stage must be "3/3")
892 # perform update:
893 # patch system files, etc.
894 # force full install of new boot image
895 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700896 # complete script normally
897 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800898
899 if OPTIONS.two_step:
Tao Baodd24da92015-07-29 14:09:23 -0700900 if not OPTIONS.source_info_dict.get("multistage_support", None):
Geremy Condra36bd3652014-02-06 19:45:10 -0800901 assert False, "two-step packages not supported by this build"
Tao Baodd24da92015-07-29 14:09:23 -0700902 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Geremy Condra36bd3652014-02-06 19:45:10 -0800903 assert fs.fs_type.upper() == "EMMC", \
904 "two-step packages only supported on devices with EMMC /misc partitions"
905 bcb_dev = {"bcb_dev": fs.device}
906 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
907 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700908if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800909""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -0700910 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800911 script.WriteRawImage("/recovery", "recovery.img")
912 script.AppendExtra("""
913set_stage("%(bcb_dev)s", "3/3");
914reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700915else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800916""" % bcb_dev)
917
Tao Bao6c55a8a2015-04-08 15:30:27 -0700918 # Dump fingerprints
919 script.Print("Source: %s" % CalculateFingerprint(
920 oem_props, oem_dict, OPTIONS.source_info_dict))
921 script.Print("Target: %s" % CalculateFingerprint(
922 oem_props, oem_dict, OPTIONS.target_info_dict))
923
Geremy Condra36bd3652014-02-06 19:45:10 -0800924 script.Print("Verifying current system...")
925
926 device_specific.IncrementalOTA_VerifyBegin()
927
Michael Rungec6e3afd2014-05-05 11:55:47 -0700928 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700929 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
930 # patching on a device that's already on the target build will damage the
931 # system. Because operations like move don't check the block state, they
932 # always apply the changes unconditionally.
933 if blockimgdiff_version <= 2:
934 script.AssertSomeFingerprint(source_fp)
935 else:
936 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700937 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700938 if blockimgdiff_version <= 2:
939 script.AssertSomeThumbprint(
940 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
941 else:
942 script.AssertSomeThumbprint(
943 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
944 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800945
Tao Baod8d14be2016-02-04 14:26:02 -0800946 # Check the required cache size (i.e. stashed blocks).
947 size = []
948 if system_diff:
949 size.append(system_diff.required_cache)
950 if vendor_diff:
951 size.append(vendor_diff.required_cache)
952
Geremy Condra36bd3652014-02-06 19:45:10 -0800953 if updating_boot:
Tao Baodd24da92015-07-29 14:09:23 -0700954 boot_type, boot_device = common.GetTypeAndDevice(
955 "/boot", OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800956 d = common.Difference(target_boot, source_boot)
957 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700958 if d is None:
959 include_full_boot = True
960 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
961 else:
962 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800963
Doug Zongkerf8340082014-08-05 10:39:37 -0700964 print "boot target: %d source: %d diff: %d" % (
965 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800966
Doug Zongkerf8340082014-08-05 10:39:37 -0700967 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800968
Doug Zongkerf8340082014-08-05 10:39:37 -0700969 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
970 (boot_type, boot_device,
971 source_boot.size, source_boot.sha1,
972 target_boot.size, target_boot.sha1))
Tao Baod8d14be2016-02-04 14:26:02 -0800973 size.append(target_boot.size)
974
975 if size:
976 script.CacheFreeSpaceCheck(max(size))
Geremy Condra36bd3652014-02-06 19:45:10 -0800977
978 device_specific.IncrementalOTA_VerifyEnd()
979
980 if OPTIONS.two_step:
981 script.WriteRawImage("/boot", "recovery.img")
982 script.AppendExtra("""
983set_stage("%(bcb_dev)s", "2/3");
984reboot_now("%(bcb_dev)s", "");
985else
986""" % bcb_dev)
987
Jesse Zhao75bcea02015-01-06 10:59:53 -0800988 # Verify the existing partitions.
989 system_diff.WriteVerifyScript(script)
990 if vendor_diff:
991 vendor_diff.WriteVerifyScript(script)
992
Geremy Condra36bd3652014-02-06 19:45:10 -0800993 script.Comment("---- start making changes here ----")
994
995 device_specific.IncrementalOTA_InstallBegin()
996
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700997 system_diff.WriteScript(script, output_zip,
998 progress=0.8 if vendor_diff else 0.9)
Tao Bao68658c02015-06-01 13:40:49 -0700999
Doug Zongkerfc44a512014-08-26 13:10:25 -07001000 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -07001001 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -08001002
1003 if OPTIONS.two_step:
1004 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1005 script.WriteRawImage("/boot", "boot.img")
1006 print "writing full boot image (forced by two-step mode)"
1007
1008 if not OPTIONS.two_step:
1009 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -07001010 if include_full_boot:
1011 print "boot image changed; including full."
1012 script.Print("Installing boot image...")
1013 script.WriteRawImage("/boot", "boot.img")
1014 else:
1015 # Produce the boot image by applying a patch to the current
1016 # contents of the boot partition, and write it back to the
1017 # partition.
1018 print "boot image changed; including patch."
1019 script.Print("Patching boot image...")
1020 script.ShowProgress(0.1, 10)
1021 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1022 % (boot_type, boot_device,
1023 source_boot.size, source_boot.sha1,
1024 target_boot.size, target_boot.sha1),
1025 "-",
1026 target_boot.size, target_boot.sha1,
1027 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -08001028 else:
1029 print "boot image unchanged; skipping."
1030
1031 # Do device-specific installation (eg, write radio image).
1032 device_specific.IncrementalOTA_InstallEnd()
1033
1034 if OPTIONS.extra_script is not None:
1035 script.AppendExtra(OPTIONS.extra_script)
1036
Doug Zongker922206e2014-03-04 13:16:24 -08001037 if OPTIONS.wipe_user_data:
1038 script.Print("Erasing user data...")
1039 script.FormatPartition("/data")
Tao Bao5d182562016-02-23 11:38:39 -08001040 metadata["ota-wipe"] = "yes"
Doug Zongker922206e2014-03-04 13:16:24 -08001041
Geremy Condra36bd3652014-02-06 19:45:10 -08001042 if OPTIONS.two_step:
1043 script.AppendExtra("""
1044set_stage("%(bcb_dev)s", "");
1045endif;
1046endif;
1047""" % bcb_dev)
1048
1049 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -08001050 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -08001051 metadata["ota-required-cache"] = str(script.required_cache)
Geremy Condra36bd3652014-02-06 19:45:10 -08001052 WriteMetadata(metadata, output_zip)
1053
Doug Zongker32b527d2014-03-04 10:03:02 -08001054
Tao Bao9bc6bb22015-11-09 16:58:28 -08001055def WriteVerifyPackage(input_zip, output_zip):
1056 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
1057
1058 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
1059 recovery_mount_options = OPTIONS.info_dict.get(
1060 "recovery_mount_options")
1061 oem_dict = None
1062 if oem_props is not None and len(oem_props) > 0:
1063 if OPTIONS.oem_source is None:
1064 raise common.ExternalError("OEM source required for this build")
1065 script.Mount("/oem", recovery_mount_options)
1066 oem_dict = common.LoadDictionaryFromLines(
1067 open(OPTIONS.oem_source).readlines())
1068
1069 target_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.info_dict)
1070 metadata = {
1071 "post-build": target_fp,
1072 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1073 OPTIONS.info_dict),
1074 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
1075 }
1076
1077 device_specific = common.DeviceSpecificParams(
1078 input_zip=input_zip,
1079 input_version=OPTIONS.info_dict["recovery_api_version"],
1080 output_zip=output_zip,
1081 script=script,
1082 input_tmp=OPTIONS.input_tmp,
1083 metadata=metadata,
1084 info_dict=OPTIONS.info_dict)
1085
1086 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
1087
1088 script.Print("Verifying device images against %s..." % target_fp)
1089 script.AppendExtra("")
1090
1091 script.Print("Verifying boot...")
1092 boot_img = common.GetBootableImage(
1093 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
1094 boot_type, boot_device = common.GetTypeAndDevice(
1095 "/boot", OPTIONS.info_dict)
1096 script.Verify("%s:%s:%d:%s" % (
1097 boot_type, boot_device, boot_img.size, boot_img.sha1))
1098 script.AppendExtra("")
1099
1100 script.Print("Verifying recovery...")
1101 recovery_img = common.GetBootableImage(
1102 "recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
1103 recovery_type, recovery_device = common.GetTypeAndDevice(
1104 "/recovery", OPTIONS.info_dict)
1105 script.Verify("%s:%s:%d:%s" % (
1106 recovery_type, recovery_device, recovery_img.size, recovery_img.sha1))
1107 script.AppendExtra("")
1108
1109 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
1110 system_tgt.ResetFileMap()
1111 system_diff = common.BlockDifference("system", system_tgt, src=None)
1112 system_diff.WriteStrictVerifyScript(script)
1113
1114 if HasVendorPartition(input_zip):
1115 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
1116 vendor_tgt.ResetFileMap()
1117 vendor_diff = common.BlockDifference("vendor", vendor_tgt, src=None)
1118 vendor_diff.WriteStrictVerifyScript(script)
1119
1120 # Device specific partitions, such as radio, bootloader and etc.
1121 device_specific.VerifyOTA_Assertions()
1122
1123 script.SetProgress(1.0)
1124 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Tao Baod8d14be2016-02-04 14:26:02 -08001125 metadata["ota-required-cache"] = str(script.required_cache)
Tao Bao9bc6bb22015-11-09 16:58:28 -08001126 WriteMetadata(metadata, output_zip)
1127
1128
Tao Baoc098e9e2016-01-07 13:03:56 -08001129def WriteABOTAPackageWithBrilloScript(target_file, output_file,
1130 source_file=None):
1131 """Generate an Android OTA package that has A/B update payload."""
1132
1133 # Setup signing keys.
1134 if OPTIONS.package_key is None:
1135 OPTIONS.package_key = OPTIONS.info_dict.get(
1136 "default_system_dev_certificate",
1137 "build/target/product/security/testkey")
1138
1139 # A/B updater expects key in RSA format.
1140 cmd = ["openssl", "pkcs8",
1141 "-in", OPTIONS.package_key + OPTIONS.private_key_suffix,
1142 "-inform", "DER", "-nocrypt"]
1143 rsa_key = common.MakeTempFile(prefix="key-", suffix=".key")
1144 cmd.extend(["-out", rsa_key])
1145 p1 = common.Run(cmd, stdout=subprocess.PIPE)
1146 p1.wait()
1147 assert p1.returncode == 0, "openssl pkcs8 failed"
1148
1149 # Stage the output zip package for signing.
1150 temp_zip_file = tempfile.NamedTemporaryFile()
1151 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1152 compression=zipfile.ZIP_DEFLATED)
1153
1154 # Metadata to comply with Android OTA package format.
1155 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties", None)
1156 oem_dict = None
1157 if oem_props:
1158 if OPTIONS.oem_source is None:
1159 raise common.ExternalError("OEM source required for this build")
1160 oem_dict = common.LoadDictionaryFromLines(
1161 open(OPTIONS.oem_source).readlines())
1162
1163 metadata = {
1164 "post-build": CalculateFingerprint(oem_props, oem_dict,
1165 OPTIONS.info_dict),
1166 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1167 OPTIONS.info_dict),
1168 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
Tao Baod8d14be2016-02-04 14:26:02 -08001169 "ota-required-cache": "0",
1170 "ota-type": "AB",
Tao Baoc098e9e2016-01-07 13:03:56 -08001171 }
1172
1173 if source_file is not None:
1174 metadata["pre-build"] = CalculateFingerprint(oem_props, oem_dict,
1175 OPTIONS.source_info_dict)
1176
1177 # 1. Generate payload.
1178 payload_file = common.MakeTempFile(prefix="payload-", suffix=".bin")
1179 cmd = ["brillo_update_payload", "generate",
1180 "--payload", payload_file,
1181 "--target_image", target_file]
1182 if source_file is not None:
1183 cmd.extend(["--source_image", source_file])
1184 p1 = common.Run(cmd, stdout=subprocess.PIPE)
1185 p1.wait()
1186 assert p1.returncode == 0, "brillo_update_payload generate failed"
1187
1188 # 2. Generate hashes of the payload and metadata files.
1189 payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
1190 metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
1191 cmd = ["brillo_update_payload", "hash",
1192 "--unsigned_payload", payload_file,
1193 "--signature_size", "256",
1194 "--metadata_hash_file", metadata_sig_file,
1195 "--payload_hash_file", payload_sig_file]
1196 p1 = common.Run(cmd, stdout=subprocess.PIPE)
1197 p1.wait()
1198 assert p1.returncode == 0, "brillo_update_payload hash failed"
1199
1200 # 3. Sign the hashes and insert them back into the payload file.
1201 signed_payload_sig_file = common.MakeTempFile(prefix="signed-sig-",
1202 suffix=".bin")
1203 signed_metadata_sig_file = common.MakeTempFile(prefix="signed-sig-",
1204 suffix=".bin")
1205 # 3a. Sign the payload hash.
1206 cmd = ["openssl", "pkeyutl", "-sign",
1207 "-inkey", rsa_key,
1208 "-pkeyopt", "digest:sha256",
1209 "-in", payload_sig_file,
1210 "-out", signed_payload_sig_file]
1211 p1 = common.Run(cmd, stdout=subprocess.PIPE)
1212 p1.wait()
1213 assert p1.returncode == 0, "openssl sign payload failed"
1214
1215 # 3b. Sign the metadata hash.
1216 cmd = ["openssl", "pkeyutl", "-sign",
1217 "-inkey", rsa_key,
1218 "-pkeyopt", "digest:sha256",
1219 "-in", metadata_sig_file,
1220 "-out", signed_metadata_sig_file]
1221 p1 = common.Run(cmd, stdout=subprocess.PIPE)
1222 p1.wait()
1223 assert p1.returncode == 0, "openssl sign metadata failed"
1224
1225 # 3c. Insert the signatures back into the payload file.
1226 signed_payload_file = common.MakeTempFile(prefix="signed-payload-",
1227 suffix=".bin")
1228 cmd = ["brillo_update_payload", "sign",
1229 "--unsigned_payload", payload_file,
1230 "--payload", signed_payload_file,
1231 "--signature_size", "256",
1232 "--metadata_signature_file", signed_metadata_sig_file,
1233 "--payload_signature_file", signed_payload_sig_file]
1234 p1 = common.Run(cmd, stdout=subprocess.PIPE)
1235 p1.wait()
1236 assert p1.returncode == 0, "brillo_update_payload sign failed"
1237
Alex Deymo19241c12016-02-04 22:29:29 -08001238 # 4. Dump the signed payload properties.
1239 properties_file = common.MakeTempFile(prefix="payload-properties-",
1240 suffix=".txt")
1241 cmd = ["brillo_update_payload", "properties",
1242 "--payload", signed_payload_file,
1243 "--properties_file", properties_file]
1244 p1 = common.Run(cmd, stdout=subprocess.PIPE)
1245 p1.wait()
1246 assert p1.returncode == 0, "brillo_update_payload properties failed"
1247
1248 # Add the signed payload file and properties into the zip.
1249 common.ZipWrite(output_zip, properties_file, arcname="payload_properties.txt")
Tao Baoc098e9e2016-01-07 13:03:56 -08001250 common.ZipWrite(output_zip, signed_payload_file, arcname="payload.bin",
1251 compress_type=zipfile.ZIP_STORED)
1252 WriteMetadata(metadata, output_zip)
1253
1254 # Sign the whole package to comply with the Android OTA package format.
1255 common.ZipClose(output_zip)
1256 SignOutput(temp_zip_file.name, output_file)
1257 temp_zip_file.close()
1258
1259
Dan Albert8b72aef2015-03-23 19:13:21 -07001260class FileDifference(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001261 def __init__(self, partition, source_zip, target_zip, output_zip):
Dan Albert8b72aef2015-03-23 19:13:21 -07001262 self.deferred_patch_list = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001263 print "Loading target..."
1264 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
1265 print "Loading source..."
1266 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
1267
1268 self.verbatim_targets = verbatim_targets = []
1269 self.patch_list = patch_list = []
1270 diffs = []
1271 self.renames = renames = {}
1272 known_paths = set()
1273 largest_source_size = 0
1274
1275 matching_file_cache = {}
1276 for fn, sf in source_data.items():
1277 assert fn == sf.name
1278 matching_file_cache["path:" + fn] = sf
1279 if fn in target_data.keys():
1280 AddToKnownPaths(fn, known_paths)
1281 # Only allow eligibility for filename/sha matching
1282 # if there isn't a perfect path match.
1283 if target_data.get(sf.name) is None:
1284 matching_file_cache["file:" + fn.split("/")[-1]] = sf
1285 matching_file_cache["sha:" + sf.sha1] = sf
1286
1287 for fn in sorted(target_data.keys()):
1288 tf = target_data[fn]
1289 assert fn == tf.name
1290 sf = ClosestFileMatch(tf, matching_file_cache, renames)
1291 if sf is not None and sf.name != tf.name:
1292 print "File has moved from " + sf.name + " to " + tf.name
1293 renames[sf.name] = tf
1294
1295 if sf is None or fn in OPTIONS.require_verbatim:
1296 # This file should be included verbatim
1297 if fn in OPTIONS.prohibit_verbatim:
1298 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
1299 print "send", fn, "verbatim"
1300 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001301 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001302 if fn in target_data.keys():
1303 AddToKnownPaths(fn, known_paths)
1304 elif tf.sha1 != sf.sha1:
1305 # File is different; consider sending as a patch
1306 diffs.append(common.Difference(tf, sf))
1307 else:
1308 # Target file data identical to source (may still be renamed)
1309 pass
1310
1311 common.ComputeDifferences(diffs)
1312
1313 for diff in diffs:
1314 tf, sf, d = diff.GetPatch()
1315 path = "/".join(tf.name.split("/")[:-1])
1316 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1317 path not in known_paths:
1318 # patch is almost as big as the file; don't bother patching
1319 # or a patch + rename cannot take place due to the target
1320 # directory not existing
1321 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001322 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001323 if sf.name in renames:
1324 del renames[sf.name]
1325 AddToKnownPaths(tf.name, known_paths)
1326 else:
1327 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1328 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1329 largest_source_size = max(largest_source_size, sf.size)
1330
1331 self.largest_source_size = largest_source_size
1332
1333 def EmitVerification(self, script):
1334 so_far = 0
Dan Albert8b72aef2015-03-23 19:13:21 -07001335 for tf, sf, _, _ in self.patch_list:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001336 if tf.name != sf.name:
1337 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1338 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1339 so_far += sf.size
1340 return so_far
1341
Michael Runge63f01de2014-10-28 19:24:19 -07001342 def EmitExplicitTargetVerification(self, script):
Dan Albert8b72aef2015-03-23 19:13:21 -07001343 for fn, _, sha1 in self.verbatim_targets:
1344 if fn[-1] != "/":
Michael Runge63f01de2014-10-28 19:24:19 -07001345 script.FileCheck("/"+fn, sha1)
1346 for tf, _, _, _ in self.patch_list:
1347 script.FileCheck(tf.name, tf.sha1)
1348
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001349 def RemoveUnneededFiles(self, script, extras=()):
Tao Baoa77d41e2015-09-03 21:17:37 -07001350 file_list = ["/" + i[0] for i in self.verbatim_targets]
1351 file_list += ["/" + i for i in self.source_data
1352 if i not in self.target_data and i not in self.renames]
1353 file_list += list(extras)
1354 # Sort the list in descending order, which removes all the files first
1355 # before attempting to remove the folder. (Bug: 22960996)
1356 script.DeleteFiles(sorted(file_list, reverse=True))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001357
1358 def TotalPatchSize(self):
1359 return sum(i[1].size for i in self.patch_list)
1360
1361 def EmitPatches(self, script, total_patch_size, so_far):
1362 self.deferred_patch_list = deferred_patch_list = []
1363 for item in self.patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001364 tf, sf, _, _ = item
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001365 if tf.name == "system/build.prop":
1366 deferred_patch_list.append(item)
1367 continue
Dan Albert8b72aef2015-03-23 19:13:21 -07001368 if sf.name != tf.name:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001369 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
Dan Albert8b72aef2015-03-23 19:13:21 -07001370 script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1,
1371 "patch/" + sf.name + ".p")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001372 so_far += tf.size
1373 script.SetProgress(so_far / total_patch_size)
1374 return so_far
1375
1376 def EmitDeferredPatches(self, script):
1377 for item in self.deferred_patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001378 tf, sf, _, _ = item
1379 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1,
1380 "patch/" + sf.name + ".p")
1381 script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001382
1383 def EmitRenames(self, script):
1384 if len(self.renames) > 0:
1385 script.Print("Renaming files...")
1386 for src, tgt in self.renames.iteritems():
1387 print "Renaming " + src + " to " + tgt.name
1388 script.RenameFile(src, tgt.name)
1389
1390
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001391def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001392 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1393 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1394
Doug Zongker26e66192014-02-20 13:22:07 -08001395 if (OPTIONS.block_based and
1396 target_has_recovery_patch and
1397 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001398 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1399
Doug Zongker37974732010-09-16 17:44:38 -07001400 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1401 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001402
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001403 if source_version == 0:
1404 print ("WARNING: generating edify script for a source that "
1405 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -07001406 script = edify_generator.EdifyGenerator(
1407 source_version, OPTIONS.target_info_dict,
1408 fstab=OPTIONS.source_info_dict["fstab"])
Doug Zongkereef39442009-04-02 12:14:19 -07001409
Michael Runge6e836112014-04-15 17:40:21 -07001410 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Tao Bao34b47bf2015-06-22 19:17:41 -07001411 recovery_mount_options = OPTIONS.source_info_dict.get(
1412 "recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001413 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001414 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001415 if OPTIONS.oem_source is None:
1416 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001417 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001418 oem_dict = common.LoadDictionaryFromLines(
1419 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001420
Dan Albert8b72aef2015-03-23 19:13:21 -07001421 metadata = {
1422 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1423 OPTIONS.source_info_dict),
Tao Baod8d14be2016-02-04 14:26:02 -08001424 "ota-type": "FILE",
Dan Albert8b72aef2015-03-23 19:13:21 -07001425 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001426
Tao Bao5d182562016-02-23 11:38:39 -08001427 post_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict)
1428 pre_timestamp = GetBuildProp("ro.build.date.utc", OPTIONS.source_info_dict)
1429 is_downgrade = long(post_timestamp) < long(pre_timestamp)
1430
1431 if OPTIONS.downgrade:
1432 metadata["ota-downgrade"] = "yes"
1433 if not is_downgrade:
1434 raise RuntimeError("--downgrade specified but no downgrade detected: "
1435 "pre: %s, post: %s" % (pre_timestamp, post_timestamp))
1436 else:
1437 if is_downgrade:
1438 # Non-fatal here to allow generating such a package which may require
1439 # manual work to adjust the post-timestamp. A legit use case is that we
1440 # cut a new build C (after having A and B), but want to enfore the
1441 # update path of A -> C -> B. Specifying --downgrade may not help since
1442 # that would enforce a data wipe for C -> B update.
1443 print("\nWARNING: downgrade detected: pre: %s, post: %s.\n"
1444 "The package may not be deployed properly. "
1445 "Try --downgrade?\n" % (pre_timestamp, post_timestamp))
1446 metadata["post-timestamp"] = post_timestamp
1447
Doug Zongker05d3dea2009-06-22 11:32:31 -07001448 device_specific = common.DeviceSpecificParams(
1449 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001450 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001451 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001452 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001453 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001454 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001455 metadata=metadata,
Tao Bao6f0b2192015-10-13 16:37:12 -07001456 info_dict=OPTIONS.source_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001457
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001458 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001459 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001460 if HasVendorPartition(target_zip):
1461 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001462 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001463 else:
1464 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001465
Dan Albert8b72aef2015-03-23 19:13:21 -07001466 target_fp = CalculateFingerprint(oem_props, oem_dict,
1467 OPTIONS.target_info_dict)
1468 source_fp = CalculateFingerprint(oem_props, oem_dict,
1469 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001470
1471 if oem_props is None:
1472 script.AssertSomeFingerprint(source_fp, target_fp)
1473 else:
1474 script.AssertSomeThumbprint(
1475 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1476 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1477
Doug Zongker2ea21062010-04-28 16:05:21 -07001478 metadata["pre-build"] = source_fp
1479 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001480
Doug Zongker55d93282011-01-25 17:03:34 -08001481 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001482 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1483 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001484 target_boot = common.GetBootableImage(
1485 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001486 updating_boot = (not OPTIONS.two_step and
1487 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001488
Doug Zongker55d93282011-01-25 17:03:34 -08001489 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001490 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1491 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001492 target_recovery = common.GetBootableImage(
1493 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001494 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001495
Doug Zongker881dd402009-09-20 14:03:55 -07001496 # Here's how we divide up the progress bar:
1497 # 0.1 for verifying the start state (PatchCheck calls)
1498 # 0.8 for applying patches (ApplyPatch calls)
1499 # 0.1 for unpacking verbatim files, symlinking, and doing the
1500 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001501
Michael Runge6e836112014-04-15 17:40:21 -07001502 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001503 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001504
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001505 # Two-step incremental package strategy (in chronological order,
1506 # which is *not* the order in which the generated script has
1507 # things):
1508 #
1509 # if stage is not "2/3" or "3/3":
1510 # do verification on current system
1511 # write recovery image to boot partition
1512 # set stage to "2/3"
1513 # reboot to boot partition and restart recovery
1514 # else if stage is "2/3":
1515 # write recovery image to recovery partition
1516 # set stage to "3/3"
1517 # reboot to recovery partition and restart recovery
1518 # else:
1519 # (stage must be "3/3")
1520 # perform update:
1521 # patch system files, etc.
1522 # force full install of new boot image
1523 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001524 # complete script normally
1525 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001526
1527 if OPTIONS.two_step:
Tao Baodd24da92015-07-29 14:09:23 -07001528 if not OPTIONS.source_info_dict.get("multistage_support", None):
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001529 assert False, "two-step packages not supported by this build"
Tao Baodd24da92015-07-29 14:09:23 -07001530 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001531 assert fs.fs_type.upper() == "EMMC", \
1532 "two-step packages only supported on devices with EMMC /misc partitions"
1533 bcb_dev = {"bcb_dev": fs.device}
1534 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1535 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001536if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001537""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001538 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001539 script.WriteRawImage("/recovery", "recovery.img")
1540 script.AppendExtra("""
1541set_stage("%(bcb_dev)s", "3/3");
1542reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001543else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001544""" % bcb_dev)
1545
Tao Bao6c55a8a2015-04-08 15:30:27 -07001546 # Dump fingerprints
1547 script.Print("Source: %s" % (source_fp,))
1548 script.Print("Target: %s" % (target_fp,))
1549
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001550 script.Print("Verifying current system...")
1551
Doug Zongkere5ff5902012-01-17 10:55:37 -08001552 device_specific.IncrementalOTA_VerifyBegin()
1553
Doug Zongker881dd402009-09-20 14:03:55 -07001554 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001555 so_far = system_diff.EmitVerification(script)
1556 if vendor_diff:
1557 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001558
Tao Baod8d14be2016-02-04 14:26:02 -08001559 size = []
1560 if system_diff.patch_list:
1561 size.append(system_diff.largest_source_size)
1562 if vendor_diff:
1563 if vendor_diff.patch_list:
1564 size.append(vendor_diff.largest_source_size)
1565
Doug Zongker5da317e2009-06-02 13:38:17 -07001566 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001567 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001568 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001569 print "boot target: %d source: %d diff: %d" % (
1570 target_boot.size, source_boot.size, len(d))
1571
Doug Zongker048e7ca2009-06-15 14:31:53 -07001572 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001573
Tao Baodd24da92015-07-29 14:09:23 -07001574 boot_type, boot_device = common.GetTypeAndDevice(
1575 "/boot", OPTIONS.source_info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001576
1577 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1578 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001579 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001580 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001581 so_far += source_boot.size
Tao Baod8d14be2016-02-04 14:26:02 -08001582 size.append(target_boot.size)
Doug Zongker5da317e2009-06-02 13:38:17 -07001583
Tao Baod8d14be2016-02-04 14:26:02 -08001584 if size:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001585 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001586
Doug Zongker05d3dea2009-06-22 11:32:31 -07001587 device_specific.IncrementalOTA_VerifyEnd()
1588
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001589 if OPTIONS.two_step:
1590 script.WriteRawImage("/boot", "recovery.img")
1591 script.AppendExtra("""
1592set_stage("%(bcb_dev)s", "2/3");
1593reboot_now("%(bcb_dev)s", "");
1594else
1595""" % bcb_dev)
1596
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001597 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001598
Doug Zongkere5ff5902012-01-17 10:55:37 -08001599 device_specific.IncrementalOTA_InstallBegin()
1600
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001601 if OPTIONS.two_step:
1602 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1603 script.WriteRawImage("/boot", "boot.img")
1604 print "writing full boot image (forced by two-step mode)"
1605
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001606 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001607 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1608 if vendor_diff:
1609 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001610
Doug Zongker881dd402009-09-20 14:03:55 -07001611 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001612 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1613 if vendor_diff:
1614 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001615 if updating_boot:
1616 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001617
1618 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001619 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1620 if vendor_diff:
1621 script.Print("Patching vendor files...")
1622 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001623
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001624 if not OPTIONS.two_step:
1625 if updating_boot:
1626 # Produce the boot image by applying a patch to the current
1627 # contents of the boot partition, and write it back to the
1628 # partition.
1629 script.Print("Patching boot image...")
1630 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1631 % (boot_type, boot_device,
1632 source_boot.size, source_boot.sha1,
1633 target_boot.size, target_boot.sha1),
1634 "-",
1635 target_boot.size, target_boot.sha1,
1636 source_boot.sha1, "patch/boot.img.p")
1637 so_far += target_boot.size
1638 script.SetProgress(so_far / total_patch_size)
1639 print "boot image changed; including."
1640 else:
1641 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001642
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001643 system_items = ItemSet("system", "META/filesystem_config.txt")
1644 if vendor_diff:
1645 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1646
Doug Zongkereef39442009-04-02 12:14:19 -07001647 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001648 # Recovery is generated as a patch using both the boot image
1649 # (which contains the same linux kernel as recovery) and the file
1650 # /system/etc/recovery-resource.dat (which contains all the images
1651 # used in the recovery UI) as sources. This lets us minimize the
1652 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001653 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001654 # For older builds where recovery-resource.dat is not present, we
1655 # use only the boot image as the source.
1656
Doug Zongkerc9253822014-02-04 12:17:58 -08001657 if not target_has_recovery_patch:
1658 def output_sink(fn, data):
1659 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001660 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001661
1662 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1663 target_recovery, target_boot)
1664 script.DeleteFiles(["/system/recovery-from-boot.p",
Tao Baof2cffbd2015-07-22 12:33:18 -07001665 "/system/etc/recovery.img",
Doug Zongkerc9253822014-02-04 12:17:58 -08001666 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001667 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001668 else:
1669 print "recovery image unchanged; skipping."
1670
Doug Zongker881dd402009-09-20 14:03:55 -07001671 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001672
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001673 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1674 if vendor_diff:
1675 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1676
1677 temp_script = script.MakeTemporary()
1678 system_items.GetMetadata(target_zip)
1679 system_items.Get("system").SetPermissions(temp_script)
1680 if vendor_diff:
1681 vendor_items.GetMetadata(target_zip)
1682 vendor_items.Get("vendor").SetPermissions(temp_script)
1683
1684 # Note that this call will mess up the trees of Items, so make sure
1685 # we're done with them.
1686 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1687 if vendor_diff:
1688 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001689
1690 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001691 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1692
1693 # Delete all the symlinks in source that aren't in target. This
1694 # needs to happen before verbatim files are unpacked, in case a
1695 # symlink in the source is replaced by a real file in the target.
Tao Bao84006ea2015-09-02 10:28:08 -07001696
1697 # If a symlink in the source will be replaced by a regular file, we cannot
1698 # delete the symlink/file in case the package gets applied again. For such
1699 # a symlink, we prepend a sha1_check() to detect if it has been updated.
1700 # (Bug: 23646151)
1701 replaced_symlinks = dict()
1702 if system_diff:
1703 for i in system_diff.verbatim_targets:
1704 replaced_symlinks["/%s" % (i[0],)] = i[2]
1705 if vendor_diff:
1706 for i in vendor_diff.verbatim_targets:
1707 replaced_symlinks["/%s" % (i[0],)] = i[2]
1708
1709 if system_diff:
1710 for tf in system_diff.renames.values():
1711 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1712 if vendor_diff:
1713 for tf in vendor_diff.renames.values():
1714 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1715
1716 always_delete = []
1717 may_delete = []
Doug Zongkereef39442009-04-02 12:14:19 -07001718 for dest, link in source_symlinks:
1719 if link not in target_symlinks_d:
Tao Bao84006ea2015-09-02 10:28:08 -07001720 if link in replaced_symlinks:
1721 may_delete.append((link, replaced_symlinks[link]))
1722 else:
1723 always_delete.append(link)
1724 script.DeleteFiles(always_delete)
1725 script.DeleteFilesIfNotMatching(may_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001726
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001727 if system_diff.verbatim_targets:
1728 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001729 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001730 if vendor_diff and vendor_diff.verbatim_targets:
1731 script.Print("Unpacking new vendor files...")
1732 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001733
Doug Zongkerc9253822014-02-04 12:17:58 -08001734 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001735 script.Print("Unpacking new recovery...")
1736 script.UnpackPackageDir("recovery", "/system")
1737
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001738 system_diff.EmitRenames(script)
1739 if vendor_diff:
1740 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001741
Doug Zongker05d3dea2009-06-22 11:32:31 -07001742 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001743
1744 # Create all the symlinks that don't already exist, or point to
1745 # somewhere different than what we want. Delete each symlink before
1746 # creating it, since the 'symlink' command won't overwrite.
1747 to_create = []
1748 for dest, link in target_symlinks:
1749 if link in source_symlinks_d:
1750 if dest != source_symlinks_d[link]:
1751 to_create.append((dest, link))
1752 else:
1753 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001754 script.DeleteFiles([i[1] for i in to_create])
1755 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001756
1757 # Now that the symlinks are created, we can set all the
1758 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001759 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001760
Doug Zongker881dd402009-09-20 14:03:55 -07001761 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001762 device_specific.IncrementalOTA_InstallEnd()
1763
Doug Zongker1c390a22009-05-14 19:06:36 -07001764 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001765 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001766
Doug Zongkere92f15a2011-08-26 13:46:40 -07001767 # Patch the build.prop file last, so if something fails but the
1768 # device can still come up, it appears to be the old build and will
1769 # get set the OTA package again to retry.
1770 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001771 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001772
Doug Zongker922206e2014-03-04 13:16:24 -08001773 if OPTIONS.wipe_user_data:
1774 script.Print("Erasing user data...")
1775 script.FormatPartition("/data")
Tao Bao5d182562016-02-23 11:38:39 -08001776 metadata["ota-wipe"] = "yes"
Doug Zongker922206e2014-03-04 13:16:24 -08001777
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001778 if OPTIONS.two_step:
1779 script.AppendExtra("""
1780set_stage("%(bcb_dev)s", "");
1781endif;
1782endif;
1783""" % bcb_dev)
1784
Michael Runge63f01de2014-10-28 19:24:19 -07001785 if OPTIONS.verify and system_diff:
1786 script.Print("Remounting and verifying system partition files...")
1787 script.Unmount("/system")
Tao Bao269d7852015-12-02 15:49:13 -08001788 script.Mount("/system", recovery_mount_options)
Michael Runge63f01de2014-10-28 19:24:19 -07001789 system_diff.EmitExplicitTargetVerification(script)
1790
1791 if OPTIONS.verify and vendor_diff:
1792 script.Print("Remounting and verifying vendor partition files...")
1793 script.Unmount("/vendor")
Tao Bao269d7852015-12-02 15:49:13 -08001794 script.Mount("/vendor", recovery_mount_options)
Michael Runge63f01de2014-10-28 19:24:19 -07001795 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001796 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001797
Tao Baod8d14be2016-02-04 14:26:02 -08001798 metadata["ota-required-cache"] = str(script.required_cache)
Doug Zongker2ea21062010-04-28 16:05:21 -07001799 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001800
1801
1802def main(argv):
1803
1804 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001805 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001806 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001807 elif o in ("-k", "--package_key"):
1808 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001809 elif o in ("-i", "--incremental_from"):
1810 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001811 elif o == "--full_radio":
1812 OPTIONS.full_radio = True
leozwangaa6c1a12015-08-14 10:57:58 -07001813 elif o == "--full_bootloader":
1814 OPTIONS.full_bootloader = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001815 elif o in ("-w", "--wipe_user_data"):
1816 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001817 elif o in ("-n", "--no_prereq"):
1818 OPTIONS.omit_prereq = True
Tao Bao5d182562016-02-23 11:38:39 -08001819 elif o == "--downgrade":
1820 OPTIONS.downgrade = True
1821 OPTIONS.wipe_user_data = True
Michael Runge6e836112014-04-15 17:40:21 -07001822 elif o in ("-o", "--oem_settings"):
1823 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001824 elif o in ("-e", "--extra_script"):
1825 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001826 elif o in ("-a", "--aslr_mode"):
1827 if a in ("on", "On", "true", "True", "yes", "Yes"):
1828 OPTIONS.aslr_mode = True
1829 else:
1830 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001831 elif o in ("-t", "--worker_threads"):
1832 if a.isdigit():
1833 OPTIONS.worker_threads = int(a)
1834 else:
1835 raise ValueError("Cannot parse value %r for option %r - only "
1836 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001837 elif o in ("-2", "--two_step"):
1838 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001839 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001840 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001841 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001842 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001843 elif o == "--block":
1844 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001845 elif o in ("-b", "--binary"):
1846 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001847 elif o in ("--no_fallback_to_full",):
1848 OPTIONS.fallback_to_full = False
Tao Bao8dcf7382015-05-21 14:09:49 -07001849 elif o == "--stash_threshold":
1850 try:
1851 OPTIONS.stash_threshold = float(a)
1852 except ValueError:
1853 raise ValueError("Cannot parse value %r for option %r - expecting "
1854 "a float" % (a, o))
Tao Bao9bc6bb22015-11-09 16:58:28 -08001855 elif o == "--gen_verify":
1856 OPTIONS.gen_verify = True
Tao Baod62c6032015-11-30 09:40:20 -08001857 elif o == "--log_diff":
1858 OPTIONS.log_diff = a
Doug Zongkereef39442009-04-02 12:14:19 -07001859 else:
1860 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001861 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001862
1863 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001864 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001865 extra_long_opts=[
1866 "board_config=",
1867 "package_key=",
1868 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001869 "full_radio",
leozwangaa6c1a12015-08-14 10:57:58 -07001870 "full_bootloader",
Dan Albert8b72aef2015-03-23 19:13:21 -07001871 "wipe_user_data",
1872 "no_prereq",
Tao Bao5d182562016-02-23 11:38:39 -08001873 "downgrade",
Dan Albert8b72aef2015-03-23 19:13:21 -07001874 "extra_script=",
1875 "worker_threads=",
1876 "aslr_mode=",
1877 "two_step",
1878 "no_signing",
1879 "block",
1880 "binary=",
1881 "oem_settings=",
1882 "verify",
1883 "no_fallback_to_full",
Tao Bao8dcf7382015-05-21 14:09:49 -07001884 "stash_threshold=",
Tao Baod62c6032015-11-30 09:40:20 -08001885 "gen_verify",
1886 "log_diff=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001887 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001888
1889 if len(args) != 2:
1890 common.Usage(__doc__)
1891 sys.exit(1)
1892
Tao Bao5d182562016-02-23 11:38:39 -08001893 if OPTIONS.downgrade:
1894 # Sanity check to enforce a data wipe.
1895 if not OPTIONS.wipe_user_data:
1896 raise ValueError("Cannot downgrade without a data wipe")
1897
1898 # We should only allow downgrading incrementals (as opposed to full).
1899 # Otherwise the device may go back from arbitrary build with this full
1900 # OTA package.
1901 if OPTIONS.incremental_source is None:
1902 raise ValueError("Cannot generate downgradable full OTAs - consider"
1903 "using --omit_prereq?")
1904
Tao Baoc098e9e2016-01-07 13:03:56 -08001905 # Load the dict file from the zip directly to have a peek at the OTA type.
1906 # For packages using A/B update, unzipping is not needed.
1907 input_zip = zipfile.ZipFile(args[0], "r")
1908 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
1909 common.ZipClose(input_zip)
1910
1911 ab_update = OPTIONS.info_dict.get("ab_update") == "true"
1912
1913 if ab_update:
1914 if OPTIONS.incremental_source is not None:
1915 OPTIONS.target_info_dict = OPTIONS.info_dict
1916 source_zip = zipfile.ZipFile(OPTIONS.incremental_source, "r")
1917 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1918 common.ZipClose(source_zip)
1919
1920 if OPTIONS.verbose:
1921 print "--- target info ---"
1922 common.DumpInfoDict(OPTIONS.info_dict)
1923
1924 if OPTIONS.incremental_source is not None:
1925 print "--- source info ---"
1926 common.DumpInfoDict(OPTIONS.source_info_dict)
1927
1928 WriteABOTAPackageWithBrilloScript(
1929 target_file=args[0],
1930 output_file=args[1],
1931 source_file=OPTIONS.incremental_source)
1932
1933 print "done."
1934 return
1935
Doug Zongker1c390a22009-05-14 19:06:36 -07001936 if OPTIONS.extra_script is not None:
1937 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1938
Doug Zongkereef39442009-04-02 12:14:19 -07001939 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001940 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001941
Doug Zongkereef39442009-04-02 12:14:19 -07001942 OPTIONS.target_tmp = OPTIONS.input_tmp
Tao Bao2c15d9e2015-07-09 11:51:16 -07001943 OPTIONS.info_dict = common.LoadInfoDict(input_zip, OPTIONS.target_tmp)
Kenny Roote2e9f612013-05-29 12:59:35 -07001944
Doug Zongker37974732010-09-16 17:44:38 -07001945 if OPTIONS.verbose:
1946 print "--- target info ---"
1947 common.DumpInfoDict(OPTIONS.info_dict)
1948
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001949 # If the caller explicitly specified the device-specific extensions
1950 # path via -s/--device_specific, use that. Otherwise, use
1951 # META/releasetools.py if it is present in the target target_files.
1952 # Otherwise, take the path of the file from 'tool_extensions' in the
1953 # info dict and look for that in the local filesystem, relative to
1954 # the current directory.
1955
Doug Zongker37974732010-09-16 17:44:38 -07001956 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001957 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1958 if os.path.exists(from_input):
1959 print "(using device-specific extensions from target_files)"
1960 OPTIONS.device_specific = from_input
1961 else:
1962 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1963
Doug Zongker37974732010-09-16 17:44:38 -07001964 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001965 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001966
Tao Baoc098e9e2016-01-07 13:03:56 -08001967 if OPTIONS.info_dict.get("no_recovery") == "true":
Tao Baodb45efa2015-10-27 19:25:18 -07001968 raise common.ExternalError(
1969 "--- target build has specified no recovery ---")
1970
Tao Bao767e3ac2015-11-10 12:19:19 -08001971 # Use the default key to sign the package if not specified with package_key.
1972 if not OPTIONS.no_signing:
1973 if OPTIONS.package_key is None:
1974 OPTIONS.package_key = OPTIONS.info_dict.get(
1975 "default_system_dev_certificate",
1976 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -07001977
Tao Bao767e3ac2015-11-10 12:19:19 -08001978 # Set up the output zip. Create a temporary zip file if signing is needed.
1979 if OPTIONS.no_signing:
1980 if os.path.exists(args[1]):
1981 os.unlink(args[1])
1982 output_zip = zipfile.ZipFile(args[1], "w",
1983 compression=zipfile.ZIP_DEFLATED)
1984 else:
1985 temp_zip_file = tempfile.NamedTemporaryFile()
1986 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1987 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001988
Daniel Rosenberg40ef35b2015-11-10 19:21:34 -08001989 # Non A/B OTAs rely on /cache partition to store temporary files.
Tao Bao767e3ac2015-11-10 12:19:19 -08001990 cache_size = OPTIONS.info_dict.get("cache_size", None)
Tao Baoc098e9e2016-01-07 13:03:56 -08001991 if cache_size is None:
Tao Bao767e3ac2015-11-10 12:19:19 -08001992 print "--- can't determine the cache partition size ---"
1993 OPTIONS.cache_size = cache_size
Tao Bao8dcf7382015-05-21 14:09:49 -07001994
Tao Bao9bc6bb22015-11-09 16:58:28 -08001995 # Generate a verify package.
1996 if OPTIONS.gen_verify:
1997 WriteVerifyPackage(input_zip, output_zip)
1998
Tao Bao767e3ac2015-11-10 12:19:19 -08001999 # Generate a full OTA.
Tao Bao9bc6bb22015-11-09 16:58:28 -08002000 elif OPTIONS.incremental_source is None:
Tao Baoc098e9e2016-01-07 13:03:56 -08002001 WriteFullOTAPackage(input_zip, output_zip)
Tao Bao767e3ac2015-11-10 12:19:19 -08002002
2003 # Generate an incremental OTA. It will fall back to generate a full OTA on
2004 # failure unless no_fallback_to_full is specified.
2005 else:
2006 print "unzipping source target-files..."
2007 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
2008 OPTIONS.incremental_source)
2009 OPTIONS.target_info_dict = OPTIONS.info_dict
2010 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip,
2011 OPTIONS.source_tmp)
2012 if OPTIONS.verbose:
2013 print "--- source info ---"
2014 common.DumpInfoDict(OPTIONS.source_info_dict)
2015 try:
2016 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Baod62c6032015-11-30 09:40:20 -08002017 if OPTIONS.log_diff:
2018 out_file = open(OPTIONS.log_diff, 'w')
2019 import target_files_diff
2020 target_files_diff.recursiveDiff('',
2021 OPTIONS.source_tmp,
2022 OPTIONS.input_tmp,
2023 out_file)
2024 out_file.close()
Tao Bao767e3ac2015-11-10 12:19:19 -08002025 except ValueError:
2026 if not OPTIONS.fallback_to_full:
2027 raise
2028 print "--- failed to build incremental; falling back to full ---"
2029 OPTIONS.incremental_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -07002030 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07002031
Tao Bao767e3ac2015-11-10 12:19:19 -08002032 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07002033
Tao Bao767e3ac2015-11-10 12:19:19 -08002034 # Sign the generated zip package unless no_signing is specified.
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09002035 if not OPTIONS.no_signing:
2036 SignOutput(temp_zip_file.name, args[1])
2037 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07002038
Doug Zongkereef39442009-04-02 12:14:19 -07002039 print "done."
2040
2041
2042if __name__ == '__main__':
2043 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08002044 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07002045 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07002046 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07002047 print
2048 print " ERROR: %s" % (e,)
2049 print
2050 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07002051 finally:
2052 common.Cleanup()