blob: 21565fcfdc45c1975ed17489f6c111e12660d666 [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
Tao Bao6c55a8a2015-04-08 15:30:27 -0700559 # Dump fingerprints
560 script.Print("Target: %s" % CalculateFingerprint(
561 oem_props, oem_dict, OPTIONS.info_dict))
562
Doug Zongkere5ff5902012-01-17 10:55:37 -0800563 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700564
Doug Zongker01ce19c2014-02-04 13:48:15 -0800565 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700566
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700567 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800568 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700569 if HasVendorPartition(input_zip):
570 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700571
Kenny Rootf32dc712012-04-08 10:42:34 -0700572 if "selinux_fc" in OPTIONS.info_dict:
573 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500574
Michael Runge7cd99ba2014-10-22 17:21:48 -0700575 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
576
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700577 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700578 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800579
Doug Zongker26e66192014-02-20 13:22:07 -0800580 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700581 # Full OTA is done as an "incremental" against an empty source
582 # image. This has the effect of writing new data from the package
583 # to the entire partition, but lets us reuse the updater code that
584 # writes incrementals to do it.
585 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
586 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700587 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700588 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800589 else:
590 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700591 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800592 if not has_recovery_patch:
593 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800594 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700595
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700596 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800597 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700598
Doug Zongker55d93282011-01-25 17:03:34 -0800599 boot_img = common.GetBootableImage("boot.img", "boot.img",
600 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800601
Doug Zongker91a99c22014-05-09 13:15:01 -0700602 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800603 def output_sink(fn, data):
604 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700605 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800606
607 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
608 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700609
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700610 system_items.GetMetadata(input_zip)
611 system_items.Get("system").SetPermissions(script)
612
613 if HasVendorPartition(input_zip):
614 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
615 script.ShowProgress(0.1, 0)
616
617 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700618 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
619 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700620 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700621 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700622 else:
623 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700624 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700625 script.UnpackPackageDir("vendor", "/vendor")
626
627 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
628 script.MakeSymlinks(symlinks)
629
630 vendor_items.GetMetadata(input_zip)
631 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700632
Doug Zongker37974732010-09-16 17:44:38 -0700633 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700634 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700635
Doug Zongker01ce19c2014-02-04 13:48:15 -0800636 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700637 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700638
Doug Zongker01ce19c2014-02-04 13:48:15 -0800639 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700640 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700641
Doug Zongker1c390a22009-05-14 19:06:36 -0700642 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700643 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700644
Doug Zongker14833602010-02-02 13:12:04 -0800645 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800646
Doug Zongker922206e2014-03-04 13:16:24 -0800647 if OPTIONS.wipe_user_data:
648 script.ShowProgress(0.1, 10)
649 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700650
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800651 if OPTIONS.two_step:
652 script.AppendExtra("""
653set_stage("%(bcb_dev)s", "");
654""" % bcb_dev)
655 script.AppendExtra("else\n")
656 script.WriteRawImage("/boot", "recovery.img")
657 script.AppendExtra("""
658set_stage("%(bcb_dev)s", "2/3");
659reboot_now("%(bcb_dev)s", "");
660endif;
661endif;
662""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800663 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700664 WriteMetadata(metadata, output_zip)
665
Doug Zongkerfc44a512014-08-26 13:10:25 -0700666
Dan Albert8e0178d2015-01-27 15:53:15 -0800667def WritePolicyConfig(file_name, output_zip):
668 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500669
Doug Zongker2ea21062010-04-28 16:05:21 -0700670
671def WriteMetadata(metadata, output_zip):
672 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
673 "".join(["%s=%s\n" % kv
674 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700675
Doug Zongkerfc44a512014-08-26 13:10:25 -0700676
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700677def LoadPartitionFiles(z, partition):
678 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700679 ZipFile, and return a dict of {filename: File object}."""
680 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700681 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700682 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700683 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700684 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700685 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700686 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700687 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800688 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700689
690
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700691def GetBuildProp(prop, info_dict):
692 """Return the fingerprint of the build of a given target-files info_dict."""
693 try:
694 return info_dict.get("build.prop", {})[prop]
695 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700696 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700697
Doug Zongkerfc44a512014-08-26 13:10:25 -0700698
Michael Runge4038aa82013-12-13 18:06:28 -0800699def AddToKnownPaths(filename, known_paths):
700 if filename[-1] == "/":
701 return
702 dirs = filename.split("/")[:-1]
703 while len(dirs) > 0:
704 path = "/".join(dirs)
705 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700706 break
Michael Runge4038aa82013-12-13 18:06:28 -0800707 known_paths.add(path)
708 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700709
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700710
Geremy Condra36bd3652014-02-06 19:45:10 -0800711def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
712 source_version = OPTIONS.source_info_dict["recovery_api_version"]
713 target_version = OPTIONS.target_info_dict["recovery_api_version"]
714
715 if source_version == 0:
716 print ("WARNING: generating edify script for a source that "
717 "can't install it.")
718 script = edify_generator.EdifyGenerator(source_version,
719 OPTIONS.target_info_dict)
720
Dan Albert8b72aef2015-03-23 19:13:21 -0700721 metadata = {
722 "pre-device": GetBuildProp("ro.product.device",
723 OPTIONS.source_info_dict),
724 "post-timestamp": GetBuildProp("ro.build.date.utc",
725 OPTIONS.target_info_dict),
726 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800727
728 device_specific = common.DeviceSpecificParams(
729 source_zip=source_zip,
730 source_version=source_version,
731 target_zip=target_zip,
732 target_version=target_version,
733 output_zip=output_zip,
734 script=script,
735 metadata=metadata,
736 info_dict=OPTIONS.info_dict)
737
Tao Bao6c55a8a2015-04-08 15:30:27 -0700738 # TODO: Currently this works differently from WriteIncrementalOTAPackage().
739 # This function doesn't consider thumbprints when writing
740 # metadata["pre/post-build"]. One possible reason is that the current
741 # devices with thumbprints are all using file-based OTAs. Long term we
742 # should factor out the common parts into a shared one to avoid further
743 # divergence.
Geremy Condra36bd3652014-02-06 19:45:10 -0800744 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
745 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
746 metadata["pre-build"] = source_fp
747 metadata["post-build"] = target_fp
748
749 source_boot = common.GetBootableImage(
750 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
751 OPTIONS.source_info_dict)
752 target_boot = common.GetBootableImage(
753 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
754 updating_boot = (not OPTIONS.two_step and
755 (source_boot.data != target_boot.data))
756
Geremy Condra36bd3652014-02-06 19:45:10 -0800757 target_recovery = common.GetBootableImage(
758 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800759
Doug Zongkerfc44a512014-08-26 13:10:25 -0700760 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
761 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700762
763 blockimgdiff_version = 1
764 if OPTIONS.info_dict:
765 blockimgdiff_version = max(
766 int(i) for i in
767 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
768
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700769 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700770 check_first_block=True,
771 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700772
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700773 if HasVendorPartition(target_zip):
774 if not HasVendorPartition(source_zip):
775 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700776 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
777 OPTIONS.source_info_dict)
778 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
779 OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700780 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700781 check_first_block=True,
782 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700783 else:
784 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800785
Michael Rungec6e3afd2014-05-05 11:55:47 -0700786 oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
Dan Albert8b72aef2015-03-23 19:13:21 -0700787 recovery_mount_options = OPTIONS.target_info_dict.get(
788 "recovery_mount_options")
Michael Rungec6e3afd2014-05-05 11:55:47 -0700789 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700790 if oem_props is not None and len(oem_props) > 0:
Michael Rungec6e3afd2014-05-05 11:55:47 -0700791 if OPTIONS.oem_source is None:
792 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700793 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700794 oem_dict = common.LoadDictionaryFromLines(
795 open(OPTIONS.oem_source).readlines())
Michael Rungec6e3afd2014-05-05 11:55:47 -0700796
797 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800798 device_specific.IncrementalOTA_Assertions()
799
800 # Two-step incremental package strategy (in chronological order,
801 # which is *not* the order in which the generated script has
802 # things):
803 #
804 # if stage is not "2/3" or "3/3":
805 # do verification on current system
806 # write recovery image to boot partition
807 # set stage to "2/3"
808 # reboot to boot partition and restart recovery
809 # else if stage is "2/3":
810 # write recovery image to recovery partition
811 # set stage to "3/3"
812 # reboot to recovery partition and restart recovery
813 # else:
814 # (stage must be "3/3")
815 # perform update:
816 # patch system files, etc.
817 # force full install of new boot image
818 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700819 # complete script normally
820 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800821
822 if OPTIONS.two_step:
823 if not OPTIONS.info_dict.get("multistage_support", None):
824 assert False, "two-step packages not supported by this build"
825 fs = OPTIONS.info_dict["fstab"]["/misc"]
826 assert fs.fs_type.upper() == "EMMC", \
827 "two-step packages only supported on devices with EMMC /misc partitions"
828 bcb_dev = {"bcb_dev": fs.device}
829 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
830 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700831if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800832""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -0700833 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800834 script.WriteRawImage("/recovery", "recovery.img")
835 script.AppendExtra("""
836set_stage("%(bcb_dev)s", "3/3");
837reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700838else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800839""" % bcb_dev)
840
Tao Bao6c55a8a2015-04-08 15:30:27 -0700841 # Dump fingerprints
842 script.Print("Source: %s" % CalculateFingerprint(
843 oem_props, oem_dict, OPTIONS.source_info_dict))
844 script.Print("Target: %s" % CalculateFingerprint(
845 oem_props, oem_dict, OPTIONS.target_info_dict))
846
Geremy Condra36bd3652014-02-06 19:45:10 -0800847 script.Print("Verifying current system...")
848
849 device_specific.IncrementalOTA_VerifyBegin()
850
Michael Rungec6e3afd2014-05-05 11:55:47 -0700851 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700852 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
853 # patching on a device that's already on the target build will damage the
854 # system. Because operations like move don't check the block state, they
855 # always apply the changes unconditionally.
856 if blockimgdiff_version <= 2:
857 script.AssertSomeFingerprint(source_fp)
858 else:
859 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700860 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700861 if blockimgdiff_version <= 2:
862 script.AssertSomeThumbprint(
863 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
864 else:
865 script.AssertSomeThumbprint(
866 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
867 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800868
869 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700870 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800871 d = common.Difference(target_boot, source_boot)
872 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700873 if d is None:
874 include_full_boot = True
875 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
876 else:
877 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800878
Doug Zongkerf8340082014-08-05 10:39:37 -0700879 print "boot target: %d source: %d diff: %d" % (
880 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800881
Doug Zongkerf8340082014-08-05 10:39:37 -0700882 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800883
Doug Zongkerf8340082014-08-05 10:39:37 -0700884 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
885 (boot_type, boot_device,
886 source_boot.size, source_boot.sha1,
887 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800888
889 device_specific.IncrementalOTA_VerifyEnd()
890
891 if OPTIONS.two_step:
892 script.WriteRawImage("/boot", "recovery.img")
893 script.AppendExtra("""
894set_stage("%(bcb_dev)s", "2/3");
895reboot_now("%(bcb_dev)s", "");
896else
897""" % bcb_dev)
898
Jesse Zhao75bcea02015-01-06 10:59:53 -0800899 # Verify the existing partitions.
900 system_diff.WriteVerifyScript(script)
901 if vendor_diff:
902 vendor_diff.WriteVerifyScript(script)
903
Geremy Condra36bd3652014-02-06 19:45:10 -0800904 script.Comment("---- start making changes here ----")
905
906 device_specific.IncrementalOTA_InstallBegin()
907
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700908 system_diff.WriteScript(script, output_zip,
909 progress=0.8 if vendor_diff else 0.9)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700910 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700911 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800912
913 if OPTIONS.two_step:
914 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
915 script.WriteRawImage("/boot", "boot.img")
916 print "writing full boot image (forced by two-step mode)"
917
918 if not OPTIONS.two_step:
919 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700920 if include_full_boot:
921 print "boot image changed; including full."
922 script.Print("Installing boot image...")
923 script.WriteRawImage("/boot", "boot.img")
924 else:
925 # Produce the boot image by applying a patch to the current
926 # contents of the boot partition, and write it back to the
927 # partition.
928 print "boot image changed; including patch."
929 script.Print("Patching boot image...")
930 script.ShowProgress(0.1, 10)
931 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
932 % (boot_type, boot_device,
933 source_boot.size, source_boot.sha1,
934 target_boot.size, target_boot.sha1),
935 "-",
936 target_boot.size, target_boot.sha1,
937 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800938 else:
939 print "boot image unchanged; skipping."
940
941 # Do device-specific installation (eg, write radio image).
942 device_specific.IncrementalOTA_InstallEnd()
943
944 if OPTIONS.extra_script is not None:
945 script.AppendExtra(OPTIONS.extra_script)
946
Doug Zongker922206e2014-03-04 13:16:24 -0800947 if OPTIONS.wipe_user_data:
948 script.Print("Erasing user data...")
949 script.FormatPartition("/data")
950
Geremy Condra36bd3652014-02-06 19:45:10 -0800951 if OPTIONS.two_step:
952 script.AppendExtra("""
953set_stage("%(bcb_dev)s", "");
954endif;
955endif;
956""" % bcb_dev)
957
958 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800959 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800960 WriteMetadata(metadata, output_zip)
961
Doug Zongker32b527d2014-03-04 10:03:02 -0800962
Dan Albert8b72aef2015-03-23 19:13:21 -0700963class FileDifference(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700964 def __init__(self, partition, source_zip, target_zip, output_zip):
Dan Albert8b72aef2015-03-23 19:13:21 -0700965 self.deferred_patch_list = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700966 print "Loading target..."
967 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
968 print "Loading source..."
969 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
970
971 self.verbatim_targets = verbatim_targets = []
972 self.patch_list = patch_list = []
973 diffs = []
974 self.renames = renames = {}
975 known_paths = set()
976 largest_source_size = 0
977
978 matching_file_cache = {}
979 for fn, sf in source_data.items():
980 assert fn == sf.name
981 matching_file_cache["path:" + fn] = sf
982 if fn in target_data.keys():
983 AddToKnownPaths(fn, known_paths)
984 # Only allow eligibility for filename/sha matching
985 # if there isn't a perfect path match.
986 if target_data.get(sf.name) is None:
987 matching_file_cache["file:" + fn.split("/")[-1]] = sf
988 matching_file_cache["sha:" + sf.sha1] = sf
989
990 for fn in sorted(target_data.keys()):
991 tf = target_data[fn]
992 assert fn == tf.name
993 sf = ClosestFileMatch(tf, matching_file_cache, renames)
994 if sf is not None and sf.name != tf.name:
995 print "File has moved from " + sf.name + " to " + tf.name
996 renames[sf.name] = tf
997
998 if sf is None or fn in OPTIONS.require_verbatim:
999 # This file should be included verbatim
1000 if fn in OPTIONS.prohibit_verbatim:
1001 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
1002 print "send", fn, "verbatim"
1003 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001004 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001005 if fn in target_data.keys():
1006 AddToKnownPaths(fn, known_paths)
1007 elif tf.sha1 != sf.sha1:
1008 # File is different; consider sending as a patch
1009 diffs.append(common.Difference(tf, sf))
1010 else:
1011 # Target file data identical to source (may still be renamed)
1012 pass
1013
1014 common.ComputeDifferences(diffs)
1015
1016 for diff in diffs:
1017 tf, sf, d = diff.GetPatch()
1018 path = "/".join(tf.name.split("/")[:-1])
1019 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1020 path not in known_paths:
1021 # patch is almost as big as the file; don't bother patching
1022 # or a patch + rename cannot take place due to the target
1023 # directory not existing
1024 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001025 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001026 if sf.name in renames:
1027 del renames[sf.name]
1028 AddToKnownPaths(tf.name, known_paths)
1029 else:
1030 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1031 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1032 largest_source_size = max(largest_source_size, sf.size)
1033
1034 self.largest_source_size = largest_source_size
1035
1036 def EmitVerification(self, script):
1037 so_far = 0
Dan Albert8b72aef2015-03-23 19:13:21 -07001038 for tf, sf, _, _ in self.patch_list:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001039 if tf.name != sf.name:
1040 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1041 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1042 so_far += sf.size
1043 return so_far
1044
Michael Runge63f01de2014-10-28 19:24:19 -07001045 def EmitExplicitTargetVerification(self, script):
Dan Albert8b72aef2015-03-23 19:13:21 -07001046 for fn, _, sha1 in self.verbatim_targets:
1047 if fn[-1] != "/":
Michael Runge63f01de2014-10-28 19:24:19 -07001048 script.FileCheck("/"+fn, sha1)
1049 for tf, _, _, _ in self.patch_list:
1050 script.FileCheck(tf.name, tf.sha1)
1051
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001052 def RemoveUnneededFiles(self, script, extras=()):
Dan Albert8b72aef2015-03-23 19:13:21 -07001053 script.DeleteFiles(
1054 ["/" + i[0] for i in self.verbatim_targets] +
1055 ["/" + i for i in sorted(self.source_data)
1056 if i not in self.target_data and i not in self.renames] +
1057 list(extras))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001058
1059 def TotalPatchSize(self):
1060 return sum(i[1].size for i in self.patch_list)
1061
1062 def EmitPatches(self, script, total_patch_size, so_far):
1063 self.deferred_patch_list = deferred_patch_list = []
1064 for item in self.patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001065 tf, sf, _, _ = item
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001066 if tf.name == "system/build.prop":
1067 deferred_patch_list.append(item)
1068 continue
Dan Albert8b72aef2015-03-23 19:13:21 -07001069 if sf.name != tf.name:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001070 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
Dan Albert8b72aef2015-03-23 19:13:21 -07001071 script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1,
1072 "patch/" + sf.name + ".p")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001073 so_far += tf.size
1074 script.SetProgress(so_far / total_patch_size)
1075 return so_far
1076
1077 def EmitDeferredPatches(self, script):
1078 for item in self.deferred_patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001079 tf, sf, _, _ = item
1080 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1,
1081 "patch/" + sf.name + ".p")
1082 script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001083
1084 def EmitRenames(self, script):
1085 if len(self.renames) > 0:
1086 script.Print("Renaming files...")
1087 for src, tgt in self.renames.iteritems():
1088 print "Renaming " + src + " to " + tgt.name
1089 script.RenameFile(src, tgt.name)
1090
1091
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001092def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001093 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1094 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1095
Doug Zongker26e66192014-02-20 13:22:07 -08001096 if (OPTIONS.block_based and
1097 target_has_recovery_patch and
1098 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001099 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1100
Doug Zongker37974732010-09-16 17:44:38 -07001101 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1102 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001103
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001104 if source_version == 0:
1105 print ("WARNING: generating edify script for a source that "
1106 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -07001107 script = edify_generator.EdifyGenerator(source_version,
1108 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -07001109
Michael Runge6e836112014-04-15 17:40:21 -07001110 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001111 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001112 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001113 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001114 if OPTIONS.oem_source is None:
1115 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001116 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001117 oem_dict = common.LoadDictionaryFromLines(
1118 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001119
Dan Albert8b72aef2015-03-23 19:13:21 -07001120 metadata = {
1121 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1122 OPTIONS.source_info_dict),
1123 "post-timestamp": GetBuildProp("ro.build.date.utc",
1124 OPTIONS.target_info_dict),
1125 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001126
Doug Zongker05d3dea2009-06-22 11:32:31 -07001127 device_specific = common.DeviceSpecificParams(
1128 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001129 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001130 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001131 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001132 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001133 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001134 metadata=metadata,
1135 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001136
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001137 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001138 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001139 if HasVendorPartition(target_zip):
1140 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001141 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001142 else:
1143 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001144
Dan Albert8b72aef2015-03-23 19:13:21 -07001145 target_fp = CalculateFingerprint(oem_props, oem_dict,
1146 OPTIONS.target_info_dict)
1147 source_fp = CalculateFingerprint(oem_props, oem_dict,
1148 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001149
1150 if oem_props is None:
1151 script.AssertSomeFingerprint(source_fp, target_fp)
1152 else:
1153 script.AssertSomeThumbprint(
1154 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1155 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1156
Doug Zongker2ea21062010-04-28 16:05:21 -07001157 metadata["pre-build"] = source_fp
1158 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001159
Doug Zongker55d93282011-01-25 17:03:34 -08001160 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001161 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1162 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001163 target_boot = common.GetBootableImage(
1164 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001165 updating_boot = (not OPTIONS.two_step and
1166 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001167
Doug Zongker55d93282011-01-25 17:03:34 -08001168 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001169 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1170 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001171 target_recovery = common.GetBootableImage(
1172 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001173 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001174
Doug Zongker881dd402009-09-20 14:03:55 -07001175 # Here's how we divide up the progress bar:
1176 # 0.1 for verifying the start state (PatchCheck calls)
1177 # 0.8 for applying patches (ApplyPatch calls)
1178 # 0.1 for unpacking verbatim files, symlinking, and doing the
1179 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001180
Michael Runge6e836112014-04-15 17:40:21 -07001181 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001182 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001183
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001184 # Two-step incremental package strategy (in chronological order,
1185 # which is *not* the order in which the generated script has
1186 # things):
1187 #
1188 # if stage is not "2/3" or "3/3":
1189 # do verification on current system
1190 # write recovery image to boot partition
1191 # set stage to "2/3"
1192 # reboot to boot partition and restart recovery
1193 # else if stage is "2/3":
1194 # write recovery image to recovery partition
1195 # set stage to "3/3"
1196 # reboot to recovery partition and restart recovery
1197 # else:
1198 # (stage must be "3/3")
1199 # perform update:
1200 # patch system files, etc.
1201 # force full install of new boot image
1202 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001203 # complete script normally
1204 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001205
1206 if OPTIONS.two_step:
1207 if not OPTIONS.info_dict.get("multistage_support", None):
1208 assert False, "two-step packages not supported by this build"
1209 fs = OPTIONS.info_dict["fstab"]["/misc"]
1210 assert fs.fs_type.upper() == "EMMC", \
1211 "two-step packages only supported on devices with EMMC /misc partitions"
1212 bcb_dev = {"bcb_dev": fs.device}
1213 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1214 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001215if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001216""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001217 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001218 script.WriteRawImage("/recovery", "recovery.img")
1219 script.AppendExtra("""
1220set_stage("%(bcb_dev)s", "3/3");
1221reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001222else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001223""" % bcb_dev)
1224
Tao Bao6c55a8a2015-04-08 15:30:27 -07001225 # Dump fingerprints
1226 script.Print("Source: %s" % (source_fp,))
1227 script.Print("Target: %s" % (target_fp,))
1228
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001229 script.Print("Verifying current system...")
1230
Doug Zongkere5ff5902012-01-17 10:55:37 -08001231 device_specific.IncrementalOTA_VerifyBegin()
1232
Doug Zongker881dd402009-09-20 14:03:55 -07001233 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001234 so_far = system_diff.EmitVerification(script)
1235 if vendor_diff:
1236 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001237
Doug Zongker5da317e2009-06-02 13:38:17 -07001238 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001239 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001240 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001241 print "boot target: %d source: %d diff: %d" % (
1242 target_boot.size, source_boot.size, len(d))
1243
Doug Zongker048e7ca2009-06-15 14:31:53 -07001244 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001245
Doug Zongker96a57e72010-09-26 14:57:41 -07001246 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001247
1248 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1249 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001250 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001251 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001252 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001253
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001254 size = []
Dan Albert8b72aef2015-03-23 19:13:21 -07001255 if system_diff.patch_list:
1256 size.append(system_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001257 if vendor_diff:
Dan Albert8b72aef2015-03-23 19:13:21 -07001258 if vendor_diff.patch_list:
1259 size.append(vendor_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001260 if size or updating_recovery or updating_boot:
1261 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001262
Doug Zongker05d3dea2009-06-22 11:32:31 -07001263 device_specific.IncrementalOTA_VerifyEnd()
1264
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001265 if OPTIONS.two_step:
1266 script.WriteRawImage("/boot", "recovery.img")
1267 script.AppendExtra("""
1268set_stage("%(bcb_dev)s", "2/3");
1269reboot_now("%(bcb_dev)s", "");
1270else
1271""" % bcb_dev)
1272
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001273 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001274
Doug Zongkere5ff5902012-01-17 10:55:37 -08001275 device_specific.IncrementalOTA_InstallBegin()
1276
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001277 if OPTIONS.two_step:
1278 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1279 script.WriteRawImage("/boot", "boot.img")
1280 print "writing full boot image (forced by two-step mode)"
1281
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001282 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001283 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1284 if vendor_diff:
1285 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001286
Doug Zongker881dd402009-09-20 14:03:55 -07001287 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001288 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1289 if vendor_diff:
1290 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001291 if updating_boot:
1292 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001293
1294 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001295 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1296 if vendor_diff:
1297 script.Print("Patching vendor files...")
1298 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001299
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001300 if not OPTIONS.two_step:
1301 if updating_boot:
1302 # Produce the boot image by applying a patch to the current
1303 # contents of the boot partition, and write it back to the
1304 # partition.
1305 script.Print("Patching boot image...")
1306 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1307 % (boot_type, boot_device,
1308 source_boot.size, source_boot.sha1,
1309 target_boot.size, target_boot.sha1),
1310 "-",
1311 target_boot.size, target_boot.sha1,
1312 source_boot.sha1, "patch/boot.img.p")
1313 so_far += target_boot.size
1314 script.SetProgress(so_far / total_patch_size)
1315 print "boot image changed; including."
1316 else:
1317 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001318
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001319 system_items = ItemSet("system", "META/filesystem_config.txt")
1320 if vendor_diff:
1321 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1322
Doug Zongkereef39442009-04-02 12:14:19 -07001323 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001324 # Recovery is generated as a patch using both the boot image
1325 # (which contains the same linux kernel as recovery) and the file
1326 # /system/etc/recovery-resource.dat (which contains all the images
1327 # used in the recovery UI) as sources. This lets us minimize the
1328 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001329 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001330 # For older builds where recovery-resource.dat is not present, we
1331 # use only the boot image as the source.
1332
Doug Zongkerc9253822014-02-04 12:17:58 -08001333 if not target_has_recovery_patch:
1334 def output_sink(fn, data):
1335 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001336 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001337
1338 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1339 target_recovery, target_boot)
1340 script.DeleteFiles(["/system/recovery-from-boot.p",
1341 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001342 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001343 else:
1344 print "recovery image unchanged; skipping."
1345
Doug Zongker881dd402009-09-20 14:03:55 -07001346 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001347
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001348 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1349 if vendor_diff:
1350 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1351
1352 temp_script = script.MakeTemporary()
1353 system_items.GetMetadata(target_zip)
1354 system_items.Get("system").SetPermissions(temp_script)
1355 if vendor_diff:
1356 vendor_items.GetMetadata(target_zip)
1357 vendor_items.Get("vendor").SetPermissions(temp_script)
1358
1359 # Note that this call will mess up the trees of Items, so make sure
1360 # we're done with them.
1361 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1362 if vendor_diff:
1363 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001364
1365 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001366 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1367
1368 # Delete all the symlinks in source that aren't in target. This
1369 # needs to happen before verbatim files are unpacked, in case a
1370 # symlink in the source is replaced by a real file in the target.
1371 to_delete = []
1372 for dest, link in source_symlinks:
1373 if link not in target_symlinks_d:
1374 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001375 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001376
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001377 if system_diff.verbatim_targets:
1378 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001379 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001380 if vendor_diff and vendor_diff.verbatim_targets:
1381 script.Print("Unpacking new vendor files...")
1382 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001383
Doug Zongkerc9253822014-02-04 12:17:58 -08001384 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001385 script.Print("Unpacking new recovery...")
1386 script.UnpackPackageDir("recovery", "/system")
1387
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001388 system_diff.EmitRenames(script)
1389 if vendor_diff:
1390 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001391
Doug Zongker05d3dea2009-06-22 11:32:31 -07001392 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001393
1394 # Create all the symlinks that don't already exist, or point to
1395 # somewhere different than what we want. Delete each symlink before
1396 # creating it, since the 'symlink' command won't overwrite.
1397 to_create = []
1398 for dest, link in target_symlinks:
1399 if link in source_symlinks_d:
1400 if dest != source_symlinks_d[link]:
1401 to_create.append((dest, link))
1402 else:
1403 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001404 script.DeleteFiles([i[1] for i in to_create])
1405 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001406
1407 # Now that the symlinks are created, we can set all the
1408 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001409 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001410
Doug Zongker881dd402009-09-20 14:03:55 -07001411 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001412 device_specific.IncrementalOTA_InstallEnd()
1413
Doug Zongker1c390a22009-05-14 19:06:36 -07001414 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001415 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001416
Doug Zongkere92f15a2011-08-26 13:46:40 -07001417 # Patch the build.prop file last, so if something fails but the
1418 # device can still come up, it appears to be the old build and will
1419 # get set the OTA package again to retry.
1420 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001421 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001422
Doug Zongker922206e2014-03-04 13:16:24 -08001423 if OPTIONS.wipe_user_data:
1424 script.Print("Erasing user data...")
1425 script.FormatPartition("/data")
1426
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001427 if OPTIONS.two_step:
1428 script.AppendExtra("""
1429set_stage("%(bcb_dev)s", "");
1430endif;
1431endif;
1432""" % bcb_dev)
1433
Michael Runge63f01de2014-10-28 19:24:19 -07001434 if OPTIONS.verify and system_diff:
1435 script.Print("Remounting and verifying system partition files...")
1436 script.Unmount("/system")
1437 script.Mount("/system")
1438 system_diff.EmitExplicitTargetVerification(script)
1439
1440 if OPTIONS.verify and vendor_diff:
1441 script.Print("Remounting and verifying vendor partition files...")
1442 script.Unmount("/vendor")
1443 script.Mount("/vendor")
1444 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001445 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001446
Doug Zongker2ea21062010-04-28 16:05:21 -07001447 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001448
1449
1450def main(argv):
1451
1452 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001453 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001454 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001455 elif o in ("-k", "--package_key"):
1456 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001457 elif o in ("-i", "--incremental_from"):
1458 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001459 elif o in ("-w", "--wipe_user_data"):
1460 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001461 elif o in ("-n", "--no_prereq"):
1462 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001463 elif o in ("-o", "--oem_settings"):
1464 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001465 elif o in ("-e", "--extra_script"):
1466 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001467 elif o in ("-a", "--aslr_mode"):
1468 if a in ("on", "On", "true", "True", "yes", "Yes"):
1469 OPTIONS.aslr_mode = True
1470 else:
1471 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001472 elif o in ("-t", "--worker_threads"):
1473 if a.isdigit():
1474 OPTIONS.worker_threads = int(a)
1475 else:
1476 raise ValueError("Cannot parse value %r for option %r - only "
1477 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001478 elif o in ("-2", "--two_step"):
1479 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001480 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001481 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001482 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001483 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001484 elif o == "--block":
1485 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001486 elif o in ("-b", "--binary"):
1487 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001488 elif o in ("--no_fallback_to_full",):
1489 OPTIONS.fallback_to_full = False
Doug Zongkereef39442009-04-02 12:14:19 -07001490 else:
1491 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001492 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001493
1494 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001495 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001496 extra_long_opts=[
1497 "board_config=",
1498 "package_key=",
1499 "incremental_from=",
1500 "wipe_user_data",
1501 "no_prereq",
1502 "extra_script=",
1503 "worker_threads=",
1504 "aslr_mode=",
1505 "two_step",
1506 "no_signing",
1507 "block",
1508 "binary=",
1509 "oem_settings=",
1510 "verify",
1511 "no_fallback_to_full",
1512 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001513
1514 if len(args) != 2:
1515 common.Usage(__doc__)
1516 sys.exit(1)
1517
Doug Zongker1c390a22009-05-14 19:06:36 -07001518 if OPTIONS.extra_script is not None:
1519 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1520
Doug Zongkereef39442009-04-02 12:14:19 -07001521 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001522 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001523
Doug Zongkereef39442009-04-02 12:14:19 -07001524 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001525 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001526
1527 # If this image was originally labelled with SELinux contexts, make sure we
1528 # also apply the labels in our new image. During building, the "file_contexts"
1529 # is in the out/ directory tree, but for repacking from target-files.zip it's
1530 # in the root directory of the ramdisk.
1531 if "selinux_fc" in OPTIONS.info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001532 OPTIONS.info_dict["selinux_fc"] = os.path.join(
1533 OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")
Kenny Roote2e9f612013-05-29 12:59:35 -07001534
Doug Zongker37974732010-09-16 17:44:38 -07001535 if OPTIONS.verbose:
1536 print "--- target info ---"
1537 common.DumpInfoDict(OPTIONS.info_dict)
1538
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001539 # If the caller explicitly specified the device-specific extensions
1540 # path via -s/--device_specific, use that. Otherwise, use
1541 # META/releasetools.py if it is present in the target target_files.
1542 # Otherwise, take the path of the file from 'tool_extensions' in the
1543 # info dict and look for that in the local filesystem, relative to
1544 # the current directory.
1545
Doug Zongker37974732010-09-16 17:44:38 -07001546 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001547 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1548 if os.path.exists(from_input):
1549 print "(using device-specific extensions from target_files)"
1550 OPTIONS.device_specific = from_input
1551 else:
1552 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1553
Doug Zongker37974732010-09-16 17:44:38 -07001554 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001555 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001556
Doug Zongker62d4f182014-08-04 16:06:43 -07001557 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001558
Doug Zongker62d4f182014-08-04 16:06:43 -07001559 if OPTIONS.no_signing:
Dan Albert8b72aef2015-03-23 19:13:21 -07001560 if os.path.exists(args[1]):
1561 os.unlink(args[1])
1562 output_zip = zipfile.ZipFile(args[1], "w",
1563 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001564 else:
1565 temp_zip_file = tempfile.NamedTemporaryFile()
1566 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1567 compression=zipfile.ZIP_DEFLATED)
1568
1569 if OPTIONS.incremental_source is None:
1570 WriteFullOTAPackage(input_zip, output_zip)
1571 if OPTIONS.package_key is None:
1572 OPTIONS.package_key = OPTIONS.info_dict.get(
1573 "default_system_dev_certificate",
1574 "build/target/product/security/testkey")
1575 break
1576
1577 else:
1578 print "unzipping source target-files..."
Dan Albert8b72aef2015-03-23 19:13:21 -07001579 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
1580 OPTIONS.incremental_source)
Doug Zongker62d4f182014-08-04 16:06:43 -07001581 OPTIONS.target_info_dict = OPTIONS.info_dict
1582 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1583 if "selinux_fc" in OPTIONS.source_info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001584 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(
1585 OPTIONS.source_tmp, "BOOT", "RAMDISK", "file_contexts")
Doug Zongker62d4f182014-08-04 16:06:43 -07001586 if OPTIONS.package_key is None:
1587 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1588 "default_system_dev_certificate",
1589 "build/target/product/security/testkey")
1590 if OPTIONS.verbose:
1591 print "--- source info ---"
1592 common.DumpInfoDict(OPTIONS.source_info_dict)
1593 try:
1594 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
1595 break
1596 except ValueError:
Dan Albert8b72aef2015-03-23 19:13:21 -07001597 if not OPTIONS.fallback_to_full:
1598 raise
Doug Zongker62d4f182014-08-04 16:06:43 -07001599 print "--- failed to build incremental; falling back to full ---"
1600 OPTIONS.incremental_source = None
1601 output_zip.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001602
1603 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001604
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001605 if not OPTIONS.no_signing:
1606 SignOutput(temp_zip_file.name, args[1])
1607 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001608
Doug Zongkereef39442009-04-02 12:14:19 -07001609 print "done."
1610
1611
1612if __name__ == '__main__':
1613 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001614 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001615 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001616 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07001617 print
1618 print " ERROR: %s" % (e,)
1619 print
1620 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001621 finally:
1622 common.Cleanup()