blob: 26fbaf0fc861e01e7ac67afaffbf28fb0501d951 [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
Michael Runge63f01de2014-10-28 19:24:19 -070040 -v (--verify)
41 Remount and verify the checksums of the files written to the
42 system and vendor (if used) partitions. Incremental builds only.
43
Michael Runge6e836112014-04-15 17:40:21 -070044 -o (--oem_settings) <file>
45 Use the file to specify the expected OEM-specific properties
46 on the OEM partition of the intended device.
47
Doug Zongkerdbfaae52009-04-21 17:12:54 -070048 -w (--wipe_user_data)
49 Generate an OTA package that will wipe the user data partition
50 when installed.
51
Doug Zongker962069c2009-04-23 11:41:58 -070052 -n (--no_prereq)
53 Omit the timestamp prereq check normally included at the top of
54 the build scripts (used for developer OTA packages which
55 legitimately need to go back and forth).
56
Doug Zongker1c390a22009-05-14 19:06:36 -070057 -e (--extra_script) <file>
58 Insert the contents of file at the end of the update script.
59
Hristo Bojinovdafb0422010-08-26 14:35:16 -070060 -a (--aslr_mode) <on|off>
61 Specify whether to turn on ASLR for the package (on by default).
Stephen Smalley56882bf2012-02-09 13:36:21 -050062
Doug Zongker9b23f2c2013-11-25 14:44:12 -080063 -2 (--two_step)
64 Generate a 'two-step' OTA package, where recovery is updated
65 first, so that any changes made to the system partition are done
66 using the new recovery (new kernel, etc.).
67
Doug Zongker26e66192014-02-20 13:22:07 -080068 --block
69 Generate a block-based OTA if possible. Will fall back to a
70 file-based OTA if the target_files is older and doesn't support
71 block-based OTAs.
72
Doug Zongker25568482014-03-03 10:21:27 -080073 -b (--binary) <file>
74 Use the given binary as the update-binary in the output package,
75 instead of the binary in the build's target_files. Use for
76 development only.
77
Martin Blumenstingl374e1142014-05-31 20:42:55 +020078 -t (--worker_threads) <int>
79 Specifies the number of worker-threads that will be used when
80 generating patches for incremental updates (defaults to 3).
81
Doug Zongkereef39442009-04-02 12:14:19 -070082"""
83
84import sys
85
Doug Zongkercf6d5a92014-02-18 10:57:07 -080086if sys.hexversion < 0x02070000:
87 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -070088 sys.exit(1)
89
90import copy
Doug Zongkerfc44a512014-08-26 13:10:25 -070091import multiprocessing
Doug Zongkereef39442009-04-02 12:14:19 -070092import os
Doug Zongkereef39442009-04-02 12:14:19 -070093import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -070094import zipfile
95
96import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -070097import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -070098import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -070099
100OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700101OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700102OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700103OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700104OPTIONS.require_verbatim = set()
105OPTIONS.prohibit_verbatim = set(("system/build.prop",))
106OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700107OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700108OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700109OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700110OPTIONS.aslr_mode = True
Doug Zongkerfc44a512014-08-26 13:10:25 -0700111OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
112if OPTIONS.worker_threads == 0:
113 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800114OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900115OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800116OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800117OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700118OPTIONS.oem_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -0700119OPTIONS.fallback_to_full = True
Doug Zongkereef39442009-04-02 12:14:19 -0700120
121def MostPopularKey(d, default):
122 """Given a dict, return the key corresponding to the largest
123 value. Returns 'default' if the dict is empty."""
124 x = [(v, k) for (k, v) in d.iteritems()]
Dan Albert8b72aef2015-03-23 19:13:21 -0700125 if not x:
126 return default
Doug Zongkereef39442009-04-02 12:14:19 -0700127 x.sort()
128 return x[-1][1]
129
130
131def IsSymlink(info):
132 """Return true if the zipfile.ZipInfo object passed in represents a
133 symlink."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700134 return (info.external_attr >> 16) == 0o120777
Doug Zongkereef39442009-04-02 12:14:19 -0700135
Hristo Bojinov96be7202010-08-02 10:26:17 -0700136def IsRegular(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 >> 28) == 0o10
Doug Zongkereef39442009-04-02 12:14:19 -0700140
Michael Runge4038aa82013-12-13 18:06:28 -0800141def ClosestFileMatch(src, tgtfiles, existing):
142 """Returns the closest file match between a source file and list
143 of potential matches. The exact filename match is preferred,
144 then the sha1 is searched for, and finally a file with the same
145 basename is evaluated. Rename support in the updater-binary is
146 required for the latter checks to be used."""
147
148 result = tgtfiles.get("path:" + src.name)
149 if result is not None:
150 return result
151
152 if not OPTIONS.target_info_dict.get("update_rename_support", False):
153 return None
154
155 if src.size < 1000:
156 return None
157
158 result = tgtfiles.get("sha1:" + src.sha1)
159 if result is not None and existing.get(result.name) is None:
160 return result
161 result = tgtfiles.get("file:" + src.name.split("/")[-1])
162 if result is not None and existing.get(result.name) is None:
163 return result
164 return None
165
Dan Albert8b72aef2015-03-23 19:13:21 -0700166class ItemSet(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700167 def __init__(self, partition, fs_config):
168 self.partition = partition
169 self.fs_config = fs_config
170 self.ITEMS = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700171
Dan Albert8b72aef2015-03-23 19:13:21 -0700172 def Get(self, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700173 if name not in self.ITEMS:
Dan Albert8b72aef2015-03-23 19:13:21 -0700174 self.ITEMS[name] = Item(self, name, is_dir=is_dir)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700175 return self.ITEMS[name]
Doug Zongkereef39442009-04-02 12:14:19 -0700176
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700177 def GetMetadata(self, input_zip):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700178 # The target_files contains a record of what the uid,
179 # gid, and mode are supposed to be.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700180 output = input_zip.read(self.fs_config)
Doug Zongkereef39442009-04-02 12:14:19 -0700181
182 for line in output.split("\n"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700183 if not line:
184 continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700185 columns = line.split()
186 name, uid, gid, mode = columns[:4]
187 selabel = None
188 capabilities = None
189
190 # After the first 4 columns, there are a series of key=value
191 # pairs. Extract out the fields we care about.
192 for element in columns[4:]:
193 key, value = element.split("=")
194 if key == "selabel":
195 selabel = value
196 if key == "capabilities":
197 capabilities = value
198
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700199 i = self.ITEMS.get(name, None)
Doug Zongker283e2a12010-03-15 17:52:32 -0700200 if i is not None:
201 i.uid = int(uid)
202 i.gid = int(gid)
203 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700204 i.selabel = selabel
205 i.capabilities = capabilities
Dan Albert8b72aef2015-03-23 19:13:21 -0700206 if i.is_dir:
Doug Zongker283e2a12010-03-15 17:52:32 -0700207 i.children.sort(key=lambda i: i.name)
208
209 # set metadata for the files generated by this script.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700210 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700211 if i:
212 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700213 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700214 if i:
215 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700216
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700217
Dan Albert8b72aef2015-03-23 19:13:21 -0700218class Item(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700219 """Items represent the metadata (user, group, mode) of files and
220 directories in the system image."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700221 def __init__(self, itemset, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700222 self.itemset = itemset
223 self.name = name
224 self.uid = None
225 self.gid = None
226 self.mode = None
227 self.selabel = None
228 self.capabilities = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700229 self.is_dir = is_dir
230 self.descendants = None
231 self.best_subtree = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700232
233 if name:
Dan Albert8b72aef2015-03-23 19:13:21 -0700234 self.parent = itemset.Get(os.path.dirname(name), is_dir=True)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700235 self.parent.children.append(self)
236 else:
237 self.parent = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700238 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700239 self.children = []
240
241 def Dump(self, indent=0):
242 if self.uid is not None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700243 print "%s%s %d %d %o" % (
244 " " * indent, self.name, self.uid, self.gid, self.mode)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700245 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700246 print "%s%s %s %s %s" % (
247 " " * indent, self.name, self.uid, self.gid, self.mode)
248 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700249 print "%s%s" % (" "*indent, self.descendants)
250 print "%s%s" % (" "*indent, self.best_subtree)
251 for i in self.children:
252 i.Dump(indent=indent+1)
253
Doug Zongkereef39442009-04-02 12:14:19 -0700254 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700255 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
Dan Albert8b72aef2015-03-23 19:13:21 -0700256 all children and determine the best strategy for using set_perm_recursive
257 and set_perm to correctly chown/chmod all the files to their desired
Doug Zongkereef39442009-04-02 12:14:19 -0700258 values. Recursively calls itself for all descendants.
259
Dan Albert8b72aef2015-03-23 19:13:21 -0700260 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count}
261 counting up all descendants of this node. (dmode or fmode may be None.)
262 Also sets the best_subtree of each directory Item to the (uid, gid, dmode,
263 fmode, selabel, capabilities) tuple that will match the most descendants of
264 that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700265 """
266
Dan Albert8b72aef2015-03-23 19:13:21 -0700267 assert self.is_dir
268 key = (self.uid, self.gid, self.mode, None, self.selabel,
269 self.capabilities)
270 self.descendants = {key: 1}
271 d = self.descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700272 for i in self.children:
Dan Albert8b72aef2015-03-23 19:13:21 -0700273 if i.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700274 for k, v in i.CountChildMetadata().iteritems():
275 d[k] = d.get(k, 0) + v
276 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700277 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700278 d[k] = d.get(k, 0) + 1
279
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700280 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
281 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700282
283 # First, find the (uid, gid) pair that matches the most
284 # descendants.
285 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700286 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700287 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
288 ug = MostPopularKey(ug, (0, 0))
289
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700290 # Now find the dmode, fmode, selabel, and capabilities that match
291 # the most descendants with that (uid, gid), and choose those.
Dan Albert8b72aef2015-03-23 19:13:21 -0700292 best_dmode = (0, 0o755)
293 best_fmode = (0, 0o644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700294 best_selabel = (0, None)
295 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700296 for k, count in d.iteritems():
Dan Albert8b72aef2015-03-23 19:13:21 -0700297 if k[:2] != ug:
298 continue
299 if k[2] is not None and count >= best_dmode[0]:
300 best_dmode = (count, k[2])
301 if k[3] is not None and count >= best_fmode[0]:
302 best_fmode = (count, k[3])
303 if k[4] is not None and count >= best_selabel[0]:
304 best_selabel = (count, k[4])
305 if k[5] is not None and count >= best_capabilities[0]:
306 best_capabilities = (count, k[5])
307 self.best_subtree = ug + (
308 best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700309
310 return d
311
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700312 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700313 """Append set_perm/set_perm_recursive commands to 'script' to
314 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700315 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700316
317 self.CountChildMetadata()
318
319 def recurse(item, current):
Dan Albert8b72aef2015-03-23 19:13:21 -0700320 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple
321 # that the current item (and all its children) have already been set to.
322 # We only need to issue set_perm/set_perm_recursive commands if we're
Doug Zongkereef39442009-04-02 12:14:19 -0700323 # supposed to be something different.
Dan Albert8b72aef2015-03-23 19:13:21 -0700324 if item.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700325 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700326 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700327 current = item.best_subtree
328
329 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700330 item.mode != current[2] or item.selabel != current[4] or \
331 item.capabilities != current[5]:
332 script.SetPermissions("/"+item.name, item.uid, item.gid,
333 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700334
335 for i in item.children:
336 recurse(i, current)
337 else:
338 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700339 item.mode != current[3] or item.selabel != current[4] or \
340 item.capabilities != current[5]:
341 script.SetPermissions("/"+item.name, item.uid, item.gid,
342 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700343
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700344 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700345
346
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700347def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
348 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700349 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800350 list of symlinks. output_zip may be None, in which case the copy is
351 skipped (but the other side effects still happen). substitute is an
352 optional dict of {output filename: contents} to be output instead of
353 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700354 """
355
356 symlinks = []
357
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700358 partition = itemset.partition
359
Doug Zongkereef39442009-04-02 12:14:19 -0700360 for info in input_zip.infolist():
Tao Baoeaf885b2015-03-23 16:01:17 -0700361 prefix = partition.upper() + "/"
362 if info.filename.startswith(prefix):
363 basefilename = info.filename[len(prefix):]
Doug Zongkereef39442009-04-02 12:14:19 -0700364 if IsSymlink(info):
365 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700366 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700367 else:
368 info2 = copy.copy(info)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700369 fn = info2.filename = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700370 if substitute and fn in substitute and substitute[fn] is None:
371 continue
372 if output_zip is not None:
373 if substitute and fn in substitute:
374 data = substitute[fn]
375 else:
376 data = input_zip.read(info.filename)
377 output_zip.writestr(info2, data)
378 if fn.endswith("/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700379 itemset.Get(fn[:-1], is_dir=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700380 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700381 itemset.Get(fn)
Doug Zongkereef39442009-04-02 12:14:19 -0700382
383 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800384 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700385
386
Doug Zongkereef39442009-04-02 12:14:19 -0700387def SignOutput(temp_zip_name, output_zip_name):
388 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
389 pw = key_passwords[OPTIONS.package_key]
390
Doug Zongker951495f2009-08-14 12:44:19 -0700391 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
392 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700393
394
Dan Albert8b72aef2015-03-23 19:13:21 -0700395def AppendAssertions(script, info_dict, oem_dict=None):
Michael Runge6e836112014-04-15 17:40:21 -0700396 oem_props = info_dict.get("oem_fingerprint_properties")
Michael Runge560569a2014-09-18 15:12:45 -0700397 if oem_props is None or len(oem_props) == 0:
Michael Runge6e836112014-04-15 17:40:21 -0700398 device = GetBuildProp("ro.product.device", info_dict)
399 script.AssertDevice(device)
400 else:
401 if oem_dict is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700402 raise common.ExternalError(
403 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700404 for prop in oem_props.split():
405 if oem_dict.get(prop) is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700406 raise common.ExternalError(
407 "The OEM file is missing the property %s" % prop)
Michael Runge6e836112014-04-15 17:40:21 -0700408 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700409
Doug Zongkereef39442009-04-02 12:14:19 -0700410
Doug Zongkerc9253822014-02-04 12:17:58 -0800411def HasRecoveryPatch(target_files_zip):
412 try:
413 target_files_zip.getinfo("SYSTEM/recovery-from-boot.p")
414 return True
415 except KeyError:
416 return False
Doug Zongker73ef8252009-07-23 15:12:53 -0700417
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700418def HasVendorPartition(target_files_zip):
419 try:
420 target_files_zip.getinfo("VENDOR/")
421 return True
422 except KeyError:
423 return False
424
Michael Runge6e836112014-04-15 17:40:21 -0700425def GetOemProperty(name, oem_props, oem_dict, info_dict):
426 if oem_props is not None and name in oem_props:
427 return oem_dict[name]
428 return GetBuildProp(name, info_dict)
429
430
431def CalculateFingerprint(oem_props, oem_dict, info_dict):
432 if oem_props is None:
433 return GetBuildProp("ro.build.fingerprint", info_dict)
434 return "%s/%s/%s:%s" % (
Dan Albert8b72aef2015-03-23 19:13:21 -0700435 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
436 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
437 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
438 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700439
Doug Zongkerfc44a512014-08-26 13:10:25 -0700440
Doug Zongker3c84f562014-07-31 11:06:30 -0700441def GetImage(which, tmpdir, info_dict):
Doug Zongkerfc44a512014-08-26 13:10:25 -0700442 # Return an image object (suitable for passing to BlockImageDiff)
443 # for the 'which' partition (most be "system" or "vendor"). If a
444 # prebuilt image and file map are found in tmpdir they are used,
445 # otherwise they are reconstructed from the individual files.
Doug Zongker3c84f562014-07-31 11:06:30 -0700446
447 assert which in ("system", "vendor")
448
449 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700450 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
451 if os.path.exists(path) and os.path.exists(mappath):
Doug Zongker3c84f562014-07-31 11:06:30 -0700452 print "using %s.img from target-files" % (which,)
Doug Zongker3c84f562014-07-31 11:06:30 -0700453 # This is a 'new' target-files, which already has the image in it.
Doug Zongker3c84f562014-07-31 11:06:30 -0700454
455 else:
456 print "building %s.img from target-files" % (which,)
457
458 # This is an 'old' target-files, which does not contain images
459 # already built. Build them.
460
Doug Zongkerfc44a512014-08-26 13:10:25 -0700461 mappath = tempfile.mkstemp()[1]
462 OPTIONS.tempfiles.append(mappath)
463
Doug Zongker3c84f562014-07-31 11:06:30 -0700464 import add_img_to_target_files
465 if which == "system":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700466 path = add_img_to_target_files.BuildSystem(
467 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700468 elif which == "vendor":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700469 path = add_img_to_target_files.BuildVendor(
470 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700471
Doug Zongkerfc44a512014-08-26 13:10:25 -0700472 return sparse_img.SparseImage(path, mappath)
473
474
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700475def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700476 # TODO: how to determine this? We don't know what version it will
477 # be installed on top of. For now, we expect the API just won't
478 # change very often.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700479 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700480
Michael Runge6e836112014-04-15 17:40:21 -0700481 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700482 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700483 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700484 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700485 if OPTIONS.oem_source is None:
486 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700487 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700488 oem_dict = common.LoadDictionaryFromLines(
489 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -0700490
Dan Albert8b72aef2015-03-23 19:13:21 -0700491 metadata = {
492 "post-build": CalculateFingerprint(oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700493 OPTIONS.info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700494 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
495 OPTIONS.info_dict),
496 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
497 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700498
Doug Zongker05d3dea2009-06-22 11:32:31 -0700499 device_specific = common.DeviceSpecificParams(
500 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700501 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700502 output_zip=output_zip,
503 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700504 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700505 metadata=metadata,
506 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700507
Doug Zongkerc9253822014-02-04 12:17:58 -0800508 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800509 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800510
Doug Zongker962069c2009-04-23 11:41:58 -0700511 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700512 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700513 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
514 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700515
Michael Runge6e836112014-04-15 17:40:21 -0700516 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700517 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800518
519 # Two-step package strategy (in chronological order, which is *not*
520 # the order in which the generated script has things):
521 #
522 # if stage is not "2/3" or "3/3":
523 # write recovery image to boot partition
524 # set stage to "2/3"
525 # reboot to boot partition and restart recovery
526 # else if stage is "2/3":
527 # write recovery image to recovery partition
528 # set stage to "3/3"
529 # reboot to recovery partition and restart recovery
530 # else:
531 # (stage must be "3/3")
532 # set stage to ""
533 # do normal full package installation:
534 # wipe and install system, boot image, etc.
535 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700536 # complete script normally
537 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800538
539 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
540 OPTIONS.input_tmp, "RECOVERY")
541 if OPTIONS.two_step:
542 if not OPTIONS.info_dict.get("multistage_support", None):
543 assert False, "two-step packages not supported by this build"
544 fs = OPTIONS.info_dict["fstab"]["/misc"]
545 assert fs.fs_type.upper() == "EMMC", \
546 "two-step packages only supported on devices with EMMC /misc partitions"
547 bcb_dev = {"bcb_dev": fs.device}
548 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
549 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700550if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800551""" % bcb_dev)
552 script.WriteRawImage("/recovery", "recovery.img")
553 script.AppendExtra("""
554set_stage("%(bcb_dev)s", "3/3");
555reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700556else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800557""" % bcb_dev)
558
Doug Zongkere5ff5902012-01-17 10:55:37 -0800559 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700560
Doug Zongker01ce19c2014-02-04 13:48:15 -0800561 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700562
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700563 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800564 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700565 if HasVendorPartition(input_zip):
566 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700567
Kenny Rootf32dc712012-04-08 10:42:34 -0700568 if "selinux_fc" in OPTIONS.info_dict:
569 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500570
Michael Runge7cd99ba2014-10-22 17:21:48 -0700571 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
572
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700573 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700574 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800575
Doug Zongker26e66192014-02-20 13:22:07 -0800576 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700577 # Full OTA is done as an "incremental" against an empty source
578 # image. This has the effect of writing new data from the package
579 # to the entire partition, but lets us reuse the updater code that
580 # writes incrementals to do it.
581 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
582 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700583 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700584 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800585 else:
586 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700587 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800588 if not has_recovery_patch:
589 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800590 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700591
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700592 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800593 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700594
Doug Zongker55d93282011-01-25 17:03:34 -0800595 boot_img = common.GetBootableImage("boot.img", "boot.img",
596 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800597
Doug Zongker91a99c22014-05-09 13:15:01 -0700598 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800599 def output_sink(fn, data):
600 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700601 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800602
603 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
604 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700605
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700606 system_items.GetMetadata(input_zip)
607 system_items.Get("system").SetPermissions(script)
608
609 if HasVendorPartition(input_zip):
610 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
611 script.ShowProgress(0.1, 0)
612
613 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700614 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
615 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700616 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700617 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700618 else:
619 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700620 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700621 script.UnpackPackageDir("vendor", "/vendor")
622
623 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
624 script.MakeSymlinks(symlinks)
625
626 vendor_items.GetMetadata(input_zip)
627 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700628
Doug Zongker37974732010-09-16 17:44:38 -0700629 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700630 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700631
Doug Zongker01ce19c2014-02-04 13:48:15 -0800632 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700633 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700634
Doug Zongker01ce19c2014-02-04 13:48:15 -0800635 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700636 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700637
Doug Zongker1c390a22009-05-14 19:06:36 -0700638 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700639 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700640
Doug Zongker14833602010-02-02 13:12:04 -0800641 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800642
Doug Zongker922206e2014-03-04 13:16:24 -0800643 if OPTIONS.wipe_user_data:
644 script.ShowProgress(0.1, 10)
645 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700646
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800647 if OPTIONS.two_step:
648 script.AppendExtra("""
649set_stage("%(bcb_dev)s", "");
650""" % bcb_dev)
651 script.AppendExtra("else\n")
652 script.WriteRawImage("/boot", "recovery.img")
653 script.AppendExtra("""
654set_stage("%(bcb_dev)s", "2/3");
655reboot_now("%(bcb_dev)s", "");
656endif;
657endif;
658""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800659 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700660 WriteMetadata(metadata, output_zip)
661
Doug Zongkerfc44a512014-08-26 13:10:25 -0700662
Dan Albert8e0178d2015-01-27 15:53:15 -0800663def WritePolicyConfig(file_name, output_zip):
664 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500665
Doug Zongker2ea21062010-04-28 16:05:21 -0700666
667def WriteMetadata(metadata, output_zip):
668 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
669 "".join(["%s=%s\n" % kv
670 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700671
Doug Zongkerfc44a512014-08-26 13:10:25 -0700672
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700673def LoadPartitionFiles(z, partition):
674 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700675 ZipFile, and return a dict of {filename: File object}."""
676 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700677 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700678 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700679 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700680 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700681 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700682 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700683 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800684 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700685
686
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700687def GetBuildProp(prop, info_dict):
688 """Return the fingerprint of the build of a given target-files info_dict."""
689 try:
690 return info_dict.get("build.prop", {})[prop]
691 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700692 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700693
Doug Zongkerfc44a512014-08-26 13:10:25 -0700694
Michael Runge4038aa82013-12-13 18:06:28 -0800695def AddToKnownPaths(filename, known_paths):
696 if filename[-1] == "/":
697 return
698 dirs = filename.split("/")[:-1]
699 while len(dirs) > 0:
700 path = "/".join(dirs)
701 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700702 break
Michael Runge4038aa82013-12-13 18:06:28 -0800703 known_paths.add(path)
704 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700705
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700706
Geremy Condra36bd3652014-02-06 19:45:10 -0800707def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
708 source_version = OPTIONS.source_info_dict["recovery_api_version"]
709 target_version = OPTIONS.target_info_dict["recovery_api_version"]
710
711 if source_version == 0:
712 print ("WARNING: generating edify script for a source that "
713 "can't install it.")
714 script = edify_generator.EdifyGenerator(source_version,
715 OPTIONS.target_info_dict)
716
Dan Albert8b72aef2015-03-23 19:13:21 -0700717 metadata = {
718 "pre-device": GetBuildProp("ro.product.device",
719 OPTIONS.source_info_dict),
720 "post-timestamp": GetBuildProp("ro.build.date.utc",
721 OPTIONS.target_info_dict),
722 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800723
724 device_specific = common.DeviceSpecificParams(
725 source_zip=source_zip,
726 source_version=source_version,
727 target_zip=target_zip,
728 target_version=target_version,
729 output_zip=output_zip,
730 script=script,
731 metadata=metadata,
732 info_dict=OPTIONS.info_dict)
733
734 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
735 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
736 metadata["pre-build"] = source_fp
737 metadata["post-build"] = target_fp
738
739 source_boot = common.GetBootableImage(
740 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
741 OPTIONS.source_info_dict)
742 target_boot = common.GetBootableImage(
743 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
744 updating_boot = (not OPTIONS.two_step and
745 (source_boot.data != target_boot.data))
746
Geremy Condra36bd3652014-02-06 19:45:10 -0800747 target_recovery = common.GetBootableImage(
748 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800749
Doug Zongkerfc44a512014-08-26 13:10:25 -0700750 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
751 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700752
753 blockimgdiff_version = 1
754 if OPTIONS.info_dict:
755 blockimgdiff_version = max(
756 int(i) for i in
757 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
758
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700759 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700760 check_first_block=True,
761 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700762
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700763 if HasVendorPartition(target_zip):
764 if not HasVendorPartition(source_zip):
765 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700766 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
767 OPTIONS.source_info_dict)
768 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
769 OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700770 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700771 check_first_block=True,
772 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700773 else:
774 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800775
Michael Rungec6e3afd2014-05-05 11:55:47 -0700776 oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
Dan Albert8b72aef2015-03-23 19:13:21 -0700777 recovery_mount_options = OPTIONS.target_info_dict.get(
778 "recovery_mount_options")
Michael Rungec6e3afd2014-05-05 11:55:47 -0700779 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700780 if oem_props is not None and len(oem_props) > 0:
Michael Rungec6e3afd2014-05-05 11:55:47 -0700781 if OPTIONS.oem_source is None:
782 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700783 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700784 oem_dict = common.LoadDictionaryFromLines(
785 open(OPTIONS.oem_source).readlines())
Michael Rungec6e3afd2014-05-05 11:55:47 -0700786
787 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800788 device_specific.IncrementalOTA_Assertions()
789
790 # Two-step incremental package strategy (in chronological order,
791 # which is *not* the order in which the generated script has
792 # things):
793 #
794 # if stage is not "2/3" or "3/3":
795 # do verification on current system
796 # write recovery image to boot partition
797 # set stage to "2/3"
798 # reboot to boot partition and restart recovery
799 # else if stage is "2/3":
800 # write recovery image to recovery partition
801 # set stage to "3/3"
802 # reboot to recovery partition and restart recovery
803 # else:
804 # (stage must be "3/3")
805 # perform update:
806 # patch system files, etc.
807 # force full install of new boot image
808 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700809 # complete script normally
810 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800811
812 if OPTIONS.two_step:
813 if not OPTIONS.info_dict.get("multistage_support", None):
814 assert False, "two-step packages not supported by this build"
815 fs = OPTIONS.info_dict["fstab"]["/misc"]
816 assert fs.fs_type.upper() == "EMMC", \
817 "two-step packages only supported on devices with EMMC /misc partitions"
818 bcb_dev = {"bcb_dev": fs.device}
819 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
820 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700821if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800822""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -0700823 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800824 script.WriteRawImage("/recovery", "recovery.img")
825 script.AppendExtra("""
826set_stage("%(bcb_dev)s", "3/3");
827reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700828else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800829""" % bcb_dev)
830
831 script.Print("Verifying current system...")
832
833 device_specific.IncrementalOTA_VerifyBegin()
834
Michael Rungec6e3afd2014-05-05 11:55:47 -0700835 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700836 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
837 # patching on a device that's already on the target build will damage the
838 # system. Because operations like move don't check the block state, they
839 # always apply the changes unconditionally.
840 if blockimgdiff_version <= 2:
841 script.AssertSomeFingerprint(source_fp)
842 else:
843 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700844 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700845 if blockimgdiff_version <= 2:
846 script.AssertSomeThumbprint(
847 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
848 else:
849 script.AssertSomeThumbprint(
850 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
851 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800852
853 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700854 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800855 d = common.Difference(target_boot, source_boot)
856 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700857 if d is None:
858 include_full_boot = True
859 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
860 else:
861 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800862
Doug Zongkerf8340082014-08-05 10:39:37 -0700863 print "boot target: %d source: %d diff: %d" % (
864 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800865
Doug Zongkerf8340082014-08-05 10:39:37 -0700866 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800867
Doug Zongkerf8340082014-08-05 10:39:37 -0700868 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
869 (boot_type, boot_device,
870 source_boot.size, source_boot.sha1,
871 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800872
873 device_specific.IncrementalOTA_VerifyEnd()
874
875 if OPTIONS.two_step:
876 script.WriteRawImage("/boot", "recovery.img")
877 script.AppendExtra("""
878set_stage("%(bcb_dev)s", "2/3");
879reboot_now("%(bcb_dev)s", "");
880else
881""" % bcb_dev)
882
Jesse Zhao75bcea02015-01-06 10:59:53 -0800883 # Verify the existing partitions.
884 system_diff.WriteVerifyScript(script)
885 if vendor_diff:
886 vendor_diff.WriteVerifyScript(script)
887
Geremy Condra36bd3652014-02-06 19:45:10 -0800888 script.Comment("---- start making changes here ----")
889
890 device_specific.IncrementalOTA_InstallBegin()
891
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700892 system_diff.WriteScript(script, output_zip,
893 progress=0.8 if vendor_diff else 0.9)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700894 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700895 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800896
897 if OPTIONS.two_step:
898 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
899 script.WriteRawImage("/boot", "boot.img")
900 print "writing full boot image (forced by two-step mode)"
901
902 if not OPTIONS.two_step:
903 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700904 if include_full_boot:
905 print "boot image changed; including full."
906 script.Print("Installing boot image...")
907 script.WriteRawImage("/boot", "boot.img")
908 else:
909 # Produce the boot image by applying a patch to the current
910 # contents of the boot partition, and write it back to the
911 # partition.
912 print "boot image changed; including patch."
913 script.Print("Patching boot image...")
914 script.ShowProgress(0.1, 10)
915 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
916 % (boot_type, boot_device,
917 source_boot.size, source_boot.sha1,
918 target_boot.size, target_boot.sha1),
919 "-",
920 target_boot.size, target_boot.sha1,
921 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800922 else:
923 print "boot image unchanged; skipping."
924
925 # Do device-specific installation (eg, write radio image).
926 device_specific.IncrementalOTA_InstallEnd()
927
928 if OPTIONS.extra_script is not None:
929 script.AppendExtra(OPTIONS.extra_script)
930
Doug Zongker922206e2014-03-04 13:16:24 -0800931 if OPTIONS.wipe_user_data:
932 script.Print("Erasing user data...")
933 script.FormatPartition("/data")
934
Geremy Condra36bd3652014-02-06 19:45:10 -0800935 if OPTIONS.two_step:
936 script.AppendExtra("""
937set_stage("%(bcb_dev)s", "");
938endif;
939endif;
940""" % bcb_dev)
941
942 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800943 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800944 WriteMetadata(metadata, output_zip)
945
Doug Zongker32b527d2014-03-04 10:03:02 -0800946
Dan Albert8b72aef2015-03-23 19:13:21 -0700947class FileDifference(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700948 def __init__(self, partition, source_zip, target_zip, output_zip):
Dan Albert8b72aef2015-03-23 19:13:21 -0700949 self.deferred_patch_list = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700950 print "Loading target..."
951 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
952 print "Loading source..."
953 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
954
955 self.verbatim_targets = verbatim_targets = []
956 self.patch_list = patch_list = []
957 diffs = []
958 self.renames = renames = {}
959 known_paths = set()
960 largest_source_size = 0
961
962 matching_file_cache = {}
963 for fn, sf in source_data.items():
964 assert fn == sf.name
965 matching_file_cache["path:" + fn] = sf
966 if fn in target_data.keys():
967 AddToKnownPaths(fn, known_paths)
968 # Only allow eligibility for filename/sha matching
969 # if there isn't a perfect path match.
970 if target_data.get(sf.name) is None:
971 matching_file_cache["file:" + fn.split("/")[-1]] = sf
972 matching_file_cache["sha:" + sf.sha1] = sf
973
974 for fn in sorted(target_data.keys()):
975 tf = target_data[fn]
976 assert fn == tf.name
977 sf = ClosestFileMatch(tf, matching_file_cache, renames)
978 if sf is not None and sf.name != tf.name:
979 print "File has moved from " + sf.name + " to " + tf.name
980 renames[sf.name] = tf
981
982 if sf is None or fn in OPTIONS.require_verbatim:
983 # This file should be included verbatim
984 if fn in OPTIONS.prohibit_verbatim:
985 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
986 print "send", fn, "verbatim"
987 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -0700988 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700989 if fn in target_data.keys():
990 AddToKnownPaths(fn, known_paths)
991 elif tf.sha1 != sf.sha1:
992 # File is different; consider sending as a patch
993 diffs.append(common.Difference(tf, sf))
994 else:
995 # Target file data identical to source (may still be renamed)
996 pass
997
998 common.ComputeDifferences(diffs)
999
1000 for diff in diffs:
1001 tf, sf, d = diff.GetPatch()
1002 path = "/".join(tf.name.split("/")[:-1])
1003 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1004 path not in known_paths:
1005 # patch is almost as big as the file; don't bother patching
1006 # or a patch + rename cannot take place due to the target
1007 # directory not existing
1008 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001009 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001010 if sf.name in renames:
1011 del renames[sf.name]
1012 AddToKnownPaths(tf.name, known_paths)
1013 else:
1014 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1015 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1016 largest_source_size = max(largest_source_size, sf.size)
1017
1018 self.largest_source_size = largest_source_size
1019
1020 def EmitVerification(self, script):
1021 so_far = 0
Dan Albert8b72aef2015-03-23 19:13:21 -07001022 for tf, sf, _, _ in self.patch_list:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001023 if tf.name != sf.name:
1024 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1025 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1026 so_far += sf.size
1027 return so_far
1028
Michael Runge63f01de2014-10-28 19:24:19 -07001029 def EmitExplicitTargetVerification(self, script):
Dan Albert8b72aef2015-03-23 19:13:21 -07001030 for fn, _, sha1 in self.verbatim_targets:
1031 if fn[-1] != "/":
Michael Runge63f01de2014-10-28 19:24:19 -07001032 script.FileCheck("/"+fn, sha1)
1033 for tf, _, _, _ in self.patch_list:
1034 script.FileCheck(tf.name, tf.sha1)
1035
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001036 def RemoveUnneededFiles(self, script, extras=()):
Dan Albert8b72aef2015-03-23 19:13:21 -07001037 script.DeleteFiles(
1038 ["/" + i[0] for i in self.verbatim_targets] +
1039 ["/" + i for i in sorted(self.source_data)
1040 if i not in self.target_data and i not in self.renames] +
1041 list(extras))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001042
1043 def TotalPatchSize(self):
1044 return sum(i[1].size for i in self.patch_list)
1045
1046 def EmitPatches(self, script, total_patch_size, so_far):
1047 self.deferred_patch_list = deferred_patch_list = []
1048 for item in self.patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001049 tf, sf, _, _ = item
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001050 if tf.name == "system/build.prop":
1051 deferred_patch_list.append(item)
1052 continue
Dan Albert8b72aef2015-03-23 19:13:21 -07001053 if sf.name != tf.name:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001054 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
Dan Albert8b72aef2015-03-23 19:13:21 -07001055 script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1,
1056 "patch/" + sf.name + ".p")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001057 so_far += tf.size
1058 script.SetProgress(so_far / total_patch_size)
1059 return so_far
1060
1061 def EmitDeferredPatches(self, script):
1062 for item in self.deferred_patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001063 tf, sf, _, _ = item
1064 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1,
1065 "patch/" + sf.name + ".p")
1066 script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001067
1068 def EmitRenames(self, script):
1069 if len(self.renames) > 0:
1070 script.Print("Renaming files...")
1071 for src, tgt in self.renames.iteritems():
1072 print "Renaming " + src + " to " + tgt.name
1073 script.RenameFile(src, tgt.name)
1074
1075
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001076def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001077 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1078 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1079
Doug Zongker26e66192014-02-20 13:22:07 -08001080 if (OPTIONS.block_based and
1081 target_has_recovery_patch and
1082 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001083 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1084
Doug Zongker37974732010-09-16 17:44:38 -07001085 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1086 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001087
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001088 if source_version == 0:
1089 print ("WARNING: generating edify script for a source that "
1090 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -07001091 script = edify_generator.EdifyGenerator(source_version,
1092 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -07001093
Michael Runge6e836112014-04-15 17:40:21 -07001094 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001095 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001096 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001097 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001098 if OPTIONS.oem_source is None:
1099 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001100 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001101 oem_dict = common.LoadDictionaryFromLines(
1102 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001103
Dan Albert8b72aef2015-03-23 19:13:21 -07001104 metadata = {
1105 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1106 OPTIONS.source_info_dict),
1107 "post-timestamp": GetBuildProp("ro.build.date.utc",
1108 OPTIONS.target_info_dict),
1109 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001110
Doug Zongker05d3dea2009-06-22 11:32:31 -07001111 device_specific = common.DeviceSpecificParams(
1112 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001113 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001114 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001115 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001116 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001117 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001118 metadata=metadata,
1119 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001120
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001121 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001122 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001123 if HasVendorPartition(target_zip):
1124 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001125 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001126 else:
1127 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001128
Dan Albert8b72aef2015-03-23 19:13:21 -07001129 target_fp = CalculateFingerprint(oem_props, oem_dict,
1130 OPTIONS.target_info_dict)
1131 source_fp = CalculateFingerprint(oem_props, oem_dict,
1132 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001133
1134 if oem_props is None:
1135 script.AssertSomeFingerprint(source_fp, target_fp)
1136 else:
1137 script.AssertSomeThumbprint(
1138 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1139 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1140
Doug Zongker2ea21062010-04-28 16:05:21 -07001141 metadata["pre-build"] = source_fp
1142 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001143
Doug Zongker55d93282011-01-25 17:03:34 -08001144 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001145 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1146 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001147 target_boot = common.GetBootableImage(
1148 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001149 updating_boot = (not OPTIONS.two_step and
1150 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001151
Doug Zongker55d93282011-01-25 17:03:34 -08001152 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001153 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1154 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001155 target_recovery = common.GetBootableImage(
1156 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001157 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001158
Doug Zongker881dd402009-09-20 14:03:55 -07001159 # Here's how we divide up the progress bar:
1160 # 0.1 for verifying the start state (PatchCheck calls)
1161 # 0.8 for applying patches (ApplyPatch calls)
1162 # 0.1 for unpacking verbatim files, symlinking, and doing the
1163 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001164
Michael Runge6e836112014-04-15 17:40:21 -07001165 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001166 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001167
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001168 # Two-step incremental package strategy (in chronological order,
1169 # which is *not* the order in which the generated script has
1170 # things):
1171 #
1172 # if stage is not "2/3" or "3/3":
1173 # do verification on current system
1174 # write recovery image to boot partition
1175 # set stage to "2/3"
1176 # reboot to boot partition and restart recovery
1177 # else if stage is "2/3":
1178 # write recovery image to recovery partition
1179 # set stage to "3/3"
1180 # reboot to recovery partition and restart recovery
1181 # else:
1182 # (stage must be "3/3")
1183 # perform update:
1184 # patch system files, etc.
1185 # force full install of new boot image
1186 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001187 # complete script normally
1188 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001189
1190 if OPTIONS.two_step:
1191 if not OPTIONS.info_dict.get("multistage_support", None):
1192 assert False, "two-step packages not supported by this build"
1193 fs = OPTIONS.info_dict["fstab"]["/misc"]
1194 assert fs.fs_type.upper() == "EMMC", \
1195 "two-step packages only supported on devices with EMMC /misc partitions"
1196 bcb_dev = {"bcb_dev": fs.device}
1197 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1198 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001199if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001200""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001201 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001202 script.WriteRawImage("/recovery", "recovery.img")
1203 script.AppendExtra("""
1204set_stage("%(bcb_dev)s", "3/3");
1205reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001206else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001207""" % bcb_dev)
1208
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001209 script.Print("Verifying current system...")
1210
Doug Zongkere5ff5902012-01-17 10:55:37 -08001211 device_specific.IncrementalOTA_VerifyBegin()
1212
Doug Zongker881dd402009-09-20 14:03:55 -07001213 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001214 so_far = system_diff.EmitVerification(script)
1215 if vendor_diff:
1216 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001217
Doug Zongker5da317e2009-06-02 13:38:17 -07001218 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001219 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001220 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001221 print "boot target: %d source: %d diff: %d" % (
1222 target_boot.size, source_boot.size, len(d))
1223
Doug Zongker048e7ca2009-06-15 14:31:53 -07001224 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001225
Doug Zongker96a57e72010-09-26 14:57:41 -07001226 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001227
1228 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1229 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001230 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001231 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001232 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001233
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001234 size = []
Dan Albert8b72aef2015-03-23 19:13:21 -07001235 if system_diff.patch_list:
1236 size.append(system_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001237 if vendor_diff:
Dan Albert8b72aef2015-03-23 19:13:21 -07001238 if vendor_diff.patch_list:
1239 size.append(vendor_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001240 if size or updating_recovery or updating_boot:
1241 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001242
Doug Zongker05d3dea2009-06-22 11:32:31 -07001243 device_specific.IncrementalOTA_VerifyEnd()
1244
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001245 if OPTIONS.two_step:
1246 script.WriteRawImage("/boot", "recovery.img")
1247 script.AppendExtra("""
1248set_stage("%(bcb_dev)s", "2/3");
1249reboot_now("%(bcb_dev)s", "");
1250else
1251""" % bcb_dev)
1252
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001253 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001254
Doug Zongkere5ff5902012-01-17 10:55:37 -08001255 device_specific.IncrementalOTA_InstallBegin()
1256
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001257 if OPTIONS.two_step:
1258 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1259 script.WriteRawImage("/boot", "boot.img")
1260 print "writing full boot image (forced by two-step mode)"
1261
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001262 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001263 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1264 if vendor_diff:
1265 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001266
Doug Zongker881dd402009-09-20 14:03:55 -07001267 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001268 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1269 if vendor_diff:
1270 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001271 if updating_boot:
1272 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001273
1274 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001275 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1276 if vendor_diff:
1277 script.Print("Patching vendor files...")
1278 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001279
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001280 if not OPTIONS.two_step:
1281 if updating_boot:
1282 # Produce the boot image by applying a patch to the current
1283 # contents of the boot partition, and write it back to the
1284 # partition.
1285 script.Print("Patching boot image...")
1286 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1287 % (boot_type, boot_device,
1288 source_boot.size, source_boot.sha1,
1289 target_boot.size, target_boot.sha1),
1290 "-",
1291 target_boot.size, target_boot.sha1,
1292 source_boot.sha1, "patch/boot.img.p")
1293 so_far += target_boot.size
1294 script.SetProgress(so_far / total_patch_size)
1295 print "boot image changed; including."
1296 else:
1297 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001298
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001299 system_items = ItemSet("system", "META/filesystem_config.txt")
1300 if vendor_diff:
1301 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1302
Doug Zongkereef39442009-04-02 12:14:19 -07001303 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001304 # Recovery is generated as a patch using both the boot image
1305 # (which contains the same linux kernel as recovery) and the file
1306 # /system/etc/recovery-resource.dat (which contains all the images
1307 # used in the recovery UI) as sources. This lets us minimize the
1308 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001309 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001310 # For older builds where recovery-resource.dat is not present, we
1311 # use only the boot image as the source.
1312
Doug Zongkerc9253822014-02-04 12:17:58 -08001313 if not target_has_recovery_patch:
1314 def output_sink(fn, data):
1315 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001316 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001317
1318 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1319 target_recovery, target_boot)
1320 script.DeleteFiles(["/system/recovery-from-boot.p",
1321 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001322 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001323 else:
1324 print "recovery image unchanged; skipping."
1325
Doug Zongker881dd402009-09-20 14:03:55 -07001326 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001327
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001328 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1329 if vendor_diff:
1330 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1331
1332 temp_script = script.MakeTemporary()
1333 system_items.GetMetadata(target_zip)
1334 system_items.Get("system").SetPermissions(temp_script)
1335 if vendor_diff:
1336 vendor_items.GetMetadata(target_zip)
1337 vendor_items.Get("vendor").SetPermissions(temp_script)
1338
1339 # Note that this call will mess up the trees of Items, so make sure
1340 # we're done with them.
1341 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1342 if vendor_diff:
1343 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001344
1345 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001346 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1347
1348 # Delete all the symlinks in source that aren't in target. This
1349 # needs to happen before verbatim files are unpacked, in case a
1350 # symlink in the source is replaced by a real file in the target.
1351 to_delete = []
1352 for dest, link in source_symlinks:
1353 if link not in target_symlinks_d:
1354 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001355 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001356
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001357 if system_diff.verbatim_targets:
1358 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001359 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001360 if vendor_diff and vendor_diff.verbatim_targets:
1361 script.Print("Unpacking new vendor files...")
1362 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001363
Doug Zongkerc9253822014-02-04 12:17:58 -08001364 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001365 script.Print("Unpacking new recovery...")
1366 script.UnpackPackageDir("recovery", "/system")
1367
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001368 system_diff.EmitRenames(script)
1369 if vendor_diff:
1370 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001371
Doug Zongker05d3dea2009-06-22 11:32:31 -07001372 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001373
1374 # Create all the symlinks that don't already exist, or point to
1375 # somewhere different than what we want. Delete each symlink before
1376 # creating it, since the 'symlink' command won't overwrite.
1377 to_create = []
1378 for dest, link in target_symlinks:
1379 if link in source_symlinks_d:
1380 if dest != source_symlinks_d[link]:
1381 to_create.append((dest, link))
1382 else:
1383 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001384 script.DeleteFiles([i[1] for i in to_create])
1385 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001386
1387 # Now that the symlinks are created, we can set all the
1388 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001389 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001390
Doug Zongker881dd402009-09-20 14:03:55 -07001391 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001392 device_specific.IncrementalOTA_InstallEnd()
1393
Doug Zongker1c390a22009-05-14 19:06:36 -07001394 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001395 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001396
Doug Zongkere92f15a2011-08-26 13:46:40 -07001397 # Patch the build.prop file last, so if something fails but the
1398 # device can still come up, it appears to be the old build and will
1399 # get set the OTA package again to retry.
1400 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001401 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001402
Doug Zongker922206e2014-03-04 13:16:24 -08001403 if OPTIONS.wipe_user_data:
1404 script.Print("Erasing user data...")
1405 script.FormatPartition("/data")
1406
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001407 if OPTIONS.two_step:
1408 script.AppendExtra("""
1409set_stage("%(bcb_dev)s", "");
1410endif;
1411endif;
1412""" % bcb_dev)
1413
Michael Runge63f01de2014-10-28 19:24:19 -07001414 if OPTIONS.verify and system_diff:
1415 script.Print("Remounting and verifying system partition files...")
1416 script.Unmount("/system")
1417 script.Mount("/system")
1418 system_diff.EmitExplicitTargetVerification(script)
1419
1420 if OPTIONS.verify and vendor_diff:
1421 script.Print("Remounting and verifying vendor partition files...")
1422 script.Unmount("/vendor")
1423 script.Mount("/vendor")
1424 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001425 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001426
Doug Zongker2ea21062010-04-28 16:05:21 -07001427 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001428
1429
1430def main(argv):
1431
1432 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001433 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001434 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001435 elif o in ("-k", "--package_key"):
1436 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001437 elif o in ("-i", "--incremental_from"):
1438 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001439 elif o in ("-w", "--wipe_user_data"):
1440 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001441 elif o in ("-n", "--no_prereq"):
1442 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001443 elif o in ("-o", "--oem_settings"):
1444 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001445 elif o in ("-e", "--extra_script"):
1446 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001447 elif o in ("-a", "--aslr_mode"):
1448 if a in ("on", "On", "true", "True", "yes", "Yes"):
1449 OPTIONS.aslr_mode = True
1450 else:
1451 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001452 elif o in ("-t", "--worker_threads"):
1453 if a.isdigit():
1454 OPTIONS.worker_threads = int(a)
1455 else:
1456 raise ValueError("Cannot parse value %r for option %r - only "
1457 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001458 elif o in ("-2", "--two_step"):
1459 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001460 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001461 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001462 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001463 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001464 elif o == "--block":
1465 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001466 elif o in ("-b", "--binary"):
1467 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001468 elif o in ("--no_fallback_to_full",):
1469 OPTIONS.fallback_to_full = False
Doug Zongkereef39442009-04-02 12:14:19 -07001470 else:
1471 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001472 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001473
1474 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001475 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001476 extra_long_opts=[
1477 "board_config=",
1478 "package_key=",
1479 "incremental_from=",
1480 "wipe_user_data",
1481 "no_prereq",
1482 "extra_script=",
1483 "worker_threads=",
1484 "aslr_mode=",
1485 "two_step",
1486 "no_signing",
1487 "block",
1488 "binary=",
1489 "oem_settings=",
1490 "verify",
1491 "no_fallback_to_full",
1492 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001493
1494 if len(args) != 2:
1495 common.Usage(__doc__)
1496 sys.exit(1)
1497
Doug Zongker1c390a22009-05-14 19:06:36 -07001498 if OPTIONS.extra_script is not None:
1499 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1500
Doug Zongkereef39442009-04-02 12:14:19 -07001501 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001502 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001503
Doug Zongkereef39442009-04-02 12:14:19 -07001504 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001505 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001506
1507 # If this image was originally labelled with SELinux contexts, make sure we
1508 # also apply the labels in our new image. During building, the "file_contexts"
1509 # is in the out/ directory tree, but for repacking from target-files.zip it's
1510 # in the root directory of the ramdisk.
1511 if "selinux_fc" in OPTIONS.info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001512 OPTIONS.info_dict["selinux_fc"] = os.path.join(
1513 OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")
Kenny Roote2e9f612013-05-29 12:59:35 -07001514
Doug Zongker37974732010-09-16 17:44:38 -07001515 if OPTIONS.verbose:
1516 print "--- target info ---"
1517 common.DumpInfoDict(OPTIONS.info_dict)
1518
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001519 # If the caller explicitly specified the device-specific extensions
1520 # path via -s/--device_specific, use that. Otherwise, use
1521 # META/releasetools.py if it is present in the target target_files.
1522 # Otherwise, take the path of the file from 'tool_extensions' in the
1523 # info dict and look for that in the local filesystem, relative to
1524 # the current directory.
1525
Doug Zongker37974732010-09-16 17:44:38 -07001526 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001527 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1528 if os.path.exists(from_input):
1529 print "(using device-specific extensions from target_files)"
1530 OPTIONS.device_specific = from_input
1531 else:
1532 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1533
Doug Zongker37974732010-09-16 17:44:38 -07001534 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001535 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001536
Doug Zongker62d4f182014-08-04 16:06:43 -07001537 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001538
Doug Zongker62d4f182014-08-04 16:06:43 -07001539 if OPTIONS.no_signing:
Dan Albert8b72aef2015-03-23 19:13:21 -07001540 if os.path.exists(args[1]):
1541 os.unlink(args[1])
1542 output_zip = zipfile.ZipFile(args[1], "w",
1543 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001544 else:
1545 temp_zip_file = tempfile.NamedTemporaryFile()
1546 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1547 compression=zipfile.ZIP_DEFLATED)
1548
1549 if OPTIONS.incremental_source is None:
1550 WriteFullOTAPackage(input_zip, output_zip)
1551 if OPTIONS.package_key is None:
1552 OPTIONS.package_key = OPTIONS.info_dict.get(
1553 "default_system_dev_certificate",
1554 "build/target/product/security/testkey")
1555 break
1556
1557 else:
1558 print "unzipping source target-files..."
Dan Albert8b72aef2015-03-23 19:13:21 -07001559 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
1560 OPTIONS.incremental_source)
Doug Zongker62d4f182014-08-04 16:06:43 -07001561 OPTIONS.target_info_dict = OPTIONS.info_dict
1562 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1563 if "selinux_fc" in OPTIONS.source_info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001564 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(
1565 OPTIONS.source_tmp, "BOOT", "RAMDISK", "file_contexts")
Doug Zongker62d4f182014-08-04 16:06:43 -07001566 if OPTIONS.package_key is None:
1567 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1568 "default_system_dev_certificate",
1569 "build/target/product/security/testkey")
1570 if OPTIONS.verbose:
1571 print "--- source info ---"
1572 common.DumpInfoDict(OPTIONS.source_info_dict)
1573 try:
1574 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
1575 break
1576 except ValueError:
Dan Albert8b72aef2015-03-23 19:13:21 -07001577 if not OPTIONS.fallback_to_full:
1578 raise
Doug Zongker62d4f182014-08-04 16:06:43 -07001579 print "--- failed to build incremental; falling back to full ---"
1580 OPTIONS.incremental_source = None
1581 output_zip.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001582
1583 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001584
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001585 if not OPTIONS.no_signing:
1586 SignOutput(temp_zip_file.name, args[1])
1587 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001588
Doug Zongkereef39442009-04-02 12:14:19 -07001589 print "done."
1590
1591
1592if __name__ == '__main__':
1593 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001594 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001595 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001596 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07001597 print
1598 print " ERROR: %s" % (e,)
1599 print
1600 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001601 finally:
1602 common.Cleanup()