blob: f838c220e5885d15512cbfb0a69fcc5e37324aed [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
24 -b (--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
55 -S (--file_context) <file>
56 the file contexts configuration used to assign SELinux file
57 context attributes
58
Doug Zongkereef39442009-04-02 12:14:19 -070059"""
60
61import sys
62
63if sys.hexversion < 0x02040000:
64 print >> sys.stderr, "Python 2.4 or newer is required."
65 sys.exit(1)
66
67import copy
Doug Zongkerc18736b2009-09-30 09:20:32 -070068import errno
Doug Zongkereef39442009-04-02 12:14:19 -070069import os
70import re
Doug Zongkereef39442009-04-02 12:14:19 -070071import subprocess
72import tempfile
73import time
74import zipfile
75
davidcad0bb92011-03-15 14:21:38 +000076try:
77 from hashlib import sha1 as sha1
78except ImportError:
79 from sha import sha as sha1
80
Doug Zongkereef39442009-04-02 12:14:19 -070081import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -070082import edify_generator
Doug Zongkereef39442009-04-02 12:14:19 -070083
84OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -070085OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -070086OPTIONS.incremental_source = None
87OPTIONS.require_verbatim = set()
88OPTIONS.prohibit_verbatim = set(("system/build.prop",))
89OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -070090OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -070091OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -070092OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -070093OPTIONS.aslr_mode = True
Doug Zongker761e6422009-09-25 10:45:39 -070094OPTIONS.worker_threads = 3
Stephen Smalley56882bf2012-02-09 13:36:21 -050095OPTIONS.selinux_fc = None
Doug Zongkereef39442009-04-02 12:14:19 -070096
97def MostPopularKey(d, default):
98 """Given a dict, return the key corresponding to the largest
99 value. Returns 'default' if the dict is empty."""
100 x = [(v, k) for (k, v) in d.iteritems()]
101 if not x: return default
102 x.sort()
103 return x[-1][1]
104
105
106def IsSymlink(info):
107 """Return true if the zipfile.ZipInfo object passed in represents a
108 symlink."""
109 return (info.external_attr >> 16) == 0120777
110
Hristo Bojinov96be7202010-08-02 10:26:17 -0700111def IsRegular(info):
112 """Return true if the zipfile.ZipInfo object passed in represents a
113 symlink."""
114 return (info.external_attr >> 28) == 010
Doug Zongkereef39442009-04-02 12:14:19 -0700115
Doug Zongkereef39442009-04-02 12:14:19 -0700116class Item:
117 """Items represent the metadata (user, group, mode) of files and
118 directories in the system image."""
119 ITEMS = {}
120 def __init__(self, name, dir=False):
121 self.name = name
122 self.uid = None
123 self.gid = None
124 self.mode = None
125 self.dir = dir
126
127 if name:
128 self.parent = Item.Get(os.path.dirname(name), dir=True)
129 self.parent.children.append(self)
130 else:
131 self.parent = None
132 if dir:
133 self.children = []
134
135 def Dump(self, indent=0):
136 if self.uid is not None:
137 print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode)
138 else:
139 print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode)
140 if self.dir:
141 print "%s%s" % (" "*indent, self.descendants)
142 print "%s%s" % (" "*indent, self.best_subtree)
143 for i in self.children:
144 i.Dump(indent=indent+1)
145
146 @classmethod
147 def Get(cls, name, dir=False):
148 if name not in cls.ITEMS:
149 cls.ITEMS[name] = Item(name, dir=dir)
150 return cls.ITEMS[name]
151
152 @classmethod
Doug Zongker283e2a12010-03-15 17:52:32 -0700153 def GetMetadata(cls, input_zip):
154
155 try:
156 # See if the target_files contains a record of what the uid,
157 # gid, and mode is supposed to be.
158 output = input_zip.read("META/filesystem_config.txt")
159 except KeyError:
160 # Run the external 'fs_config' program to determine the desired
161 # uid, gid, and mode for every Item object. Note this uses the
162 # one in the client now, which might not be the same as the one
163 # used when this target_files was built.
164 p = common.Run(["fs_config"], stdin=subprocess.PIPE,
165 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
166 suffix = { False: "", True: "/" }
167 input = "".join(["%s%s\n" % (i.name, suffix[i.dir])
168 for i in cls.ITEMS.itervalues() if i.name])
Doug Zongker3475d362010-03-17 16:39:30 -0700169 output, error = p.communicate(input)
Doug Zongker283e2a12010-03-15 17:52:32 -0700170 assert not error
Doug Zongkereef39442009-04-02 12:14:19 -0700171
172 for line in output.split("\n"):
173 if not line: continue
174 name, uid, gid, mode = line.split()
Doug Zongker283e2a12010-03-15 17:52:32 -0700175 i = cls.ITEMS.get(name, None)
176 if i is not None:
177 i.uid = int(uid)
178 i.gid = int(gid)
179 i.mode = int(mode, 8)
180 if i.dir:
181 i.children.sort(key=lambda i: i.name)
182
183 # set metadata for the files generated by this script.
184 i = cls.ITEMS.get("system/recovery-from-boot.p", None)
185 if i: i.uid, i.gid, i.mode = 0, 0, 0644
186 i = cls.ITEMS.get("system/etc/install-recovery.sh", None)
187 if i: i.uid, i.gid, i.mode = 0, 0, 0544
Doug Zongkereef39442009-04-02 12:14:19 -0700188
189 def CountChildMetadata(self):
190 """Count up the (uid, gid, mode) tuples for all children and
191 determine the best strategy for using set_perm_recursive and
192 set_perm to correctly chown/chmod all the files to their desired
193 values. Recursively calls itself for all descendants.
194
195 Returns a dict of {(uid, gid, dmode, fmode): count} counting up
196 all descendants of this node. (dmode or fmode may be None.) Also
197 sets the best_subtree of each directory Item to the (uid, gid,
198 dmode, fmode) tuple that will match the most descendants of that
199 Item.
200 """
201
202 assert self.dir
203 d = self.descendants = {(self.uid, self.gid, self.mode, None): 1}
204 for i in self.children:
205 if i.dir:
206 for k, v in i.CountChildMetadata().iteritems():
207 d[k] = d.get(k, 0) + v
208 else:
209 k = (i.uid, i.gid, None, i.mode)
210 d[k] = d.get(k, 0) + 1
211
212 # Find the (uid, gid, dmode, fmode) tuple that matches the most
213 # descendants.
214
215 # First, find the (uid, gid) pair that matches the most
216 # descendants.
217 ug = {}
218 for (uid, gid, _, _), count in d.iteritems():
219 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
220 ug = MostPopularKey(ug, (0, 0))
221
222 # Now find the dmode and fmode that match the most descendants
223 # with that (uid, gid), and choose those.
224 best_dmode = (0, 0755)
225 best_fmode = (0, 0644)
226 for k, count in d.iteritems():
227 if k[:2] != ug: continue
228 if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2])
229 if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3])
230 self.best_subtree = ug + (best_dmode[1], best_fmode[1])
231
232 return d
233
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700234 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700235 """Append set_perm/set_perm_recursive commands to 'script' to
236 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700237 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700238
239 self.CountChildMetadata()
240
241 def recurse(item, current):
242 # current is the (uid, gid, dmode, fmode) tuple that the current
243 # item (and all its children) have already been set to. We only
244 # need to issue set_perm/set_perm_recursive commands if we're
245 # supposed to be something different.
246 if item.dir:
247 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700248 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700249 current = item.best_subtree
250
251 if item.uid != current[0] or item.gid != current[1] or \
252 item.mode != current[2]:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700253 script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode)
Doug Zongkereef39442009-04-02 12:14:19 -0700254
255 for i in item.children:
256 recurse(i, current)
257 else:
258 if item.uid != current[0] or item.gid != current[1] or \
259 item.mode != current[3]:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700260 script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode)
Doug Zongkereef39442009-04-02 12:14:19 -0700261
262 recurse(self, (-1, -1, -1, -1))
263
264
265def CopySystemFiles(input_zip, output_zip=None,
266 substitute=None):
267 """Copies files underneath system/ in the input zip to the output
268 zip. Populates the Item class with their metadata, and returns a
Hristo Bojinov96be7202010-08-02 10:26:17 -0700269 list of symlinks as well as a list of files that will be retouched.
270 output_zip may be None, in which case the copy is skipped (but the
271 other side effects still happen). substitute is an optional dict
272 of {output filename: contents} to be output instead of certain input
273 files.
Doug Zongkereef39442009-04-02 12:14:19 -0700274 """
275
276 symlinks = []
Hristo Bojinov96be7202010-08-02 10:26:17 -0700277 retouch_files = []
Doug Zongkereef39442009-04-02 12:14:19 -0700278
279 for info in input_zip.infolist():
280 if info.filename.startswith("SYSTEM/"):
281 basefilename = info.filename[7:]
282 if IsSymlink(info):
283 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700284 "/system/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700285 else:
286 info2 = copy.copy(info)
287 fn = info2.filename = "system/" + basefilename
288 if substitute and fn in substitute and substitute[fn] is None:
289 continue
290 if output_zip is not None:
291 if substitute and fn in substitute:
292 data = substitute[fn]
293 else:
294 data = input_zip.read(info.filename)
Hristo Bojinov96be7202010-08-02 10:26:17 -0700295 if info.filename.startswith("SYSTEM/lib/") and IsRegular(info):
296 retouch_files.append(("/system/" + basefilename,
Doug Zongker55d93282011-01-25 17:03:34 -0800297 common.sha1(data).hexdigest()))
Doug Zongkereef39442009-04-02 12:14:19 -0700298 output_zip.writestr(info2, data)
299 if fn.endswith("/"):
300 Item.Get(fn[:-1], dir=True)
301 else:
302 Item.Get(fn, dir=False)
303
304 symlinks.sort()
Hristo Bojinov96be7202010-08-02 10:26:17 -0700305 return (symlinks, retouch_files)
Doug Zongkereef39442009-04-02 12:14:19 -0700306
307
Doug Zongkereef39442009-04-02 12:14:19 -0700308def SignOutput(temp_zip_name, output_zip_name):
309 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
310 pw = key_passwords[OPTIONS.package_key]
311
Doug Zongker951495f2009-08-14 12:44:19 -0700312 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
313 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700314
315
Doug Zongkereef39442009-04-02 12:14:19 -0700316def AppendAssertions(script, input_zip):
Doug Zongkereef39442009-04-02 12:14:19 -0700317 device = GetBuildProp("ro.product.device", input_zip)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700318 script.AssertDevice(device)
Doug Zongkereef39442009-04-02 12:14:19 -0700319
Doug Zongkereef39442009-04-02 12:14:19 -0700320
Doug Zongker486de122010-09-16 14:01:56 -0700321def MakeRecoveryPatch(output_zip, recovery_img, boot_img):
Doug Zongker73ef8252009-07-23 15:12:53 -0700322 """Generate a binary patch that creates the recovery image starting
323 with the boot image. (Most of the space in these images is just the
324 kernel, which is identical for the two, so the resulting patch
325 should be efficient.) Add it to the output zip, along with a shell
326 script that is run from init.rc on first boot to actually do the
327 patching and install the new recovery image.
328
329 recovery_img and boot_img should be File objects for the
Doug Zongker67369982010-07-07 13:53:32 -0700330 corresponding images. info should be the dictionary returned by
331 common.LoadInfoDict() on the input target_files.
Doug Zongker73ef8252009-07-23 15:12:53 -0700332
333 Returns an Item for the shell script, which must be made
334 executable.
335 """
336
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700337 d = common.Difference(recovery_img, boot_img)
Doug Zongker761e6422009-09-25 10:45:39 -0700338 _, _, patch = d.ComputePatch()
Doug Zongkercfd7db62009-10-07 11:35:53 -0700339 common.ZipWriteStr(output_zip, "recovery/recovery-from-boot.p", patch)
Doug Zongker73ef8252009-07-23 15:12:53 -0700340 Item.Get("system/recovery-from-boot.p", dir=False)
341
Doug Zongker96a57e72010-09-26 14:57:41 -0700342 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
343 recovery_type, recovery_device = common.GetTypeAndDevice("/recovery", OPTIONS.info_dict)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700344
Doug Zongker73ef8252009-07-23 15:12:53 -0700345 sh = """#!/system/bin/sh
Doug Zongkerbd2dadc2011-12-02 10:46:59 -0800346if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then
Doug Zongker73ef8252009-07-23 15:12:53 -0700347 log -t recovery "Installing new recovery image"
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700348 applypatch %(boot_type)s:%(boot_device)s:%(boot_size)d:%(boot_sha1)s %(recovery_type)s:%(recovery_device)s %(recovery_sha1)s %(recovery_size)d %(boot_sha1)s:/system/recovery-from-boot.p
Doug Zongker73ef8252009-07-23 15:12:53 -0700349else
350 log -t recovery "Recovery image already installed"
351fi
352""" % { 'boot_size': boot_img.size,
353 'boot_sha1': boot_img.sha1,
Doug Zongker73ef8252009-07-23 15:12:53 -0700354 'recovery_size': recovery_img.size,
Doug Zongker67369982010-07-07 13:53:32 -0700355 'recovery_sha1': recovery_img.sha1,
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700356 'boot_type': boot_type,
357 'boot_device': boot_device,
358 'recovery_type': recovery_type,
359 'recovery_device': recovery_device,
Doug Zongker67369982010-07-07 13:53:32 -0700360 }
Doug Zongkercfd7db62009-10-07 11:35:53 -0700361 common.ZipWriteStr(output_zip, "recovery/etc/install-recovery.sh", sh)
Doug Zongker73ef8252009-07-23 15:12:53 -0700362 return Item.Get("system/etc/install-recovery.sh", dir=False)
363
364
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700365def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700366 # TODO: how to determine this? We don't know what version it will
367 # be installed on top of. For now, we expect the API just won't
368 # change very often.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700369 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700370
Doug Zongker2ea21062010-04-28 16:05:21 -0700371 metadata = {"post-build": GetBuildProp("ro.build.fingerprint", input_zip),
372 "pre-device": GetBuildProp("ro.product.device", input_zip),
Doug Zongker3b852692010-06-21 15:30:45 -0700373 "post-timestamp": GetBuildProp("ro.build.date.utc", input_zip),
Doug Zongker2ea21062010-04-28 16:05:21 -0700374 }
375
Doug Zongker05d3dea2009-06-22 11:32:31 -0700376 device_specific = common.DeviceSpecificParams(
377 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700378 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700379 output_zip=output_zip,
380 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700381 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700382 metadata=metadata,
383 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700384
Doug Zongker962069c2009-04-23 11:41:58 -0700385 if not OPTIONS.omit_prereq:
386 ts = GetBuildProp("ro.build.date.utc", input_zip)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700387 script.AssertOlderBuild(ts)
Doug Zongkereef39442009-04-02 12:14:19 -0700388
389 AppendAssertions(script, input_zip)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700390 device_specific.FullOTA_Assertions()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700391
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700392 script.ShowProgress(0.5, 0)
Doug Zongkereef39442009-04-02 12:14:19 -0700393
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700394 if OPTIONS.wipe_user_data:
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700395 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700396
Stephen Smalley56882bf2012-02-09 13:36:21 -0500397 if OPTIONS.selinux_fc is not None:
398 WritePolicyConfig(OPTIONS.selinux_fc, output_zip)
399
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700400 script.FormatPartition("/system")
401 script.Mount("/system")
Doug Zongkercfd7db62009-10-07 11:35:53 -0700402 script.UnpackPackageDir("recovery", "/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700403 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700404
Hristo Bojinov96be7202010-08-02 10:26:17 -0700405 (symlinks, retouch_files) = CopySystemFiles(input_zip, output_zip)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700406 script.MakeSymlinks(symlinks)
Hristo Bojinov96be7202010-08-02 10:26:17 -0700407 if OPTIONS.aslr_mode:
408 script.RetouchBinaries(retouch_files)
409 else:
410 script.UndoRetouchBinaries(retouch_files)
Doug Zongkereef39442009-04-02 12:14:19 -0700411
Doug Zongker55d93282011-01-25 17:03:34 -0800412 boot_img = common.GetBootableImage("boot.img", "boot.img",
413 OPTIONS.input_tmp, "BOOT")
414 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
415 OPTIONS.input_tmp, "RECOVERY")
Doug Zongker486de122010-09-16 14:01:56 -0700416 MakeRecoveryPatch(output_zip, recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700417
Doug Zongker283e2a12010-03-15 17:52:32 -0700418 Item.GetMetadata(input_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700419 Item.Get("system").SetPermissions(script)
420
Doug Zongker37974732010-09-16 17:44:38 -0700421 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700422 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700423 script.ShowProgress(0.2, 0)
424
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700425 script.ShowProgress(0.2, 10)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700426 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700427
428 script.ShowProgress(0.1, 0)
429 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700430
Doug Zongker1c390a22009-05-14 19:06:36 -0700431 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700432 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700433
Doug Zongker14833602010-02-02 13:12:04 -0800434 script.UnmountAll()
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700435 script.AddToZip(input_zip, output_zip)
Doug Zongker2ea21062010-04-28 16:05:21 -0700436 WriteMetadata(metadata, output_zip)
437
Stephen Smalley56882bf2012-02-09 13:36:21 -0500438def WritePolicyConfig(file_context, output_zip):
439 f = open(file_context, 'r');
440 basename = os.path.basename(file_context)
441 common.ZipWriteStr(output_zip, basename, f.read())
442
Doug Zongker2ea21062010-04-28 16:05:21 -0700443
444def WriteMetadata(metadata, output_zip):
445 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
446 "".join(["%s=%s\n" % kv
447 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700448
Doug Zongkereef39442009-04-02 12:14:19 -0700449def LoadSystemFiles(z):
450 """Load all the files from SYSTEM/... in a given target-files
451 ZipFile, and return a dict of {filename: File object}."""
452 out = {}
Hristo Bojinov96be7202010-08-02 10:26:17 -0700453 retouch_files = []
Doug Zongkereef39442009-04-02 12:14:19 -0700454 for info in z.infolist():
455 if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
Hristo Bojinov96be7202010-08-02 10:26:17 -0700456 basefilename = info.filename[7:]
457 fn = "system/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700458 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700459 out[fn] = common.File(fn, data)
Hristo Bojinov96be7202010-08-02 10:26:17 -0700460 if info.filename.startswith("SYSTEM/lib/") and IsRegular(info):
461 retouch_files.append(("/system/" + basefilename,
462 out[fn].sha1))
463 return (out, retouch_files)
Doug Zongkereef39442009-04-02 12:14:19 -0700464
465
Doug Zongkereef39442009-04-02 12:14:19 -0700466def GetBuildProp(property, z):
467 """Return the fingerprint of the build of a given target-files
468 ZipFile object."""
469 bp = z.read("SYSTEM/build.prop")
470 if not property:
471 return bp
472 m = re.search(re.escape(property) + r"=(.*)\n", bp)
473 if not m:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700474 raise common.ExternalError("couldn't find %s in build.prop" % (property,))
Doug Zongkereef39442009-04-02 12:14:19 -0700475 return m.group(1).strip()
476
477
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700478def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Doug Zongker37974732010-09-16 17:44:38 -0700479 source_version = OPTIONS.source_info_dict["recovery_api_version"]
480 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700481
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700482 if source_version == 0:
483 print ("WARNING: generating edify script for a source that "
484 "can't install it.")
Doug Zongkerb984ae52010-09-16 23:13:11 -0700485 script = edify_generator.EdifyGenerator(source_version, OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700486
Doug Zongker2ea21062010-04-28 16:05:21 -0700487 metadata = {"pre-device": GetBuildProp("ro.product.device", source_zip),
Doug Zongker3b852692010-06-21 15:30:45 -0700488 "post-timestamp": GetBuildProp("ro.build.date.utc", target_zip),
Doug Zongker2ea21062010-04-28 16:05:21 -0700489 }
490
Doug Zongker05d3dea2009-06-22 11:32:31 -0700491 device_specific = common.DeviceSpecificParams(
492 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800493 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700494 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800495 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700496 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -0700497 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -0700498 metadata=metadata,
499 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700500
Doug Zongkereef39442009-04-02 12:14:19 -0700501 print "Loading target..."
Hristo Bojinov96be7202010-08-02 10:26:17 -0700502 (target_data, target_retouch_files) = LoadSystemFiles(target_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700503 print "Loading source..."
Hristo Bojinov96be7202010-08-02 10:26:17 -0700504 (source_data, source_retouch_files) = LoadSystemFiles(source_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700505
506 verbatim_targets = []
507 patch_list = []
Doug Zongker761e6422009-09-25 10:45:39 -0700508 diffs = []
Doug Zongkereef39442009-04-02 12:14:19 -0700509 largest_source_size = 0
510 for fn in sorted(target_data.keys()):
511 tf = target_data[fn]
Doug Zongker761e6422009-09-25 10:45:39 -0700512 assert fn == tf.name
Doug Zongkereef39442009-04-02 12:14:19 -0700513 sf = source_data.get(fn, None)
514
515 if sf is None or fn in OPTIONS.require_verbatim:
516 # This file should be included verbatim
517 if fn in OPTIONS.prohibit_verbatim:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700518 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
Doug Zongkereef39442009-04-02 12:14:19 -0700519 print "send", fn, "verbatim"
520 tf.AddToZip(output_zip)
521 verbatim_targets.append((fn, tf.size))
522 elif tf.sha1 != sf.sha1:
523 # File is different; consider sending as a patch
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700524 diffs.append(common.Difference(tf, sf))
Doug Zongkereef39442009-04-02 12:14:19 -0700525 else:
526 # Target file identical to source.
527 pass
528
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700529 common.ComputeDifferences(diffs)
Doug Zongker761e6422009-09-25 10:45:39 -0700530
531 for diff in diffs:
532 tf, sf, d = diff.GetPatch()
533 if d is None or len(d) > tf.size * OPTIONS.patch_threshold:
534 # patch is almost as big as the file; don't bother patching
535 tf.AddToZip(output_zip)
536 verbatim_targets.append((tf.name, tf.size))
537 else:
538 common.ZipWriteStr(output_zip, "patch/" + tf.name + ".p", d)
Doug Zongker55d93282011-01-25 17:03:34 -0800539 patch_list.append((tf.name, tf, sf, tf.size, common.sha1(d).hexdigest()))
Doug Zongker761e6422009-09-25 10:45:39 -0700540 largest_source_size = max(largest_source_size, sf.size)
Doug Zongkereef39442009-04-02 12:14:19 -0700541
542 source_fp = GetBuildProp("ro.build.fingerprint", source_zip)
543 target_fp = GetBuildProp("ro.build.fingerprint", target_zip)
Doug Zongker2ea21062010-04-28 16:05:21 -0700544 metadata["pre-build"] = source_fp
545 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -0700546
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700547 script.Mount("/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700548 script.AssertSomeFingerprint(source_fp, target_fp)
Doug Zongkereef39442009-04-02 12:14:19 -0700549
Doug Zongker55d93282011-01-25 17:03:34 -0800550 source_boot = common.GetBootableImage(
551 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT")
552 target_boot = common.GetBootableImage(
553 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker5da317e2009-06-02 13:38:17 -0700554 updating_boot = (source_boot.data != target_boot.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700555
Doug Zongker55d93282011-01-25 17:03:34 -0800556 source_recovery = common.GetBootableImage(
557 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY")
558 target_recovery = common.GetBootableImage(
559 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -0700560 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700561
Doug Zongker881dd402009-09-20 14:03:55 -0700562 # Here's how we divide up the progress bar:
563 # 0.1 for verifying the start state (PatchCheck calls)
564 # 0.8 for applying patches (ApplyPatch calls)
565 # 0.1 for unpacking verbatim files, symlinking, and doing the
566 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -0700567
568 AppendAssertions(script, target_zip)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700569 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -0700570
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700571 script.Print("Verifying current system...")
572
Doug Zongker881dd402009-09-20 14:03:55 -0700573 script.ShowProgress(0.1, 0)
574 total_verify_size = float(sum([i[2].size for i in patch_list]) + 1)
575 if updating_boot:
576 total_verify_size += source_boot.size
577 so_far = 0
Doug Zongkereef39442009-04-02 12:14:19 -0700578
Doug Zongker5a482092010-02-17 16:09:18 -0800579 for fn, tf, sf, size, patch_sha in patch_list:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700580 script.PatchCheck("/"+fn, tf.sha1, sf.sha1)
Doug Zongker881dd402009-09-20 14:03:55 -0700581 so_far += sf.size
582 script.SetProgress(so_far / total_verify_size)
Doug Zongkereef39442009-04-02 12:14:19 -0700583
Doug Zongker5da317e2009-06-02 13:38:17 -0700584 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700585 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -0700586 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -0700587 print "boot target: %d source: %d diff: %d" % (
588 target_boot.size, source_boot.size, len(d))
589
Doug Zongker048e7ca2009-06-15 14:31:53 -0700590 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -0700591
Doug Zongker96a57e72010-09-26 14:57:41 -0700592 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -0700593
594 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
595 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -0700596 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700597 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -0700598 so_far += source_boot.size
599 script.SetProgress(so_far / total_verify_size)
Doug Zongker5da317e2009-06-02 13:38:17 -0700600
601 if patch_list or updating_recovery or updating_boot:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700602 script.CacheFreeSpaceCheck(largest_source_size)
Doug Zongker5a482092010-02-17 16:09:18 -0800603
Doug Zongker05d3dea2009-06-22 11:32:31 -0700604 device_specific.IncrementalOTA_VerifyEnd()
605
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700606 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -0700607
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700608 if OPTIONS.wipe_user_data:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700609 script.Print("Erasing user data...")
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700610 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700611
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700612 script.Print("Removing unneeded files...")
Doug Zongker0f3298a2009-06-30 08:16:58 -0700613 script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
614 ["/"+i for i in sorted(source_data)
Doug Zongker3b949f02009-08-24 10:24:32 -0700615 if i not in target_data] +
616 ["/system/recovery.img"])
Doug Zongkereef39442009-04-02 12:14:19 -0700617
Doug Zongker881dd402009-09-20 14:03:55 -0700618 script.ShowProgress(0.8, 0)
619 total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
620 if updating_boot:
621 total_patch_size += target_boot.size
622 so_far = 0
623
624 script.Print("Patching system files...")
Doug Zongkere92f15a2011-08-26 13:46:40 -0700625 deferred_patch_list = []
626 for item in patch_list:
627 fn, tf, sf, size, _ = item
628 if tf.name == "system/build.prop":
629 deferred_patch_list.append(item)
630 continue
Doug Zongkerc8d446b2010-02-22 15:41:53 -0800631 script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
Doug Zongker881dd402009-09-20 14:03:55 -0700632 so_far += tf.size
633 script.SetProgress(so_far / total_patch_size)
634
Doug Zongkereef39442009-04-02 12:14:19 -0700635 if updating_boot:
Doug Zongker5da317e2009-06-02 13:38:17 -0700636 # Produce the boot image by applying a patch to the current
637 # contents of the boot partition, and write it back to the
638 # partition.
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700639 script.Print("Patching boot image...")
Doug Zongkerf2ab2902010-09-22 10:12:54 -0700640 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
641 % (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -0700642 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700643 target_boot.size, target_boot.sha1),
644 "-",
645 target_boot.size, target_boot.sha1,
Doug Zongkerc8d446b2010-02-22 15:41:53 -0800646 source_boot.sha1, "patch/boot.img.p")
Doug Zongker881dd402009-09-20 14:03:55 -0700647 so_far += target_boot.size
648 script.SetProgress(so_far / total_patch_size)
Doug Zongkereef39442009-04-02 12:14:19 -0700649 print "boot image changed; including."
650 else:
651 print "boot image unchanged; skipping."
652
653 if updating_recovery:
Doug Zongker73ef8252009-07-23 15:12:53 -0700654 # Is it better to generate recovery as a patch from the current
655 # boot image, or from the previous recovery image? For large
656 # updates with significant kernel changes, probably the former.
657 # For small updates where the kernel hasn't changed, almost
658 # certainly the latter. We pick the first option. Future
659 # complicated schemes may let us effectively use both.
660 #
661 # A wacky possibility: as long as there is room in the boot
662 # partition, include the binaries and image files from recovery in
663 # the boot image (though not in the ramdisk) so they can be used
664 # as fodder for constructing the recovery image.
Doug Zongker486de122010-09-16 14:01:56 -0700665 MakeRecoveryPatch(output_zip, target_recovery, target_boot)
Doug Zongker42265392010-02-12 10:21:00 -0800666 script.DeleteFiles(["/system/recovery-from-boot.p",
667 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -0700668 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -0700669 else:
670 print "recovery image unchanged; skipping."
671
Doug Zongker881dd402009-09-20 14:03:55 -0700672 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -0700673
Hristo Bojinov96be7202010-08-02 10:26:17 -0700674 (target_symlinks, target_retouch_dummies) = CopySystemFiles(target_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700675
676 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700677 temp_script = script.MakeTemporary()
Doug Zongker283e2a12010-03-15 17:52:32 -0700678 Item.GetMetadata(target_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700679 Item.Get("system").SetPermissions(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -0700680
681 # Note that this call will mess up the tree of Items, so make sure
682 # we're done with it.
Hristo Bojinov96be7202010-08-02 10:26:17 -0700683 (source_symlinks, source_retouch_dummies) = CopySystemFiles(source_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700684 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
685
686 # Delete all the symlinks in source that aren't in target. This
687 # needs to happen before verbatim files are unpacked, in case a
688 # symlink in the source is replaced by a real file in the target.
689 to_delete = []
690 for dest, link in source_symlinks:
691 if link not in target_symlinks_d:
692 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700693 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -0700694
695 if verbatim_targets:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700696 script.Print("Unpacking new files...")
697 script.UnpackPackageDir("system", "/system")
698
Doug Zongker42265392010-02-12 10:21:00 -0800699 if updating_recovery:
700 script.Print("Unpacking new recovery...")
701 script.UnpackPackageDir("recovery", "/system")
702
Doug Zongker05d3dea2009-06-22 11:32:31 -0700703 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -0700704
705 # Create all the symlinks that don't already exist, or point to
706 # somewhere different than what we want. Delete each symlink before
707 # creating it, since the 'symlink' command won't overwrite.
708 to_create = []
709 for dest, link in target_symlinks:
710 if link in source_symlinks_d:
711 if dest != source_symlinks_d[link]:
712 to_create.append((dest, link))
713 else:
714 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700715 script.DeleteFiles([i[1] for i in to_create])
716 script.MakeSymlinks(to_create)
Hristo Bojinov96be7202010-08-02 10:26:17 -0700717 if OPTIONS.aslr_mode:
718 script.RetouchBinaries(target_retouch_files)
719 else:
720 script.UndoRetouchBinaries(target_retouch_files)
Doug Zongkereef39442009-04-02 12:14:19 -0700721
722 # Now that the symlinks are created, we can set all the
723 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700724 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -0700725
Doug Zongker881dd402009-09-20 14:03:55 -0700726 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -0700727 device_specific.IncrementalOTA_InstallEnd()
728
Doug Zongker1c390a22009-05-14 19:06:36 -0700729 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -0700730 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700731
Doug Zongkere92f15a2011-08-26 13:46:40 -0700732 # Patch the build.prop file last, so if something fails but the
733 # device can still come up, it appears to be the old build and will
734 # get set the OTA package again to retry.
735 script.Print("Patching remaining system files...")
736 for item in deferred_patch_list:
737 fn, tf, sf, size, _ = item
738 script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
739 script.SetPermissions("/system/build.prop", 0, 0, 0644)
740
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700741 script.AddToZip(target_zip, output_zip)
Doug Zongker2ea21062010-04-28 16:05:21 -0700742 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700743
744
745def main(argv):
746
747 def option_handler(o, a):
748 if o in ("-b", "--board_config"):
Doug Zongkerfdd8e692009-08-03 17:27:48 -0700749 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -0700750 elif o in ("-k", "--package_key"):
751 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -0700752 elif o in ("-i", "--incremental_from"):
753 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700754 elif o in ("-w", "--wipe_user_data"):
755 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -0700756 elif o in ("-n", "--no_prereq"):
757 OPTIONS.omit_prereq = True
Doug Zongker1c390a22009-05-14 19:06:36 -0700758 elif o in ("-e", "--extra_script"):
759 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700760 elif o in ("-a", "--aslr_mode"):
761 if a in ("on", "On", "true", "True", "yes", "Yes"):
762 OPTIONS.aslr_mode = True
763 else:
764 OPTIONS.aslr_mode = False
Doug Zongker761e6422009-09-25 10:45:39 -0700765 elif o in ("--worker_threads"):
766 OPTIONS.worker_threads = int(a)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500767 elif o in ("-S", "--file_context"):
768 OPTIONS.selinux_fc = a
Doug Zongkereef39442009-04-02 12:14:19 -0700769 else:
770 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700771 return True
Doug Zongkereef39442009-04-02 12:14:19 -0700772
773 args = common.ParseOptions(argv, __doc__,
Stephen Smalley56882bf2012-02-09 13:36:21 -0500774 extra_opts="b:k:i:d:wne:a:S:",
Doug Zongkereef39442009-04-02 12:14:19 -0700775 extra_long_opts=["board_config=",
776 "package_key=",
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700777 "incremental_from=",
Doug Zongker962069c2009-04-23 11:41:58 -0700778 "wipe_user_data",
Doug Zongker1c390a22009-05-14 19:06:36 -0700779 "no_prereq",
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700780 "extra_script=",
Hristo Bojinov96be7202010-08-02 10:26:17 -0700781 "worker_threads=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -0700782 "aslr_mode=",
Stephen Smalley56882bf2012-02-09 13:36:21 -0500783 "file_context=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -0700784 ],
Doug Zongkereef39442009-04-02 12:14:19 -0700785 extra_option_handler=option_handler)
786
787 if len(args) != 2:
788 common.Usage(__doc__)
789 sys.exit(1)
790
Doug Zongker1c390a22009-05-14 19:06:36 -0700791 if OPTIONS.extra_script is not None:
792 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
793
Doug Zongkereef39442009-04-02 12:14:19 -0700794 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -0800795 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -0700796
Doug Zongkereef39442009-04-02 12:14:19 -0700797 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -0700798 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
799 if OPTIONS.verbose:
800 print "--- target info ---"
801 common.DumpInfoDict(OPTIONS.info_dict)
802
803 if OPTIONS.device_specific is None:
804 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
805 if OPTIONS.device_specific is not None:
806 OPTIONS.device_specific = os.path.normpath(OPTIONS.device_specific)
807 print "using device-specific extensions in", OPTIONS.device_specific
808
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700809 temp_zip_file = tempfile.NamedTemporaryFile()
810 output_zip = zipfile.ZipFile(temp_zip_file, "w",
811 compression=zipfile.ZIP_DEFLATED)
Doug Zongkereef39442009-04-02 12:14:19 -0700812
813 if OPTIONS.incremental_source is None:
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700814 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700815 if OPTIONS.package_key is None:
816 OPTIONS.package_key = OPTIONS.info_dict.get(
817 "default_system_dev_certificate",
818 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -0700819 else:
820 print "unzipping source target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -0800821 OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
Doug Zongker37974732010-09-16 17:44:38 -0700822 OPTIONS.target_info_dict = OPTIONS.info_dict
823 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700824 if OPTIONS.package_key is None:
Doug Zongker91b4f8a2011-09-23 12:48:33 -0700825 OPTIONS.package_key = OPTIONS.source_info_dict.get(
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700826 "default_system_dev_certificate",
827 "build/target/product/security/testkey")
Doug Zongker37974732010-09-16 17:44:38 -0700828 if OPTIONS.verbose:
829 print "--- source info ---"
830 common.DumpInfoDict(OPTIONS.source_info_dict)
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700831 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700832
833 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700834
835 SignOutput(temp_zip_file.name, args[1])
836 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -0700837
838 common.Cleanup()
839
840 print "done."
841
842
843if __name__ == '__main__':
844 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -0800845 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -0700846 main(sys.argv[1:])
847 except common.ExternalError, e:
848 print
849 print " ERROR: %s" % (e,)
850 print
851 sys.exit(1)