blob: e79c13fc25a6ca85f7e16f671eac4e96bb6e7556 [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
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700120 self.secontext = None
Doug Zongkereef39442009-04-02 12:14:19 -0700121 self.dir = dir
122
123 if name:
124 self.parent = Item.Get(os.path.dirname(name), dir=True)
125 self.parent.children.append(self)
126 else:
127 self.parent = None
128 if dir:
129 self.children = []
130
131 def Dump(self, indent=0):
132 if self.uid is not None:
133 print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode)
134 else:
135 print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode)
136 if self.dir:
137 print "%s%s" % (" "*indent, self.descendants)
138 print "%s%s" % (" "*indent, self.best_subtree)
139 for i in self.children:
140 i.Dump(indent=indent+1)
141
142 @classmethod
143 def Get(cls, name, dir=False):
144 if name not in cls.ITEMS:
145 cls.ITEMS[name] = Item(name, dir=dir)
146 return cls.ITEMS[name]
147
148 @classmethod
Doug Zongker283e2a12010-03-15 17:52:32 -0700149 def GetMetadata(cls, input_zip):
150
151 try:
152 # See if the target_files contains a record of what the uid,
153 # gid, and mode is supposed to be.
154 output = input_zip.read("META/filesystem_config.txt")
155 except KeyError:
156 # Run the external 'fs_config' program to determine the desired
157 # uid, gid, and mode for every Item object. Note this uses the
158 # one in the client now, which might not be the same as the one
159 # used when this target_files was built.
160 p = common.Run(["fs_config"], stdin=subprocess.PIPE,
161 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
162 suffix = { False: "", True: "/" }
163 input = "".join(["%s%s\n" % (i.name, suffix[i.dir])
164 for i in cls.ITEMS.itervalues() if i.name])
Doug Zongker3475d362010-03-17 16:39:30 -0700165 output, error = p.communicate(input)
Doug Zongker283e2a12010-03-15 17:52:32 -0700166 assert not error
Doug Zongkereef39442009-04-02 12:14:19 -0700167
168 for line in output.split("\n"):
169 if not line: continue
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700170 name, uid, gid, mode, secontext = line.split()
Doug Zongker283e2a12010-03-15 17:52:32 -0700171 i = cls.ITEMS.get(name, None)
172 if i is not None:
173 i.uid = int(uid)
174 i.gid = int(gid)
175 i.mode = int(mode, 8)
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700176 i.secontext = secontext
Doug Zongker283e2a12010-03-15 17:52:32 -0700177 if i.dir:
178 i.children.sort(key=lambda i: i.name)
179
180 # set metadata for the files generated by this script.
181 i = cls.ITEMS.get("system/recovery-from-boot.p", None)
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700182 if i: i.uid, i.gid, i.mode, i.secontext = 0, 0, 0644, "u:object_r:system_file:s0"
Doug Zongker283e2a12010-03-15 17:52:32 -0700183 i = cls.ITEMS.get("system/etc/install-recovery.sh", None)
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700184 if i: i.uid, i.gid, i.mode, i.secontext = 0, 0, 0544, "u:object_r:system_file:s0"
Doug Zongkereef39442009-04-02 12:14:19 -0700185
186 def CountChildMetadata(self):
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700187 """Count up the (uid, gid, mode, secontext) tuples for all children and
Doug Zongkereef39442009-04-02 12:14:19 -0700188 determine the best strategy for using set_perm_recursive and
189 set_perm to correctly chown/chmod all the files to their desired
190 values. Recursively calls itself for all descendants.
191
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700192 Returns a dict of {(uid, gid, dmode, fmode, secontext): count} counting up
Doug Zongkereef39442009-04-02 12:14:19 -0700193 all descendants of this node. (dmode or fmode may be None.) Also
194 sets the best_subtree of each directory Item to the (uid, gid,
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700195 dmode, fmode, secontext) tuple that will match the most descendants of that
Doug Zongkereef39442009-04-02 12:14:19 -0700196 Item.
197 """
198
199 assert self.dir
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700200 d = self.descendants = {(self.uid, self.gid, self.mode, None, self.secontext): 1}
Doug Zongkereef39442009-04-02 12:14:19 -0700201 for i in self.children:
202 if i.dir:
203 for k, v in i.CountChildMetadata().iteritems():
204 d[k] = d.get(k, 0) + v
205 else:
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700206 k = (i.uid, i.gid, None, i.mode, i.secontext)
Doug Zongkereef39442009-04-02 12:14:19 -0700207 d[k] = d.get(k, 0) + 1
208
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700209 # Find the (uid, gid, dmode, fmode, secontext) tuple that matches the most
Doug Zongkereef39442009-04-02 12:14:19 -0700210 # descendants.
211
212 # First, find the (uid, gid) pair that matches the most
213 # descendants.
214 ug = {}
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700215 for (uid, gid, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700216 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
217 ug = MostPopularKey(ug, (0, 0))
218
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700219 # Now find the dmode, fmode and secontext that match the most descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700220 # with that (uid, gid), and choose those.
221 best_dmode = (0, 0755)
222 best_fmode = (0, 0644)
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700223 best_secontext = (0, "u:object_r:system_file:s0")
Doug Zongkereef39442009-04-02 12:14:19 -0700224 for k, count in d.iteritems():
225 if k[:2] != ug: continue
226 if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2])
227 if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3])
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700228 if k[4] is not None and count >= best_secontext[0]: best_secontext = (count, k[4])
229 self.best_subtree = ug + (best_dmode[1], best_fmode[1], best_secontext[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700230
231 return d
232
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700233 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700234 """Append set_perm/set_perm_recursive commands to 'script' to
235 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700236 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700237
238 self.CountChildMetadata()
239
240 def recurse(item, current):
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700241 # current is the (uid, gid, dmode, fmode, secontext) tuple that the current
Doug Zongkereef39442009-04-02 12:14:19 -0700242 # item (and all its children) have already been set to. We only
243 # need to issue set_perm/set_perm_recursive commands if we're
244 # supposed to be something different.
245 if item.dir:
246 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700247 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700248 current = item.best_subtree
249
250 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700251 item.mode != current[2] or item.secontext != current[4]:
252 script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode, item.secontext)
Doug Zongkereef39442009-04-02 12:14:19 -0700253
254 for i in item.children:
255 recurse(i, current)
256 else:
257 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700258 item.mode != current[3] or item.secontext != current[4]:
259 script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode, item.secontext)
Doug Zongkereef39442009-04-02 12:14:19 -0700260
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700261 recurse(self, (-1, -1, -1, -1, "u:object_r:unlabeled:s0"))
Doug Zongkereef39442009-04-02 12:14:19 -0700262
263
264def CopySystemFiles(input_zip, output_zip=None,
265 substitute=None):
266 """Copies files underneath system/ in the input zip to the output
267 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800268 list of symlinks. output_zip may be None, in which case the copy is
269 skipped (but the other side effects still happen). substitute is an
270 optional dict of {output filename: contents} to be output instead of
271 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700272 """
273
274 symlinks = []
275
276 for info in input_zip.infolist():
277 if info.filename.startswith("SYSTEM/"):
278 basefilename = info.filename[7:]
279 if IsSymlink(info):
280 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700281 "/system/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700282 else:
283 info2 = copy.copy(info)
284 fn = info2.filename = "system/" + basefilename
285 if substitute and fn in substitute and substitute[fn] is None:
286 continue
287 if output_zip is not None:
288 if substitute and fn in substitute:
289 data = substitute[fn]
290 else:
291 data = input_zip.read(info.filename)
292 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()
Doug Zongker1807e702012-02-28 12:21:08 -0800299 return symlinks
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 Zongker1eb74dd2012-08-16 16:19:00 -0700310def AppendAssertions(script, info_dict):
311 device = GetBuildProp("ro.product.device", info_dict)
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 Zongkerb32161a2012-08-21 10:33:44 -0700315def MakeRecoveryPatch(input_tmp, 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 Zongkerb32161a2012-08-21 10:33:44 -0700331 diff_program = ["imgdiff"]
332 path = os.path.join(input_tmp, "SYSTEM", "etc", "recovery-resource.dat")
333 if os.path.exists(path):
334 diff_program.append("-b")
335 diff_program.append(path)
336 bonus_args = "-b /system/etc/recovery-resource.dat"
337 else:
338 bonus_args = ""
339
340 d = common.Difference(recovery_img, boot_img, diff_program=diff_program)
Doug Zongker761e6422009-09-25 10:45:39 -0700341 _, _, patch = d.ComputePatch()
Doug Zongkercfd7db62009-10-07 11:35:53 -0700342 common.ZipWriteStr(output_zip, "recovery/recovery-from-boot.p", patch)
Doug Zongker73ef8252009-07-23 15:12:53 -0700343 Item.Get("system/recovery-from-boot.p", dir=False)
344
Doug Zongker96a57e72010-09-26 14:57:41 -0700345 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
346 recovery_type, recovery_device = common.GetTypeAndDevice("/recovery", OPTIONS.info_dict)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700347
Doug Zongker73ef8252009-07-23 15:12:53 -0700348 sh = """#!/system/bin/sh
Doug Zongker0276d182011-12-02 10:46:59 -0800349if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then
Doug Zongker73ef8252009-07-23 15:12:53 -0700350 log -t recovery "Installing new recovery image"
Doug Zongkerb32161a2012-08-21 10:33:44 -0700351 applypatch %(bonus_args)s %(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 -0700352else
353 log -t recovery "Recovery image already installed"
354fi
355""" % { 'boot_size': boot_img.size,
356 'boot_sha1': boot_img.sha1,
Doug Zongker73ef8252009-07-23 15:12:53 -0700357 'recovery_size': recovery_img.size,
Doug Zongker67369982010-07-07 13:53:32 -0700358 'recovery_sha1': recovery_img.sha1,
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700359 'boot_type': boot_type,
360 'boot_device': boot_device,
361 'recovery_type': recovery_type,
362 'recovery_device': recovery_device,
Doug Zongkerb32161a2012-08-21 10:33:44 -0700363 'bonus_args': bonus_args,
Doug Zongker67369982010-07-07 13:53:32 -0700364 }
Doug Zongkercfd7db62009-10-07 11:35:53 -0700365 common.ZipWriteStr(output_zip, "recovery/etc/install-recovery.sh", sh)
Doug Zongker73ef8252009-07-23 15:12:53 -0700366 return Item.Get("system/etc/install-recovery.sh", dir=False)
367
368
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700369def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700370 # TODO: how to determine this? We don't know what version it will
371 # be installed on top of. For now, we expect the API just won't
372 # change very often.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700373 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700374
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700375 metadata = {"post-build": GetBuildProp("ro.build.fingerprint",
376 OPTIONS.info_dict),
377 "pre-device": GetBuildProp("ro.product.device",
378 OPTIONS.info_dict),
379 "post-timestamp": GetBuildProp("ro.build.date.utc",
380 OPTIONS.info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700381 }
382
Doug Zongker05d3dea2009-06-22 11:32:31 -0700383 device_specific = common.DeviceSpecificParams(
384 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700385 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700386 output_zip=output_zip,
387 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700388 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700389 metadata=metadata,
390 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700391
Doug Zongker962069c2009-04-23 11:41:58 -0700392 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700393 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700394 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
395 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700396
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700397 AppendAssertions(script, OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700398 device_specific.FullOTA_Assertions()
Doug Zongkere5ff5902012-01-17 10:55:37 -0800399 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700400
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700401 script.ShowProgress(0.5, 0)
Doug Zongkereef39442009-04-02 12:14:19 -0700402
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700403 if OPTIONS.wipe_user_data:
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700404 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700405
Kenny Rootf32dc712012-04-08 10:42:34 -0700406 if "selinux_fc" in OPTIONS.info_dict:
407 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500408
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700409 script.FormatPartition("/system")
410 script.Mount("/system")
Doug Zongkercfd7db62009-10-07 11:35:53 -0700411 script.UnpackPackageDir("recovery", "/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700412 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700413
Doug Zongker1807e702012-02-28 12:21:08 -0800414 symlinks = CopySystemFiles(input_zip, output_zip)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700415 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700416
Doug Zongker55d93282011-01-25 17:03:34 -0800417 boot_img = common.GetBootableImage("boot.img", "boot.img",
418 OPTIONS.input_tmp, "BOOT")
419 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
420 OPTIONS.input_tmp, "RECOVERY")
Doug Zongkerb32161a2012-08-21 10:33:44 -0700421 MakeRecoveryPatch(OPTIONS.input_tmp, output_zip, recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700422
Doug Zongker283e2a12010-03-15 17:52:32 -0700423 Item.GetMetadata(input_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700424 Item.Get("system").SetPermissions(script)
425
Doug Zongker37974732010-09-16 17:44:38 -0700426 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700427 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700428 script.ShowProgress(0.2, 0)
429
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700430 script.ShowProgress(0.2, 10)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700431 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700432
433 script.ShowProgress(0.1, 0)
434 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700435
Doug Zongker1c390a22009-05-14 19:06:36 -0700436 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700437 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700438
Doug Zongker14833602010-02-02 13:12:04 -0800439 script.UnmountAll()
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700440 script.AddToZip(input_zip, output_zip)
Doug Zongker2ea21062010-04-28 16:05:21 -0700441 WriteMetadata(metadata, output_zip)
442
Stephen Smalley56882bf2012-02-09 13:36:21 -0500443def WritePolicyConfig(file_context, output_zip):
444 f = open(file_context, 'r');
445 basename = os.path.basename(file_context)
446 common.ZipWriteStr(output_zip, basename, f.read())
447
Doug Zongker2ea21062010-04-28 16:05:21 -0700448
449def WriteMetadata(metadata, output_zip):
450 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
451 "".join(["%s=%s\n" % kv
452 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700453
Doug Zongkereef39442009-04-02 12:14:19 -0700454def LoadSystemFiles(z):
455 """Load all the files from SYSTEM/... in a given target-files
456 ZipFile, and return a dict of {filename: File object}."""
457 out = {}
458 for info in z.infolist():
459 if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
Hristo Bojinov96be7202010-08-02 10:26:17 -0700460 basefilename = info.filename[7:]
461 fn = "system/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700462 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700463 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800464 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700465
466
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700467def GetBuildProp(prop, info_dict):
468 """Return the fingerprint of the build of a given target-files info_dict."""
469 try:
470 return info_dict.get("build.prop", {})[prop]
471 except KeyError:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700472 raise common.ExternalError("couldn't find %s in build.prop" % (property,))
Doug Zongkereef39442009-04-02 12:14:19 -0700473
474
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700475def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Doug Zongker37974732010-09-16 17:44:38 -0700476 source_version = OPTIONS.source_info_dict["recovery_api_version"]
477 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700478
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700479 if source_version == 0:
480 print ("WARNING: generating edify script for a source that "
481 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700482 script = edify_generator.EdifyGenerator(source_version,
483 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700484
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700485 metadata = {"pre-device": GetBuildProp("ro.product.device",
486 OPTIONS.source_info_dict),
487 "post-timestamp": GetBuildProp("ro.build.date.utc",
488 OPTIONS.target_info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700489 }
490
Doug Zongker05d3dea2009-06-22 11:32:31 -0700491 device_specific = common.DeviceSpecificParams(
492 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800493 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700494 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800495 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700496 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -0700497 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -0700498 metadata=metadata,
499 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700500
Doug Zongkereef39442009-04-02 12:14:19 -0700501 print "Loading target..."
Doug Zongker1807e702012-02-28 12:21:08 -0800502 target_data = LoadSystemFiles(target_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700503 print "Loading source..."
Doug Zongker1807e702012-02-28 12:21:08 -0800504 source_data = LoadSystemFiles(source_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700505
506 verbatim_targets = []
507 patch_list = []
Doug Zongker761e6422009-09-25 10:45:39 -0700508 diffs = []
Doug Zongkereef39442009-04-02 12:14:19 -0700509 largest_source_size = 0
510 for fn in sorted(target_data.keys()):
511 tf = target_data[fn]
Doug Zongker761e6422009-09-25 10:45:39 -0700512 assert fn == tf.name
Doug Zongkereef39442009-04-02 12:14:19 -0700513 sf = source_data.get(fn, None)
514
515 if sf is None or fn in OPTIONS.require_verbatim:
516 # This file should be included verbatim
517 if fn in OPTIONS.prohibit_verbatim:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700518 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
Doug Zongkereef39442009-04-02 12:14:19 -0700519 print "send", fn, "verbatim"
520 tf.AddToZip(output_zip)
521 verbatim_targets.append((fn, tf.size))
522 elif tf.sha1 != sf.sha1:
523 # File is different; consider sending as a patch
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700524 diffs.append(common.Difference(tf, sf))
Doug Zongkereef39442009-04-02 12:14:19 -0700525 else:
526 # Target file identical to source.
527 pass
528
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700529 common.ComputeDifferences(diffs)
Doug Zongker761e6422009-09-25 10:45:39 -0700530
531 for diff in diffs:
532 tf, sf, d = diff.GetPatch()
533 if d is None or len(d) > tf.size * OPTIONS.patch_threshold:
534 # patch is almost as big as the file; don't bother patching
535 tf.AddToZip(output_zip)
536 verbatim_targets.append((tf.name, tf.size))
537 else:
538 common.ZipWriteStr(output_zip, "patch/" + tf.name + ".p", d)
Doug Zongker55d93282011-01-25 17:03:34 -0800539 patch_list.append((tf.name, tf, sf, tf.size, common.sha1(d).hexdigest()))
Doug Zongker761e6422009-09-25 10:45:39 -0700540 largest_source_size = max(largest_source_size, sf.size)
Doug Zongkereef39442009-04-02 12:14:19 -0700541
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700542 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
543 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
Doug Zongker2ea21062010-04-28 16:05:21 -0700544 metadata["pre-build"] = source_fp
545 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -0700546
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700547 script.Mount("/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700548 script.AssertSomeFingerprint(source_fp, target_fp)
Doug Zongkereef39442009-04-02 12:14:19 -0700549
Doug Zongker55d93282011-01-25 17:03:34 -0800550 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700551 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
552 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -0800553 target_boot = common.GetBootableImage(
554 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker5da317e2009-06-02 13:38:17 -0700555 updating_boot = (source_boot.data != target_boot.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700556
Doug Zongker55d93282011-01-25 17:03:34 -0800557 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700558 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
559 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -0800560 target_recovery = common.GetBootableImage(
561 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -0700562 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700563
Doug Zongker881dd402009-09-20 14:03:55 -0700564 # Here's how we divide up the progress bar:
565 # 0.1 for verifying the start state (PatchCheck calls)
566 # 0.8 for applying patches (ApplyPatch calls)
567 # 0.1 for unpacking verbatim files, symlinking, and doing the
568 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -0700569
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700570 AppendAssertions(script, OPTIONS.target_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700571 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -0700572
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700573 script.Print("Verifying current system...")
574
Doug Zongkere5ff5902012-01-17 10:55:37 -0800575 device_specific.IncrementalOTA_VerifyBegin()
576
Doug Zongker881dd402009-09-20 14:03:55 -0700577 script.ShowProgress(0.1, 0)
578 total_verify_size = float(sum([i[2].size for i in patch_list]) + 1)
579 if updating_boot:
580 total_verify_size += source_boot.size
581 so_far = 0
Doug Zongkereef39442009-04-02 12:14:19 -0700582
Doug Zongker5a482092010-02-17 16:09:18 -0800583 for fn, tf, sf, size, patch_sha in patch_list:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700584 script.PatchCheck("/"+fn, tf.sha1, sf.sha1)
Doug Zongker881dd402009-09-20 14:03:55 -0700585 so_far += sf.size
586 script.SetProgress(so_far / total_verify_size)
Doug Zongkereef39442009-04-02 12:14:19 -0700587
Doug Zongker5da317e2009-06-02 13:38:17 -0700588 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700589 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -0700590 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -0700591 print "boot target: %d source: %d diff: %d" % (
592 target_boot.size, source_boot.size, len(d))
593
Doug Zongker048e7ca2009-06-15 14:31:53 -0700594 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -0700595
Doug Zongker96a57e72010-09-26 14:57:41 -0700596 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -0700597
598 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
599 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -0700600 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700601 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -0700602 so_far += source_boot.size
603 script.SetProgress(so_far / total_verify_size)
Doug Zongker5da317e2009-06-02 13:38:17 -0700604
605 if patch_list or updating_recovery or updating_boot:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700606 script.CacheFreeSpaceCheck(largest_source_size)
Doug Zongker5a482092010-02-17 16:09:18 -0800607
Doug Zongker05d3dea2009-06-22 11:32:31 -0700608 device_specific.IncrementalOTA_VerifyEnd()
609
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700610 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -0700611
Doug Zongkere5ff5902012-01-17 10:55:37 -0800612 device_specific.IncrementalOTA_InstallBegin()
613
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700614 if OPTIONS.wipe_user_data:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700615 script.Print("Erasing user data...")
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700616 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700617
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700618 script.Print("Removing unneeded files...")
Doug Zongker0f3298a2009-06-30 08:16:58 -0700619 script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
620 ["/"+i for i in sorted(source_data)
Doug Zongker3b949f02009-08-24 10:24:32 -0700621 if i not in target_data] +
622 ["/system/recovery.img"])
Doug Zongkereef39442009-04-02 12:14:19 -0700623
Doug Zongker881dd402009-09-20 14:03:55 -0700624 script.ShowProgress(0.8, 0)
625 total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
626 if updating_boot:
627 total_patch_size += target_boot.size
628 so_far = 0
629
630 script.Print("Patching system files...")
Doug Zongkere92f15a2011-08-26 13:46:40 -0700631 deferred_patch_list = []
632 for item in patch_list:
633 fn, tf, sf, size, _ = item
634 if tf.name == "system/build.prop":
635 deferred_patch_list.append(item)
636 continue
Doug Zongkerc8d446b2010-02-22 15:41:53 -0800637 script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
Doug Zongker881dd402009-09-20 14:03:55 -0700638 so_far += tf.size
639 script.SetProgress(so_far / total_patch_size)
640
Doug Zongkereef39442009-04-02 12:14:19 -0700641 if updating_boot:
Doug Zongker5da317e2009-06-02 13:38:17 -0700642 # Produce the boot image by applying a patch to the current
643 # contents of the boot partition, and write it back to the
644 # partition.
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700645 script.Print("Patching boot image...")
Doug Zongkerf2ab2902010-09-22 10:12:54 -0700646 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
647 % (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -0700648 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700649 target_boot.size, target_boot.sha1),
650 "-",
651 target_boot.size, target_boot.sha1,
Doug Zongkerc8d446b2010-02-22 15:41:53 -0800652 source_boot.sha1, "patch/boot.img.p")
Doug Zongker881dd402009-09-20 14:03:55 -0700653 so_far += target_boot.size
654 script.SetProgress(so_far / total_patch_size)
Doug Zongkereef39442009-04-02 12:14:19 -0700655 print "boot image changed; including."
656 else:
657 print "boot image unchanged; skipping."
658
659 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -0700660 # Recovery is generated as a patch using both the boot image
661 # (which contains the same linux kernel as recovery) and the file
662 # /system/etc/recovery-resource.dat (which contains all the images
663 # used in the recovery UI) as sources. This lets us minimize the
664 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -0700665 #
Doug Zongkerb32161a2012-08-21 10:33:44 -0700666 # For older builds where recovery-resource.dat is not present, we
667 # use only the boot image as the source.
668
669 MakeRecoveryPatch(OPTIONS.target_tmp, output_zip,
670 target_recovery, target_boot)
Doug Zongker42265392010-02-12 10:21:00 -0800671 script.DeleteFiles(["/system/recovery-from-boot.p",
672 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -0700673 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -0700674 else:
675 print "recovery image unchanged; skipping."
676
Doug Zongker881dd402009-09-20 14:03:55 -0700677 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -0700678
Doug Zongker1807e702012-02-28 12:21:08 -0800679 target_symlinks = CopySystemFiles(target_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700680
681 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700682 temp_script = script.MakeTemporary()
Doug Zongker283e2a12010-03-15 17:52:32 -0700683 Item.GetMetadata(target_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700684 Item.Get("system").SetPermissions(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -0700685
686 # Note that this call will mess up the tree of Items, so make sure
687 # we're done with it.
Doug Zongker1807e702012-02-28 12:21:08 -0800688 source_symlinks = CopySystemFiles(source_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700689 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
690
691 # Delete all the symlinks in source that aren't in target. This
692 # needs to happen before verbatim files are unpacked, in case a
693 # symlink in the source is replaced by a real file in the target.
694 to_delete = []
695 for dest, link in source_symlinks:
696 if link not in target_symlinks_d:
697 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700698 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -0700699
700 if verbatim_targets:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700701 script.Print("Unpacking new files...")
702 script.UnpackPackageDir("system", "/system")
703
Doug Zongker42265392010-02-12 10:21:00 -0800704 if updating_recovery:
705 script.Print("Unpacking new recovery...")
706 script.UnpackPackageDir("recovery", "/system")
707
Doug Zongker05d3dea2009-06-22 11:32:31 -0700708 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -0700709
710 # Create all the symlinks that don't already exist, or point to
711 # somewhere different than what we want. Delete each symlink before
712 # creating it, since the 'symlink' command won't overwrite.
713 to_create = []
714 for dest, link in target_symlinks:
715 if link in source_symlinks_d:
716 if dest != source_symlinks_d[link]:
717 to_create.append((dest, link))
718 else:
719 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700720 script.DeleteFiles([i[1] for i in to_create])
721 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -0700722
723 # Now that the symlinks are created, we can set all the
724 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700725 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -0700726
Doug Zongker881dd402009-09-20 14:03:55 -0700727 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -0700728 device_specific.IncrementalOTA_InstallEnd()
729
Doug Zongker1c390a22009-05-14 19:06:36 -0700730 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -0700731 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700732
Doug Zongkere92f15a2011-08-26 13:46:40 -0700733 # Patch the build.prop file last, so if something fails but the
734 # device can still come up, it appears to be the old build and will
735 # get set the OTA package again to retry.
736 script.Print("Patching remaining system files...")
737 for item in deferred_patch_list:
738 fn, tf, sf, size, _ = item
739 script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
Nick Kralevichfbbd7952013-07-17 17:43:09 -0700740 script.SetPermissions("/system/build.prop", 0, 0, 0644, "u:object_r:system_file:s0")
Doug Zongkere92f15a2011-08-26 13:46:40 -0700741
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700742 script.AddToZip(target_zip, output_zip)
Doug Zongker2ea21062010-04-28 16:05:21 -0700743 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700744
745
746def main(argv):
747
748 def option_handler(o, a):
749 if o in ("-b", "--board_config"):
Doug Zongkerfdd8e692009-08-03 17:27:48 -0700750 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -0700751 elif o in ("-k", "--package_key"):
752 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -0700753 elif o in ("-i", "--incremental_from"):
754 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700755 elif o in ("-w", "--wipe_user_data"):
756 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -0700757 elif o in ("-n", "--no_prereq"):
758 OPTIONS.omit_prereq = True
Doug Zongker1c390a22009-05-14 19:06:36 -0700759 elif o in ("-e", "--extra_script"):
760 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700761 elif o in ("-a", "--aslr_mode"):
762 if a in ("on", "On", "true", "True", "yes", "Yes"):
763 OPTIONS.aslr_mode = True
764 else:
765 OPTIONS.aslr_mode = False
Doug Zongker761e6422009-09-25 10:45:39 -0700766 elif o in ("--worker_threads"):
767 OPTIONS.worker_threads = int(a)
Doug Zongkereef39442009-04-02 12:14:19 -0700768 else:
769 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700770 return True
Doug Zongkereef39442009-04-02 12:14:19 -0700771
772 args = common.ParseOptions(argv, __doc__,
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700773 extra_opts="b:k:i:d:wne:a:",
Doug Zongkereef39442009-04-02 12:14:19 -0700774 extra_long_opts=["board_config=",
775 "package_key=",
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700776 "incremental_from=",
Doug Zongker962069c2009-04-23 11:41:58 -0700777 "wipe_user_data",
Doug Zongker1c390a22009-05-14 19:06:36 -0700778 "no_prereq",
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700779 "extra_script=",
Hristo Bojinov96be7202010-08-02 10:26:17 -0700780 "worker_threads=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -0700781 "aslr_mode=",
782 ],
Doug Zongkereef39442009-04-02 12:14:19 -0700783 extra_option_handler=option_handler)
784
785 if len(args) != 2:
786 common.Usage(__doc__)
787 sys.exit(1)
788
Doug Zongker1c390a22009-05-14 19:06:36 -0700789 if OPTIONS.extra_script is not None:
790 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
791
Doug Zongkereef39442009-04-02 12:14:19 -0700792 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -0800793 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -0700794
Doug Zongkereef39442009-04-02 12:14:19 -0700795 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -0700796 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -0700797
798 # If this image was originally labelled with SELinux contexts, make sure we
799 # also apply the labels in our new image. During building, the "file_contexts"
800 # is in the out/ directory tree, but for repacking from target-files.zip it's
801 # in the root directory of the ramdisk.
802 if "selinux_fc" in OPTIONS.info_dict:
803 OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK",
804 "file_contexts")
805
Doug Zongker37974732010-09-16 17:44:38 -0700806 if OPTIONS.verbose:
807 print "--- target info ---"
808 common.DumpInfoDict(OPTIONS.info_dict)
809
810 if OPTIONS.device_specific is None:
811 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
812 if OPTIONS.device_specific is not None:
813 OPTIONS.device_specific = os.path.normpath(OPTIONS.device_specific)
814 print "using device-specific extensions in", OPTIONS.device_specific
815
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700816 temp_zip_file = tempfile.NamedTemporaryFile()
817 output_zip = zipfile.ZipFile(temp_zip_file, "w",
818 compression=zipfile.ZIP_DEFLATED)
Doug Zongkereef39442009-04-02 12:14:19 -0700819
820 if OPTIONS.incremental_source is None:
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700821 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700822 if OPTIONS.package_key is None:
823 OPTIONS.package_key = OPTIONS.info_dict.get(
824 "default_system_dev_certificate",
825 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -0700826 else:
827 print "unzipping source target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -0800828 OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
Doug Zongker37974732010-09-16 17:44:38 -0700829 OPTIONS.target_info_dict = OPTIONS.info_dict
830 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700831 if OPTIONS.package_key is None:
Doug Zongker91b4f8a2011-09-23 12:48:33 -0700832 OPTIONS.package_key = OPTIONS.source_info_dict.get(
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700833 "default_system_dev_certificate",
834 "build/target/product/security/testkey")
Doug Zongker37974732010-09-16 17:44:38 -0700835 if OPTIONS.verbose:
836 print "--- source info ---"
837 common.DumpInfoDict(OPTIONS.source_info_dict)
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700838 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700839
840 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700841
842 SignOutput(temp_zip_file.name, args[1])
843 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -0700844
845 common.Cleanup()
846
847 print "done."
848
849
850if __name__ == '__main__':
851 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -0800852 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -0700853 main(sys.argv[1:])
854 except common.ExternalError, e:
855 print
856 print " ERROR: %s" % (e,)
857 print
858 sys.exit(1)