blob: 3a696757016c676309616b3456a0140d759d97c2 [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 Baod47d8e12015-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 Baod47d8e12015-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."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700146 return (info.external_attr >> 16) == 0o120777
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
150 symlink."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700151 return (info.external_attr >> 28) == 0o10
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
221 # set metadata for the files generated by this script.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700222 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700223 if i:
224 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700225 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700226 if i:
227 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700228
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700229
Dan Albert8b72aef2015-03-23 19:13:21 -0700230class Item(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700231 """Items represent the metadata (user, group, mode) of files and
232 directories in the system image."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700233 def __init__(self, itemset, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700234 self.itemset = itemset
235 self.name = name
236 self.uid = None
237 self.gid = None
238 self.mode = None
239 self.selabel = None
240 self.capabilities = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700241 self.is_dir = is_dir
242 self.descendants = None
243 self.best_subtree = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700244
245 if name:
Dan Albert8b72aef2015-03-23 19:13:21 -0700246 self.parent = itemset.Get(os.path.dirname(name), is_dir=True)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700247 self.parent.children.append(self)
248 else:
249 self.parent = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700250 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700251 self.children = []
252
253 def Dump(self, indent=0):
254 if self.uid is not None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700255 print "%s%s %d %d %o" % (
256 " " * indent, self.name, self.uid, self.gid, self.mode)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700257 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700258 print "%s%s %s %s %s" % (
259 " " * indent, self.name, self.uid, self.gid, self.mode)
260 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700261 print "%s%s" % (" "*indent, self.descendants)
262 print "%s%s" % (" "*indent, self.best_subtree)
263 for i in self.children:
264 i.Dump(indent=indent+1)
265
Doug Zongkereef39442009-04-02 12:14:19 -0700266 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700267 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
Dan Albert8b72aef2015-03-23 19:13:21 -0700268 all children and determine the best strategy for using set_perm_recursive
269 and set_perm to correctly chown/chmod all the files to their desired
Doug Zongkereef39442009-04-02 12:14:19 -0700270 values. Recursively calls itself for all descendants.
271
Dan Albert8b72aef2015-03-23 19:13:21 -0700272 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count}
273 counting up all descendants of this node. (dmode or fmode may be None.)
274 Also sets the best_subtree of each directory Item to the (uid, gid, dmode,
275 fmode, selabel, capabilities) tuple that will match the most descendants of
276 that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700277 """
278
Dan Albert8b72aef2015-03-23 19:13:21 -0700279 assert self.is_dir
280 key = (self.uid, self.gid, self.mode, None, self.selabel,
281 self.capabilities)
282 self.descendants = {key: 1}
283 d = self.descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700284 for i in self.children:
Dan Albert8b72aef2015-03-23 19:13:21 -0700285 if i.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700286 for k, v in i.CountChildMetadata().iteritems():
287 d[k] = d.get(k, 0) + v
288 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700289 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700290 d[k] = d.get(k, 0) + 1
291
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700292 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
293 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700294
295 # First, find the (uid, gid) pair that matches the most
296 # descendants.
297 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700298 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700299 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
300 ug = MostPopularKey(ug, (0, 0))
301
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700302 # Now find the dmode, fmode, selabel, and capabilities that match
303 # the most descendants with that (uid, gid), and choose those.
Dan Albert8b72aef2015-03-23 19:13:21 -0700304 best_dmode = (0, 0o755)
305 best_fmode = (0, 0o644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700306 best_selabel = (0, None)
307 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700308 for k, count in d.iteritems():
Dan Albert8b72aef2015-03-23 19:13:21 -0700309 if k[:2] != ug:
310 continue
311 if k[2] is not None and count >= best_dmode[0]:
312 best_dmode = (count, k[2])
313 if k[3] is not None and count >= best_fmode[0]:
314 best_fmode = (count, k[3])
315 if k[4] is not None and count >= best_selabel[0]:
316 best_selabel = (count, k[4])
317 if k[5] is not None and count >= best_capabilities[0]:
318 best_capabilities = (count, k[5])
319 self.best_subtree = ug + (
320 best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700321
322 return d
323
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700324 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700325 """Append set_perm/set_perm_recursive commands to 'script' to
326 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700327 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700328
329 self.CountChildMetadata()
330
331 def recurse(item, current):
Dan Albert8b72aef2015-03-23 19:13:21 -0700332 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple
333 # that the current item (and all its children) have already been set to.
334 # We only need to issue set_perm/set_perm_recursive commands if we're
Doug Zongkereef39442009-04-02 12:14:19 -0700335 # supposed to be something different.
Dan Albert8b72aef2015-03-23 19:13:21 -0700336 if item.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700337 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700338 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700339 current = item.best_subtree
340
341 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700342 item.mode != current[2] or item.selabel != current[4] or \
343 item.capabilities != current[5]:
344 script.SetPermissions("/"+item.name, item.uid, item.gid,
345 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700346
347 for i in item.children:
348 recurse(i, current)
349 else:
350 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700351 item.mode != current[3] or item.selabel != current[4] or \
352 item.capabilities != current[5]:
353 script.SetPermissions("/"+item.name, item.uid, item.gid,
354 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700355
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700356 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700357
358
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700359def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
360 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700361 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800362 list of symlinks. output_zip may be None, in which case the copy is
363 skipped (but the other side effects still happen). substitute is an
364 optional dict of {output filename: contents} to be output instead of
365 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700366 """
367
368 symlinks = []
369
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700370 partition = itemset.partition
371
Doug Zongkereef39442009-04-02 12:14:19 -0700372 for info in input_zip.infolist():
Tao Baoeaf885b2015-03-23 16:01:17 -0700373 prefix = partition.upper() + "/"
374 if info.filename.startswith(prefix):
375 basefilename = info.filename[len(prefix):]
Doug Zongkereef39442009-04-02 12:14:19 -0700376 if IsSymlink(info):
377 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700378 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700379 else:
Tao Baof3282b42015-04-01 11:21:55 -0700380 import copy
Doug Zongkereef39442009-04-02 12:14:19 -0700381 info2 = copy.copy(info)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700382 fn = info2.filename = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700383 if substitute and fn in substitute and substitute[fn] is None:
384 continue
385 if output_zip is not None:
386 if substitute and fn in substitute:
387 data = substitute[fn]
388 else:
389 data = input_zip.read(info.filename)
Tao Baof3282b42015-04-01 11:21:55 -0700390 common.ZipWriteStr(output_zip, info2, data)
Doug Zongkereef39442009-04-02 12:14:19 -0700391 if fn.endswith("/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700392 itemset.Get(fn[:-1], is_dir=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700393 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700394 itemset.Get(fn)
Doug Zongkereef39442009-04-02 12:14:19 -0700395
396 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800397 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700398
399
Doug Zongkereef39442009-04-02 12:14:19 -0700400def SignOutput(temp_zip_name, output_zip_name):
401 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
402 pw = key_passwords[OPTIONS.package_key]
403
Doug Zongker951495f2009-08-14 12:44:19 -0700404 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
405 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700406
407
Dan Albert8b72aef2015-03-23 19:13:21 -0700408def AppendAssertions(script, info_dict, oem_dict=None):
Michael Runge6e836112014-04-15 17:40:21 -0700409 oem_props = info_dict.get("oem_fingerprint_properties")
Michael Runge560569a2014-09-18 15:12:45 -0700410 if oem_props is None or len(oem_props) == 0:
Michael Runge6e836112014-04-15 17:40:21 -0700411 device = GetBuildProp("ro.product.device", info_dict)
412 script.AssertDevice(device)
413 else:
414 if oem_dict is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700415 raise common.ExternalError(
416 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700417 for prop in oem_props.split():
418 if oem_dict.get(prop) is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700419 raise common.ExternalError(
420 "The OEM file is missing the property %s" % prop)
Michael Runge6e836112014-04-15 17:40:21 -0700421 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700422
Doug Zongkereef39442009-04-02 12:14:19 -0700423
Doug Zongkerc9253822014-02-04 12:17:58 -0800424def HasRecoveryPatch(target_files_zip):
425 try:
426 target_files_zip.getinfo("SYSTEM/recovery-from-boot.p")
427 return True
428 except KeyError:
429 return False
Doug Zongker73ef8252009-07-23 15:12:53 -0700430
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700431def HasVendorPartition(target_files_zip):
432 try:
433 target_files_zip.getinfo("VENDOR/")
434 return True
435 except KeyError:
436 return False
437
Michael Runge6e836112014-04-15 17:40:21 -0700438def GetOemProperty(name, oem_props, oem_dict, info_dict):
439 if oem_props is not None and name in oem_props:
440 return oem_dict[name]
441 return GetBuildProp(name, info_dict)
442
443
444def CalculateFingerprint(oem_props, oem_dict, info_dict):
445 if oem_props is None:
446 return GetBuildProp("ro.build.fingerprint", info_dict)
447 return "%s/%s/%s:%s" % (
Dan Albert8b72aef2015-03-23 19:13:21 -0700448 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
449 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
450 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
451 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700452
Doug Zongkerfc44a512014-08-26 13:10:25 -0700453
Doug Zongker3c84f562014-07-31 11:06:30 -0700454def GetImage(which, tmpdir, info_dict):
Doug Zongkerfc44a512014-08-26 13:10:25 -0700455 # Return an image object (suitable for passing to BlockImageDiff)
456 # for the 'which' partition (most be "system" or "vendor"). If a
457 # prebuilt image and file map are found in tmpdir they are used,
458 # otherwise they are reconstructed from the individual files.
Doug Zongker3c84f562014-07-31 11:06:30 -0700459
460 assert which in ("system", "vendor")
461
462 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700463 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
464 if os.path.exists(path) and os.path.exists(mappath):
Doug Zongker3c84f562014-07-31 11:06:30 -0700465 print "using %s.img from target-files" % (which,)
Doug Zongker3c84f562014-07-31 11:06:30 -0700466 # This is a 'new' target-files, which already has the image in it.
Doug Zongker3c84f562014-07-31 11:06:30 -0700467
468 else:
469 print "building %s.img from target-files" % (which,)
470
471 # This is an 'old' target-files, which does not contain images
472 # already built. Build them.
473
Doug Zongkerfc44a512014-08-26 13:10:25 -0700474 mappath = tempfile.mkstemp()[1]
475 OPTIONS.tempfiles.append(mappath)
476
Doug Zongker3c84f562014-07-31 11:06:30 -0700477 import add_img_to_target_files
478 if which == "system":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700479 path = add_img_to_target_files.BuildSystem(
480 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700481 elif which == "vendor":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700482 path = add_img_to_target_files.BuildVendor(
483 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700484
Tao Bao5ece99d2015-05-12 11:42:31 -0700485 # Bug: http://b/20939131
486 # In ext4 filesystems, block 0 might be changed even being mounted
487 # R/O. We add it to clobbered_blocks so that it will be written to the
488 # target unconditionally. Note that they are still part of care_map.
489 clobbered_blocks = "0"
490
491 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700492
493
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700494def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700495 # TODO: how to determine this? We don't know what version it will
Tao Baobebd3cf2015-06-22 19:17:41 -0700496 # be installed on top of. For now, we expect the API just won't
497 # change very often. Similarly for fstab, it might have changed
498 # in the target build.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700499 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700500
Michael Runge6e836112014-04-15 17:40:21 -0700501 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700502 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700503 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700504 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700505 if OPTIONS.oem_source is None:
506 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700507 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700508 oem_dict = common.LoadDictionaryFromLines(
509 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -0700510
Dan Albert8b72aef2015-03-23 19:13:21 -0700511 metadata = {
512 "post-build": CalculateFingerprint(oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700513 OPTIONS.info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700514 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
515 OPTIONS.info_dict),
516 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
517 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700518
Doug Zongker05d3dea2009-06-22 11:32:31 -0700519 device_specific = common.DeviceSpecificParams(
520 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700521 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700522 output_zip=output_zip,
523 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700524 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700525 metadata=metadata,
526 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700527
Doug Zongkerc9253822014-02-04 12:17:58 -0800528 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800529 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800530
Doug Zongker962069c2009-04-23 11:41:58 -0700531 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700532 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700533 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
534 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700535
Michael Runge6e836112014-04-15 17:40:21 -0700536 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700537 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800538
539 # Two-step package strategy (in chronological order, which is *not*
540 # the order in which the generated script has things):
541 #
542 # if stage is not "2/3" or "3/3":
543 # write recovery image to boot partition
544 # set stage to "2/3"
545 # reboot to boot partition and restart recovery
546 # else if stage is "2/3":
547 # write recovery image to recovery partition
548 # set stage to "3/3"
549 # reboot to recovery partition and restart recovery
550 # else:
551 # (stage must be "3/3")
552 # set stage to ""
553 # do normal full package installation:
554 # wipe and install system, boot image, etc.
555 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700556 # complete script normally
557 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800558
559 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
560 OPTIONS.input_tmp, "RECOVERY")
561 if OPTIONS.two_step:
562 if not OPTIONS.info_dict.get("multistage_support", None):
563 assert False, "two-step packages not supported by this build"
564 fs = OPTIONS.info_dict["fstab"]["/misc"]
565 assert fs.fs_type.upper() == "EMMC", \
566 "two-step packages only supported on devices with EMMC /misc partitions"
567 bcb_dev = {"bcb_dev": fs.device}
568 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
569 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700570if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800571""" % bcb_dev)
572 script.WriteRawImage("/recovery", "recovery.img")
573 script.AppendExtra("""
574set_stage("%(bcb_dev)s", "3/3");
575reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700576else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800577""" % bcb_dev)
578
Tao Bao6c55a8a2015-04-08 15:30:27 -0700579 # Dump fingerprints
580 script.Print("Target: %s" % CalculateFingerprint(
581 oem_props, oem_dict, OPTIONS.info_dict))
582
Doug Zongkere5ff5902012-01-17 10:55:37 -0800583 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700584
Doug Zongker01ce19c2014-02-04 13:48:15 -0800585 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700586
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700587 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800588 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700589 if HasVendorPartition(input_zip):
590 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700591
Kenny Rootf32dc712012-04-08 10:42:34 -0700592 if "selinux_fc" in OPTIONS.info_dict:
593 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500594
Michael Runge7cd99ba2014-10-22 17:21:48 -0700595 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
596
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700597 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700598 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800599
Doug Zongker26e66192014-02-20 13:22:07 -0800600 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700601 # Full OTA is done as an "incremental" against an empty source
602 # image. This has the effect of writing new data from the package
603 # to the entire partition, but lets us reuse the updater code that
604 # writes incrementals to do it.
605 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
606 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700607 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700608 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800609 else:
610 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700611 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800612 if not has_recovery_patch:
613 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800614 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700615
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700616 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800617 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700618
Doug Zongker55d93282011-01-25 17:03:34 -0800619 boot_img = common.GetBootableImage("boot.img", "boot.img",
620 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800621
Doug Zongker91a99c22014-05-09 13:15:01 -0700622 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800623 def output_sink(fn, data):
624 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700625 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800626
627 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
628 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700629
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700630 system_items.GetMetadata(input_zip)
631 system_items.Get("system").SetPermissions(script)
632
633 if HasVendorPartition(input_zip):
634 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
635 script.ShowProgress(0.1, 0)
636
637 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700638 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
639 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700640 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700641 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700642 else:
643 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700644 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700645 script.UnpackPackageDir("vendor", "/vendor")
646
647 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
648 script.MakeSymlinks(symlinks)
649
650 vendor_items.GetMetadata(input_zip)
651 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700652
Doug Zongker37974732010-09-16 17:44:38 -0700653 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700654 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700655
Doug Zongker01ce19c2014-02-04 13:48:15 -0800656 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700657 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700658
Doug Zongker01ce19c2014-02-04 13:48:15 -0800659 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700660 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700661
Doug Zongker1c390a22009-05-14 19:06:36 -0700662 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700663 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700664
Doug Zongker14833602010-02-02 13:12:04 -0800665 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800666
Doug Zongker922206e2014-03-04 13:16:24 -0800667 if OPTIONS.wipe_user_data:
668 script.ShowProgress(0.1, 10)
669 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700670
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800671 if OPTIONS.two_step:
672 script.AppendExtra("""
673set_stage("%(bcb_dev)s", "");
674""" % bcb_dev)
675 script.AppendExtra("else\n")
676 script.WriteRawImage("/boot", "recovery.img")
677 script.AppendExtra("""
678set_stage("%(bcb_dev)s", "2/3");
679reboot_now("%(bcb_dev)s", "");
680endif;
681endif;
682""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800683 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700684 WriteMetadata(metadata, output_zip)
685
Doug Zongkerfc44a512014-08-26 13:10:25 -0700686
Dan Albert8e0178d2015-01-27 15:53:15 -0800687def WritePolicyConfig(file_name, output_zip):
688 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500689
Doug Zongker2ea21062010-04-28 16:05:21 -0700690
691def WriteMetadata(metadata, output_zip):
692 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
693 "".join(["%s=%s\n" % kv
694 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700695
Doug Zongkerfc44a512014-08-26 13:10:25 -0700696
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700697def LoadPartitionFiles(z, partition):
698 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700699 ZipFile, and return a dict of {filename: File object}."""
700 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700701 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700702 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700703 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700704 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700705 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700706 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700707 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800708 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700709
710
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700711def GetBuildProp(prop, info_dict):
712 """Return the fingerprint of the build of a given target-files info_dict."""
713 try:
714 return info_dict.get("build.prop", {})[prop]
715 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700716 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700717
Doug Zongkerfc44a512014-08-26 13:10:25 -0700718
Michael Runge4038aa82013-12-13 18:06:28 -0800719def AddToKnownPaths(filename, known_paths):
720 if filename[-1] == "/":
721 return
722 dirs = filename.split("/")[:-1]
723 while len(dirs) > 0:
724 path = "/".join(dirs)
725 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700726 break
Michael Runge4038aa82013-12-13 18:06:28 -0800727 known_paths.add(path)
728 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700729
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700730
Geremy Condra36bd3652014-02-06 19:45:10 -0800731def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
732 source_version = OPTIONS.source_info_dict["recovery_api_version"]
733 target_version = OPTIONS.target_info_dict["recovery_api_version"]
734
735 if source_version == 0:
736 print ("WARNING: generating edify script for a source that "
737 "can't install it.")
Tao Baobebd3cf2015-06-22 19:17:41 -0700738 script = edify_generator.EdifyGenerator(
739 source_version, OPTIONS.target_info_dict,
740 fstab=OPTIONS.source_info_dict["fstab"])
Geremy Condra36bd3652014-02-06 19:45:10 -0800741
Dan Albert8b72aef2015-03-23 19:13:21 -0700742 metadata = {
743 "pre-device": GetBuildProp("ro.product.device",
744 OPTIONS.source_info_dict),
745 "post-timestamp": GetBuildProp("ro.build.date.utc",
746 OPTIONS.target_info_dict),
747 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800748
749 device_specific = common.DeviceSpecificParams(
750 source_zip=source_zip,
751 source_version=source_version,
752 target_zip=target_zip,
753 target_version=target_version,
754 output_zip=output_zip,
755 script=script,
756 metadata=metadata,
757 info_dict=OPTIONS.info_dict)
758
Tao Bao6c55a8a2015-04-08 15:30:27 -0700759 # TODO: Currently this works differently from WriteIncrementalOTAPackage().
760 # This function doesn't consider thumbprints when writing
761 # metadata["pre/post-build"]. One possible reason is that the current
762 # devices with thumbprints are all using file-based OTAs. Long term we
763 # should factor out the common parts into a shared one to avoid further
764 # divergence.
Geremy Condra36bd3652014-02-06 19:45:10 -0800765 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
766 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
767 metadata["pre-build"] = source_fp
768 metadata["post-build"] = target_fp
769
770 source_boot = common.GetBootableImage(
771 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
772 OPTIONS.source_info_dict)
773 target_boot = common.GetBootableImage(
774 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
775 updating_boot = (not OPTIONS.two_step and
776 (source_boot.data != target_boot.data))
777
Geremy Condra36bd3652014-02-06 19:45:10 -0800778 target_recovery = common.GetBootableImage(
779 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800780
Doug Zongkerfc44a512014-08-26 13:10:25 -0700781 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
782 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700783
784 blockimgdiff_version = 1
785 if OPTIONS.info_dict:
786 blockimgdiff_version = max(
787 int(i) for i in
788 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
789
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700790 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700791 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700792
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700793 if HasVendorPartition(target_zip):
794 if not HasVendorPartition(source_zip):
795 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700796 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
797 OPTIONS.source_info_dict)
798 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
799 OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700800 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700801 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700802 else:
803 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800804
Michael Rungec6e3afd2014-05-05 11:55:47 -0700805 oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
Tao Baobebd3cf2015-06-22 19:17:41 -0700806 recovery_mount_options = OPTIONS.source_info_dict.get(
Dan Albert8b72aef2015-03-23 19:13:21 -0700807 "recovery_mount_options")
Michael Rungec6e3afd2014-05-05 11:55:47 -0700808 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700809 if oem_props is not None and len(oem_props) > 0:
Michael Rungec6e3afd2014-05-05 11:55:47 -0700810 if OPTIONS.oem_source is None:
811 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700812 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700813 oem_dict = common.LoadDictionaryFromLines(
814 open(OPTIONS.oem_source).readlines())
Michael Rungec6e3afd2014-05-05 11:55:47 -0700815
816 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800817 device_specific.IncrementalOTA_Assertions()
818
819 # Two-step incremental package strategy (in chronological order,
820 # which is *not* the order in which the generated script has
821 # things):
822 #
823 # if stage is not "2/3" or "3/3":
824 # do verification on current system
825 # write recovery image to boot partition
826 # set stage to "2/3"
827 # reboot to boot partition and restart recovery
828 # else if stage is "2/3":
829 # write recovery image to recovery partition
830 # set stage to "3/3"
831 # reboot to recovery partition and restart recovery
832 # else:
833 # (stage must be "3/3")
834 # perform update:
835 # patch system files, etc.
836 # force full install of new boot image
837 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700838 # complete script normally
839 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800840
841 if OPTIONS.two_step:
Tao Baocce673b2015-07-29 14:09:23 -0700842 if not OPTIONS.source_info_dict.get("multistage_support", None):
Geremy Condra36bd3652014-02-06 19:45:10 -0800843 assert False, "two-step packages not supported by this build"
Tao Baocce673b2015-07-29 14:09:23 -0700844 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Geremy Condra36bd3652014-02-06 19:45:10 -0800845 assert fs.fs_type.upper() == "EMMC", \
846 "two-step packages only supported on devices with EMMC /misc partitions"
847 bcb_dev = {"bcb_dev": fs.device}
848 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
849 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700850if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800851""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -0700852 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800853 script.WriteRawImage("/recovery", "recovery.img")
854 script.AppendExtra("""
855set_stage("%(bcb_dev)s", "3/3");
856reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700857else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800858""" % bcb_dev)
859
Tao Bao6c55a8a2015-04-08 15:30:27 -0700860 # Dump fingerprints
861 script.Print("Source: %s" % CalculateFingerprint(
862 oem_props, oem_dict, OPTIONS.source_info_dict))
863 script.Print("Target: %s" % CalculateFingerprint(
864 oem_props, oem_dict, OPTIONS.target_info_dict))
865
Geremy Condra36bd3652014-02-06 19:45:10 -0800866 script.Print("Verifying current system...")
867
868 device_specific.IncrementalOTA_VerifyBegin()
869
Michael Rungec6e3afd2014-05-05 11:55:47 -0700870 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700871 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
872 # patching on a device that's already on the target build will damage the
873 # system. Because operations like move don't check the block state, they
874 # always apply the changes unconditionally.
875 if blockimgdiff_version <= 2:
876 script.AssertSomeFingerprint(source_fp)
877 else:
878 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700879 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700880 if blockimgdiff_version <= 2:
881 script.AssertSomeThumbprint(
882 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
883 else:
884 script.AssertSomeThumbprint(
885 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
886 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800887
888 if updating_boot:
Tao Baocce673b2015-07-29 14:09:23 -0700889 boot_type, boot_device = common.GetTypeAndDevice(
890 "/boot", OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800891 d = common.Difference(target_boot, source_boot)
892 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700893 if d is None:
894 include_full_boot = True
895 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
896 else:
897 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800898
Doug Zongkerf8340082014-08-05 10:39:37 -0700899 print "boot target: %d source: %d diff: %d" % (
900 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800901
Doug Zongkerf8340082014-08-05 10:39:37 -0700902 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800903
Doug Zongkerf8340082014-08-05 10:39:37 -0700904 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
905 (boot_type, boot_device,
906 source_boot.size, source_boot.sha1,
907 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800908
909 device_specific.IncrementalOTA_VerifyEnd()
910
911 if OPTIONS.two_step:
912 script.WriteRawImage("/boot", "recovery.img")
913 script.AppendExtra("""
914set_stage("%(bcb_dev)s", "2/3");
915reboot_now("%(bcb_dev)s", "");
916else
917""" % bcb_dev)
918
Jesse Zhao75bcea02015-01-06 10:59:53 -0800919 # Verify the existing partitions.
920 system_diff.WriteVerifyScript(script)
921 if vendor_diff:
922 vendor_diff.WriteVerifyScript(script)
923
Geremy Condra36bd3652014-02-06 19:45:10 -0800924 script.Comment("---- start making changes here ----")
925
926 device_specific.IncrementalOTA_InstallBegin()
927
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700928 system_diff.WriteScript(script, output_zip,
929 progress=0.8 if vendor_diff else 0.9)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700930 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700931 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800932
933 if OPTIONS.two_step:
934 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
935 script.WriteRawImage("/boot", "boot.img")
936 print "writing full boot image (forced by two-step mode)"
937
938 if not OPTIONS.two_step:
939 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700940 if include_full_boot:
941 print "boot image changed; including full."
942 script.Print("Installing boot image...")
943 script.WriteRawImage("/boot", "boot.img")
944 else:
945 # Produce the boot image by applying a patch to the current
946 # contents of the boot partition, and write it back to the
947 # partition.
948 print "boot image changed; including patch."
949 script.Print("Patching boot image...")
950 script.ShowProgress(0.1, 10)
951 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
952 % (boot_type, boot_device,
953 source_boot.size, source_boot.sha1,
954 target_boot.size, target_boot.sha1),
955 "-",
956 target_boot.size, target_boot.sha1,
957 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800958 else:
959 print "boot image unchanged; skipping."
960
961 # Do device-specific installation (eg, write radio image).
962 device_specific.IncrementalOTA_InstallEnd()
963
964 if OPTIONS.extra_script is not None:
965 script.AppendExtra(OPTIONS.extra_script)
966
Doug Zongker922206e2014-03-04 13:16:24 -0800967 if OPTIONS.wipe_user_data:
968 script.Print("Erasing user data...")
969 script.FormatPartition("/data")
970
Geremy Condra36bd3652014-02-06 19:45:10 -0800971 if OPTIONS.two_step:
972 script.AppendExtra("""
973set_stage("%(bcb_dev)s", "");
974endif;
975endif;
976""" % bcb_dev)
977
978 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800979 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800980 WriteMetadata(metadata, output_zip)
981
Doug Zongker32b527d2014-03-04 10:03:02 -0800982
Dan Albert8b72aef2015-03-23 19:13:21 -0700983class FileDifference(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700984 def __init__(self, partition, source_zip, target_zip, output_zip):
Dan Albert8b72aef2015-03-23 19:13:21 -0700985 self.deferred_patch_list = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700986 print "Loading target..."
987 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
988 print "Loading source..."
989 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
990
991 self.verbatim_targets = verbatim_targets = []
992 self.patch_list = patch_list = []
993 diffs = []
994 self.renames = renames = {}
995 known_paths = set()
996 largest_source_size = 0
997
998 matching_file_cache = {}
999 for fn, sf in source_data.items():
1000 assert fn == sf.name
1001 matching_file_cache["path:" + fn] = sf
1002 if fn in target_data.keys():
1003 AddToKnownPaths(fn, known_paths)
1004 # Only allow eligibility for filename/sha matching
1005 # if there isn't a perfect path match.
1006 if target_data.get(sf.name) is None:
1007 matching_file_cache["file:" + fn.split("/")[-1]] = sf
1008 matching_file_cache["sha:" + sf.sha1] = sf
1009
1010 for fn in sorted(target_data.keys()):
1011 tf = target_data[fn]
1012 assert fn == tf.name
1013 sf = ClosestFileMatch(tf, matching_file_cache, renames)
1014 if sf is not None and sf.name != tf.name:
1015 print "File has moved from " + sf.name + " to " + tf.name
1016 renames[sf.name] = tf
1017
1018 if sf is None or fn in OPTIONS.require_verbatim:
1019 # This file should be included verbatim
1020 if fn in OPTIONS.prohibit_verbatim:
1021 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
1022 print "send", fn, "verbatim"
1023 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001024 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001025 if fn in target_data.keys():
1026 AddToKnownPaths(fn, known_paths)
1027 elif tf.sha1 != sf.sha1:
1028 # File is different; consider sending as a patch
1029 diffs.append(common.Difference(tf, sf))
1030 else:
1031 # Target file data identical to source (may still be renamed)
1032 pass
1033
1034 common.ComputeDifferences(diffs)
1035
1036 for diff in diffs:
1037 tf, sf, d = diff.GetPatch()
1038 path = "/".join(tf.name.split("/")[:-1])
1039 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1040 path not in known_paths:
1041 # patch is almost as big as the file; don't bother patching
1042 # or a patch + rename cannot take place due to the target
1043 # directory not existing
1044 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001045 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001046 if sf.name in renames:
1047 del renames[sf.name]
1048 AddToKnownPaths(tf.name, known_paths)
1049 else:
1050 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1051 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1052 largest_source_size = max(largest_source_size, sf.size)
1053
1054 self.largest_source_size = largest_source_size
1055
1056 def EmitVerification(self, script):
1057 so_far = 0
Dan Albert8b72aef2015-03-23 19:13:21 -07001058 for tf, sf, _, _ in self.patch_list:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001059 if tf.name != sf.name:
1060 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1061 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1062 so_far += sf.size
1063 return so_far
1064
Michael Runge63f01de2014-10-28 19:24:19 -07001065 def EmitExplicitTargetVerification(self, script):
Dan Albert8b72aef2015-03-23 19:13:21 -07001066 for fn, _, sha1 in self.verbatim_targets:
1067 if fn[-1] != "/":
Michael Runge63f01de2014-10-28 19:24:19 -07001068 script.FileCheck("/"+fn, sha1)
1069 for tf, _, _, _ in self.patch_list:
1070 script.FileCheck(tf.name, tf.sha1)
1071
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001072 def RemoveUnneededFiles(self, script, extras=()):
Dan Albert8b72aef2015-03-23 19:13:21 -07001073 script.DeleteFiles(
1074 ["/" + i[0] for i in self.verbatim_targets] +
1075 ["/" + i for i in sorted(self.source_data)
1076 if i not in self.target_data and i not in self.renames] +
1077 list(extras))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001078
1079 def TotalPatchSize(self):
1080 return sum(i[1].size for i in self.patch_list)
1081
1082 def EmitPatches(self, script, total_patch_size, so_far):
1083 self.deferred_patch_list = deferred_patch_list = []
1084 for item in self.patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001085 tf, sf, _, _ = item
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001086 if tf.name == "system/build.prop":
1087 deferred_patch_list.append(item)
1088 continue
Dan Albert8b72aef2015-03-23 19:13:21 -07001089 if sf.name != tf.name:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001090 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
Dan Albert8b72aef2015-03-23 19:13:21 -07001091 script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1,
1092 "patch/" + sf.name + ".p")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001093 so_far += tf.size
1094 script.SetProgress(so_far / total_patch_size)
1095 return so_far
1096
1097 def EmitDeferredPatches(self, script):
1098 for item in self.deferred_patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001099 tf, sf, _, _ = item
1100 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1,
1101 "patch/" + sf.name + ".p")
1102 script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001103
1104 def EmitRenames(self, script):
1105 if len(self.renames) > 0:
1106 script.Print("Renaming files...")
1107 for src, tgt in self.renames.iteritems():
1108 print "Renaming " + src + " to " + tgt.name
1109 script.RenameFile(src, tgt.name)
1110
1111
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001112def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001113 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1114 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1115
Doug Zongker26e66192014-02-20 13:22:07 -08001116 if (OPTIONS.block_based and
1117 target_has_recovery_patch and
1118 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001119 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1120
Doug Zongker37974732010-09-16 17:44:38 -07001121 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1122 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001123
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001124 if source_version == 0:
1125 print ("WARNING: generating edify script for a source that "
1126 "can't install it.")
Tao Baobebd3cf2015-06-22 19:17:41 -07001127 script = edify_generator.EdifyGenerator(
1128 source_version, OPTIONS.target_info_dict,
1129 fstab=OPTIONS.source_info_dict["fstab"])
Doug Zongkereef39442009-04-02 12:14:19 -07001130
Michael Runge6e836112014-04-15 17:40:21 -07001131 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Tao Baobebd3cf2015-06-22 19:17:41 -07001132 recovery_mount_options = OPTIONS.source_info_dict.get(
1133 "recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001134 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001135 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001136 if OPTIONS.oem_source is None:
1137 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001138 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001139 oem_dict = common.LoadDictionaryFromLines(
1140 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001141
Dan Albert8b72aef2015-03-23 19:13:21 -07001142 metadata = {
1143 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1144 OPTIONS.source_info_dict),
1145 "post-timestamp": GetBuildProp("ro.build.date.utc",
1146 OPTIONS.target_info_dict),
1147 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001148
Doug Zongker05d3dea2009-06-22 11:32:31 -07001149 device_specific = common.DeviceSpecificParams(
1150 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001151 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001152 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001153 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001154 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001155 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001156 metadata=metadata,
1157 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001158
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001159 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001160 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001161 if HasVendorPartition(target_zip):
1162 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001163 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001164 else:
1165 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001166
Dan Albert8b72aef2015-03-23 19:13:21 -07001167 target_fp = CalculateFingerprint(oem_props, oem_dict,
1168 OPTIONS.target_info_dict)
1169 source_fp = CalculateFingerprint(oem_props, oem_dict,
1170 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001171
1172 if oem_props is None:
1173 script.AssertSomeFingerprint(source_fp, target_fp)
1174 else:
1175 script.AssertSomeThumbprint(
1176 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1177 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1178
Doug Zongker2ea21062010-04-28 16:05:21 -07001179 metadata["pre-build"] = source_fp
1180 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001181
Doug Zongker55d93282011-01-25 17:03:34 -08001182 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001183 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1184 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001185 target_boot = common.GetBootableImage(
1186 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001187 updating_boot = (not OPTIONS.two_step and
1188 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001189
Doug Zongker55d93282011-01-25 17:03:34 -08001190 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001191 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1192 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001193 target_recovery = common.GetBootableImage(
1194 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001195 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001196
Doug Zongker881dd402009-09-20 14:03:55 -07001197 # Here's how we divide up the progress bar:
1198 # 0.1 for verifying the start state (PatchCheck calls)
1199 # 0.8 for applying patches (ApplyPatch calls)
1200 # 0.1 for unpacking verbatim files, symlinking, and doing the
1201 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001202
Michael Runge6e836112014-04-15 17:40:21 -07001203 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001204 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001205
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001206 # Two-step incremental package strategy (in chronological order,
1207 # which is *not* the order in which the generated script has
1208 # things):
1209 #
1210 # if stage is not "2/3" or "3/3":
1211 # do verification on current system
1212 # write recovery image to boot partition
1213 # set stage to "2/3"
1214 # reboot to boot partition and restart recovery
1215 # else if stage is "2/3":
1216 # write recovery image to recovery partition
1217 # set stage to "3/3"
1218 # reboot to recovery partition and restart recovery
1219 # else:
1220 # (stage must be "3/3")
1221 # perform update:
1222 # patch system files, etc.
1223 # force full install of new boot image
1224 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001225 # complete script normally
1226 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001227
1228 if OPTIONS.two_step:
Tao Baocce673b2015-07-29 14:09:23 -07001229 if not OPTIONS.source_info_dict.get("multistage_support", None):
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001230 assert False, "two-step packages not supported by this build"
Tao Baocce673b2015-07-29 14:09:23 -07001231 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001232 assert fs.fs_type.upper() == "EMMC", \
1233 "two-step packages only supported on devices with EMMC /misc partitions"
1234 bcb_dev = {"bcb_dev": fs.device}
1235 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1236 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001237if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001238""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001239 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001240 script.WriteRawImage("/recovery", "recovery.img")
1241 script.AppendExtra("""
1242set_stage("%(bcb_dev)s", "3/3");
1243reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001244else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001245""" % bcb_dev)
1246
Tao Bao6c55a8a2015-04-08 15:30:27 -07001247 # Dump fingerprints
1248 script.Print("Source: %s" % (source_fp,))
1249 script.Print("Target: %s" % (target_fp,))
1250
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001251 script.Print("Verifying current system...")
1252
Doug Zongkere5ff5902012-01-17 10:55:37 -08001253 device_specific.IncrementalOTA_VerifyBegin()
1254
Doug Zongker881dd402009-09-20 14:03:55 -07001255 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001256 so_far = system_diff.EmitVerification(script)
1257 if vendor_diff:
1258 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001259
Doug Zongker5da317e2009-06-02 13:38:17 -07001260 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001261 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001262 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001263 print "boot target: %d source: %d diff: %d" % (
1264 target_boot.size, source_boot.size, len(d))
1265
Doug Zongker048e7ca2009-06-15 14:31:53 -07001266 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001267
Tao Baocce673b2015-07-29 14:09:23 -07001268 boot_type, boot_device = common.GetTypeAndDevice(
1269 "/boot", OPTIONS.source_info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001270
1271 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1272 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001273 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001274 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001275 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001276
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001277 size = []
Dan Albert8b72aef2015-03-23 19:13:21 -07001278 if system_diff.patch_list:
1279 size.append(system_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001280 if vendor_diff:
Dan Albert8b72aef2015-03-23 19:13:21 -07001281 if vendor_diff.patch_list:
1282 size.append(vendor_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001283 if size or updating_recovery or updating_boot:
1284 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001285
Doug Zongker05d3dea2009-06-22 11:32:31 -07001286 device_specific.IncrementalOTA_VerifyEnd()
1287
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001288 if OPTIONS.two_step:
1289 script.WriteRawImage("/boot", "recovery.img")
1290 script.AppendExtra("""
1291set_stage("%(bcb_dev)s", "2/3");
1292reboot_now("%(bcb_dev)s", "");
1293else
1294""" % bcb_dev)
1295
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001296 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001297
Doug Zongkere5ff5902012-01-17 10:55:37 -08001298 device_specific.IncrementalOTA_InstallBegin()
1299
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001300 if OPTIONS.two_step:
1301 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1302 script.WriteRawImage("/boot", "boot.img")
1303 print "writing full boot image (forced by two-step mode)"
1304
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001305 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001306 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1307 if vendor_diff:
1308 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001309
Doug Zongker881dd402009-09-20 14:03:55 -07001310 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001311 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1312 if vendor_diff:
1313 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001314 if updating_boot:
1315 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001316
1317 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001318 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1319 if vendor_diff:
1320 script.Print("Patching vendor files...")
1321 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001322
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001323 if not OPTIONS.two_step:
1324 if updating_boot:
1325 # Produce the boot image by applying a patch to the current
1326 # contents of the boot partition, and write it back to the
1327 # partition.
1328 script.Print("Patching boot image...")
1329 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1330 % (boot_type, boot_device,
1331 source_boot.size, source_boot.sha1,
1332 target_boot.size, target_boot.sha1),
1333 "-",
1334 target_boot.size, target_boot.sha1,
1335 source_boot.sha1, "patch/boot.img.p")
1336 so_far += target_boot.size
1337 script.SetProgress(so_far / total_patch_size)
1338 print "boot image changed; including."
1339 else:
1340 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001341
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001342 system_items = ItemSet("system", "META/filesystem_config.txt")
1343 if vendor_diff:
1344 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1345
Doug Zongkereef39442009-04-02 12:14:19 -07001346 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001347 # Recovery is generated as a patch using both the boot image
1348 # (which contains the same linux kernel as recovery) and the file
1349 # /system/etc/recovery-resource.dat (which contains all the images
1350 # used in the recovery UI) as sources. This lets us minimize the
1351 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001352 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001353 # For older builds where recovery-resource.dat is not present, we
1354 # use only the boot image as the source.
1355
Doug Zongkerc9253822014-02-04 12:17:58 -08001356 if not target_has_recovery_patch:
1357 def output_sink(fn, data):
1358 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001359 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001360
1361 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1362 target_recovery, target_boot)
1363 script.DeleteFiles(["/system/recovery-from-boot.p",
1364 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001365 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001366 else:
1367 print "recovery image unchanged; skipping."
1368
Doug Zongker881dd402009-09-20 14:03:55 -07001369 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001370
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001371 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1372 if vendor_diff:
1373 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1374
1375 temp_script = script.MakeTemporary()
1376 system_items.GetMetadata(target_zip)
1377 system_items.Get("system").SetPermissions(temp_script)
1378 if vendor_diff:
1379 vendor_items.GetMetadata(target_zip)
1380 vendor_items.Get("vendor").SetPermissions(temp_script)
1381
1382 # Note that this call will mess up the trees of Items, so make sure
1383 # we're done with them.
1384 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1385 if vendor_diff:
1386 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001387
1388 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001389 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1390
1391 # Delete all the symlinks in source that aren't in target. This
1392 # needs to happen before verbatim files are unpacked, in case a
1393 # symlink in the source is replaced by a real file in the target.
1394 to_delete = []
1395 for dest, link in source_symlinks:
1396 if link not in target_symlinks_d:
1397 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001398 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001399
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001400 if system_diff.verbatim_targets:
1401 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001402 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001403 if vendor_diff and vendor_diff.verbatim_targets:
1404 script.Print("Unpacking new vendor files...")
1405 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001406
Doug Zongkerc9253822014-02-04 12:17:58 -08001407 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001408 script.Print("Unpacking new recovery...")
1409 script.UnpackPackageDir("recovery", "/system")
1410
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001411 system_diff.EmitRenames(script)
1412 if vendor_diff:
1413 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001414
Doug Zongker05d3dea2009-06-22 11:32:31 -07001415 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001416
1417 # Create all the symlinks that don't already exist, or point to
1418 # somewhere different than what we want. Delete each symlink before
1419 # creating it, since the 'symlink' command won't overwrite.
1420 to_create = []
1421 for dest, link in target_symlinks:
1422 if link in source_symlinks_d:
1423 if dest != source_symlinks_d[link]:
1424 to_create.append((dest, link))
1425 else:
1426 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001427 script.DeleteFiles([i[1] for i in to_create])
1428 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001429
1430 # Now that the symlinks are created, we can set all the
1431 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001432 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001433
Doug Zongker881dd402009-09-20 14:03:55 -07001434 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001435 device_specific.IncrementalOTA_InstallEnd()
1436
Doug Zongker1c390a22009-05-14 19:06:36 -07001437 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001438 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001439
Doug Zongkere92f15a2011-08-26 13:46:40 -07001440 # Patch the build.prop file last, so if something fails but the
1441 # device can still come up, it appears to be the old build and will
1442 # get set the OTA package again to retry.
1443 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001444 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001445
Doug Zongker922206e2014-03-04 13:16:24 -08001446 if OPTIONS.wipe_user_data:
1447 script.Print("Erasing user data...")
1448 script.FormatPartition("/data")
1449
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001450 if OPTIONS.two_step:
1451 script.AppendExtra("""
1452set_stage("%(bcb_dev)s", "");
1453endif;
1454endif;
1455""" % bcb_dev)
1456
Michael Runge63f01de2014-10-28 19:24:19 -07001457 if OPTIONS.verify and system_diff:
1458 script.Print("Remounting and verifying system partition files...")
1459 script.Unmount("/system")
1460 script.Mount("/system")
1461 system_diff.EmitExplicitTargetVerification(script)
1462
1463 if OPTIONS.verify and vendor_diff:
1464 script.Print("Remounting and verifying vendor partition files...")
1465 script.Unmount("/vendor")
1466 script.Mount("/vendor")
1467 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001468 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001469
Doug Zongker2ea21062010-04-28 16:05:21 -07001470 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001471
1472
1473def main(argv):
1474
1475 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001476 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001477 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001478 elif o in ("-k", "--package_key"):
1479 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001480 elif o in ("-i", "--incremental_from"):
1481 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001482 elif o == "--full_radio":
1483 OPTIONS.full_radio = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001484 elif o in ("-w", "--wipe_user_data"):
1485 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001486 elif o in ("-n", "--no_prereq"):
1487 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001488 elif o in ("-o", "--oem_settings"):
1489 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001490 elif o in ("-e", "--extra_script"):
1491 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001492 elif o in ("-a", "--aslr_mode"):
1493 if a in ("on", "On", "true", "True", "yes", "Yes"):
1494 OPTIONS.aslr_mode = True
1495 else:
1496 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001497 elif o in ("-t", "--worker_threads"):
1498 if a.isdigit():
1499 OPTIONS.worker_threads = int(a)
1500 else:
1501 raise ValueError("Cannot parse value %r for option %r - only "
1502 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001503 elif o in ("-2", "--two_step"):
1504 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001505 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001506 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001507 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001508 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001509 elif o == "--block":
1510 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001511 elif o in ("-b", "--binary"):
1512 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001513 elif o in ("--no_fallback_to_full",):
1514 OPTIONS.fallback_to_full = False
Tao Baod47d8e12015-05-21 14:09:49 -07001515 elif o == "--stash_threshold":
1516 try:
1517 OPTIONS.stash_threshold = float(a)
1518 except ValueError:
1519 raise ValueError("Cannot parse value %r for option %r - expecting "
1520 "a float" % (a, o))
Doug Zongkereef39442009-04-02 12:14:19 -07001521 else:
1522 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001523 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001524
1525 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001526 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001527 extra_long_opts=[
1528 "board_config=",
1529 "package_key=",
1530 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001531 "full_radio",
Dan Albert8b72aef2015-03-23 19:13:21 -07001532 "wipe_user_data",
1533 "no_prereq",
1534 "extra_script=",
1535 "worker_threads=",
1536 "aslr_mode=",
1537 "two_step",
1538 "no_signing",
1539 "block",
1540 "binary=",
1541 "oem_settings=",
1542 "verify",
1543 "no_fallback_to_full",
Tao Baod47d8e12015-05-21 14:09:49 -07001544 "stash_threshold=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001545 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001546
1547 if len(args) != 2:
1548 common.Usage(__doc__)
1549 sys.exit(1)
1550
Doug Zongker1c390a22009-05-14 19:06:36 -07001551 if OPTIONS.extra_script is not None:
1552 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1553
Doug Zongkereef39442009-04-02 12:14:19 -07001554 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001555 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001556
Doug Zongkereef39442009-04-02 12:14:19 -07001557 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001558 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001559
1560 # If this image was originally labelled with SELinux contexts, make sure we
1561 # also apply the labels in our new image. During building, the "file_contexts"
1562 # is in the out/ directory tree, but for repacking from target-files.zip it's
1563 # in the root directory of the ramdisk.
1564 if "selinux_fc" in OPTIONS.info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001565 OPTIONS.info_dict["selinux_fc"] = os.path.join(
1566 OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")
Kenny Roote2e9f612013-05-29 12:59:35 -07001567
Doug Zongker37974732010-09-16 17:44:38 -07001568 if OPTIONS.verbose:
1569 print "--- target info ---"
1570 common.DumpInfoDict(OPTIONS.info_dict)
1571
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001572 # If the caller explicitly specified the device-specific extensions
1573 # path via -s/--device_specific, use that. Otherwise, use
1574 # META/releasetools.py if it is present in the target target_files.
1575 # Otherwise, take the path of the file from 'tool_extensions' in the
1576 # info dict and look for that in the local filesystem, relative to
1577 # the current directory.
1578
Doug Zongker37974732010-09-16 17:44:38 -07001579 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001580 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1581 if os.path.exists(from_input):
1582 print "(using device-specific extensions from target_files)"
1583 OPTIONS.device_specific = from_input
1584 else:
1585 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1586
Doug Zongker37974732010-09-16 17:44:38 -07001587 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001588 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001589
Doug Zongker62d4f182014-08-04 16:06:43 -07001590 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001591
Doug Zongker62d4f182014-08-04 16:06:43 -07001592 if OPTIONS.no_signing:
Dan Albert8b72aef2015-03-23 19:13:21 -07001593 if os.path.exists(args[1]):
1594 os.unlink(args[1])
1595 output_zip = zipfile.ZipFile(args[1], "w",
1596 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001597 else:
1598 temp_zip_file = tempfile.NamedTemporaryFile()
1599 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1600 compression=zipfile.ZIP_DEFLATED)
1601
Tao Baod47d8e12015-05-21 14:09:49 -07001602 cache_size = OPTIONS.info_dict.get("cache_size", None)
1603 if cache_size is None:
1604 raise RuntimeError("can't determine the cache partition size")
1605 OPTIONS.cache_size = cache_size
1606
Doug Zongker62d4f182014-08-04 16:06:43 -07001607 if OPTIONS.incremental_source is None:
1608 WriteFullOTAPackage(input_zip, output_zip)
1609 if OPTIONS.package_key is None:
1610 OPTIONS.package_key = OPTIONS.info_dict.get(
1611 "default_system_dev_certificate",
1612 "build/target/product/security/testkey")
Tao Baof3282b42015-04-01 11:21:55 -07001613 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001614 break
1615
1616 else:
1617 print "unzipping source target-files..."
Dan Albert8b72aef2015-03-23 19:13:21 -07001618 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
1619 OPTIONS.incremental_source)
Doug Zongker62d4f182014-08-04 16:06:43 -07001620 OPTIONS.target_info_dict = OPTIONS.info_dict
1621 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1622 if "selinux_fc" in OPTIONS.source_info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001623 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(
1624 OPTIONS.source_tmp, "BOOT", "RAMDISK", "file_contexts")
Doug Zongker62d4f182014-08-04 16:06:43 -07001625 if OPTIONS.package_key is None:
1626 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1627 "default_system_dev_certificate",
1628 "build/target/product/security/testkey")
1629 if OPTIONS.verbose:
1630 print "--- source info ---"
1631 common.DumpInfoDict(OPTIONS.source_info_dict)
1632 try:
1633 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Baof3282b42015-04-01 11:21:55 -07001634 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001635 break
1636 except ValueError:
Dan Albert8b72aef2015-03-23 19:13:21 -07001637 if not OPTIONS.fallback_to_full:
1638 raise
Doug Zongker62d4f182014-08-04 16:06:43 -07001639 print "--- failed to build incremental; falling back to full ---"
1640 OPTIONS.incremental_source = None
Tao Baof3282b42015-04-01 11:21:55 -07001641 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001642
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001643 if not OPTIONS.no_signing:
1644 SignOutput(temp_zip_file.name, args[1])
1645 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001646
Doug Zongkereef39442009-04-02 12:14:19 -07001647 print "done."
1648
1649
1650if __name__ == '__main__':
1651 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001652 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001653 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001654 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07001655 print
1656 print " ERROR: %s" % (e,)
1657 print
1658 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001659 finally:
1660 common.Cleanup()