blob: b0913e457b8d4b78c7f7dba9cc13fae5a22cf54a [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
Doug Zongkerfc44a512014-08-26 13:10:25 -070095import multiprocessing
Doug Zongkereef39442009-04-02 12:14:19 -070096import os
Doug Zongkereef39442009-04-02 12:14:19 -070097import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -070098import zipfile
99
100import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700101import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -0700102import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700103
104OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700105OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700106OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700107OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700108OPTIONS.require_verbatim = set()
109OPTIONS.prohibit_verbatim = set(("system/build.prop",))
110OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700111OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700112OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700113OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700114OPTIONS.aslr_mode = True
Doug Zongkerfc44a512014-08-26 13:10:25 -0700115OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
116if OPTIONS.worker_threads == 0:
117 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800118OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900119OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800120OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800121OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700122OPTIONS.oem_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -0700123OPTIONS.fallback_to_full = True
Tao Bao43078aa2015-04-21 14:32:35 -0700124OPTIONS.full_radio = False
Doug Zongkereef39442009-04-02 12:14:19 -0700125
126def MostPopularKey(d, default):
127 """Given a dict, return the key corresponding to the largest
128 value. Returns 'default' if the dict is empty."""
129 x = [(v, k) for (k, v) in d.iteritems()]
Dan Albert8b72aef2015-03-23 19:13:21 -0700130 if not x:
131 return default
Doug Zongkereef39442009-04-02 12:14:19 -0700132 x.sort()
133 return x[-1][1]
134
135
136def IsSymlink(info):
137 """Return true if the zipfile.ZipInfo object passed in represents a
138 symlink."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700139 return (info.external_attr >> 16) == 0o120777
Doug Zongkereef39442009-04-02 12:14:19 -0700140
Hristo Bojinov96be7202010-08-02 10:26:17 -0700141def IsRegular(info):
142 """Return true if the zipfile.ZipInfo object passed in represents a
143 symlink."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700144 return (info.external_attr >> 28) == 0o10
Doug Zongkereef39442009-04-02 12:14:19 -0700145
Michael Runge4038aa82013-12-13 18:06:28 -0800146def ClosestFileMatch(src, tgtfiles, existing):
147 """Returns the closest file match between a source file and list
148 of potential matches. The exact filename match is preferred,
149 then the sha1 is searched for, and finally a file with the same
150 basename is evaluated. Rename support in the updater-binary is
151 required for the latter checks to be used."""
152
153 result = tgtfiles.get("path:" + src.name)
154 if result is not None:
155 return result
156
157 if not OPTIONS.target_info_dict.get("update_rename_support", False):
158 return None
159
160 if src.size < 1000:
161 return None
162
163 result = tgtfiles.get("sha1:" + src.sha1)
164 if result is not None and existing.get(result.name) is None:
165 return result
166 result = tgtfiles.get("file:" + src.name.split("/")[-1])
167 if result is not None and existing.get(result.name) is None:
168 return result
169 return None
170
Dan Albert8b72aef2015-03-23 19:13:21 -0700171class ItemSet(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700172 def __init__(self, partition, fs_config):
173 self.partition = partition
174 self.fs_config = fs_config
175 self.ITEMS = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700176
Dan Albert8b72aef2015-03-23 19:13:21 -0700177 def Get(self, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700178 if name not in self.ITEMS:
Dan Albert8b72aef2015-03-23 19:13:21 -0700179 self.ITEMS[name] = Item(self, name, is_dir=is_dir)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700180 return self.ITEMS[name]
Doug Zongkereef39442009-04-02 12:14:19 -0700181
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700182 def GetMetadata(self, input_zip):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700183 # The target_files contains a record of what the uid,
184 # gid, and mode are supposed to be.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700185 output = input_zip.read(self.fs_config)
Doug Zongkereef39442009-04-02 12:14:19 -0700186
187 for line in output.split("\n"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700188 if not line:
189 continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700190 columns = line.split()
191 name, uid, gid, mode = columns[:4]
192 selabel = None
193 capabilities = None
194
195 # After the first 4 columns, there are a series of key=value
196 # pairs. Extract out the fields we care about.
197 for element in columns[4:]:
198 key, value = element.split("=")
199 if key == "selabel":
200 selabel = value
201 if key == "capabilities":
202 capabilities = value
203
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700204 i = self.ITEMS.get(name, None)
Doug Zongker283e2a12010-03-15 17:52:32 -0700205 if i is not None:
206 i.uid = int(uid)
207 i.gid = int(gid)
208 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700209 i.selabel = selabel
210 i.capabilities = capabilities
Dan Albert8b72aef2015-03-23 19:13:21 -0700211 if i.is_dir:
Doug Zongker283e2a12010-03-15 17:52:32 -0700212 i.children.sort(key=lambda i: i.name)
213
214 # set metadata for the files generated by this script.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700215 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700216 if i:
217 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700218 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700219 if i:
220 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700221
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700222
Dan Albert8b72aef2015-03-23 19:13:21 -0700223class Item(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700224 """Items represent the metadata (user, group, mode) of files and
225 directories in the system image."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700226 def __init__(self, itemset, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700227 self.itemset = itemset
228 self.name = name
229 self.uid = None
230 self.gid = None
231 self.mode = None
232 self.selabel = None
233 self.capabilities = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700234 self.is_dir = is_dir
235 self.descendants = None
236 self.best_subtree = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700237
238 if name:
Dan Albert8b72aef2015-03-23 19:13:21 -0700239 self.parent = itemset.Get(os.path.dirname(name), is_dir=True)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700240 self.parent.children.append(self)
241 else:
242 self.parent = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700243 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700244 self.children = []
245
246 def Dump(self, indent=0):
247 if self.uid is not None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700248 print "%s%s %d %d %o" % (
249 " " * indent, self.name, self.uid, self.gid, self.mode)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700250 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700251 print "%s%s %s %s %s" % (
252 " " * indent, self.name, self.uid, self.gid, self.mode)
253 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700254 print "%s%s" % (" "*indent, self.descendants)
255 print "%s%s" % (" "*indent, self.best_subtree)
256 for i in self.children:
257 i.Dump(indent=indent+1)
258
Doug Zongkereef39442009-04-02 12:14:19 -0700259 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700260 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
Dan Albert8b72aef2015-03-23 19:13:21 -0700261 all children and determine the best strategy for using set_perm_recursive
262 and set_perm to correctly chown/chmod all the files to their desired
Doug Zongkereef39442009-04-02 12:14:19 -0700263 values. Recursively calls itself for all descendants.
264
Dan Albert8b72aef2015-03-23 19:13:21 -0700265 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count}
266 counting up all descendants of this node. (dmode or fmode may be None.)
267 Also sets the best_subtree of each directory Item to the (uid, gid, dmode,
268 fmode, selabel, capabilities) tuple that will match the most descendants of
269 that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700270 """
271
Dan Albert8b72aef2015-03-23 19:13:21 -0700272 assert self.is_dir
273 key = (self.uid, self.gid, self.mode, None, self.selabel,
274 self.capabilities)
275 self.descendants = {key: 1}
276 d = self.descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700277 for i in self.children:
Dan Albert8b72aef2015-03-23 19:13:21 -0700278 if i.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700279 for k, v in i.CountChildMetadata().iteritems():
280 d[k] = d.get(k, 0) + v
281 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700282 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700283 d[k] = d.get(k, 0) + 1
284
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700285 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
286 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700287
288 # First, find the (uid, gid) pair that matches the most
289 # descendants.
290 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700291 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700292 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
293 ug = MostPopularKey(ug, (0, 0))
294
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700295 # Now find the dmode, fmode, selabel, and capabilities that match
296 # the most descendants with that (uid, gid), and choose those.
Dan Albert8b72aef2015-03-23 19:13:21 -0700297 best_dmode = (0, 0o755)
298 best_fmode = (0, 0o644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700299 best_selabel = (0, None)
300 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700301 for k, count in d.iteritems():
Dan Albert8b72aef2015-03-23 19:13:21 -0700302 if k[:2] != ug:
303 continue
304 if k[2] is not None and count >= best_dmode[0]:
305 best_dmode = (count, k[2])
306 if k[3] is not None and count >= best_fmode[0]:
307 best_fmode = (count, k[3])
308 if k[4] is not None and count >= best_selabel[0]:
309 best_selabel = (count, k[4])
310 if k[5] is not None and count >= best_capabilities[0]:
311 best_capabilities = (count, k[5])
312 self.best_subtree = ug + (
313 best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700314
315 return d
316
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700317 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700318 """Append set_perm/set_perm_recursive commands to 'script' to
319 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700320 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700321
322 self.CountChildMetadata()
323
324 def recurse(item, current):
Dan Albert8b72aef2015-03-23 19:13:21 -0700325 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple
326 # that the current item (and all its children) have already been set to.
327 # We only need to issue set_perm/set_perm_recursive commands if we're
Doug Zongkereef39442009-04-02 12:14:19 -0700328 # supposed to be something different.
Dan Albert8b72aef2015-03-23 19:13:21 -0700329 if item.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700330 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700331 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700332 current = item.best_subtree
333
334 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700335 item.mode != current[2] or item.selabel != current[4] or \
336 item.capabilities != current[5]:
337 script.SetPermissions("/"+item.name, item.uid, item.gid,
338 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700339
340 for i in item.children:
341 recurse(i, current)
342 else:
343 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700344 item.mode != current[3] or item.selabel != current[4] or \
345 item.capabilities != current[5]:
346 script.SetPermissions("/"+item.name, item.uid, item.gid,
347 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700348
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700349 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700350
351
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700352def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
353 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700354 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800355 list of symlinks. output_zip may be None, in which case the copy is
356 skipped (but the other side effects still happen). substitute is an
357 optional dict of {output filename: contents} to be output instead of
358 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700359 """
360
361 symlinks = []
362
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700363 partition = itemset.partition
364
Doug Zongkereef39442009-04-02 12:14:19 -0700365 for info in input_zip.infolist():
Tao Baoeaf885b2015-03-23 16:01:17 -0700366 prefix = partition.upper() + "/"
367 if info.filename.startswith(prefix):
368 basefilename = info.filename[len(prefix):]
Doug Zongkereef39442009-04-02 12:14:19 -0700369 if IsSymlink(info):
370 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700371 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700372 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700373 import copy
Doug Zongkereef39442009-04-02 12:14:19 -0700374 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)
Tao Bao2ed665a2015-04-01 11:21:55 -0700383 common.ZipWriteStr(output_zip, info2, data)
Doug Zongkereef39442009-04-02 12:14:19 -0700384 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
Tao Baoff777812015-05-12 11:42:31 -0700478 # Bug: http://b/20939131
479 # In ext4 filesystems, block 0 might be changed even being mounted
480 # R/O. We add it to clobbered_blocks so that it will be written to the
481 # target unconditionally. Note that they are still part of care_map.
482 clobbered_blocks = "0"
483
484 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700485
486
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700487def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700488 # TODO: how to determine this? We don't know what version it will
489 # be installed on top of. For now, we expect the API just won't
490 # change very often.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700491 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700492
Michael Runge6e836112014-04-15 17:40:21 -0700493 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700494 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700495 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700496 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700497 if OPTIONS.oem_source is None:
498 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700499 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700500 oem_dict = common.LoadDictionaryFromLines(
501 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -0700502
Dan Albert8b72aef2015-03-23 19:13:21 -0700503 metadata = {
504 "post-build": CalculateFingerprint(oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700505 OPTIONS.info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700506 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
507 OPTIONS.info_dict),
508 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
509 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700510
Doug Zongker05d3dea2009-06-22 11:32:31 -0700511 device_specific = common.DeviceSpecificParams(
512 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700513 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700514 output_zip=output_zip,
515 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700516 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700517 metadata=metadata,
518 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700519
Doug Zongkerc9253822014-02-04 12:17:58 -0800520 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800521 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800522
Doug Zongker962069c2009-04-23 11:41:58 -0700523 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700524 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700525 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
526 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700527
Michael Runge6e836112014-04-15 17:40:21 -0700528 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700529 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800530
531 # Two-step package strategy (in chronological order, which is *not*
532 # the order in which the generated script has things):
533 #
534 # if stage is not "2/3" or "3/3":
535 # write recovery image to boot partition
536 # set stage to "2/3"
537 # reboot to boot partition and restart recovery
538 # else if stage is "2/3":
539 # write recovery image to recovery partition
540 # set stage to "3/3"
541 # reboot to recovery partition and restart recovery
542 # else:
543 # (stage must be "3/3")
544 # set stage to ""
545 # do normal full package installation:
546 # wipe and install system, boot image, etc.
547 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700548 # complete script normally
549 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800550
551 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
552 OPTIONS.input_tmp, "RECOVERY")
553 if OPTIONS.two_step:
554 if not OPTIONS.info_dict.get("multistage_support", None):
555 assert False, "two-step packages not supported by this build"
556 fs = OPTIONS.info_dict["fstab"]["/misc"]
557 assert fs.fs_type.upper() == "EMMC", \
558 "two-step packages only supported on devices with EMMC /misc partitions"
559 bcb_dev = {"bcb_dev": fs.device}
560 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
561 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700562if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800563""" % bcb_dev)
564 script.WriteRawImage("/recovery", "recovery.img")
565 script.AppendExtra("""
566set_stage("%(bcb_dev)s", "3/3");
567reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700568else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800569""" % bcb_dev)
570
Tao Bao6c55a8a2015-04-08 15:30:27 -0700571 # Dump fingerprints
572 script.Print("Target: %s" % CalculateFingerprint(
573 oem_props, oem_dict, OPTIONS.info_dict))
574
Doug Zongkere5ff5902012-01-17 10:55:37 -0800575 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700576
Doug Zongker01ce19c2014-02-04 13:48:15 -0800577 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700578
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700579 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800580 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700581 if HasVendorPartition(input_zip):
582 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700583
Kenny Rootf32dc712012-04-08 10:42:34 -0700584 if "selinux_fc" in OPTIONS.info_dict:
585 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500586
Michael Runge7cd99ba2014-10-22 17:21:48 -0700587 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
588
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700589 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700590 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800591
Doug Zongker26e66192014-02-20 13:22:07 -0800592 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700593 # Full OTA is done as an "incremental" against an empty source
594 # image. This has the effect of writing new data from the package
595 # to the entire partition, but lets us reuse the updater code that
596 # writes incrementals to do it.
597 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
598 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700599 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700600 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800601 else:
602 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700603 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800604 if not has_recovery_patch:
605 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800606 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700607
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700608 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800609 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700610
Doug Zongker55d93282011-01-25 17:03:34 -0800611 boot_img = common.GetBootableImage("boot.img", "boot.img",
612 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800613
Doug Zongker91a99c22014-05-09 13:15:01 -0700614 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800615 def output_sink(fn, data):
616 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700617 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800618
619 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
620 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700621
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700622 system_items.GetMetadata(input_zip)
623 system_items.Get("system").SetPermissions(script)
624
625 if HasVendorPartition(input_zip):
626 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
627 script.ShowProgress(0.1, 0)
628
629 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700630 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
631 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700632 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700633 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700634 else:
635 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700636 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700637 script.UnpackPackageDir("vendor", "/vendor")
638
639 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
640 script.MakeSymlinks(symlinks)
641
642 vendor_items.GetMetadata(input_zip)
643 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700644
Doug Zongker37974732010-09-16 17:44:38 -0700645 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700646 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700647
Doug Zongker01ce19c2014-02-04 13:48:15 -0800648 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700649 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700650
Doug Zongker01ce19c2014-02-04 13:48:15 -0800651 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700652 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700653
Doug Zongker1c390a22009-05-14 19:06:36 -0700654 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700655 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700656
Doug Zongker14833602010-02-02 13:12:04 -0800657 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800658
Doug Zongker922206e2014-03-04 13:16:24 -0800659 if OPTIONS.wipe_user_data:
660 script.ShowProgress(0.1, 10)
661 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700662
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800663 if OPTIONS.two_step:
664 script.AppendExtra("""
665set_stage("%(bcb_dev)s", "");
666""" % bcb_dev)
667 script.AppendExtra("else\n")
668 script.WriteRawImage("/boot", "recovery.img")
669 script.AppendExtra("""
670set_stage("%(bcb_dev)s", "2/3");
671reboot_now("%(bcb_dev)s", "");
672endif;
673endif;
674""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800675 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700676 WriteMetadata(metadata, output_zip)
677
Doug Zongkerfc44a512014-08-26 13:10:25 -0700678
Dan Albert8e0178d2015-01-27 15:53:15 -0800679def WritePolicyConfig(file_name, output_zip):
680 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500681
Doug Zongker2ea21062010-04-28 16:05:21 -0700682
683def WriteMetadata(metadata, output_zip):
684 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
685 "".join(["%s=%s\n" % kv
686 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700687
Doug Zongkerfc44a512014-08-26 13:10:25 -0700688
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700689def LoadPartitionFiles(z, partition):
690 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700691 ZipFile, and return a dict of {filename: File object}."""
692 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700693 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700694 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700695 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700696 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700697 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700698 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700699 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800700 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700701
702
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700703def GetBuildProp(prop, info_dict):
704 """Return the fingerprint of the build of a given target-files info_dict."""
705 try:
706 return info_dict.get("build.prop", {})[prop]
707 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700708 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700709
Doug Zongkerfc44a512014-08-26 13:10:25 -0700710
Michael Runge4038aa82013-12-13 18:06:28 -0800711def AddToKnownPaths(filename, known_paths):
712 if filename[-1] == "/":
713 return
714 dirs = filename.split("/")[:-1]
715 while len(dirs) > 0:
716 path = "/".join(dirs)
717 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700718 break
Michael Runge4038aa82013-12-13 18:06:28 -0800719 known_paths.add(path)
720 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700721
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700722
Geremy Condra36bd3652014-02-06 19:45:10 -0800723def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
724 source_version = OPTIONS.source_info_dict["recovery_api_version"]
725 target_version = OPTIONS.target_info_dict["recovery_api_version"]
726
727 if source_version == 0:
728 print ("WARNING: generating edify script for a source that "
729 "can't install it.")
730 script = edify_generator.EdifyGenerator(source_version,
731 OPTIONS.target_info_dict)
732
Dan Albert8b72aef2015-03-23 19:13:21 -0700733 metadata = {
734 "pre-device": GetBuildProp("ro.product.device",
735 OPTIONS.source_info_dict),
736 "post-timestamp": GetBuildProp("ro.build.date.utc",
737 OPTIONS.target_info_dict),
738 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800739
740 device_specific = common.DeviceSpecificParams(
741 source_zip=source_zip,
742 source_version=source_version,
743 target_zip=target_zip,
744 target_version=target_version,
745 output_zip=output_zip,
746 script=script,
747 metadata=metadata,
748 info_dict=OPTIONS.info_dict)
749
Tao Bao6c55a8a2015-04-08 15:30:27 -0700750 # TODO: Currently this works differently from WriteIncrementalOTAPackage().
751 # This function doesn't consider thumbprints when writing
752 # metadata["pre/post-build"]. One possible reason is that the current
753 # devices with thumbprints are all using file-based OTAs. Long term we
754 # should factor out the common parts into a shared one to avoid further
755 # divergence.
Geremy Condra36bd3652014-02-06 19:45:10 -0800756 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
757 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
758 metadata["pre-build"] = source_fp
759 metadata["post-build"] = target_fp
760
761 source_boot = common.GetBootableImage(
762 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
763 OPTIONS.source_info_dict)
764 target_boot = common.GetBootableImage(
765 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
766 updating_boot = (not OPTIONS.two_step and
767 (source_boot.data != target_boot.data))
768
Geremy Condra36bd3652014-02-06 19:45:10 -0800769 target_recovery = common.GetBootableImage(
770 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800771
Doug Zongkerfc44a512014-08-26 13:10:25 -0700772 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
773 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700774
775 blockimgdiff_version = 1
776 if OPTIONS.info_dict:
777 blockimgdiff_version = max(
778 int(i) for i in
779 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
780
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700781 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700782 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700783
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700784 if HasVendorPartition(target_zip):
785 if not HasVendorPartition(source_zip):
786 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700787 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
788 OPTIONS.source_info_dict)
789 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
790 OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700791 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700792 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700793 else:
794 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800795
Michael Rungec6e3afd2014-05-05 11:55:47 -0700796 oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
Dan Albert8b72aef2015-03-23 19:13:21 -0700797 recovery_mount_options = OPTIONS.target_info_dict.get(
798 "recovery_mount_options")
Michael Rungec6e3afd2014-05-05 11:55:47 -0700799 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700800 if oem_props is not None and len(oem_props) > 0:
Michael Rungec6e3afd2014-05-05 11:55:47 -0700801 if OPTIONS.oem_source is None:
802 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700803 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700804 oem_dict = common.LoadDictionaryFromLines(
805 open(OPTIONS.oem_source).readlines())
Michael Rungec6e3afd2014-05-05 11:55:47 -0700806
807 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800808 device_specific.IncrementalOTA_Assertions()
809
810 # Two-step incremental package strategy (in chronological order,
811 # which is *not* the order in which the generated script has
812 # things):
813 #
814 # if stage is not "2/3" or "3/3":
815 # do verification on current system
816 # write recovery image to boot partition
817 # set stage to "2/3"
818 # reboot to boot partition and restart recovery
819 # else if stage is "2/3":
820 # write recovery image to recovery partition
821 # set stage to "3/3"
822 # reboot to recovery partition and restart recovery
823 # else:
824 # (stage must be "3/3")
825 # perform update:
826 # patch system files, etc.
827 # force full install of new boot image
828 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700829 # complete script normally
830 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800831
832 if OPTIONS.two_step:
833 if not OPTIONS.info_dict.get("multistage_support", None):
834 assert False, "two-step packages not supported by this build"
835 fs = OPTIONS.info_dict["fstab"]["/misc"]
836 assert fs.fs_type.upper() == "EMMC", \
837 "two-step packages only supported on devices with EMMC /misc partitions"
838 bcb_dev = {"bcb_dev": fs.device}
839 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
840 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700841if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800842""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -0700843 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800844 script.WriteRawImage("/recovery", "recovery.img")
845 script.AppendExtra("""
846set_stage("%(bcb_dev)s", "3/3");
847reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700848else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800849""" % bcb_dev)
850
Tao Bao6c55a8a2015-04-08 15:30:27 -0700851 # Dump fingerprints
852 script.Print("Source: %s" % CalculateFingerprint(
853 oem_props, oem_dict, OPTIONS.source_info_dict))
854 script.Print("Target: %s" % CalculateFingerprint(
855 oem_props, oem_dict, OPTIONS.target_info_dict))
856
Geremy Condra36bd3652014-02-06 19:45:10 -0800857 script.Print("Verifying current system...")
858
859 device_specific.IncrementalOTA_VerifyBegin()
860
Michael Rungec6e3afd2014-05-05 11:55:47 -0700861 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700862 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
863 # patching on a device that's already on the target build will damage the
864 # system. Because operations like move don't check the block state, they
865 # always apply the changes unconditionally.
866 if blockimgdiff_version <= 2:
867 script.AssertSomeFingerprint(source_fp)
868 else:
869 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700870 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700871 if blockimgdiff_version <= 2:
872 script.AssertSomeThumbprint(
873 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
874 else:
875 script.AssertSomeThumbprint(
876 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
877 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800878
879 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700880 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800881 d = common.Difference(target_boot, source_boot)
882 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700883 if d is None:
884 include_full_boot = True
885 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
886 else:
887 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800888
Doug Zongkerf8340082014-08-05 10:39:37 -0700889 print "boot target: %d source: %d diff: %d" % (
890 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800891
Doug Zongkerf8340082014-08-05 10:39:37 -0700892 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800893
Doug Zongkerf8340082014-08-05 10:39:37 -0700894 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
895 (boot_type, boot_device,
896 source_boot.size, source_boot.sha1,
897 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800898
899 device_specific.IncrementalOTA_VerifyEnd()
900
901 if OPTIONS.two_step:
902 script.WriteRawImage("/boot", "recovery.img")
903 script.AppendExtra("""
904set_stage("%(bcb_dev)s", "2/3");
905reboot_now("%(bcb_dev)s", "");
906else
907""" % bcb_dev)
908
Jesse Zhao75bcea02015-01-06 10:59:53 -0800909 # Verify the existing partitions.
910 system_diff.WriteVerifyScript(script)
911 if vendor_diff:
912 vendor_diff.WriteVerifyScript(script)
913
Geremy Condra36bd3652014-02-06 19:45:10 -0800914 script.Comment("---- start making changes here ----")
915
916 device_specific.IncrementalOTA_InstallBegin()
917
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700918 system_diff.WriteScript(script, output_zip,
919 progress=0.8 if vendor_diff else 0.9)
Tao Bao68658c02015-06-01 13:40:49 -0700920
Doug Zongkerfc44a512014-08-26 13:10:25 -0700921 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700922 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800923
924 if OPTIONS.two_step:
925 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
926 script.WriteRawImage("/boot", "boot.img")
927 print "writing full boot image (forced by two-step mode)"
928
929 if not OPTIONS.two_step:
930 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700931 if include_full_boot:
932 print "boot image changed; including full."
933 script.Print("Installing boot image...")
934 script.WriteRawImage("/boot", "boot.img")
935 else:
936 # Produce the boot image by applying a patch to the current
937 # contents of the boot partition, and write it back to the
938 # partition.
939 print "boot image changed; including patch."
940 script.Print("Patching boot image...")
941 script.ShowProgress(0.1, 10)
942 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
943 % (boot_type, boot_device,
944 source_boot.size, source_boot.sha1,
945 target_boot.size, target_boot.sha1),
946 "-",
947 target_boot.size, target_boot.sha1,
948 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800949 else:
950 print "boot image unchanged; skipping."
951
952 # Do device-specific installation (eg, write radio image).
953 device_specific.IncrementalOTA_InstallEnd()
954
955 if OPTIONS.extra_script is not None:
956 script.AppendExtra(OPTIONS.extra_script)
957
Doug Zongker922206e2014-03-04 13:16:24 -0800958 if OPTIONS.wipe_user_data:
959 script.Print("Erasing user data...")
960 script.FormatPartition("/data")
961
Geremy Condra36bd3652014-02-06 19:45:10 -0800962 if OPTIONS.two_step:
963 script.AppendExtra("""
964set_stage("%(bcb_dev)s", "");
965endif;
966endif;
967""" % bcb_dev)
968
969 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800970 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800971 WriteMetadata(metadata, output_zip)
972
Doug Zongker32b527d2014-03-04 10:03:02 -0800973
Dan Albert8b72aef2015-03-23 19:13:21 -0700974class FileDifference(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700975 def __init__(self, partition, source_zip, target_zip, output_zip):
Dan Albert8b72aef2015-03-23 19:13:21 -0700976 self.deferred_patch_list = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700977 print "Loading target..."
978 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
979 print "Loading source..."
980 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
981
982 self.verbatim_targets = verbatim_targets = []
983 self.patch_list = patch_list = []
984 diffs = []
985 self.renames = renames = {}
986 known_paths = set()
987 largest_source_size = 0
988
989 matching_file_cache = {}
990 for fn, sf in source_data.items():
991 assert fn == sf.name
992 matching_file_cache["path:" + fn] = sf
993 if fn in target_data.keys():
994 AddToKnownPaths(fn, known_paths)
995 # Only allow eligibility for filename/sha matching
996 # if there isn't a perfect path match.
997 if target_data.get(sf.name) is None:
998 matching_file_cache["file:" + fn.split("/")[-1]] = sf
999 matching_file_cache["sha:" + sf.sha1] = sf
1000
1001 for fn in sorted(target_data.keys()):
1002 tf = target_data[fn]
1003 assert fn == tf.name
1004 sf = ClosestFileMatch(tf, matching_file_cache, renames)
1005 if sf is not None and sf.name != tf.name:
1006 print "File has moved from " + sf.name + " to " + tf.name
1007 renames[sf.name] = tf
1008
1009 if sf is None or fn in OPTIONS.require_verbatim:
1010 # This file should be included verbatim
1011 if fn in OPTIONS.prohibit_verbatim:
1012 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
1013 print "send", fn, "verbatim"
1014 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001015 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001016 if fn in target_data.keys():
1017 AddToKnownPaths(fn, known_paths)
1018 elif tf.sha1 != sf.sha1:
1019 # File is different; consider sending as a patch
1020 diffs.append(common.Difference(tf, sf))
1021 else:
1022 # Target file data identical to source (may still be renamed)
1023 pass
1024
1025 common.ComputeDifferences(diffs)
1026
1027 for diff in diffs:
1028 tf, sf, d = diff.GetPatch()
1029 path = "/".join(tf.name.split("/")[:-1])
1030 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1031 path not in known_paths:
1032 # patch is almost as big as the file; don't bother patching
1033 # or a patch + rename cannot take place due to the target
1034 # directory not existing
1035 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001036 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001037 if sf.name in renames:
1038 del renames[sf.name]
1039 AddToKnownPaths(tf.name, known_paths)
1040 else:
1041 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1042 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1043 largest_source_size = max(largest_source_size, sf.size)
1044
1045 self.largest_source_size = largest_source_size
1046
1047 def EmitVerification(self, script):
1048 so_far = 0
Dan Albert8b72aef2015-03-23 19:13:21 -07001049 for tf, sf, _, _ in self.patch_list:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001050 if tf.name != sf.name:
1051 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1052 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1053 so_far += sf.size
1054 return so_far
1055
Michael Runge63f01de2014-10-28 19:24:19 -07001056 def EmitExplicitTargetVerification(self, script):
Dan Albert8b72aef2015-03-23 19:13:21 -07001057 for fn, _, sha1 in self.verbatim_targets:
1058 if fn[-1] != "/":
Michael Runge63f01de2014-10-28 19:24:19 -07001059 script.FileCheck("/"+fn, sha1)
1060 for tf, _, _, _ in self.patch_list:
1061 script.FileCheck(tf.name, tf.sha1)
1062
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001063 def RemoveUnneededFiles(self, script, extras=()):
Dan Albert8b72aef2015-03-23 19:13:21 -07001064 script.DeleteFiles(
1065 ["/" + i[0] for i in self.verbatim_targets] +
1066 ["/" + i for i in sorted(self.source_data)
1067 if i not in self.target_data and i not in self.renames] +
1068 list(extras))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001069
1070 def TotalPatchSize(self):
1071 return sum(i[1].size for i in self.patch_list)
1072
1073 def EmitPatches(self, script, total_patch_size, so_far):
1074 self.deferred_patch_list = deferred_patch_list = []
1075 for item in self.patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001076 tf, sf, _, _ = item
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001077 if tf.name == "system/build.prop":
1078 deferred_patch_list.append(item)
1079 continue
Dan Albert8b72aef2015-03-23 19:13:21 -07001080 if sf.name != tf.name:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001081 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
Dan Albert8b72aef2015-03-23 19:13:21 -07001082 script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1,
1083 "patch/" + sf.name + ".p")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001084 so_far += tf.size
1085 script.SetProgress(so_far / total_patch_size)
1086 return so_far
1087
1088 def EmitDeferredPatches(self, script):
1089 for item in self.deferred_patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001090 tf, sf, _, _ = item
1091 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1,
1092 "patch/" + sf.name + ".p")
1093 script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001094
1095 def EmitRenames(self, script):
1096 if len(self.renames) > 0:
1097 script.Print("Renaming files...")
1098 for src, tgt in self.renames.iteritems():
1099 print "Renaming " + src + " to " + tgt.name
1100 script.RenameFile(src, tgt.name)
1101
1102
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001103def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001104 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1105 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1106
Doug Zongker26e66192014-02-20 13:22:07 -08001107 if (OPTIONS.block_based and
1108 target_has_recovery_patch and
1109 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001110 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1111
Doug Zongker37974732010-09-16 17:44:38 -07001112 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1113 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001114
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001115 if source_version == 0:
1116 print ("WARNING: generating edify script for a source that "
1117 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -07001118 script = edify_generator.EdifyGenerator(source_version,
1119 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -07001120
Michael Runge6e836112014-04-15 17:40:21 -07001121 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001122 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001123 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001124 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001125 if OPTIONS.oem_source is None:
1126 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001127 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001128 oem_dict = common.LoadDictionaryFromLines(
1129 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001130
Dan Albert8b72aef2015-03-23 19:13:21 -07001131 metadata = {
1132 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1133 OPTIONS.source_info_dict),
1134 "post-timestamp": GetBuildProp("ro.build.date.utc",
1135 OPTIONS.target_info_dict),
1136 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001137
Doug Zongker05d3dea2009-06-22 11:32:31 -07001138 device_specific = common.DeviceSpecificParams(
1139 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001140 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001141 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001142 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001143 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001144 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001145 metadata=metadata,
1146 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001147
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001148 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001149 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001150 if HasVendorPartition(target_zip):
1151 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001152 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001153 else:
1154 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001155
Dan Albert8b72aef2015-03-23 19:13:21 -07001156 target_fp = CalculateFingerprint(oem_props, oem_dict,
1157 OPTIONS.target_info_dict)
1158 source_fp = CalculateFingerprint(oem_props, oem_dict,
1159 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001160
1161 if oem_props is None:
1162 script.AssertSomeFingerprint(source_fp, target_fp)
1163 else:
1164 script.AssertSomeThumbprint(
1165 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1166 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1167
Doug Zongker2ea21062010-04-28 16:05:21 -07001168 metadata["pre-build"] = source_fp
1169 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001170
Doug Zongker55d93282011-01-25 17:03:34 -08001171 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001172 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1173 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001174 target_boot = common.GetBootableImage(
1175 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001176 updating_boot = (not OPTIONS.two_step and
1177 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001178
Doug Zongker55d93282011-01-25 17:03:34 -08001179 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001180 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1181 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001182 target_recovery = common.GetBootableImage(
1183 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001184 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001185
Doug Zongker881dd402009-09-20 14:03:55 -07001186 # Here's how we divide up the progress bar:
1187 # 0.1 for verifying the start state (PatchCheck calls)
1188 # 0.8 for applying patches (ApplyPatch calls)
1189 # 0.1 for unpacking verbatim files, symlinking, and doing the
1190 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001191
Michael Runge6e836112014-04-15 17:40:21 -07001192 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001193 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001194
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001195 # Two-step incremental package strategy (in chronological order,
1196 # which is *not* the order in which the generated script has
1197 # things):
1198 #
1199 # if stage is not "2/3" or "3/3":
1200 # do verification on current system
1201 # write recovery image to boot partition
1202 # set stage to "2/3"
1203 # reboot to boot partition and restart recovery
1204 # else if stage is "2/3":
1205 # write recovery image to recovery partition
1206 # set stage to "3/3"
1207 # reboot to recovery partition and restart recovery
1208 # else:
1209 # (stage must be "3/3")
1210 # perform update:
1211 # patch system files, etc.
1212 # force full install of new boot image
1213 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001214 # complete script normally
1215 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001216
1217 if OPTIONS.two_step:
1218 if not OPTIONS.info_dict.get("multistage_support", None):
1219 assert False, "two-step packages not supported by this build"
1220 fs = OPTIONS.info_dict["fstab"]["/misc"]
1221 assert fs.fs_type.upper() == "EMMC", \
1222 "two-step packages only supported on devices with EMMC /misc partitions"
1223 bcb_dev = {"bcb_dev": fs.device}
1224 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1225 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001226if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001227""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001228 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001229 script.WriteRawImage("/recovery", "recovery.img")
1230 script.AppendExtra("""
1231set_stage("%(bcb_dev)s", "3/3");
1232reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001233else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001234""" % bcb_dev)
1235
Tao Bao6c55a8a2015-04-08 15:30:27 -07001236 # Dump fingerprints
1237 script.Print("Source: %s" % (source_fp,))
1238 script.Print("Target: %s" % (target_fp,))
1239
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001240 script.Print("Verifying current system...")
1241
Doug Zongkere5ff5902012-01-17 10:55:37 -08001242 device_specific.IncrementalOTA_VerifyBegin()
1243
Doug Zongker881dd402009-09-20 14:03:55 -07001244 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001245 so_far = system_diff.EmitVerification(script)
1246 if vendor_diff:
1247 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001248
Doug Zongker5da317e2009-06-02 13:38:17 -07001249 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001250 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001251 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001252 print "boot target: %d source: %d diff: %d" % (
1253 target_boot.size, source_boot.size, len(d))
1254
Doug Zongker048e7ca2009-06-15 14:31:53 -07001255 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001256
Doug Zongker96a57e72010-09-26 14:57:41 -07001257 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001258
1259 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1260 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001261 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001262 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001263 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001264
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001265 size = []
Dan Albert8b72aef2015-03-23 19:13:21 -07001266 if system_diff.patch_list:
1267 size.append(system_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001268 if vendor_diff:
Dan Albert8b72aef2015-03-23 19:13:21 -07001269 if vendor_diff.patch_list:
1270 size.append(vendor_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001271 if size or updating_recovery or updating_boot:
1272 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001273
Doug Zongker05d3dea2009-06-22 11:32:31 -07001274 device_specific.IncrementalOTA_VerifyEnd()
1275
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001276 if OPTIONS.two_step:
1277 script.WriteRawImage("/boot", "recovery.img")
1278 script.AppendExtra("""
1279set_stage("%(bcb_dev)s", "2/3");
1280reboot_now("%(bcb_dev)s", "");
1281else
1282""" % bcb_dev)
1283
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001284 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001285
Doug Zongkere5ff5902012-01-17 10:55:37 -08001286 device_specific.IncrementalOTA_InstallBegin()
1287
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001288 if OPTIONS.two_step:
1289 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1290 script.WriteRawImage("/boot", "boot.img")
1291 print "writing full boot image (forced by two-step mode)"
1292
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001293 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001294 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1295 if vendor_diff:
1296 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001297
Doug Zongker881dd402009-09-20 14:03:55 -07001298 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001299 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1300 if vendor_diff:
1301 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001302 if updating_boot:
1303 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001304
1305 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001306 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1307 if vendor_diff:
1308 script.Print("Patching vendor files...")
1309 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001310
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001311 if not OPTIONS.two_step:
1312 if updating_boot:
1313 # Produce the boot image by applying a patch to the current
1314 # contents of the boot partition, and write it back to the
1315 # partition.
1316 script.Print("Patching boot image...")
1317 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1318 % (boot_type, boot_device,
1319 source_boot.size, source_boot.sha1,
1320 target_boot.size, target_boot.sha1),
1321 "-",
1322 target_boot.size, target_boot.sha1,
1323 source_boot.sha1, "patch/boot.img.p")
1324 so_far += target_boot.size
1325 script.SetProgress(so_far / total_patch_size)
1326 print "boot image changed; including."
1327 else:
1328 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001329
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001330 system_items = ItemSet("system", "META/filesystem_config.txt")
1331 if vendor_diff:
1332 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1333
Doug Zongkereef39442009-04-02 12:14:19 -07001334 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001335 # Recovery is generated as a patch using both the boot image
1336 # (which contains the same linux kernel as recovery) and the file
1337 # /system/etc/recovery-resource.dat (which contains all the images
1338 # used in the recovery UI) as sources. This lets us minimize the
1339 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001340 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001341 # For older builds where recovery-resource.dat is not present, we
1342 # use only the boot image as the source.
1343
Doug Zongkerc9253822014-02-04 12:17:58 -08001344 if not target_has_recovery_patch:
1345 def output_sink(fn, data):
1346 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001347 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001348
1349 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1350 target_recovery, target_boot)
1351 script.DeleteFiles(["/system/recovery-from-boot.p",
1352 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001353 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001354 else:
1355 print "recovery image unchanged; skipping."
1356
Doug Zongker881dd402009-09-20 14:03:55 -07001357 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001358
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001359 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1360 if vendor_diff:
1361 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1362
1363 temp_script = script.MakeTemporary()
1364 system_items.GetMetadata(target_zip)
1365 system_items.Get("system").SetPermissions(temp_script)
1366 if vendor_diff:
1367 vendor_items.GetMetadata(target_zip)
1368 vendor_items.Get("vendor").SetPermissions(temp_script)
1369
1370 # Note that this call will mess up the trees of Items, so make sure
1371 # we're done with them.
1372 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1373 if vendor_diff:
1374 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001375
1376 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001377 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1378
1379 # Delete all the symlinks in source that aren't in target. This
1380 # needs to happen before verbatim files are unpacked, in case a
1381 # symlink in the source is replaced by a real file in the target.
1382 to_delete = []
1383 for dest, link in source_symlinks:
1384 if link not in target_symlinks_d:
1385 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001386 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001387
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001388 if system_diff.verbatim_targets:
1389 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001390 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001391 if vendor_diff and vendor_diff.verbatim_targets:
1392 script.Print("Unpacking new vendor files...")
1393 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001394
Doug Zongkerc9253822014-02-04 12:17:58 -08001395 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001396 script.Print("Unpacking new recovery...")
1397 script.UnpackPackageDir("recovery", "/system")
1398
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001399 system_diff.EmitRenames(script)
1400 if vendor_diff:
1401 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001402
Doug Zongker05d3dea2009-06-22 11:32:31 -07001403 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001404
1405 # Create all the symlinks that don't already exist, or point to
1406 # somewhere different than what we want. Delete each symlink before
1407 # creating it, since the 'symlink' command won't overwrite.
1408 to_create = []
1409 for dest, link in target_symlinks:
1410 if link in source_symlinks_d:
1411 if dest != source_symlinks_d[link]:
1412 to_create.append((dest, link))
1413 else:
1414 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001415 script.DeleteFiles([i[1] for i in to_create])
1416 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001417
1418 # Now that the symlinks are created, we can set all the
1419 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001420 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001421
Doug Zongker881dd402009-09-20 14:03:55 -07001422 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001423 device_specific.IncrementalOTA_InstallEnd()
1424
Doug Zongker1c390a22009-05-14 19:06:36 -07001425 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001426 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001427
Doug Zongkere92f15a2011-08-26 13:46:40 -07001428 # Patch the build.prop file last, so if something fails but the
1429 # device can still come up, it appears to be the old build and will
1430 # get set the OTA package again to retry.
1431 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001432 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001433
Doug Zongker922206e2014-03-04 13:16:24 -08001434 if OPTIONS.wipe_user_data:
1435 script.Print("Erasing user data...")
1436 script.FormatPartition("/data")
1437
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001438 if OPTIONS.two_step:
1439 script.AppendExtra("""
1440set_stage("%(bcb_dev)s", "");
1441endif;
1442endif;
1443""" % bcb_dev)
1444
Michael Runge63f01de2014-10-28 19:24:19 -07001445 if OPTIONS.verify and system_diff:
1446 script.Print("Remounting and verifying system partition files...")
1447 script.Unmount("/system")
1448 script.Mount("/system")
1449 system_diff.EmitExplicitTargetVerification(script)
1450
1451 if OPTIONS.verify and vendor_diff:
1452 script.Print("Remounting and verifying vendor partition files...")
1453 script.Unmount("/vendor")
1454 script.Mount("/vendor")
1455 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001456 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001457
Doug Zongker2ea21062010-04-28 16:05:21 -07001458 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001459
1460
1461def main(argv):
1462
1463 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001464 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001465 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001466 elif o in ("-k", "--package_key"):
1467 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001468 elif o in ("-i", "--incremental_from"):
1469 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001470 elif o == "--full_radio":
1471 OPTIONS.full_radio = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001472 elif o in ("-w", "--wipe_user_data"):
1473 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001474 elif o in ("-n", "--no_prereq"):
1475 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001476 elif o in ("-o", "--oem_settings"):
1477 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001478 elif o in ("-e", "--extra_script"):
1479 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001480 elif o in ("-a", "--aslr_mode"):
1481 if a in ("on", "On", "true", "True", "yes", "Yes"):
1482 OPTIONS.aslr_mode = True
1483 else:
1484 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001485 elif o in ("-t", "--worker_threads"):
1486 if a.isdigit():
1487 OPTIONS.worker_threads = int(a)
1488 else:
1489 raise ValueError("Cannot parse value %r for option %r - only "
1490 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001491 elif o in ("-2", "--two_step"):
1492 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001493 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001494 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001495 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001496 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001497 elif o == "--block":
1498 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001499 elif o in ("-b", "--binary"):
1500 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001501 elif o in ("--no_fallback_to_full",):
1502 OPTIONS.fallback_to_full = False
Doug Zongkereef39442009-04-02 12:14:19 -07001503 else:
1504 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001505 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001506
1507 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001508 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001509 extra_long_opts=[
1510 "board_config=",
1511 "package_key=",
1512 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001513 "full_radio",
Dan Albert8b72aef2015-03-23 19:13:21 -07001514 "wipe_user_data",
1515 "no_prereq",
1516 "extra_script=",
1517 "worker_threads=",
1518 "aslr_mode=",
1519 "two_step",
1520 "no_signing",
1521 "block",
1522 "binary=",
1523 "oem_settings=",
1524 "verify",
1525 "no_fallback_to_full",
1526 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001527
1528 if len(args) != 2:
1529 common.Usage(__doc__)
1530 sys.exit(1)
1531
Doug Zongker1c390a22009-05-14 19:06:36 -07001532 if OPTIONS.extra_script is not None:
1533 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1534
Doug Zongkereef39442009-04-02 12:14:19 -07001535 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001536 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001537
Doug Zongkereef39442009-04-02 12:14:19 -07001538 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001539 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001540
1541 # If this image was originally labelled with SELinux contexts, make sure we
1542 # also apply the labels in our new image. During building, the "file_contexts"
1543 # is in the out/ directory tree, but for repacking from target-files.zip it's
1544 # in the root directory of the ramdisk.
1545 if "selinux_fc" in OPTIONS.info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001546 OPTIONS.info_dict["selinux_fc"] = os.path.join(
1547 OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")
Kenny Roote2e9f612013-05-29 12:59:35 -07001548
Doug Zongker37974732010-09-16 17:44:38 -07001549 if OPTIONS.verbose:
1550 print "--- target info ---"
1551 common.DumpInfoDict(OPTIONS.info_dict)
1552
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001553 # If the caller explicitly specified the device-specific extensions
1554 # path via -s/--device_specific, use that. Otherwise, use
1555 # META/releasetools.py if it is present in the target target_files.
1556 # Otherwise, take the path of the file from 'tool_extensions' in the
1557 # info dict and look for that in the local filesystem, relative to
1558 # the current directory.
1559
Doug Zongker37974732010-09-16 17:44:38 -07001560 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001561 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1562 if os.path.exists(from_input):
1563 print "(using device-specific extensions from target_files)"
1564 OPTIONS.device_specific = from_input
1565 else:
1566 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1567
Doug Zongker37974732010-09-16 17:44:38 -07001568 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001569 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001570
Doug Zongker62d4f182014-08-04 16:06:43 -07001571 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001572
Doug Zongker62d4f182014-08-04 16:06:43 -07001573 if OPTIONS.no_signing:
Dan Albert8b72aef2015-03-23 19:13:21 -07001574 if os.path.exists(args[1]):
1575 os.unlink(args[1])
1576 output_zip = zipfile.ZipFile(args[1], "w",
1577 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001578 else:
1579 temp_zip_file = tempfile.NamedTemporaryFile()
1580 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1581 compression=zipfile.ZIP_DEFLATED)
1582
1583 if OPTIONS.incremental_source is None:
1584 WriteFullOTAPackage(input_zip, output_zip)
1585 if OPTIONS.package_key is None:
1586 OPTIONS.package_key = OPTIONS.info_dict.get(
1587 "default_system_dev_certificate",
1588 "build/target/product/security/testkey")
Tao Bao2ed665a2015-04-01 11:21:55 -07001589 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001590 break
1591
1592 else:
1593 print "unzipping source target-files..."
Dan Albert8b72aef2015-03-23 19:13:21 -07001594 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
1595 OPTIONS.incremental_source)
Doug Zongker62d4f182014-08-04 16:06:43 -07001596 OPTIONS.target_info_dict = OPTIONS.info_dict
1597 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1598 if "selinux_fc" in OPTIONS.source_info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001599 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(
1600 OPTIONS.source_tmp, "BOOT", "RAMDISK", "file_contexts")
Doug Zongker62d4f182014-08-04 16:06:43 -07001601 if OPTIONS.package_key is None:
1602 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1603 "default_system_dev_certificate",
1604 "build/target/product/security/testkey")
1605 if OPTIONS.verbose:
1606 print "--- source info ---"
1607 common.DumpInfoDict(OPTIONS.source_info_dict)
1608 try:
1609 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Bao2ed665a2015-04-01 11:21:55 -07001610 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001611 break
1612 except ValueError:
Dan Albert8b72aef2015-03-23 19:13:21 -07001613 if not OPTIONS.fallback_to_full:
1614 raise
Doug Zongker62d4f182014-08-04 16:06:43 -07001615 print "--- failed to build incremental; falling back to full ---"
1616 OPTIONS.incremental_source = None
Tao Bao2ed665a2015-04-01 11:21:55 -07001617 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001618
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001619 if not OPTIONS.no_signing:
1620 SignOutput(temp_zip_file.name, args[1])
1621 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001622
Doug Zongkereef39442009-04-02 12:14:19 -07001623 print "done."
1624
1625
1626if __name__ == '__main__':
1627 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001628 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001629 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001630 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07001631 print
1632 print " ERROR: %s" % (e,)
1633 print
1634 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001635 finally:
1636 common.Cleanup()