blob: 137285089db876c3e2bbc07ebeaaadd6896ea7e0 [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
Tao Bao34b47bf2015-06-22 19:17:41 -0700489 # be installed on top of. For now, we expect the API just won't
490 # change very often. Similarly for fstab, it might have changed
491 # in the target build.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700492 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700493
Michael Runge6e836112014-04-15 17:40:21 -0700494 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700495 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700496 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700497 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700498 if OPTIONS.oem_source is None:
499 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700500 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700501 oem_dict = common.LoadDictionaryFromLines(
502 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -0700503
Dan Albert8b72aef2015-03-23 19:13:21 -0700504 metadata = {
505 "post-build": CalculateFingerprint(oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700506 OPTIONS.info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700507 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
508 OPTIONS.info_dict),
509 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
510 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700511
Doug Zongker05d3dea2009-06-22 11:32:31 -0700512 device_specific = common.DeviceSpecificParams(
513 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700514 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700515 output_zip=output_zip,
516 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700517 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700518 metadata=metadata,
519 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700520
Doug Zongkerc9253822014-02-04 12:17:58 -0800521 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800522 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800523
Doug Zongker962069c2009-04-23 11:41:58 -0700524 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700525 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700526 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
527 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700528
Michael Runge6e836112014-04-15 17:40:21 -0700529 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700530 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800531
532 # Two-step package strategy (in chronological order, which is *not*
533 # the order in which the generated script has things):
534 #
535 # if stage is not "2/3" or "3/3":
536 # write recovery image to boot partition
537 # set stage to "2/3"
538 # reboot to boot partition and restart recovery
539 # else if stage is "2/3":
540 # write recovery image to recovery partition
541 # set stage to "3/3"
542 # reboot to recovery partition and restart recovery
543 # else:
544 # (stage must be "3/3")
545 # set stage to ""
546 # do normal full package installation:
547 # wipe and install system, boot image, etc.
548 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700549 # complete script normally
550 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800551
552 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
553 OPTIONS.input_tmp, "RECOVERY")
554 if OPTIONS.two_step:
555 if not OPTIONS.info_dict.get("multistage_support", None):
556 assert False, "two-step packages not supported by this build"
557 fs = OPTIONS.info_dict["fstab"]["/misc"]
558 assert fs.fs_type.upper() == "EMMC", \
559 "two-step packages only supported on devices with EMMC /misc partitions"
560 bcb_dev = {"bcb_dev": fs.device}
561 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
562 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700563if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800564""" % bcb_dev)
565 script.WriteRawImage("/recovery", "recovery.img")
566 script.AppendExtra("""
567set_stage("%(bcb_dev)s", "3/3");
568reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700569else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800570""" % bcb_dev)
571
Tao Bao6c55a8a2015-04-08 15:30:27 -0700572 # Dump fingerprints
573 script.Print("Target: %s" % CalculateFingerprint(
574 oem_props, oem_dict, OPTIONS.info_dict))
575
Doug Zongkere5ff5902012-01-17 10:55:37 -0800576 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700577
Doug Zongker01ce19c2014-02-04 13:48:15 -0800578 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700579
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700580 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800581 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700582 if HasVendorPartition(input_zip):
583 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700584
Kenny Rootf32dc712012-04-08 10:42:34 -0700585 if "selinux_fc" in OPTIONS.info_dict:
586 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500587
Michael Runge7cd99ba2014-10-22 17:21:48 -0700588 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
589
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700590 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700591 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800592
Doug Zongker26e66192014-02-20 13:22:07 -0800593 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700594 # Full OTA is done as an "incremental" against an empty source
595 # image. This has the effect of writing new data from the package
596 # to the entire partition, but lets us reuse the updater code that
597 # writes incrementals to do it.
598 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
599 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700600 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700601 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800602 else:
603 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700604 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800605 if not has_recovery_patch:
606 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800607 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700608
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700609 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800610 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700611
Doug Zongker55d93282011-01-25 17:03:34 -0800612 boot_img = common.GetBootableImage("boot.img", "boot.img",
613 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800614
Doug Zongker91a99c22014-05-09 13:15:01 -0700615 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800616 def output_sink(fn, data):
617 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700618 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800619
620 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
621 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700622
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700623 system_items.GetMetadata(input_zip)
624 system_items.Get("system").SetPermissions(script)
625
626 if HasVendorPartition(input_zip):
627 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
628 script.ShowProgress(0.1, 0)
629
630 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700631 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
632 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700633 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700634 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700635 else:
636 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700637 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700638 script.UnpackPackageDir("vendor", "/vendor")
639
640 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
641 script.MakeSymlinks(symlinks)
642
643 vendor_items.GetMetadata(input_zip)
644 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700645
Doug Zongker37974732010-09-16 17:44:38 -0700646 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700647 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700648
Doug Zongker01ce19c2014-02-04 13:48:15 -0800649 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700650 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700651
Doug Zongker01ce19c2014-02-04 13:48:15 -0800652 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700653 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700654
Doug Zongker1c390a22009-05-14 19:06:36 -0700655 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700656 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700657
Doug Zongker14833602010-02-02 13:12:04 -0800658 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800659
Doug Zongker922206e2014-03-04 13:16:24 -0800660 if OPTIONS.wipe_user_data:
661 script.ShowProgress(0.1, 10)
662 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700663
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800664 if OPTIONS.two_step:
665 script.AppendExtra("""
666set_stage("%(bcb_dev)s", "");
667""" % bcb_dev)
668 script.AppendExtra("else\n")
669 script.WriteRawImage("/boot", "recovery.img")
670 script.AppendExtra("""
671set_stage("%(bcb_dev)s", "2/3");
672reboot_now("%(bcb_dev)s", "");
673endif;
674endif;
675""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800676 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700677 WriteMetadata(metadata, output_zip)
678
Doug Zongkerfc44a512014-08-26 13:10:25 -0700679
Dan Albert8e0178d2015-01-27 15:53:15 -0800680def WritePolicyConfig(file_name, output_zip):
681 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500682
Doug Zongker2ea21062010-04-28 16:05:21 -0700683
684def WriteMetadata(metadata, output_zip):
685 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
686 "".join(["%s=%s\n" % kv
687 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700688
Doug Zongkerfc44a512014-08-26 13:10:25 -0700689
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700690def LoadPartitionFiles(z, partition):
691 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700692 ZipFile, and return a dict of {filename: File object}."""
693 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700694 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700695 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700696 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700697 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700698 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700699 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700700 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800701 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700702
703
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700704def GetBuildProp(prop, info_dict):
705 """Return the fingerprint of the build of a given target-files info_dict."""
706 try:
707 return info_dict.get("build.prop", {})[prop]
708 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700709 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700710
Doug Zongkerfc44a512014-08-26 13:10:25 -0700711
Michael Runge4038aa82013-12-13 18:06:28 -0800712def AddToKnownPaths(filename, known_paths):
713 if filename[-1] == "/":
714 return
715 dirs = filename.split("/")[:-1]
716 while len(dirs) > 0:
717 path = "/".join(dirs)
718 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700719 break
Michael Runge4038aa82013-12-13 18:06:28 -0800720 known_paths.add(path)
721 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700722
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700723
Geremy Condra36bd3652014-02-06 19:45:10 -0800724def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
725 source_version = OPTIONS.source_info_dict["recovery_api_version"]
726 target_version = OPTIONS.target_info_dict["recovery_api_version"]
727
728 if source_version == 0:
729 print ("WARNING: generating edify script for a source that "
730 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -0700731 script = edify_generator.EdifyGenerator(
732 source_version, OPTIONS.target_info_dict,
733 fstab=OPTIONS.source_info_dict["fstab"])
Geremy Condra36bd3652014-02-06 19:45:10 -0800734
Dan Albert8b72aef2015-03-23 19:13:21 -0700735 metadata = {
736 "pre-device": GetBuildProp("ro.product.device",
737 OPTIONS.source_info_dict),
738 "post-timestamp": GetBuildProp("ro.build.date.utc",
739 OPTIONS.target_info_dict),
740 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800741
742 device_specific = common.DeviceSpecificParams(
743 source_zip=source_zip,
744 source_version=source_version,
745 target_zip=target_zip,
746 target_version=target_version,
747 output_zip=output_zip,
748 script=script,
749 metadata=metadata,
750 info_dict=OPTIONS.info_dict)
751
Tao Bao6c55a8a2015-04-08 15:30:27 -0700752 # TODO: Currently this works differently from WriteIncrementalOTAPackage().
753 # This function doesn't consider thumbprints when writing
754 # metadata["pre/post-build"]. One possible reason is that the current
755 # devices with thumbprints are all using file-based OTAs. Long term we
756 # should factor out the common parts into a shared one to avoid further
757 # divergence.
Geremy Condra36bd3652014-02-06 19:45:10 -0800758 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
759 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
760 metadata["pre-build"] = source_fp
761 metadata["post-build"] = target_fp
762
763 source_boot = common.GetBootableImage(
764 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
765 OPTIONS.source_info_dict)
766 target_boot = common.GetBootableImage(
767 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
768 updating_boot = (not OPTIONS.two_step and
769 (source_boot.data != target_boot.data))
770
Geremy Condra36bd3652014-02-06 19:45:10 -0800771 target_recovery = common.GetBootableImage(
772 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800773
Doug Zongkerfc44a512014-08-26 13:10:25 -0700774 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
775 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700776
777 blockimgdiff_version = 1
778 if OPTIONS.info_dict:
779 blockimgdiff_version = max(
780 int(i) for i in
781 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
782
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700783 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700784 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700785
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700786 if HasVendorPartition(target_zip):
787 if not HasVendorPartition(source_zip):
788 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700789 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
790 OPTIONS.source_info_dict)
791 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
792 OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700793 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700794 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700795 else:
796 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800797
Michael Rungec6e3afd2014-05-05 11:55:47 -0700798 oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
Tao Bao34b47bf2015-06-22 19:17:41 -0700799 recovery_mount_options = OPTIONS.source_info_dict.get(
Dan Albert8b72aef2015-03-23 19:13:21 -0700800 "recovery_mount_options")
Michael Rungec6e3afd2014-05-05 11:55:47 -0700801 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700802 if oem_props is not None and len(oem_props) > 0:
Michael Rungec6e3afd2014-05-05 11:55:47 -0700803 if OPTIONS.oem_source is None:
804 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700805 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700806 oem_dict = common.LoadDictionaryFromLines(
807 open(OPTIONS.oem_source).readlines())
Michael Rungec6e3afd2014-05-05 11:55:47 -0700808
809 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800810 device_specific.IncrementalOTA_Assertions()
811
812 # Two-step incremental package strategy (in chronological order,
813 # which is *not* the order in which the generated script has
814 # things):
815 #
816 # if stage is not "2/3" or "3/3":
817 # do verification on current system
818 # write recovery image to boot partition
819 # set stage to "2/3"
820 # reboot to boot partition and restart recovery
821 # else if stage is "2/3":
822 # write recovery image to recovery partition
823 # set stage to "3/3"
824 # reboot to recovery partition and restart recovery
825 # else:
826 # (stage must be "3/3")
827 # perform update:
828 # patch system files, etc.
829 # force full install of new boot image
830 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700831 # complete script normally
832 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800833
834 if OPTIONS.two_step:
835 if not OPTIONS.info_dict.get("multistage_support", None):
836 assert False, "two-step packages not supported by this build"
837 fs = OPTIONS.info_dict["fstab"]["/misc"]
838 assert fs.fs_type.upper() == "EMMC", \
839 "two-step packages only supported on devices with EMMC /misc partitions"
840 bcb_dev = {"bcb_dev": fs.device}
841 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
842 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700843if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800844""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -0700845 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800846 script.WriteRawImage("/recovery", "recovery.img")
847 script.AppendExtra("""
848set_stage("%(bcb_dev)s", "3/3");
849reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700850else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800851""" % bcb_dev)
852
Tao Bao6c55a8a2015-04-08 15:30:27 -0700853 # Dump fingerprints
854 script.Print("Source: %s" % CalculateFingerprint(
855 oem_props, oem_dict, OPTIONS.source_info_dict))
856 script.Print("Target: %s" % CalculateFingerprint(
857 oem_props, oem_dict, OPTIONS.target_info_dict))
858
Geremy Condra36bd3652014-02-06 19:45:10 -0800859 script.Print("Verifying current system...")
860
861 device_specific.IncrementalOTA_VerifyBegin()
862
Michael Rungec6e3afd2014-05-05 11:55:47 -0700863 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700864 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
865 # patching on a device that's already on the target build will damage the
866 # system. Because operations like move don't check the block state, they
867 # always apply the changes unconditionally.
868 if blockimgdiff_version <= 2:
869 script.AssertSomeFingerprint(source_fp)
870 else:
871 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700872 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700873 if blockimgdiff_version <= 2:
874 script.AssertSomeThumbprint(
875 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
876 else:
877 script.AssertSomeThumbprint(
878 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
879 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800880
881 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700882 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800883 d = common.Difference(target_boot, source_boot)
884 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700885 if d is None:
886 include_full_boot = True
887 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
888 else:
889 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800890
Doug Zongkerf8340082014-08-05 10:39:37 -0700891 print "boot target: %d source: %d diff: %d" % (
892 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800893
Doug Zongkerf8340082014-08-05 10:39:37 -0700894 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800895
Doug Zongkerf8340082014-08-05 10:39:37 -0700896 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
897 (boot_type, boot_device,
898 source_boot.size, source_boot.sha1,
899 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800900
901 device_specific.IncrementalOTA_VerifyEnd()
902
903 if OPTIONS.two_step:
904 script.WriteRawImage("/boot", "recovery.img")
905 script.AppendExtra("""
906set_stage("%(bcb_dev)s", "2/3");
907reboot_now("%(bcb_dev)s", "");
908else
909""" % bcb_dev)
910
Jesse Zhao75bcea02015-01-06 10:59:53 -0800911 # Verify the existing partitions.
912 system_diff.WriteVerifyScript(script)
913 if vendor_diff:
914 vendor_diff.WriteVerifyScript(script)
915
Geremy Condra36bd3652014-02-06 19:45:10 -0800916 script.Comment("---- start making changes here ----")
917
918 device_specific.IncrementalOTA_InstallBegin()
919
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700920 system_diff.WriteScript(script, output_zip,
921 progress=0.8 if vendor_diff else 0.9)
Tao Bao68658c02015-06-01 13:40:49 -0700922
Doug Zongkerfc44a512014-08-26 13:10:25 -0700923 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700924 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800925
926 if OPTIONS.two_step:
927 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
928 script.WriteRawImage("/boot", "boot.img")
929 print "writing full boot image (forced by two-step mode)"
930
931 if not OPTIONS.two_step:
932 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700933 if include_full_boot:
934 print "boot image changed; including full."
935 script.Print("Installing boot image...")
936 script.WriteRawImage("/boot", "boot.img")
937 else:
938 # Produce the boot image by applying a patch to the current
939 # contents of the boot partition, and write it back to the
940 # partition.
941 print "boot image changed; including patch."
942 script.Print("Patching boot image...")
943 script.ShowProgress(0.1, 10)
944 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
945 % (boot_type, boot_device,
946 source_boot.size, source_boot.sha1,
947 target_boot.size, target_boot.sha1),
948 "-",
949 target_boot.size, target_boot.sha1,
950 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800951 else:
952 print "boot image unchanged; skipping."
953
954 # Do device-specific installation (eg, write radio image).
955 device_specific.IncrementalOTA_InstallEnd()
956
957 if OPTIONS.extra_script is not None:
958 script.AppendExtra(OPTIONS.extra_script)
959
Doug Zongker922206e2014-03-04 13:16:24 -0800960 if OPTIONS.wipe_user_data:
961 script.Print("Erasing user data...")
962 script.FormatPartition("/data")
963
Geremy Condra36bd3652014-02-06 19:45:10 -0800964 if OPTIONS.two_step:
965 script.AppendExtra("""
966set_stage("%(bcb_dev)s", "");
967endif;
968endif;
969""" % bcb_dev)
970
971 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800972 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800973 WriteMetadata(metadata, output_zip)
974
Doug Zongker32b527d2014-03-04 10:03:02 -0800975
Dan Albert8b72aef2015-03-23 19:13:21 -0700976class FileDifference(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700977 def __init__(self, partition, source_zip, target_zip, output_zip):
Dan Albert8b72aef2015-03-23 19:13:21 -0700978 self.deferred_patch_list = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700979 print "Loading target..."
980 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
981 print "Loading source..."
982 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
983
984 self.verbatim_targets = verbatim_targets = []
985 self.patch_list = patch_list = []
986 diffs = []
987 self.renames = renames = {}
988 known_paths = set()
989 largest_source_size = 0
990
991 matching_file_cache = {}
992 for fn, sf in source_data.items():
993 assert fn == sf.name
994 matching_file_cache["path:" + fn] = sf
995 if fn in target_data.keys():
996 AddToKnownPaths(fn, known_paths)
997 # Only allow eligibility for filename/sha matching
998 # if there isn't a perfect path match.
999 if target_data.get(sf.name) is None:
1000 matching_file_cache["file:" + fn.split("/")[-1]] = sf
1001 matching_file_cache["sha:" + sf.sha1] = sf
1002
1003 for fn in sorted(target_data.keys()):
1004 tf = target_data[fn]
1005 assert fn == tf.name
1006 sf = ClosestFileMatch(tf, matching_file_cache, renames)
1007 if sf is not None and sf.name != tf.name:
1008 print "File has moved from " + sf.name + " to " + tf.name
1009 renames[sf.name] = tf
1010
1011 if sf is None or fn in OPTIONS.require_verbatim:
1012 # This file should be included verbatim
1013 if fn in OPTIONS.prohibit_verbatim:
1014 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
1015 print "send", fn, "verbatim"
1016 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001017 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001018 if fn in target_data.keys():
1019 AddToKnownPaths(fn, known_paths)
1020 elif tf.sha1 != sf.sha1:
1021 # File is different; consider sending as a patch
1022 diffs.append(common.Difference(tf, sf))
1023 else:
1024 # Target file data identical to source (may still be renamed)
1025 pass
1026
1027 common.ComputeDifferences(diffs)
1028
1029 for diff in diffs:
1030 tf, sf, d = diff.GetPatch()
1031 path = "/".join(tf.name.split("/")[:-1])
1032 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1033 path not in known_paths:
1034 # patch is almost as big as the file; don't bother patching
1035 # or a patch + rename cannot take place due to the target
1036 # directory not existing
1037 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001038 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001039 if sf.name in renames:
1040 del renames[sf.name]
1041 AddToKnownPaths(tf.name, known_paths)
1042 else:
1043 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1044 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1045 largest_source_size = max(largest_source_size, sf.size)
1046
1047 self.largest_source_size = largest_source_size
1048
1049 def EmitVerification(self, script):
1050 so_far = 0
Dan Albert8b72aef2015-03-23 19:13:21 -07001051 for tf, sf, _, _ in self.patch_list:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001052 if tf.name != sf.name:
1053 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1054 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1055 so_far += sf.size
1056 return so_far
1057
Michael Runge63f01de2014-10-28 19:24:19 -07001058 def EmitExplicitTargetVerification(self, script):
Dan Albert8b72aef2015-03-23 19:13:21 -07001059 for fn, _, sha1 in self.verbatim_targets:
1060 if fn[-1] != "/":
Michael Runge63f01de2014-10-28 19:24:19 -07001061 script.FileCheck("/"+fn, sha1)
1062 for tf, _, _, _ in self.patch_list:
1063 script.FileCheck(tf.name, tf.sha1)
1064
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001065 def RemoveUnneededFiles(self, script, extras=()):
Dan Albert8b72aef2015-03-23 19:13:21 -07001066 script.DeleteFiles(
1067 ["/" + i[0] for i in self.verbatim_targets] +
1068 ["/" + i for i in sorted(self.source_data)
1069 if i not in self.target_data and i not in self.renames] +
1070 list(extras))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001071
1072 def TotalPatchSize(self):
1073 return sum(i[1].size for i in self.patch_list)
1074
1075 def EmitPatches(self, script, total_patch_size, so_far):
1076 self.deferred_patch_list = deferred_patch_list = []
1077 for item in self.patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001078 tf, sf, _, _ = item
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001079 if tf.name == "system/build.prop":
1080 deferred_patch_list.append(item)
1081 continue
Dan Albert8b72aef2015-03-23 19:13:21 -07001082 if sf.name != tf.name:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001083 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
Dan Albert8b72aef2015-03-23 19:13:21 -07001084 script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1,
1085 "patch/" + sf.name + ".p")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001086 so_far += tf.size
1087 script.SetProgress(so_far / total_patch_size)
1088 return so_far
1089
1090 def EmitDeferredPatches(self, script):
1091 for item in self.deferred_patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001092 tf, sf, _, _ = item
1093 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1,
1094 "patch/" + sf.name + ".p")
1095 script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001096
1097 def EmitRenames(self, script):
1098 if len(self.renames) > 0:
1099 script.Print("Renaming files...")
1100 for src, tgt in self.renames.iteritems():
1101 print "Renaming " + src + " to " + tgt.name
1102 script.RenameFile(src, tgt.name)
1103
1104
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001105def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001106 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1107 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1108
Doug Zongker26e66192014-02-20 13:22:07 -08001109 if (OPTIONS.block_based and
1110 target_has_recovery_patch and
1111 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001112 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1113
Doug Zongker37974732010-09-16 17:44:38 -07001114 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1115 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001116
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001117 if source_version == 0:
1118 print ("WARNING: generating edify script for a source that "
1119 "can't install it.")
Tao Bao34b47bf2015-06-22 19:17:41 -07001120 script = edify_generator.EdifyGenerator(
1121 source_version, OPTIONS.target_info_dict,
1122 fstab=OPTIONS.source_info_dict["fstab"])
Doug Zongkereef39442009-04-02 12:14:19 -07001123
Michael Runge6e836112014-04-15 17:40:21 -07001124 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Tao Bao34b47bf2015-06-22 19:17:41 -07001125 recovery_mount_options = OPTIONS.source_info_dict.get(
1126 "recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001127 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001128 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001129 if OPTIONS.oem_source is None:
1130 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001131 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001132 oem_dict = common.LoadDictionaryFromLines(
1133 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001134
Dan Albert8b72aef2015-03-23 19:13:21 -07001135 metadata = {
1136 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1137 OPTIONS.source_info_dict),
1138 "post-timestamp": GetBuildProp("ro.build.date.utc",
1139 OPTIONS.target_info_dict),
1140 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001141
Doug Zongker05d3dea2009-06-22 11:32:31 -07001142 device_specific = common.DeviceSpecificParams(
1143 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001144 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001145 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001146 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001147 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001148 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001149 metadata=metadata,
1150 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001151
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001152 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001153 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001154 if HasVendorPartition(target_zip):
1155 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001156 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001157 else:
1158 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001159
Dan Albert8b72aef2015-03-23 19:13:21 -07001160 target_fp = CalculateFingerprint(oem_props, oem_dict,
1161 OPTIONS.target_info_dict)
1162 source_fp = CalculateFingerprint(oem_props, oem_dict,
1163 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001164
1165 if oem_props is None:
1166 script.AssertSomeFingerprint(source_fp, target_fp)
1167 else:
1168 script.AssertSomeThumbprint(
1169 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1170 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1171
Doug Zongker2ea21062010-04-28 16:05:21 -07001172 metadata["pre-build"] = source_fp
1173 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001174
Doug Zongker55d93282011-01-25 17:03:34 -08001175 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001176 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1177 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001178 target_boot = common.GetBootableImage(
1179 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001180 updating_boot = (not OPTIONS.two_step and
1181 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001182
Doug Zongker55d93282011-01-25 17:03:34 -08001183 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001184 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1185 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001186 target_recovery = common.GetBootableImage(
1187 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001188 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001189
Doug Zongker881dd402009-09-20 14:03:55 -07001190 # Here's how we divide up the progress bar:
1191 # 0.1 for verifying the start state (PatchCheck calls)
1192 # 0.8 for applying patches (ApplyPatch calls)
1193 # 0.1 for unpacking verbatim files, symlinking, and doing the
1194 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001195
Michael Runge6e836112014-04-15 17:40:21 -07001196 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001197 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001198
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001199 # Two-step incremental package strategy (in chronological order,
1200 # which is *not* the order in which the generated script has
1201 # things):
1202 #
1203 # if stage is not "2/3" or "3/3":
1204 # do verification on current system
1205 # write recovery image to boot partition
1206 # set stage to "2/3"
1207 # reboot to boot partition and restart recovery
1208 # else if stage is "2/3":
1209 # write recovery image to recovery partition
1210 # set stage to "3/3"
1211 # reboot to recovery partition and restart recovery
1212 # else:
1213 # (stage must be "3/3")
1214 # perform update:
1215 # patch system files, etc.
1216 # force full install of new boot image
1217 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001218 # complete script normally
1219 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001220
1221 if OPTIONS.two_step:
1222 if not OPTIONS.info_dict.get("multistage_support", None):
1223 assert False, "two-step packages not supported by this build"
1224 fs = OPTIONS.info_dict["fstab"]["/misc"]
1225 assert fs.fs_type.upper() == "EMMC", \
1226 "two-step packages only supported on devices with EMMC /misc partitions"
1227 bcb_dev = {"bcb_dev": fs.device}
1228 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1229 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001230if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001231""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001232 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001233 script.WriteRawImage("/recovery", "recovery.img")
1234 script.AppendExtra("""
1235set_stage("%(bcb_dev)s", "3/3");
1236reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001237else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001238""" % bcb_dev)
1239
Tao Bao6c55a8a2015-04-08 15:30:27 -07001240 # Dump fingerprints
1241 script.Print("Source: %s" % (source_fp,))
1242 script.Print("Target: %s" % (target_fp,))
1243
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001244 script.Print("Verifying current system...")
1245
Doug Zongkere5ff5902012-01-17 10:55:37 -08001246 device_specific.IncrementalOTA_VerifyBegin()
1247
Doug Zongker881dd402009-09-20 14:03:55 -07001248 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001249 so_far = system_diff.EmitVerification(script)
1250 if vendor_diff:
1251 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001252
Doug Zongker5da317e2009-06-02 13:38:17 -07001253 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001254 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001255 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001256 print "boot target: %d source: %d diff: %d" % (
1257 target_boot.size, source_boot.size, len(d))
1258
Doug Zongker048e7ca2009-06-15 14:31:53 -07001259 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001260
Doug Zongker96a57e72010-09-26 14:57:41 -07001261 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001262
1263 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1264 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001265 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001266 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001267 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001268
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001269 size = []
Dan Albert8b72aef2015-03-23 19:13:21 -07001270 if system_diff.patch_list:
1271 size.append(system_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001272 if vendor_diff:
Dan Albert8b72aef2015-03-23 19:13:21 -07001273 if vendor_diff.patch_list:
1274 size.append(vendor_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001275 if size or updating_recovery or updating_boot:
1276 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001277
Doug Zongker05d3dea2009-06-22 11:32:31 -07001278 device_specific.IncrementalOTA_VerifyEnd()
1279
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001280 if OPTIONS.two_step:
1281 script.WriteRawImage("/boot", "recovery.img")
1282 script.AppendExtra("""
1283set_stage("%(bcb_dev)s", "2/3");
1284reboot_now("%(bcb_dev)s", "");
1285else
1286""" % bcb_dev)
1287
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001288 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001289
Doug Zongkere5ff5902012-01-17 10:55:37 -08001290 device_specific.IncrementalOTA_InstallBegin()
1291
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001292 if OPTIONS.two_step:
1293 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1294 script.WriteRawImage("/boot", "boot.img")
1295 print "writing full boot image (forced by two-step mode)"
1296
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001297 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001298 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1299 if vendor_diff:
1300 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001301
Doug Zongker881dd402009-09-20 14:03:55 -07001302 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001303 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1304 if vendor_diff:
1305 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001306 if updating_boot:
1307 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001308
1309 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001310 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1311 if vendor_diff:
1312 script.Print("Patching vendor files...")
1313 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001314
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001315 if not OPTIONS.two_step:
1316 if updating_boot:
1317 # Produce the boot image by applying a patch to the current
1318 # contents of the boot partition, and write it back to the
1319 # partition.
1320 script.Print("Patching boot image...")
1321 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1322 % (boot_type, boot_device,
1323 source_boot.size, source_boot.sha1,
1324 target_boot.size, target_boot.sha1),
1325 "-",
1326 target_boot.size, target_boot.sha1,
1327 source_boot.sha1, "patch/boot.img.p")
1328 so_far += target_boot.size
1329 script.SetProgress(so_far / total_patch_size)
1330 print "boot image changed; including."
1331 else:
1332 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001333
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001334 system_items = ItemSet("system", "META/filesystem_config.txt")
1335 if vendor_diff:
1336 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1337
Doug Zongkereef39442009-04-02 12:14:19 -07001338 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001339 # Recovery is generated as a patch using both the boot image
1340 # (which contains the same linux kernel as recovery) and the file
1341 # /system/etc/recovery-resource.dat (which contains all the images
1342 # used in the recovery UI) as sources. This lets us minimize the
1343 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001344 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001345 # For older builds where recovery-resource.dat is not present, we
1346 # use only the boot image as the source.
1347
Doug Zongkerc9253822014-02-04 12:17:58 -08001348 if not target_has_recovery_patch:
1349 def output_sink(fn, data):
1350 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001351 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001352
1353 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1354 target_recovery, target_boot)
1355 script.DeleteFiles(["/system/recovery-from-boot.p",
1356 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001357 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001358 else:
1359 print "recovery image unchanged; skipping."
1360
Doug Zongker881dd402009-09-20 14:03:55 -07001361 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001362
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001363 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1364 if vendor_diff:
1365 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1366
1367 temp_script = script.MakeTemporary()
1368 system_items.GetMetadata(target_zip)
1369 system_items.Get("system").SetPermissions(temp_script)
1370 if vendor_diff:
1371 vendor_items.GetMetadata(target_zip)
1372 vendor_items.Get("vendor").SetPermissions(temp_script)
1373
1374 # Note that this call will mess up the trees of Items, so make sure
1375 # we're done with them.
1376 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1377 if vendor_diff:
1378 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001379
1380 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001381 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1382
1383 # Delete all the symlinks in source that aren't in target. This
1384 # needs to happen before verbatim files are unpacked, in case a
1385 # symlink in the source is replaced by a real file in the target.
1386 to_delete = []
1387 for dest, link in source_symlinks:
1388 if link not in target_symlinks_d:
1389 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001390 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001391
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001392 if system_diff.verbatim_targets:
1393 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001394 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001395 if vendor_diff and vendor_diff.verbatim_targets:
1396 script.Print("Unpacking new vendor files...")
1397 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001398
Doug Zongkerc9253822014-02-04 12:17:58 -08001399 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001400 script.Print("Unpacking new recovery...")
1401 script.UnpackPackageDir("recovery", "/system")
1402
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001403 system_diff.EmitRenames(script)
1404 if vendor_diff:
1405 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001406
Doug Zongker05d3dea2009-06-22 11:32:31 -07001407 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001408
1409 # Create all the symlinks that don't already exist, or point to
1410 # somewhere different than what we want. Delete each symlink before
1411 # creating it, since the 'symlink' command won't overwrite.
1412 to_create = []
1413 for dest, link in target_symlinks:
1414 if link in source_symlinks_d:
1415 if dest != source_symlinks_d[link]:
1416 to_create.append((dest, link))
1417 else:
1418 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001419 script.DeleteFiles([i[1] for i in to_create])
1420 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001421
1422 # Now that the symlinks are created, we can set all the
1423 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001424 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001425
Doug Zongker881dd402009-09-20 14:03:55 -07001426 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001427 device_specific.IncrementalOTA_InstallEnd()
1428
Doug Zongker1c390a22009-05-14 19:06:36 -07001429 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001430 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001431
Doug Zongkere92f15a2011-08-26 13:46:40 -07001432 # Patch the build.prop file last, so if something fails but the
1433 # device can still come up, it appears to be the old build and will
1434 # get set the OTA package again to retry.
1435 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001436 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001437
Doug Zongker922206e2014-03-04 13:16:24 -08001438 if OPTIONS.wipe_user_data:
1439 script.Print("Erasing user data...")
1440 script.FormatPartition("/data")
1441
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001442 if OPTIONS.two_step:
1443 script.AppendExtra("""
1444set_stage("%(bcb_dev)s", "");
1445endif;
1446endif;
1447""" % bcb_dev)
1448
Michael Runge63f01de2014-10-28 19:24:19 -07001449 if OPTIONS.verify and system_diff:
1450 script.Print("Remounting and verifying system partition files...")
1451 script.Unmount("/system")
1452 script.Mount("/system")
1453 system_diff.EmitExplicitTargetVerification(script)
1454
1455 if OPTIONS.verify and vendor_diff:
1456 script.Print("Remounting and verifying vendor partition files...")
1457 script.Unmount("/vendor")
1458 script.Mount("/vendor")
1459 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001460 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001461
Doug Zongker2ea21062010-04-28 16:05:21 -07001462 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001463
1464
1465def main(argv):
1466
1467 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001468 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001469 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001470 elif o in ("-k", "--package_key"):
1471 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001472 elif o in ("-i", "--incremental_from"):
1473 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001474 elif o == "--full_radio":
1475 OPTIONS.full_radio = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001476 elif o in ("-w", "--wipe_user_data"):
1477 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001478 elif o in ("-n", "--no_prereq"):
1479 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001480 elif o in ("-o", "--oem_settings"):
1481 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001482 elif o in ("-e", "--extra_script"):
1483 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001484 elif o in ("-a", "--aslr_mode"):
1485 if a in ("on", "On", "true", "True", "yes", "Yes"):
1486 OPTIONS.aslr_mode = True
1487 else:
1488 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001489 elif o in ("-t", "--worker_threads"):
1490 if a.isdigit():
1491 OPTIONS.worker_threads = int(a)
1492 else:
1493 raise ValueError("Cannot parse value %r for option %r - only "
1494 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001495 elif o in ("-2", "--two_step"):
1496 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001497 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001498 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001499 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001500 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001501 elif o == "--block":
1502 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001503 elif o in ("-b", "--binary"):
1504 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001505 elif o in ("--no_fallback_to_full",):
1506 OPTIONS.fallback_to_full = False
Doug Zongkereef39442009-04-02 12:14:19 -07001507 else:
1508 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001509 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001510
1511 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001512 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001513 extra_long_opts=[
1514 "board_config=",
1515 "package_key=",
1516 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001517 "full_radio",
Dan Albert8b72aef2015-03-23 19:13:21 -07001518 "wipe_user_data",
1519 "no_prereq",
1520 "extra_script=",
1521 "worker_threads=",
1522 "aslr_mode=",
1523 "two_step",
1524 "no_signing",
1525 "block",
1526 "binary=",
1527 "oem_settings=",
1528 "verify",
1529 "no_fallback_to_full",
1530 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001531
1532 if len(args) != 2:
1533 common.Usage(__doc__)
1534 sys.exit(1)
1535
Doug Zongker1c390a22009-05-14 19:06:36 -07001536 if OPTIONS.extra_script is not None:
1537 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1538
Doug Zongkereef39442009-04-02 12:14:19 -07001539 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001540 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001541
Doug Zongkereef39442009-04-02 12:14:19 -07001542 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001543 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001544
1545 # If this image was originally labelled with SELinux contexts, make sure we
1546 # also apply the labels in our new image. During building, the "file_contexts"
1547 # is in the out/ directory tree, but for repacking from target-files.zip it's
1548 # in the root directory of the ramdisk.
1549 if "selinux_fc" in OPTIONS.info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001550 OPTIONS.info_dict["selinux_fc"] = os.path.join(
1551 OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")
Kenny Roote2e9f612013-05-29 12:59:35 -07001552
Doug Zongker37974732010-09-16 17:44:38 -07001553 if OPTIONS.verbose:
1554 print "--- target info ---"
1555 common.DumpInfoDict(OPTIONS.info_dict)
1556
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001557 # If the caller explicitly specified the device-specific extensions
1558 # path via -s/--device_specific, use that. Otherwise, use
1559 # META/releasetools.py if it is present in the target target_files.
1560 # Otherwise, take the path of the file from 'tool_extensions' in the
1561 # info dict and look for that in the local filesystem, relative to
1562 # the current directory.
1563
Doug Zongker37974732010-09-16 17:44:38 -07001564 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001565 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1566 if os.path.exists(from_input):
1567 print "(using device-specific extensions from target_files)"
1568 OPTIONS.device_specific = from_input
1569 else:
1570 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1571
Doug Zongker37974732010-09-16 17:44:38 -07001572 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001573 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001574
Doug Zongker62d4f182014-08-04 16:06:43 -07001575 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001576
Doug Zongker62d4f182014-08-04 16:06:43 -07001577 if OPTIONS.no_signing:
Dan Albert8b72aef2015-03-23 19:13:21 -07001578 if os.path.exists(args[1]):
1579 os.unlink(args[1])
1580 output_zip = zipfile.ZipFile(args[1], "w",
1581 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001582 else:
1583 temp_zip_file = tempfile.NamedTemporaryFile()
1584 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1585 compression=zipfile.ZIP_DEFLATED)
1586
1587 if OPTIONS.incremental_source is None:
1588 WriteFullOTAPackage(input_zip, output_zip)
1589 if OPTIONS.package_key is None:
1590 OPTIONS.package_key = OPTIONS.info_dict.get(
1591 "default_system_dev_certificate",
1592 "build/target/product/security/testkey")
Tao Bao2ed665a2015-04-01 11:21:55 -07001593 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001594 break
1595
1596 else:
1597 print "unzipping source target-files..."
Dan Albert8b72aef2015-03-23 19:13:21 -07001598 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
1599 OPTIONS.incremental_source)
Doug Zongker62d4f182014-08-04 16:06:43 -07001600 OPTIONS.target_info_dict = OPTIONS.info_dict
1601 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1602 if "selinux_fc" in OPTIONS.source_info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001603 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(
1604 OPTIONS.source_tmp, "BOOT", "RAMDISK", "file_contexts")
Doug Zongker62d4f182014-08-04 16:06:43 -07001605 if OPTIONS.package_key is None:
1606 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1607 "default_system_dev_certificate",
1608 "build/target/product/security/testkey")
1609 if OPTIONS.verbose:
1610 print "--- source info ---"
1611 common.DumpInfoDict(OPTIONS.source_info_dict)
1612 try:
1613 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Bao2ed665a2015-04-01 11:21:55 -07001614 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001615 break
1616 except ValueError:
Dan Albert8b72aef2015-03-23 19:13:21 -07001617 if not OPTIONS.fallback_to_full:
1618 raise
Doug Zongker62d4f182014-08-04 16:06:43 -07001619 print "--- failed to build incremental; falling back to full ---"
1620 OPTIONS.incremental_source = None
Tao Bao2ed665a2015-04-01 11:21:55 -07001621 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001622
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001623 if not OPTIONS.no_signing:
1624 SignOutput(temp_zip_file.name, args[1])
1625 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001626
Doug Zongkereef39442009-04-02 12:14:19 -07001627 print "done."
1628
1629
1630if __name__ == '__main__':
1631 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001632 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001633 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001634 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07001635 print
1636 print " ERROR: %s" % (e,)
1637 print
1638 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001639 finally:
1640 common.Cleanup()