blob: a6b9b69399124174193ba937897245fdaf045ea1 [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 Kralevich0eb17d92013-09-07 17:10:29 -0700120 self.selabel = None
121 self.capabilities = None
Doug Zongkereef39442009-04-02 12:14:19 -0700122 self.dir = dir
123
124 if name:
125 self.parent = Item.Get(os.path.dirname(name), dir=True)
126 self.parent.children.append(self)
127 else:
128 self.parent = None
129 if dir:
130 self.children = []
131
132 def Dump(self, indent=0):
133 if self.uid is not None:
134 print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode)
135 else:
136 print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode)
137 if self.dir:
138 print "%s%s" % (" "*indent, self.descendants)
139 print "%s%s" % (" "*indent, self.best_subtree)
140 for i in self.children:
141 i.Dump(indent=indent+1)
142
143 @classmethod
144 def Get(cls, name, dir=False):
145 if name not in cls.ITEMS:
146 cls.ITEMS[name] = Item(name, dir=dir)
147 return cls.ITEMS[name]
148
149 @classmethod
Doug Zongker283e2a12010-03-15 17:52:32 -0700150 def GetMetadata(cls, input_zip):
151
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700152 # The target_files contains a record of what the uid,
153 # gid, and mode are supposed to be.
154 output = input_zip.read("META/filesystem_config.txt")
Doug Zongkereef39442009-04-02 12:14:19 -0700155
156 for line in output.split("\n"):
157 if not line: continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700158 columns = line.split()
159 name, uid, gid, mode = columns[:4]
160 selabel = None
161 capabilities = None
162
163 # After the first 4 columns, there are a series of key=value
164 # pairs. Extract out the fields we care about.
165 for element in columns[4:]:
166 key, value = element.split("=")
167 if key == "selabel":
168 selabel = value
169 if key == "capabilities":
170 capabilities = value
171
Doug Zongker283e2a12010-03-15 17:52:32 -0700172 i = cls.ITEMS.get(name, None)
173 if i is not None:
174 i.uid = int(uid)
175 i.gid = int(gid)
176 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700177 i.selabel = selabel
178 i.capabilities = capabilities
Doug Zongker283e2a12010-03-15 17:52:32 -0700179 if i.dir:
180 i.children.sort(key=lambda i: i.name)
181
182 # set metadata for the files generated by this script.
183 i = cls.ITEMS.get("system/recovery-from-boot.p", None)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700184 if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0644, None, None
Doug Zongker283e2a12010-03-15 17:52:32 -0700185 i = cls.ITEMS.get("system/etc/install-recovery.sh", None)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700186 if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700187
188 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700189 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
190 all children and determine the best strategy for using set_perm_recursive and
Doug Zongkereef39442009-04-02 12:14:19 -0700191 set_perm to correctly chown/chmod all the files to their desired
192 values. Recursively calls itself for all descendants.
193
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700194 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count} counting up
Doug Zongkereef39442009-04-02 12:14:19 -0700195 all descendants of this node. (dmode or fmode may be None.) Also
196 sets the best_subtree of each directory Item to the (uid, gid,
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700197 dmode, fmode, selabel, capabilities) tuple that will match the most
198 descendants of that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700199 """
200
201 assert self.dir
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700202 d = self.descendants = {(self.uid, self.gid, self.mode, None, self.selabel, self.capabilities): 1}
Doug Zongkereef39442009-04-02 12:14:19 -0700203 for i in self.children:
204 if i.dir:
205 for k, v in i.CountChildMetadata().iteritems():
206 d[k] = d.get(k, 0) + v
207 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700208 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700209 d[k] = d.get(k, 0) + 1
210
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700211 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
212 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700213
214 # First, find the (uid, gid) pair that matches the most
215 # descendants.
216 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700217 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700218 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
219 ug = MostPopularKey(ug, (0, 0))
220
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700221 # Now find the dmode, fmode, selabel, and capabilities that match
222 # the most descendants with that (uid, gid), and choose those.
Doug Zongkereef39442009-04-02 12:14:19 -0700223 best_dmode = (0, 0755)
224 best_fmode = (0, 0644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700225 best_selabel = (0, None)
226 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700227 for k, count in d.iteritems():
228 if k[:2] != ug: continue
229 if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2])
230 if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3])
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700231 if k[4] is not None and count >= best_selabel[0]: best_selabel = (count, k[4])
232 if k[5] is not None and count >= best_capabilities[0]: best_capabilities = (count, k[5])
233 self.best_subtree = ug + (best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700234
235 return d
236
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700237 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700238 """Append set_perm/set_perm_recursive commands to 'script' to
239 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700240 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700241
242 self.CountChildMetadata()
243
244 def recurse(item, current):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700245 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple that the current
Doug Zongkereef39442009-04-02 12:14:19 -0700246 # item (and all its children) have already been set to. We only
247 # need to issue set_perm/set_perm_recursive commands if we're
248 # supposed to be something different.
249 if item.dir:
250 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700251 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700252 current = item.best_subtree
253
254 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700255 item.mode != current[2] or item.selabel != current[4] or \
256 item.capabilities != current[5]:
257 script.SetPermissions("/"+item.name, item.uid, item.gid,
258 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700259
260 for i in item.children:
261 recurse(i, current)
262 else:
263 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700264 item.mode != current[3] or item.selabel != current[4] or \
265 item.capabilities != current[5]:
266 script.SetPermissions("/"+item.name, item.uid, item.gid,
267 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700268
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700269 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700270
271
272def CopySystemFiles(input_zip, output_zip=None,
273 substitute=None):
274 """Copies files underneath system/ in the input zip to the output
275 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800276 list of symlinks. output_zip may be None, in which case the copy is
277 skipped (but the other side effects still happen). substitute is an
278 optional dict of {output filename: contents} to be output instead of
279 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700280 """
281
282 symlinks = []
283
284 for info in input_zip.infolist():
285 if info.filename.startswith("SYSTEM/"):
286 basefilename = info.filename[7:]
287 if IsSymlink(info):
288 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700289 "/system/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700290 else:
291 info2 = copy.copy(info)
292 fn = info2.filename = "system/" + basefilename
293 if substitute and fn in substitute and substitute[fn] is None:
294 continue
295 if output_zip is not None:
296 if substitute and fn in substitute:
297 data = substitute[fn]
298 else:
299 data = input_zip.read(info.filename)
300 output_zip.writestr(info2, data)
301 if fn.endswith("/"):
302 Item.Get(fn[:-1], dir=True)
303 else:
304 Item.Get(fn, dir=False)
305
306 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800307 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700308
309
Doug Zongkereef39442009-04-02 12:14:19 -0700310def SignOutput(temp_zip_name, output_zip_name):
311 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
312 pw = key_passwords[OPTIONS.package_key]
313
Doug Zongker951495f2009-08-14 12:44:19 -0700314 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
315 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700316
317
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700318def AppendAssertions(script, info_dict):
319 device = GetBuildProp("ro.product.device", info_dict)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700320 script.AssertDevice(device)
Doug Zongkereef39442009-04-02 12:14:19 -0700321
Doug Zongkereef39442009-04-02 12:14:19 -0700322
Doug Zongkerb32161a2012-08-21 10:33:44 -0700323def MakeRecoveryPatch(input_tmp, output_zip, recovery_img, boot_img):
Doug Zongker73ef8252009-07-23 15:12:53 -0700324 """Generate a binary patch that creates the recovery image starting
325 with the boot image. (Most of the space in these images is just the
326 kernel, which is identical for the two, so the resulting patch
327 should be efficient.) Add it to the output zip, along with a shell
328 script that is run from init.rc on first boot to actually do the
329 patching and install the new recovery image.
330
331 recovery_img and boot_img should be File objects for the
Doug Zongker67369982010-07-07 13:53:32 -0700332 corresponding images. info should be the dictionary returned by
333 common.LoadInfoDict() on the input target_files.
Doug Zongker73ef8252009-07-23 15:12:53 -0700334
335 Returns an Item for the shell script, which must be made
336 executable.
337 """
338
Doug Zongkerb32161a2012-08-21 10:33:44 -0700339 diff_program = ["imgdiff"]
340 path = os.path.join(input_tmp, "SYSTEM", "etc", "recovery-resource.dat")
341 if os.path.exists(path):
342 diff_program.append("-b")
343 diff_program.append(path)
344 bonus_args = "-b /system/etc/recovery-resource.dat"
345 else:
346 bonus_args = ""
347
348 d = common.Difference(recovery_img, boot_img, diff_program=diff_program)
Doug Zongker761e6422009-09-25 10:45:39 -0700349 _, _, patch = d.ComputePatch()
Doug Zongkercfd7db62009-10-07 11:35:53 -0700350 common.ZipWriteStr(output_zip, "recovery/recovery-from-boot.p", patch)
Doug Zongker73ef8252009-07-23 15:12:53 -0700351 Item.Get("system/recovery-from-boot.p", dir=False)
352
Doug Zongker96a57e72010-09-26 14:57:41 -0700353 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
354 recovery_type, recovery_device = common.GetTypeAndDevice("/recovery", OPTIONS.info_dict)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700355
Doug Zongker73ef8252009-07-23 15:12:53 -0700356 sh = """#!/system/bin/sh
Doug Zongker0276d182011-12-02 10:46:59 -0800357if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then
Doug Zongker73ef8252009-07-23 15:12:53 -0700358 log -t recovery "Installing new recovery image"
Doug Zongkerb32161a2012-08-21 10:33:44 -0700359 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 -0700360else
361 log -t recovery "Recovery image already installed"
362fi
363""" % { 'boot_size': boot_img.size,
364 'boot_sha1': boot_img.sha1,
Doug Zongker73ef8252009-07-23 15:12:53 -0700365 'recovery_size': recovery_img.size,
Doug Zongker67369982010-07-07 13:53:32 -0700366 'recovery_sha1': recovery_img.sha1,
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700367 'boot_type': boot_type,
368 'boot_device': boot_device,
369 'recovery_type': recovery_type,
370 'recovery_device': recovery_device,
Doug Zongkerb32161a2012-08-21 10:33:44 -0700371 'bonus_args': bonus_args,
Doug Zongker67369982010-07-07 13:53:32 -0700372 }
Doug Zongkercfd7db62009-10-07 11:35:53 -0700373 common.ZipWriteStr(output_zip, "recovery/etc/install-recovery.sh", sh)
Doug Zongker73ef8252009-07-23 15:12:53 -0700374 return Item.Get("system/etc/install-recovery.sh", dir=False)
375
376
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700377def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700378 # TODO: how to determine this? We don't know what version it will
379 # be installed on top of. For now, we expect the API just won't
380 # change very often.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700381 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700382
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700383 metadata = {"post-build": GetBuildProp("ro.build.fingerprint",
384 OPTIONS.info_dict),
385 "pre-device": GetBuildProp("ro.product.device",
386 OPTIONS.info_dict),
387 "post-timestamp": GetBuildProp("ro.build.date.utc",
388 OPTIONS.info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700389 }
390
Doug Zongker05d3dea2009-06-22 11:32:31 -0700391 device_specific = common.DeviceSpecificParams(
392 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700393 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700394 output_zip=output_zip,
395 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700396 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700397 metadata=metadata,
398 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700399
Doug Zongker962069c2009-04-23 11:41:58 -0700400 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700401 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700402 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
403 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700404
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700405 AppendAssertions(script, OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700406 device_specific.FullOTA_Assertions()
Doug Zongkere5ff5902012-01-17 10:55:37 -0800407 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700408
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700409 script.ShowProgress(0.5, 0)
Doug Zongkereef39442009-04-02 12:14:19 -0700410
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700411 if OPTIONS.wipe_user_data:
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700412 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700413
Kenny Rootf32dc712012-04-08 10:42:34 -0700414 if "selinux_fc" in OPTIONS.info_dict:
415 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500416
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700417 script.FormatPartition("/system")
418 script.Mount("/system")
Doug Zongkercfd7db62009-10-07 11:35:53 -0700419 script.UnpackPackageDir("recovery", "/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700420 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700421
Doug Zongker1807e702012-02-28 12:21:08 -0800422 symlinks = CopySystemFiles(input_zip, output_zip)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700423 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700424
Doug Zongker55d93282011-01-25 17:03:34 -0800425 boot_img = common.GetBootableImage("boot.img", "boot.img",
426 OPTIONS.input_tmp, "BOOT")
427 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
428 OPTIONS.input_tmp, "RECOVERY")
Doug Zongkerb32161a2012-08-21 10:33:44 -0700429 MakeRecoveryPatch(OPTIONS.input_tmp, output_zip, recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700430
Doug Zongker283e2a12010-03-15 17:52:32 -0700431 Item.GetMetadata(input_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700432 Item.Get("system").SetPermissions(script)
433
Doug Zongker37974732010-09-16 17:44:38 -0700434 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700435 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700436 script.ShowProgress(0.2, 0)
437
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700438 script.ShowProgress(0.2, 10)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700439 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700440
441 script.ShowProgress(0.1, 0)
442 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700443
Doug Zongker1c390a22009-05-14 19:06:36 -0700444 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700445 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700446
Doug Zongker14833602010-02-02 13:12:04 -0800447 script.UnmountAll()
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700448 script.AddToZip(input_zip, output_zip)
Doug Zongker2ea21062010-04-28 16:05:21 -0700449 WriteMetadata(metadata, output_zip)
450
Stephen Smalley56882bf2012-02-09 13:36:21 -0500451def WritePolicyConfig(file_context, output_zip):
452 f = open(file_context, 'r');
453 basename = os.path.basename(file_context)
454 common.ZipWriteStr(output_zip, basename, f.read())
455
Doug Zongker2ea21062010-04-28 16:05:21 -0700456
457def WriteMetadata(metadata, output_zip):
458 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
459 "".join(["%s=%s\n" % kv
460 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700461
Doug Zongkereef39442009-04-02 12:14:19 -0700462def LoadSystemFiles(z):
463 """Load all the files from SYSTEM/... in a given target-files
464 ZipFile, and return a dict of {filename: File object}."""
465 out = {}
466 for info in z.infolist():
467 if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
Hristo Bojinov96be7202010-08-02 10:26:17 -0700468 basefilename = info.filename[7:]
469 fn = "system/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700470 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700471 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800472 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700473
474
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700475def GetBuildProp(prop, info_dict):
476 """Return the fingerprint of the build of a given target-files info_dict."""
477 try:
478 return info_dict.get("build.prop", {})[prop]
479 except KeyError:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700480 raise common.ExternalError("couldn't find %s in build.prop" % (property,))
Doug Zongkereef39442009-04-02 12:14:19 -0700481
482
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700483def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Doug Zongker37974732010-09-16 17:44:38 -0700484 source_version = OPTIONS.source_info_dict["recovery_api_version"]
485 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700486
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700487 if source_version == 0:
488 print ("WARNING: generating edify script for a source that "
489 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700490 script = edify_generator.EdifyGenerator(source_version,
491 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700492
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700493 metadata = {"pre-device": GetBuildProp("ro.product.device",
494 OPTIONS.source_info_dict),
495 "post-timestamp": GetBuildProp("ro.build.date.utc",
496 OPTIONS.target_info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700497 }
498
Doug Zongker05d3dea2009-06-22 11:32:31 -0700499 device_specific = common.DeviceSpecificParams(
500 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800501 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700502 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800503 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700504 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -0700505 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -0700506 metadata=metadata,
507 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700508
Doug Zongkereef39442009-04-02 12:14:19 -0700509 print "Loading target..."
Doug Zongker1807e702012-02-28 12:21:08 -0800510 target_data = LoadSystemFiles(target_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700511 print "Loading source..."
Doug Zongker1807e702012-02-28 12:21:08 -0800512 source_data = LoadSystemFiles(source_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700513
514 verbatim_targets = []
515 patch_list = []
Doug Zongker761e6422009-09-25 10:45:39 -0700516 diffs = []
Doug Zongkereef39442009-04-02 12:14:19 -0700517 largest_source_size = 0
518 for fn in sorted(target_data.keys()):
519 tf = target_data[fn]
Doug Zongker761e6422009-09-25 10:45:39 -0700520 assert fn == tf.name
Doug Zongkereef39442009-04-02 12:14:19 -0700521 sf = source_data.get(fn, None)
522
523 if sf is None or fn in OPTIONS.require_verbatim:
524 # This file should be included verbatim
525 if fn in OPTIONS.prohibit_verbatim:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700526 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
Doug Zongkereef39442009-04-02 12:14:19 -0700527 print "send", fn, "verbatim"
528 tf.AddToZip(output_zip)
529 verbatim_targets.append((fn, tf.size))
530 elif tf.sha1 != sf.sha1:
531 # File is different; consider sending as a patch
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700532 diffs.append(common.Difference(tf, sf))
Doug Zongkereef39442009-04-02 12:14:19 -0700533 else:
534 # Target file identical to source.
535 pass
536
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700537 common.ComputeDifferences(diffs)
Doug Zongker761e6422009-09-25 10:45:39 -0700538
539 for diff in diffs:
540 tf, sf, d = diff.GetPatch()
541 if d is None or len(d) > tf.size * OPTIONS.patch_threshold:
542 # patch is almost as big as the file; don't bother patching
543 tf.AddToZip(output_zip)
544 verbatim_targets.append((tf.name, tf.size))
545 else:
546 common.ZipWriteStr(output_zip, "patch/" + tf.name + ".p", d)
Doug Zongker55d93282011-01-25 17:03:34 -0800547 patch_list.append((tf.name, tf, sf, tf.size, common.sha1(d).hexdigest()))
Doug Zongker761e6422009-09-25 10:45:39 -0700548 largest_source_size = max(largest_source_size, sf.size)
Doug Zongkereef39442009-04-02 12:14:19 -0700549
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700550 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
551 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
Doug Zongker2ea21062010-04-28 16:05:21 -0700552 metadata["pre-build"] = source_fp
553 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -0700554
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700555 script.Mount("/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700556 script.AssertSomeFingerprint(source_fp, target_fp)
Doug Zongkereef39442009-04-02 12:14:19 -0700557
Doug Zongker55d93282011-01-25 17:03:34 -0800558 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700559 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
560 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -0800561 target_boot = common.GetBootableImage(
562 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker5da317e2009-06-02 13:38:17 -0700563 updating_boot = (source_boot.data != target_boot.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700564
Doug Zongker55d93282011-01-25 17:03:34 -0800565 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700566 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
567 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -0800568 target_recovery = common.GetBootableImage(
569 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -0700570 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700571
Doug Zongker881dd402009-09-20 14:03:55 -0700572 # Here's how we divide up the progress bar:
573 # 0.1 for verifying the start state (PatchCheck calls)
574 # 0.8 for applying patches (ApplyPatch calls)
575 # 0.1 for unpacking verbatim files, symlinking, and doing the
576 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -0700577
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700578 AppendAssertions(script, OPTIONS.target_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700579 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -0700580
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700581 script.Print("Verifying current system...")
582
Doug Zongkere5ff5902012-01-17 10:55:37 -0800583 device_specific.IncrementalOTA_VerifyBegin()
584
Doug Zongker881dd402009-09-20 14:03:55 -0700585 script.ShowProgress(0.1, 0)
586 total_verify_size = float(sum([i[2].size for i in patch_list]) + 1)
587 if updating_boot:
588 total_verify_size += source_boot.size
589 so_far = 0
Doug Zongkereef39442009-04-02 12:14:19 -0700590
Doug Zongker5a482092010-02-17 16:09:18 -0800591 for fn, tf, sf, size, patch_sha in patch_list:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700592 script.PatchCheck("/"+fn, tf.sha1, sf.sha1)
Doug Zongker881dd402009-09-20 14:03:55 -0700593 so_far += sf.size
594 script.SetProgress(so_far / total_verify_size)
Doug Zongkereef39442009-04-02 12:14:19 -0700595
Doug Zongker5da317e2009-06-02 13:38:17 -0700596 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700597 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -0700598 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -0700599 print "boot target: %d source: %d diff: %d" % (
600 target_boot.size, source_boot.size, len(d))
601
Doug Zongker048e7ca2009-06-15 14:31:53 -0700602 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -0700603
Doug Zongker96a57e72010-09-26 14:57:41 -0700604 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -0700605
606 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
607 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -0700608 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700609 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -0700610 so_far += source_boot.size
611 script.SetProgress(so_far / total_verify_size)
Doug Zongker5da317e2009-06-02 13:38:17 -0700612
613 if patch_list or updating_recovery or updating_boot:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700614 script.CacheFreeSpaceCheck(largest_source_size)
Doug Zongker5a482092010-02-17 16:09:18 -0800615
Doug Zongker05d3dea2009-06-22 11:32:31 -0700616 device_specific.IncrementalOTA_VerifyEnd()
617
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700618 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -0700619
Doug Zongkere5ff5902012-01-17 10:55:37 -0800620 device_specific.IncrementalOTA_InstallBegin()
621
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700622 if OPTIONS.wipe_user_data:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700623 script.Print("Erasing user data...")
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700624 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700625
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700626 script.Print("Removing unneeded files...")
Doug Zongker0f3298a2009-06-30 08:16:58 -0700627 script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
628 ["/"+i for i in sorted(source_data)
Doug Zongker3b949f02009-08-24 10:24:32 -0700629 if i not in target_data] +
630 ["/system/recovery.img"])
Doug Zongkereef39442009-04-02 12:14:19 -0700631
Doug Zongker881dd402009-09-20 14:03:55 -0700632 script.ShowProgress(0.8, 0)
633 total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
634 if updating_boot:
635 total_patch_size += target_boot.size
636 so_far = 0
637
638 script.Print("Patching system files...")
Doug Zongkere92f15a2011-08-26 13:46:40 -0700639 deferred_patch_list = []
640 for item in patch_list:
641 fn, tf, sf, size, _ = item
642 if tf.name == "system/build.prop":
643 deferred_patch_list.append(item)
644 continue
Doug Zongkerc8d446b2010-02-22 15:41:53 -0800645 script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
Doug Zongker881dd402009-09-20 14:03:55 -0700646 so_far += tf.size
647 script.SetProgress(so_far / total_patch_size)
648
Doug Zongkereef39442009-04-02 12:14:19 -0700649 if updating_boot:
Doug Zongker5da317e2009-06-02 13:38:17 -0700650 # Produce the boot image by applying a patch to the current
651 # contents of the boot partition, and write it back to the
652 # partition.
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700653 script.Print("Patching boot image...")
Doug Zongkerf2ab2902010-09-22 10:12:54 -0700654 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
655 % (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -0700656 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700657 target_boot.size, target_boot.sha1),
658 "-",
659 target_boot.size, target_boot.sha1,
Doug Zongkerc8d446b2010-02-22 15:41:53 -0800660 source_boot.sha1, "patch/boot.img.p")
Doug Zongker881dd402009-09-20 14:03:55 -0700661 so_far += target_boot.size
662 script.SetProgress(so_far / total_patch_size)
Doug Zongkereef39442009-04-02 12:14:19 -0700663 print "boot image changed; including."
664 else:
665 print "boot image unchanged; skipping."
666
667 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -0700668 # Recovery is generated as a patch using both the boot image
669 # (which contains the same linux kernel as recovery) and the file
670 # /system/etc/recovery-resource.dat (which contains all the images
671 # used in the recovery UI) as sources. This lets us minimize the
672 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -0700673 #
Doug Zongkerb32161a2012-08-21 10:33:44 -0700674 # For older builds where recovery-resource.dat is not present, we
675 # use only the boot image as the source.
676
677 MakeRecoveryPatch(OPTIONS.target_tmp, output_zip,
678 target_recovery, target_boot)
Doug Zongker42265392010-02-12 10:21:00 -0800679 script.DeleteFiles(["/system/recovery-from-boot.p",
680 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -0700681 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -0700682 else:
683 print "recovery image unchanged; skipping."
684
Doug Zongker881dd402009-09-20 14:03:55 -0700685 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -0700686
Doug Zongker1807e702012-02-28 12:21:08 -0800687 target_symlinks = CopySystemFiles(target_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700688
689 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700690 temp_script = script.MakeTemporary()
Doug Zongker283e2a12010-03-15 17:52:32 -0700691 Item.GetMetadata(target_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700692 Item.Get("system").SetPermissions(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -0700693
694 # Note that this call will mess up the tree of Items, so make sure
695 # we're done with it.
Doug Zongker1807e702012-02-28 12:21:08 -0800696 source_symlinks = CopySystemFiles(source_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700697 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
698
699 # Delete all the symlinks in source that aren't in target. This
700 # needs to happen before verbatim files are unpacked, in case a
701 # symlink in the source is replaced by a real file in the target.
702 to_delete = []
703 for dest, link in source_symlinks:
704 if link not in target_symlinks_d:
705 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700706 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -0700707
708 if verbatim_targets:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700709 script.Print("Unpacking new files...")
710 script.UnpackPackageDir("system", "/system")
711
Doug Zongker42265392010-02-12 10:21:00 -0800712 if updating_recovery:
713 script.Print("Unpacking new recovery...")
714 script.UnpackPackageDir("recovery", "/system")
715
Doug Zongker05d3dea2009-06-22 11:32:31 -0700716 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -0700717
718 # Create all the symlinks that don't already exist, or point to
719 # somewhere different than what we want. Delete each symlink before
720 # creating it, since the 'symlink' command won't overwrite.
721 to_create = []
722 for dest, link in target_symlinks:
723 if link in source_symlinks_d:
724 if dest != source_symlinks_d[link]:
725 to_create.append((dest, link))
726 else:
727 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700728 script.DeleteFiles([i[1] for i in to_create])
729 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -0700730
731 # Now that the symlinks are created, we can set all the
732 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700733 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -0700734
Doug Zongker881dd402009-09-20 14:03:55 -0700735 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -0700736 device_specific.IncrementalOTA_InstallEnd()
737
Doug Zongker1c390a22009-05-14 19:06:36 -0700738 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -0700739 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700740
Doug Zongkere92f15a2011-08-26 13:46:40 -0700741 # Patch the build.prop file last, so if something fails but the
742 # device can still come up, it appears to be the old build and will
743 # get set the OTA package again to retry.
744 script.Print("Patching remaining system files...")
745 for item in deferred_patch_list:
746 fn, tf, sf, size, _ = item
747 script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700748 script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None)
Doug Zongkere92f15a2011-08-26 13:46:40 -0700749
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700750 script.AddToZip(target_zip, output_zip)
Doug Zongker2ea21062010-04-28 16:05:21 -0700751 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700752
753
754def main(argv):
755
756 def option_handler(o, a):
757 if o in ("-b", "--board_config"):
Doug Zongkerfdd8e692009-08-03 17:27:48 -0700758 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -0700759 elif o in ("-k", "--package_key"):
760 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -0700761 elif o in ("-i", "--incremental_from"):
762 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700763 elif o in ("-w", "--wipe_user_data"):
764 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -0700765 elif o in ("-n", "--no_prereq"):
766 OPTIONS.omit_prereq = True
Doug Zongker1c390a22009-05-14 19:06:36 -0700767 elif o in ("-e", "--extra_script"):
768 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700769 elif o in ("-a", "--aslr_mode"):
770 if a in ("on", "On", "true", "True", "yes", "Yes"):
771 OPTIONS.aslr_mode = True
772 else:
773 OPTIONS.aslr_mode = False
Doug Zongker761e6422009-09-25 10:45:39 -0700774 elif o in ("--worker_threads"):
775 OPTIONS.worker_threads = int(a)
Doug Zongkereef39442009-04-02 12:14:19 -0700776 else:
777 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700778 return True
Doug Zongkereef39442009-04-02 12:14:19 -0700779
780 args = common.ParseOptions(argv, __doc__,
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700781 extra_opts="b:k:i:d:wne:a:",
Doug Zongkereef39442009-04-02 12:14:19 -0700782 extra_long_opts=["board_config=",
783 "package_key=",
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700784 "incremental_from=",
Doug Zongker962069c2009-04-23 11:41:58 -0700785 "wipe_user_data",
Doug Zongker1c390a22009-05-14 19:06:36 -0700786 "no_prereq",
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700787 "extra_script=",
Hristo Bojinov96be7202010-08-02 10:26:17 -0700788 "worker_threads=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -0700789 "aslr_mode=",
790 ],
Doug Zongkereef39442009-04-02 12:14:19 -0700791 extra_option_handler=option_handler)
792
793 if len(args) != 2:
794 common.Usage(__doc__)
795 sys.exit(1)
796
Doug Zongker1c390a22009-05-14 19:06:36 -0700797 if OPTIONS.extra_script is not None:
798 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
799
Doug Zongkereef39442009-04-02 12:14:19 -0700800 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -0800801 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -0700802
Doug Zongkereef39442009-04-02 12:14:19 -0700803 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -0700804 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -0700805
806 # If this image was originally labelled with SELinux contexts, make sure we
807 # also apply the labels in our new image. During building, the "file_contexts"
808 # is in the out/ directory tree, but for repacking from target-files.zip it's
809 # in the root directory of the ramdisk.
810 if "selinux_fc" in OPTIONS.info_dict:
811 OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK",
812 "file_contexts")
813
Doug Zongker37974732010-09-16 17:44:38 -0700814 if OPTIONS.verbose:
815 print "--- target info ---"
816 common.DumpInfoDict(OPTIONS.info_dict)
817
818 if OPTIONS.device_specific is None:
819 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
820 if OPTIONS.device_specific is not None:
821 OPTIONS.device_specific = os.path.normpath(OPTIONS.device_specific)
822 print "using device-specific extensions in", OPTIONS.device_specific
823
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700824 temp_zip_file = tempfile.NamedTemporaryFile()
825 output_zip = zipfile.ZipFile(temp_zip_file, "w",
826 compression=zipfile.ZIP_DEFLATED)
Doug Zongkereef39442009-04-02 12:14:19 -0700827
828 if OPTIONS.incremental_source is None:
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700829 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700830 if OPTIONS.package_key is None:
831 OPTIONS.package_key = OPTIONS.info_dict.get(
832 "default_system_dev_certificate",
833 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -0700834 else:
835 print "unzipping source target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -0800836 OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
Doug Zongker37974732010-09-16 17:44:38 -0700837 OPTIONS.target_info_dict = OPTIONS.info_dict
838 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700839 if OPTIONS.package_key is None:
Doug Zongker91b4f8a2011-09-23 12:48:33 -0700840 OPTIONS.package_key = OPTIONS.source_info_dict.get(
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700841 "default_system_dev_certificate",
842 "build/target/product/security/testkey")
Doug Zongker37974732010-09-16 17:44:38 -0700843 if OPTIONS.verbose:
844 print "--- source info ---"
845 common.DumpInfoDict(OPTIONS.source_info_dict)
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700846 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700847
848 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700849
850 SignOutput(temp_zip_file.name, args[1])
851 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -0700852
853 common.Cleanup()
854
855 print "done."
856
857
858if __name__ == '__main__':
859 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -0800860 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -0700861 main(sys.argv[1:])
862 except common.ExternalError, e:
863 print
864 print " ERROR: %s" % (e,)
865 print
866 sys.exit(1)