blob: c5c16b408a9e65e3cccc85f1eeebeb9c5c6fff1a [file] [log] [blame]
Doug Zongkereef39442009-04-02 12:14:19 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2008 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""
18Given a target-files zipfile, produces an OTA package that installs
19that build. An incremental OTA is produced if -i is given, otherwise
20a full OTA is produced.
21
22Usage: ota_from_target_files [flags] input_target_files output_ota_package
23
Doug Zongker25568482014-03-03 10:21:27 -080024 --board_config <file>
Doug Zongkerfdd8e692009-08-03 17:27:48 -070025 Deprecated.
Doug Zongkereef39442009-04-02 12:14:19 -070026
Doug Zongkerafb32ea2011-09-22 10:28:04 -070027 -k (--package_key) <key> Key to use to sign the package (default is
28 the value of default_system_dev_certificate from the input
29 target-files's META/misc_info.txt, or
30 "build/target/product/security/testkey" if that value is not
31 specified).
32
33 For incremental OTAs, the default value is based on the source
34 target-file, not the target build.
Doug Zongkereef39442009-04-02 12:14:19 -070035
36 -i (--incremental_from) <file>
37 Generate an incremental OTA using the given target-files zip as
38 the starting build.
39
Tao Bao43078aa2015-04-21 14:32:35 -070040 --full_radio
41 When generating an incremental OTA, always include a full copy of
42 radio image. This option is only meaningful when -i is specified,
43 because a full radio is always included in a full OTA if applicable.
44
leozwanga1fcaf82015-09-15 08:44:12 -070045 --full_bootloader
46 When generating an incremental OTA, always include a full copy of
47 bootloader image. This option is only meaningful when -i is specified,
48 because a full bootloader is always included in a full OTA if applicable.
49
Michael Runge63f01de2014-10-28 19:24:19 -070050 -v (--verify)
51 Remount and verify the checksums of the files written to the
52 system and vendor (if used) partitions. Incremental builds only.
53
Michael Runge6e836112014-04-15 17:40:21 -070054 -o (--oem_settings) <file>
55 Use the file to specify the expected OEM-specific properties
56 on the OEM partition of the intended device.
57
Doug Zongkerdbfaae52009-04-21 17:12:54 -070058 -w (--wipe_user_data)
59 Generate an OTA package that will wipe the user data partition
60 when installed.
61
Doug Zongker962069c2009-04-23 11:41:58 -070062 -n (--no_prereq)
63 Omit the timestamp prereq check normally included at the top of
64 the build scripts (used for developer OTA packages which
65 legitimately need to go back and forth).
66
Doug Zongker1c390a22009-05-14 19:06:36 -070067 -e (--extra_script) <file>
68 Insert the contents of file at the end of the update script.
69
Hristo Bojinovdafb0422010-08-26 14:35:16 -070070 -a (--aslr_mode) <on|off>
71 Specify whether to turn on ASLR for the package (on by default).
Stephen Smalley56882bf2012-02-09 13:36:21 -050072
Doug Zongker9b23f2c2013-11-25 14:44:12 -080073 -2 (--two_step)
74 Generate a 'two-step' OTA package, where recovery is updated
75 first, so that any changes made to the system partition are done
76 using the new recovery (new kernel, etc.).
77
Doug Zongker26e66192014-02-20 13:22:07 -080078 --block
79 Generate a block-based OTA if possible. Will fall back to a
80 file-based OTA if the target_files is older and doesn't support
81 block-based OTAs.
82
Doug Zongker25568482014-03-03 10:21:27 -080083 -b (--binary) <file>
84 Use the given binary as the update-binary in the output package,
85 instead of the binary in the build's target_files. Use for
86 development only.
87
Martin Blumenstingl374e1142014-05-31 20:42:55 +020088 -t (--worker_threads) <int>
89 Specifies the number of worker-threads that will be used when
90 generating patches for incremental updates (defaults to 3).
91
Tao Baod47d8e12015-05-21 14:09:49 -070092 --stash_threshold <float>
93 Specifies the threshold that will be used to compute the maximum
94 allowed stash size (defaults to 0.8).
Doug Zongkereef39442009-04-02 12:14:19 -070095"""
96
97import sys
98
Doug Zongkercf6d5a92014-02-18 10:57:07 -080099if sys.hexversion < 0x02070000:
100 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -0700101 sys.exit(1)
102
Doug Zongkerfc44a512014-08-26 13:10:25 -0700103import multiprocessing
Doug Zongkereef39442009-04-02 12:14:19 -0700104import os
Doug Zongkereef39442009-04-02 12:14:19 -0700105import tempfile
Doug Zongkereef39442009-04-02 12:14:19 -0700106import zipfile
107
108import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700109import edify_generator
Doug Zongkerfc44a512014-08-26 13:10:25 -0700110import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700111
112OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700113OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700114OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700115OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700116OPTIONS.require_verbatim = set()
117OPTIONS.prohibit_verbatim = set(("system/build.prop",))
118OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700119OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700120OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700121OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700122OPTIONS.aslr_mode = True
Doug Zongkerfc44a512014-08-26 13:10:25 -0700123OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
124if OPTIONS.worker_threads == 0:
125 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800126OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900127OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800128OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800129OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700130OPTIONS.oem_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -0700131OPTIONS.fallback_to_full = True
Tao Bao43078aa2015-04-21 14:32:35 -0700132OPTIONS.full_radio = False
leozwanga1fcaf82015-09-15 08:44:12 -0700133OPTIONS.full_bootloader = False
Tao Baod47d8e12015-05-21 14:09:49 -0700134# Stash size cannot exceed cache_size * threshold.
135OPTIONS.cache_size = None
136OPTIONS.stash_threshold = 0.8
137
Doug Zongkereef39442009-04-02 12:14:19 -0700138def MostPopularKey(d, default):
139 """Given a dict, return the key corresponding to the largest
140 value. Returns 'default' if the dict is empty."""
141 x = [(v, k) for (k, v) in d.iteritems()]
Dan Albert8b72aef2015-03-23 19:13:21 -0700142 if not x:
143 return default
Doug Zongkereef39442009-04-02 12:14:19 -0700144 x.sort()
145 return x[-1][1]
146
147
148def IsSymlink(info):
149 """Return true if the zipfile.ZipInfo object passed in represents a
150 symlink."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700151 return (info.external_attr >> 16) == 0o120777
Doug Zongkereef39442009-04-02 12:14:19 -0700152
Hristo Bojinov96be7202010-08-02 10:26:17 -0700153def IsRegular(info):
154 """Return true if the zipfile.ZipInfo object passed in represents a
155 symlink."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700156 return (info.external_attr >> 28) == 0o10
Doug Zongkereef39442009-04-02 12:14:19 -0700157
Michael Runge4038aa82013-12-13 18:06:28 -0800158def ClosestFileMatch(src, tgtfiles, existing):
159 """Returns the closest file match between a source file and list
160 of potential matches. The exact filename match is preferred,
161 then the sha1 is searched for, and finally a file with the same
162 basename is evaluated. Rename support in the updater-binary is
163 required for the latter checks to be used."""
164
165 result = tgtfiles.get("path:" + src.name)
166 if result is not None:
167 return result
168
169 if not OPTIONS.target_info_dict.get("update_rename_support", False):
170 return None
171
172 if src.size < 1000:
173 return None
174
175 result = tgtfiles.get("sha1:" + src.sha1)
176 if result is not None and existing.get(result.name) is None:
177 return result
178 result = tgtfiles.get("file:" + src.name.split("/")[-1])
179 if result is not None and existing.get(result.name) is None:
180 return result
181 return None
182
Dan Albert8b72aef2015-03-23 19:13:21 -0700183class ItemSet(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700184 def __init__(self, partition, fs_config):
185 self.partition = partition
186 self.fs_config = fs_config
187 self.ITEMS = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700188
Dan Albert8b72aef2015-03-23 19:13:21 -0700189 def Get(self, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700190 if name not in self.ITEMS:
Dan Albert8b72aef2015-03-23 19:13:21 -0700191 self.ITEMS[name] = Item(self, name, is_dir=is_dir)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700192 return self.ITEMS[name]
Doug Zongkereef39442009-04-02 12:14:19 -0700193
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700194 def GetMetadata(self, input_zip):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700195 # The target_files contains a record of what the uid,
196 # gid, and mode are supposed to be.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700197 output = input_zip.read(self.fs_config)
Doug Zongkereef39442009-04-02 12:14:19 -0700198
199 for line in output.split("\n"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700200 if not line:
201 continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700202 columns = line.split()
203 name, uid, gid, mode = columns[:4]
204 selabel = None
205 capabilities = None
206
207 # After the first 4 columns, there are a series of key=value
208 # pairs. Extract out the fields we care about.
209 for element in columns[4:]:
210 key, value = element.split("=")
211 if key == "selabel":
212 selabel = value
213 if key == "capabilities":
214 capabilities = value
215
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700216 i = self.ITEMS.get(name, None)
Doug Zongker283e2a12010-03-15 17:52:32 -0700217 if i is not None:
218 i.uid = int(uid)
219 i.gid = int(gid)
220 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700221 i.selabel = selabel
222 i.capabilities = capabilities
Dan Albert8b72aef2015-03-23 19:13:21 -0700223 if i.is_dir:
Doug Zongker283e2a12010-03-15 17:52:32 -0700224 i.children.sort(key=lambda i: i.name)
225
226 # set metadata for the files generated by this script.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700227 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700228 if i:
229 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700230 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Dan Albert8b72aef2015-03-23 19:13:21 -0700231 if i:
232 i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700233
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700234
Dan Albert8b72aef2015-03-23 19:13:21 -0700235class Item(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700236 """Items represent the metadata (user, group, mode) of files and
237 directories in the system image."""
Dan Albert8b72aef2015-03-23 19:13:21 -0700238 def __init__(self, itemset, name, is_dir=False):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700239 self.itemset = itemset
240 self.name = name
241 self.uid = None
242 self.gid = None
243 self.mode = None
244 self.selabel = None
245 self.capabilities = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700246 self.is_dir = is_dir
247 self.descendants = None
248 self.best_subtree = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700249
250 if name:
Dan Albert8b72aef2015-03-23 19:13:21 -0700251 self.parent = itemset.Get(os.path.dirname(name), is_dir=True)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700252 self.parent.children.append(self)
253 else:
254 self.parent = None
Dan Albert8b72aef2015-03-23 19:13:21 -0700255 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700256 self.children = []
257
258 def Dump(self, indent=0):
259 if self.uid is not None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700260 print "%s%s %d %d %o" % (
261 " " * indent, self.name, self.uid, self.gid, self.mode)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700262 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700263 print "%s%s %s %s %s" % (
264 " " * indent, self.name, self.uid, self.gid, self.mode)
265 if self.is_dir:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700266 print "%s%s" % (" "*indent, self.descendants)
267 print "%s%s" % (" "*indent, self.best_subtree)
268 for i in self.children:
269 i.Dump(indent=indent+1)
270
Doug Zongkereef39442009-04-02 12:14:19 -0700271 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700272 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
Dan Albert8b72aef2015-03-23 19:13:21 -0700273 all children and determine the best strategy for using set_perm_recursive
274 and set_perm to correctly chown/chmod all the files to their desired
Doug Zongkereef39442009-04-02 12:14:19 -0700275 values. Recursively calls itself for all descendants.
276
Dan Albert8b72aef2015-03-23 19:13:21 -0700277 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count}
278 counting up all descendants of this node. (dmode or fmode may be None.)
279 Also sets the best_subtree of each directory Item to the (uid, gid, dmode,
280 fmode, selabel, capabilities) tuple that will match the most descendants of
281 that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700282 """
283
Dan Albert8b72aef2015-03-23 19:13:21 -0700284 assert self.is_dir
285 key = (self.uid, self.gid, self.mode, None, self.selabel,
286 self.capabilities)
287 self.descendants = {key: 1}
288 d = self.descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700289 for i in self.children:
Dan Albert8b72aef2015-03-23 19:13:21 -0700290 if i.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700291 for k, v in i.CountChildMetadata().iteritems():
292 d[k] = d.get(k, 0) + v
293 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700294 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700295 d[k] = d.get(k, 0) + 1
296
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700297 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
298 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700299
300 # First, find the (uid, gid) pair that matches the most
301 # descendants.
302 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700303 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700304 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
305 ug = MostPopularKey(ug, (0, 0))
306
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700307 # Now find the dmode, fmode, selabel, and capabilities that match
308 # the most descendants with that (uid, gid), and choose those.
Dan Albert8b72aef2015-03-23 19:13:21 -0700309 best_dmode = (0, 0o755)
310 best_fmode = (0, 0o644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700311 best_selabel = (0, None)
312 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700313 for k, count in d.iteritems():
Dan Albert8b72aef2015-03-23 19:13:21 -0700314 if k[:2] != ug:
315 continue
316 if k[2] is not None and count >= best_dmode[0]:
317 best_dmode = (count, k[2])
318 if k[3] is not None and count >= best_fmode[0]:
319 best_fmode = (count, k[3])
320 if k[4] is not None and count >= best_selabel[0]:
321 best_selabel = (count, k[4])
322 if k[5] is not None and count >= best_capabilities[0]:
323 best_capabilities = (count, k[5])
324 self.best_subtree = ug + (
325 best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700326
327 return d
328
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700329 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700330 """Append set_perm/set_perm_recursive commands to 'script' to
331 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700332 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700333
334 self.CountChildMetadata()
335
336 def recurse(item, current):
Dan Albert8b72aef2015-03-23 19:13:21 -0700337 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple
338 # that the current item (and all its children) have already been set to.
339 # We only need to issue set_perm/set_perm_recursive commands if we're
Doug Zongkereef39442009-04-02 12:14:19 -0700340 # supposed to be something different.
Dan Albert8b72aef2015-03-23 19:13:21 -0700341 if item.is_dir:
Doug Zongkereef39442009-04-02 12:14:19 -0700342 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700343 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700344 current = item.best_subtree
345
346 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700347 item.mode != current[2] or item.selabel != current[4] or \
348 item.capabilities != current[5]:
349 script.SetPermissions("/"+item.name, item.uid, item.gid,
350 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700351
352 for i in item.children:
353 recurse(i, current)
354 else:
355 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700356 item.mode != current[3] or item.selabel != current[4] or \
357 item.capabilities != current[5]:
358 script.SetPermissions("/"+item.name, item.uid, item.gid,
359 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700360
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700361 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700362
363
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700364def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
365 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700366 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800367 list of symlinks. output_zip may be None, in which case the copy is
368 skipped (but the other side effects still happen). substitute is an
369 optional dict of {output filename: contents} to be output instead of
370 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700371 """
372
373 symlinks = []
374
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700375 partition = itemset.partition
376
Doug Zongkereef39442009-04-02 12:14:19 -0700377 for info in input_zip.infolist():
Tao Baoeaf885b2015-03-23 16:01:17 -0700378 prefix = partition.upper() + "/"
379 if info.filename.startswith(prefix):
380 basefilename = info.filename[len(prefix):]
Doug Zongkereef39442009-04-02 12:14:19 -0700381 if IsSymlink(info):
382 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700383 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700384 else:
Tao Baof3282b42015-04-01 11:21:55 -0700385 import copy
Doug Zongkereef39442009-04-02 12:14:19 -0700386 info2 = copy.copy(info)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700387 fn = info2.filename = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700388 if substitute and fn in substitute and substitute[fn] is None:
389 continue
390 if output_zip is not None:
391 if substitute and fn in substitute:
392 data = substitute[fn]
393 else:
394 data = input_zip.read(info.filename)
Tao Baof3282b42015-04-01 11:21:55 -0700395 common.ZipWriteStr(output_zip, info2, data)
Doug Zongkereef39442009-04-02 12:14:19 -0700396 if fn.endswith("/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700397 itemset.Get(fn[:-1], is_dir=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700398 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700399 itemset.Get(fn)
Doug Zongkereef39442009-04-02 12:14:19 -0700400
401 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800402 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700403
404
Doug Zongkereef39442009-04-02 12:14:19 -0700405def SignOutput(temp_zip_name, output_zip_name):
406 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
407 pw = key_passwords[OPTIONS.package_key]
408
Doug Zongker951495f2009-08-14 12:44:19 -0700409 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
410 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700411
412
Dan Albert8b72aef2015-03-23 19:13:21 -0700413def AppendAssertions(script, info_dict, oem_dict=None):
Michael Runge6e836112014-04-15 17:40:21 -0700414 oem_props = info_dict.get("oem_fingerprint_properties")
Michael Runge560569a2014-09-18 15:12:45 -0700415 if oem_props is None or len(oem_props) == 0:
Michael Runge6e836112014-04-15 17:40:21 -0700416 device = GetBuildProp("ro.product.device", info_dict)
417 script.AssertDevice(device)
418 else:
419 if oem_dict is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700420 raise common.ExternalError(
421 "No OEM file provided to answer expected assertions")
Michael Runge6e836112014-04-15 17:40:21 -0700422 for prop in oem_props.split():
423 if oem_dict.get(prop) is None:
Dan Albert8b72aef2015-03-23 19:13:21 -0700424 raise common.ExternalError(
425 "The OEM file is missing the property %s" % prop)
Michael Runge6e836112014-04-15 17:40:21 -0700426 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700427
Doug Zongkereef39442009-04-02 12:14:19 -0700428
Doug Zongkerc9253822014-02-04 12:17:58 -0800429def HasRecoveryPatch(target_files_zip):
430 try:
431 target_files_zip.getinfo("SYSTEM/recovery-from-boot.p")
432 return True
433 except KeyError:
434 return False
Doug Zongker73ef8252009-07-23 15:12:53 -0700435
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700436def HasVendorPartition(target_files_zip):
437 try:
438 target_files_zip.getinfo("VENDOR/")
439 return True
440 except KeyError:
441 return False
442
Michael Runge6e836112014-04-15 17:40:21 -0700443def GetOemProperty(name, oem_props, oem_dict, info_dict):
444 if oem_props is not None and name in oem_props:
445 return oem_dict[name]
446 return GetBuildProp(name, info_dict)
447
448
449def CalculateFingerprint(oem_props, oem_dict, info_dict):
450 if oem_props is None:
451 return GetBuildProp("ro.build.fingerprint", info_dict)
452 return "%s/%s/%s:%s" % (
Dan Albert8b72aef2015-03-23 19:13:21 -0700453 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
454 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
455 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
456 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700457
Doug Zongkerfc44a512014-08-26 13:10:25 -0700458
Doug Zongker3c84f562014-07-31 11:06:30 -0700459def GetImage(which, tmpdir, info_dict):
Doug Zongkerfc44a512014-08-26 13:10:25 -0700460 # Return an image object (suitable for passing to BlockImageDiff)
461 # for the 'which' partition (most be "system" or "vendor"). If a
462 # prebuilt image and file map are found in tmpdir they are used,
463 # otherwise they are reconstructed from the individual files.
Doug Zongker3c84f562014-07-31 11:06:30 -0700464
465 assert which in ("system", "vendor")
466
467 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700468 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
469 if os.path.exists(path) and os.path.exists(mappath):
Doug Zongker3c84f562014-07-31 11:06:30 -0700470 print "using %s.img from target-files" % (which,)
Doug Zongker3c84f562014-07-31 11:06:30 -0700471 # This is a 'new' target-files, which already has the image in it.
Doug Zongker3c84f562014-07-31 11:06:30 -0700472
473 else:
474 print "building %s.img from target-files" % (which,)
475
476 # This is an 'old' target-files, which does not contain images
477 # already built. Build them.
478
Doug Zongkerfc44a512014-08-26 13:10:25 -0700479 mappath = tempfile.mkstemp()[1]
480 OPTIONS.tempfiles.append(mappath)
481
Doug Zongker3c84f562014-07-31 11:06:30 -0700482 import add_img_to_target_files
483 if which == "system":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700484 path = add_img_to_target_files.BuildSystem(
485 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700486 elif which == "vendor":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700487 path = add_img_to_target_files.BuildVendor(
488 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700489
Tao Bao5ece99d2015-05-12 11:42:31 -0700490 # Bug: http://b/20939131
491 # In ext4 filesystems, block 0 might be changed even being mounted
492 # R/O. We add it to clobbered_blocks so that it will be written to the
493 # target unconditionally. Note that they are still part of care_map.
494 clobbered_blocks = "0"
495
496 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700497
498
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700499def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700500 # TODO: how to determine this? We don't know what version it will
Tao Baobebd3cf2015-06-22 19:17:41 -0700501 # be installed on top of. For now, we expect the API just won't
502 # change very often. Similarly for fstab, it might have changed
503 # in the target build.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700504 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700505
Michael Runge6e836112014-04-15 17:40:21 -0700506 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700507 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700508 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700509 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700510 if OPTIONS.oem_source is None:
511 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700512 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700513 oem_dict = common.LoadDictionaryFromLines(
514 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -0700515
Dan Albert8b72aef2015-03-23 19:13:21 -0700516 metadata = {
517 "post-build": CalculateFingerprint(oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700518 OPTIONS.info_dict),
Dan Albert8b72aef2015-03-23 19:13:21 -0700519 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
520 OPTIONS.info_dict),
521 "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict),
522 }
Doug Zongker2ea21062010-04-28 16:05:21 -0700523
Doug Zongker05d3dea2009-06-22 11:32:31 -0700524 device_specific = common.DeviceSpecificParams(
525 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700526 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700527 output_zip=output_zip,
528 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700529 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700530 metadata=metadata,
531 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700532
Doug Zongkerc9253822014-02-04 12:17:58 -0800533 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800534 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800535
Doug Zongker962069c2009-04-23 11:41:58 -0700536 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700537 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700538 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
539 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700540
Michael Runge6e836112014-04-15 17:40:21 -0700541 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700542 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800543
544 # Two-step package strategy (in chronological order, which is *not*
545 # the order in which the generated script has things):
546 #
547 # if stage is not "2/3" or "3/3":
548 # write recovery image to boot partition
549 # set stage to "2/3"
550 # reboot to boot partition and restart recovery
551 # else if stage is "2/3":
552 # write recovery image to recovery partition
553 # set stage to "3/3"
554 # reboot to recovery partition and restart recovery
555 # else:
556 # (stage must be "3/3")
557 # set stage to ""
558 # do normal full package installation:
559 # wipe and install system, boot image, etc.
560 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700561 # complete script normally
562 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800563
564 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
565 OPTIONS.input_tmp, "RECOVERY")
566 if OPTIONS.two_step:
567 if not OPTIONS.info_dict.get("multistage_support", None):
568 assert False, "two-step packages not supported by this build"
569 fs = OPTIONS.info_dict["fstab"]["/misc"]
570 assert fs.fs_type.upper() == "EMMC", \
571 "two-step packages only supported on devices with EMMC /misc partitions"
572 bcb_dev = {"bcb_dev": fs.device}
573 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
574 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700575if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800576""" % bcb_dev)
577 script.WriteRawImage("/recovery", "recovery.img")
578 script.AppendExtra("""
579set_stage("%(bcb_dev)s", "3/3");
580reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700581else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800582""" % bcb_dev)
583
Tao Bao6c55a8a2015-04-08 15:30:27 -0700584 # Dump fingerprints
585 script.Print("Target: %s" % CalculateFingerprint(
586 oem_props, oem_dict, OPTIONS.info_dict))
587
Doug Zongkere5ff5902012-01-17 10:55:37 -0800588 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700589
Doug Zongker01ce19c2014-02-04 13:48:15 -0800590 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700591
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700592 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800593 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700594 if HasVendorPartition(input_zip):
595 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700596
Kenny Rootf32dc712012-04-08 10:42:34 -0700597 if "selinux_fc" in OPTIONS.info_dict:
598 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500599
Michael Runge7cd99ba2014-10-22 17:21:48 -0700600 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
601
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700602 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700603 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800604
Doug Zongker26e66192014-02-20 13:22:07 -0800605 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700606 # Full OTA is done as an "incremental" against an empty source
607 # image. This has the effect of writing new data from the package
608 # to the entire partition, but lets us reuse the updater code that
609 # writes incrementals to do it.
610 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
611 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700612 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700613 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800614 else:
615 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700616 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800617 if not has_recovery_patch:
618 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800619 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700620
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700621 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800622 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700623
Doug Zongker55d93282011-01-25 17:03:34 -0800624 boot_img = common.GetBootableImage("boot.img", "boot.img",
625 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800626
Doug Zongker91a99c22014-05-09 13:15:01 -0700627 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800628 def output_sink(fn, data):
629 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -0700630 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -0800631
632 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
633 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700634
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700635 system_items.GetMetadata(input_zip)
636 system_items.Get("system").SetPermissions(script)
637
638 if HasVendorPartition(input_zip):
639 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
640 script.ShowProgress(0.1, 0)
641
642 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700643 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
644 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700645 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700646 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700647 else:
648 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700649 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700650 script.UnpackPackageDir("vendor", "/vendor")
651
652 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
653 script.MakeSymlinks(symlinks)
654
655 vendor_items.GetMetadata(input_zip)
656 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700657
Doug Zongker37974732010-09-16 17:44:38 -0700658 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700659 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700660
Doug Zongker01ce19c2014-02-04 13:48:15 -0800661 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700662 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700663
Doug Zongker01ce19c2014-02-04 13:48:15 -0800664 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700665 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700666
Doug Zongker1c390a22009-05-14 19:06:36 -0700667 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700668 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700669
Doug Zongker14833602010-02-02 13:12:04 -0800670 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800671
Doug Zongker922206e2014-03-04 13:16:24 -0800672 if OPTIONS.wipe_user_data:
673 script.ShowProgress(0.1, 10)
674 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700675
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800676 if OPTIONS.two_step:
677 script.AppendExtra("""
678set_stage("%(bcb_dev)s", "");
679""" % bcb_dev)
680 script.AppendExtra("else\n")
681 script.WriteRawImage("/boot", "recovery.img")
682 script.AppendExtra("""
683set_stage("%(bcb_dev)s", "2/3");
684reboot_now("%(bcb_dev)s", "");
685endif;
686endif;
687""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800688 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700689 WriteMetadata(metadata, output_zip)
690
Doug Zongkerfc44a512014-08-26 13:10:25 -0700691
Dan Albert8e0178d2015-01-27 15:53:15 -0800692def WritePolicyConfig(file_name, output_zip):
693 common.ZipWrite(output_zip, file_name, os.path.basename(file_name))
Stephen Smalley56882bf2012-02-09 13:36:21 -0500694
Doug Zongker2ea21062010-04-28 16:05:21 -0700695
696def WriteMetadata(metadata, output_zip):
697 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
698 "".join(["%s=%s\n" % kv
699 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700700
Doug Zongkerfc44a512014-08-26 13:10:25 -0700701
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700702def LoadPartitionFiles(z, partition):
703 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700704 ZipFile, and return a dict of {filename: File object}."""
705 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700706 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700707 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700708 if info.filename.startswith(prefix) and not IsSymlink(info):
Tao Baoeaf885b2015-03-23 16:01:17 -0700709 basefilename = info.filename[len(prefix):]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700710 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700711 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700712 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800713 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700714
715
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700716def GetBuildProp(prop, info_dict):
717 """Return the fingerprint of the build of a given target-files info_dict."""
718 try:
719 return info_dict.get("build.prop", {})[prop]
720 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700721 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700722
Doug Zongkerfc44a512014-08-26 13:10:25 -0700723
Michael Runge4038aa82013-12-13 18:06:28 -0800724def AddToKnownPaths(filename, known_paths):
725 if filename[-1] == "/":
726 return
727 dirs = filename.split("/")[:-1]
728 while len(dirs) > 0:
729 path = "/".join(dirs)
730 if path in known_paths:
Dan Albert8b72aef2015-03-23 19:13:21 -0700731 break
Michael Runge4038aa82013-12-13 18:06:28 -0800732 known_paths.add(path)
733 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700734
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700735
Geremy Condra36bd3652014-02-06 19:45:10 -0800736def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
737 source_version = OPTIONS.source_info_dict["recovery_api_version"]
738 target_version = OPTIONS.target_info_dict["recovery_api_version"]
739
740 if source_version == 0:
741 print ("WARNING: generating edify script for a source that "
742 "can't install it.")
Tao Baobebd3cf2015-06-22 19:17:41 -0700743 script = edify_generator.EdifyGenerator(
744 source_version, OPTIONS.target_info_dict,
745 fstab=OPTIONS.source_info_dict["fstab"])
Geremy Condra36bd3652014-02-06 19:45:10 -0800746
Dan Albert8b72aef2015-03-23 19:13:21 -0700747 metadata = {
748 "pre-device": GetBuildProp("ro.product.device",
749 OPTIONS.source_info_dict),
750 "post-timestamp": GetBuildProp("ro.build.date.utc",
751 OPTIONS.target_info_dict),
752 }
Geremy Condra36bd3652014-02-06 19:45:10 -0800753
754 device_specific = common.DeviceSpecificParams(
755 source_zip=source_zip,
756 source_version=source_version,
757 target_zip=target_zip,
758 target_version=target_version,
759 output_zip=output_zip,
760 script=script,
761 metadata=metadata,
Tao Baoe09359a2015-10-13 16:37:12 -0700762 info_dict=OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800763
Tao Bao6c55a8a2015-04-08 15:30:27 -0700764 # TODO: Currently this works differently from WriteIncrementalOTAPackage().
765 # This function doesn't consider thumbprints when writing
766 # metadata["pre/post-build"]. One possible reason is that the current
767 # devices with thumbprints are all using file-based OTAs. Long term we
768 # should factor out the common parts into a shared one to avoid further
769 # divergence.
Geremy Condra36bd3652014-02-06 19:45:10 -0800770 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
771 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
772 metadata["pre-build"] = source_fp
773 metadata["post-build"] = target_fp
774
775 source_boot = common.GetBootableImage(
776 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
777 OPTIONS.source_info_dict)
778 target_boot = common.GetBootableImage(
779 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
780 updating_boot = (not OPTIONS.two_step and
781 (source_boot.data != target_boot.data))
782
Geremy Condra36bd3652014-02-06 19:45:10 -0800783 target_recovery = common.GetBootableImage(
784 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Geremy Condra36bd3652014-02-06 19:45:10 -0800785
Doug Zongkerfc44a512014-08-26 13:10:25 -0700786 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
787 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700788
789 blockimgdiff_version = 1
790 if OPTIONS.info_dict:
791 blockimgdiff_version = max(
792 int(i) for i in
793 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
794
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700795 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700796 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700797
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700798 if HasVendorPartition(target_zip):
799 if not HasVendorPartition(source_zip):
800 raise RuntimeError("can't generate incremental that adds /vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700801 vendor_src = GetImage("vendor", OPTIONS.source_tmp,
802 OPTIONS.source_info_dict)
803 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp,
804 OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700805 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700806 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700807 else:
808 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800809
Michael Rungec6e3afd2014-05-05 11:55:47 -0700810 oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
Tao Baobebd3cf2015-06-22 19:17:41 -0700811 recovery_mount_options = OPTIONS.source_info_dict.get(
Dan Albert8b72aef2015-03-23 19:13:21 -0700812 "recovery_mount_options")
Michael Rungec6e3afd2014-05-05 11:55:47 -0700813 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700814 if oem_props is not None and len(oem_props) > 0:
Michael Rungec6e3afd2014-05-05 11:55:47 -0700815 if OPTIONS.oem_source is None:
816 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700817 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -0700818 oem_dict = common.LoadDictionaryFromLines(
819 open(OPTIONS.oem_source).readlines())
Michael Rungec6e3afd2014-05-05 11:55:47 -0700820
821 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800822 device_specific.IncrementalOTA_Assertions()
823
824 # Two-step incremental package strategy (in chronological order,
825 # which is *not* the order in which the generated script has
826 # things):
827 #
828 # if stage is not "2/3" or "3/3":
829 # do verification on current system
830 # write recovery image to boot partition
831 # set stage to "2/3"
832 # reboot to boot partition and restart recovery
833 # else if stage is "2/3":
834 # write recovery image to recovery partition
835 # set stage to "3/3"
836 # reboot to recovery partition and restart recovery
837 # else:
838 # (stage must be "3/3")
839 # perform update:
840 # patch system files, etc.
841 # force full install of new boot image
842 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -0700843 # complete script normally
844 # (allow recovery to mark itself finished and reboot)
Geremy Condra36bd3652014-02-06 19:45:10 -0800845
846 if OPTIONS.two_step:
Tao Baocce673b2015-07-29 14:09:23 -0700847 if not OPTIONS.source_info_dict.get("multistage_support", None):
Geremy Condra36bd3652014-02-06 19:45:10 -0800848 assert False, "two-step packages not supported by this build"
Tao Baocce673b2015-07-29 14:09:23 -0700849 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Geremy Condra36bd3652014-02-06 19:45:10 -0800850 assert fs.fs_type.upper() == "EMMC", \
851 "two-step packages only supported on devices with EMMC /misc partitions"
852 bcb_dev = {"bcb_dev": fs.device}
853 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
854 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700855if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800856""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -0700857 script.AppendExtra("sleep(20);\n")
Geremy Condra36bd3652014-02-06 19:45:10 -0800858 script.WriteRawImage("/recovery", "recovery.img")
859 script.AppendExtra("""
860set_stage("%(bcb_dev)s", "3/3");
861reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700862else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800863""" % bcb_dev)
864
Tao Bao6c55a8a2015-04-08 15:30:27 -0700865 # Dump fingerprints
866 script.Print("Source: %s" % CalculateFingerprint(
867 oem_props, oem_dict, OPTIONS.source_info_dict))
868 script.Print("Target: %s" % CalculateFingerprint(
869 oem_props, oem_dict, OPTIONS.target_info_dict))
870
Geremy Condra36bd3652014-02-06 19:45:10 -0800871 script.Print("Verifying current system...")
872
873 device_specific.IncrementalOTA_VerifyBegin()
874
Michael Rungec6e3afd2014-05-05 11:55:47 -0700875 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700876 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
877 # patching on a device that's already on the target build will damage the
878 # system. Because operations like move don't check the block state, they
879 # always apply the changes unconditionally.
880 if blockimgdiff_version <= 2:
881 script.AssertSomeFingerprint(source_fp)
882 else:
883 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700884 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700885 if blockimgdiff_version <= 2:
886 script.AssertSomeThumbprint(
887 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
888 else:
889 script.AssertSomeThumbprint(
890 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
891 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800892
893 if updating_boot:
Tao Baocce673b2015-07-29 14:09:23 -0700894 boot_type, boot_device = common.GetTypeAndDevice(
895 "/boot", OPTIONS.source_info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800896 d = common.Difference(target_boot, source_boot)
897 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700898 if d is None:
899 include_full_boot = True
900 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
901 else:
902 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800903
Doug Zongkerf8340082014-08-05 10:39:37 -0700904 print "boot target: %d source: %d diff: %d" % (
905 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800906
Doug Zongkerf8340082014-08-05 10:39:37 -0700907 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800908
Doug Zongkerf8340082014-08-05 10:39:37 -0700909 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
910 (boot_type, boot_device,
911 source_boot.size, source_boot.sha1,
912 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800913
914 device_specific.IncrementalOTA_VerifyEnd()
915
916 if OPTIONS.two_step:
917 script.WriteRawImage("/boot", "recovery.img")
918 script.AppendExtra("""
919set_stage("%(bcb_dev)s", "2/3");
920reboot_now("%(bcb_dev)s", "");
921else
922""" % bcb_dev)
923
Jesse Zhao75bcea02015-01-06 10:59:53 -0800924 # Verify the existing partitions.
925 system_diff.WriteVerifyScript(script)
926 if vendor_diff:
927 vendor_diff.WriteVerifyScript(script)
928
Geremy Condra36bd3652014-02-06 19:45:10 -0800929 script.Comment("---- start making changes here ----")
930
931 device_specific.IncrementalOTA_InstallBegin()
932
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700933 system_diff.WriteScript(script, output_zip,
934 progress=0.8 if vendor_diff else 0.9)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700935 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700936 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800937
938 if OPTIONS.two_step:
939 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
940 script.WriteRawImage("/boot", "boot.img")
941 print "writing full boot image (forced by two-step mode)"
942
943 if not OPTIONS.two_step:
944 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700945 if include_full_boot:
946 print "boot image changed; including full."
947 script.Print("Installing boot image...")
948 script.WriteRawImage("/boot", "boot.img")
949 else:
950 # Produce the boot image by applying a patch to the current
951 # contents of the boot partition, and write it back to the
952 # partition.
953 print "boot image changed; including patch."
954 script.Print("Patching boot image...")
955 script.ShowProgress(0.1, 10)
956 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
957 % (boot_type, boot_device,
958 source_boot.size, source_boot.sha1,
959 target_boot.size, target_boot.sha1),
960 "-",
961 target_boot.size, target_boot.sha1,
962 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800963 else:
964 print "boot image unchanged; skipping."
965
966 # Do device-specific installation (eg, write radio image).
967 device_specific.IncrementalOTA_InstallEnd()
968
969 if OPTIONS.extra_script is not None:
970 script.AppendExtra(OPTIONS.extra_script)
971
Doug Zongker922206e2014-03-04 13:16:24 -0800972 if OPTIONS.wipe_user_data:
973 script.Print("Erasing user data...")
974 script.FormatPartition("/data")
975
Geremy Condra36bd3652014-02-06 19:45:10 -0800976 if OPTIONS.two_step:
977 script.AppendExtra("""
978set_stage("%(bcb_dev)s", "");
979endif;
980endif;
981""" % bcb_dev)
982
983 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800984 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800985 WriteMetadata(metadata, output_zip)
986
Doug Zongker32b527d2014-03-04 10:03:02 -0800987
Dan Albert8b72aef2015-03-23 19:13:21 -0700988class FileDifference(object):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700989 def __init__(self, partition, source_zip, target_zip, output_zip):
Dan Albert8b72aef2015-03-23 19:13:21 -0700990 self.deferred_patch_list = None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700991 print "Loading target..."
992 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
993 print "Loading source..."
994 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
995
996 self.verbatim_targets = verbatim_targets = []
997 self.patch_list = patch_list = []
998 diffs = []
999 self.renames = renames = {}
1000 known_paths = set()
1001 largest_source_size = 0
1002
1003 matching_file_cache = {}
1004 for fn, sf in source_data.items():
1005 assert fn == sf.name
1006 matching_file_cache["path:" + fn] = sf
1007 if fn in target_data.keys():
1008 AddToKnownPaths(fn, known_paths)
1009 # Only allow eligibility for filename/sha matching
1010 # if there isn't a perfect path match.
1011 if target_data.get(sf.name) is None:
1012 matching_file_cache["file:" + fn.split("/")[-1]] = sf
1013 matching_file_cache["sha:" + sf.sha1] = sf
1014
1015 for fn in sorted(target_data.keys()):
1016 tf = target_data[fn]
1017 assert fn == tf.name
1018 sf = ClosestFileMatch(tf, matching_file_cache, renames)
1019 if sf is not None and sf.name != tf.name:
1020 print "File has moved from " + sf.name + " to " + tf.name
1021 renames[sf.name] = tf
1022
1023 if sf is None or fn in OPTIONS.require_verbatim:
1024 # This file should be included verbatim
1025 if fn in OPTIONS.prohibit_verbatim:
1026 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
1027 print "send", fn, "verbatim"
1028 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001029 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001030 if fn in target_data.keys():
1031 AddToKnownPaths(fn, known_paths)
1032 elif tf.sha1 != sf.sha1:
1033 # File is different; consider sending as a patch
1034 diffs.append(common.Difference(tf, sf))
1035 else:
1036 # Target file data identical to source (may still be renamed)
1037 pass
1038
1039 common.ComputeDifferences(diffs)
1040
1041 for diff in diffs:
1042 tf, sf, d = diff.GetPatch()
1043 path = "/".join(tf.name.split("/")[:-1])
1044 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1045 path not in known_paths:
1046 # patch is almost as big as the file; don't bother patching
1047 # or a patch + rename cannot take place due to the target
1048 # directory not existing
1049 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001050 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001051 if sf.name in renames:
1052 del renames[sf.name]
1053 AddToKnownPaths(tf.name, known_paths)
1054 else:
1055 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1056 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1057 largest_source_size = max(largest_source_size, sf.size)
1058
1059 self.largest_source_size = largest_source_size
1060
1061 def EmitVerification(self, script):
1062 so_far = 0
Dan Albert8b72aef2015-03-23 19:13:21 -07001063 for tf, sf, _, _ in self.patch_list:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001064 if tf.name != sf.name:
1065 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1066 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1067 so_far += sf.size
1068 return so_far
1069
Michael Runge63f01de2014-10-28 19:24:19 -07001070 def EmitExplicitTargetVerification(self, script):
Dan Albert8b72aef2015-03-23 19:13:21 -07001071 for fn, _, sha1 in self.verbatim_targets:
1072 if fn[-1] != "/":
Michael Runge63f01de2014-10-28 19:24:19 -07001073 script.FileCheck("/"+fn, sha1)
1074 for tf, _, _, _ in self.patch_list:
1075 script.FileCheck(tf.name, tf.sha1)
1076
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001077 def RemoveUnneededFiles(self, script, extras=()):
Dan Albert8b72aef2015-03-23 19:13:21 -07001078 script.DeleteFiles(
1079 ["/" + i[0] for i in self.verbatim_targets] +
1080 ["/" + i for i in sorted(self.source_data)
1081 if i not in self.target_data and i not in self.renames] +
1082 list(extras))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001083
1084 def TotalPatchSize(self):
1085 return sum(i[1].size for i in self.patch_list)
1086
1087 def EmitPatches(self, script, total_patch_size, so_far):
1088 self.deferred_patch_list = deferred_patch_list = []
1089 for item in self.patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001090 tf, sf, _, _ = item
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001091 if tf.name == "system/build.prop":
1092 deferred_patch_list.append(item)
1093 continue
Dan Albert8b72aef2015-03-23 19:13:21 -07001094 if sf.name != tf.name:
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001095 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
Dan Albert8b72aef2015-03-23 19:13:21 -07001096 script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1,
1097 "patch/" + sf.name + ".p")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001098 so_far += tf.size
1099 script.SetProgress(so_far / total_patch_size)
1100 return so_far
1101
1102 def EmitDeferredPatches(self, script):
1103 for item in self.deferred_patch_list:
Dan Albert8b72aef2015-03-23 19:13:21 -07001104 tf, sf, _, _ = item
1105 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1,
1106 "patch/" + sf.name + ".p")
1107 script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001108
1109 def EmitRenames(self, script):
1110 if len(self.renames) > 0:
1111 script.Print("Renaming files...")
1112 for src, tgt in self.renames.iteritems():
1113 print "Renaming " + src + " to " + tgt.name
1114 script.RenameFile(src, tgt.name)
1115
1116
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001117def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001118 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1119 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1120
Doug Zongker26e66192014-02-20 13:22:07 -08001121 if (OPTIONS.block_based and
1122 target_has_recovery_patch and
1123 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001124 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1125
Doug Zongker37974732010-09-16 17:44:38 -07001126 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1127 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001128
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001129 if source_version == 0:
1130 print ("WARNING: generating edify script for a source that "
1131 "can't install it.")
Tao Baobebd3cf2015-06-22 19:17:41 -07001132 script = edify_generator.EdifyGenerator(
1133 source_version, OPTIONS.target_info_dict,
1134 fstab=OPTIONS.source_info_dict["fstab"])
Doug Zongkereef39442009-04-02 12:14:19 -07001135
Michael Runge6e836112014-04-15 17:40:21 -07001136 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Tao Baobebd3cf2015-06-22 19:17:41 -07001137 recovery_mount_options = OPTIONS.source_info_dict.get(
1138 "recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001139 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001140 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001141 if OPTIONS.oem_source is None:
1142 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001143 script.Mount("/oem", recovery_mount_options)
Dan Albert8b72aef2015-03-23 19:13:21 -07001144 oem_dict = common.LoadDictionaryFromLines(
1145 open(OPTIONS.oem_source).readlines())
Michael Runge6e836112014-04-15 17:40:21 -07001146
Dan Albert8b72aef2015-03-23 19:13:21 -07001147 metadata = {
1148 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
1149 OPTIONS.source_info_dict),
1150 "post-timestamp": GetBuildProp("ro.build.date.utc",
1151 OPTIONS.target_info_dict),
1152 }
Doug Zongker2ea21062010-04-28 16:05:21 -07001153
Doug Zongker05d3dea2009-06-22 11:32:31 -07001154 device_specific = common.DeviceSpecificParams(
1155 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001156 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001157 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001158 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001159 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001160 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001161 metadata=metadata,
Tao Baoe09359a2015-10-13 16:37:12 -07001162 info_dict=OPTIONS.source_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001163
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001164 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001165 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001166 if HasVendorPartition(target_zip):
1167 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001168 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001169 else:
1170 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001171
Dan Albert8b72aef2015-03-23 19:13:21 -07001172 target_fp = CalculateFingerprint(oem_props, oem_dict,
1173 OPTIONS.target_info_dict)
1174 source_fp = CalculateFingerprint(oem_props, oem_dict,
1175 OPTIONS.source_info_dict)
Michael Runge6e836112014-04-15 17:40:21 -07001176
1177 if oem_props is None:
1178 script.AssertSomeFingerprint(source_fp, target_fp)
1179 else:
1180 script.AssertSomeThumbprint(
1181 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1182 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1183
Doug Zongker2ea21062010-04-28 16:05:21 -07001184 metadata["pre-build"] = source_fp
1185 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001186
Doug Zongker55d93282011-01-25 17:03:34 -08001187 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001188 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1189 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001190 target_boot = common.GetBootableImage(
1191 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001192 updating_boot = (not OPTIONS.two_step and
1193 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001194
Doug Zongker55d93282011-01-25 17:03:34 -08001195 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001196 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1197 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001198 target_recovery = common.GetBootableImage(
1199 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001200 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001201
Doug Zongker881dd402009-09-20 14:03:55 -07001202 # Here's how we divide up the progress bar:
1203 # 0.1 for verifying the start state (PatchCheck calls)
1204 # 0.8 for applying patches (ApplyPatch calls)
1205 # 0.1 for unpacking verbatim files, symlinking, and doing the
1206 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001207
Michael Runge6e836112014-04-15 17:40:21 -07001208 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001209 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001210
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001211 # Two-step incremental package strategy (in chronological order,
1212 # which is *not* the order in which the generated script has
1213 # things):
1214 #
1215 # if stage is not "2/3" or "3/3":
1216 # do verification on current system
1217 # write recovery image to boot partition
1218 # set stage to "2/3"
1219 # reboot to boot partition and restart recovery
1220 # else if stage is "2/3":
1221 # write recovery image to recovery partition
1222 # set stage to "3/3"
1223 # reboot to recovery partition and restart recovery
1224 # else:
1225 # (stage must be "3/3")
1226 # perform update:
1227 # patch system files, etc.
1228 # force full install of new boot image
1229 # set up system to update recovery partition on first boot
Dan Albert8b72aef2015-03-23 19:13:21 -07001230 # complete script normally
1231 # (allow recovery to mark itself finished and reboot)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001232
1233 if OPTIONS.two_step:
Tao Baocce673b2015-07-29 14:09:23 -07001234 if not OPTIONS.source_info_dict.get("multistage_support", None):
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001235 assert False, "two-step packages not supported by this build"
Tao Baocce673b2015-07-29 14:09:23 -07001236 fs = OPTIONS.source_info_dict["fstab"]["/misc"]
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001237 assert fs.fs_type.upper() == "EMMC", \
1238 "two-step packages only supported on devices with EMMC /misc partitions"
1239 bcb_dev = {"bcb_dev": fs.device}
1240 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1241 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001242if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001243""" % bcb_dev)
Dan Albert8b72aef2015-03-23 19:13:21 -07001244 script.AppendExtra("sleep(20);\n")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001245 script.WriteRawImage("/recovery", "recovery.img")
1246 script.AppendExtra("""
1247set_stage("%(bcb_dev)s", "3/3");
1248reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001249else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001250""" % bcb_dev)
1251
Tao Bao6c55a8a2015-04-08 15:30:27 -07001252 # Dump fingerprints
1253 script.Print("Source: %s" % (source_fp,))
1254 script.Print("Target: %s" % (target_fp,))
1255
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001256 script.Print("Verifying current system...")
1257
Doug Zongkere5ff5902012-01-17 10:55:37 -08001258 device_specific.IncrementalOTA_VerifyBegin()
1259
Doug Zongker881dd402009-09-20 14:03:55 -07001260 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001261 so_far = system_diff.EmitVerification(script)
1262 if vendor_diff:
1263 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001264
Doug Zongker5da317e2009-06-02 13:38:17 -07001265 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001266 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001267 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001268 print "boot target: %d source: %d diff: %d" % (
1269 target_boot.size, source_boot.size, len(d))
1270
Doug Zongker048e7ca2009-06-15 14:31:53 -07001271 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001272
Tao Baocce673b2015-07-29 14:09:23 -07001273 boot_type, boot_device = common.GetTypeAndDevice(
1274 "/boot", OPTIONS.source_info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001275
1276 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1277 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001278 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001279 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001280 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001281
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001282 size = []
Dan Albert8b72aef2015-03-23 19:13:21 -07001283 if system_diff.patch_list:
1284 size.append(system_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001285 if vendor_diff:
Dan Albert8b72aef2015-03-23 19:13:21 -07001286 if vendor_diff.patch_list:
1287 size.append(vendor_diff.largest_source_size)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001288 if size or updating_recovery or updating_boot:
1289 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001290
Doug Zongker05d3dea2009-06-22 11:32:31 -07001291 device_specific.IncrementalOTA_VerifyEnd()
1292
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001293 if OPTIONS.two_step:
1294 script.WriteRawImage("/boot", "recovery.img")
1295 script.AppendExtra("""
1296set_stage("%(bcb_dev)s", "2/3");
1297reboot_now("%(bcb_dev)s", "");
1298else
1299""" % bcb_dev)
1300
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001301 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001302
Doug Zongkere5ff5902012-01-17 10:55:37 -08001303 device_specific.IncrementalOTA_InstallBegin()
1304
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001305 if OPTIONS.two_step:
1306 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1307 script.WriteRawImage("/boot", "boot.img")
1308 print "writing full boot image (forced by two-step mode)"
1309
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001310 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001311 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1312 if vendor_diff:
1313 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001314
Doug Zongker881dd402009-09-20 14:03:55 -07001315 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001316 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1317 if vendor_diff:
1318 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001319 if updating_boot:
1320 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001321
1322 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001323 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1324 if vendor_diff:
1325 script.Print("Patching vendor files...")
1326 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001327
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001328 if not OPTIONS.two_step:
1329 if updating_boot:
1330 # Produce the boot image by applying a patch to the current
1331 # contents of the boot partition, and write it back to the
1332 # partition.
1333 script.Print("Patching boot image...")
1334 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1335 % (boot_type, boot_device,
1336 source_boot.size, source_boot.sha1,
1337 target_boot.size, target_boot.sha1),
1338 "-",
1339 target_boot.size, target_boot.sha1,
1340 source_boot.sha1, "patch/boot.img.p")
1341 so_far += target_boot.size
1342 script.SetProgress(so_far / total_patch_size)
1343 print "boot image changed; including."
1344 else:
1345 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001346
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001347 system_items = ItemSet("system", "META/filesystem_config.txt")
1348 if vendor_diff:
1349 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1350
Doug Zongkereef39442009-04-02 12:14:19 -07001351 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001352 # Recovery is generated as a patch using both the boot image
1353 # (which contains the same linux kernel as recovery) and the file
1354 # /system/etc/recovery-resource.dat (which contains all the images
1355 # used in the recovery UI) as sources. This lets us minimize the
1356 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001357 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001358 # For older builds where recovery-resource.dat is not present, we
1359 # use only the boot image as the source.
1360
Doug Zongkerc9253822014-02-04 12:17:58 -08001361 if not target_has_recovery_patch:
1362 def output_sink(fn, data):
1363 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Dan Albert8b72aef2015-03-23 19:13:21 -07001364 system_items.Get("system/" + fn)
Doug Zongkerc9253822014-02-04 12:17:58 -08001365
1366 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1367 target_recovery, target_boot)
1368 script.DeleteFiles(["/system/recovery-from-boot.p",
1369 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001370 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001371 else:
1372 print "recovery image unchanged; skipping."
1373
Doug Zongker881dd402009-09-20 14:03:55 -07001374 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001375
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001376 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1377 if vendor_diff:
1378 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1379
1380 temp_script = script.MakeTemporary()
1381 system_items.GetMetadata(target_zip)
1382 system_items.Get("system").SetPermissions(temp_script)
1383 if vendor_diff:
1384 vendor_items.GetMetadata(target_zip)
1385 vendor_items.Get("vendor").SetPermissions(temp_script)
1386
1387 # Note that this call will mess up the trees of Items, so make sure
1388 # we're done with them.
1389 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1390 if vendor_diff:
1391 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001392
1393 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001394 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1395
1396 # Delete all the symlinks in source that aren't in target. This
1397 # needs to happen before verbatim files are unpacked, in case a
1398 # symlink in the source is replaced by a real file in the target.
Tao Bao39c322c2015-09-02 10:28:08 -07001399
1400 # If a symlink in the source will be replaced by a regular file, we cannot
1401 # delete the symlink/file in case the package gets applied again. For such
1402 # a symlink, we prepend a sha1_check() to detect if it has been updated.
1403 # (Bug: 23646151)
1404 replaced_symlinks = dict()
1405 if system_diff:
1406 for i in system_diff.verbatim_targets:
1407 replaced_symlinks["/%s" % (i[0],)] = i[2]
1408 if vendor_diff:
1409 for i in vendor_diff.verbatim_targets:
1410 replaced_symlinks["/%s" % (i[0],)] = i[2]
1411
1412 if system_diff:
1413 for tf in system_diff.renames.values():
1414 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1415 if vendor_diff:
1416 for tf in vendor_diff.renames.values():
1417 replaced_symlinks["/%s" % (tf.name,)] = tf.sha1
1418
1419 always_delete = []
1420 may_delete = []
Doug Zongkereef39442009-04-02 12:14:19 -07001421 for dest, link in source_symlinks:
1422 if link not in target_symlinks_d:
Tao Bao39c322c2015-09-02 10:28:08 -07001423 if link in replaced_symlinks:
1424 may_delete.append((link, replaced_symlinks[link]))
1425 else:
1426 always_delete.append(link)
1427 script.DeleteFiles(always_delete)
1428 script.DeleteFilesIfNotMatching(may_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001429
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001430 if system_diff.verbatim_targets:
1431 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001432 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001433 if vendor_diff and vendor_diff.verbatim_targets:
1434 script.Print("Unpacking new vendor files...")
1435 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001436
Doug Zongkerc9253822014-02-04 12:17:58 -08001437 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001438 script.Print("Unpacking new recovery...")
1439 script.UnpackPackageDir("recovery", "/system")
1440
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001441 system_diff.EmitRenames(script)
1442 if vendor_diff:
1443 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001444
Doug Zongker05d3dea2009-06-22 11:32:31 -07001445 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001446
1447 # Create all the symlinks that don't already exist, or point to
1448 # somewhere different than what we want. Delete each symlink before
1449 # creating it, since the 'symlink' command won't overwrite.
1450 to_create = []
1451 for dest, link in target_symlinks:
1452 if link in source_symlinks_d:
1453 if dest != source_symlinks_d[link]:
1454 to_create.append((dest, link))
1455 else:
1456 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001457 script.DeleteFiles([i[1] for i in to_create])
1458 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001459
1460 # Now that the symlinks are created, we can set all the
1461 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001462 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001463
Doug Zongker881dd402009-09-20 14:03:55 -07001464 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001465 device_specific.IncrementalOTA_InstallEnd()
1466
Doug Zongker1c390a22009-05-14 19:06:36 -07001467 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001468 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001469
Doug Zongkere92f15a2011-08-26 13:46:40 -07001470 # Patch the build.prop file last, so if something fails but the
1471 # device can still come up, it appears to be the old build and will
1472 # get set the OTA package again to retry.
1473 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001474 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001475
Doug Zongker922206e2014-03-04 13:16:24 -08001476 if OPTIONS.wipe_user_data:
1477 script.Print("Erasing user data...")
1478 script.FormatPartition("/data")
1479
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001480 if OPTIONS.two_step:
1481 script.AppendExtra("""
1482set_stage("%(bcb_dev)s", "");
1483endif;
1484endif;
1485""" % bcb_dev)
1486
Michael Runge63f01de2014-10-28 19:24:19 -07001487 if OPTIONS.verify and system_diff:
1488 script.Print("Remounting and verifying system partition files...")
1489 script.Unmount("/system")
1490 script.Mount("/system")
1491 system_diff.EmitExplicitTargetVerification(script)
1492
1493 if OPTIONS.verify and vendor_diff:
1494 script.Print("Remounting and verifying vendor partition files...")
1495 script.Unmount("/vendor")
1496 script.Mount("/vendor")
1497 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001498 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001499
Doug Zongker2ea21062010-04-28 16:05:21 -07001500 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001501
1502
1503def main(argv):
1504
1505 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001506 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001507 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001508 elif o in ("-k", "--package_key"):
1509 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001510 elif o in ("-i", "--incremental_from"):
1511 OPTIONS.incremental_source = a
Tao Bao43078aa2015-04-21 14:32:35 -07001512 elif o == "--full_radio":
1513 OPTIONS.full_radio = True
leozwanga1fcaf82015-09-15 08:44:12 -07001514 elif o == "--full_bootloader":
1515 OPTIONS.full_bootloader = True
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001516 elif o in ("-w", "--wipe_user_data"):
1517 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001518 elif o in ("-n", "--no_prereq"):
1519 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001520 elif o in ("-o", "--oem_settings"):
1521 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001522 elif o in ("-e", "--extra_script"):
1523 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001524 elif o in ("-a", "--aslr_mode"):
1525 if a in ("on", "On", "true", "True", "yes", "Yes"):
1526 OPTIONS.aslr_mode = True
1527 else:
1528 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001529 elif o in ("-t", "--worker_threads"):
1530 if a.isdigit():
1531 OPTIONS.worker_threads = int(a)
1532 else:
1533 raise ValueError("Cannot parse value %r for option %r - only "
1534 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001535 elif o in ("-2", "--two_step"):
1536 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001537 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001538 OPTIONS.no_signing = True
Dan Albert8b72aef2015-03-23 19:13:21 -07001539 elif o == "--verify":
Michael Runge63f01de2014-10-28 19:24:19 -07001540 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001541 elif o == "--block":
1542 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001543 elif o in ("-b", "--binary"):
1544 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001545 elif o in ("--no_fallback_to_full",):
1546 OPTIONS.fallback_to_full = False
Tao Baod47d8e12015-05-21 14:09:49 -07001547 elif o == "--stash_threshold":
1548 try:
1549 OPTIONS.stash_threshold = float(a)
1550 except ValueError:
1551 raise ValueError("Cannot parse value %r for option %r - expecting "
1552 "a float" % (a, o))
Doug Zongkereef39442009-04-02 12:14:19 -07001553 else:
1554 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001555 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001556
1557 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001558 extra_opts="b:k:i:d:wne:t:a:2o:",
Dan Albert8b72aef2015-03-23 19:13:21 -07001559 extra_long_opts=[
1560 "board_config=",
1561 "package_key=",
1562 "incremental_from=",
Tao Bao43078aa2015-04-21 14:32:35 -07001563 "full_radio",
leozwanga1fcaf82015-09-15 08:44:12 -07001564 "full_bootloader",
Dan Albert8b72aef2015-03-23 19:13:21 -07001565 "wipe_user_data",
1566 "no_prereq",
1567 "extra_script=",
1568 "worker_threads=",
1569 "aslr_mode=",
1570 "two_step",
1571 "no_signing",
1572 "block",
1573 "binary=",
1574 "oem_settings=",
1575 "verify",
1576 "no_fallback_to_full",
Tao Baod47d8e12015-05-21 14:09:49 -07001577 "stash_threshold=",
Dan Albert8b72aef2015-03-23 19:13:21 -07001578 ], extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001579
1580 if len(args) != 2:
1581 common.Usage(__doc__)
1582 sys.exit(1)
1583
Doug Zongker1c390a22009-05-14 19:06:36 -07001584 if OPTIONS.extra_script is not None:
1585 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1586
Doug Zongkereef39442009-04-02 12:14:19 -07001587 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001588 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001589
Doug Zongkereef39442009-04-02 12:14:19 -07001590 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001591 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001592
1593 # If this image was originally labelled with SELinux contexts, make sure we
1594 # also apply the labels in our new image. During building, the "file_contexts"
1595 # is in the out/ directory tree, but for repacking from target-files.zip it's
1596 # in the root directory of the ramdisk.
1597 if "selinux_fc" in OPTIONS.info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001598 OPTIONS.info_dict["selinux_fc"] = os.path.join(
1599 OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")
Kenny Roote2e9f612013-05-29 12:59:35 -07001600
Doug Zongker37974732010-09-16 17:44:38 -07001601 if OPTIONS.verbose:
1602 print "--- target info ---"
1603 common.DumpInfoDict(OPTIONS.info_dict)
1604
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001605 # If the caller explicitly specified the device-specific extensions
1606 # path via -s/--device_specific, use that. Otherwise, use
1607 # META/releasetools.py if it is present in the target target_files.
1608 # Otherwise, take the path of the file from 'tool_extensions' in the
1609 # info dict and look for that in the local filesystem, relative to
1610 # the current directory.
1611
Doug Zongker37974732010-09-16 17:44:38 -07001612 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001613 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1614 if os.path.exists(from_input):
1615 print "(using device-specific extensions from target_files)"
1616 OPTIONS.device_specific = from_input
1617 else:
1618 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1619
Doug Zongker37974732010-09-16 17:44:38 -07001620 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001621 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001622
Doug Zongker62d4f182014-08-04 16:06:43 -07001623 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001624
Doug Zongker62d4f182014-08-04 16:06:43 -07001625 if OPTIONS.no_signing:
Dan Albert8b72aef2015-03-23 19:13:21 -07001626 if os.path.exists(args[1]):
1627 os.unlink(args[1])
1628 output_zip = zipfile.ZipFile(args[1], "w",
1629 compression=zipfile.ZIP_DEFLATED)
Doug Zongker62d4f182014-08-04 16:06:43 -07001630 else:
1631 temp_zip_file = tempfile.NamedTemporaryFile()
1632 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1633 compression=zipfile.ZIP_DEFLATED)
1634
Tao Baod47d8e12015-05-21 14:09:49 -07001635 cache_size = OPTIONS.info_dict.get("cache_size", None)
1636 if cache_size is None:
1637 raise RuntimeError("can't determine the cache partition size")
1638 OPTIONS.cache_size = cache_size
1639
Doug Zongker62d4f182014-08-04 16:06:43 -07001640 if OPTIONS.incremental_source is None:
1641 WriteFullOTAPackage(input_zip, output_zip)
1642 if OPTIONS.package_key is None:
1643 OPTIONS.package_key = OPTIONS.info_dict.get(
1644 "default_system_dev_certificate",
1645 "build/target/product/security/testkey")
Tao Baof3282b42015-04-01 11:21:55 -07001646 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001647 break
1648
1649 else:
1650 print "unzipping source target-files..."
Dan Albert8b72aef2015-03-23 19:13:21 -07001651 OPTIONS.source_tmp, source_zip = common.UnzipTemp(
1652 OPTIONS.incremental_source)
Doug Zongker62d4f182014-08-04 16:06:43 -07001653 OPTIONS.target_info_dict = OPTIONS.info_dict
1654 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1655 if "selinux_fc" in OPTIONS.source_info_dict:
Dan Albert8b72aef2015-03-23 19:13:21 -07001656 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(
1657 OPTIONS.source_tmp, "BOOT", "RAMDISK", "file_contexts")
Doug Zongker62d4f182014-08-04 16:06:43 -07001658 if OPTIONS.package_key is None:
1659 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1660 "default_system_dev_certificate",
1661 "build/target/product/security/testkey")
1662 if OPTIONS.verbose:
1663 print "--- source info ---"
1664 common.DumpInfoDict(OPTIONS.source_info_dict)
1665 try:
1666 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Tao Baof3282b42015-04-01 11:21:55 -07001667 common.ZipClose(output_zip)
Doug Zongker62d4f182014-08-04 16:06:43 -07001668 break
1669 except ValueError:
Dan Albert8b72aef2015-03-23 19:13:21 -07001670 if not OPTIONS.fallback_to_full:
1671 raise
Doug Zongker62d4f182014-08-04 16:06:43 -07001672 print "--- failed to build incremental; falling back to full ---"
1673 OPTIONS.incremental_source = None
Tao Baof3282b42015-04-01 11:21:55 -07001674 common.ZipClose(output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001675
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001676 if not OPTIONS.no_signing:
1677 SignOutput(temp_zip_file.name, args[1])
1678 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001679
Doug Zongkereef39442009-04-02 12:14:19 -07001680 print "done."
1681
1682
1683if __name__ == '__main__':
1684 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001685 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001686 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -07001687 except common.ExternalError as e:
Doug Zongkereef39442009-04-02 12:14:19 -07001688 print
1689 print " ERROR: %s" % (e,)
1690 print
1691 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001692 finally:
1693 common.Cleanup()