blob: c6fd47eec659fcf87bac3cec3c8db7b475c094ba [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
leozwanga1fcaf82015-09-15 08:44:12 -070045 --full_bootloader
46 When generating an incremental OTA, always include a full copy of
47 bootloader image. This option is only meaningful when -i is specified,
48 because a full bootloader is always included in a full OTA if applicable.
49
Michael Runge63f01de2014-10-28 19:24:19 -070050 -v (--verify)
51 Remount and verify the checksums of the files written to the
52 system and vendor (if used) partitions. Incremental builds only.
53
Michael Runge6e836112014-04-15 17:40:21 -070054 -o (--oem_settings) <file>
55 Use the file to specify the expected OEM-specific properties
56 on the OEM partition of the intended device.
57
Doug Zongkerdbfaae52009-04-21 17:12:54 -070058 -w (--wipe_user_data)
59 Generate an OTA package that will wipe the user data partition
60 when installed.
61
Doug Zongker962069c2009-04-23 11:41:58 -070062 -n (--no_prereq)
63 Omit the timestamp prereq check normally included at the top of
64 the build scripts (used for developer OTA packages which
65 legitimately need to go back and forth).
66
Doug Zongker1c390a22009-05-14 19:06:36 -070067 -e (--extra_script) <file>
68 Insert the contents of file at the end of the update script.
69
Hristo Bojinovdafb0422010-08-26 14:35:16 -070070 -a (--aslr_mode) <on|off>
71 Specify whether to turn on ASLR for the package (on by default).
Stephen Smalley56882bf2012-02-09 13:36:21 -050072
Doug Zongker9b23f2c2013-11-25 14:44:12 -080073 -2 (--two_step)
74 Generate a 'two-step' OTA package, where recovery is updated
75 first, so that any changes made to the system partition are done
76 using the new recovery (new kernel, etc.).
77
Doug Zongker26e66192014-02-20 13:22:07 -080078 --block
79 Generate a block-based OTA if possible. Will fall back to a
80 file-based OTA if the target_files is older and doesn't support
81 block-based OTAs.
82
Doug Zongker25568482014-03-03 10:21:27 -080083 -b (--binary) <file>
84 Use the given binary as the update-binary in the output package,
85 instead of the binary in the build's target_files. Use for
86 development only.
87
Martin Blumenstingl374e1142014-05-31 20:42:55 +020088 -t (--worker_threads) <int>
89 Specifies the number of worker-threads that will be used when
90 generating patches for incremental updates (defaults to 3).
91
Doug Zongkereef39442009-04-02 12:14:19 -070092"""
93
94import sys
95
Doug Zongkercf6d5a92014-02-18 10:57:07 -080096if sys.hexversion < 0x02070000:
97 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -070098 sys.exit(1)
99
Doug Zongkerfc44a512014-08-26 13:10:25 -0700100import multiprocessing
Doug Zongkereef39442009-04-02 12:14:19 -0700101import os
Doug Zongkereef39442009-04-02 12:14:19 -0700102import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -0700103import zipfile
104
105import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700106import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -0700107import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700108
109OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700110OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700111OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700112OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700113OPTIONS.require_verbatim = set()
114OPTIONS.prohibit_verbatim = set(("system/build.prop",))
115OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700116OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700117OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700118OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700119OPTIONS.aslr_mode = True
Doug Zongkerfc44a512014-08-26 13:10:25 -0700120OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
121if OPTIONS.worker_threads == 0:
122 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800123OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900124OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800125OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800126OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700127OPTIONS.oem_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -0700128OPTIONS.fallback_to_full = True
Tao Bao43078aa2015-04-21 14:32:35 -0700129OPTIONS.full_radio = False
leozwanga1fcaf82015-09-15 08:44:12 -0700130OPTIONS.full_bootloader = False
Doug Zongkereef39442009-04-02 12:14:19 -0700131
132def MostPopularKey(d, default):
133 """Given a dict, return the key corresponding to the largest
134 value. Returns 'default' if the dict is empty."""
135 x = [(v, k) for (k, v) in d.iteritems()]
Dan Albert8b72aef2015-03-23 19:13:21 -0700136 if not x:
137 return default
Doug Zongkereef39442009-04-02 12:14:19 -0700138 x.sort()
139 return x[-1][1]
140
141
142def IsSymlink(info):
143 """Return true if the zipfile.ZipInfo object passed in represents a
144 symlink."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700145 return (info.external_attr >> 16) == 0o120777
Doug Zongkereef39442009-04-02 12:14:19 -0700146
Hristo Bojinov96be7202010-08-02 10:26:17 -0700147def IsRegular(info):
148 """Return true if the zipfile.ZipInfo object passed in represents a
149 symlink."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700150 return (info.external_attr >> 28) == 0o10
Doug Zongkereef39442009-04-02 12:14:19 -0700151
Michael Runge4038aa82013-12-13 18:06:28 -0800152def ClosestFileMatch(src, tgtfiles, existing):
153 """Returns the closest file match between a source file and list
154 of potential matches. The exact filename match is preferred,
155 then the sha1 is searched for, and finally a file with the same
156 basename is evaluated. Rename support in the updater-binary is
157 required for the latter checks to be used."""
158
159 result = tgtfiles.get("path:" + src.name)
160 if result is not None:
161 return result
162
163 if not OPTIONS.target_info_dict.get("update_rename_support", False):
164 return None
165
166 if src.size < 1000:
167 return None
168
169 result = tgtfiles.get("sha1:" + src.sha1)
170 if result is not None and existing.get(result.name) is None:
171 return result
172 result = tgtfiles.get("file:" + src.name.split("/")[-1])
173 if result is not None and existing.get(result.name) is None:
174 return result
175 return None
176
Dan Albert8b72aef2015-03-23 19:13:21 -0700177class ItemSet(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700178 def __init__(self, partition, fs_config):
179 self.partition = partition
180 self.fs_config = fs_config
181 self.ITEMS = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700182
Dan Albert8b72aef2015-03-23 19:13:21 -0700183 def Get(self, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700184 if name not in self.ITEMS:
Dan Albert8b72aef2015-03-23 19:13:21 -0700185 self.ITEMS[name] = Item(self, name, is_dir=is_dir)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700186 return self.ITEMS[name]
Doug Zongkereef39442009-04-02 12:14:19 -0700187
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700188 def GetMetadata(self, input_zip):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700189 # The target_files contains a record of what the uid,
190 # gid, and mode are supposed to be.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700191 output = input_zip.read(self.fs_config)
Doug Zongkereef39442009-04-02 12:14:19 -0700192
193 for line in output.split("\n"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700194 if not line:
195 continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700196 columns = line.split()
197 name, uid, gid, mode = columns[:4]
198 selabel = None
199 capabilities = None
200
201 # After the first 4 columns, there are a series of key=value
202 # pairs. Extract out the fields we care about.
203 for element in columns[4:]:
204 key, value = element.split("=")
205 if key == "selabel":
206 selabel = value
207 if key == "capabilities":
208 capabilities = value
209
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700210 i = self.ITEMS.get(name, None)
Doug Zongker283e2a12010-03-15 17:52:32 -0700211 if i is not None:
212 i.uid = int(uid)
213 i.gid = int(gid)
214 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700215 i.selabel = selabel
216 i.capabilities = capabilities
Dan Albert8b72aef2015-03-23 19:13:21 -0700217 if i.is_dir:
Doug Zongker283e2a12010-03-15 17:52:32 -0700218 i.children.sort(key=lambda i: i.name)
219
220 # set metadata for the files generated by this script.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700221 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700222 if i:
223 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700224 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700225 if i:
226 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700227
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700228
Dan Albert8b72aef2015-03-23 19:13:21 -0700229class Item(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700230 """Items represent the metadata (user, group, mode) of files and
231 directories in the system image."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700232 def __init__(self, itemset, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700233 self.itemset = itemset
234 self.name = name
235 self.uid = None
236 self.gid = None
237 self.mode = None
238 self.selabel = None
239 self.capabilities = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700240 self.is_dir = is_dir
241 self.descendants = None
242 self.best_subtree = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700243
244 if name:
Dan Albert8b72aef2015-03-23 19:13:21 -0700245 self.parent = itemset.Get(os.path.dirname(name), is_dir=True)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700246 self.parent.children.append(self)
247 else:
248 self.parent = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700249 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700250 self.children = []
251
252 def Dump(self, indent=0):
253 if self.uid is not None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700254 print "%s%s %d %d %o" % (
255 " " * indent, self.name, self.uid, self.gid, self.mode)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700256 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700257 print "%s%s %s %s %s" % (
258 " " * indent, self.name, self.uid, self.gid, self.mode)
259 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700260 print "%s%s" % (" "*indent, self.descendants)
261 print "%s%s" % (" "*indent, self.best_subtree)
262 for i in self.children:
263 i.Dump(indent=indent+1)
264
Doug Zongkereef39442009-04-02 12:14:19 -0700265 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700266 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
Dan Albert8b72aef2015-03-23 19:13:21 -0700267 all children and determine the best strategy for using set_perm_recursive
268 and set_perm to correctly chown/chmod all the files to their desired
Doug Zongkereef39442009-04-02 12:14:19 -0700269 values. Recursively calls itself for all descendants.
270
Dan Albert8b72aef2015-03-23 19:13:21 -0700271 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count}
272 counting up all descendants of this node. (dmode or fmode may be None.)
273 Also sets the best_subtree of each directory Item to the (uid, gid, dmode,
274 fmode, selabel, capabilities) tuple that will match the most descendants of
275 that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700276 """
277
Dan Albert8b72aef2015-03-23 19:13:21 -0700278 assert self.is_dir
279 key = (self.uid, self.gid, self.mode, None, self.selabel,
280 self.capabilities)
281 self.descendants = {key: 1}
282 d = self.descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700283 for i in self.children:
Dan Albert8b72aef2015-03-23 19:13:21 -0700284 if i.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700285 for k, v in i.CountChildMetadata().iteritems():
286 d[k] = d.get(k, 0) + v
287 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700288 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700289 d[k] = d.get(k, 0) + 1
290
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700291 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
292 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700293
294 # First, find the (uid, gid) pair that matches the most
295 # descendants.
296 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700297 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700298 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
299 ug = MostPopularKey(ug, (0, 0))
300
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700301 # Now find the dmode, fmode, selabel, and capabilities that match
302 # the most descendants with that (uid, gid), and choose those.
Dan Albert8b72aef2015-03-23 19:13:21 -0700303 best_dmode = (0, 0o755)
304 best_fmode = (0, 0o644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700305 best_selabel = (0, None)
306 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700307 for k, count in d.iteritems():
Dan Albert8b72aef2015-03-23 19:13:21 -0700308 if k[:2] != ug:
309 continue
310 if k[2] is not None and count >= best_dmode[0]:
311 best_dmode = (count, k[2])
312 if k[3] is not None and count >= best_fmode[0]:
313 best_fmode = (count, k[3])
314 if k[4] is not None and count >= best_selabel[0]:
315 best_selabel = (count, k[4])
316 if k[5] is not None and count >= best_capabilities[0]:
317 best_capabilities = (count, k[5])
318 self.best_subtree = ug + (
319 best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700320
321 return d
322
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700323 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700324 """Append set_perm/set_perm_recursive commands to 'script' to
325 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700326 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700327
328 self.CountChildMetadata()
329
330 def recurse(item, current):
Dan Albert8b72aef2015-03-23 19:13:21 -0700331 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple
332 # that the current item (and all its children) have already been set to.
333 # We only need to issue set_perm/set_perm_recursive commands if we're
Doug Zongkereef39442009-04-02 12:14:19 -0700334 # supposed to be something different.
Dan Albert8b72aef2015-03-23 19:13:21 -0700335 if item.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700336 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700337 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700338 current = item.best_subtree
339
340 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700341 item.mode != current[2] or item.selabel != current[4] or \
342 item.capabilities != current[5]:
343 script.SetPermissions("/"+item.name, item.uid, item.gid,
344 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700345
346 for i in item.children:
347 recurse(i, current)
348 else:
349 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700350 item.mode != current[3] or item.selabel != current[4] or \
351 item.capabilities != current[5]:
352 script.SetPermissions("/"+item.name, item.uid, item.gid,
353 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700354
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700355 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700356
357
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700358def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
359 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700360 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800361 list of symlinks. output_zip may be None, in which case the copy is
362 skipped (but the other side effects still happen). substitute is an
363 optional dict of {output filename: contents} to be output instead of
364 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700365 """
366
367 symlinks = []
368
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700369 partition = itemset.partition
370
Doug Zongkereef39442009-04-02 12:14:19 -0700371 for info in input_zip.infolist():
Tao Baoeaf885b2015-03-23 16:01:17 -0700372 prefix = partition.upper() + "/"
373 if info.filename.startswith(prefix):
374 basefilename = info.filename[len(prefix):]
Doug Zongkereef39442009-04-02 12:14:19 -0700375 if IsSymlink(info):
376 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700377 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700378 else:
Tao Baof3282b42015-04-01 11:21:55 -0700379 import copy
Doug Zongkereef39442009-04-02 12:14:19 -0700380 info2 = copy.copy(info)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700381 fn = info2.filename = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700382 if substitute and fn in substitute and substitute[fn] is None:
383 continue
384 if output_zip is not None:
385 if substitute and fn in substitute:
386 data = substitute[fn]
387 else:
388 data = input_zip.read(info.filename)
Tao Baof3282b42015-04-01 11:21:55 -0700389 common.ZipWriteStr(output_zip, info2, data)
Doug Zongkereef39442009-04-02 12:14:19 -0700390 if fn.endswith("/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700391 itemset.Get(fn[:-1], is_dir=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700392 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700393 itemset.Get(fn)
Doug Zongkereef39442009-04-02 12:14:19 -0700394
395 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800396 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700397
398
Doug Zongkereef39442009-04-02 12:14:19 -0700399def SignOutput(temp_zip_name, output_zip_name):
400 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
401 pw = key_passwords[OPTIONS.package_key]
402
Doug Zongker951495f2009-08-14 12:44:19 -0700403 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
404 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700405
406
Dan Albert8b72aef2015-03-23 19:13:21 -0700407def AppendAssertions(script, info_dict, oem_dict=None):
Michael Runge6e836112014-04-15 17:40:21 -0700408 oem_props = info_dict.get("oem_fingerprint_properties")
Michael Runge560569a2014-09-18 15:12:45 -0700409 if oem_props is None or len(oem_props) == 0:
Michael Runge6e836112014-04-15 17:40:21 -0700410 device = GetBuildProp("ro.product.device", info_dict)
411 script.AssertDevice(device)
412 else:
413 if oem_dict is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700414 raise common.ExternalError(
415 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700416 for prop in oem_props.split():
417 if oem_dict.get(prop) is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700418 raise common.ExternalError(
419 "The OEM file is missing the property %s" % prop)
Michael Runge6e836112014-04-15 17:40:21 -0700420 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700421
Doug Zongkereef39442009-04-02 12:14:19 -0700422
Doug Zongkerc9253822014-02-04 12:17:58 -0800423def HasRecoveryPatch(target_files_zip):
424 try:
425 target_files_zip.getinfo("SYSTEM/recovery-from-boot.p")
426 return True
427 except KeyError:
428 return False
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 Bao5ece99d2015-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 Baobebd3cf2015-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
Kenny Rootf32dc712012-04-08 10:42:34 -0700591 if "selinux_fc" in OPTIONS.info_dict:
592 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500593
Michael Runge7cd99ba2014-10-22 17:21:48 -0700594 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
595
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700596 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700597 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800598
Doug Zongker26e66192014-02-20 13:22:07 -0800599 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700600 # Full OTA is done as an "incremental" against an empty source
601 # image. This has the effect of writing new data from the package
602 # to the entire partition, but lets us reuse the updater code that
603 # writes incrementals to do it.
604 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
605 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700606 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700607 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800608 else:
609 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700610 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800611 if not has_recovery_patch:
612 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800613 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700614
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700615 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800616 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700617
Doug Zongker55d93282011-01-25 17:03:34 -0800618 boot_img = common.GetBootableImage("boot.img", "boot.img",
619 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800620
Doug Zongker91a99c22014-05-09 13:15:01 -0700621 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800622 def output_sink(fn, data):
623 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700624 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800625
626 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
627 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700628
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700629 system_items.GetMetadata(input_zip)
630 system_items.Get("system").SetPermissions(script)
631
632 if HasVendorPartition(input_zip):
633 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
634 script.ShowProgress(0.1, 0)
635
636 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700637 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
638 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700639 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700640 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700641 else:
642 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700643 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700644 script.UnpackPackageDir("vendor", "/vendor")
645
646 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
647 script.MakeSymlinks(symlinks)
648
649 vendor_items.GetMetadata(input_zip)
650 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700651
Doug Zongker37974732010-09-16 17:44:38 -0700652 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700653 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700654
Doug Zongker01ce19c2014-02-04 13:48:15 -0800655 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700656 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700657
Doug Zongker01ce19c2014-02-04 13:48:15 -0800658 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700659 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700660
Doug Zongker1c390a22009-05-14 19:06:36 -0700661 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700662 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700663
Doug Zongker14833602010-02-02 13:12:04 -0800664 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800665
Doug Zongker922206e2014-03-04 13:16:24 -0800666 if OPTIONS.wipe_user_data:
667 script.ShowProgress(0.1, 10)
668 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700669
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800670 if OPTIONS.two_step:
671 script.AppendExtra("""
672set_stage("%(bcb_dev)s", "");
673""" % bcb_dev)
674 script.AppendExtra("else\n")
675 script.WriteRawImage("/boot", "recovery.img")
676 script.AppendExtra("""
677set_stage("%(bcb_dev)s", "2/3");
678reboot_now("%(bcb_dev)s", "");
679endif;
680endif;
681""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800682 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700683 WriteMetadata(metadata, output_zip)
684
Doug Zongkerfc44a512014-08-26 13:10:25 -0700685
Dan Albert8e0178d2015-01-27 15:53:15 -0800686def WritePolicyConfig(file_name, output_zip):
687 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500688
Doug Zongker2ea21062010-04-28 16:05:21 -0700689
690def WriteMetadata(metadata, output_zip):
691 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
692 "".join(["%s=%s\n" % kv
693 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700694
Doug Zongkerfc44a512014-08-26 13:10:25 -0700695
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700696def LoadPartitionFiles(z, partition):
697 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700698 ZipFile, and return a dict of {filename: File object}."""
699 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700700 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700701 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700702 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700703 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700704 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700705 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700706 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800707 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700708
709
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700710def GetBuildProp(prop, info_dict):
711 """Return the fingerprint of the build of a given target-files info_dict."""
712 try:
713 return info_dict.get("build.prop", {})[prop]
714 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700715 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700716
Doug Zongkerfc44a512014-08-26 13:10:25 -0700717
Michael Runge4038aa82013-12-13 18:06:28 -0800718def AddToKnownPaths(filename, known_paths):
719 if filename[-1] == "/":
720 return
721 dirs = filename.split("/")[:-1]
722 while len(dirs) > 0:
723 path = "/".join(dirs)
724 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700725 break
Michael Runge4038aa82013-12-13 18:06:28 -0800726 known_paths.add(path)
727 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700728
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700729
Geremy Condra36bd3652014-02-06 19:45:10 -0800730def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
731 source_version = OPTIONS.source_info_dict["recovery_api_version"]
732 target_version = OPTIONS.target_info_dict["recovery_api_version"]
733
734 if source_version == 0:
735 print ("WARNING: generating edify script for a source that "
736 "can't install it.")
Tao Baobebd3cf2015-06-22 19:17:41 -0700737 script = edify_generator.EdifyGenerator(
738 source_version, OPTIONS.target_info_dict,
739 fstab=OPTIONS.source_info_dict["fstab"])
Geremy Condra36bd3652014-02-06 19:45:10 -0800740
Dan Albert8b72aef2015-03-23 19:13:21 -0700741 metadata = {
742 "pre-device": GetBuildProp("ro.product.device",
743 OPTIONS.source_info_dict),
744 "post-timestamp": GetBuildProp("ro.build.date.utc",
745 OPTIONS.target_info_dict),
746 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800747
748 device_specific = common.DeviceSpecificParams(
749 source_zip=source_zip,
750 source_version=source_version,
751 target_zip=target_zip,
752 target_version=target_version,
753 output_zip=output_zip,
754 script=script,
755 metadata=metadata,
Tao Baoe09359a2015-10-13 16:37:12 -0700756 info_dict=OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800757
Tao Bao6c55a8a2015-04-08 15:30:27 -0700758 # TODO: Currently this works differently from WriteIncrementalOTAPackage().
759 # This function doesn't consider thumbprints when writing
760 # metadata["pre/post-build"]. One possible reason is that the current
761 # devices with thumbprints are all using file-based OTAs. Long term we
762 # should factor out the common parts into a shared one to avoid further
763 # divergence.
Geremy Condra36bd3652014-02-06 19:45:10 -0800764 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
765 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
766 metadata["pre-build"] = source_fp
767 metadata["post-build"] = target_fp
768
769 source_boot = common.GetBootableImage(
770 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
771 OPTIONS.source_info_dict)
772 target_boot = common.GetBootableImage(
773 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
774 updating_boot = (not OPTIONS.two_step and
775 (source_boot.data != target_boot.data))
776
Geremy Condra36bd3652014-02-06 19:45:10 -0800777 target_recovery = common.GetBootableImage(
778 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800779
Doug Zongkerfc44a512014-08-26 13:10:25 -0700780 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
781 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700782
783 blockimgdiff_version = 1
784 if OPTIONS.info_dict:
785 blockimgdiff_version = max(
786 int(i) for i in
787 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
788
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700789 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700790 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700791
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700792 if HasVendorPartition(target_zip):
793 if not HasVendorPartition(source_zip):
794 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700795 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
796 OPTIONS.source_info_dict)
797 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
798 OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700799 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700800 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700801 else:
802 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800803
Michael Rungec6e3afd2014-05-05 11:55:47 -0700804 oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
Tao Baobebd3cf2015-06-22 19:17:41 -0700805 recovery_mount_options = OPTIONS.source_info_dict.get(
Dan Albert8b72aef2015-03-23 19:13:21 -0700806 "recovery_mount_options")
Michael Rungec6e3afd2014-05-05 11:55:47 -0700807 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700808 if oem_props is not None and len(oem_props) > 0:
Michael Rungec6e3afd2014-05-05 11:55:47 -0700809 if OPTIONS.oem_source is None:
810 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700811 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700812 oem_dict = common.LoadDictionaryFromLines(
813 open(OPTIONS.oem_source).readlines())
Michael Rungec6e3afd2014-05-05 11:55:47 -0700814
815 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:
Tao Baocce673b2015-07-29 14:09:23 -0700841 if not OPTIONS.source_info_dict.get("multistage_support", None):
Geremy Condra36bd3652014-02-06 19:45:10 -0800842 assert False, "two-step packages not supported by this build"
Tao Baocce673b2015-07-29 14:09:23 -0700843 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Geremy Condra36bd3652014-02-06 19:45:10 -0800844 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:
Tao Baocce673b2015-07-29 14:09:23 -0700888 boot_type, boot_device = common.GetTypeAndDevice(
889 "/boot", OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800890 d = common.Difference(target_boot, source_boot)
891 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700892 if d is None:
893 include_full_boot = True
894 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
895 else:
896 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800897
Doug Zongkerf8340082014-08-05 10:39:37 -0700898 print "boot target: %d source: %d diff: %d" % (
899 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800900
Doug Zongkerf8340082014-08-05 10:39:37 -0700901 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800902
Doug Zongkerf8340082014-08-05 10:39:37 -0700903 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
904 (boot_type, boot_device,
905 source_boot.size, source_boot.sha1,
906 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800907
908 device_specific.IncrementalOTA_VerifyEnd()
909
910 if OPTIONS.two_step:
911 script.WriteRawImage("/boot", "recovery.img")
912 script.AppendExtra("""
913set_stage("%(bcb_dev)s", "2/3");
914reboot_now("%(bcb_dev)s", "");
915else
916""" % bcb_dev)
917
Jesse Zhao75bcea02015-01-06 10:59:53 -0800918 # Verify the existing partitions.
919 system_diff.WriteVerifyScript(script)
920 if vendor_diff:
921 vendor_diff.WriteVerifyScript(script)
922
Geremy Condra36bd3652014-02-06 19:45:10 -0800923 script.Comment("---- start making changes here ----")
924
925 device_specific.IncrementalOTA_InstallBegin()
926
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700927 system_diff.WriteScript(script, output_zip,
928 progress=0.8 if vendor_diff else 0.9)
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 Baobebd3cf2015-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 Baobebd3cf2015-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,
Tao Baoe09359a2015-10-13 16:37:12 -07001156 info_dict=OPTIONS.source_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:
Tao Baocce673b2015-07-29 14:09:23 -07001228 if not OPTIONS.source_info_dict.get("multistage_support", None):
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001229 assert False, "two-step packages not supported by this build"
Tao Baocce673b2015-07-29 14:09:23 -07001230 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001231 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
Tao Baocce673b2015-07-29 14:09:23 -07001267 boot_type, boot_device = common.GetTypeAndDevice(
1268 "/boot", OPTIONS.source_info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001269
1270 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1271 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001272 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001273 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001274 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001275
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001276 size = []
Dan Albert8b72aef2015-03-23 19:13:21 -07001277 if system_diff.patch_list:
1278 size.append(system_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001279 if vendor_diff:
Dan Albert8b72aef2015-03-23 19:13:21 -07001280 if vendor_diff.patch_list:
1281 size.append(vendor_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001282 if size or updating_recovery or updating_boot:
1283 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001284
Doug Zongker05d3dea2009-06-22 11:32:31 -07001285 device_specific.IncrementalOTA_VerifyEnd()
1286
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001287 if OPTIONS.two_step:
1288 script.WriteRawImage("/boot", "recovery.img")
1289 script.AppendExtra("""
1290set_stage("%(bcb_dev)s", "2/3");
1291reboot_now("%(bcb_dev)s", "");
1292else
1293""" % bcb_dev)
1294
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001295 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001296
Doug Zongkere5ff5902012-01-17 10:55:37 -08001297 device_specific.IncrementalOTA_InstallBegin()
1298
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001299 if OPTIONS.two_step:
1300 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1301 script.WriteRawImage("/boot", "boot.img")
1302 print "writing full boot image (forced by two-step mode)"
1303
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001304 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001305 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1306 if vendor_diff:
1307 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001308
Doug Zongker881dd402009-09-20 14:03:55 -07001309 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001310 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1311 if vendor_diff:
1312 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001313 if updating_boot:
1314 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001315
1316 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001317 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1318 if vendor_diff:
1319 script.Print("Patching vendor files...")
1320 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001321
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001322 if not OPTIONS.two_step:
1323 if updating_boot:
1324 # Produce the boot image by applying a patch to the current
1325 # contents of the boot partition, and write it back to the
1326 # partition.
1327 script.Print("Patching boot image...")
1328 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1329 % (boot_type, boot_device,
1330 source_boot.size, source_boot.sha1,
1331 target_boot.size, target_boot.sha1),
1332 "-",
1333 target_boot.size, target_boot.sha1,
1334 source_boot.sha1, "patch/boot.img.p")
1335 so_far += target_boot.size
1336 script.SetProgress(so_far / total_patch_size)
1337 print "boot image changed; including."
1338 else:
1339 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001340
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001341 system_items = ItemSet("system", "META/filesystem_config.txt")
1342 if vendor_diff:
1343 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1344
Doug Zongkereef39442009-04-02 12:14:19 -07001345 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001346 # Recovery is generated as a patch using both the boot image
1347 # (which contains the same linux kernel as recovery) and the file
1348 # /system/etc/recovery-resource.dat (which contains all the images
1349 # used in the recovery UI) as sources. This lets us minimize the
1350 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001351 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001352 # For older builds where recovery-resource.dat is not present, we
1353 # use only the boot image as the source.
1354
Doug Zongkerc9253822014-02-04 12:17:58 -08001355 if not target_has_recovery_patch:
1356 def output_sink(fn, data):
1357 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001358 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001359
1360 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1361 target_recovery, target_boot)
1362 script.DeleteFiles(["/system/recovery-from-boot.p",
1363 "/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.
Tao Bao39c322c2015-09-02 10:28:08 -07001393
1394 # If a symlink in the source will be replaced by a regular file, we cannot
1395 # delete the symlink/file in case the package gets applied again. For such
1396 # a symlink, we prepend a sha1_check() to detect if it has been updated.
1397 # (Bug: 23646151)
1398 replaced_symlinks = dict()
1399 if system_diff:
1400 for i in system_diff.verbatim_targets:
1401 replaced_symlinks["/%s" % (i[0],)] = i[2]
1402 if vendor_diff:
1403 for i in vendor_diff.verbatim_targets:
1404 replaced_symlinks["/%s" % (i[0],)] = i[2]
1405
1406 if system_diff:
1407 for tf in system_diff.renames.values():
1408 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1409 if vendor_diff:
1410 for tf in vendor_diff.renames.values():
1411 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1412
1413 always_delete = []
1414 may_delete = []
Doug Zongkereef39442009-04-02 12:14:19 -07001415 for dest, link in source_symlinks:
1416 if link not in target_symlinks_d:
Tao Bao39c322c2015-09-02 10:28:08 -07001417 if link in replaced_symlinks:
1418 may_delete.append((link, replaced_symlinks[link]))
1419 else:
1420 always_delete.append(link)
1421 script.DeleteFiles(always_delete)
1422 script.DeleteFilesIfNotMatching(may_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001423
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001424 if system_diff.verbatim_targets:
1425 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001426 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001427 if vendor_diff and vendor_diff.verbatim_targets:
1428 script.Print("Unpacking new vendor files...")
1429 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001430
Doug Zongkerc9253822014-02-04 12:17:58 -08001431 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001432 script.Print("Unpacking new recovery...")
1433 script.UnpackPackageDir("recovery", "/system")
1434
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001435 system_diff.EmitRenames(script)
1436 if vendor_diff:
1437 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001438
Doug Zongker05d3dea2009-06-22 11:32:31 -07001439 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001440
1441 # Create all the symlinks that don't already exist, or point to
1442 # somewhere different than what we want. Delete each symlink before
1443 # creating it, since the 'symlink' command won't overwrite.
1444 to_create = []
1445 for dest, link in target_symlinks:
1446 if link in source_symlinks_d:
1447 if dest != source_symlinks_d[link]:
1448 to_create.append((dest, link))
1449 else:
1450 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001451 script.DeleteFiles([i[1] for i in to_create])
1452 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001453
1454 # Now that the symlinks are created, we can set all the
1455 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001456 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001457
Doug Zongker881dd402009-09-20 14:03:55 -07001458 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001459 device_specific.IncrementalOTA_InstallEnd()
1460
Doug Zongker1c390a22009-05-14 19:06:36 -07001461 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001462 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001463
Doug Zongkere92f15a2011-08-26 13:46:40 -07001464 # Patch the build.prop file last, so if something fails but the
1465 # device can still come up, it appears to be the old build and will
1466 # get set the OTA package again to retry.
1467 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001468 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001469
Doug Zongker922206e2014-03-04 13:16:24 -08001470 if OPTIONS.wipe_user_data:
1471 script.Print("Erasing user data...")
1472 script.FormatPartition("/data")
1473
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001474 if OPTIONS.two_step:
1475 script.AppendExtra("""
1476set_stage("%(bcb_dev)s", "");
1477endif;
1478endif;
1479""" % bcb_dev)
1480
Michael Runge63f01de2014-10-28 19:24:19 -07001481 if OPTIONS.verify and system_diff:
1482 script.Print("Remounting and verifying system partition files...")
1483 script.Unmount("/system")
1484 script.Mount("/system")
1485 system_diff.EmitExplicitTargetVerification(script)
1486
1487 if OPTIONS.verify and vendor_diff:
1488 script.Print("Remounting and verifying vendor partition files...")
1489 script.Unmount("/vendor")
1490 script.Mount("/vendor")
1491 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001492 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001493
Doug Zongker2ea21062010-04-28 16:05:21 -07001494 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001495
1496
1497def main(argv):
1498
1499 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001500 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001501 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001502 elif o in ("-k", "--package_key"):
1503 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001504 elif o in ("-i", "--incremental_from"):
1505 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001506 elif o == "--full_radio":
1507 OPTIONS.full_radio = True
leozwanga1fcaf82015-09-15 08:44:12 -07001508 elif o == "--full_bootloader":
1509 OPTIONS.full_bootloader = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001510 elif o in ("-w", "--wipe_user_data"):
1511 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001512 elif o in ("-n", "--no_prereq"):
1513 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001514 elif o in ("-o", "--oem_settings"):
1515 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001516 elif o in ("-e", "--extra_script"):
1517 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001518 elif o in ("-a", "--aslr_mode"):
1519 if a in ("on", "On", "true", "True", "yes", "Yes"):
1520 OPTIONS.aslr_mode = True
1521 else:
1522 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001523 elif o in ("-t", "--worker_threads"):
1524 if a.isdigit():
1525 OPTIONS.worker_threads = int(a)
1526 else:
1527 raise ValueError("Cannot parse value %r for option %r - only "
1528 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001529 elif o in ("-2", "--two_step"):
1530 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001531 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001532 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001533 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001534 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001535 elif o == "--block":
1536 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001537 elif o in ("-b", "--binary"):
1538 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001539 elif o in ("--no_fallback_to_full",):
1540 OPTIONS.fallback_to_full = False
Doug Zongkereef39442009-04-02 12:14:19 -07001541 else:
1542 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001543 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001544
1545 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001546 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001547 extra_long_opts=[
1548 "board_config=",
1549 "package_key=",
1550 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001551 "full_radio",
leozwanga1fcaf82015-09-15 08:44:12 -07001552 "full_bootloader",
Dan Albert8b72aef2015-03-23 19:13:21 -07001553 "wipe_user_data",
1554 "no_prereq",
1555 "extra_script=",
1556 "worker_threads=",
1557 "aslr_mode=",
1558 "two_step",
1559 "no_signing",
1560 "block",
1561 "binary=",
1562 "oem_settings=",
1563 "verify",
1564 "no_fallback_to_full",
1565 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001566
1567 if len(args) != 2:
1568 common.Usage(__doc__)
1569 sys.exit(1)
1570
Doug Zongker1c390a22009-05-14 19:06:36 -07001571 if OPTIONS.extra_script is not None:
1572 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1573
Doug Zongkereef39442009-04-02 12:14:19 -07001574 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001575 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001576
Doug Zongkereef39442009-04-02 12:14:19 -07001577 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001578 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001579
1580 # If this image was originally labelled with SELinux contexts, make sure we
1581 # also apply the labels in our new image. During building, the "file_contexts"
1582 # is in the out/ directory tree, but for repacking from target-files.zip it's
1583 # in the root directory of the ramdisk.
1584 if "selinux_fc" in OPTIONS.info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001585 OPTIONS.info_dict["selinux_fc"] = os.path.join(
1586 OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")
Kenny Roote2e9f612013-05-29 12:59:35 -07001587
Doug Zongker37974732010-09-16 17:44:38 -07001588 if OPTIONS.verbose:
1589 print "--- target info ---"
1590 common.DumpInfoDict(OPTIONS.info_dict)
1591
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001592 # If the caller explicitly specified the device-specific extensions
1593 # path via -s/--device_specific, use that. Otherwise, use
1594 # META/releasetools.py if it is present in the target target_files.
1595 # Otherwise, take the path of the file from 'tool_extensions' in the
1596 # info dict and look for that in the local filesystem, relative to
1597 # the current directory.
1598
Doug Zongker37974732010-09-16 17:44:38 -07001599 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001600 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1601 if os.path.exists(from_input):
1602 print "(using device-specific extensions from target_files)"
1603 OPTIONS.device_specific = from_input
1604 else:
1605 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1606
Doug Zongker37974732010-09-16 17:44:38 -07001607 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001608 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001609
Doug Zongker62d4f182014-08-04 16:06:43 -07001610 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001611
Doug Zongker62d4f182014-08-04 16:06:43 -07001612 if OPTIONS.no_signing:
Dan Albert8b72aef2015-03-23 19:13:21 -07001613 if os.path.exists(args[1]):
1614 os.unlink(args[1])
1615 output_zip = zipfile.ZipFile(args[1], "w",
1616 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001617 else:
1618 temp_zip_file = tempfile.NamedTemporaryFile()
1619 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1620 compression=zipfile.ZIP_DEFLATED)
1621
1622 if OPTIONS.incremental_source is None:
1623 WriteFullOTAPackage(input_zip, output_zip)
1624 if OPTIONS.package_key is None:
1625 OPTIONS.package_key = OPTIONS.info_dict.get(
1626 "default_system_dev_certificate",
1627 "build/target/product/security/testkey")
Tao Baof3282b42015-04-01 11:21:55 -07001628 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001629 break
1630
1631 else:
1632 print "unzipping source target-files..."
Dan Albert8b72aef2015-03-23 19:13:21 -07001633 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
1634 OPTIONS.incremental_source)
Doug Zongker62d4f182014-08-04 16:06:43 -07001635 OPTIONS.target_info_dict = OPTIONS.info_dict
1636 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1637 if "selinux_fc" in OPTIONS.source_info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001638 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(
1639 OPTIONS.source_tmp, "BOOT", "RAMDISK", "file_contexts")
Doug Zongker62d4f182014-08-04 16:06:43 -07001640 if OPTIONS.package_key is None:
1641 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1642 "default_system_dev_certificate",
1643 "build/target/product/security/testkey")
1644 if OPTIONS.verbose:
1645 print "--- source info ---"
1646 common.DumpInfoDict(OPTIONS.source_info_dict)
1647 try:
1648 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Baof3282b42015-04-01 11:21:55 -07001649 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001650 break
1651 except ValueError:
Dan Albert8b72aef2015-03-23 19:13:21 -07001652 if not OPTIONS.fallback_to_full:
1653 raise
Doug Zongker62d4f182014-08-04 16:06:43 -07001654 print "--- failed to build incremental; falling back to full ---"
1655 OPTIONS.incremental_source = None
Tao Baof3282b42015-04-01 11:21:55 -07001656 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001657
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001658 if not OPTIONS.no_signing:
1659 SignOutput(temp_zip_file.name, args[1])
1660 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001661
Doug Zongkereef39442009-04-02 12:14:19 -07001662 print "done."
1663
1664
1665if __name__ == '__main__':
1666 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001667 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001668 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001669 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07001670 print
1671 print " ERROR: %s" % (e,)
1672 print
1673 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001674 finally:
1675 common.Cleanup()