blob: 7e855ce026b161da28135e2d55787b01ab3d6745 [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.
Doug Zongkereef39442009-04-02 12:14:19 -070051"""
52
53import sys
54
55if sys.hexversion < 0x02040000:
56 print >> sys.stderr, "Python 2.4 or newer is required."
57 sys.exit(1)
58
59import copy
Doug Zongkerc18736b2009-09-30 09:20:32 -070060import errno
Doug Zongkereef39442009-04-02 12:14:19 -070061import os
62import re
Doug Zongkereef39442009-04-02 12:14:19 -070063import subprocess
64import tempfile
65import time
66import zipfile
67
davidcad0bb92011-03-15 14:21:38 +000068try:
69 from hashlib import sha1 as sha1
70except ImportError:
71 from sha import sha as sha1
72
Doug Zongkereef39442009-04-02 12:14:19 -070073import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -070074import edify_generator
Doug Zongkereef39442009-04-02 12:14:19 -070075
76OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -070077OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -070078OPTIONS.incremental_source = None
79OPTIONS.require_verbatim = set()
80OPTIONS.prohibit_verbatim = set(("system/build.prop",))
81OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -070082OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -070083OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -070084OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -070085OPTIONS.aslr_mode = True
Doug Zongker761e6422009-09-25 10:45:39 -070086OPTIONS.worker_threads = 3
Doug Zongkereef39442009-04-02 12:14:19 -070087
88def MostPopularKey(d, default):
89 """Given a dict, return the key corresponding to the largest
90 value. Returns 'default' if the dict is empty."""
91 x = [(v, k) for (k, v) in d.iteritems()]
92 if not x: return default
93 x.sort()
94 return x[-1][1]
95
96
97def IsSymlink(info):
98 """Return true if the zipfile.ZipInfo object passed in represents a
99 symlink."""
100 return (info.external_attr >> 16) == 0120777
101
Hristo Bojinov96be7202010-08-02 10:26:17 -0700102def IsRegular(info):
103 """Return true if the zipfile.ZipInfo object passed in represents a
104 symlink."""
105 return (info.external_attr >> 28) == 010
Doug Zongkereef39442009-04-02 12:14:19 -0700106
Doug Zongkereef39442009-04-02 12:14:19 -0700107class Item:
108 """Items represent the metadata (user, group, mode) of files and
109 directories in the system image."""
110 ITEMS = {}
111 def __init__(self, name, dir=False):
112 self.name = name
113 self.uid = None
114 self.gid = None
115 self.mode = None
116 self.dir = dir
117
118 if name:
119 self.parent = Item.Get(os.path.dirname(name), dir=True)
120 self.parent.children.append(self)
121 else:
122 self.parent = None
123 if dir:
124 self.children = []
125
126 def Dump(self, indent=0):
127 if self.uid is not None:
128 print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode)
129 else:
130 print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode)
131 if self.dir:
132 print "%s%s" % (" "*indent, self.descendants)
133 print "%s%s" % (" "*indent, self.best_subtree)
134 for i in self.children:
135 i.Dump(indent=indent+1)
136
137 @classmethod
138 def Get(cls, name, dir=False):
139 if name not in cls.ITEMS:
140 cls.ITEMS[name] = Item(name, dir=dir)
141 return cls.ITEMS[name]
142
143 @classmethod
Doug Zongker283e2a12010-03-15 17:52:32 -0700144 def GetMetadata(cls, input_zip):
145
146 try:
147 # See if the target_files contains a record of what the uid,
148 # gid, and mode is supposed to be.
149 output = input_zip.read("META/filesystem_config.txt")
150 except KeyError:
151 # Run the external 'fs_config' program to determine the desired
152 # uid, gid, and mode for every Item object. Note this uses the
153 # one in the client now, which might not be the same as the one
154 # used when this target_files was built.
155 p = common.Run(["fs_config"], stdin=subprocess.PIPE,
156 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
157 suffix = { False: "", True: "/" }
158 input = "".join(["%s%s\n" % (i.name, suffix[i.dir])
159 for i in cls.ITEMS.itervalues() if i.name])
Doug Zongker3475d362010-03-17 16:39:30 -0700160 output, error = p.communicate(input)
Doug Zongker283e2a12010-03-15 17:52:32 -0700161 assert not error
Doug Zongkereef39442009-04-02 12:14:19 -0700162
163 for line in output.split("\n"):
164 if not line: continue
165 name, uid, gid, mode = line.split()
Doug Zongker283e2a12010-03-15 17:52:32 -0700166 i = cls.ITEMS.get(name, None)
167 if i is not None:
168 i.uid = int(uid)
169 i.gid = int(gid)
170 i.mode = int(mode, 8)
171 if i.dir:
172 i.children.sort(key=lambda i: i.name)
173
174 # set metadata for the files generated by this script.
175 i = cls.ITEMS.get("system/recovery-from-boot.p", None)
176 if i: i.uid, i.gid, i.mode = 0, 0, 0644
177 i = cls.ITEMS.get("system/etc/install-recovery.sh", None)
178 if i: i.uid, i.gid, i.mode = 0, 0, 0544
Doug Zongkereef39442009-04-02 12:14:19 -0700179
180 def CountChildMetadata(self):
181 """Count up the (uid, gid, mode) tuples for all children and
182 determine the best strategy for using set_perm_recursive and
183 set_perm to correctly chown/chmod all the files to their desired
184 values. Recursively calls itself for all descendants.
185
186 Returns a dict of {(uid, gid, dmode, fmode): count} counting up
187 all descendants of this node. (dmode or fmode may be None.) Also
188 sets the best_subtree of each directory Item to the (uid, gid,
189 dmode, fmode) tuple that will match the most descendants of that
190 Item.
191 """
192
193 assert self.dir
194 d = self.descendants = {(self.uid, self.gid, self.mode, None): 1}
195 for i in self.children:
196 if i.dir:
197 for k, v in i.CountChildMetadata().iteritems():
198 d[k] = d.get(k, 0) + v
199 else:
200 k = (i.uid, i.gid, None, i.mode)
201 d[k] = d.get(k, 0) + 1
202
203 # Find the (uid, gid, dmode, fmode) tuple that matches the most
204 # descendants.
205
206 # First, find the (uid, gid) pair that matches the most
207 # descendants.
208 ug = {}
209 for (uid, gid, _, _), count in d.iteritems():
210 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
211 ug = MostPopularKey(ug, (0, 0))
212
213 # Now find the dmode and fmode that match the most descendants
214 # with that (uid, gid), and choose those.
215 best_dmode = (0, 0755)
216 best_fmode = (0, 0644)
217 for k, count in d.iteritems():
218 if k[:2] != ug: continue
219 if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2])
220 if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3])
221 self.best_subtree = ug + (best_dmode[1], best_fmode[1])
222
223 return d
224
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700225 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700226 """Append set_perm/set_perm_recursive commands to 'script' to
227 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700228 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700229
230 self.CountChildMetadata()
231
232 def recurse(item, current):
233 # current is the (uid, gid, dmode, fmode) tuple that the current
234 # item (and all its children) have already been set to. We only
235 # need to issue set_perm/set_perm_recursive commands if we're
236 # supposed to be something different.
237 if item.dir:
238 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700239 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700240 current = item.best_subtree
241
242 if item.uid != current[0] or item.gid != current[1] or \
243 item.mode != current[2]:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700244 script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode)
Doug Zongkereef39442009-04-02 12:14:19 -0700245
246 for i in item.children:
247 recurse(i, current)
248 else:
249 if item.uid != current[0] or item.gid != current[1] or \
250 item.mode != current[3]:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700251 script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode)
Doug Zongkereef39442009-04-02 12:14:19 -0700252
253 recurse(self, (-1, -1, -1, -1))
254
255
256def CopySystemFiles(input_zip, output_zip=None,
257 substitute=None):
258 """Copies files underneath system/ in the input zip to the output
259 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800260 list of symlinks. output_zip may be None, in which case the copy is
261 skipped (but the other side effects still happen). substitute is an
262 optional dict of {output filename: contents} to be output instead of
263 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700264 """
265
266 symlinks = []
267
268 for info in input_zip.infolist():
269 if info.filename.startswith("SYSTEM/"):
270 basefilename = info.filename[7:]
271 if IsSymlink(info):
272 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700273 "/system/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700274 else:
275 info2 = copy.copy(info)
276 fn = info2.filename = "system/" + basefilename
277 if substitute and fn in substitute and substitute[fn] is None:
278 continue
279 if output_zip is not None:
280 if substitute and fn in substitute:
281 data = substitute[fn]
282 else:
283 data = input_zip.read(info.filename)
284 output_zip.writestr(info2, data)
285 if fn.endswith("/"):
286 Item.Get(fn[:-1], dir=True)
287 else:
288 Item.Get(fn, dir=False)
289
290 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800291 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700292
293
Doug Zongkereef39442009-04-02 12:14:19 -0700294def SignOutput(temp_zip_name, output_zip_name):
295 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
296 pw = key_passwords[OPTIONS.package_key]
297
Doug Zongker951495f2009-08-14 12:44:19 -0700298 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
299 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700300
301
Doug Zongkereef39442009-04-02 12:14:19 -0700302def AppendAssertions(script, input_zip):
Doug Zongkereef39442009-04-02 12:14:19 -0700303 device = GetBuildProp("ro.product.device", input_zip)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700304 script.AssertDevice(device)
Doug Zongkereef39442009-04-02 12:14:19 -0700305
Doug Zongkereef39442009-04-02 12:14:19 -0700306
Doug Zongker486de122010-09-16 14:01:56 -0700307def MakeRecoveryPatch(output_zip, recovery_img, boot_img):
Doug Zongker73ef8252009-07-23 15:12:53 -0700308 """Generate a binary patch that creates the recovery image starting
309 with the boot image. (Most of the space in these images is just the
310 kernel, which is identical for the two, so the resulting patch
311 should be efficient.) Add it to the output zip, along with a shell
312 script that is run from init.rc on first boot to actually do the
313 patching and install the new recovery image.
314
315 recovery_img and boot_img should be File objects for the
Doug Zongker67369982010-07-07 13:53:32 -0700316 corresponding images. info should be the dictionary returned by
317 common.LoadInfoDict() on the input target_files.
Doug Zongker73ef8252009-07-23 15:12:53 -0700318
319 Returns an Item for the shell script, which must be made
320 executable.
321 """
322
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700323 d = common.Difference(recovery_img, boot_img)
Doug Zongker761e6422009-09-25 10:45:39 -0700324 _, _, patch = d.ComputePatch()
Doug Zongkercfd7db62009-10-07 11:35:53 -0700325 common.ZipWriteStr(output_zip, "recovery/recovery-from-boot.p", patch)
Doug Zongker73ef8252009-07-23 15:12:53 -0700326 Item.Get("system/recovery-from-boot.p", dir=False)
327
Doug Zongker96a57e72010-09-26 14:57:41 -0700328 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
329 recovery_type, recovery_device = common.GetTypeAndDevice("/recovery", OPTIONS.info_dict)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700330
Doug Zongker73ef8252009-07-23 15:12:53 -0700331 sh = """#!/system/bin/sh
Doug Zongker0276d182011-12-02 10:46:59 -0800332if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then
Doug Zongker73ef8252009-07-23 15:12:53 -0700333 log -t recovery "Installing new recovery image"
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700334 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 -0700335else
336 log -t recovery "Recovery image already installed"
337fi
338""" % { 'boot_size': boot_img.size,
339 'boot_sha1': boot_img.sha1,
Doug Zongker73ef8252009-07-23 15:12:53 -0700340 'recovery_size': recovery_img.size,
Doug Zongker67369982010-07-07 13:53:32 -0700341 'recovery_sha1': recovery_img.sha1,
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700342 'boot_type': boot_type,
343 'boot_device': boot_device,
344 'recovery_type': recovery_type,
345 'recovery_device': recovery_device,
Doug Zongker67369982010-07-07 13:53:32 -0700346 }
Doug Zongkercfd7db62009-10-07 11:35:53 -0700347 common.ZipWriteStr(output_zip, "recovery/etc/install-recovery.sh", sh)
Doug Zongker73ef8252009-07-23 15:12:53 -0700348 return Item.Get("system/etc/install-recovery.sh", dir=False)
349
350
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700351def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700352 # TODO: how to determine this? We don't know what version it will
353 # be installed on top of. For now, we expect the API just won't
354 # change very often.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700355 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700356
Doug Zongker2ea21062010-04-28 16:05:21 -0700357 metadata = {"post-build": GetBuildProp("ro.build.fingerprint", input_zip),
358 "pre-device": GetBuildProp("ro.product.device", input_zip),
Doug Zongker3b852692010-06-21 15:30:45 -0700359 "post-timestamp": GetBuildProp("ro.build.date.utc", input_zip),
Doug Zongker2ea21062010-04-28 16:05:21 -0700360 }
361
Doug Zongker05d3dea2009-06-22 11:32:31 -0700362 device_specific = common.DeviceSpecificParams(
363 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700364 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700365 output_zip=output_zip,
366 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700367 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700368 metadata=metadata,
369 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700370
Doug Zongker962069c2009-04-23 11:41:58 -0700371 if not OPTIONS.omit_prereq:
372 ts = GetBuildProp("ro.build.date.utc", input_zip)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700373 script.AssertOlderBuild(ts)
Doug Zongkereef39442009-04-02 12:14:19 -0700374
375 AppendAssertions(script, input_zip)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700376 device_specific.FullOTA_Assertions()
Doug Zongkere5ff5902012-01-17 10:55:37 -0800377 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700378
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700379 script.ShowProgress(0.5, 0)
Doug Zongkereef39442009-04-02 12:14:19 -0700380
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700381 if OPTIONS.wipe_user_data:
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700382 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700383
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700384 script.FormatPartition("/system")
385 script.Mount("/system")
Doug Zongkercfd7db62009-10-07 11:35:53 -0700386 script.UnpackPackageDir("recovery", "/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700387 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700388
Doug Zongker1807e702012-02-28 12:21:08 -0800389 symlinks = CopySystemFiles(input_zip, output_zip)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700390 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700391
Doug Zongker55d93282011-01-25 17:03:34 -0800392 boot_img = common.GetBootableImage("boot.img", "boot.img",
393 OPTIONS.input_tmp, "BOOT")
394 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
395 OPTIONS.input_tmp, "RECOVERY")
Doug Zongker486de122010-09-16 14:01:56 -0700396 MakeRecoveryPatch(output_zip, recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700397
Doug Zongker283e2a12010-03-15 17:52:32 -0700398 Item.GetMetadata(input_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700399 Item.Get("system").SetPermissions(script)
400
Doug Zongker37974732010-09-16 17:44:38 -0700401 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700402 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700403 script.ShowProgress(0.2, 0)
404
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700405 script.ShowProgress(0.2, 10)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700406 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700407
408 script.ShowProgress(0.1, 0)
409 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700410
Doug Zongker1c390a22009-05-14 19:06:36 -0700411 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700412 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700413
Doug Zongker14833602010-02-02 13:12:04 -0800414 script.UnmountAll()
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700415 script.AddToZip(input_zip, output_zip)
Doug Zongker2ea21062010-04-28 16:05:21 -0700416 WriteMetadata(metadata, output_zip)
417
418
419def WriteMetadata(metadata, output_zip):
420 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
421 "".join(["%s=%s\n" % kv
422 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700423
424
Doug Zongkereef39442009-04-02 12:14:19 -0700425
426
427def LoadSystemFiles(z):
428 """Load all the files from SYSTEM/... in a given target-files
429 ZipFile, and return a dict of {filename: File object}."""
430 out = {}
431 for info in z.infolist():
432 if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
Hristo Bojinov96be7202010-08-02 10:26:17 -0700433 basefilename = info.filename[7:]
434 fn = "system/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700435 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700436 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800437 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700438
439
Doug Zongkereef39442009-04-02 12:14:19 -0700440def GetBuildProp(property, z):
441 """Return the fingerprint of the build of a given target-files
442 ZipFile object."""
443 bp = z.read("SYSTEM/build.prop")
444 if not property:
445 return bp
446 m = re.search(re.escape(property) + r"=(.*)\n", bp)
447 if not m:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700448 raise common.ExternalError("couldn't find %s in build.prop" % (property,))
Doug Zongkereef39442009-04-02 12:14:19 -0700449 return m.group(1).strip()
450
451
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700452def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Doug Zongker37974732010-09-16 17:44:38 -0700453 source_version = OPTIONS.source_info_dict["recovery_api_version"]
454 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700455
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700456 if source_version == 0:
457 print ("WARNING: generating edify script for a source that "
458 "can't install it.")
Doug Zongkerb984ae52010-09-16 23:13:11 -0700459 script = edify_generator.EdifyGenerator(source_version, OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700460
Doug Zongker2ea21062010-04-28 16:05:21 -0700461 metadata = {"pre-device": GetBuildProp("ro.product.device", source_zip),
Doug Zongker3b852692010-06-21 15:30:45 -0700462 "post-timestamp": GetBuildProp("ro.build.date.utc", target_zip),
Doug Zongker2ea21062010-04-28 16:05:21 -0700463 }
464
Doug Zongker05d3dea2009-06-22 11:32:31 -0700465 device_specific = common.DeviceSpecificParams(
466 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800467 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700468 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800469 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700470 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -0700471 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -0700472 metadata=metadata,
473 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700474
Doug Zongkereef39442009-04-02 12:14:19 -0700475 print "Loading target..."
Doug Zongker1807e702012-02-28 12:21:08 -0800476 target_data = LoadSystemFiles(target_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700477 print "Loading source..."
Doug Zongker1807e702012-02-28 12:21:08 -0800478 source_data = LoadSystemFiles(source_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700479
480 verbatim_targets = []
481 patch_list = []
Doug Zongker761e6422009-09-25 10:45:39 -0700482 diffs = []
Doug Zongkereef39442009-04-02 12:14:19 -0700483 largest_source_size = 0
484 for fn in sorted(target_data.keys()):
485 tf = target_data[fn]
Doug Zongker761e6422009-09-25 10:45:39 -0700486 assert fn == tf.name
Doug Zongkereef39442009-04-02 12:14:19 -0700487 sf = source_data.get(fn, None)
488
489 if sf is None or fn in OPTIONS.require_verbatim:
490 # This file should be included verbatim
491 if fn in OPTIONS.prohibit_verbatim:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700492 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
Doug Zongkereef39442009-04-02 12:14:19 -0700493 print "send", fn, "verbatim"
494 tf.AddToZip(output_zip)
495 verbatim_targets.append((fn, tf.size))
496 elif tf.sha1 != sf.sha1:
497 # File is different; consider sending as a patch
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700498 diffs.append(common.Difference(tf, sf))
Doug Zongkereef39442009-04-02 12:14:19 -0700499 else:
500 # Target file identical to source.
501 pass
502
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700503 common.ComputeDifferences(diffs)
Doug Zongker761e6422009-09-25 10:45:39 -0700504
505 for diff in diffs:
506 tf, sf, d = diff.GetPatch()
507 if d is None or len(d) > tf.size * OPTIONS.patch_threshold:
508 # patch is almost as big as the file; don't bother patching
509 tf.AddToZip(output_zip)
510 verbatim_targets.append((tf.name, tf.size))
511 else:
512 common.ZipWriteStr(output_zip, "patch/" + tf.name + ".p", d)
Doug Zongker55d93282011-01-25 17:03:34 -0800513 patch_list.append((tf.name, tf, sf, tf.size, common.sha1(d).hexdigest()))
Doug Zongker761e6422009-09-25 10:45:39 -0700514 largest_source_size = max(largest_source_size, sf.size)
Doug Zongkereef39442009-04-02 12:14:19 -0700515
516 source_fp = GetBuildProp("ro.build.fingerprint", source_zip)
517 target_fp = GetBuildProp("ro.build.fingerprint", target_zip)
Doug Zongker2ea21062010-04-28 16:05:21 -0700518 metadata["pre-build"] = source_fp
519 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -0700520
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700521 script.Mount("/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700522 script.AssertSomeFingerprint(source_fp, target_fp)
Doug Zongkereef39442009-04-02 12:14:19 -0700523
Doug Zongker55d93282011-01-25 17:03:34 -0800524 source_boot = common.GetBootableImage(
525 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT")
526 target_boot = common.GetBootableImage(
527 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker5da317e2009-06-02 13:38:17 -0700528 updating_boot = (source_boot.data != target_boot.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700529
Doug Zongker55d93282011-01-25 17:03:34 -0800530 source_recovery = common.GetBootableImage(
531 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY")
532 target_recovery = common.GetBootableImage(
533 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -0700534 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700535
Doug Zongker881dd402009-09-20 14:03:55 -0700536 # Here's how we divide up the progress bar:
537 # 0.1 for verifying the start state (PatchCheck calls)
538 # 0.8 for applying patches (ApplyPatch calls)
539 # 0.1 for unpacking verbatim files, symlinking, and doing the
540 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -0700541
542 AppendAssertions(script, target_zip)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700543 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -0700544
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700545 script.Print("Verifying current system...")
546
Doug Zongkere5ff5902012-01-17 10:55:37 -0800547 device_specific.IncrementalOTA_VerifyBegin()
548
Doug Zongker881dd402009-09-20 14:03:55 -0700549 script.ShowProgress(0.1, 0)
550 total_verify_size = float(sum([i[2].size for i in patch_list]) + 1)
551 if updating_boot:
552 total_verify_size += source_boot.size
553 so_far = 0
Doug Zongkereef39442009-04-02 12:14:19 -0700554
Doug Zongker5a482092010-02-17 16:09:18 -0800555 for fn, tf, sf, size, patch_sha in patch_list:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700556 script.PatchCheck("/"+fn, tf.sha1, sf.sha1)
Doug Zongker881dd402009-09-20 14:03:55 -0700557 so_far += sf.size
558 script.SetProgress(so_far / total_verify_size)
Doug Zongkereef39442009-04-02 12:14:19 -0700559
Doug Zongker5da317e2009-06-02 13:38:17 -0700560 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700561 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -0700562 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -0700563 print "boot target: %d source: %d diff: %d" % (
564 target_boot.size, source_boot.size, len(d))
565
Doug Zongker048e7ca2009-06-15 14:31:53 -0700566 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -0700567
Doug Zongker96a57e72010-09-26 14:57:41 -0700568 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -0700569
570 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
571 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -0700572 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700573 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -0700574 so_far += source_boot.size
575 script.SetProgress(so_far / total_verify_size)
Doug Zongker5da317e2009-06-02 13:38:17 -0700576
577 if patch_list or updating_recovery or updating_boot:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700578 script.CacheFreeSpaceCheck(largest_source_size)
Doug Zongker5a482092010-02-17 16:09:18 -0800579
Doug Zongker05d3dea2009-06-22 11:32:31 -0700580 device_specific.IncrementalOTA_VerifyEnd()
581
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700582 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -0700583
Doug Zongkere5ff5902012-01-17 10:55:37 -0800584 device_specific.IncrementalOTA_InstallBegin()
585
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700586 if OPTIONS.wipe_user_data:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700587 script.Print("Erasing user data...")
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700588 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700589
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700590 script.Print("Removing unneeded files...")
Doug Zongker0f3298a2009-06-30 08:16:58 -0700591 script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
592 ["/"+i for i in sorted(source_data)
Doug Zongker3b949f02009-08-24 10:24:32 -0700593 if i not in target_data] +
594 ["/system/recovery.img"])
Doug Zongkereef39442009-04-02 12:14:19 -0700595
Doug Zongker881dd402009-09-20 14:03:55 -0700596 script.ShowProgress(0.8, 0)
597 total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
598 if updating_boot:
599 total_patch_size += target_boot.size
600 so_far = 0
601
602 script.Print("Patching system files...")
Doug Zongkere92f15a2011-08-26 13:46:40 -0700603 deferred_patch_list = []
604 for item in patch_list:
605 fn, tf, sf, size, _ = item
606 if tf.name == "system/build.prop":
607 deferred_patch_list.append(item)
608 continue
Doug Zongkerc8d446b2010-02-22 15:41:53 -0800609 script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
Doug Zongker881dd402009-09-20 14:03:55 -0700610 so_far += tf.size
611 script.SetProgress(so_far / total_patch_size)
612
Doug Zongkereef39442009-04-02 12:14:19 -0700613 if updating_boot:
Doug Zongker5da317e2009-06-02 13:38:17 -0700614 # Produce the boot image by applying a patch to the current
615 # contents of the boot partition, and write it back to the
616 # partition.
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700617 script.Print("Patching boot image...")
Doug Zongkerf2ab2902010-09-22 10:12:54 -0700618 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
619 % (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -0700620 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700621 target_boot.size, target_boot.sha1),
622 "-",
623 target_boot.size, target_boot.sha1,
Doug Zongkerc8d446b2010-02-22 15:41:53 -0800624 source_boot.sha1, "patch/boot.img.p")
Doug Zongker881dd402009-09-20 14:03:55 -0700625 so_far += target_boot.size
626 script.SetProgress(so_far / total_patch_size)
Doug Zongkereef39442009-04-02 12:14:19 -0700627 print "boot image changed; including."
628 else:
629 print "boot image unchanged; skipping."
630
631 if updating_recovery:
Doug Zongker73ef8252009-07-23 15:12:53 -0700632 # Is it better to generate recovery as a patch from the current
633 # boot image, or from the previous recovery image? For large
634 # updates with significant kernel changes, probably the former.
635 # For small updates where the kernel hasn't changed, almost
636 # certainly the latter. We pick the first option. Future
637 # complicated schemes may let us effectively use both.
638 #
639 # A wacky possibility: as long as there is room in the boot
640 # partition, include the binaries and image files from recovery in
641 # the boot image (though not in the ramdisk) so they can be used
642 # as fodder for constructing the recovery image.
Doug Zongker486de122010-09-16 14:01:56 -0700643 MakeRecoveryPatch(output_zip, target_recovery, target_boot)
Doug Zongker42265392010-02-12 10:21:00 -0800644 script.DeleteFiles(["/system/recovery-from-boot.p",
645 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -0700646 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -0700647 else:
648 print "recovery image unchanged; skipping."
649
Doug Zongker881dd402009-09-20 14:03:55 -0700650 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -0700651
Doug Zongker1807e702012-02-28 12:21:08 -0800652 target_symlinks = CopySystemFiles(target_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700653
654 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700655 temp_script = script.MakeTemporary()
Doug Zongker283e2a12010-03-15 17:52:32 -0700656 Item.GetMetadata(target_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700657 Item.Get("system").SetPermissions(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -0700658
659 # Note that this call will mess up the tree of Items, so make sure
660 # we're done with it.
Doug Zongker1807e702012-02-28 12:21:08 -0800661 source_symlinks = CopySystemFiles(source_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700662 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
663
664 # Delete all the symlinks in source that aren't in target. This
665 # needs to happen before verbatim files are unpacked, in case a
666 # symlink in the source is replaced by a real file in the target.
667 to_delete = []
668 for dest, link in source_symlinks:
669 if link not in target_symlinks_d:
670 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700671 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -0700672
673 if verbatim_targets:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700674 script.Print("Unpacking new files...")
675 script.UnpackPackageDir("system", "/system")
676
Doug Zongker42265392010-02-12 10:21:00 -0800677 if updating_recovery:
678 script.Print("Unpacking new recovery...")
679 script.UnpackPackageDir("recovery", "/system")
680
Doug Zongker05d3dea2009-06-22 11:32:31 -0700681 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -0700682
683 # Create all the symlinks that don't already exist, or point to
684 # somewhere different than what we want. Delete each symlink before
685 # creating it, since the 'symlink' command won't overwrite.
686 to_create = []
687 for dest, link in target_symlinks:
688 if link in source_symlinks_d:
689 if dest != source_symlinks_d[link]:
690 to_create.append((dest, link))
691 else:
692 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700693 script.DeleteFiles([i[1] for i in to_create])
694 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -0700695
696 # Now that the symlinks are created, we can set all the
697 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700698 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -0700699
Doug Zongker881dd402009-09-20 14:03:55 -0700700 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -0700701 device_specific.IncrementalOTA_InstallEnd()
702
Doug Zongker1c390a22009-05-14 19:06:36 -0700703 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -0700704 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700705
Doug Zongkere92f15a2011-08-26 13:46:40 -0700706 # Patch the build.prop file last, so if something fails but the
707 # device can still come up, it appears to be the old build and will
708 # get set the OTA package again to retry.
709 script.Print("Patching remaining system files...")
710 for item in deferred_patch_list:
711 fn, tf, sf, size, _ = item
712 script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
713 script.SetPermissions("/system/build.prop", 0, 0, 0644)
714
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700715 script.AddToZip(target_zip, output_zip)
Doug Zongker2ea21062010-04-28 16:05:21 -0700716 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700717
718
719def main(argv):
720
721 def option_handler(o, a):
722 if o in ("-b", "--board_config"):
Doug Zongkerfdd8e692009-08-03 17:27:48 -0700723 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -0700724 elif o in ("-k", "--package_key"):
725 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -0700726 elif o in ("-i", "--incremental_from"):
727 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700728 elif o in ("-w", "--wipe_user_data"):
729 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -0700730 elif o in ("-n", "--no_prereq"):
731 OPTIONS.omit_prereq = True
Doug Zongker1c390a22009-05-14 19:06:36 -0700732 elif o in ("-e", "--extra_script"):
733 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700734 elif o in ("-a", "--aslr_mode"):
735 if a in ("on", "On", "true", "True", "yes", "Yes"):
736 OPTIONS.aslr_mode = True
737 else:
738 OPTIONS.aslr_mode = False
Doug Zongker761e6422009-09-25 10:45:39 -0700739 elif o in ("--worker_threads"):
740 OPTIONS.worker_threads = int(a)
Doug Zongkereef39442009-04-02 12:14:19 -0700741 else:
742 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700743 return True
Doug Zongkereef39442009-04-02 12:14:19 -0700744
745 args = common.ParseOptions(argv, __doc__,
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700746 extra_opts="b:k:i:d:wne:a:",
Doug Zongkereef39442009-04-02 12:14:19 -0700747 extra_long_opts=["board_config=",
748 "package_key=",
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700749 "incremental_from=",
Doug Zongker962069c2009-04-23 11:41:58 -0700750 "wipe_user_data",
Doug Zongker1c390a22009-05-14 19:06:36 -0700751 "no_prereq",
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700752 "extra_script=",
Hristo Bojinov96be7202010-08-02 10:26:17 -0700753 "worker_threads=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -0700754 "aslr_mode=",
755 ],
Doug Zongkereef39442009-04-02 12:14:19 -0700756 extra_option_handler=option_handler)
757
758 if len(args) != 2:
759 common.Usage(__doc__)
760 sys.exit(1)
761
Doug Zongker1c390a22009-05-14 19:06:36 -0700762 if OPTIONS.extra_script is not None:
763 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
764
Doug Zongkereef39442009-04-02 12:14:19 -0700765 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -0800766 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -0700767
Doug Zongkereef39442009-04-02 12:14:19 -0700768 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -0700769 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
770 if OPTIONS.verbose:
771 print "--- target info ---"
772 common.DumpInfoDict(OPTIONS.info_dict)
773
774 if OPTIONS.device_specific is None:
775 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
776 if OPTIONS.device_specific is not None:
777 OPTIONS.device_specific = os.path.normpath(OPTIONS.device_specific)
778 print "using device-specific extensions in", OPTIONS.device_specific
779
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700780 temp_zip_file = tempfile.NamedTemporaryFile()
781 output_zip = zipfile.ZipFile(temp_zip_file, "w",
782 compression=zipfile.ZIP_DEFLATED)
Doug Zongkereef39442009-04-02 12:14:19 -0700783
784 if OPTIONS.incremental_source is None:
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700785 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700786 if OPTIONS.package_key is None:
787 OPTIONS.package_key = OPTIONS.info_dict.get(
788 "default_system_dev_certificate",
789 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -0700790 else:
791 print "unzipping source target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -0800792 OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
Doug Zongker37974732010-09-16 17:44:38 -0700793 OPTIONS.target_info_dict = OPTIONS.info_dict
794 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700795 if OPTIONS.package_key is None:
Doug Zongker91b4f8a2011-09-23 12:48:33 -0700796 OPTIONS.package_key = OPTIONS.source_info_dict.get(
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700797 "default_system_dev_certificate",
798 "build/target/product/security/testkey")
Doug Zongker37974732010-09-16 17:44:38 -0700799 if OPTIONS.verbose:
800 print "--- source info ---"
801 common.DumpInfoDict(OPTIONS.source_info_dict)
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700802 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700803
804 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700805
806 SignOutput(temp_zip_file.name, args[1])
807 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -0700808
809 common.Cleanup()
810
811 print "done."
812
813
814if __name__ == '__main__':
815 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -0800816 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -0700817 main(sys.argv[1:])
818 except common.ExternalError, e:
819 print
820 print " ERROR: %s" % (e,)
821 print
822 sys.exit(1)