blob: f05cd1bf891dbd55ccbe33376f9db264df30023f [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).
Doug Zongkereef39442009-04-02 12:14:19 -070054"""
55
56import sys
57
58if sys.hexversion < 0x02040000:
59 print >> sys.stderr, "Python 2.4 or newer is required."
60 sys.exit(1)
61
62import copy
Doug Zongkerc18736b2009-09-30 09:20:32 -070063import errno
Doug Zongkereef39442009-04-02 12:14:19 -070064import os
65import re
Doug Zongkereef39442009-04-02 12:14:19 -070066import subprocess
67import tempfile
68import time
69import zipfile
70
davidcad0bb92011-03-15 14:21:38 +000071try:
72 from hashlib import sha1 as sha1
73except ImportError:
74 from sha import sha as sha1
75
Doug Zongkereef39442009-04-02 12:14:19 -070076import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -070077import edify_generator
Doug Zongkereef39442009-04-02 12:14:19 -070078
79OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -070080OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -070081OPTIONS.incremental_source = None
82OPTIONS.require_verbatim = set()
83OPTIONS.prohibit_verbatim = set(("system/build.prop",))
84OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -070085OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -070086OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -070087OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -070088OPTIONS.aslr_mode = True
Doug Zongker761e6422009-09-25 10:45:39 -070089OPTIONS.worker_threads = 3
Doug Zongkereef39442009-04-02 12:14:19 -070090
91def MostPopularKey(d, default):
92 """Given a dict, return the key corresponding to the largest
93 value. Returns 'default' if the dict is empty."""
94 x = [(v, k) for (k, v) in d.iteritems()]
95 if not x: return default
96 x.sort()
97 return x[-1][1]
98
99
100def IsSymlink(info):
101 """Return true if the zipfile.ZipInfo object passed in represents a
102 symlink."""
103 return (info.external_attr >> 16) == 0120777
104
Hristo Bojinov96be7202010-08-02 10:26:17 -0700105def IsRegular(info):
106 """Return true if the zipfile.ZipInfo object passed in represents a
107 symlink."""
108 return (info.external_attr >> 28) == 010
Doug Zongkereef39442009-04-02 12:14:19 -0700109
Doug Zongkereef39442009-04-02 12:14:19 -0700110class Item:
111 """Items represent the metadata (user, group, mode) of files and
112 directories in the system image."""
113 ITEMS = {}
114 def __init__(self, name, dir=False):
115 self.name = name
116 self.uid = None
117 self.gid = None
118 self.mode = None
119 self.dir = dir
120
121 if name:
122 self.parent = Item.Get(os.path.dirname(name), dir=True)
123 self.parent.children.append(self)
124 else:
125 self.parent = None
126 if dir:
127 self.children = []
128
129 def Dump(self, indent=0):
130 if self.uid is not None:
131 print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode)
132 else:
133 print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode)
134 if self.dir:
135 print "%s%s" % (" "*indent, self.descendants)
136 print "%s%s" % (" "*indent, self.best_subtree)
137 for i in self.children:
138 i.Dump(indent=indent+1)
139
140 @classmethod
141 def Get(cls, name, dir=False):
142 if name not in cls.ITEMS:
143 cls.ITEMS[name] = Item(name, dir=dir)
144 return cls.ITEMS[name]
145
146 @classmethod
Doug Zongker283e2a12010-03-15 17:52:32 -0700147 def GetMetadata(cls, input_zip):
148
149 try:
150 # See if the target_files contains a record of what the uid,
151 # gid, and mode is supposed to be.
152 output = input_zip.read("META/filesystem_config.txt")
153 except KeyError:
154 # Run the external 'fs_config' program to determine the desired
155 # uid, gid, and mode for every Item object. Note this uses the
156 # one in the client now, which might not be the same as the one
157 # used when this target_files was built.
158 p = common.Run(["fs_config"], stdin=subprocess.PIPE,
159 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
160 suffix = { False: "", True: "/" }
161 input = "".join(["%s%s\n" % (i.name, suffix[i.dir])
162 for i in cls.ITEMS.itervalues() if i.name])
Doug Zongker3475d362010-03-17 16:39:30 -0700163 output, error = p.communicate(input)
Doug Zongker283e2a12010-03-15 17:52:32 -0700164 assert not error
Doug Zongkereef39442009-04-02 12:14:19 -0700165
166 for line in output.split("\n"):
167 if not line: continue
168 name, uid, gid, mode = line.split()
Doug Zongker283e2a12010-03-15 17:52:32 -0700169 i = cls.ITEMS.get(name, None)
170 if i is not None:
171 i.uid = int(uid)
172 i.gid = int(gid)
173 i.mode = int(mode, 8)
174 if i.dir:
175 i.children.sort(key=lambda i: i.name)
176
177 # set metadata for the files generated by this script.
178 i = cls.ITEMS.get("system/recovery-from-boot.p", None)
179 if i: i.uid, i.gid, i.mode = 0, 0, 0644
180 i = cls.ITEMS.get("system/etc/install-recovery.sh", None)
181 if i: i.uid, i.gid, i.mode = 0, 0, 0544
Doug Zongkereef39442009-04-02 12:14:19 -0700182
183 def CountChildMetadata(self):
184 """Count up the (uid, gid, mode) tuples for all children and
185 determine the best strategy for using set_perm_recursive and
186 set_perm to correctly chown/chmod all the files to their desired
187 values. Recursively calls itself for all descendants.
188
189 Returns a dict of {(uid, gid, dmode, fmode): count} counting up
190 all descendants of this node. (dmode or fmode may be None.) Also
191 sets the best_subtree of each directory Item to the (uid, gid,
192 dmode, fmode) tuple that will match the most descendants of that
193 Item.
194 """
195
196 assert self.dir
197 d = self.descendants = {(self.uid, self.gid, self.mode, None): 1}
198 for i in self.children:
199 if i.dir:
200 for k, v in i.CountChildMetadata().iteritems():
201 d[k] = d.get(k, 0) + v
202 else:
203 k = (i.uid, i.gid, None, i.mode)
204 d[k] = d.get(k, 0) + 1
205
206 # Find the (uid, gid, dmode, fmode) tuple that matches the most
207 # descendants.
208
209 # First, find the (uid, gid) pair that matches the most
210 # descendants.
211 ug = {}
212 for (uid, gid, _, _), count in d.iteritems():
213 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
214 ug = MostPopularKey(ug, (0, 0))
215
216 # Now find the dmode and fmode that match the most descendants
217 # with that (uid, gid), and choose those.
218 best_dmode = (0, 0755)
219 best_fmode = (0, 0644)
220 for k, count in d.iteritems():
221 if k[:2] != ug: continue
222 if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2])
223 if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3])
224 self.best_subtree = ug + (best_dmode[1], best_fmode[1])
225
226 return d
227
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700228 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700229 """Append set_perm/set_perm_recursive commands to 'script' to
230 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700231 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700232
233 self.CountChildMetadata()
234
235 def recurse(item, current):
236 # current is the (uid, gid, dmode, fmode) tuple that the current
237 # item (and all its children) have already been set to. We only
238 # need to issue set_perm/set_perm_recursive commands if we're
239 # supposed to be something different.
240 if item.dir:
241 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700242 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700243 current = item.best_subtree
244
245 if item.uid != current[0] or item.gid != current[1] or \
246 item.mode != current[2]:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700247 script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode)
Doug Zongkereef39442009-04-02 12:14:19 -0700248
249 for i in item.children:
250 recurse(i, current)
251 else:
252 if item.uid != current[0] or item.gid != current[1] or \
253 item.mode != current[3]:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700254 script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode)
Doug Zongkereef39442009-04-02 12:14:19 -0700255
256 recurse(self, (-1, -1, -1, -1))
257
258
259def CopySystemFiles(input_zip, output_zip=None,
260 substitute=None):
261 """Copies files underneath system/ in the input zip to the output
262 zip. Populates the Item class with their metadata, and returns a
Hristo Bojinov96be7202010-08-02 10:26:17 -0700263 list of symlinks as well as a list of files that will be retouched.
264 output_zip may be None, in which case the copy is skipped (but the
265 other side effects still happen). substitute is an optional dict
266 of {output filename: contents} to be output instead of certain input
267 files.
Doug Zongkereef39442009-04-02 12:14:19 -0700268 """
269
270 symlinks = []
Hristo Bojinov96be7202010-08-02 10:26:17 -0700271 retouch_files = []
Doug Zongkereef39442009-04-02 12:14:19 -0700272
273 for info in input_zip.infolist():
274 if info.filename.startswith("SYSTEM/"):
275 basefilename = info.filename[7:]
276 if IsSymlink(info):
277 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700278 "/system/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700279 else:
280 info2 = copy.copy(info)
281 fn = info2.filename = "system/" + basefilename
282 if substitute and fn in substitute and substitute[fn] is None:
283 continue
284 if output_zip is not None:
285 if substitute and fn in substitute:
286 data = substitute[fn]
287 else:
288 data = input_zip.read(info.filename)
Hristo Bojinov96be7202010-08-02 10:26:17 -0700289 if info.filename.startswith("SYSTEM/lib/") and IsRegular(info):
290 retouch_files.append(("/system/" + basefilename,
Doug Zongker55d93282011-01-25 17:03:34 -0800291 common.sha1(data).hexdigest()))
Doug Zongkereef39442009-04-02 12:14:19 -0700292 output_zip.writestr(info2, data)
293 if fn.endswith("/"):
294 Item.Get(fn[:-1], dir=True)
295 else:
296 Item.Get(fn, dir=False)
297
298 symlinks.sort()
Hristo Bojinov96be7202010-08-02 10:26:17 -0700299 return (symlinks, retouch_files)
Doug Zongkereef39442009-04-02 12:14:19 -0700300
301
Doug Zongkereef39442009-04-02 12:14:19 -0700302def SignOutput(temp_zip_name, output_zip_name):
303 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
304 pw = key_passwords[OPTIONS.package_key]
305
Doug Zongker951495f2009-08-14 12:44:19 -0700306 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
307 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700308
309
Doug Zongkereef39442009-04-02 12:14:19 -0700310def AppendAssertions(script, input_zip):
Doug Zongkereef39442009-04-02 12:14:19 -0700311 device = GetBuildProp("ro.product.device", input_zip)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700312 script.AssertDevice(device)
Doug Zongkereef39442009-04-02 12:14:19 -0700313
Doug Zongkereef39442009-04-02 12:14:19 -0700314
Doug Zongker486de122010-09-16 14:01:56 -0700315def MakeRecoveryPatch(output_zip, recovery_img, boot_img):
Doug Zongker73ef8252009-07-23 15:12:53 -0700316 """Generate a binary patch that creates the recovery image starting
317 with the boot image. (Most of the space in these images is just the
318 kernel, which is identical for the two, so the resulting patch
319 should be efficient.) Add it to the output zip, along with a shell
320 script that is run from init.rc on first boot to actually do the
321 patching and install the new recovery image.
322
323 recovery_img and boot_img should be File objects for the
Doug Zongker67369982010-07-07 13:53:32 -0700324 corresponding images. info should be the dictionary returned by
325 common.LoadInfoDict() on the input target_files.
Doug Zongker73ef8252009-07-23 15:12:53 -0700326
327 Returns an Item for the shell script, which must be made
328 executable.
329 """
330
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700331 d = common.Difference(recovery_img, boot_img)
Doug Zongker761e6422009-09-25 10:45:39 -0700332 _, _, patch = d.ComputePatch()
Doug Zongkercfd7db62009-10-07 11:35:53 -0700333 common.ZipWriteStr(output_zip, "recovery/recovery-from-boot.p", patch)
Doug Zongker73ef8252009-07-23 15:12:53 -0700334 Item.Get("system/recovery-from-boot.p", dir=False)
335
Doug Zongker96a57e72010-09-26 14:57:41 -0700336 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
337 recovery_type, recovery_device = common.GetTypeAndDevice("/recovery", OPTIONS.info_dict)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700338
Doug Zongker73ef8252009-07-23 15:12:53 -0700339 sh = """#!/system/bin/sh
Doug Zongker0276d182011-12-02 10:46:59 -0800340if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then
Doug Zongker73ef8252009-07-23 15:12:53 -0700341 log -t recovery "Installing new recovery image"
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700342 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 -0700343else
344 log -t recovery "Recovery image already installed"
345fi
346""" % { 'boot_size': boot_img.size,
347 'boot_sha1': boot_img.sha1,
Doug Zongker73ef8252009-07-23 15:12:53 -0700348 'recovery_size': recovery_img.size,
Doug Zongker67369982010-07-07 13:53:32 -0700349 'recovery_sha1': recovery_img.sha1,
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700350 'boot_type': boot_type,
351 'boot_device': boot_device,
352 'recovery_type': recovery_type,
353 'recovery_device': recovery_device,
Doug Zongker67369982010-07-07 13:53:32 -0700354 }
Doug Zongkercfd7db62009-10-07 11:35:53 -0700355 common.ZipWriteStr(output_zip, "recovery/etc/install-recovery.sh", sh)
Doug Zongker73ef8252009-07-23 15:12:53 -0700356 return Item.Get("system/etc/install-recovery.sh", dir=False)
357
358
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700359def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700360 # TODO: how to determine this? We don't know what version it will
361 # be installed on top of. For now, we expect the API just won't
362 # change very often.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700363 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700364
Doug Zongker2ea21062010-04-28 16:05:21 -0700365 metadata = {"post-build": GetBuildProp("ro.build.fingerprint", input_zip),
366 "pre-device": GetBuildProp("ro.product.device", input_zip),
Doug Zongker3b852692010-06-21 15:30:45 -0700367 "post-timestamp": GetBuildProp("ro.build.date.utc", input_zip),
Doug Zongker2ea21062010-04-28 16:05:21 -0700368 }
369
Doug Zongker05d3dea2009-06-22 11:32:31 -0700370 device_specific = common.DeviceSpecificParams(
371 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700372 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700373 output_zip=output_zip,
374 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700375 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700376 metadata=metadata,
377 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700378
Doug Zongker962069c2009-04-23 11:41:58 -0700379 if not OPTIONS.omit_prereq:
380 ts = GetBuildProp("ro.build.date.utc", input_zip)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700381 script.AssertOlderBuild(ts)
Doug Zongkereef39442009-04-02 12:14:19 -0700382
383 AppendAssertions(script, input_zip)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700384 device_specific.FullOTA_Assertions()
Doug Zongkere5ff5902012-01-17 10:55:37 -0800385 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700386
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700387 script.ShowProgress(0.5, 0)
Doug Zongkereef39442009-04-02 12:14:19 -0700388
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700389 if OPTIONS.wipe_user_data:
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700390 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700391
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700392 script.FormatPartition("/system")
393 script.Mount("/system")
Doug Zongkercfd7db62009-10-07 11:35:53 -0700394 script.UnpackPackageDir("recovery", "/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700395 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700396
Hristo Bojinov96be7202010-08-02 10:26:17 -0700397 (symlinks, retouch_files) = CopySystemFiles(input_zip, output_zip)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700398 script.MakeSymlinks(symlinks)
Hristo Bojinov96be7202010-08-02 10:26:17 -0700399 if OPTIONS.aslr_mode:
400 script.RetouchBinaries(retouch_files)
401 else:
402 script.UndoRetouchBinaries(retouch_files)
Doug Zongkereef39442009-04-02 12:14:19 -0700403
Doug Zongker55d93282011-01-25 17:03:34 -0800404 boot_img = common.GetBootableImage("boot.img", "boot.img",
405 OPTIONS.input_tmp, "BOOT")
406 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
407 OPTIONS.input_tmp, "RECOVERY")
Doug Zongker486de122010-09-16 14:01:56 -0700408 MakeRecoveryPatch(output_zip, recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700409
Doug Zongker283e2a12010-03-15 17:52:32 -0700410 Item.GetMetadata(input_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700411 Item.Get("system").SetPermissions(script)
412
Doug Zongker37974732010-09-16 17:44:38 -0700413 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700414 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700415 script.ShowProgress(0.2, 0)
416
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700417 script.ShowProgress(0.2, 10)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700418 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700419
420 script.ShowProgress(0.1, 0)
421 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700422
Doug Zongker1c390a22009-05-14 19:06:36 -0700423 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700424 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700425
Doug Zongker14833602010-02-02 13:12:04 -0800426 script.UnmountAll()
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700427 script.AddToZip(input_zip, output_zip)
Doug Zongker2ea21062010-04-28 16:05:21 -0700428 WriteMetadata(metadata, output_zip)
429
430
431def WriteMetadata(metadata, output_zip):
432 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
433 "".join(["%s=%s\n" % kv
434 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700435
436
Doug Zongkereef39442009-04-02 12:14:19 -0700437
438
439def LoadSystemFiles(z):
440 """Load all the files from SYSTEM/... in a given target-files
441 ZipFile, and return a dict of {filename: File object}."""
442 out = {}
Hristo Bojinov96be7202010-08-02 10:26:17 -0700443 retouch_files = []
Doug Zongkereef39442009-04-02 12:14:19 -0700444 for info in z.infolist():
445 if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
Hristo Bojinov96be7202010-08-02 10:26:17 -0700446 basefilename = info.filename[7:]
447 fn = "system/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700448 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700449 out[fn] = common.File(fn, data)
Hristo Bojinov96be7202010-08-02 10:26:17 -0700450 if info.filename.startswith("SYSTEM/lib/") and IsRegular(info):
451 retouch_files.append(("/system/" + basefilename,
452 out[fn].sha1))
453 return (out, retouch_files)
Doug Zongkereef39442009-04-02 12:14:19 -0700454
455
Doug Zongkereef39442009-04-02 12:14:19 -0700456def GetBuildProp(property, z):
457 """Return the fingerprint of the build of a given target-files
458 ZipFile object."""
459 bp = z.read("SYSTEM/build.prop")
460 if not property:
461 return bp
462 m = re.search(re.escape(property) + r"=(.*)\n", bp)
463 if not m:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700464 raise common.ExternalError("couldn't find %s in build.prop" % (property,))
Doug Zongkereef39442009-04-02 12:14:19 -0700465 return m.group(1).strip()
466
467
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700468def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Doug Zongker37974732010-09-16 17:44:38 -0700469 source_version = OPTIONS.source_info_dict["recovery_api_version"]
470 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700471
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700472 if source_version == 0:
473 print ("WARNING: generating edify script for a source that "
474 "can't install it.")
Doug Zongkerb984ae52010-09-16 23:13:11 -0700475 script = edify_generator.EdifyGenerator(source_version, OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700476
Doug Zongker2ea21062010-04-28 16:05:21 -0700477 metadata = {"pre-device": GetBuildProp("ro.product.device", source_zip),
Doug Zongker3b852692010-06-21 15:30:45 -0700478 "post-timestamp": GetBuildProp("ro.build.date.utc", target_zip),
Doug Zongker2ea21062010-04-28 16:05:21 -0700479 }
480
Doug Zongker05d3dea2009-06-22 11:32:31 -0700481 device_specific = common.DeviceSpecificParams(
482 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800483 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700484 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800485 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700486 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -0700487 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -0700488 metadata=metadata,
489 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700490
Doug Zongkereef39442009-04-02 12:14:19 -0700491 print "Loading target..."
Hristo Bojinov96be7202010-08-02 10:26:17 -0700492 (target_data, target_retouch_files) = LoadSystemFiles(target_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700493 print "Loading source..."
Hristo Bojinov96be7202010-08-02 10:26:17 -0700494 (source_data, source_retouch_files) = LoadSystemFiles(source_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700495
496 verbatim_targets = []
497 patch_list = []
Doug Zongker761e6422009-09-25 10:45:39 -0700498 diffs = []
Doug Zongkereef39442009-04-02 12:14:19 -0700499 largest_source_size = 0
500 for fn in sorted(target_data.keys()):
501 tf = target_data[fn]
Doug Zongker761e6422009-09-25 10:45:39 -0700502 assert fn == tf.name
Doug Zongkereef39442009-04-02 12:14:19 -0700503 sf = source_data.get(fn, None)
504
505 if sf is None or fn in OPTIONS.require_verbatim:
506 # This file should be included verbatim
507 if fn in OPTIONS.prohibit_verbatim:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700508 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
Doug Zongkereef39442009-04-02 12:14:19 -0700509 print "send", fn, "verbatim"
510 tf.AddToZip(output_zip)
511 verbatim_targets.append((fn, tf.size))
512 elif tf.sha1 != sf.sha1:
513 # File is different; consider sending as a patch
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700514 diffs.append(common.Difference(tf, sf))
Doug Zongkereef39442009-04-02 12:14:19 -0700515 else:
516 # Target file identical to source.
517 pass
518
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700519 common.ComputeDifferences(diffs)
Doug Zongker761e6422009-09-25 10:45:39 -0700520
521 for diff in diffs:
522 tf, sf, d = diff.GetPatch()
523 if d is None or len(d) > tf.size * OPTIONS.patch_threshold:
524 # patch is almost as big as the file; don't bother patching
525 tf.AddToZip(output_zip)
526 verbatim_targets.append((tf.name, tf.size))
527 else:
528 common.ZipWriteStr(output_zip, "patch/" + tf.name + ".p", d)
Doug Zongker55d93282011-01-25 17:03:34 -0800529 patch_list.append((tf.name, tf, sf, tf.size, common.sha1(d).hexdigest()))
Doug Zongker761e6422009-09-25 10:45:39 -0700530 largest_source_size = max(largest_source_size, sf.size)
Doug Zongkereef39442009-04-02 12:14:19 -0700531
532 source_fp = GetBuildProp("ro.build.fingerprint", source_zip)
533 target_fp = GetBuildProp("ro.build.fingerprint", target_zip)
Doug Zongker2ea21062010-04-28 16:05:21 -0700534 metadata["pre-build"] = source_fp
535 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -0700536
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700537 script.Mount("/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700538 script.AssertSomeFingerprint(source_fp, target_fp)
Doug Zongkereef39442009-04-02 12:14:19 -0700539
Doug Zongker55d93282011-01-25 17:03:34 -0800540 source_boot = common.GetBootableImage(
541 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT")
542 target_boot = common.GetBootableImage(
543 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker5da317e2009-06-02 13:38:17 -0700544 updating_boot = (source_boot.data != target_boot.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700545
Doug Zongker55d93282011-01-25 17:03:34 -0800546 source_recovery = common.GetBootableImage(
547 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY")
548 target_recovery = common.GetBootableImage(
549 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -0700550 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700551
Doug Zongker881dd402009-09-20 14:03:55 -0700552 # Here's how we divide up the progress bar:
553 # 0.1 for verifying the start state (PatchCheck calls)
554 # 0.8 for applying patches (ApplyPatch calls)
555 # 0.1 for unpacking verbatim files, symlinking, and doing the
556 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -0700557
558 AppendAssertions(script, target_zip)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700559 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -0700560
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700561 script.Print("Verifying current system...")
562
Doug Zongkere5ff5902012-01-17 10:55:37 -0800563 device_specific.IncrementalOTA_VerifyBegin()
564
Doug Zongker881dd402009-09-20 14:03:55 -0700565 script.ShowProgress(0.1, 0)
566 total_verify_size = float(sum([i[2].size for i in patch_list]) + 1)
567 if updating_boot:
568 total_verify_size += source_boot.size
569 so_far = 0
Doug Zongkereef39442009-04-02 12:14:19 -0700570
Doug Zongker5a482092010-02-17 16:09:18 -0800571 for fn, tf, sf, size, patch_sha in patch_list:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700572 script.PatchCheck("/"+fn, tf.sha1, sf.sha1)
Doug Zongker881dd402009-09-20 14:03:55 -0700573 so_far += sf.size
574 script.SetProgress(so_far / total_verify_size)
Doug Zongkereef39442009-04-02 12:14:19 -0700575
Doug Zongker5da317e2009-06-02 13:38:17 -0700576 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700577 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -0700578 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -0700579 print "boot target: %d source: %d diff: %d" % (
580 target_boot.size, source_boot.size, len(d))
581
Doug Zongker048e7ca2009-06-15 14:31:53 -0700582 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -0700583
Doug Zongker96a57e72010-09-26 14:57:41 -0700584 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -0700585
586 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
587 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -0700588 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700589 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -0700590 so_far += source_boot.size
591 script.SetProgress(so_far / total_verify_size)
Doug Zongker5da317e2009-06-02 13:38:17 -0700592
593 if patch_list or updating_recovery or updating_boot:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700594 script.CacheFreeSpaceCheck(largest_source_size)
Doug Zongker5a482092010-02-17 16:09:18 -0800595
Doug Zongker05d3dea2009-06-22 11:32:31 -0700596 device_specific.IncrementalOTA_VerifyEnd()
597
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700598 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -0700599
Doug Zongkere5ff5902012-01-17 10:55:37 -0800600 device_specific.IncrementalOTA_InstallBegin()
601
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700602 if OPTIONS.wipe_user_data:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700603 script.Print("Erasing user data...")
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700604 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700605
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700606 script.Print("Removing unneeded files...")
Doug Zongker0f3298a2009-06-30 08:16:58 -0700607 script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
608 ["/"+i for i in sorted(source_data)
Doug Zongker3b949f02009-08-24 10:24:32 -0700609 if i not in target_data] +
610 ["/system/recovery.img"])
Doug Zongkereef39442009-04-02 12:14:19 -0700611
Doug Zongker881dd402009-09-20 14:03:55 -0700612 script.ShowProgress(0.8, 0)
613 total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
614 if updating_boot:
615 total_patch_size += target_boot.size
616 so_far = 0
617
618 script.Print("Patching system files...")
Doug Zongkere92f15a2011-08-26 13:46:40 -0700619 deferred_patch_list = []
620 for item in patch_list:
621 fn, tf, sf, size, _ = item
622 if tf.name == "system/build.prop":
623 deferred_patch_list.append(item)
624 continue
Doug Zongkerc8d446b2010-02-22 15:41:53 -0800625 script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
Doug Zongker881dd402009-09-20 14:03:55 -0700626 so_far += tf.size
627 script.SetProgress(so_far / total_patch_size)
628
Doug Zongkereef39442009-04-02 12:14:19 -0700629 if updating_boot:
Doug Zongker5da317e2009-06-02 13:38:17 -0700630 # Produce the boot image by applying a patch to the current
631 # contents of the boot partition, and write it back to the
632 # partition.
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700633 script.Print("Patching boot image...")
Doug Zongkerf2ab2902010-09-22 10:12:54 -0700634 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
635 % (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -0700636 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700637 target_boot.size, target_boot.sha1),
638 "-",
639 target_boot.size, target_boot.sha1,
Doug Zongkerc8d446b2010-02-22 15:41:53 -0800640 source_boot.sha1, "patch/boot.img.p")
Doug Zongker881dd402009-09-20 14:03:55 -0700641 so_far += target_boot.size
642 script.SetProgress(so_far / total_patch_size)
Doug Zongkereef39442009-04-02 12:14:19 -0700643 print "boot image changed; including."
644 else:
645 print "boot image unchanged; skipping."
646
647 if updating_recovery:
Doug Zongker73ef8252009-07-23 15:12:53 -0700648 # Is it better to generate recovery as a patch from the current
649 # boot image, or from the previous recovery image? For large
650 # updates with significant kernel changes, probably the former.
651 # For small updates where the kernel hasn't changed, almost
652 # certainly the latter. We pick the first option. Future
653 # complicated schemes may let us effectively use both.
654 #
655 # A wacky possibility: as long as there is room in the boot
656 # partition, include the binaries and image files from recovery in
657 # the boot image (though not in the ramdisk) so they can be used
658 # as fodder for constructing the recovery image.
Doug Zongker486de122010-09-16 14:01:56 -0700659 MakeRecoveryPatch(output_zip, target_recovery, target_boot)
Doug Zongker42265392010-02-12 10:21:00 -0800660 script.DeleteFiles(["/system/recovery-from-boot.p",
661 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -0700662 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -0700663 else:
664 print "recovery image unchanged; skipping."
665
Doug Zongker881dd402009-09-20 14:03:55 -0700666 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -0700667
Hristo Bojinov96be7202010-08-02 10:26:17 -0700668 (target_symlinks, target_retouch_dummies) = CopySystemFiles(target_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700669
670 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700671 temp_script = script.MakeTemporary()
Doug Zongker283e2a12010-03-15 17:52:32 -0700672 Item.GetMetadata(target_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700673 Item.Get("system").SetPermissions(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -0700674
675 # Note that this call will mess up the tree of Items, so make sure
676 # we're done with it.
Hristo Bojinov96be7202010-08-02 10:26:17 -0700677 (source_symlinks, source_retouch_dummies) = CopySystemFiles(source_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700678 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
679
680 # Delete all the symlinks in source that aren't in target. This
681 # needs to happen before verbatim files are unpacked, in case a
682 # symlink in the source is replaced by a real file in the target.
683 to_delete = []
684 for dest, link in source_symlinks:
685 if link not in target_symlinks_d:
686 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700687 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -0700688
689 if verbatim_targets:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700690 script.Print("Unpacking new files...")
691 script.UnpackPackageDir("system", "/system")
692
Doug Zongker42265392010-02-12 10:21:00 -0800693 if updating_recovery:
694 script.Print("Unpacking new recovery...")
695 script.UnpackPackageDir("recovery", "/system")
696
Doug Zongker05d3dea2009-06-22 11:32:31 -0700697 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -0700698
699 # Create all the symlinks that don't already exist, or point to
700 # somewhere different than what we want. Delete each symlink before
701 # creating it, since the 'symlink' command won't overwrite.
702 to_create = []
703 for dest, link in target_symlinks:
704 if link in source_symlinks_d:
705 if dest != source_symlinks_d[link]:
706 to_create.append((dest, link))
707 else:
708 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700709 script.DeleteFiles([i[1] for i in to_create])
710 script.MakeSymlinks(to_create)
Hristo Bojinov96be7202010-08-02 10:26:17 -0700711 if OPTIONS.aslr_mode:
712 script.RetouchBinaries(target_retouch_files)
713 else:
714 script.UndoRetouchBinaries(target_retouch_files)
Doug Zongkereef39442009-04-02 12:14:19 -0700715
716 # Now that the symlinks are created, we can set all the
717 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700718 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -0700719
Doug Zongker881dd402009-09-20 14:03:55 -0700720 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -0700721 device_specific.IncrementalOTA_InstallEnd()
722
Doug Zongker1c390a22009-05-14 19:06:36 -0700723 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -0700724 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700725
Doug Zongkere92f15a2011-08-26 13:46:40 -0700726 # Patch the build.prop file last, so if something fails but the
727 # device can still come up, it appears to be the old build and will
728 # get set the OTA package again to retry.
729 script.Print("Patching remaining system files...")
730 for item in deferred_patch_list:
731 fn, tf, sf, size, _ = item
732 script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
733 script.SetPermissions("/system/build.prop", 0, 0, 0644)
734
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700735 script.AddToZip(target_zip, output_zip)
Doug Zongker2ea21062010-04-28 16:05:21 -0700736 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700737
738
739def main(argv):
740
741 def option_handler(o, a):
742 if o in ("-b", "--board_config"):
Doug Zongkerfdd8e692009-08-03 17:27:48 -0700743 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -0700744 elif o in ("-k", "--package_key"):
745 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -0700746 elif o in ("-i", "--incremental_from"):
747 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700748 elif o in ("-w", "--wipe_user_data"):
749 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -0700750 elif o in ("-n", "--no_prereq"):
751 OPTIONS.omit_prereq = True
Doug Zongker1c390a22009-05-14 19:06:36 -0700752 elif o in ("-e", "--extra_script"):
753 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700754 elif o in ("-a", "--aslr_mode"):
755 if a in ("on", "On", "true", "True", "yes", "Yes"):
756 OPTIONS.aslr_mode = True
757 else:
758 OPTIONS.aslr_mode = False
Doug Zongker761e6422009-09-25 10:45:39 -0700759 elif o in ("--worker_threads"):
760 OPTIONS.worker_threads = int(a)
Doug Zongkereef39442009-04-02 12:14:19 -0700761 else:
762 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700763 return True
Doug Zongkereef39442009-04-02 12:14:19 -0700764
765 args = common.ParseOptions(argv, __doc__,
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700766 extra_opts="b:k:i:d:wne:a:",
Doug Zongkereef39442009-04-02 12:14:19 -0700767 extra_long_opts=["board_config=",
768 "package_key=",
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700769 "incremental_from=",
Doug Zongker962069c2009-04-23 11:41:58 -0700770 "wipe_user_data",
Doug Zongker1c390a22009-05-14 19:06:36 -0700771 "no_prereq",
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700772 "extra_script=",
Hristo Bojinov96be7202010-08-02 10:26:17 -0700773 "worker_threads=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -0700774 "aslr_mode=",
775 ],
Doug Zongkereef39442009-04-02 12:14:19 -0700776 extra_option_handler=option_handler)
777
778 if len(args) != 2:
779 common.Usage(__doc__)
780 sys.exit(1)
781
Doug Zongker1c390a22009-05-14 19:06:36 -0700782 if OPTIONS.extra_script is not None:
783 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
784
Doug Zongkereef39442009-04-02 12:14:19 -0700785 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -0800786 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -0700787
Doug Zongkereef39442009-04-02 12:14:19 -0700788 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -0700789 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
790 if OPTIONS.verbose:
791 print "--- target info ---"
792 common.DumpInfoDict(OPTIONS.info_dict)
793
794 if OPTIONS.device_specific is None:
795 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
796 if OPTIONS.device_specific is not None:
797 OPTIONS.device_specific = os.path.normpath(OPTIONS.device_specific)
798 print "using device-specific extensions in", OPTIONS.device_specific
799
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700800 temp_zip_file = tempfile.NamedTemporaryFile()
801 output_zip = zipfile.ZipFile(temp_zip_file, "w",
802 compression=zipfile.ZIP_DEFLATED)
Doug Zongkereef39442009-04-02 12:14:19 -0700803
804 if OPTIONS.incremental_source is None:
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700805 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700806 if OPTIONS.package_key is None:
807 OPTIONS.package_key = OPTIONS.info_dict.get(
808 "default_system_dev_certificate",
809 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -0700810 else:
811 print "unzipping source target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -0800812 OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
Doug Zongker37974732010-09-16 17:44:38 -0700813 OPTIONS.target_info_dict = OPTIONS.info_dict
814 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700815 if OPTIONS.package_key is None:
Doug Zongker91b4f8a2011-09-23 12:48:33 -0700816 OPTIONS.package_key = OPTIONS.source_info_dict.get(
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700817 "default_system_dev_certificate",
818 "build/target/product/security/testkey")
Doug Zongker37974732010-09-16 17:44:38 -0700819 if OPTIONS.verbose:
820 print "--- source info ---"
821 common.DumpInfoDict(OPTIONS.source_info_dict)
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700822 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700823
824 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700825
826 SignOutput(temp_zip_file.name, args[1])
827 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -0700828
829 common.Cleanup()
830
831 print "done."
832
833
834if __name__ == '__main__':
835 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -0800836 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -0700837 main(sys.argv[1:])
838 except common.ExternalError, e:
839 print
840 print " ERROR: %s" % (e,)
841 print
842 sys.exit(1)