blob: a7936b13a9ced0fb5a8cee9e1be74661f480dcee [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
Doug Zongkerdbfaae52009-04-21 17:12:54 -070040 -w (--wipe_user_data)
41 Generate an OTA package that will wipe the user data partition
42 when installed.
43
Doug Zongker962069c2009-04-23 11:41:58 -070044 -n (--no_prereq)
45 Omit the timestamp prereq check normally included at the top of
46 the build scripts (used for developer OTA packages which
47 legitimately need to go back and forth).
48
Doug Zongker1c390a22009-05-14 19:06:36 -070049 -e (--extra_script) <file>
50 Insert the contents of file at the end of the update script.
51
Hristo Bojinovdafb0422010-08-26 14:35:16 -070052 -a (--aslr_mode) <on|off>
53 Specify whether to turn on ASLR for the package (on by default).
Stephen Smalley56882bf2012-02-09 13:36:21 -050054
Doug Zongker9b23f2c2013-11-25 14:44:12 -080055 -2 (--two_step)
56 Generate a 'two-step' OTA package, where recovery is updated
57 first, so that any changes made to the system partition are done
58 using the new recovery (new kernel, etc.).
59
Doug Zongker26e66192014-02-20 13:22:07 -080060 --block
61 Generate a block-based OTA if possible. Will fall back to a
62 file-based OTA if the target_files is older and doesn't support
63 block-based OTAs.
64
Doug Zongker25568482014-03-03 10:21:27 -080065 -b (--binary) <file>
66 Use the given binary as the update-binary in the output package,
67 instead of the binary in the build's target_files. Use for
68 development only.
69
Doug Zongkereef39442009-04-02 12:14:19 -070070"""
71
72import sys
73
Doug Zongkercf6d5a92014-02-18 10:57:07 -080074if sys.hexversion < 0x02070000:
75 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -070076 sys.exit(1)
77
78import copy
Doug Zongkerc18736b2009-09-30 09:20:32 -070079import errno
Doug Zongkereef39442009-04-02 12:14:19 -070080import os
81import re
Doug Zongkereef39442009-04-02 12:14:19 -070082import subprocess
83import tempfile
84import time
85import zipfile
86
davidcad0bb92011-03-15 14:21:38 +000087try:
88 from hashlib import sha1 as sha1
89except ImportError:
90 from sha import sha as sha1
91
Doug Zongkereef39442009-04-02 12:14:19 -070092import common
Doug Zongker01ce19c2014-02-04 13:48:15 -080093import img_from_target_files
Doug Zongkerc494d7c2009-06-18 08:43:44 -070094import edify_generator
Geremy Condra36bd3652014-02-06 19:45:10 -080095import build_image
Doug Zongkereef39442009-04-02 12:14:19 -070096
97OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -070098OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -070099OPTIONS.incremental_source = None
100OPTIONS.require_verbatim = set()
101OPTIONS.prohibit_verbatim = set(("system/build.prop",))
102OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700103OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700104OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700105OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700106OPTIONS.aslr_mode = True
Doug Zongker761e6422009-09-25 10:45:39 -0700107OPTIONS.worker_threads = 3
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800108OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900109OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800110OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800111OPTIONS.updater_binary = None
Doug Zongkereef39442009-04-02 12:14:19 -0700112
113def MostPopularKey(d, default):
114 """Given a dict, return the key corresponding to the largest
115 value. Returns 'default' if the dict is empty."""
116 x = [(v, k) for (k, v) in d.iteritems()]
117 if not x: return default
118 x.sort()
119 return x[-1][1]
120
121
122def IsSymlink(info):
123 """Return true if the zipfile.ZipInfo object passed in represents a
124 symlink."""
125 return (info.external_attr >> 16) == 0120777
126
Hristo Bojinov96be7202010-08-02 10:26:17 -0700127def IsRegular(info):
128 """Return true if the zipfile.ZipInfo object passed in represents a
129 symlink."""
130 return (info.external_attr >> 28) == 010
Doug Zongkereef39442009-04-02 12:14:19 -0700131
Michael Runge4038aa82013-12-13 18:06:28 -0800132def ClosestFileMatch(src, tgtfiles, existing):
133 """Returns the closest file match between a source file and list
134 of potential matches. The exact filename match is preferred,
135 then the sha1 is searched for, and finally a file with the same
136 basename is evaluated. Rename support in the updater-binary is
137 required for the latter checks to be used."""
138
139 result = tgtfiles.get("path:" + src.name)
140 if result is not None:
141 return result
142
143 if not OPTIONS.target_info_dict.get("update_rename_support", False):
144 return None
145
146 if src.size < 1000:
147 return None
148
149 result = tgtfiles.get("sha1:" + src.sha1)
150 if result is not None and existing.get(result.name) is None:
151 return result
152 result = tgtfiles.get("file:" + src.name.split("/")[-1])
153 if result is not None and existing.get(result.name) is None:
154 return result
155 return None
156
Doug Zongkereef39442009-04-02 12:14:19 -0700157class Item:
158 """Items represent the metadata (user, group, mode) of files and
159 directories in the system image."""
160 ITEMS = {}
161 def __init__(self, name, dir=False):
162 self.name = name
163 self.uid = None
164 self.gid = None
165 self.mode = None
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700166 self.selabel = None
167 self.capabilities = None
Doug Zongkereef39442009-04-02 12:14:19 -0700168 self.dir = dir
169
170 if name:
171 self.parent = Item.Get(os.path.dirname(name), dir=True)
172 self.parent.children.append(self)
173 else:
174 self.parent = None
175 if dir:
176 self.children = []
177
178 def Dump(self, indent=0):
179 if self.uid is not None:
180 print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode)
181 else:
182 print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode)
183 if self.dir:
184 print "%s%s" % (" "*indent, self.descendants)
185 print "%s%s" % (" "*indent, self.best_subtree)
186 for i in self.children:
187 i.Dump(indent=indent+1)
188
189 @classmethod
190 def Get(cls, name, dir=False):
191 if name not in cls.ITEMS:
192 cls.ITEMS[name] = Item(name, dir=dir)
193 return cls.ITEMS[name]
194
195 @classmethod
Doug Zongker283e2a12010-03-15 17:52:32 -0700196 def GetMetadata(cls, input_zip):
197
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700198 # The target_files contains a record of what the uid,
199 # gid, and mode are supposed to be.
200 output = input_zip.read("META/filesystem_config.txt")
Doug Zongkereef39442009-04-02 12:14:19 -0700201
202 for line in output.split("\n"):
203 if not line: continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700204 columns = line.split()
205 name, uid, gid, mode = columns[:4]
206 selabel = None
207 capabilities = None
208
209 # After the first 4 columns, there are a series of key=value
210 # pairs. Extract out the fields we care about.
211 for element in columns[4:]:
212 key, value = element.split("=")
213 if key == "selabel":
214 selabel = value
215 if key == "capabilities":
216 capabilities = value
217
Doug Zongker283e2a12010-03-15 17:52:32 -0700218 i = cls.ITEMS.get(name, None)
219 if i is not None:
220 i.uid = int(uid)
221 i.gid = int(gid)
222 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700223 i.selabel = selabel
224 i.capabilities = capabilities
Doug Zongker283e2a12010-03-15 17:52:32 -0700225 if i.dir:
226 i.children.sort(key=lambda i: i.name)
227
228 # set metadata for the files generated by this script.
229 i = cls.ITEMS.get("system/recovery-from-boot.p", None)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700230 if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0644, None, None
Doug Zongker283e2a12010-03-15 17:52:32 -0700231 i = cls.ITEMS.get("system/etc/install-recovery.sh", None)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700232 if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700233
234 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700235 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
236 all children and determine the best strategy for using set_perm_recursive and
Doug Zongkereef39442009-04-02 12:14:19 -0700237 set_perm to correctly chown/chmod all the files to their desired
238 values. Recursively calls itself for all descendants.
239
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700240 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count} counting up
Doug Zongkereef39442009-04-02 12:14:19 -0700241 all descendants of this node. (dmode or fmode may be None.) Also
242 sets the best_subtree of each directory Item to the (uid, gid,
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700243 dmode, fmode, selabel, capabilities) tuple that will match the most
244 descendants of that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700245 """
246
247 assert self.dir
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700248 d = self.descendants = {(self.uid, self.gid, self.mode, None, self.selabel, self.capabilities): 1}
Doug Zongkereef39442009-04-02 12:14:19 -0700249 for i in self.children:
250 if i.dir:
251 for k, v in i.CountChildMetadata().iteritems():
252 d[k] = d.get(k, 0) + v
253 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700254 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700255 d[k] = d.get(k, 0) + 1
256
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700257 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
258 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700259
260 # First, find the (uid, gid) pair that matches the most
261 # descendants.
262 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700263 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700264 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
265 ug = MostPopularKey(ug, (0, 0))
266
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700267 # Now find the dmode, fmode, selabel, and capabilities that match
268 # the most descendants with that (uid, gid), and choose those.
Doug Zongkereef39442009-04-02 12:14:19 -0700269 best_dmode = (0, 0755)
270 best_fmode = (0, 0644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700271 best_selabel = (0, None)
272 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700273 for k, count in d.iteritems():
274 if k[:2] != ug: continue
275 if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2])
276 if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3])
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700277 if k[4] is not None and count >= best_selabel[0]: best_selabel = (count, k[4])
278 if k[5] is not None and count >= best_capabilities[0]: best_capabilities = (count, k[5])
279 self.best_subtree = ug + (best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700280
281 return d
282
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700283 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700284 """Append set_perm/set_perm_recursive commands to 'script' to
285 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700286 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700287
288 self.CountChildMetadata()
289
290 def recurse(item, current):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700291 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple that the current
Doug Zongkereef39442009-04-02 12:14:19 -0700292 # item (and all its children) have already been set to. We only
293 # need to issue set_perm/set_perm_recursive commands if we're
294 # supposed to be something different.
295 if item.dir:
296 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700297 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700298 current = item.best_subtree
299
300 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700301 item.mode != current[2] or item.selabel != current[4] or \
302 item.capabilities != current[5]:
303 script.SetPermissions("/"+item.name, item.uid, item.gid,
304 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700305
306 for i in item.children:
307 recurse(i, current)
308 else:
309 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700310 item.mode != current[3] or item.selabel != current[4] or \
311 item.capabilities != current[5]:
312 script.SetPermissions("/"+item.name, item.uid, item.gid,
313 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700314
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700315 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700316
317
318def CopySystemFiles(input_zip, output_zip=None,
319 substitute=None):
320 """Copies files underneath system/ in the input zip to the output
321 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800322 list of symlinks. output_zip may be None, in which case the copy is
323 skipped (but the other side effects still happen). substitute is an
324 optional dict of {output filename: contents} to be output instead of
325 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700326 """
327
328 symlinks = []
329
330 for info in input_zip.infolist():
331 if info.filename.startswith("SYSTEM/"):
332 basefilename = info.filename[7:]
333 if IsSymlink(info):
334 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700335 "/system/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700336 else:
337 info2 = copy.copy(info)
338 fn = info2.filename = "system/" + basefilename
339 if substitute and fn in substitute and substitute[fn] is None:
340 continue
341 if output_zip is not None:
342 if substitute and fn in substitute:
343 data = substitute[fn]
344 else:
345 data = input_zip.read(info.filename)
346 output_zip.writestr(info2, data)
347 if fn.endswith("/"):
348 Item.Get(fn[:-1], dir=True)
349 else:
350 Item.Get(fn, dir=False)
351
352 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800353 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700354
355
Doug Zongkereef39442009-04-02 12:14:19 -0700356def SignOutput(temp_zip_name, output_zip_name):
357 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
358 pw = key_passwords[OPTIONS.package_key]
359
Doug Zongker951495f2009-08-14 12:44:19 -0700360 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
361 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700362
363
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700364def AppendAssertions(script, info_dict):
365 device = GetBuildProp("ro.product.device", info_dict)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700366 script.AssertDevice(device)
Doug Zongkereef39442009-04-02 12:14:19 -0700367
Doug Zongkereef39442009-04-02 12:14:19 -0700368
Doug Zongkerc9253822014-02-04 12:17:58 -0800369def HasRecoveryPatch(target_files_zip):
370 try:
371 target_files_zip.getinfo("SYSTEM/recovery-from-boot.p")
372 return True
373 except KeyError:
374 return False
Doug Zongker73ef8252009-07-23 15:12:53 -0700375
376
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700377def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700378 # TODO: how to determine this? We don't know what version it will
379 # be installed on top of. For now, we expect the API just won't
380 # change very often.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700381 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700382
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700383 metadata = {"post-build": GetBuildProp("ro.build.fingerprint",
384 OPTIONS.info_dict),
385 "pre-device": GetBuildProp("ro.product.device",
386 OPTIONS.info_dict),
387 "post-timestamp": GetBuildProp("ro.build.date.utc",
388 OPTIONS.info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700389 }
390
Doug Zongker05d3dea2009-06-22 11:32:31 -0700391 device_specific = common.DeviceSpecificParams(
392 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700393 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700394 output_zip=output_zip,
395 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700396 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700397 metadata=metadata,
398 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700399
Doug Zongkerc9253822014-02-04 12:17:58 -0800400 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800401 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800402
Doug Zongker962069c2009-04-23 11:41:58 -0700403 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700404 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700405 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
406 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700407
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700408 AppendAssertions(script, OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700409 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800410
411 # Two-step package strategy (in chronological order, which is *not*
412 # the order in which the generated script has things):
413 #
414 # if stage is not "2/3" or "3/3":
415 # write recovery image to boot partition
416 # set stage to "2/3"
417 # reboot to boot partition and restart recovery
418 # else if stage is "2/3":
419 # write recovery image to recovery partition
420 # set stage to "3/3"
421 # reboot to recovery partition and restart recovery
422 # else:
423 # (stage must be "3/3")
424 # set stage to ""
425 # do normal full package installation:
426 # wipe and install system, boot image, etc.
427 # set up system to update recovery partition on first boot
428 # complete script normally (allow recovery to mark itself finished and reboot)
429
430 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
431 OPTIONS.input_tmp, "RECOVERY")
432 if OPTIONS.two_step:
433 if not OPTIONS.info_dict.get("multistage_support", None):
434 assert False, "two-step packages not supported by this build"
435 fs = OPTIONS.info_dict["fstab"]["/misc"]
436 assert fs.fs_type.upper() == "EMMC", \
437 "two-step packages only supported on devices with EMMC /misc partitions"
438 bcb_dev = {"bcb_dev": fs.device}
439 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
440 script.AppendExtra("""
441if get_stage("%(bcb_dev)s", "stage") == "2/3" then
442""" % bcb_dev)
443 script.WriteRawImage("/recovery", "recovery.img")
444 script.AppendExtra("""
445set_stage("%(bcb_dev)s", "3/3");
446reboot_now("%(bcb_dev)s", "recovery");
447else if get_stage("%(bcb_dev)s", "stage") == "3/3" then
448""" % bcb_dev)
449
Doug Zongkere5ff5902012-01-17 10:55:37 -0800450 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700451
Doug Zongker01ce19c2014-02-04 13:48:15 -0800452 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700453
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700454 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800455 system_progress -= 0.1
456 script.ShowProgress(0.1, 10)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700457 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700458
Kenny Rootf32dc712012-04-08 10:42:34 -0700459 if "selinux_fc" in OPTIONS.info_dict:
460 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500461
Doug Zongker01ce19c2014-02-04 13:48:15 -0800462 script.ShowProgress(system_progress, 30)
Doug Zongker26e66192014-02-20 13:22:07 -0800463 if block_based:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800464 img_from_target_files.AddSystem(output_zip, sparse=False)
465 script.WriteRawImage("/system", "system.img")
466 else:
467 script.FormatPartition("/system")
468 script.Mount("/system")
469 if not has_recovery_patch:
470 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800471 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700472
Doug Zongker01ce19c2014-02-04 13:48:15 -0800473 symlinks = CopySystemFiles(input_zip, output_zip)
474 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700475
Doug Zongker55d93282011-01-25 17:03:34 -0800476 boot_img = common.GetBootableImage("boot.img", "boot.img",
477 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800478
479 if not has_recovery_patch:
480 def output_sink(fn, data):
481 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
482 Item.Get("system/" + fn, dir=False)
483
484 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
485 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700486
Doug Zongker01ce19c2014-02-04 13:48:15 -0800487 Item.GetMetadata(input_zip)
488 Item.Get("system").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700489
Doug Zongker37974732010-09-16 17:44:38 -0700490 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700491 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700492
Doug Zongker01ce19c2014-02-04 13:48:15 -0800493 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700494 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700495
Doug Zongker01ce19c2014-02-04 13:48:15 -0800496 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700497 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700498
Doug Zongker1c390a22009-05-14 19:06:36 -0700499 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700500 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700501
Doug Zongker14833602010-02-02 13:12:04 -0800502 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800503
504 if OPTIONS.two_step:
505 script.AppendExtra("""
506set_stage("%(bcb_dev)s", "");
507""" % bcb_dev)
508 script.AppendExtra("else\n")
509 script.WriteRawImage("/boot", "recovery.img")
510 script.AppendExtra("""
511set_stage("%(bcb_dev)s", "2/3");
512reboot_now("%(bcb_dev)s", "");
513endif;
514endif;
515""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800516 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700517 WriteMetadata(metadata, output_zip)
518
Stephen Smalley56882bf2012-02-09 13:36:21 -0500519def WritePolicyConfig(file_context, output_zip):
520 f = open(file_context, 'r');
521 basename = os.path.basename(file_context)
522 common.ZipWriteStr(output_zip, basename, f.read())
523
Doug Zongker2ea21062010-04-28 16:05:21 -0700524
525def WriteMetadata(metadata, output_zip):
526 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
527 "".join(["%s=%s\n" % kv
528 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700529
Doug Zongkereef39442009-04-02 12:14:19 -0700530def LoadSystemFiles(z):
531 """Load all the files from SYSTEM/... in a given target-files
532 ZipFile, and return a dict of {filename: File object}."""
533 out = {}
534 for info in z.infolist():
535 if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
Hristo Bojinov96be7202010-08-02 10:26:17 -0700536 basefilename = info.filename[7:]
537 fn = "system/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700538 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700539 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800540 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700541
542
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700543def GetBuildProp(prop, info_dict):
544 """Return the fingerprint of the build of a given target-files info_dict."""
545 try:
546 return info_dict.get("build.prop", {})[prop]
547 except KeyError:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700548 raise common.ExternalError("couldn't find %s in build.prop" % (property,))
Doug Zongkereef39442009-04-02 12:14:19 -0700549
Michael Runge4038aa82013-12-13 18:06:28 -0800550def AddToKnownPaths(filename, known_paths):
551 if filename[-1] == "/":
552 return
553 dirs = filename.split("/")[:-1]
554 while len(dirs) > 0:
555 path = "/".join(dirs)
556 if path in known_paths:
557 break;
558 known_paths.add(path)
559 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700560
Geremy Condra36bd3652014-02-06 19:45:10 -0800561def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
562 source_version = OPTIONS.source_info_dict["recovery_api_version"]
563 target_version = OPTIONS.target_info_dict["recovery_api_version"]
564
565 if source_version == 0:
566 print ("WARNING: generating edify script for a source that "
567 "can't install it.")
568 script = edify_generator.EdifyGenerator(source_version,
569 OPTIONS.target_info_dict)
570
571 metadata = {"pre-device": GetBuildProp("ro.product.device",
572 OPTIONS.source_info_dict),
573 "post-timestamp": GetBuildProp("ro.build.date.utc",
574 OPTIONS.target_info_dict),
575 }
576
577 device_specific = common.DeviceSpecificParams(
578 source_zip=source_zip,
579 source_version=source_version,
580 target_zip=target_zip,
581 target_version=target_version,
582 output_zip=output_zip,
583 script=script,
584 metadata=metadata,
585 info_dict=OPTIONS.info_dict)
586
587 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
588 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
589 metadata["pre-build"] = source_fp
590 metadata["post-build"] = target_fp
591
592 source_boot = common.GetBootableImage(
593 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
594 OPTIONS.source_info_dict)
595 target_boot = common.GetBootableImage(
596 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
597 updating_boot = (not OPTIONS.two_step and
598 (source_boot.data != target_boot.data))
599
600 source_recovery = common.GetBootableImage(
601 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
602 OPTIONS.source_info_dict)
603 target_recovery = common.GetBootableImage(
604 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
605 updating_recovery = (source_recovery.data != target_recovery.data)
606
607 with tempfile.NamedTemporaryFile() as src_file:
608 with tempfile.NamedTemporaryFile() as tgt_file:
609 print "building source system image..."
610 src_file = tempfile.NamedTemporaryFile()
611 src_data = img_from_target_files.BuildSystem(
612 OPTIONS.source_tmp, OPTIONS.source_info_dict, sparse=False)
613 src_sys_sha1 = sha1(src_data).hexdigest()
614 print "source system sha1:", src_sys_sha1
615 src_file.write(src_data)
616 src_data = None
617
618 print "building target system image..."
619 tgt_file = tempfile.NamedTemporaryFile()
620 tgt_data = img_from_target_files.BuildSystem(
621 OPTIONS.target_tmp, OPTIONS.target_info_dict, sparse=False)
622 tgt_sys_sha1 = sha1(tgt_data).hexdigest()
623 print "target system sha1:", tgt_sys_sha1
624 tgt_sys_len = len(tgt_data)
625 tgt_file.write(tgt_data)
626 tgt_data = None
627
628 system_type, system_device = common.GetTypeAndDevice("/system", OPTIONS.info_dict)
629 system_patch = common.MakeSystemPatch(src_file, tgt_file)
630 system_patch.AddToZip(output_zip, compression=zipfile.ZIP_STORED)
631
632 AppendAssertions(script, OPTIONS.target_info_dict)
633 device_specific.IncrementalOTA_Assertions()
634
635 # Two-step incremental package strategy (in chronological order,
636 # which is *not* the order in which the generated script has
637 # things):
638 #
639 # if stage is not "2/3" or "3/3":
640 # do verification on current system
641 # write recovery image to boot partition
642 # set stage to "2/3"
643 # reboot to boot partition and restart recovery
644 # else if stage is "2/3":
645 # write recovery image to recovery partition
646 # set stage to "3/3"
647 # reboot to recovery partition and restart recovery
648 # else:
649 # (stage must be "3/3")
650 # perform update:
651 # patch system files, etc.
652 # force full install of new boot image
653 # set up system to update recovery partition on first boot
654 # complete script normally (allow recovery to mark itself finished and reboot)
655
656 if OPTIONS.two_step:
657 if not OPTIONS.info_dict.get("multistage_support", None):
658 assert False, "two-step packages not supported by this build"
659 fs = OPTIONS.info_dict["fstab"]["/misc"]
660 assert fs.fs_type.upper() == "EMMC", \
661 "two-step packages only supported on devices with EMMC /misc partitions"
662 bcb_dev = {"bcb_dev": fs.device}
663 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
664 script.AppendExtra("""
665if get_stage("%(bcb_dev)s", "stage") == "2/3" then
666""" % bcb_dev)
667 script.AppendExtra("sleep(20);\n");
668 script.WriteRawImage("/recovery", "recovery.img")
669 script.AppendExtra("""
670set_stage("%(bcb_dev)s", "3/3");
671reboot_now("%(bcb_dev)s", "recovery");
672else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
673""" % bcb_dev)
674
675 script.Print("Verifying current system...")
676
677 device_specific.IncrementalOTA_VerifyBegin()
678
679 script.AssertRecoveryFingerprint(source_fp, target_fp)
680
681 if updating_boot:
Geremy Condra36bd3652014-02-06 19:45:10 -0800682 d = common.Difference(target_boot, source_boot)
683 _, _, d = d.ComputePatch()
684 print "boot target: %d source: %d diff: %d" % (
685 target_boot.size, source_boot.size, len(d))
686
687 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
688
689 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
690
691 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
692 (boot_type, boot_device,
693 source_boot.size, source_boot.sha1,
694 target_boot.size, target_boot.sha1))
695
696 device_specific.IncrementalOTA_VerifyEnd()
697
698 if OPTIONS.two_step:
699 script.WriteRawImage("/boot", "recovery.img")
700 script.AppendExtra("""
701set_stage("%(bcb_dev)s", "2/3");
702reboot_now("%(bcb_dev)s", "");
703else
704""" % bcb_dev)
705
706 script.Comment("---- start making changes here ----")
707
708 device_specific.IncrementalOTA_InstallBegin()
709
710 if OPTIONS.wipe_user_data:
711 script.Print("Erasing user data...")
712 script.FormatPartition("/data")
713
714 script.Print("Patching system image...")
715 script.Syspatch(system_device,
716 OPTIONS.info_dict["system_size"],
717 tgt_sys_sha1,
718 src_sys_sha1,
719 system_patch.name)
720
721 if OPTIONS.two_step:
722 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
723 script.WriteRawImage("/boot", "boot.img")
724 print "writing full boot image (forced by two-step mode)"
725
726 if not OPTIONS.two_step:
727 if updating_boot:
728 # Produce the boot image by applying a patch to the current
729 # contents of the boot partition, and write it back to the
730 # partition.
731 script.Print("Patching boot image...")
732 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
733 % (boot_type, boot_device,
734 source_boot.size, source_boot.sha1,
735 target_boot.size, target_boot.sha1),
736 "-",
737 target_boot.size, target_boot.sha1,
738 source_boot.sha1, "patch/boot.img.p")
739 print "boot image changed; including."
740 else:
741 print "boot image unchanged; skipping."
742
743 # Do device-specific installation (eg, write radio image).
744 device_specific.IncrementalOTA_InstallEnd()
745
746 if OPTIONS.extra_script is not None:
747 script.AppendExtra(OPTIONS.extra_script)
748
749 if OPTIONS.two_step:
750 script.AppendExtra("""
751set_stage("%(bcb_dev)s", "");
752endif;
753endif;
754""" % bcb_dev)
755
756 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800757 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800758 WriteMetadata(metadata, output_zip)
759
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700760def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -0800761 target_has_recovery_patch = HasRecoveryPatch(target_zip)
762 source_has_recovery_patch = HasRecoveryPatch(source_zip)
763
Doug Zongker26e66192014-02-20 13:22:07 -0800764 if (OPTIONS.block_based and
765 target_has_recovery_patch and
766 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -0800767 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
768
Doug Zongker37974732010-09-16 17:44:38 -0700769 source_version = OPTIONS.source_info_dict["recovery_api_version"]
770 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700771
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700772 if source_version == 0:
773 print ("WARNING: generating edify script for a source that "
774 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700775 script = edify_generator.EdifyGenerator(source_version,
776 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700777
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700778 metadata = {"pre-device": GetBuildProp("ro.product.device",
779 OPTIONS.source_info_dict),
780 "post-timestamp": GetBuildProp("ro.build.date.utc",
781 OPTIONS.target_info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700782 }
783
Doug Zongker05d3dea2009-06-22 11:32:31 -0700784 device_specific = common.DeviceSpecificParams(
785 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800786 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700787 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800788 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700789 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -0700790 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -0700791 metadata=metadata,
792 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700793
Doug Zongkereef39442009-04-02 12:14:19 -0700794 print "Loading target..."
Doug Zongker1807e702012-02-28 12:21:08 -0800795 target_data = LoadSystemFiles(target_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700796 print "Loading source..."
Doug Zongker1807e702012-02-28 12:21:08 -0800797 source_data = LoadSystemFiles(source_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700798
799 verbatim_targets = []
800 patch_list = []
Doug Zongker761e6422009-09-25 10:45:39 -0700801 diffs = []
Michael Runge4038aa82013-12-13 18:06:28 -0800802 renames = {}
803 known_paths = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700804 largest_source_size = 0
Michael Runge4038aa82013-12-13 18:06:28 -0800805
806 matching_file_cache = {}
807 for fn, sf in source_data.items():
808 assert fn == sf.name
809 matching_file_cache["path:" + fn] = sf
810 if fn in target_data.keys():
811 AddToKnownPaths(fn, known_paths)
812 # Only allow eligibility for filename/sha matching
813 # if there isn't a perfect path match.
814 if target_data.get(sf.name) is None:
815 matching_file_cache["file:" + fn.split("/")[-1]] = sf
816 matching_file_cache["sha:" + sf.sha1] = sf
817
Doug Zongkereef39442009-04-02 12:14:19 -0700818 for fn in sorted(target_data.keys()):
819 tf = target_data[fn]
Doug Zongker761e6422009-09-25 10:45:39 -0700820 assert fn == tf.name
Michael Runge4038aa82013-12-13 18:06:28 -0800821 sf = ClosestFileMatch(tf, matching_file_cache, renames)
822 if sf is not None and sf.name != tf.name:
823 print "File has moved from " + sf.name + " to " + tf.name
824 renames[sf.name] = tf
Doug Zongkereef39442009-04-02 12:14:19 -0700825
826 if sf is None or fn in OPTIONS.require_verbatim:
827 # This file should be included verbatim
828 if fn in OPTIONS.prohibit_verbatim:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700829 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
Doug Zongkereef39442009-04-02 12:14:19 -0700830 print "send", fn, "verbatim"
831 tf.AddToZip(output_zip)
832 verbatim_targets.append((fn, tf.size))
Michael Runge4038aa82013-12-13 18:06:28 -0800833 if fn in target_data.keys():
834 AddToKnownPaths(fn, known_paths)
Doug Zongkereef39442009-04-02 12:14:19 -0700835 elif tf.sha1 != sf.sha1:
836 # File is different; consider sending as a patch
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700837 diffs.append(common.Difference(tf, sf))
Doug Zongkereef39442009-04-02 12:14:19 -0700838 else:
Michael Runge4038aa82013-12-13 18:06:28 -0800839 # Target file data identical to source (may still be renamed)
Doug Zongkereef39442009-04-02 12:14:19 -0700840 pass
841
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700842 common.ComputeDifferences(diffs)
Doug Zongker761e6422009-09-25 10:45:39 -0700843
844 for diff in diffs:
845 tf, sf, d = diff.GetPatch()
Michael Runge4038aa82013-12-13 18:06:28 -0800846 path = "/".join(tf.name.split("/")[:-1])
847 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
848 path not in known_paths:
Doug Zongker761e6422009-09-25 10:45:39 -0700849 # patch is almost as big as the file; don't bother patching
Michael Runge4038aa82013-12-13 18:06:28 -0800850 # or a patch + rename cannot take place due to the target
851 # directory not existing
Doug Zongker761e6422009-09-25 10:45:39 -0700852 tf.AddToZip(output_zip)
853 verbatim_targets.append((tf.name, tf.size))
Michael Runge4038aa82013-12-13 18:06:28 -0800854 if sf.name in renames:
855 del renames[sf.name]
856 AddToKnownPaths(tf.name, known_paths)
Doug Zongker761e6422009-09-25 10:45:39 -0700857 else:
Michael Runge4038aa82013-12-13 18:06:28 -0800858 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
859 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
Doug Zongker761e6422009-09-25 10:45:39 -0700860 largest_source_size = max(largest_source_size, sf.size)
Doug Zongkereef39442009-04-02 12:14:19 -0700861
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700862 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
863 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
Doug Zongker2ea21062010-04-28 16:05:21 -0700864 metadata["pre-build"] = source_fp
865 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -0700866
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700867 script.Mount("/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700868 script.AssertSomeFingerprint(source_fp, target_fp)
Doug Zongkereef39442009-04-02 12:14:19 -0700869
Doug Zongker55d93282011-01-25 17:03:34 -0800870 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700871 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
872 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -0800873 target_boot = common.GetBootableImage(
874 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800875 updating_boot = (not OPTIONS.two_step and
876 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -0700877
Doug Zongker55d93282011-01-25 17:03:34 -0800878 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700879 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
880 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -0800881 target_recovery = common.GetBootableImage(
882 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -0700883 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700884
Doug Zongker881dd402009-09-20 14:03:55 -0700885 # Here's how we divide up the progress bar:
886 # 0.1 for verifying the start state (PatchCheck calls)
887 # 0.8 for applying patches (ApplyPatch calls)
888 # 0.1 for unpacking verbatim files, symlinking, and doing the
889 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -0700890
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700891 AppendAssertions(script, OPTIONS.target_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700892 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -0700893
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800894 # Two-step incremental package strategy (in chronological order,
895 # which is *not* the order in which the generated script has
896 # things):
897 #
898 # if stage is not "2/3" or "3/3":
899 # do verification on current system
900 # write recovery image to boot partition
901 # set stage to "2/3"
902 # reboot to boot partition and restart recovery
903 # else if stage is "2/3":
904 # write recovery image to recovery partition
905 # set stage to "3/3"
906 # reboot to recovery partition and restart recovery
907 # else:
908 # (stage must be "3/3")
909 # perform update:
910 # patch system files, etc.
911 # force full install of new boot image
912 # set up system to update recovery partition on first boot
913 # complete script normally (allow recovery to mark itself finished and reboot)
914
915 if OPTIONS.two_step:
916 if not OPTIONS.info_dict.get("multistage_support", None):
917 assert False, "two-step packages not supported by this build"
918 fs = OPTIONS.info_dict["fstab"]["/misc"]
919 assert fs.fs_type.upper() == "EMMC", \
920 "two-step packages only supported on devices with EMMC /misc partitions"
921 bcb_dev = {"bcb_dev": fs.device}
922 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
923 script.AppendExtra("""
924if get_stage("%(bcb_dev)s", "stage") == "2/3" then
925""" % bcb_dev)
926 script.AppendExtra("sleep(20);\n");
927 script.WriteRawImage("/recovery", "recovery.img")
928 script.AppendExtra("""
929set_stage("%(bcb_dev)s", "3/3");
930reboot_now("%(bcb_dev)s", "recovery");
931else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
932""" % bcb_dev)
933
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700934 script.Print("Verifying current system...")
935
Doug Zongkere5ff5902012-01-17 10:55:37 -0800936 device_specific.IncrementalOTA_VerifyBegin()
937
Doug Zongker881dd402009-09-20 14:03:55 -0700938 script.ShowProgress(0.1, 0)
Doug Zongker881dd402009-09-20 14:03:55 -0700939 so_far = 0
Doug Zongkereef39442009-04-02 12:14:19 -0700940
Michael Runge4038aa82013-12-13 18:06:28 -0800941 for tf, sf, size, patch_sha in patch_list:
942 if tf.name != sf.name:
943 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
944 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
Doug Zongker881dd402009-09-20 14:03:55 -0700945 so_far += sf.size
Doug Zongkereef39442009-04-02 12:14:19 -0700946
Doug Zongker5da317e2009-06-02 13:38:17 -0700947 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700948 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -0700949 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -0700950 print "boot target: %d source: %d diff: %d" % (
951 target_boot.size, source_boot.size, len(d))
952
Doug Zongker048e7ca2009-06-15 14:31:53 -0700953 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -0700954
Doug Zongker96a57e72010-09-26 14:57:41 -0700955 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -0700956
957 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
958 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -0700959 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700960 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -0700961 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -0700962
963 if patch_list or updating_recovery or updating_boot:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700964 script.CacheFreeSpaceCheck(largest_source_size)
Doug Zongker5a482092010-02-17 16:09:18 -0800965
Doug Zongker05d3dea2009-06-22 11:32:31 -0700966 device_specific.IncrementalOTA_VerifyEnd()
967
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800968 if OPTIONS.two_step:
969 script.WriteRawImage("/boot", "recovery.img")
970 script.AppendExtra("""
971set_stage("%(bcb_dev)s", "2/3");
972reboot_now("%(bcb_dev)s", "");
973else
974""" % bcb_dev)
975
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700976 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -0700977
Doug Zongkere5ff5902012-01-17 10:55:37 -0800978 device_specific.IncrementalOTA_InstallBegin()
979
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800980 if OPTIONS.two_step:
981 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
982 script.WriteRawImage("/boot", "boot.img")
983 print "writing full boot image (forced by two-step mode)"
984
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700985 if OPTIONS.wipe_user_data:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700986 script.Print("Erasing user data...")
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700987 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700988
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700989 script.Print("Removing unneeded files...")
Doug Zongker0f3298a2009-06-30 08:16:58 -0700990 script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
991 ["/"+i for i in sorted(source_data)
Michael Runge4038aa82013-12-13 18:06:28 -0800992 if i not in target_data and
993 i not in renames] +
Doug Zongker3b949f02009-08-24 10:24:32 -0700994 ["/system/recovery.img"])
Doug Zongkereef39442009-04-02 12:14:19 -0700995
Doug Zongker881dd402009-09-20 14:03:55 -0700996 script.ShowProgress(0.8, 0)
997 total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
998 if updating_boot:
999 total_patch_size += target_boot.size
1000 so_far = 0
1001
1002 script.Print("Patching system files...")
Doug Zongkere92f15a2011-08-26 13:46:40 -07001003 deferred_patch_list = []
1004 for item in patch_list:
Michael Runge4038aa82013-12-13 18:06:28 -08001005 tf, sf, size, _ = item
Doug Zongkere92f15a2011-08-26 13:46:40 -07001006 if tf.name == "system/build.prop":
1007 deferred_patch_list.append(item)
1008 continue
Michael Runge4038aa82013-12-13 18:06:28 -08001009 if (sf.name != tf.name):
1010 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1011 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
Doug Zongker881dd402009-09-20 14:03:55 -07001012 so_far += tf.size
1013 script.SetProgress(so_far / total_patch_size)
1014
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001015 if not OPTIONS.two_step:
1016 if updating_boot:
1017 # Produce the boot image by applying a patch to the current
1018 # contents of the boot partition, and write it back to the
1019 # partition.
1020 script.Print("Patching boot image...")
1021 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1022 % (boot_type, boot_device,
1023 source_boot.size, source_boot.sha1,
1024 target_boot.size, target_boot.sha1),
1025 "-",
1026 target_boot.size, target_boot.sha1,
1027 source_boot.sha1, "patch/boot.img.p")
1028 so_far += target_boot.size
1029 script.SetProgress(so_far / total_patch_size)
1030 print "boot image changed; including."
1031 else:
1032 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001033
1034 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001035 # Recovery is generated as a patch using both the boot image
1036 # (which contains the same linux kernel as recovery) and the file
1037 # /system/etc/recovery-resource.dat (which contains all the images
1038 # used in the recovery UI) as sources. This lets us minimize the
1039 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001040 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001041 # For older builds where recovery-resource.dat is not present, we
1042 # use only the boot image as the source.
1043
Doug Zongkerc9253822014-02-04 12:17:58 -08001044 if not target_has_recovery_patch:
1045 def output_sink(fn, data):
1046 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
1047 Item.Get("system/" + fn, dir=False)
1048
1049 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1050 target_recovery, target_boot)
1051 script.DeleteFiles(["/system/recovery-from-boot.p",
1052 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001053 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001054 else:
1055 print "recovery image unchanged; skipping."
1056
Doug Zongker881dd402009-09-20 14:03:55 -07001057 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001058
Doug Zongker1807e702012-02-28 12:21:08 -08001059 target_symlinks = CopySystemFiles(target_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -07001060
1061 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001062 temp_script = script.MakeTemporary()
Doug Zongker283e2a12010-03-15 17:52:32 -07001063 Item.GetMetadata(target_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -07001064 Item.Get("system").SetPermissions(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001065
1066 # Note that this call will mess up the tree of Items, so make sure
1067 # we're done with it.
Doug Zongker1807e702012-02-28 12:21:08 -08001068 source_symlinks = CopySystemFiles(source_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -07001069 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1070
1071 # Delete all the symlinks in source that aren't in target. This
1072 # needs to happen before verbatim files are unpacked, in case a
1073 # symlink in the source is replaced by a real file in the target.
1074 to_delete = []
1075 for dest, link in source_symlinks:
1076 if link not in target_symlinks_d:
1077 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001078 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001079
1080 if verbatim_targets:
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001081 script.Print("Unpacking new files...")
1082 script.UnpackPackageDir("system", "/system")
1083
Doug Zongkerc9253822014-02-04 12:17:58 -08001084 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001085 script.Print("Unpacking new recovery...")
1086 script.UnpackPackageDir("recovery", "/system")
1087
Michael Runge4038aa82013-12-13 18:06:28 -08001088 if len(renames) > 0:
1089 script.Print("Renaming files...")
1090
1091 for src in renames:
1092 print "Renaming " + src + " to " + renames[src].name
1093 script.RenameFile(src, renames[src].name)
1094
Doug Zongker05d3dea2009-06-22 11:32:31 -07001095 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001096
1097 # Create all the symlinks that don't already exist, or point to
1098 # somewhere different than what we want. Delete each symlink before
1099 # creating it, since the 'symlink' command won't overwrite.
1100 to_create = []
1101 for dest, link in target_symlinks:
1102 if link in source_symlinks_d:
1103 if dest != source_symlinks_d[link]:
1104 to_create.append((dest, link))
1105 else:
1106 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001107 script.DeleteFiles([i[1] for i in to_create])
1108 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001109
1110 # Now that the symlinks are created, we can set all the
1111 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001112 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001113
Doug Zongker881dd402009-09-20 14:03:55 -07001114 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001115 device_specific.IncrementalOTA_InstallEnd()
1116
Doug Zongker1c390a22009-05-14 19:06:36 -07001117 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001118 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001119
Doug Zongkere92f15a2011-08-26 13:46:40 -07001120 # Patch the build.prop file last, so if something fails but the
1121 # device can still come up, it appears to be the old build and will
1122 # get set the OTA package again to retry.
1123 script.Print("Patching remaining system files...")
1124 for item in deferred_patch_list:
Michael Runge4038aa82013-12-13 18:06:28 -08001125 tf, sf, size, _ = item
1126 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
Nick Kralevich0eb17d92013-09-07 17:10:29 -07001127 script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001128
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001129 if OPTIONS.two_step:
1130 script.AppendExtra("""
1131set_stage("%(bcb_dev)s", "");
1132endif;
1133endif;
1134""" % bcb_dev)
1135
Doug Zongker25568482014-03-03 10:21:27 -08001136 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -07001137 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001138
1139
1140def main(argv):
1141
1142 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001143 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001144 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001145 elif o in ("-k", "--package_key"):
1146 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001147 elif o in ("-i", "--incremental_from"):
1148 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001149 elif o in ("-w", "--wipe_user_data"):
1150 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001151 elif o in ("-n", "--no_prereq"):
1152 OPTIONS.omit_prereq = True
Doug Zongker1c390a22009-05-14 19:06:36 -07001153 elif o in ("-e", "--extra_script"):
1154 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001155 elif o in ("-a", "--aslr_mode"):
1156 if a in ("on", "On", "true", "True", "yes", "Yes"):
1157 OPTIONS.aslr_mode = True
1158 else:
1159 OPTIONS.aslr_mode = False
Doug Zongker761e6422009-09-25 10:45:39 -07001160 elif o in ("--worker_threads"):
1161 OPTIONS.worker_threads = int(a)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001162 elif o in ("-2", "--two_step"):
1163 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001164 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001165 OPTIONS.no_signing = True
Doug Zongker26e66192014-02-20 13:22:07 -08001166 elif o == "--block":
1167 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001168 elif o in ("-b", "--binary"):
1169 OPTIONS.updater_binary = a
Doug Zongkereef39442009-04-02 12:14:19 -07001170 else:
1171 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001172 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001173
1174 args = common.ParseOptions(argv, __doc__,
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001175 extra_opts="b:k:i:d:wne:a:2",
Doug Zongkereef39442009-04-02 12:14:19 -07001176 extra_long_opts=["board_config=",
1177 "package_key=",
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001178 "incremental_from=",
Doug Zongker962069c2009-04-23 11:41:58 -07001179 "wipe_user_data",
Doug Zongker1c390a22009-05-14 19:06:36 -07001180 "no_prereq",
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001181 "extra_script=",
Hristo Bojinov96be7202010-08-02 10:26:17 -07001182 "worker_threads=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001183 "aslr_mode=",
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001184 "two_step",
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001185 "no_signing",
Doug Zongker26e66192014-02-20 13:22:07 -08001186 "block",
Doug Zongker25568482014-03-03 10:21:27 -08001187 "binary=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001188 ],
Doug Zongkereef39442009-04-02 12:14:19 -07001189 extra_option_handler=option_handler)
1190
1191 if len(args) != 2:
1192 common.Usage(__doc__)
1193 sys.exit(1)
1194
Doug Zongker1c390a22009-05-14 19:06:36 -07001195 if OPTIONS.extra_script is not None:
1196 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1197
Doug Zongkereef39442009-04-02 12:14:19 -07001198 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001199 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001200
Doug Zongkereef39442009-04-02 12:14:19 -07001201 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001202 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001203
1204 # If this image was originally labelled with SELinux contexts, make sure we
1205 # also apply the labels in our new image. During building, the "file_contexts"
1206 # is in the out/ directory tree, but for repacking from target-files.zip it's
1207 # in the root directory of the ramdisk.
1208 if "selinux_fc" in OPTIONS.info_dict:
1209 OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK",
1210 "file_contexts")
1211
Doug Zongker37974732010-09-16 17:44:38 -07001212 if OPTIONS.verbose:
1213 print "--- target info ---"
1214 common.DumpInfoDict(OPTIONS.info_dict)
1215
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001216 # If the caller explicitly specified the device-specific extensions
1217 # path via -s/--device_specific, use that. Otherwise, use
1218 # META/releasetools.py if it is present in the target target_files.
1219 # Otherwise, take the path of the file from 'tool_extensions' in the
1220 # info dict and look for that in the local filesystem, relative to
1221 # the current directory.
1222
Doug Zongker37974732010-09-16 17:44:38 -07001223 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001224 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1225 if os.path.exists(from_input):
1226 print "(using device-specific extensions from target_files)"
1227 OPTIONS.device_specific = from_input
1228 else:
1229 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1230
Doug Zongker37974732010-09-16 17:44:38 -07001231 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001232 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001233
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001234 if OPTIONS.no_signing:
1235 output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
1236 else:
1237 temp_zip_file = tempfile.NamedTemporaryFile()
1238 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1239 compression=zipfile.ZIP_DEFLATED)
Doug Zongkereef39442009-04-02 12:14:19 -07001240
1241 if OPTIONS.incremental_source is None:
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001242 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001243 if OPTIONS.package_key is None:
1244 OPTIONS.package_key = OPTIONS.info_dict.get(
1245 "default_system_dev_certificate",
1246 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -07001247 else:
1248 print "unzipping source target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001249 OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
Doug Zongker37974732010-09-16 17:44:38 -07001250 OPTIONS.target_info_dict = OPTIONS.info_dict
1251 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001252 if OPTIONS.package_key is None:
Doug Zongker91b4f8a2011-09-23 12:48:33 -07001253 OPTIONS.package_key = OPTIONS.source_info_dict.get(
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001254 "default_system_dev_certificate",
1255 "build/target/product/security/testkey")
Doug Zongker37974732010-09-16 17:44:38 -07001256 if OPTIONS.verbose:
1257 print "--- source info ---"
1258 common.DumpInfoDict(OPTIONS.source_info_dict)
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001259 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001260
1261 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001262
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001263 if not OPTIONS.no_signing:
1264 SignOutput(temp_zip_file.name, args[1])
1265 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001266
1267 common.Cleanup()
1268
1269 print "done."
1270
1271
1272if __name__ == '__main__':
1273 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001274 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001275 main(sys.argv[1:])
1276 except common.ExternalError, e:
1277 print
1278 print " ERROR: %s" % (e,)
1279 print
1280 sys.exit(1)