blob: eab3daa87a8ff5e51d9be255b39590dc8d6b0f3b [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
Doug Zongkereef39442009-04-02 12:14:19 -070087"""
88
89import sys
90
Doug Zongkercf6d5a92014-02-18 10:57:07 -080091if sys.hexversion < 0x02070000:
92 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -070093 sys.exit(1)
94
95import copy
Doug Zongkerfc44a512014-08-26 13:10:25 -070096import multiprocessing
Doug Zongkereef39442009-04-02 12:14:19 -070097import os
Doug Zongkereef39442009-04-02 12:14:19 -070098import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -070099import zipfile
100
101import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700102import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -0700103import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700104
105OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700106OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700107OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700108OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700109OPTIONS.require_verbatim = set()
110OPTIONS.prohibit_verbatim = set(("system/build.prop",))
111OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700112OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700113OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700114OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700115OPTIONS.aslr_mode = True
Doug Zongkerfc44a512014-08-26 13:10:25 -0700116OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
117if OPTIONS.worker_threads == 0:
118 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800119OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900120OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800121OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800122OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700123OPTIONS.oem_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -0700124OPTIONS.fallback_to_full = True
Tao Bao43078aa2015-04-21 14:32:35 -0700125OPTIONS.full_radio = False
Doug Zongkereef39442009-04-02 12:14:19 -0700126
127def MostPopularKey(d, default):
128 """Given a dict, return the key corresponding to the largest
129 value. Returns 'default' if the dict is empty."""
130 x = [(v, k) for (k, v) in d.iteritems()]
Dan Albert8b72aef2015-03-23 19:13:21 -0700131 if not x:
132 return default
Doug Zongkereef39442009-04-02 12:14:19 -0700133 x.sort()
134 return x[-1][1]
135
136
137def IsSymlink(info):
138 """Return true if the zipfile.ZipInfo object passed in represents a
139 symlink."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700140 return (info.external_attr >> 16) == 0o120777
Doug Zongkereef39442009-04-02 12:14:19 -0700141
Hristo Bojinov96be7202010-08-02 10:26:17 -0700142def IsRegular(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 >> 28) == 0o10
Doug Zongkereef39442009-04-02 12:14:19 -0700146
Michael Runge4038aa82013-12-13 18:06:28 -0800147def ClosestFileMatch(src, tgtfiles, existing):
148 """Returns the closest file match between a source file and list
149 of potential matches. The exact filename match is preferred,
150 then the sha1 is searched for, and finally a file with the same
151 basename is evaluated. Rename support in the updater-binary is
152 required for the latter checks to be used."""
153
154 result = tgtfiles.get("path:" + src.name)
155 if result is not None:
156 return result
157
158 if not OPTIONS.target_info_dict.get("update_rename_support", False):
159 return None
160
161 if src.size < 1000:
162 return None
163
164 result = tgtfiles.get("sha1:" + src.sha1)
165 if result is not None and existing.get(result.name) is None:
166 return result
167 result = tgtfiles.get("file:" + src.name.split("/")[-1])
168 if result is not None and existing.get(result.name) is None:
169 return result
170 return None
171
Dan Albert8b72aef2015-03-23 19:13:21 -0700172class ItemSet(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700173 def __init__(self, partition, fs_config):
174 self.partition = partition
175 self.fs_config = fs_config
176 self.ITEMS = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700177
Dan Albert8b72aef2015-03-23 19:13:21 -0700178 def Get(self, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700179 if name not in self.ITEMS:
Dan Albert8b72aef2015-03-23 19:13:21 -0700180 self.ITEMS[name] = Item(self, name, is_dir=is_dir)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700181 return self.ITEMS[name]
Doug Zongkereef39442009-04-02 12:14:19 -0700182
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700183 def GetMetadata(self, input_zip):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700184 # The target_files contains a record of what the uid,
185 # gid, and mode are supposed to be.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700186 output = input_zip.read(self.fs_config)
Doug Zongkereef39442009-04-02 12:14:19 -0700187
188 for line in output.split("\n"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700189 if not line:
190 continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700191 columns = line.split()
192 name, uid, gid, mode = columns[:4]
193 selabel = None
194 capabilities = None
195
196 # After the first 4 columns, there are a series of key=value
197 # pairs. Extract out the fields we care about.
198 for element in columns[4:]:
199 key, value = element.split("=")
200 if key == "selabel":
201 selabel = value
202 if key == "capabilities":
203 capabilities = value
204
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700205 i = self.ITEMS.get(name, None)
Doug Zongker283e2a12010-03-15 17:52:32 -0700206 if i is not None:
207 i.uid = int(uid)
208 i.gid = int(gid)
209 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700210 i.selabel = selabel
211 i.capabilities = capabilities
Dan Albert8b72aef2015-03-23 19:13:21 -0700212 if i.is_dir:
Doug Zongker283e2a12010-03-15 17:52:32 -0700213 i.children.sort(key=lambda i: i.name)
214
215 # set metadata for the files generated by this script.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700216 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700217 if i:
218 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700219 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700220 if i:
221 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700222
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700223
Dan Albert8b72aef2015-03-23 19:13:21 -0700224class Item(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700225 """Items represent the metadata (user, group, mode) of files and
226 directories in the system image."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700227 def __init__(self, itemset, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700228 self.itemset = itemset
229 self.name = name
230 self.uid = None
231 self.gid = None
232 self.mode = None
233 self.selabel = None
234 self.capabilities = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700235 self.is_dir = is_dir
236 self.descendants = None
237 self.best_subtree = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700238
239 if name:
Dan Albert8b72aef2015-03-23 19:13:21 -0700240 self.parent = itemset.Get(os.path.dirname(name), is_dir=True)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700241 self.parent.children.append(self)
242 else:
243 self.parent = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700244 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700245 self.children = []
246
247 def Dump(self, indent=0):
248 if self.uid is not None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700249 print "%s%s %d %d %o" % (
250 " " * indent, self.name, self.uid, self.gid, self.mode)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700251 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700252 print "%s%s %s %s %s" % (
253 " " * indent, self.name, self.uid, self.gid, self.mode)
254 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700255 print "%s%s" % (" "*indent, self.descendants)
256 print "%s%s" % (" "*indent, self.best_subtree)
257 for i in self.children:
258 i.Dump(indent=indent+1)
259
Doug Zongkereef39442009-04-02 12:14:19 -0700260 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700261 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
Dan Albert8b72aef2015-03-23 19:13:21 -0700262 all children and determine the best strategy for using set_perm_recursive
263 and set_perm to correctly chown/chmod all the files to their desired
Doug Zongkereef39442009-04-02 12:14:19 -0700264 values. Recursively calls itself for all descendants.
265
Dan Albert8b72aef2015-03-23 19:13:21 -0700266 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count}
267 counting up all descendants of this node. (dmode or fmode may be None.)
268 Also sets the best_subtree of each directory Item to the (uid, gid, dmode,
269 fmode, selabel, capabilities) tuple that will match the most descendants of
270 that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700271 """
272
Dan Albert8b72aef2015-03-23 19:13:21 -0700273 assert self.is_dir
274 key = (self.uid, self.gid, self.mode, None, self.selabel,
275 self.capabilities)
276 self.descendants = {key: 1}
277 d = self.descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700278 for i in self.children:
Dan Albert8b72aef2015-03-23 19:13:21 -0700279 if i.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700280 for k, v in i.CountChildMetadata().iteritems():
281 d[k] = d.get(k, 0) + v
282 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700283 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700284 d[k] = d.get(k, 0) + 1
285
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700286 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
287 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700288
289 # First, find the (uid, gid) pair that matches the most
290 # descendants.
291 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700292 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700293 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
294 ug = MostPopularKey(ug, (0, 0))
295
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700296 # Now find the dmode, fmode, selabel, and capabilities that match
297 # the most descendants with that (uid, gid), and choose those.
Dan Albert8b72aef2015-03-23 19:13:21 -0700298 best_dmode = (0, 0o755)
299 best_fmode = (0, 0o644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700300 best_selabel = (0, None)
301 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700302 for k, count in d.iteritems():
Dan Albert8b72aef2015-03-23 19:13:21 -0700303 if k[:2] != ug:
304 continue
305 if k[2] is not None and count >= best_dmode[0]:
306 best_dmode = (count, k[2])
307 if k[3] is not None and count >= best_fmode[0]:
308 best_fmode = (count, k[3])
309 if k[4] is not None and count >= best_selabel[0]:
310 best_selabel = (count, k[4])
311 if k[5] is not None and count >= best_capabilities[0]:
312 best_capabilities = (count, k[5])
313 self.best_subtree = ug + (
314 best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700315
316 return d
317
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700318 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700319 """Append set_perm/set_perm_recursive commands to 'script' to
320 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700321 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700322
323 self.CountChildMetadata()
324
325 def recurse(item, current):
Dan Albert8b72aef2015-03-23 19:13:21 -0700326 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple
327 # that the current item (and all its children) have already been set to.
328 # We only need to issue set_perm/set_perm_recursive commands if we're
Doug Zongkereef39442009-04-02 12:14:19 -0700329 # supposed to be something different.
Dan Albert8b72aef2015-03-23 19:13:21 -0700330 if item.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700331 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700332 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700333 current = item.best_subtree
334
335 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700336 item.mode != current[2] or item.selabel != current[4] or \
337 item.capabilities != current[5]:
338 script.SetPermissions("/"+item.name, item.uid, item.gid,
339 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700340
341 for i in item.children:
342 recurse(i, current)
343 else:
344 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700345 item.mode != current[3] or item.selabel != current[4] or \
346 item.capabilities != current[5]:
347 script.SetPermissions("/"+item.name, item.uid, item.gid,
348 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700349
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700350 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700351
352
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700353def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
354 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700355 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800356 list of symlinks. output_zip may be None, in which case the copy is
357 skipped (but the other side effects still happen). substitute is an
358 optional dict of {output filename: contents} to be output instead of
359 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700360 """
361
362 symlinks = []
363
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700364 partition = itemset.partition
365
Doug Zongkereef39442009-04-02 12:14:19 -0700366 for info in input_zip.infolist():
Tao Baoeaf885b2015-03-23 16:01:17 -0700367 prefix = partition.upper() + "/"
368 if info.filename.startswith(prefix):
369 basefilename = info.filename[len(prefix):]
Doug Zongkereef39442009-04-02 12:14:19 -0700370 if IsSymlink(info):
371 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700372 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700373 else:
374 info2 = copy.copy(info)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700375 fn = info2.filename = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700376 if substitute and fn in substitute and substitute[fn] is None:
377 continue
378 if output_zip is not None:
379 if substitute and fn in substitute:
380 data = substitute[fn]
381 else:
382 data = input_zip.read(info.filename)
383 output_zip.writestr(info2, data)
384 if fn.endswith("/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700385 itemset.Get(fn[:-1], is_dir=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700386 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700387 itemset.Get(fn)
Doug Zongkereef39442009-04-02 12:14:19 -0700388
389 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800390 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700391
392
Doug Zongkereef39442009-04-02 12:14:19 -0700393def SignOutput(temp_zip_name, output_zip_name):
394 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
395 pw = key_passwords[OPTIONS.package_key]
396
Doug Zongker951495f2009-08-14 12:44:19 -0700397 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
398 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700399
400
Dan Albert8b72aef2015-03-23 19:13:21 -0700401def AppendAssertions(script, info_dict, oem_dict=None):
Michael Runge6e836112014-04-15 17:40:21 -0700402 oem_props = info_dict.get("oem_fingerprint_properties")
Michael Runge560569a2014-09-18 15:12:45 -0700403 if oem_props is None or len(oem_props) == 0:
Michael Runge6e836112014-04-15 17:40:21 -0700404 device = GetBuildProp("ro.product.device", info_dict)
405 script.AssertDevice(device)
406 else:
407 if oem_dict is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700408 raise common.ExternalError(
409 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700410 for prop in oem_props.split():
411 if oem_dict.get(prop) is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700412 raise common.ExternalError(
413 "The OEM file is missing the property %s" % prop)
Michael Runge6e836112014-04-15 17:40:21 -0700414 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700415
Doug Zongkereef39442009-04-02 12:14:19 -0700416
Doug Zongkerc9253822014-02-04 12:17:58 -0800417def HasRecoveryPatch(target_files_zip):
418 try:
419 target_files_zip.getinfo("SYSTEM/recovery-from-boot.p")
420 return True
421 except KeyError:
422 return False
Doug Zongker73ef8252009-07-23 15:12:53 -0700423
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700424def HasVendorPartition(target_files_zip):
425 try:
426 target_files_zip.getinfo("VENDOR/")
427 return True
428 except KeyError:
429 return False
430
Michael Runge6e836112014-04-15 17:40:21 -0700431def GetOemProperty(name, oem_props, oem_dict, info_dict):
432 if oem_props is not None and name in oem_props:
433 return oem_dict[name]
434 return GetBuildProp(name, info_dict)
435
436
437def CalculateFingerprint(oem_props, oem_dict, info_dict):
438 if oem_props is None:
439 return GetBuildProp("ro.build.fingerprint", info_dict)
440 return "%s/%s/%s:%s" % (
Dan Albert8b72aef2015-03-23 19:13:21 -0700441 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
442 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
443 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
444 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700445
Doug Zongkerfc44a512014-08-26 13:10:25 -0700446
Doug Zongker3c84f562014-07-31 11:06:30 -0700447def GetImage(which, tmpdir, info_dict):
Doug Zongkerfc44a512014-08-26 13:10:25 -0700448 # Return an image object (suitable for passing to BlockImageDiff)
449 # for the 'which' partition (most be "system" or "vendor"). If a
450 # prebuilt image and file map are found in tmpdir they are used,
451 # otherwise they are reconstructed from the individual files.
Doug Zongker3c84f562014-07-31 11:06:30 -0700452
453 assert which in ("system", "vendor")
454
455 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700456 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
457 if os.path.exists(path) and os.path.exists(mappath):
Doug Zongker3c84f562014-07-31 11:06:30 -0700458 print "using %s.img from target-files" % (which,)
Doug Zongker3c84f562014-07-31 11:06:30 -0700459 # This is a 'new' target-files, which already has the image in it.
Doug Zongker3c84f562014-07-31 11:06:30 -0700460
461 else:
462 print "building %s.img from target-files" % (which,)
463
464 # This is an 'old' target-files, which does not contain images
465 # already built. Build them.
466
Doug Zongkerfc44a512014-08-26 13:10:25 -0700467 mappath = tempfile.mkstemp()[1]
468 OPTIONS.tempfiles.append(mappath)
469
Doug Zongker3c84f562014-07-31 11:06:30 -0700470 import add_img_to_target_files
471 if which == "system":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700472 path = add_img_to_target_files.BuildSystem(
473 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700474 elif which == "vendor":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700475 path = add_img_to_target_files.BuildVendor(
476 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700477
Doug Zongkerfc44a512014-08-26 13:10:25 -0700478 return sparse_img.SparseImage(path, mappath)
479
480
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700481def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700482 # TODO: how to determine this? We don't know what version it will
483 # be installed on top of. For now, we expect the API just won't
484 # change very often.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700485 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700486
Michael Runge6e836112014-04-15 17:40:21 -0700487 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700488 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700489 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700490 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700491 if OPTIONS.oem_source is None:
492 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700493 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700494 oem_dict = common.LoadDictionaryFromLines(
495 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -0700496
Dan Albert8b72aef2015-03-23 19:13:21 -0700497 metadata = {
498 "post-build": CalculateFingerprint(oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700499 OPTIONS.info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700500 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
501 OPTIONS.info_dict),
502 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
503 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700504
Doug Zongker05d3dea2009-06-22 11:32:31 -0700505 device_specific = common.DeviceSpecificParams(
506 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700507 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700508 output_zip=output_zip,
509 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700510 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700511 metadata=metadata,
512 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700513
Doug Zongkerc9253822014-02-04 12:17:58 -0800514 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800515 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800516
Doug Zongker962069c2009-04-23 11:41:58 -0700517 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700518 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700519 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
520 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700521
Michael Runge6e836112014-04-15 17:40:21 -0700522 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700523 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800524
525 # Two-step package strategy (in chronological order, which is *not*
526 # the order in which the generated script has things):
527 #
528 # if stage is not "2/3" or "3/3":
529 # write recovery image to boot partition
530 # set stage to "2/3"
531 # reboot to boot partition and restart recovery
532 # else if stage is "2/3":
533 # write recovery image to recovery partition
534 # set stage to "3/3"
535 # reboot to recovery partition and restart recovery
536 # else:
537 # (stage must be "3/3")
538 # set stage to ""
539 # do normal full package installation:
540 # wipe and install system, boot image, etc.
541 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700542 # complete script normally
543 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800544
545 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
546 OPTIONS.input_tmp, "RECOVERY")
547 if OPTIONS.two_step:
548 if not OPTIONS.info_dict.get("multistage_support", None):
549 assert False, "two-step packages not supported by this build"
550 fs = OPTIONS.info_dict["fstab"]["/misc"]
551 assert fs.fs_type.upper() == "EMMC", \
552 "two-step packages only supported on devices with EMMC /misc partitions"
553 bcb_dev = {"bcb_dev": fs.device}
554 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
555 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700556if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800557""" % bcb_dev)
558 script.WriteRawImage("/recovery", "recovery.img")
559 script.AppendExtra("""
560set_stage("%(bcb_dev)s", "3/3");
561reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700562else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800563""" % bcb_dev)
564
Tao Bao6c55a8a2015-04-08 15:30:27 -0700565 # Dump fingerprints
566 script.Print("Target: %s" % CalculateFingerprint(
567 oem_props, oem_dict, OPTIONS.info_dict))
568
Doug Zongkere5ff5902012-01-17 10:55:37 -0800569 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700570
Doug Zongker01ce19c2014-02-04 13:48:15 -0800571 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700572
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700573 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800574 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700575 if HasVendorPartition(input_zip):
576 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700577
Kenny Rootf32dc712012-04-08 10:42:34 -0700578 if "selinux_fc" in OPTIONS.info_dict:
579 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500580
Michael Runge7cd99ba2014-10-22 17:21:48 -0700581 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
582
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700583 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700584 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800585
Doug Zongker26e66192014-02-20 13:22:07 -0800586 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700587 # Full OTA is done as an "incremental" against an empty source
588 # image. This has the effect of writing new data from the package
589 # to the entire partition, but lets us reuse the updater code that
590 # writes incrementals to do it.
591 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
592 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700593 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700594 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800595 else:
596 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700597 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800598 if not has_recovery_patch:
599 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800600 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700601
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700602 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800603 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700604
Doug Zongker55d93282011-01-25 17:03:34 -0800605 boot_img = common.GetBootableImage("boot.img", "boot.img",
606 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800607
Doug Zongker91a99c22014-05-09 13:15:01 -0700608 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800609 def output_sink(fn, data):
610 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700611 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800612
613 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
614 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700615
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700616 system_items.GetMetadata(input_zip)
617 system_items.Get("system").SetPermissions(script)
618
619 if HasVendorPartition(input_zip):
620 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
621 script.ShowProgress(0.1, 0)
622
623 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700624 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
625 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700626 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700627 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700628 else:
629 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700630 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700631 script.UnpackPackageDir("vendor", "/vendor")
632
633 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
634 script.MakeSymlinks(symlinks)
635
636 vendor_items.GetMetadata(input_zip)
637 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700638
Doug Zongker37974732010-09-16 17:44:38 -0700639 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700640 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700641
Doug Zongker01ce19c2014-02-04 13:48:15 -0800642 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700643 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700644
Doug Zongker01ce19c2014-02-04 13:48:15 -0800645 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700646 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700647
Doug Zongker1c390a22009-05-14 19:06:36 -0700648 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700649 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700650
Doug Zongker14833602010-02-02 13:12:04 -0800651 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800652
Doug Zongker922206e2014-03-04 13:16:24 -0800653 if OPTIONS.wipe_user_data:
654 script.ShowProgress(0.1, 10)
655 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700656
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800657 if OPTIONS.two_step:
658 script.AppendExtra("""
659set_stage("%(bcb_dev)s", "");
660""" % bcb_dev)
661 script.AppendExtra("else\n")
662 script.WriteRawImage("/boot", "recovery.img")
663 script.AppendExtra("""
664set_stage("%(bcb_dev)s", "2/3");
665reboot_now("%(bcb_dev)s", "");
666endif;
667endif;
668""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800669 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700670 WriteMetadata(metadata, output_zip)
671
Doug Zongkerfc44a512014-08-26 13:10:25 -0700672
Dan Albert8e0178d2015-01-27 15:53:15 -0800673def WritePolicyConfig(file_name, output_zip):
674 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500675
Doug Zongker2ea21062010-04-28 16:05:21 -0700676
677def WriteMetadata(metadata, output_zip):
678 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
679 "".join(["%s=%s\n" % kv
680 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700681
Doug Zongkerfc44a512014-08-26 13:10:25 -0700682
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700683def LoadPartitionFiles(z, partition):
684 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700685 ZipFile, and return a dict of {filename: File object}."""
686 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700687 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700688 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700689 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700690 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700691 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700692 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700693 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800694 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700695
696
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700697def GetBuildProp(prop, info_dict):
698 """Return the fingerprint of the build of a given target-files info_dict."""
699 try:
700 return info_dict.get("build.prop", {})[prop]
701 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700702 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700703
Doug Zongkerfc44a512014-08-26 13:10:25 -0700704
Michael Runge4038aa82013-12-13 18:06:28 -0800705def AddToKnownPaths(filename, known_paths):
706 if filename[-1] == "/":
707 return
708 dirs = filename.split("/")[:-1]
709 while len(dirs) > 0:
710 path = "/".join(dirs)
711 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700712 break
Michael Runge4038aa82013-12-13 18:06:28 -0800713 known_paths.add(path)
714 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700715
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700716
Geremy Condra36bd3652014-02-06 19:45:10 -0800717def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
718 source_version = OPTIONS.source_info_dict["recovery_api_version"]
719 target_version = OPTIONS.target_info_dict["recovery_api_version"]
720
721 if source_version == 0:
722 print ("WARNING: generating edify script for a source that "
723 "can't install it.")
724 script = edify_generator.EdifyGenerator(source_version,
725 OPTIONS.target_info_dict)
726
Dan Albert8b72aef2015-03-23 19:13:21 -0700727 metadata = {
728 "pre-device": GetBuildProp("ro.product.device",
729 OPTIONS.source_info_dict),
730 "post-timestamp": GetBuildProp("ro.build.date.utc",
731 OPTIONS.target_info_dict),
732 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800733
734 device_specific = common.DeviceSpecificParams(
735 source_zip=source_zip,
736 source_version=source_version,
737 target_zip=target_zip,
738 target_version=target_version,
739 output_zip=output_zip,
740 script=script,
741 metadata=metadata,
742 info_dict=OPTIONS.info_dict)
743
Tao Bao6c55a8a2015-04-08 15:30:27 -0700744 # TODO: Currently this works differently from WriteIncrementalOTAPackage().
745 # This function doesn't consider thumbprints when writing
746 # metadata["pre/post-build"]. One possible reason is that the current
747 # devices with thumbprints are all using file-based OTAs. Long term we
748 # should factor out the common parts into a shared one to avoid further
749 # divergence.
Geremy Condra36bd3652014-02-06 19:45:10 -0800750 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
751 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
752 metadata["pre-build"] = source_fp
753 metadata["post-build"] = target_fp
754
755 source_boot = common.GetBootableImage(
756 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
757 OPTIONS.source_info_dict)
758 target_boot = common.GetBootableImage(
759 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
760 updating_boot = (not OPTIONS.two_step and
761 (source_boot.data != target_boot.data))
762
Geremy Condra36bd3652014-02-06 19:45:10 -0800763 target_recovery = common.GetBootableImage(
764 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800765
Doug Zongkerfc44a512014-08-26 13:10:25 -0700766 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
767 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700768
769 blockimgdiff_version = 1
770 if OPTIONS.info_dict:
771 blockimgdiff_version = max(
772 int(i) for i in
773 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
774
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700775 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700776 check_first_block=True,
777 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700778
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700779 if HasVendorPartition(target_zip):
780 if not HasVendorPartition(source_zip):
781 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700782 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
783 OPTIONS.source_info_dict)
784 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
785 OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700786 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700787 check_first_block=True,
788 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700789 else:
790 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800791
Michael Rungec6e3afd2014-05-05 11:55:47 -0700792 oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
Dan Albert8b72aef2015-03-23 19:13:21 -0700793 recovery_mount_options = OPTIONS.target_info_dict.get(
794 "recovery_mount_options")
Michael Rungec6e3afd2014-05-05 11:55:47 -0700795 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700796 if oem_props is not None and len(oem_props) > 0:
Michael Rungec6e3afd2014-05-05 11:55:47 -0700797 if OPTIONS.oem_source is None:
798 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700799 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700800 oem_dict = common.LoadDictionaryFromLines(
801 open(OPTIONS.oem_source).readlines())
Michael Rungec6e3afd2014-05-05 11:55:47 -0700802
803 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800804 device_specific.IncrementalOTA_Assertions()
805
806 # Two-step incremental package strategy (in chronological order,
807 # which is *not* the order in which the generated script has
808 # things):
809 #
810 # if stage is not "2/3" or "3/3":
811 # do verification on current system
812 # write recovery image to boot partition
813 # set stage to "2/3"
814 # reboot to boot partition and restart recovery
815 # else if stage is "2/3":
816 # write recovery image to recovery partition
817 # set stage to "3/3"
818 # reboot to recovery partition and restart recovery
819 # else:
820 # (stage must be "3/3")
821 # perform update:
822 # patch system files, etc.
823 # force full install of new boot image
824 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700825 # complete script normally
826 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800827
828 if OPTIONS.two_step:
829 if not OPTIONS.info_dict.get("multistage_support", None):
830 assert False, "two-step packages not supported by this build"
831 fs = OPTIONS.info_dict["fstab"]["/misc"]
832 assert fs.fs_type.upper() == "EMMC", \
833 "two-step packages only supported on devices with EMMC /misc partitions"
834 bcb_dev = {"bcb_dev": fs.device}
835 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
836 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700837if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800838""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -0700839 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800840 script.WriteRawImage("/recovery", "recovery.img")
841 script.AppendExtra("""
842set_stage("%(bcb_dev)s", "3/3");
843reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700844else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800845""" % bcb_dev)
846
Tao Bao6c55a8a2015-04-08 15:30:27 -0700847 # Dump fingerprints
848 script.Print("Source: %s" % CalculateFingerprint(
849 oem_props, oem_dict, OPTIONS.source_info_dict))
850 script.Print("Target: %s" % CalculateFingerprint(
851 oem_props, oem_dict, OPTIONS.target_info_dict))
852
Geremy Condra36bd3652014-02-06 19:45:10 -0800853 script.Print("Verifying current system...")
854
855 device_specific.IncrementalOTA_VerifyBegin()
856
Michael Rungec6e3afd2014-05-05 11:55:47 -0700857 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700858 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
859 # patching on a device that's already on the target build will damage the
860 # system. Because operations like move don't check the block state, they
861 # always apply the changes unconditionally.
862 if blockimgdiff_version <= 2:
863 script.AssertSomeFingerprint(source_fp)
864 else:
865 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700866 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700867 if blockimgdiff_version <= 2:
868 script.AssertSomeThumbprint(
869 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
870 else:
871 script.AssertSomeThumbprint(
872 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
873 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800874
875 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700876 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800877 d = common.Difference(target_boot, source_boot)
878 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700879 if d is None:
880 include_full_boot = True
881 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
882 else:
883 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800884
Doug Zongkerf8340082014-08-05 10:39:37 -0700885 print "boot target: %d source: %d diff: %d" % (
886 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800887
Doug Zongkerf8340082014-08-05 10:39:37 -0700888 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800889
Doug Zongkerf8340082014-08-05 10:39:37 -0700890 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
891 (boot_type, boot_device,
892 source_boot.size, source_boot.sha1,
893 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800894
895 device_specific.IncrementalOTA_VerifyEnd()
896
897 if OPTIONS.two_step:
898 script.WriteRawImage("/boot", "recovery.img")
899 script.AppendExtra("""
900set_stage("%(bcb_dev)s", "2/3");
901reboot_now("%(bcb_dev)s", "");
902else
903""" % bcb_dev)
904
Jesse Zhao75bcea02015-01-06 10:59:53 -0800905 # Verify the existing partitions.
906 system_diff.WriteVerifyScript(script)
907 if vendor_diff:
908 vendor_diff.WriteVerifyScript(script)
909
Geremy Condra36bd3652014-02-06 19:45:10 -0800910 script.Comment("---- start making changes here ----")
911
912 device_specific.IncrementalOTA_InstallBegin()
913
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700914 system_diff.WriteScript(script, output_zip,
915 progress=0.8 if vendor_diff else 0.9)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700916 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700917 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800918
919 if OPTIONS.two_step:
920 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
921 script.WriteRawImage("/boot", "boot.img")
922 print "writing full boot image (forced by two-step mode)"
923
924 if not OPTIONS.two_step:
925 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700926 if include_full_boot:
927 print "boot image changed; including full."
928 script.Print("Installing boot image...")
929 script.WriteRawImage("/boot", "boot.img")
930 else:
931 # Produce the boot image by applying a patch to the current
932 # contents of the boot partition, and write it back to the
933 # partition.
934 print "boot image changed; including patch."
935 script.Print("Patching boot image...")
936 script.ShowProgress(0.1, 10)
937 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
938 % (boot_type, boot_device,
939 source_boot.size, source_boot.sha1,
940 target_boot.size, target_boot.sha1),
941 "-",
942 target_boot.size, target_boot.sha1,
943 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800944 else:
945 print "boot image unchanged; skipping."
946
947 # Do device-specific installation (eg, write radio image).
948 device_specific.IncrementalOTA_InstallEnd()
949
950 if OPTIONS.extra_script is not None:
951 script.AppendExtra(OPTIONS.extra_script)
952
Doug Zongker922206e2014-03-04 13:16:24 -0800953 if OPTIONS.wipe_user_data:
954 script.Print("Erasing user data...")
955 script.FormatPartition("/data")
956
Geremy Condra36bd3652014-02-06 19:45:10 -0800957 if OPTIONS.two_step:
958 script.AppendExtra("""
959set_stage("%(bcb_dev)s", "");
960endif;
961endif;
962""" % bcb_dev)
963
964 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800965 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800966 WriteMetadata(metadata, output_zip)
967
Doug Zongker32b527d2014-03-04 10:03:02 -0800968
Dan Albert8b72aef2015-03-23 19:13:21 -0700969class FileDifference(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700970 def __init__(self, partition, source_zip, target_zip, output_zip):
Dan Albert8b72aef2015-03-23 19:13:21 -0700971 self.deferred_patch_list = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700972 print "Loading target..."
973 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
974 print "Loading source..."
975 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
976
977 self.verbatim_targets = verbatim_targets = []
978 self.patch_list = patch_list = []
979 diffs = []
980 self.renames = renames = {}
981 known_paths = set()
982 largest_source_size = 0
983
984 matching_file_cache = {}
985 for fn, sf in source_data.items():
986 assert fn == sf.name
987 matching_file_cache["path:" + fn] = sf
988 if fn in target_data.keys():
989 AddToKnownPaths(fn, known_paths)
990 # Only allow eligibility for filename/sha matching
991 # if there isn't a perfect path match.
992 if target_data.get(sf.name) is None:
993 matching_file_cache["file:" + fn.split("/")[-1]] = sf
994 matching_file_cache["sha:" + sf.sha1] = sf
995
996 for fn in sorted(target_data.keys()):
997 tf = target_data[fn]
998 assert fn == tf.name
999 sf = ClosestFileMatch(tf, matching_file_cache, renames)
1000 if sf is not None and sf.name != tf.name:
1001 print "File has moved from " + sf.name + " to " + tf.name
1002 renames[sf.name] = tf
1003
1004 if sf is None or fn in OPTIONS.require_verbatim:
1005 # This file should be included verbatim
1006 if fn in OPTIONS.prohibit_verbatim:
1007 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
1008 print "send", fn, "verbatim"
1009 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001010 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001011 if fn in target_data.keys():
1012 AddToKnownPaths(fn, known_paths)
1013 elif tf.sha1 != sf.sha1:
1014 # File is different; consider sending as a patch
1015 diffs.append(common.Difference(tf, sf))
1016 else:
1017 # Target file data identical to source (may still be renamed)
1018 pass
1019
1020 common.ComputeDifferences(diffs)
1021
1022 for diff in diffs:
1023 tf, sf, d = diff.GetPatch()
1024 path = "/".join(tf.name.split("/")[:-1])
1025 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1026 path not in known_paths:
1027 # patch is almost as big as the file; don't bother patching
1028 # or a patch + rename cannot take place due to the target
1029 # directory not existing
1030 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001031 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001032 if sf.name in renames:
1033 del renames[sf.name]
1034 AddToKnownPaths(tf.name, known_paths)
1035 else:
1036 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1037 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1038 largest_source_size = max(largest_source_size, sf.size)
1039
1040 self.largest_source_size = largest_source_size
1041
1042 def EmitVerification(self, script):
1043 so_far = 0
Dan Albert8b72aef2015-03-23 19:13:21 -07001044 for tf, sf, _, _ in self.patch_list:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001045 if tf.name != sf.name:
1046 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1047 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1048 so_far += sf.size
1049 return so_far
1050
Michael Runge63f01de2014-10-28 19:24:19 -07001051 def EmitExplicitTargetVerification(self, script):
Dan Albert8b72aef2015-03-23 19:13:21 -07001052 for fn, _, sha1 in self.verbatim_targets:
1053 if fn[-1] != "/":
Michael Runge63f01de2014-10-28 19:24:19 -07001054 script.FileCheck("/"+fn, sha1)
1055 for tf, _, _, _ in self.patch_list:
1056 script.FileCheck(tf.name, tf.sha1)
1057
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001058 def RemoveUnneededFiles(self, script, extras=()):
Dan Albert8b72aef2015-03-23 19:13:21 -07001059 script.DeleteFiles(
1060 ["/" + i[0] for i in self.verbatim_targets] +
1061 ["/" + i for i in sorted(self.source_data)
1062 if i not in self.target_data and i not in self.renames] +
1063 list(extras))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001064
1065 def TotalPatchSize(self):
1066 return sum(i[1].size for i in self.patch_list)
1067
1068 def EmitPatches(self, script, total_patch_size, so_far):
1069 self.deferred_patch_list = deferred_patch_list = []
1070 for item in self.patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001071 tf, sf, _, _ = item
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001072 if tf.name == "system/build.prop":
1073 deferred_patch_list.append(item)
1074 continue
Dan Albert8b72aef2015-03-23 19:13:21 -07001075 if sf.name != tf.name:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001076 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
Dan Albert8b72aef2015-03-23 19:13:21 -07001077 script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1,
1078 "patch/" + sf.name + ".p")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001079 so_far += tf.size
1080 script.SetProgress(so_far / total_patch_size)
1081 return so_far
1082
1083 def EmitDeferredPatches(self, script):
1084 for item in self.deferred_patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001085 tf, sf, _, _ = item
1086 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1,
1087 "patch/" + sf.name + ".p")
1088 script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001089
1090 def EmitRenames(self, script):
1091 if len(self.renames) > 0:
1092 script.Print("Renaming files...")
1093 for src, tgt in self.renames.iteritems():
1094 print "Renaming " + src + " to " + tgt.name
1095 script.RenameFile(src, tgt.name)
1096
1097
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001098def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001099 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1100 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1101
Doug Zongker26e66192014-02-20 13:22:07 -08001102 if (OPTIONS.block_based and
1103 target_has_recovery_patch and
1104 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001105 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1106
Doug Zongker37974732010-09-16 17:44:38 -07001107 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1108 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001109
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001110 if source_version == 0:
1111 print ("WARNING: generating edify script for a source that "
1112 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -07001113 script = edify_generator.EdifyGenerator(source_version,
1114 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -07001115
Michael Runge6e836112014-04-15 17:40:21 -07001116 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001117 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001118 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001119 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001120 if OPTIONS.oem_source is None:
1121 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001122 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001123 oem_dict = common.LoadDictionaryFromLines(
1124 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001125
Dan Albert8b72aef2015-03-23 19:13:21 -07001126 metadata = {
1127 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1128 OPTIONS.source_info_dict),
1129 "post-timestamp": GetBuildProp("ro.build.date.utc",
1130 OPTIONS.target_info_dict),
1131 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001132
Doug Zongker05d3dea2009-06-22 11:32:31 -07001133 device_specific = common.DeviceSpecificParams(
1134 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001135 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001136 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001137 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001138 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001139 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001140 metadata=metadata,
1141 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001142
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001143 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001144 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001145 if HasVendorPartition(target_zip):
1146 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001147 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001148 else:
1149 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001150
Dan Albert8b72aef2015-03-23 19:13:21 -07001151 target_fp = CalculateFingerprint(oem_props, oem_dict,
1152 OPTIONS.target_info_dict)
1153 source_fp = CalculateFingerprint(oem_props, oem_dict,
1154 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001155
1156 if oem_props is None:
1157 script.AssertSomeFingerprint(source_fp, target_fp)
1158 else:
1159 script.AssertSomeThumbprint(
1160 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1161 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1162
Doug Zongker2ea21062010-04-28 16:05:21 -07001163 metadata["pre-build"] = source_fp
1164 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001165
Doug Zongker55d93282011-01-25 17:03:34 -08001166 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001167 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1168 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001169 target_boot = common.GetBootableImage(
1170 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001171 updating_boot = (not OPTIONS.two_step and
1172 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001173
Doug Zongker55d93282011-01-25 17:03:34 -08001174 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001175 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1176 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001177 target_recovery = common.GetBootableImage(
1178 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001179 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001180
Doug Zongker881dd402009-09-20 14:03:55 -07001181 # Here's how we divide up the progress bar:
1182 # 0.1 for verifying the start state (PatchCheck calls)
1183 # 0.8 for applying patches (ApplyPatch calls)
1184 # 0.1 for unpacking verbatim files, symlinking, and doing the
1185 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001186
Michael Runge6e836112014-04-15 17:40:21 -07001187 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001188 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001189
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001190 # Two-step incremental package strategy (in chronological order,
1191 # which is *not* the order in which the generated script has
1192 # things):
1193 #
1194 # if stage is not "2/3" or "3/3":
1195 # do verification on current system
1196 # write recovery image to boot partition
1197 # set stage to "2/3"
1198 # reboot to boot partition and restart recovery
1199 # else if stage is "2/3":
1200 # write recovery image to recovery partition
1201 # set stage to "3/3"
1202 # reboot to recovery partition and restart recovery
1203 # else:
1204 # (stage must be "3/3")
1205 # perform update:
1206 # patch system files, etc.
1207 # force full install of new boot image
1208 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001209 # complete script normally
1210 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001211
1212 if OPTIONS.two_step:
1213 if not OPTIONS.info_dict.get("multistage_support", None):
1214 assert False, "two-step packages not supported by this build"
1215 fs = OPTIONS.info_dict["fstab"]["/misc"]
1216 assert fs.fs_type.upper() == "EMMC", \
1217 "two-step packages only supported on devices with EMMC /misc partitions"
1218 bcb_dev = {"bcb_dev": fs.device}
1219 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1220 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001221if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001222""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001223 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001224 script.WriteRawImage("/recovery", "recovery.img")
1225 script.AppendExtra("""
1226set_stage("%(bcb_dev)s", "3/3");
1227reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001228else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001229""" % bcb_dev)
1230
Tao Bao6c55a8a2015-04-08 15:30:27 -07001231 # Dump fingerprints
1232 script.Print("Source: %s" % (source_fp,))
1233 script.Print("Target: %s" % (target_fp,))
1234
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001235 script.Print("Verifying current system...")
1236
Doug Zongkere5ff5902012-01-17 10:55:37 -08001237 device_specific.IncrementalOTA_VerifyBegin()
1238
Doug Zongker881dd402009-09-20 14:03:55 -07001239 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001240 so_far = system_diff.EmitVerification(script)
1241 if vendor_diff:
1242 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001243
Doug Zongker5da317e2009-06-02 13:38:17 -07001244 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001245 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001246 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001247 print "boot target: %d source: %d diff: %d" % (
1248 target_boot.size, source_boot.size, len(d))
1249
Doug Zongker048e7ca2009-06-15 14:31:53 -07001250 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001251
Doug Zongker96a57e72010-09-26 14:57:41 -07001252 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001253
1254 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1255 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001256 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001257 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001258 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001259
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001260 size = []
Dan Albert8b72aef2015-03-23 19:13:21 -07001261 if system_diff.patch_list:
1262 size.append(system_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001263 if vendor_diff:
Dan Albert8b72aef2015-03-23 19:13:21 -07001264 if vendor_diff.patch_list:
1265 size.append(vendor_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001266 if size or updating_recovery or updating_boot:
1267 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001268
Doug Zongker05d3dea2009-06-22 11:32:31 -07001269 device_specific.IncrementalOTA_VerifyEnd()
1270
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001271 if OPTIONS.two_step:
1272 script.WriteRawImage("/boot", "recovery.img")
1273 script.AppendExtra("""
1274set_stage("%(bcb_dev)s", "2/3");
1275reboot_now("%(bcb_dev)s", "");
1276else
1277""" % bcb_dev)
1278
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001279 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001280
Doug Zongkere5ff5902012-01-17 10:55:37 -08001281 device_specific.IncrementalOTA_InstallBegin()
1282
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001283 if OPTIONS.two_step:
1284 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1285 script.WriteRawImage("/boot", "boot.img")
1286 print "writing full boot image (forced by two-step mode)"
1287
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001288 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001289 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1290 if vendor_diff:
1291 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001292
Doug Zongker881dd402009-09-20 14:03:55 -07001293 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001294 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1295 if vendor_diff:
1296 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001297 if updating_boot:
1298 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001299
1300 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001301 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1302 if vendor_diff:
1303 script.Print("Patching vendor files...")
1304 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001305
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001306 if not OPTIONS.two_step:
1307 if updating_boot:
1308 # Produce the boot image by applying a patch to the current
1309 # contents of the boot partition, and write it back to the
1310 # partition.
1311 script.Print("Patching boot image...")
1312 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1313 % (boot_type, boot_device,
1314 source_boot.size, source_boot.sha1,
1315 target_boot.size, target_boot.sha1),
1316 "-",
1317 target_boot.size, target_boot.sha1,
1318 source_boot.sha1, "patch/boot.img.p")
1319 so_far += target_boot.size
1320 script.SetProgress(so_far / total_patch_size)
1321 print "boot image changed; including."
1322 else:
1323 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001324
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001325 system_items = ItemSet("system", "META/filesystem_config.txt")
1326 if vendor_diff:
1327 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1328
Doug Zongkereef39442009-04-02 12:14:19 -07001329 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001330 # Recovery is generated as a patch using both the boot image
1331 # (which contains the same linux kernel as recovery) and the file
1332 # /system/etc/recovery-resource.dat (which contains all the images
1333 # used in the recovery UI) as sources. This lets us minimize the
1334 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001335 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001336 # For older builds where recovery-resource.dat is not present, we
1337 # use only the boot image as the source.
1338
Doug Zongkerc9253822014-02-04 12:17:58 -08001339 if not target_has_recovery_patch:
1340 def output_sink(fn, data):
1341 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001342 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001343
1344 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1345 target_recovery, target_boot)
1346 script.DeleteFiles(["/system/recovery-from-boot.p",
1347 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001348 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001349 else:
1350 print "recovery image unchanged; skipping."
1351
Doug Zongker881dd402009-09-20 14:03:55 -07001352 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001353
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001354 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1355 if vendor_diff:
1356 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1357
1358 temp_script = script.MakeTemporary()
1359 system_items.GetMetadata(target_zip)
1360 system_items.Get("system").SetPermissions(temp_script)
1361 if vendor_diff:
1362 vendor_items.GetMetadata(target_zip)
1363 vendor_items.Get("vendor").SetPermissions(temp_script)
1364
1365 # Note that this call will mess up the trees of Items, so make sure
1366 # we're done with them.
1367 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1368 if vendor_diff:
1369 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001370
1371 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001372 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1373
1374 # Delete all the symlinks in source that aren't in target. This
1375 # needs to happen before verbatim files are unpacked, in case a
1376 # symlink in the source is replaced by a real file in the target.
1377 to_delete = []
1378 for dest, link in source_symlinks:
1379 if link not in target_symlinks_d:
1380 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001381 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001382
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001383 if system_diff.verbatim_targets:
1384 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001385 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001386 if vendor_diff and vendor_diff.verbatim_targets:
1387 script.Print("Unpacking new vendor files...")
1388 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001389
Doug Zongkerc9253822014-02-04 12:17:58 -08001390 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001391 script.Print("Unpacking new recovery...")
1392 script.UnpackPackageDir("recovery", "/system")
1393
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001394 system_diff.EmitRenames(script)
1395 if vendor_diff:
1396 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001397
Doug Zongker05d3dea2009-06-22 11:32:31 -07001398 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001399
1400 # Create all the symlinks that don't already exist, or point to
1401 # somewhere different than what we want. Delete each symlink before
1402 # creating it, since the 'symlink' command won't overwrite.
1403 to_create = []
1404 for dest, link in target_symlinks:
1405 if link in source_symlinks_d:
1406 if dest != source_symlinks_d[link]:
1407 to_create.append((dest, link))
1408 else:
1409 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001410 script.DeleteFiles([i[1] for i in to_create])
1411 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001412
1413 # Now that the symlinks are created, we can set all the
1414 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001415 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001416
Doug Zongker881dd402009-09-20 14:03:55 -07001417 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001418 device_specific.IncrementalOTA_InstallEnd()
1419
Doug Zongker1c390a22009-05-14 19:06:36 -07001420 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001421 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001422
Doug Zongkere92f15a2011-08-26 13:46:40 -07001423 # Patch the build.prop file last, so if something fails but the
1424 # device can still come up, it appears to be the old build and will
1425 # get set the OTA package again to retry.
1426 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001427 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001428
Doug Zongker922206e2014-03-04 13:16:24 -08001429 if OPTIONS.wipe_user_data:
1430 script.Print("Erasing user data...")
1431 script.FormatPartition("/data")
1432
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001433 if OPTIONS.two_step:
1434 script.AppendExtra("""
1435set_stage("%(bcb_dev)s", "");
1436endif;
1437endif;
1438""" % bcb_dev)
1439
Michael Runge63f01de2014-10-28 19:24:19 -07001440 if OPTIONS.verify and system_diff:
1441 script.Print("Remounting and verifying system partition files...")
1442 script.Unmount("/system")
1443 script.Mount("/system")
1444 system_diff.EmitExplicitTargetVerification(script)
1445
1446 if OPTIONS.verify and vendor_diff:
1447 script.Print("Remounting and verifying vendor partition files...")
1448 script.Unmount("/vendor")
1449 script.Mount("/vendor")
1450 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001451 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001452
Doug Zongker2ea21062010-04-28 16:05:21 -07001453 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001454
1455
1456def main(argv):
1457
1458 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001459 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001460 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001461 elif o in ("-k", "--package_key"):
1462 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001463 elif o in ("-i", "--incremental_from"):
1464 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001465 elif o == "--full_radio":
1466 OPTIONS.full_radio = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001467 elif o in ("-w", "--wipe_user_data"):
1468 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001469 elif o in ("-n", "--no_prereq"):
1470 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001471 elif o in ("-o", "--oem_settings"):
1472 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001473 elif o in ("-e", "--extra_script"):
1474 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001475 elif o in ("-a", "--aslr_mode"):
1476 if a in ("on", "On", "true", "True", "yes", "Yes"):
1477 OPTIONS.aslr_mode = True
1478 else:
1479 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001480 elif o in ("-t", "--worker_threads"):
1481 if a.isdigit():
1482 OPTIONS.worker_threads = int(a)
1483 else:
1484 raise ValueError("Cannot parse value %r for option %r - only "
1485 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001486 elif o in ("-2", "--two_step"):
1487 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001488 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001489 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001490 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001491 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001492 elif o == "--block":
1493 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001494 elif o in ("-b", "--binary"):
1495 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001496 elif o in ("--no_fallback_to_full",):
1497 OPTIONS.fallback_to_full = False
Doug Zongkereef39442009-04-02 12:14:19 -07001498 else:
1499 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001500 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001501
1502 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001503 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001504 extra_long_opts=[
1505 "board_config=",
1506 "package_key=",
1507 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001508 "full_radio",
Dan Albert8b72aef2015-03-23 19:13:21 -07001509 "wipe_user_data",
1510 "no_prereq",
1511 "extra_script=",
1512 "worker_threads=",
1513 "aslr_mode=",
1514 "two_step",
1515 "no_signing",
1516 "block",
1517 "binary=",
1518 "oem_settings=",
1519 "verify",
1520 "no_fallback_to_full",
1521 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001522
1523 if len(args) != 2:
1524 common.Usage(__doc__)
1525 sys.exit(1)
1526
Doug Zongker1c390a22009-05-14 19:06:36 -07001527 if OPTIONS.extra_script is not None:
1528 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1529
Doug Zongkereef39442009-04-02 12:14:19 -07001530 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001531 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001532
Doug Zongkereef39442009-04-02 12:14:19 -07001533 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001534 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001535
1536 # If this image was originally labelled with SELinux contexts, make sure we
1537 # also apply the labels in our new image. During building, the "file_contexts"
1538 # is in the out/ directory tree, but for repacking from target-files.zip it's
1539 # in the root directory of the ramdisk.
1540 if "selinux_fc" in OPTIONS.info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001541 OPTIONS.info_dict["selinux_fc"] = os.path.join(
1542 OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")
Kenny Roote2e9f612013-05-29 12:59:35 -07001543
Doug Zongker37974732010-09-16 17:44:38 -07001544 if OPTIONS.verbose:
1545 print "--- target info ---"
1546 common.DumpInfoDict(OPTIONS.info_dict)
1547
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001548 # If the caller explicitly specified the device-specific extensions
1549 # path via -s/--device_specific, use that. Otherwise, use
1550 # META/releasetools.py if it is present in the target target_files.
1551 # Otherwise, take the path of the file from 'tool_extensions' in the
1552 # info dict and look for that in the local filesystem, relative to
1553 # the current directory.
1554
Doug Zongker37974732010-09-16 17:44:38 -07001555 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001556 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1557 if os.path.exists(from_input):
1558 print "(using device-specific extensions from target_files)"
1559 OPTIONS.device_specific = from_input
1560 else:
1561 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1562
Doug Zongker37974732010-09-16 17:44:38 -07001563 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001564 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001565
Doug Zongker62d4f182014-08-04 16:06:43 -07001566 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001567
Doug Zongker62d4f182014-08-04 16:06:43 -07001568 if OPTIONS.no_signing:
Dan Albert8b72aef2015-03-23 19:13:21 -07001569 if os.path.exists(args[1]):
1570 os.unlink(args[1])
1571 output_zip = zipfile.ZipFile(args[1], "w",
1572 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001573 else:
1574 temp_zip_file = tempfile.NamedTemporaryFile()
1575 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1576 compression=zipfile.ZIP_DEFLATED)
1577
1578 if OPTIONS.incremental_source is None:
1579 WriteFullOTAPackage(input_zip, output_zip)
1580 if OPTIONS.package_key is None:
1581 OPTIONS.package_key = OPTIONS.info_dict.get(
1582 "default_system_dev_certificate",
1583 "build/target/product/security/testkey")
1584 break
1585
1586 else:
1587 print "unzipping source target-files..."
Dan Albert8b72aef2015-03-23 19:13:21 -07001588 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
1589 OPTIONS.incremental_source)
Doug Zongker62d4f182014-08-04 16:06:43 -07001590 OPTIONS.target_info_dict = OPTIONS.info_dict
1591 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1592 if "selinux_fc" in OPTIONS.source_info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001593 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(
1594 OPTIONS.source_tmp, "BOOT", "RAMDISK", "file_contexts")
Doug Zongker62d4f182014-08-04 16:06:43 -07001595 if OPTIONS.package_key is None:
1596 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1597 "default_system_dev_certificate",
1598 "build/target/product/security/testkey")
1599 if OPTIONS.verbose:
1600 print "--- source info ---"
1601 common.DumpInfoDict(OPTIONS.source_info_dict)
1602 try:
1603 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
1604 break
1605 except ValueError:
Dan Albert8b72aef2015-03-23 19:13:21 -07001606 if not OPTIONS.fallback_to_full:
1607 raise
Doug Zongker62d4f182014-08-04 16:06:43 -07001608 print "--- failed to build incremental; falling back to full ---"
1609 OPTIONS.incremental_source = None
1610 output_zip.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001611
1612 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001613
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001614 if not OPTIONS.no_signing:
1615 SignOutput(temp_zip_file.name, args[1])
1616 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001617
Doug Zongkereef39442009-04-02 12:14:19 -07001618 print "done."
1619
1620
1621if __name__ == '__main__':
1622 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001623 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001624 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001625 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07001626 print
1627 print " ERROR: %s" % (e,)
1628 print
1629 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001630 finally:
1631 common.Cleanup()