blob: 3cd271a7f1064953fad188b9e12b03374abf5384 [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
Doug Zongkereef39442009-04-02 12:14:19 -070055"""
56
57import sys
58
59if sys.hexversion < 0x02040000:
60 print >> sys.stderr, "Python 2.4 or newer is required."
61 sys.exit(1)
62
63import copy
Doug Zongkerc18736b2009-09-30 09:20:32 -070064import errno
Doug Zongkereef39442009-04-02 12:14:19 -070065import os
66import re
Doug Zongkereef39442009-04-02 12:14:19 -070067import subprocess
68import tempfile
69import time
70import zipfile
71
davidcad0bb92011-03-15 14:21:38 +000072try:
73 from hashlib import sha1 as sha1
74except ImportError:
75 from sha import sha as sha1
76
Doug Zongkereef39442009-04-02 12:14:19 -070077import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -070078import edify_generator
Doug Zongkereef39442009-04-02 12:14:19 -070079
80OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -070081OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -070082OPTIONS.incremental_source = None
83OPTIONS.require_verbatim = set()
84OPTIONS.prohibit_verbatim = set(("system/build.prop",))
85OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -070086OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -070087OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -070088OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -070089OPTIONS.aslr_mode = True
Doug Zongker761e6422009-09-25 10:45:39 -070090OPTIONS.worker_threads = 3
Doug Zongkereef39442009-04-02 12:14:19 -070091
92def MostPopularKey(d, default):
93 """Given a dict, return the key corresponding to the largest
94 value. Returns 'default' if the dict is empty."""
95 x = [(v, k) for (k, v) in d.iteritems()]
96 if not x: return default
97 x.sort()
98 return x[-1][1]
99
100
101def IsSymlink(info):
102 """Return true if the zipfile.ZipInfo object passed in represents a
103 symlink."""
104 return (info.external_attr >> 16) == 0120777
105
Hristo Bojinov96be7202010-08-02 10:26:17 -0700106def IsRegular(info):
107 """Return true if the zipfile.ZipInfo object passed in represents a
108 symlink."""
109 return (info.external_attr >> 28) == 010
Doug Zongkereef39442009-04-02 12:14:19 -0700110
Doug Zongkereef39442009-04-02 12:14:19 -0700111class Item:
112 """Items represent the metadata (user, group, mode) of files and
113 directories in the system image."""
114 ITEMS = {}
115 def __init__(self, name, dir=False):
116 self.name = name
117 self.uid = None
118 self.gid = None
119 self.mode = None
120 self.dir = dir
121
122 if name:
123 self.parent = Item.Get(os.path.dirname(name), dir=True)
124 self.parent.children.append(self)
125 else:
126 self.parent = None
127 if dir:
128 self.children = []
129
130 def Dump(self, indent=0):
131 if self.uid is not None:
132 print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode)
133 else:
134 print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode)
135 if self.dir:
136 print "%s%s" % (" "*indent, self.descendants)
137 print "%s%s" % (" "*indent, self.best_subtree)
138 for i in self.children:
139 i.Dump(indent=indent+1)
140
141 @classmethod
142 def Get(cls, name, dir=False):
143 if name not in cls.ITEMS:
144 cls.ITEMS[name] = Item(name, dir=dir)
145 return cls.ITEMS[name]
146
147 @classmethod
Doug Zongker283e2a12010-03-15 17:52:32 -0700148 def GetMetadata(cls, input_zip):
149
150 try:
151 # See if the target_files contains a record of what the uid,
152 # gid, and mode is supposed to be.
153 output = input_zip.read("META/filesystem_config.txt")
154 except KeyError:
155 # Run the external 'fs_config' program to determine the desired
156 # uid, gid, and mode for every Item object. Note this uses the
157 # one in the client now, which might not be the same as the one
158 # used when this target_files was built.
159 p = common.Run(["fs_config"], stdin=subprocess.PIPE,
160 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
161 suffix = { False: "", True: "/" }
162 input = "".join(["%s%s\n" % (i.name, suffix[i.dir])
163 for i in cls.ITEMS.itervalues() if i.name])
Doug Zongker3475d362010-03-17 16:39:30 -0700164 output, error = p.communicate(input)
Doug Zongker283e2a12010-03-15 17:52:32 -0700165 assert not error
Doug Zongkereef39442009-04-02 12:14:19 -0700166
167 for line in output.split("\n"):
168 if not line: continue
169 name, uid, gid, mode = line.split()
Doug Zongker283e2a12010-03-15 17:52:32 -0700170 i = cls.ITEMS.get(name, None)
171 if i is not None:
172 i.uid = int(uid)
173 i.gid = int(gid)
174 i.mode = int(mode, 8)
175 if i.dir:
176 i.children.sort(key=lambda i: i.name)
177
178 # set metadata for the files generated by this script.
179 i = cls.ITEMS.get("system/recovery-from-boot.p", None)
180 if i: i.uid, i.gid, i.mode = 0, 0, 0644
181 i = cls.ITEMS.get("system/etc/install-recovery.sh", None)
182 if i: i.uid, i.gid, i.mode = 0, 0, 0544
Doug Zongkereef39442009-04-02 12:14:19 -0700183
184 def CountChildMetadata(self):
185 """Count up the (uid, gid, mode) tuples for all children and
186 determine the best strategy for using set_perm_recursive and
187 set_perm to correctly chown/chmod all the files to their desired
188 values. Recursively calls itself for all descendants.
189
190 Returns a dict of {(uid, gid, dmode, fmode): count} counting up
191 all descendants of this node. (dmode or fmode may be None.) Also
192 sets the best_subtree of each directory Item to the (uid, gid,
193 dmode, fmode) tuple that will match the most descendants of that
194 Item.
195 """
196
197 assert self.dir
198 d = self.descendants = {(self.uid, self.gid, self.mode, None): 1}
199 for i in self.children:
200 if i.dir:
201 for k, v in i.CountChildMetadata().iteritems():
202 d[k] = d.get(k, 0) + v
203 else:
204 k = (i.uid, i.gid, None, i.mode)
205 d[k] = d.get(k, 0) + 1
206
207 # Find the (uid, gid, dmode, fmode) tuple that matches the most
208 # descendants.
209
210 # First, find the (uid, gid) pair that matches the most
211 # descendants.
212 ug = {}
213 for (uid, gid, _, _), count in d.iteritems():
214 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
215 ug = MostPopularKey(ug, (0, 0))
216
217 # Now find the dmode and fmode that match the most descendants
218 # with that (uid, gid), and choose those.
219 best_dmode = (0, 0755)
220 best_fmode = (0, 0644)
221 for k, count in d.iteritems():
222 if k[:2] != ug: continue
223 if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2])
224 if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3])
225 self.best_subtree = ug + (best_dmode[1], best_fmode[1])
226
227 return d
228
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700229 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700230 """Append set_perm/set_perm_recursive commands to 'script' to
231 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700232 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700233
234 self.CountChildMetadata()
235
236 def recurse(item, current):
237 # current is the (uid, gid, dmode, fmode) tuple that the current
238 # item (and all its children) have already been set to. We only
239 # need to issue set_perm/set_perm_recursive commands if we're
240 # supposed to be something different.
241 if item.dir:
242 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700243 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700244 current = item.best_subtree
245
246 if item.uid != current[0] or item.gid != current[1] or \
247 item.mode != current[2]:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700248 script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode)
Doug Zongkereef39442009-04-02 12:14:19 -0700249
250 for i in item.children:
251 recurse(i, current)
252 else:
253 if item.uid != current[0] or item.gid != current[1] or \
254 item.mode != current[3]:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700255 script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode)
Doug Zongkereef39442009-04-02 12:14:19 -0700256
257 recurse(self, (-1, -1, -1, -1))
258
259
260def CopySystemFiles(input_zip, output_zip=None,
261 substitute=None):
262 """Copies files underneath system/ in the input zip to the output
263 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800264 list of symlinks. output_zip may be None, in which case the copy is
265 skipped (but the other side effects still happen). substitute is an
266 optional dict of {output filename: contents} to be output instead of
267 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700268 """
269
270 symlinks = []
271
272 for info in input_zip.infolist():
273 if info.filename.startswith("SYSTEM/"):
274 basefilename = info.filename[7:]
275 if IsSymlink(info):
276 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700277 "/system/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700278 else:
279 info2 = copy.copy(info)
280 fn = info2.filename = "system/" + basefilename
281 if substitute and fn in substitute and substitute[fn] is None:
282 continue
283 if output_zip is not None:
284 if substitute and fn in substitute:
285 data = substitute[fn]
286 else:
287 data = input_zip.read(info.filename)
288 output_zip.writestr(info2, data)
289 if fn.endswith("/"):
290 Item.Get(fn[:-1], dir=True)
291 else:
292 Item.Get(fn, dir=False)
293
294 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800295 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700296
297
Doug Zongkereef39442009-04-02 12:14:19 -0700298def SignOutput(temp_zip_name, output_zip_name):
299 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
300 pw = key_passwords[OPTIONS.package_key]
301
Doug Zongker951495f2009-08-14 12:44:19 -0700302 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
303 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700304
305
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700306def AppendAssertions(script, info_dict):
307 device = GetBuildProp("ro.product.device", info_dict)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700308 script.AssertDevice(device)
Doug Zongkereef39442009-04-02 12:14:19 -0700309
Doug Zongkereef39442009-04-02 12:14:19 -0700310
Doug Zongker486de122010-09-16 14:01:56 -0700311def MakeRecoveryPatch(output_zip, recovery_img, boot_img):
Doug Zongker73ef8252009-07-23 15:12:53 -0700312 """Generate a binary patch that creates the recovery image starting
313 with the boot image. (Most of the space in these images is just the
314 kernel, which is identical for the two, so the resulting patch
315 should be efficient.) Add it to the output zip, along with a shell
316 script that is run from init.rc on first boot to actually do the
317 patching and install the new recovery image.
318
319 recovery_img and boot_img should be File objects for the
Doug Zongker67369982010-07-07 13:53:32 -0700320 corresponding images. info should be the dictionary returned by
321 common.LoadInfoDict() on the input target_files.
Doug Zongker73ef8252009-07-23 15:12:53 -0700322
323 Returns an Item for the shell script, which must be made
324 executable.
325 """
326
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700327 d = common.Difference(recovery_img, boot_img)
Doug Zongker761e6422009-09-25 10:45:39 -0700328 _, _, patch = d.ComputePatch()
Doug Zongkercfd7db62009-10-07 11:35:53 -0700329 common.ZipWriteStr(output_zip, "recovery/recovery-from-boot.p", patch)
Doug Zongker73ef8252009-07-23 15:12:53 -0700330 Item.Get("system/recovery-from-boot.p", dir=False)
331
Doug Zongker96a57e72010-09-26 14:57:41 -0700332 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
333 recovery_type, recovery_device = common.GetTypeAndDevice("/recovery", OPTIONS.info_dict)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700334
Doug Zongker73ef8252009-07-23 15:12:53 -0700335 sh = """#!/system/bin/sh
Doug Zongker0276d182011-12-02 10:46:59 -0800336if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then
Doug Zongker73ef8252009-07-23 15:12:53 -0700337 log -t recovery "Installing new recovery image"
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700338 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 -0700339else
340 log -t recovery "Recovery image already installed"
341fi
342""" % { 'boot_size': boot_img.size,
343 'boot_sha1': boot_img.sha1,
Doug Zongker73ef8252009-07-23 15:12:53 -0700344 'recovery_size': recovery_img.size,
Doug Zongker67369982010-07-07 13:53:32 -0700345 'recovery_sha1': recovery_img.sha1,
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700346 'boot_type': boot_type,
347 'boot_device': boot_device,
348 'recovery_type': recovery_type,
349 'recovery_device': recovery_device,
Doug Zongker67369982010-07-07 13:53:32 -0700350 }
Doug Zongkercfd7db62009-10-07 11:35:53 -0700351 common.ZipWriteStr(output_zip, "recovery/etc/install-recovery.sh", sh)
Doug Zongker73ef8252009-07-23 15:12:53 -0700352 return Item.Get("system/etc/install-recovery.sh", dir=False)
353
354
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700355def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700356 # TODO: how to determine this? We don't know what version it will
357 # be installed on top of. For now, we expect the API just won't
358 # change very often.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700359 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700360
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700361 metadata = {"post-build": GetBuildProp("ro.build.fingerprint",
362 OPTIONS.info_dict),
363 "pre-device": GetBuildProp("ro.product.device",
364 OPTIONS.info_dict),
365 "post-timestamp": GetBuildProp("ro.build.date.utc",
366 OPTIONS.info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700367 }
368
Doug Zongker05d3dea2009-06-22 11:32:31 -0700369 device_specific = common.DeviceSpecificParams(
370 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700371 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700372 output_zip=output_zip,
373 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700374 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700375 metadata=metadata,
376 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700377
Doug Zongker962069c2009-04-23 11:41:58 -0700378 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700379 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700380 script.AssertOlderBuild(ts)
Doug Zongkereef39442009-04-02 12:14:19 -0700381
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700382 AppendAssertions(script, OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700383 device_specific.FullOTA_Assertions()
Doug Zongkere5ff5902012-01-17 10:55:37 -0800384 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700385
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700386 script.ShowProgress(0.5, 0)
Doug Zongkereef39442009-04-02 12:14:19 -0700387
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700388 if OPTIONS.wipe_user_data:
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700389 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700390
Kenny Rootf32dc712012-04-08 10:42:34 -0700391 if "selinux_fc" in OPTIONS.info_dict:
392 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500393
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700394 script.FormatPartition("/system")
395 script.Mount("/system")
Doug Zongkercfd7db62009-10-07 11:35:53 -0700396 script.UnpackPackageDir("recovery", "/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700397 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700398
Doug Zongker1807e702012-02-28 12:21:08 -0800399 symlinks = CopySystemFiles(input_zip, output_zip)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700400 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700401
Doug Zongker55d93282011-01-25 17:03:34 -0800402 boot_img = common.GetBootableImage("boot.img", "boot.img",
403 OPTIONS.input_tmp, "BOOT")
404 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
405 OPTIONS.input_tmp, "RECOVERY")
Doug Zongker486de122010-09-16 14:01:56 -0700406 MakeRecoveryPatch(output_zip, recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700407
Doug Zongker283e2a12010-03-15 17:52:32 -0700408 Item.GetMetadata(input_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700409 Item.Get("system").SetPermissions(script)
410
Doug Zongker37974732010-09-16 17:44:38 -0700411 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700412 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700413 script.ShowProgress(0.2, 0)
414
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700415 script.ShowProgress(0.2, 10)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700416 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700417
418 script.ShowProgress(0.1, 0)
419 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700420
Doug Zongker1c390a22009-05-14 19:06:36 -0700421 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700422 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700423
Doug Zongker14833602010-02-02 13:12:04 -0800424 script.UnmountAll()
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700425 script.AddToZip(input_zip, output_zip)
Doug Zongker2ea21062010-04-28 16:05:21 -0700426 WriteMetadata(metadata, output_zip)
427
Stephen Smalley56882bf2012-02-09 13:36:21 -0500428def WritePolicyConfig(file_context, output_zip):
429 f = open(file_context, 'r');
430 basename = os.path.basename(file_context)
431 common.ZipWriteStr(output_zip, basename, f.read())
432
Doug Zongker2ea21062010-04-28 16:05:21 -0700433
434def WriteMetadata(metadata, output_zip):
435 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
436 "".join(["%s=%s\n" % kv
437 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700438
Doug Zongkereef39442009-04-02 12:14:19 -0700439def 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 = {}
443 for info in z.infolist():
444 if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
Hristo Bojinov96be7202010-08-02 10:26:17 -0700445 basefilename = info.filename[7:]
446 fn = "system/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700447 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700448 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800449 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700450
451
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700452def GetBuildProp(prop, info_dict):
453 """Return the fingerprint of the build of a given target-files info_dict."""
454 try:
455 return info_dict.get("build.prop", {})[prop]
456 except KeyError:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700457 raise common.ExternalError("couldn't find %s in build.prop" % (property,))
Doug Zongkereef39442009-04-02 12:14:19 -0700458
459
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700460def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Doug Zongker37974732010-09-16 17:44:38 -0700461 source_version = OPTIONS.source_info_dict["recovery_api_version"]
462 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700463
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700464 if source_version == 0:
465 print ("WARNING: generating edify script for a source that "
466 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700467 script = edify_generator.EdifyGenerator(source_version,
468 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700469
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700470 metadata = {"pre-device": GetBuildProp("ro.product.device",
471 OPTIONS.source_info_dict),
472 "post-timestamp": GetBuildProp("ro.build.date.utc",
473 OPTIONS.target_info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700474 }
475
Doug Zongker05d3dea2009-06-22 11:32:31 -0700476 device_specific = common.DeviceSpecificParams(
477 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800478 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700479 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800480 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700481 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -0700482 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -0700483 metadata=metadata,
484 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700485
Doug Zongkereef39442009-04-02 12:14:19 -0700486 print "Loading target..."
Doug Zongker1807e702012-02-28 12:21:08 -0800487 target_data = LoadSystemFiles(target_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700488 print "Loading source..."
Doug Zongker1807e702012-02-28 12:21:08 -0800489 source_data = LoadSystemFiles(source_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700490
491 verbatim_targets = []
492 patch_list = []
Doug Zongker761e6422009-09-25 10:45:39 -0700493 diffs = []
Doug Zongkereef39442009-04-02 12:14:19 -0700494 largest_source_size = 0
495 for fn in sorted(target_data.keys()):
496 tf = target_data[fn]
Doug Zongker761e6422009-09-25 10:45:39 -0700497 assert fn == tf.name
Doug Zongkereef39442009-04-02 12:14:19 -0700498 sf = source_data.get(fn, None)
499
500 if sf is None or fn in OPTIONS.require_verbatim:
501 # This file should be included verbatim
502 if fn in OPTIONS.prohibit_verbatim:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700503 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
Doug Zongkereef39442009-04-02 12:14:19 -0700504 print "send", fn, "verbatim"
505 tf.AddToZip(output_zip)
506 verbatim_targets.append((fn, tf.size))
507 elif tf.sha1 != sf.sha1:
508 # File is different; consider sending as a patch
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700509 diffs.append(common.Difference(tf, sf))
Doug Zongkereef39442009-04-02 12:14:19 -0700510 else:
511 # Target file identical to source.
512 pass
513
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700514 common.ComputeDifferences(diffs)
Doug Zongker761e6422009-09-25 10:45:39 -0700515
516 for diff in diffs:
517 tf, sf, d = diff.GetPatch()
518 if d is None or len(d) > tf.size * OPTIONS.patch_threshold:
519 # patch is almost as big as the file; don't bother patching
520 tf.AddToZip(output_zip)
521 verbatim_targets.append((tf.name, tf.size))
522 else:
523 common.ZipWriteStr(output_zip, "patch/" + tf.name + ".p", d)
Doug Zongker55d93282011-01-25 17:03:34 -0800524 patch_list.append((tf.name, tf, sf, tf.size, common.sha1(d).hexdigest()))
Doug Zongker761e6422009-09-25 10:45:39 -0700525 largest_source_size = max(largest_source_size, sf.size)
Doug Zongkereef39442009-04-02 12:14:19 -0700526
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700527 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
528 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
Doug Zongker2ea21062010-04-28 16:05:21 -0700529 metadata["pre-build"] = source_fp
530 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -0700531
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700532 script.Mount("/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700533 script.AssertSomeFingerprint(source_fp, target_fp)
Doug Zongkereef39442009-04-02 12:14:19 -0700534
Doug Zongker55d93282011-01-25 17:03:34 -0800535 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700536 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
537 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -0800538 target_boot = common.GetBootableImage(
539 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker5da317e2009-06-02 13:38:17 -0700540 updating_boot = (source_boot.data != target_boot.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700541
Doug Zongker55d93282011-01-25 17:03:34 -0800542 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700543 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
544 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -0800545 target_recovery = common.GetBootableImage(
546 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -0700547 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700548
Doug Zongker881dd402009-09-20 14:03:55 -0700549 # Here's how we divide up the progress bar:
550 # 0.1 for verifying the start state (PatchCheck calls)
551 # 0.8 for applying patches (ApplyPatch calls)
552 # 0.1 for unpacking verbatim files, symlinking, and doing the
553 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -0700554
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700555 AppendAssertions(script, OPTIONS.target_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700556 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -0700557
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700558 script.Print("Verifying current system...")
559
Doug Zongkere5ff5902012-01-17 10:55:37 -0800560 device_specific.IncrementalOTA_VerifyBegin()
561
Doug Zongker881dd402009-09-20 14:03:55 -0700562 script.ShowProgress(0.1, 0)
563 total_verify_size = float(sum([i[2].size for i in patch_list]) + 1)
564 if updating_boot:
565 total_verify_size += source_boot.size
566 so_far = 0
Doug Zongkereef39442009-04-02 12:14:19 -0700567
Doug Zongker5a482092010-02-17 16:09:18 -0800568 for fn, tf, sf, size, patch_sha in patch_list:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700569 script.PatchCheck("/"+fn, tf.sha1, sf.sha1)
Doug Zongker881dd402009-09-20 14:03:55 -0700570 so_far += sf.size
571 script.SetProgress(so_far / total_verify_size)
Doug Zongkereef39442009-04-02 12:14:19 -0700572
Doug Zongker5da317e2009-06-02 13:38:17 -0700573 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700574 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -0700575 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -0700576 print "boot target: %d source: %d diff: %d" % (
577 target_boot.size, source_boot.size, len(d))
578
Doug Zongker048e7ca2009-06-15 14:31:53 -0700579 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -0700580
Doug Zongker96a57e72010-09-26 14:57:41 -0700581 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -0700582
583 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
584 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -0700585 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700586 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -0700587 so_far += source_boot.size
588 script.SetProgress(so_far / total_verify_size)
Doug Zongker5da317e2009-06-02 13:38:17 -0700589
590 if patch_list or updating_recovery or updating_boot:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700591 script.CacheFreeSpaceCheck(largest_source_size)
Doug Zongker5a482092010-02-17 16:09:18 -0800592
Doug Zongker05d3dea2009-06-22 11:32:31 -0700593 device_specific.IncrementalOTA_VerifyEnd()
594
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700595 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -0700596
Doug Zongkere5ff5902012-01-17 10:55:37 -0800597 device_specific.IncrementalOTA_InstallBegin()
598
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700599 if OPTIONS.wipe_user_data:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700600 script.Print("Erasing user data...")
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700601 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700602
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700603 script.Print("Removing unneeded files...")
Doug Zongker0f3298a2009-06-30 08:16:58 -0700604 script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
605 ["/"+i for i in sorted(source_data)
Doug Zongker3b949f02009-08-24 10:24:32 -0700606 if i not in target_data] +
607 ["/system/recovery.img"])
Doug Zongkereef39442009-04-02 12:14:19 -0700608
Doug Zongker881dd402009-09-20 14:03:55 -0700609 script.ShowProgress(0.8, 0)
610 total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
611 if updating_boot:
612 total_patch_size += target_boot.size
613 so_far = 0
614
615 script.Print("Patching system files...")
Doug Zongkere92f15a2011-08-26 13:46:40 -0700616 deferred_patch_list = []
617 for item in patch_list:
618 fn, tf, sf, size, _ = item
619 if tf.name == "system/build.prop":
620 deferred_patch_list.append(item)
621 continue
Doug Zongkerc8d446b2010-02-22 15:41:53 -0800622 script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
Doug Zongker881dd402009-09-20 14:03:55 -0700623 so_far += tf.size
624 script.SetProgress(so_far / total_patch_size)
625
Doug Zongkereef39442009-04-02 12:14:19 -0700626 if updating_boot:
Doug Zongker5da317e2009-06-02 13:38:17 -0700627 # Produce the boot image by applying a patch to the current
628 # contents of the boot partition, and write it back to the
629 # partition.
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700630 script.Print("Patching boot image...")
Doug Zongkerf2ab2902010-09-22 10:12:54 -0700631 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
632 % (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -0700633 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700634 target_boot.size, target_boot.sha1),
635 "-",
636 target_boot.size, target_boot.sha1,
Doug Zongkerc8d446b2010-02-22 15:41:53 -0800637 source_boot.sha1, "patch/boot.img.p")
Doug Zongker881dd402009-09-20 14:03:55 -0700638 so_far += target_boot.size
639 script.SetProgress(so_far / total_patch_size)
Doug Zongkereef39442009-04-02 12:14:19 -0700640 print "boot image changed; including."
641 else:
642 print "boot image unchanged; skipping."
643
644 if updating_recovery:
Doug Zongker73ef8252009-07-23 15:12:53 -0700645 # Is it better to generate recovery as a patch from the current
646 # boot image, or from the previous recovery image? For large
647 # updates with significant kernel changes, probably the former.
648 # For small updates where the kernel hasn't changed, almost
649 # certainly the latter. We pick the first option. Future
650 # complicated schemes may let us effectively use both.
651 #
652 # A wacky possibility: as long as there is room in the boot
653 # partition, include the binaries and image files from recovery in
654 # the boot image (though not in the ramdisk) so they can be used
655 # as fodder for constructing the recovery image.
Doug Zongker486de122010-09-16 14:01:56 -0700656 MakeRecoveryPatch(output_zip, target_recovery, target_boot)
Doug Zongker42265392010-02-12 10:21:00 -0800657 script.DeleteFiles(["/system/recovery-from-boot.p",
658 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -0700659 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -0700660 else:
661 print "recovery image unchanged; skipping."
662
Doug Zongker881dd402009-09-20 14:03:55 -0700663 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -0700664
Doug Zongker1807e702012-02-28 12:21:08 -0800665 target_symlinks = CopySystemFiles(target_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700666
667 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700668 temp_script = script.MakeTemporary()
Doug Zongker283e2a12010-03-15 17:52:32 -0700669 Item.GetMetadata(target_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700670 Item.Get("system").SetPermissions(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -0700671
672 # Note that this call will mess up the tree of Items, so make sure
673 # we're done with it.
Doug Zongker1807e702012-02-28 12:21:08 -0800674 source_symlinks = CopySystemFiles(source_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700675 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
676
677 # Delete all the symlinks in source that aren't in target. This
678 # needs to happen before verbatim files are unpacked, in case a
679 # symlink in the source is replaced by a real file in the target.
680 to_delete = []
681 for dest, link in source_symlinks:
682 if link not in target_symlinks_d:
683 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700684 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -0700685
686 if verbatim_targets:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700687 script.Print("Unpacking new files...")
688 script.UnpackPackageDir("system", "/system")
689
Doug Zongker42265392010-02-12 10:21:00 -0800690 if updating_recovery:
691 script.Print("Unpacking new recovery...")
692 script.UnpackPackageDir("recovery", "/system")
693
Doug Zongker05d3dea2009-06-22 11:32:31 -0700694 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -0700695
696 # Create all the symlinks that don't already exist, or point to
697 # somewhere different than what we want. Delete each symlink before
698 # creating it, since the 'symlink' command won't overwrite.
699 to_create = []
700 for dest, link in target_symlinks:
701 if link in source_symlinks_d:
702 if dest != source_symlinks_d[link]:
703 to_create.append((dest, link))
704 else:
705 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700706 script.DeleteFiles([i[1] for i in to_create])
707 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -0700708
709 # Now that the symlinks are created, we can set all the
710 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700711 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -0700712
Doug Zongker881dd402009-09-20 14:03:55 -0700713 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -0700714 device_specific.IncrementalOTA_InstallEnd()
715
Doug Zongker1c390a22009-05-14 19:06:36 -0700716 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -0700717 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700718
Doug Zongkere92f15a2011-08-26 13:46:40 -0700719 # Patch the build.prop file last, so if something fails but the
720 # device can still come up, it appears to be the old build and will
721 # get set the OTA package again to retry.
722 script.Print("Patching remaining system files...")
723 for item in deferred_patch_list:
724 fn, tf, sf, size, _ = item
725 script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
726 script.SetPermissions("/system/build.prop", 0, 0, 0644)
727
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700728 script.AddToZip(target_zip, output_zip)
Doug Zongker2ea21062010-04-28 16:05:21 -0700729 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700730
731
732def main(argv):
733
734 def option_handler(o, a):
735 if o in ("-b", "--board_config"):
Doug Zongkerfdd8e692009-08-03 17:27:48 -0700736 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -0700737 elif o in ("-k", "--package_key"):
738 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -0700739 elif o in ("-i", "--incremental_from"):
740 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700741 elif o in ("-w", "--wipe_user_data"):
742 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -0700743 elif o in ("-n", "--no_prereq"):
744 OPTIONS.omit_prereq = True
Doug Zongker1c390a22009-05-14 19:06:36 -0700745 elif o in ("-e", "--extra_script"):
746 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700747 elif o in ("-a", "--aslr_mode"):
748 if a in ("on", "On", "true", "True", "yes", "Yes"):
749 OPTIONS.aslr_mode = True
750 else:
751 OPTIONS.aslr_mode = False
Doug Zongker761e6422009-09-25 10:45:39 -0700752 elif o in ("--worker_threads"):
753 OPTIONS.worker_threads = int(a)
Doug Zongkereef39442009-04-02 12:14:19 -0700754 else:
755 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700756 return True
Doug Zongkereef39442009-04-02 12:14:19 -0700757
758 args = common.ParseOptions(argv, __doc__,
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700759 extra_opts="b:k:i:d:wne:a:",
Doug Zongkereef39442009-04-02 12:14:19 -0700760 extra_long_opts=["board_config=",
761 "package_key=",
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700762 "incremental_from=",
Doug Zongker962069c2009-04-23 11:41:58 -0700763 "wipe_user_data",
Doug Zongker1c390a22009-05-14 19:06:36 -0700764 "no_prereq",
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700765 "extra_script=",
Hristo Bojinov96be7202010-08-02 10:26:17 -0700766 "worker_threads=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -0700767 "aslr_mode=",
768 ],
Doug Zongkereef39442009-04-02 12:14:19 -0700769 extra_option_handler=option_handler)
770
771 if len(args) != 2:
772 common.Usage(__doc__)
773 sys.exit(1)
774
Doug Zongker1c390a22009-05-14 19:06:36 -0700775 if OPTIONS.extra_script is not None:
776 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
777
Doug Zongkereef39442009-04-02 12:14:19 -0700778 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -0800779 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -0700780
Doug Zongkereef39442009-04-02 12:14:19 -0700781 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -0700782 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
783 if OPTIONS.verbose:
784 print "--- target info ---"
785 common.DumpInfoDict(OPTIONS.info_dict)
786
787 if OPTIONS.device_specific is None:
788 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
789 if OPTIONS.device_specific is not None:
790 OPTIONS.device_specific = os.path.normpath(OPTIONS.device_specific)
791 print "using device-specific extensions in", OPTIONS.device_specific
792
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700793 temp_zip_file = tempfile.NamedTemporaryFile()
794 output_zip = zipfile.ZipFile(temp_zip_file, "w",
795 compression=zipfile.ZIP_DEFLATED)
Doug Zongkereef39442009-04-02 12:14:19 -0700796
797 if OPTIONS.incremental_source is None:
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700798 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700799 if OPTIONS.package_key is None:
800 OPTIONS.package_key = OPTIONS.info_dict.get(
801 "default_system_dev_certificate",
802 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -0700803 else:
804 print "unzipping source target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -0800805 OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
Doug Zongker37974732010-09-16 17:44:38 -0700806 OPTIONS.target_info_dict = OPTIONS.info_dict
807 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700808 if OPTIONS.package_key is None:
Doug Zongker91b4f8a2011-09-23 12:48:33 -0700809 OPTIONS.package_key = OPTIONS.source_info_dict.get(
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700810 "default_system_dev_certificate",
811 "build/target/product/security/testkey")
Doug Zongker37974732010-09-16 17:44:38 -0700812 if OPTIONS.verbose:
813 print "--- source info ---"
814 common.DumpInfoDict(OPTIONS.source_info_dict)
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700815 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700816
817 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700818
819 SignOutput(temp_zip_file.name, args[1])
820 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -0700821
822 common.Cleanup()
823
824 print "done."
825
826
827if __name__ == '__main__':
828 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -0800829 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -0700830 main(sys.argv[1:])
831 except common.ExternalError, e:
832 print
833 print " ERROR: %s" % (e,)
834 print
835 sys.exit(1)