blob: f5b912f7c29fd55a7f9e26f61427820615a697ce [file] [log] [blame]
Doug Zongkereef39442009-04-02 12:14:19 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2008 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""
18Given a target-files zipfile, produces an OTA package that installs
19that build. An incremental OTA is produced if -i is given, otherwise
20a full OTA is produced.
21
22Usage: ota_from_target_files [flags] input_target_files output_ota_package
23
Doug Zongker25568482014-03-03 10:21:27 -080024 --board_config <file>
Doug Zongkerfdd8e692009-08-03 17:27:48 -070025 Deprecated.
Doug Zongkereef39442009-04-02 12:14:19 -070026
Doug Zongkerafb32ea2011-09-22 10:28:04 -070027 -k (--package_key) <key> Key to use to sign the package (default is
28 the value of default_system_dev_certificate from the input
29 target-files's META/misc_info.txt, or
30 "build/target/product/security/testkey" if that value is not
31 specified).
32
33 For incremental OTAs, the default value is based on the source
34 target-file, not the target build.
Doug Zongkereef39442009-04-02 12:14:19 -070035
36 -i (--incremental_from) <file>
37 Generate an incremental OTA using the given target-files zip as
38 the starting build.
39
Tao Bao43078aa2015-04-21 14:32:35 -070040 --full_radio
41 When generating an incremental OTA, always include a full copy of
42 radio image. This option is only meaningful when -i is specified,
43 because a full radio is always included in a full OTA if applicable.
44
Michael Runge63f01de2014-10-28 19:24:19 -070045 -v (--verify)
46 Remount and verify the checksums of the files written to the
47 system and vendor (if used) partitions. Incremental builds only.
48
Michael Runge6e836112014-04-15 17:40:21 -070049 -o (--oem_settings) <file>
50 Use the file to specify the expected OEM-specific properties
51 on the OEM partition of the intended device.
52
Doug Zongkerdbfaae52009-04-21 17:12:54 -070053 -w (--wipe_user_data)
54 Generate an OTA package that will wipe the user data partition
55 when installed.
56
Doug Zongker962069c2009-04-23 11:41:58 -070057 -n (--no_prereq)
58 Omit the timestamp prereq check normally included at the top of
59 the build scripts (used for developer OTA packages which
60 legitimately need to go back and forth).
61
Doug Zongker1c390a22009-05-14 19:06:36 -070062 -e (--extra_script) <file>
63 Insert the contents of file at the end of the update script.
64
Hristo Bojinovdafb0422010-08-26 14:35:16 -070065 -a (--aslr_mode) <on|off>
66 Specify whether to turn on ASLR for the package (on by default).
Stephen Smalley56882bf2012-02-09 13:36:21 -050067
Doug Zongker9b23f2c2013-11-25 14:44:12 -080068 -2 (--two_step)
69 Generate a 'two-step' OTA package, where recovery is updated
70 first, so that any changes made to the system partition are done
71 using the new recovery (new kernel, etc.).
72
Doug Zongker26e66192014-02-20 13:22:07 -080073 --block
74 Generate a block-based OTA if possible. Will fall back to a
75 file-based OTA if the target_files is older and doesn't support
76 block-based OTAs.
77
Doug Zongker25568482014-03-03 10:21:27 -080078 -b (--binary) <file>
79 Use the given binary as the update-binary in the output package,
80 instead of the binary in the build's target_files. Use for
81 development only.
82
Martin Blumenstingl374e1142014-05-31 20:42:55 +020083 -t (--worker_threads) <int>
84 Specifies the number of worker-threads that will be used when
85 generating patches for incremental updates (defaults to 3).
86
Tao Bao8dcf7382015-05-21 14:09:49 -070087 --stash_threshold <float>
88 Specifies the threshold that will be used to compute the maximum
89 allowed stash size (defaults to 0.8).
Doug Zongkereef39442009-04-02 12:14:19 -070090"""
91
92import sys
93
Doug Zongkercf6d5a92014-02-18 10:57:07 -080094if sys.hexversion < 0x02070000:
95 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -070096 sys.exit(1)
97
Doug Zongkerfc44a512014-08-26 13:10:25 -070098import multiprocessing
Doug Zongkereef39442009-04-02 12:14:19 -070099import os
Doug Zongkereef39442009-04-02 12:14:19 -0700100import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -0700101import zipfile
102
103import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700104import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -0700105import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700106
107OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700108OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700109OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700110OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700111OPTIONS.require_verbatim = set()
112OPTIONS.prohibit_verbatim = set(("system/build.prop",))
113OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700114OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700115OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700116OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700117OPTIONS.aslr_mode = True
Doug Zongkerfc44a512014-08-26 13:10:25 -0700118OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
119if OPTIONS.worker_threads == 0:
120 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800121OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900122OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800123OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800124OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700125OPTIONS.oem_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -0700126OPTIONS.fallback_to_full = True
Tao Bao43078aa2015-04-21 14:32:35 -0700127OPTIONS.full_radio = False
Tao Bao8dcf7382015-05-21 14:09:49 -0700128# Stash size cannot exceed cache_size * threshold.
129OPTIONS.cache_size = None
130OPTIONS.stash_threshold = 0.8
131
Doug Zongkereef39442009-04-02 12:14:19 -0700132
133def MostPopularKey(d, default):
134 """Given a dict, return the key corresponding to the largest
135 value. Returns 'default' if the dict is empty."""
136 x = [(v, k) for (k, v) in d.iteritems()]
Dan Albert8b72aef2015-03-23 19:13:21 -0700137 if not x:
138 return default
Doug Zongkereef39442009-04-02 12:14:19 -0700139 x.sort()
140 return x[-1][1]
141
142
143def IsSymlink(info):
144 """Return true if the zipfile.ZipInfo object passed in represents a
145 symlink."""
Ying Wang2ffb3142015-07-06 14:02:01 -0700146 return (info.external_attr >> 16) & 0o770000 == 0o120000
Doug Zongkereef39442009-04-02 12:14:19 -0700147
Hristo Bojinov96be7202010-08-02 10:26:17 -0700148def IsRegular(info):
149 """Return true if the zipfile.ZipInfo object passed in represents a
Ying Wang2ffb3142015-07-06 14:02:01 -0700150 regular file."""
151 return (info.external_attr >> 16) & 0o770000 == 0o100000
Doug Zongkereef39442009-04-02 12:14:19 -0700152
Michael Runge4038aa82013-12-13 18:06:28 -0800153def ClosestFileMatch(src, tgtfiles, existing):
154 """Returns the closest file match between a source file and list
155 of potential matches. The exact filename match is preferred,
156 then the sha1 is searched for, and finally a file with the same
157 basename is evaluated. Rename support in the updater-binary is
158 required for the latter checks to be used."""
159
160 result = tgtfiles.get("path:" + src.name)
161 if result is not None:
162 return result
163
164 if not OPTIONS.target_info_dict.get("update_rename_support", False):
165 return None
166
167 if src.size < 1000:
168 return None
169
170 result = tgtfiles.get("sha1:" + src.sha1)
171 if result is not None and existing.get(result.name) is None:
172 return result
173 result = tgtfiles.get("file:" + src.name.split("/")[-1])
174 if result is not None and existing.get(result.name) is None:
175 return result
176 return None
177
Dan Albert8b72aef2015-03-23 19:13:21 -0700178class ItemSet(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700179 def __init__(self, partition, fs_config):
180 self.partition = partition
181 self.fs_config = fs_config
182 self.ITEMS = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700183
Dan Albert8b72aef2015-03-23 19:13:21 -0700184 def Get(self, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700185 if name not in self.ITEMS:
Dan Albert8b72aef2015-03-23 19:13:21 -0700186 self.ITEMS[name] = Item(self, name, is_dir=is_dir)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700187 return self.ITEMS[name]
Doug Zongkereef39442009-04-02 12:14:19 -0700188
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700189 def GetMetadata(self, input_zip):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700190 # The target_files contains a record of what the uid,
191 # gid, and mode are supposed to be.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700192 output = input_zip.read(self.fs_config)
Doug Zongkereef39442009-04-02 12:14:19 -0700193
194 for line in output.split("\n"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700195 if not line:
196 continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700197 columns = line.split()
198 name, uid, gid, mode = columns[:4]
199 selabel = None
200 capabilities = None
201
202 # After the first 4 columns, there are a series of key=value
203 # pairs. Extract out the fields we care about.
204 for element in columns[4:]:
205 key, value = element.split("=")
206 if key == "selabel":
207 selabel = value
208 if key == "capabilities":
209 capabilities = value
210
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700211 i = self.ITEMS.get(name, None)
Doug Zongker283e2a12010-03-15 17:52:32 -0700212 if i is not None:
213 i.uid = int(uid)
214 i.gid = int(gid)
215 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700216 i.selabel = selabel
217 i.capabilities = capabilities
Dan Albert8b72aef2015-03-23 19:13:21 -0700218 if i.is_dir:
Doug Zongker283e2a12010-03-15 17:52:32 -0700219 i.children.sort(key=lambda i: i.name)
220
Tao Baof2cffbd2015-07-22 12:33:18 -0700221 # Set metadata for the files generated by this script. For full recovery
222 # image at system/etc/recovery.img, it will be taken care by fs_config.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700223 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700224 if i:
225 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700226 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700227 if i:
228 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700229
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700230
Dan Albert8b72aef2015-03-23 19:13:21 -0700231class Item(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700232 """Items represent the metadata (user, group, mode) of files and
233 directories in the system image."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700234 def __init__(self, itemset, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700235 self.itemset = itemset
236 self.name = name
237 self.uid = None
238 self.gid = None
239 self.mode = None
240 self.selabel = None
241 self.capabilities = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700242 self.is_dir = is_dir
243 self.descendants = None
244 self.best_subtree = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700245
246 if name:
Dan Albert8b72aef2015-03-23 19:13:21 -0700247 self.parent = itemset.Get(os.path.dirname(name), is_dir=True)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700248 self.parent.children.append(self)
249 else:
250 self.parent = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700251 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700252 self.children = []
253
254 def Dump(self, indent=0):
255 if self.uid is not None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700256 print "%s%s %d %d %o" % (
257 " " * indent, self.name, self.uid, self.gid, self.mode)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700258 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700259 print "%s%s %s %s %s" % (
260 " " * indent, self.name, self.uid, self.gid, self.mode)
261 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700262 print "%s%s" % (" "*indent, self.descendants)
263 print "%s%s" % (" "*indent, self.best_subtree)
264 for i in self.children:
265 i.Dump(indent=indent+1)
266
Doug Zongkereef39442009-04-02 12:14:19 -0700267 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700268 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
Dan Albert8b72aef2015-03-23 19:13:21 -0700269 all children and determine the best strategy for using set_perm_recursive
270 and set_perm to correctly chown/chmod all the files to their desired
Doug Zongkereef39442009-04-02 12:14:19 -0700271 values. Recursively calls itself for all descendants.
272
Dan Albert8b72aef2015-03-23 19:13:21 -0700273 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count}
274 counting up all descendants of this node. (dmode or fmode may be None.)
275 Also sets the best_subtree of each directory Item to the (uid, gid, dmode,
276 fmode, selabel, capabilities) tuple that will match the most descendants of
277 that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700278 """
279
Dan Albert8b72aef2015-03-23 19:13:21 -0700280 assert self.is_dir
281 key = (self.uid, self.gid, self.mode, None, self.selabel,
282 self.capabilities)
283 self.descendants = {key: 1}
284 d = self.descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700285 for i in self.children:
Dan Albert8b72aef2015-03-23 19:13:21 -0700286 if i.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700287 for k, v in i.CountChildMetadata().iteritems():
288 d[k] = d.get(k, 0) + v
289 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700290 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700291 d[k] = d.get(k, 0) + 1
292
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700293 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
294 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700295
296 # First, find the (uid, gid) pair that matches the most
297 # descendants.
298 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700299 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700300 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
301 ug = MostPopularKey(ug, (0, 0))
302
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700303 # Now find the dmode, fmode, selabel, and capabilities that match
304 # the most descendants with that (uid, gid), and choose those.
Dan Albert8b72aef2015-03-23 19:13:21 -0700305 best_dmode = (0, 0o755)
306 best_fmode = (0, 0o644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700307 best_selabel = (0, None)
308 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700309 for k, count in d.iteritems():
Dan Albert8b72aef2015-03-23 19:13:21 -0700310 if k[:2] != ug:
311 continue
312 if k[2] is not None and count >= best_dmode[0]:
313 best_dmode = (count, k[2])
314 if k[3] is not None and count >= best_fmode[0]:
315 best_fmode = (count, k[3])
316 if k[4] is not None and count >= best_selabel[0]:
317 best_selabel = (count, k[4])
318 if k[5] is not None and count >= best_capabilities[0]:
319 best_capabilities = (count, k[5])
320 self.best_subtree = ug + (
321 best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700322
323 return d
324
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700325 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700326 """Append set_perm/set_perm_recursive commands to 'script' to
327 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700328 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700329
330 self.CountChildMetadata()
331
332 def recurse(item, current):
Dan Albert8b72aef2015-03-23 19:13:21 -0700333 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple
334 # that the current item (and all its children) have already been set to.
335 # We only need to issue set_perm/set_perm_recursive commands if we're
Doug Zongkereef39442009-04-02 12:14:19 -0700336 # supposed to be something different.
Dan Albert8b72aef2015-03-23 19:13:21 -0700337 if item.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700338 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700339 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700340 current = item.best_subtree
341
342 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700343 item.mode != current[2] or item.selabel != current[4] or \
344 item.capabilities != current[5]:
345 script.SetPermissions("/"+item.name, item.uid, item.gid,
346 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700347
348 for i in item.children:
349 recurse(i, current)
350 else:
351 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700352 item.mode != current[3] or item.selabel != current[4] or \
353 item.capabilities != current[5]:
354 script.SetPermissions("/"+item.name, item.uid, item.gid,
355 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700356
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700357 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700358
359
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700360def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
361 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700362 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800363 list of symlinks. output_zip may be None, in which case the copy is
364 skipped (but the other side effects still happen). substitute is an
365 optional dict of {output filename: contents} to be output instead of
366 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700367 """
368
369 symlinks = []
370
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700371 partition = itemset.partition
372
Doug Zongkereef39442009-04-02 12:14:19 -0700373 for info in input_zip.infolist():
Tao Baoeaf885b2015-03-23 16:01:17 -0700374 prefix = partition.upper() + "/"
375 if info.filename.startswith(prefix):
376 basefilename = info.filename[len(prefix):]
Doug Zongkereef39442009-04-02 12:14:19 -0700377 if IsSymlink(info):
378 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700379 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700380 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700381 import copy
Doug Zongkereef39442009-04-02 12:14:19 -0700382 info2 = copy.copy(info)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700383 fn = info2.filename = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700384 if substitute and fn in substitute and substitute[fn] is None:
385 continue
386 if output_zip is not None:
387 if substitute and fn in substitute:
388 data = substitute[fn]
389 else:
390 data = input_zip.read(info.filename)
Tao Bao2ed665a2015-04-01 11:21:55 -0700391 common.ZipWriteStr(output_zip, info2, data)
Doug Zongkereef39442009-04-02 12:14:19 -0700392 if fn.endswith("/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700393 itemset.Get(fn[:-1], is_dir=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700394 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700395 itemset.Get(fn)
Doug Zongkereef39442009-04-02 12:14:19 -0700396
397 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800398 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700399
400
Doug Zongkereef39442009-04-02 12:14:19 -0700401def SignOutput(temp_zip_name, output_zip_name):
402 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
403 pw = key_passwords[OPTIONS.package_key]
404
Doug Zongker951495f2009-08-14 12:44:19 -0700405 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
406 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700407
408
Dan Albert8b72aef2015-03-23 19:13:21 -0700409def AppendAssertions(script, info_dict, oem_dict=None):
Michael Runge6e836112014-04-15 17:40:21 -0700410 oem_props = info_dict.get("oem_fingerprint_properties")
Michael Runge560569a2014-09-18 15:12:45 -0700411 if oem_props is None or len(oem_props) == 0:
Michael Runge6e836112014-04-15 17:40:21 -0700412 device = GetBuildProp("ro.product.device", info_dict)
413 script.AssertDevice(device)
414 else:
415 if oem_dict is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700416 raise common.ExternalError(
417 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700418 for prop in oem_props.split():
419 if oem_dict.get(prop) is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700420 raise common.ExternalError(
421 "The OEM file is missing the property %s" % prop)
Michael Runge6e836112014-04-15 17:40:21 -0700422 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700423
Doug Zongkereef39442009-04-02 12:14:19 -0700424
Doug Zongkerc9253822014-02-04 12:17:58 -0800425def HasRecoveryPatch(target_files_zip):
Tao Baof2cffbd2015-07-22 12:33:18 -0700426 namelist = [name for name in target_files_zip.namelist()]
427 return ("SYSTEM/recovery-from-boot.p" in namelist or
428 "SYSTEM/etc/recovery.img" in namelist)
Doug Zongker73ef8252009-07-23 15:12:53 -0700429
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700430def HasVendorPartition(target_files_zip):
431 try:
432 target_files_zip.getinfo("VENDOR/")
433 return True
434 except KeyError:
435 return False
436
Michael Runge6e836112014-04-15 17:40:21 -0700437def GetOemProperty(name, oem_props, oem_dict, info_dict):
438 if oem_props is not None and name in oem_props:
439 return oem_dict[name]
440 return GetBuildProp(name, info_dict)
441
442
443def CalculateFingerprint(oem_props, oem_dict, info_dict):
444 if oem_props is None:
445 return GetBuildProp("ro.build.fingerprint", info_dict)
446 return "%s/%s/%s:%s" % (
Dan Albert8b72aef2015-03-23 19:13:21 -0700447 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
448 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
449 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
450 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700451
Doug Zongkerfc44a512014-08-26 13:10:25 -0700452
Doug Zongker3c84f562014-07-31 11:06:30 -0700453def GetImage(which, tmpdir, info_dict):
Doug Zongkerfc44a512014-08-26 13:10:25 -0700454 # Return an image object (suitable for passing to BlockImageDiff)
455 # for the 'which' partition (most be "system" or "vendor"). If a
456 # prebuilt image and file map are found in tmpdir they are used,
457 # otherwise they are reconstructed from the individual files.
Doug Zongker3c84f562014-07-31 11:06:30 -0700458
459 assert which in ("system", "vendor")
460
461 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700462 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
463 if os.path.exists(path) and os.path.exists(mappath):
Doug Zongker3c84f562014-07-31 11:06:30 -0700464 print "using %s.img from target-files" % (which,)
Doug Zongker3c84f562014-07-31 11:06:30 -0700465 # This is a 'new' target-files, which already has the image in it.
Doug Zongker3c84f562014-07-31 11:06:30 -0700466
467 else:
468 print "building %s.img from target-files" % (which,)
469
470 # This is an 'old' target-files, which does not contain images
471 # already built. Build them.
472
Doug Zongkerfc44a512014-08-26 13:10:25 -0700473 mappath = tempfile.mkstemp()[1]
474 OPTIONS.tempfiles.append(mappath)
475
Doug Zongker3c84f562014-07-31 11:06:30 -0700476 import add_img_to_target_files
477 if which == "system":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700478 path = add_img_to_target_files.BuildSystem(
479 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700480 elif which == "vendor":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700481 path = add_img_to_target_files.BuildVendor(
482 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700483
Tao Baoff777812015-05-12 11:42:31 -0700484 # Bug: http://b/20939131
485 # In ext4 filesystems, block 0 might be changed even being mounted
486 # R/O. We add it to clobbered_blocks so that it will be written to the
487 # target unconditionally. Note that they are still part of care_map.
488 clobbered_blocks = "0"
489
490 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700491
492
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700493def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700494 # TODO: how to determine this? We don't know what version it will
Tao Bao34b47bf2015-06-22 19:17:41 -0700495 # be installed on top of. For now, we expect the API just won't
496 # change very often. Similarly for fstab, it might have changed
497 # in the target build.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700498 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700499
Michael Runge6e836112014-04-15 17:40:21 -0700500 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700501 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700502 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700503 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700504 if OPTIONS.oem_source is None:
505 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700506 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700507 oem_dict = common.LoadDictionaryFromLines(
508 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -0700509
Dan Albert8b72aef2015-03-23 19:13:21 -0700510 metadata = {
511 "post-build": CalculateFingerprint(oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700512 OPTIONS.info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700513 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
514 OPTIONS.info_dict),
515 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
516 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700517
Doug Zongker05d3dea2009-06-22 11:32:31 -0700518 device_specific = common.DeviceSpecificParams(
519 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700520 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700521 output_zip=output_zip,
522 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700523 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700524 metadata=metadata,
525 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700526
Doug Zongkerc9253822014-02-04 12:17:58 -0800527 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800528 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800529
Doug Zongker962069c2009-04-23 11:41:58 -0700530 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700531 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700532 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
533 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700534
Michael Runge6e836112014-04-15 17:40:21 -0700535 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700536 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800537
538 # Two-step package strategy (in chronological order, which is *not*
539 # the order in which the generated script has things):
540 #
541 # if stage is not "2/3" or "3/3":
542 # write recovery image to boot partition
543 # set stage to "2/3"
544 # reboot to boot partition and restart recovery
545 # else if stage is "2/3":
546 # write recovery image to recovery partition
547 # set stage to "3/3"
548 # reboot to recovery partition and restart recovery
549 # else:
550 # (stage must be "3/3")
551 # set stage to ""
552 # do normal full package installation:
553 # wipe and install system, boot image, etc.
554 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700555 # complete script normally
556 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800557
558 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
559 OPTIONS.input_tmp, "RECOVERY")
560 if OPTIONS.two_step:
561 if not OPTIONS.info_dict.get("multistage_support", None):
562 assert False, "two-step packages not supported by this build"
563 fs = OPTIONS.info_dict["fstab"]["/misc"]
564 assert fs.fs_type.upper() == "EMMC", \
565 "two-step packages only supported on devices with EMMC /misc partitions"
566 bcb_dev = {"bcb_dev": fs.device}
567 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
568 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700569if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800570""" % bcb_dev)
571 script.WriteRawImage("/recovery", "recovery.img")
572 script.AppendExtra("""
573set_stage("%(bcb_dev)s", "3/3");
574reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700575else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800576""" % bcb_dev)
577
Tao Bao6c55a8a2015-04-08 15:30:27 -0700578 # Dump fingerprints
579 script.Print("Target: %s" % CalculateFingerprint(
580 oem_props, oem_dict, OPTIONS.info_dict))
581
Doug Zongkere5ff5902012-01-17 10:55:37 -0800582 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700583
Doug Zongker01ce19c2014-02-04 13:48:15 -0800584 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700585
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700586 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800587 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700588 if HasVendorPartition(input_zip):
589 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700590
Tao Bao2c15d9e2015-07-09 11:51:16 -0700591 # Place a copy of file_contexts into the OTA package which will be used by
592 # the recovery program.
Kenny Rootf32dc712012-04-08 10:42:34 -0700593 if "selinux_fc" in OPTIONS.info_dict:
594 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500595
Michael Runge7cd99ba2014-10-22 17:21:48 -0700596 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
597
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700598 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700599 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800600
Doug Zongker26e66192014-02-20 13:22:07 -0800601 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700602 # Full OTA is done as an "incremental" against an empty source
603 # image. This has the effect of writing new data from the package
604 # to the entire partition, but lets us reuse the updater code that
605 # writes incrementals to do it.
606 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
607 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700608 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700609 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800610 else:
611 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700612 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800613 if not has_recovery_patch:
614 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800615 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700616
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700617 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800618 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700619
Doug Zongker55d93282011-01-25 17:03:34 -0800620 boot_img = common.GetBootableImage("boot.img", "boot.img",
621 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800622
Doug Zongker91a99c22014-05-09 13:15:01 -0700623 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800624 def output_sink(fn, data):
625 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700626 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800627
628 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
629 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700630
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700631 system_items.GetMetadata(input_zip)
632 system_items.Get("system").SetPermissions(script)
633
634 if HasVendorPartition(input_zip):
635 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
636 script.ShowProgress(0.1, 0)
637
638 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700639 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
640 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700641 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700642 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700643 else:
644 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700645 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700646 script.UnpackPackageDir("vendor", "/vendor")
647
648 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
649 script.MakeSymlinks(symlinks)
650
651 vendor_items.GetMetadata(input_zip)
652 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700653
Doug Zongker37974732010-09-16 17:44:38 -0700654 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700655 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700656
Doug Zongker01ce19c2014-02-04 13:48:15 -0800657 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700658 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700659
Doug Zongker01ce19c2014-02-04 13:48:15 -0800660 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700661 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700662
Doug Zongker1c390a22009-05-14 19:06:36 -0700663 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700664 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700665
Doug Zongker14833602010-02-02 13:12:04 -0800666 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800667
Doug Zongker922206e2014-03-04 13:16:24 -0800668 if OPTIONS.wipe_user_data:
669 script.ShowProgress(0.1, 10)
670 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700671
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800672 if OPTIONS.two_step:
673 script.AppendExtra("""
674set_stage("%(bcb_dev)s", "");
675""" % bcb_dev)
676 script.AppendExtra("else\n")
677 script.WriteRawImage("/boot", "recovery.img")
678 script.AppendExtra("""
679set_stage("%(bcb_dev)s", "2/3");
680reboot_now("%(bcb_dev)s", "");
681endif;
682endif;
683""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800684 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700685 WriteMetadata(metadata, output_zip)
686
Doug Zongkerfc44a512014-08-26 13:10:25 -0700687
Dan Albert8e0178d2015-01-27 15:53:15 -0800688def WritePolicyConfig(file_name, output_zip):
689 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500690
Doug Zongker2ea21062010-04-28 16:05:21 -0700691
692def WriteMetadata(metadata, output_zip):
693 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
694 "".join(["%s=%s\n" % kv
695 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700696
Doug Zongkerfc44a512014-08-26 13:10:25 -0700697
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700698def LoadPartitionFiles(z, partition):
699 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700700 ZipFile, and return a dict of {filename: File object}."""
701 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700702 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700703 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700704 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700705 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700706 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700707 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700708 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800709 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700710
711
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700712def GetBuildProp(prop, info_dict):
713 """Return the fingerprint of the build of a given target-files info_dict."""
714 try:
715 return info_dict.get("build.prop", {})[prop]
716 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700717 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700718
Doug Zongkerfc44a512014-08-26 13:10:25 -0700719
Michael Runge4038aa82013-12-13 18:06:28 -0800720def AddToKnownPaths(filename, known_paths):
721 if filename[-1] == "/":
722 return
723 dirs = filename.split("/")[:-1]
724 while len(dirs) > 0:
725 path = "/".join(dirs)
726 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700727 break
Michael Runge4038aa82013-12-13 18:06:28 -0800728 known_paths.add(path)
729 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700730
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700731
Geremy Condra36bd3652014-02-06 19:45:10 -0800732def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
Tao Bao3806c232015-07-05 21:08:33 -0700733 # TODO(tbao): We should factor out the common parts between
734 # WriteBlockIncrementalOTAPackage() and WriteIncrementalOTAPackage().
Geremy Condra36bd3652014-02-06 19:45:10 -0800735 source_version = OPTIONS.source_info_dict["recovery_api_version"]
736 target_version = OPTIONS.target_info_dict["recovery_api_version"]
737
738 if source_version == 0:
739 print ("WARNING: generating edify script for a source that "
740 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -0700741 script = edify_generator.EdifyGenerator(
742 source_version, OPTIONS.target_info_dict,
743 fstab=OPTIONS.source_info_dict["fstab"])
Geremy Condra36bd3652014-02-06 19:45:10 -0800744
Tao Bao3806c232015-07-05 21:08:33 -0700745 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
746 recovery_mount_options = OPTIONS.source_info_dict.get(
747 "recovery_mount_options")
748 oem_dict = None
749 if oem_props is not None and len(oem_props) > 0:
750 if OPTIONS.oem_source is None:
751 raise common.ExternalError("OEM source required for this build")
752 script.Mount("/oem", recovery_mount_options)
753 oem_dict = common.LoadDictionaryFromLines(
754 open(OPTIONS.oem_source).readlines())
755
Dan Albert8b72aef2015-03-23 19:13:21 -0700756 metadata = {
Tao Bao3806c232015-07-05 21:08:33 -0700757 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
758 OPTIONS.source_info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700759 "post-timestamp": GetBuildProp("ro.build.date.utc",
760 OPTIONS.target_info_dict),
761 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800762
763 device_specific = common.DeviceSpecificParams(
764 source_zip=source_zip,
765 source_version=source_version,
766 target_zip=target_zip,
767 target_version=target_version,
768 output_zip=output_zip,
769 script=script,
770 metadata=metadata,
771 info_dict=OPTIONS.info_dict)
772
Tao Bao3806c232015-07-05 21:08:33 -0700773 source_fp = CalculateFingerprint(oem_props, oem_dict,
774 OPTIONS.source_info_dict)
775 target_fp = CalculateFingerprint(oem_props, oem_dict,
776 OPTIONS.target_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800777 metadata["pre-build"] = source_fp
778 metadata["post-build"] = target_fp
779
780 source_boot = common.GetBootableImage(
781 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
782 OPTIONS.source_info_dict)
783 target_boot = common.GetBootableImage(
784 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
785 updating_boot = (not OPTIONS.two_step and
786 (source_boot.data != target_boot.data))
787
Geremy Condra36bd3652014-02-06 19:45:10 -0800788 target_recovery = common.GetBootableImage(
789 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800790
Doug Zongkerfc44a512014-08-26 13:10:25 -0700791 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
792 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700793
794 blockimgdiff_version = 1
795 if OPTIONS.info_dict:
796 blockimgdiff_version = max(
797 int(i) for i in
798 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
799
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700800 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700801 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700802
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700803 if HasVendorPartition(target_zip):
804 if not HasVendorPartition(source_zip):
805 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700806 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
807 OPTIONS.source_info_dict)
808 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
809 OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700810 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700811 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700812 else:
813 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800814
Michael Rungec6e3afd2014-05-05 11:55:47 -0700815 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800816 device_specific.IncrementalOTA_Assertions()
817
818 # Two-step incremental package strategy (in chronological order,
819 # which is *not* the order in which the generated script has
820 # things):
821 #
822 # if stage is not "2/3" or "3/3":
823 # do verification on current system
824 # write recovery image to boot partition
825 # set stage to "2/3"
826 # reboot to boot partition and restart recovery
827 # else if stage is "2/3":
828 # write recovery image to recovery partition
829 # set stage to "3/3"
830 # reboot to recovery partition and restart recovery
831 # else:
832 # (stage must be "3/3")
833 # perform update:
834 # patch system files, etc.
835 # force full install of new boot image
836 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700837 # complete script normally
838 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800839
840 if OPTIONS.two_step:
841 if not OPTIONS.info_dict.get("multistage_support", None):
842 assert False, "two-step packages not supported by this build"
843 fs = OPTIONS.info_dict["fstab"]["/misc"]
844 assert fs.fs_type.upper() == "EMMC", \
845 "two-step packages only supported on devices with EMMC /misc partitions"
846 bcb_dev = {"bcb_dev": fs.device}
847 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
848 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700849if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800850""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -0700851 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800852 script.WriteRawImage("/recovery", "recovery.img")
853 script.AppendExtra("""
854set_stage("%(bcb_dev)s", "3/3");
855reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700856else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800857""" % bcb_dev)
858
Tao Bao6c55a8a2015-04-08 15:30:27 -0700859 # Dump fingerprints
860 script.Print("Source: %s" % CalculateFingerprint(
861 oem_props, oem_dict, OPTIONS.source_info_dict))
862 script.Print("Target: %s" % CalculateFingerprint(
863 oem_props, oem_dict, OPTIONS.target_info_dict))
864
Geremy Condra36bd3652014-02-06 19:45:10 -0800865 script.Print("Verifying current system...")
866
867 device_specific.IncrementalOTA_VerifyBegin()
868
Michael Rungec6e3afd2014-05-05 11:55:47 -0700869 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700870 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
871 # patching on a device that's already on the target build will damage the
872 # system. Because operations like move don't check the block state, they
873 # always apply the changes unconditionally.
874 if blockimgdiff_version <= 2:
875 script.AssertSomeFingerprint(source_fp)
876 else:
877 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700878 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700879 if blockimgdiff_version <= 2:
880 script.AssertSomeThumbprint(
881 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
882 else:
883 script.AssertSomeThumbprint(
884 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
885 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800886
887 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700888 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800889 d = common.Difference(target_boot, source_boot)
890 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700891 if d is None:
892 include_full_boot = True
893 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
894 else:
895 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800896
Doug Zongkerf8340082014-08-05 10:39:37 -0700897 print "boot target: %d source: %d diff: %d" % (
898 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800899
Doug Zongkerf8340082014-08-05 10:39:37 -0700900 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800901
Doug Zongkerf8340082014-08-05 10:39:37 -0700902 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
903 (boot_type, boot_device,
904 source_boot.size, source_boot.sha1,
905 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800906
907 device_specific.IncrementalOTA_VerifyEnd()
908
909 if OPTIONS.two_step:
910 script.WriteRawImage("/boot", "recovery.img")
911 script.AppendExtra("""
912set_stage("%(bcb_dev)s", "2/3");
913reboot_now("%(bcb_dev)s", "");
914else
915""" % bcb_dev)
916
Jesse Zhao75bcea02015-01-06 10:59:53 -0800917 # Verify the existing partitions.
918 system_diff.WriteVerifyScript(script)
919 if vendor_diff:
920 vendor_diff.WriteVerifyScript(script)
921
Geremy Condra36bd3652014-02-06 19:45:10 -0800922 script.Comment("---- start making changes here ----")
923
924 device_specific.IncrementalOTA_InstallBegin()
925
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700926 system_diff.WriteScript(script, output_zip,
927 progress=0.8 if vendor_diff else 0.9)
Tao Bao68658c02015-06-01 13:40:49 -0700928
Doug Zongkerfc44a512014-08-26 13:10:25 -0700929 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700930 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800931
932 if OPTIONS.two_step:
933 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
934 script.WriteRawImage("/boot", "boot.img")
935 print "writing full boot image (forced by two-step mode)"
936
937 if not OPTIONS.two_step:
938 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700939 if include_full_boot:
940 print "boot image changed; including full."
941 script.Print("Installing boot image...")
942 script.WriteRawImage("/boot", "boot.img")
943 else:
944 # Produce the boot image by applying a patch to the current
945 # contents of the boot partition, and write it back to the
946 # partition.
947 print "boot image changed; including patch."
948 script.Print("Patching boot image...")
949 script.ShowProgress(0.1, 10)
950 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
951 % (boot_type, boot_device,
952 source_boot.size, source_boot.sha1,
953 target_boot.size, target_boot.sha1),
954 "-",
955 target_boot.size, target_boot.sha1,
956 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800957 else:
958 print "boot image unchanged; skipping."
959
960 # Do device-specific installation (eg, write radio image).
961 device_specific.IncrementalOTA_InstallEnd()
962
963 if OPTIONS.extra_script is not None:
964 script.AppendExtra(OPTIONS.extra_script)
965
Doug Zongker922206e2014-03-04 13:16:24 -0800966 if OPTIONS.wipe_user_data:
967 script.Print("Erasing user data...")
968 script.FormatPartition("/data")
969
Geremy Condra36bd3652014-02-06 19:45:10 -0800970 if OPTIONS.two_step:
971 script.AppendExtra("""
972set_stage("%(bcb_dev)s", "");
973endif;
974endif;
975""" % bcb_dev)
976
977 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800978 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800979 WriteMetadata(metadata, output_zip)
980
Doug Zongker32b527d2014-03-04 10:03:02 -0800981
Dan Albert8b72aef2015-03-23 19:13:21 -0700982class FileDifference(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700983 def __init__(self, partition, source_zip, target_zip, output_zip):
Dan Albert8b72aef2015-03-23 19:13:21 -0700984 self.deferred_patch_list = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700985 print "Loading target..."
986 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
987 print "Loading source..."
988 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
989
990 self.verbatim_targets = verbatim_targets = []
991 self.patch_list = patch_list = []
992 diffs = []
993 self.renames = renames = {}
994 known_paths = set()
995 largest_source_size = 0
996
997 matching_file_cache = {}
998 for fn, sf in source_data.items():
999 assert fn == sf.name
1000 matching_file_cache["path:" + fn] = sf
1001 if fn in target_data.keys():
1002 AddToKnownPaths(fn, known_paths)
1003 # Only allow eligibility for filename/sha matching
1004 # if there isn't a perfect path match.
1005 if target_data.get(sf.name) is None:
1006 matching_file_cache["file:" + fn.split("/")[-1]] = sf
1007 matching_file_cache["sha:" + sf.sha1] = sf
1008
1009 for fn in sorted(target_data.keys()):
1010 tf = target_data[fn]
1011 assert fn == tf.name
1012 sf = ClosestFileMatch(tf, matching_file_cache, renames)
1013 if sf is not None and sf.name != tf.name:
1014 print "File has moved from " + sf.name + " to " + tf.name
1015 renames[sf.name] = tf
1016
1017 if sf is None or fn in OPTIONS.require_verbatim:
1018 # This file should be included verbatim
1019 if fn in OPTIONS.prohibit_verbatim:
1020 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
1021 print "send", fn, "verbatim"
1022 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001023 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001024 if fn in target_data.keys():
1025 AddToKnownPaths(fn, known_paths)
1026 elif tf.sha1 != sf.sha1:
1027 # File is different; consider sending as a patch
1028 diffs.append(common.Difference(tf, sf))
1029 else:
1030 # Target file data identical to source (may still be renamed)
1031 pass
1032
1033 common.ComputeDifferences(diffs)
1034
1035 for diff in diffs:
1036 tf, sf, d = diff.GetPatch()
1037 path = "/".join(tf.name.split("/")[:-1])
1038 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1039 path not in known_paths:
1040 # patch is almost as big as the file; don't bother patching
1041 # or a patch + rename cannot take place due to the target
1042 # directory not existing
1043 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001044 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001045 if sf.name in renames:
1046 del renames[sf.name]
1047 AddToKnownPaths(tf.name, known_paths)
1048 else:
1049 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1050 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1051 largest_source_size = max(largest_source_size, sf.size)
1052
1053 self.largest_source_size = largest_source_size
1054
1055 def EmitVerification(self, script):
1056 so_far = 0
Dan Albert8b72aef2015-03-23 19:13:21 -07001057 for tf, sf, _, _ in self.patch_list:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001058 if tf.name != sf.name:
1059 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1060 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1061 so_far += sf.size
1062 return so_far
1063
Michael Runge63f01de2014-10-28 19:24:19 -07001064 def EmitExplicitTargetVerification(self, script):
Dan Albert8b72aef2015-03-23 19:13:21 -07001065 for fn, _, sha1 in self.verbatim_targets:
1066 if fn[-1] != "/":
Michael Runge63f01de2014-10-28 19:24:19 -07001067 script.FileCheck("/"+fn, sha1)
1068 for tf, _, _, _ in self.patch_list:
1069 script.FileCheck(tf.name, tf.sha1)
1070
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001071 def RemoveUnneededFiles(self, script, extras=()):
Dan Albert8b72aef2015-03-23 19:13:21 -07001072 script.DeleteFiles(
1073 ["/" + i[0] for i in self.verbatim_targets] +
1074 ["/" + i for i in sorted(self.source_data)
1075 if i not in self.target_data and i not in self.renames] +
1076 list(extras))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001077
1078 def TotalPatchSize(self):
1079 return sum(i[1].size for i in self.patch_list)
1080
1081 def EmitPatches(self, script, total_patch_size, so_far):
1082 self.deferred_patch_list = deferred_patch_list = []
1083 for item in self.patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001084 tf, sf, _, _ = item
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001085 if tf.name == "system/build.prop":
1086 deferred_patch_list.append(item)
1087 continue
Dan Albert8b72aef2015-03-23 19:13:21 -07001088 if sf.name != tf.name:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001089 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
Dan Albert8b72aef2015-03-23 19:13:21 -07001090 script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1,
1091 "patch/" + sf.name + ".p")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001092 so_far += tf.size
1093 script.SetProgress(so_far / total_patch_size)
1094 return so_far
1095
1096 def EmitDeferredPatches(self, script):
1097 for item in self.deferred_patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001098 tf, sf, _, _ = item
1099 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1,
1100 "patch/" + sf.name + ".p")
1101 script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001102
1103 def EmitRenames(self, script):
1104 if len(self.renames) > 0:
1105 script.Print("Renaming files...")
1106 for src, tgt in self.renames.iteritems():
1107 print "Renaming " + src + " to " + tgt.name
1108 script.RenameFile(src, tgt.name)
1109
1110
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001111def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001112 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1113 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1114
Doug Zongker26e66192014-02-20 13:22:07 -08001115 if (OPTIONS.block_based and
1116 target_has_recovery_patch and
1117 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001118 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1119
Doug Zongker37974732010-09-16 17:44:38 -07001120 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1121 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001122
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001123 if source_version == 0:
1124 print ("WARNING: generating edify script for a source that "
1125 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -07001126 script = edify_generator.EdifyGenerator(
1127 source_version, OPTIONS.target_info_dict,
1128 fstab=OPTIONS.source_info_dict["fstab"])
Doug Zongkereef39442009-04-02 12:14:19 -07001129
Michael Runge6e836112014-04-15 17:40:21 -07001130 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Tao Bao34b47bf2015-06-22 19:17:41 -07001131 recovery_mount_options = OPTIONS.source_info_dict.get(
1132 "recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001133 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001134 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001135 if OPTIONS.oem_source is None:
1136 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001137 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001138 oem_dict = common.LoadDictionaryFromLines(
1139 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001140
Dan Albert8b72aef2015-03-23 19:13:21 -07001141 metadata = {
1142 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1143 OPTIONS.source_info_dict),
1144 "post-timestamp": GetBuildProp("ro.build.date.utc",
1145 OPTIONS.target_info_dict),
1146 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001147
Doug Zongker05d3dea2009-06-22 11:32:31 -07001148 device_specific = common.DeviceSpecificParams(
1149 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001150 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001151 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001152 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001153 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001154 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001155 metadata=metadata,
1156 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001157
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001158 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001159 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001160 if HasVendorPartition(target_zip):
1161 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001162 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001163 else:
1164 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001165
Dan Albert8b72aef2015-03-23 19:13:21 -07001166 target_fp = CalculateFingerprint(oem_props, oem_dict,
1167 OPTIONS.target_info_dict)
1168 source_fp = CalculateFingerprint(oem_props, oem_dict,
1169 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001170
1171 if oem_props is None:
1172 script.AssertSomeFingerprint(source_fp, target_fp)
1173 else:
1174 script.AssertSomeThumbprint(
1175 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1176 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1177
Doug Zongker2ea21062010-04-28 16:05:21 -07001178 metadata["pre-build"] = source_fp
1179 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001180
Doug Zongker55d93282011-01-25 17:03:34 -08001181 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001182 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1183 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001184 target_boot = common.GetBootableImage(
1185 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001186 updating_boot = (not OPTIONS.two_step and
1187 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001188
Doug Zongker55d93282011-01-25 17:03:34 -08001189 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001190 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1191 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001192 target_recovery = common.GetBootableImage(
1193 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001194 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001195
Doug Zongker881dd402009-09-20 14:03:55 -07001196 # Here's how we divide up the progress bar:
1197 # 0.1 for verifying the start state (PatchCheck calls)
1198 # 0.8 for applying patches (ApplyPatch calls)
1199 # 0.1 for unpacking verbatim files, symlinking, and doing the
1200 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001201
Michael Runge6e836112014-04-15 17:40:21 -07001202 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001203 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001204
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001205 # Two-step incremental package strategy (in chronological order,
1206 # which is *not* the order in which the generated script has
1207 # things):
1208 #
1209 # if stage is not "2/3" or "3/3":
1210 # do verification on current system
1211 # write recovery image to boot partition
1212 # set stage to "2/3"
1213 # reboot to boot partition and restart recovery
1214 # else if stage is "2/3":
1215 # write recovery image to recovery partition
1216 # set stage to "3/3"
1217 # reboot to recovery partition and restart recovery
1218 # else:
1219 # (stage must be "3/3")
1220 # perform update:
1221 # patch system files, etc.
1222 # force full install of new boot image
1223 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001224 # complete script normally
1225 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001226
1227 if OPTIONS.two_step:
1228 if not OPTIONS.info_dict.get("multistage_support", None):
1229 assert False, "two-step packages not supported by this build"
1230 fs = OPTIONS.info_dict["fstab"]["/misc"]
1231 assert fs.fs_type.upper() == "EMMC", \
1232 "two-step packages only supported on devices with EMMC /misc partitions"
1233 bcb_dev = {"bcb_dev": fs.device}
1234 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1235 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001236if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001237""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001238 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001239 script.WriteRawImage("/recovery", "recovery.img")
1240 script.AppendExtra("""
1241set_stage("%(bcb_dev)s", "3/3");
1242reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001243else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001244""" % bcb_dev)
1245
Tao Bao6c55a8a2015-04-08 15:30:27 -07001246 # Dump fingerprints
1247 script.Print("Source: %s" % (source_fp,))
1248 script.Print("Target: %s" % (target_fp,))
1249
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001250 script.Print("Verifying current system...")
1251
Doug Zongkere5ff5902012-01-17 10:55:37 -08001252 device_specific.IncrementalOTA_VerifyBegin()
1253
Doug Zongker881dd402009-09-20 14:03:55 -07001254 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001255 so_far = system_diff.EmitVerification(script)
1256 if vendor_diff:
1257 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001258
Doug Zongker5da317e2009-06-02 13:38:17 -07001259 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001260 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001261 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001262 print "boot target: %d source: %d diff: %d" % (
1263 target_boot.size, source_boot.size, len(d))
1264
Doug Zongker048e7ca2009-06-15 14:31:53 -07001265 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001266
Doug Zongker96a57e72010-09-26 14:57:41 -07001267 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001268
1269 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1270 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001271 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001272 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001273 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001274
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001275 size = []
Dan Albert8b72aef2015-03-23 19:13:21 -07001276 if system_diff.patch_list:
1277 size.append(system_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001278 if vendor_diff:
Dan Albert8b72aef2015-03-23 19:13:21 -07001279 if vendor_diff.patch_list:
1280 size.append(vendor_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001281 if size or updating_recovery or updating_boot:
1282 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001283
Doug Zongker05d3dea2009-06-22 11:32:31 -07001284 device_specific.IncrementalOTA_VerifyEnd()
1285
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001286 if OPTIONS.two_step:
1287 script.WriteRawImage("/boot", "recovery.img")
1288 script.AppendExtra("""
1289set_stage("%(bcb_dev)s", "2/3");
1290reboot_now("%(bcb_dev)s", "");
1291else
1292""" % bcb_dev)
1293
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001294 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001295
Doug Zongkere5ff5902012-01-17 10:55:37 -08001296 device_specific.IncrementalOTA_InstallBegin()
1297
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001298 if OPTIONS.two_step:
1299 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1300 script.WriteRawImage("/boot", "boot.img")
1301 print "writing full boot image (forced by two-step mode)"
1302
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001303 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001304 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1305 if vendor_diff:
1306 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001307
Doug Zongker881dd402009-09-20 14:03:55 -07001308 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001309 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1310 if vendor_diff:
1311 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001312 if updating_boot:
1313 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001314
1315 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001316 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1317 if vendor_diff:
1318 script.Print("Patching vendor files...")
1319 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001320
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001321 if not OPTIONS.two_step:
1322 if updating_boot:
1323 # Produce the boot image by applying a patch to the current
1324 # contents of the boot partition, and write it back to the
1325 # partition.
1326 script.Print("Patching boot image...")
1327 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1328 % (boot_type, boot_device,
1329 source_boot.size, source_boot.sha1,
1330 target_boot.size, target_boot.sha1),
1331 "-",
1332 target_boot.size, target_boot.sha1,
1333 source_boot.sha1, "patch/boot.img.p")
1334 so_far += target_boot.size
1335 script.SetProgress(so_far / total_patch_size)
1336 print "boot image changed; including."
1337 else:
1338 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001339
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001340 system_items = ItemSet("system", "META/filesystem_config.txt")
1341 if vendor_diff:
1342 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1343
Doug Zongkereef39442009-04-02 12:14:19 -07001344 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001345 # Recovery is generated as a patch using both the boot image
1346 # (which contains the same linux kernel as recovery) and the file
1347 # /system/etc/recovery-resource.dat (which contains all the images
1348 # used in the recovery UI) as sources. This lets us minimize the
1349 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001350 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001351 # For older builds where recovery-resource.dat is not present, we
1352 # use only the boot image as the source.
1353
Doug Zongkerc9253822014-02-04 12:17:58 -08001354 if not target_has_recovery_patch:
1355 def output_sink(fn, data):
1356 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001357 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001358
1359 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1360 target_recovery, target_boot)
1361 script.DeleteFiles(["/system/recovery-from-boot.p",
Tao Baof2cffbd2015-07-22 12:33:18 -07001362 "/system/etc/recovery.img",
Doug Zongkerc9253822014-02-04 12:17:58 -08001363 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001364 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001365 else:
1366 print "recovery image unchanged; skipping."
1367
Doug Zongker881dd402009-09-20 14:03:55 -07001368 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001369
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001370 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1371 if vendor_diff:
1372 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1373
1374 temp_script = script.MakeTemporary()
1375 system_items.GetMetadata(target_zip)
1376 system_items.Get("system").SetPermissions(temp_script)
1377 if vendor_diff:
1378 vendor_items.GetMetadata(target_zip)
1379 vendor_items.Get("vendor").SetPermissions(temp_script)
1380
1381 # Note that this call will mess up the trees of Items, so make sure
1382 # we're done with them.
1383 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1384 if vendor_diff:
1385 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001386
1387 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001388 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1389
1390 # Delete all the symlinks in source that aren't in target. This
1391 # needs to happen before verbatim files are unpacked, in case a
1392 # symlink in the source is replaced by a real file in the target.
1393 to_delete = []
1394 for dest, link in source_symlinks:
1395 if link not in target_symlinks_d:
1396 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001397 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001398
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001399 if system_diff.verbatim_targets:
1400 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001401 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001402 if vendor_diff and vendor_diff.verbatim_targets:
1403 script.Print("Unpacking new vendor files...")
1404 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001405
Doug Zongkerc9253822014-02-04 12:17:58 -08001406 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001407 script.Print("Unpacking new recovery...")
1408 script.UnpackPackageDir("recovery", "/system")
1409
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001410 system_diff.EmitRenames(script)
1411 if vendor_diff:
1412 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001413
Doug Zongker05d3dea2009-06-22 11:32:31 -07001414 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001415
1416 # Create all the symlinks that don't already exist, or point to
1417 # somewhere different than what we want. Delete each symlink before
1418 # creating it, since the 'symlink' command won't overwrite.
1419 to_create = []
1420 for dest, link in target_symlinks:
1421 if link in source_symlinks_d:
1422 if dest != source_symlinks_d[link]:
1423 to_create.append((dest, link))
1424 else:
1425 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001426 script.DeleteFiles([i[1] for i in to_create])
1427 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001428
1429 # Now that the symlinks are created, we can set all the
1430 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001431 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001432
Doug Zongker881dd402009-09-20 14:03:55 -07001433 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001434 device_specific.IncrementalOTA_InstallEnd()
1435
Doug Zongker1c390a22009-05-14 19:06:36 -07001436 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001437 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001438
Doug Zongkere92f15a2011-08-26 13:46:40 -07001439 # Patch the build.prop file last, so if something fails but the
1440 # device can still come up, it appears to be the old build and will
1441 # get set the OTA package again to retry.
1442 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001443 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001444
Doug Zongker922206e2014-03-04 13:16:24 -08001445 if OPTIONS.wipe_user_data:
1446 script.Print("Erasing user data...")
1447 script.FormatPartition("/data")
1448
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001449 if OPTIONS.two_step:
1450 script.AppendExtra("""
1451set_stage("%(bcb_dev)s", "");
1452endif;
1453endif;
1454""" % bcb_dev)
1455
Michael Runge63f01de2014-10-28 19:24:19 -07001456 if OPTIONS.verify and system_diff:
1457 script.Print("Remounting and verifying system partition files...")
1458 script.Unmount("/system")
1459 script.Mount("/system")
1460 system_diff.EmitExplicitTargetVerification(script)
1461
1462 if OPTIONS.verify and vendor_diff:
1463 script.Print("Remounting and verifying vendor partition files...")
1464 script.Unmount("/vendor")
1465 script.Mount("/vendor")
1466 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001467 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001468
Doug Zongker2ea21062010-04-28 16:05:21 -07001469 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001470
1471
1472def main(argv):
1473
1474 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001475 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001476 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001477 elif o in ("-k", "--package_key"):
1478 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001479 elif o in ("-i", "--incremental_from"):
1480 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001481 elif o == "--full_radio":
1482 OPTIONS.full_radio = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001483 elif o in ("-w", "--wipe_user_data"):
1484 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001485 elif o in ("-n", "--no_prereq"):
1486 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001487 elif o in ("-o", "--oem_settings"):
1488 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001489 elif o in ("-e", "--extra_script"):
1490 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001491 elif o in ("-a", "--aslr_mode"):
1492 if a in ("on", "On", "true", "True", "yes", "Yes"):
1493 OPTIONS.aslr_mode = True
1494 else:
1495 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001496 elif o in ("-t", "--worker_threads"):
1497 if a.isdigit():
1498 OPTIONS.worker_threads = int(a)
1499 else:
1500 raise ValueError("Cannot parse value %r for option %r - only "
1501 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001502 elif o in ("-2", "--two_step"):
1503 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001504 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001505 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001506 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001507 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001508 elif o == "--block":
1509 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001510 elif o in ("-b", "--binary"):
1511 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001512 elif o in ("--no_fallback_to_full",):
1513 OPTIONS.fallback_to_full = False
Tao Bao8dcf7382015-05-21 14:09:49 -07001514 elif o == "--stash_threshold":
1515 try:
1516 OPTIONS.stash_threshold = float(a)
1517 except ValueError:
1518 raise ValueError("Cannot parse value %r for option %r - expecting "
1519 "a float" % (a, o))
Doug Zongkereef39442009-04-02 12:14:19 -07001520 else:
1521 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001522 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001523
1524 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001525 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001526 extra_long_opts=[
1527 "board_config=",
1528 "package_key=",
1529 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001530 "full_radio",
Dan Albert8b72aef2015-03-23 19:13:21 -07001531 "wipe_user_data",
1532 "no_prereq",
1533 "extra_script=",
1534 "worker_threads=",
1535 "aslr_mode=",
1536 "two_step",
1537 "no_signing",
1538 "block",
1539 "binary=",
1540 "oem_settings=",
1541 "verify",
1542 "no_fallback_to_full",
Tao Bao8dcf7382015-05-21 14:09:49 -07001543 "stash_threshold=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001544 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001545
1546 if len(args) != 2:
1547 common.Usage(__doc__)
1548 sys.exit(1)
1549
Doug Zongker1c390a22009-05-14 19:06:36 -07001550 if OPTIONS.extra_script is not None:
1551 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1552
Doug Zongkereef39442009-04-02 12:14:19 -07001553 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001554 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001555
Doug Zongkereef39442009-04-02 12:14:19 -07001556 OPTIONS.target_tmp = OPTIONS.input_tmp
Tao Bao2c15d9e2015-07-09 11:51:16 -07001557 OPTIONS.info_dict = common.LoadInfoDict(input_zip, OPTIONS.target_tmp)
Kenny Roote2e9f612013-05-29 12:59:35 -07001558
Doug Zongker37974732010-09-16 17:44:38 -07001559 if OPTIONS.verbose:
1560 print "--- target info ---"
1561 common.DumpInfoDict(OPTIONS.info_dict)
1562
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001563 # If the caller explicitly specified the device-specific extensions
1564 # path via -s/--device_specific, use that. Otherwise, use
1565 # META/releasetools.py if it is present in the target target_files.
1566 # Otherwise, take the path of the file from 'tool_extensions' in the
1567 # info dict and look for that in the local filesystem, relative to
1568 # the current directory.
1569
Doug Zongker37974732010-09-16 17:44:38 -07001570 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001571 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1572 if os.path.exists(from_input):
1573 print "(using device-specific extensions from target_files)"
1574 OPTIONS.device_specific = from_input
1575 else:
1576 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1577
Doug Zongker37974732010-09-16 17:44:38 -07001578 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001579 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001580
Doug Zongker62d4f182014-08-04 16:06:43 -07001581 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001582
Doug Zongker62d4f182014-08-04 16:06:43 -07001583 if OPTIONS.no_signing:
Dan Albert8b72aef2015-03-23 19:13:21 -07001584 if os.path.exists(args[1]):
1585 os.unlink(args[1])
1586 output_zip = zipfile.ZipFile(args[1], "w",
1587 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001588 else:
1589 temp_zip_file = tempfile.NamedTemporaryFile()
1590 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1591 compression=zipfile.ZIP_DEFLATED)
1592
Tao Bao8dcf7382015-05-21 14:09:49 -07001593 cache_size = OPTIONS.info_dict.get("cache_size", None)
1594 if cache_size is None:
1595 raise RuntimeError("can't determine the cache partition size")
1596 OPTIONS.cache_size = cache_size
1597
Doug Zongker62d4f182014-08-04 16:06:43 -07001598 if OPTIONS.incremental_source is None:
1599 WriteFullOTAPackage(input_zip, output_zip)
1600 if OPTIONS.package_key is None:
1601 OPTIONS.package_key = OPTIONS.info_dict.get(
1602 "default_system_dev_certificate",
1603 "build/target/product/security/testkey")
Tao Bao2ed665a2015-04-01 11:21:55 -07001604 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001605 break
1606
1607 else:
1608 print "unzipping source target-files..."
Dan Albert8b72aef2015-03-23 19:13:21 -07001609 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
1610 OPTIONS.incremental_source)
Doug Zongker62d4f182014-08-04 16:06:43 -07001611 OPTIONS.target_info_dict = OPTIONS.info_dict
Tao Bao2c15d9e2015-07-09 11:51:16 -07001612 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip,
1613 OPTIONS.source_tmp)
Doug Zongker62d4f182014-08-04 16:06:43 -07001614 if OPTIONS.package_key is None:
1615 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1616 "default_system_dev_certificate",
1617 "build/target/product/security/testkey")
1618 if OPTIONS.verbose:
1619 print "--- source info ---"
1620 common.DumpInfoDict(OPTIONS.source_info_dict)
1621 try:
1622 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Bao2ed665a2015-04-01 11:21:55 -07001623 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001624 break
1625 except ValueError:
Dan Albert8b72aef2015-03-23 19:13:21 -07001626 if not OPTIONS.fallback_to_full:
1627 raise
Doug Zongker62d4f182014-08-04 16:06:43 -07001628 print "--- failed to build incremental; falling back to full ---"
1629 OPTIONS.incremental_source = None
Tao Bao2ed665a2015-04-01 11:21:55 -07001630 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001631
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001632 if not OPTIONS.no_signing:
1633 SignOutput(temp_zip_file.name, args[1])
1634 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001635
Doug Zongkereef39442009-04-02 12:14:19 -07001636 print "done."
1637
1638
1639if __name__ == '__main__':
1640 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001641 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001642 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001643 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07001644 print
1645 print " ERROR: %s" % (e,)
1646 print
1647 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001648 finally:
1649 common.Cleanup()