blob: 1e1d04e24d911bb537fd52b24b4e24d718c41b3d [file] [log] [blame]
Doug Zongkereef39442009-04-02 12:14:19 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2008 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""
18Given a target-files zipfile, produces an OTA package that installs
19that build. An incremental OTA is produced if -i is given, otherwise
20a full OTA is produced.
21
22Usage: ota_from_target_files [flags] input_target_files output_ota_package
23
24 -b (--board_config) <file>
Doug Zongkerfdd8e692009-08-03 17:27:48 -070025 Deprecated.
Doug Zongkereef39442009-04-02 12:14:19 -070026
Doug Zongkerafb32ea2011-09-22 10:28:04 -070027 -k (--package_key) <key> Key to use to sign the package (default is
28 the value of default_system_dev_certificate from the input
29 target-files's META/misc_info.txt, or
30 "build/target/product/security/testkey" if that value is not
31 specified).
32
33 For incremental OTAs, the default value is based on the source
34 target-file, not the target build.
Doug Zongkereef39442009-04-02 12:14:19 -070035
36 -i (--incremental_from) <file>
37 Generate an incremental OTA using the given target-files zip as
38 the starting build.
39
Doug Zongkerdbfaae52009-04-21 17:12:54 -070040 -w (--wipe_user_data)
41 Generate an OTA package that will wipe the user data partition
42 when installed.
43
Doug Zongker962069c2009-04-23 11:41:58 -070044 -n (--no_prereq)
45 Omit the timestamp prereq check normally included at the top of
46 the build scripts (used for developer OTA packages which
47 legitimately need to go back and forth).
48
Doug Zongker1c390a22009-05-14 19:06:36 -070049 -e (--extra_script) <file>
50 Insert the contents of file at the end of the update script.
51
Hristo Bojinovdafb0422010-08-26 14:35:16 -070052 -a (--aslr_mode) <on|off>
53 Specify whether to turn on ASLR for the package (on by default).
Stephen Smalley56882bf2012-02-09 13:36:21 -050054
Doug Zongkereef39442009-04-02 12:14:19 -070055"""
56
57import sys
58
59if sys.hexversion < 0x02040000:
60 print >> sys.stderr, "Python 2.4 or newer is required."
61 sys.exit(1)
62
63import copy
Doug Zongkerc18736b2009-09-30 09:20:32 -070064import errno
Doug Zongkereef39442009-04-02 12:14:19 -070065import os
66import re
Doug Zongkereef39442009-04-02 12:14:19 -070067import subprocess
68import tempfile
69import time
70import zipfile
71
davidcad0bb92011-03-15 14:21:38 +000072try:
73 from hashlib import sha1 as sha1
74except ImportError:
75 from sha import sha as sha1
76
Doug Zongkereef39442009-04-02 12:14:19 -070077import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -070078import edify_generator
Doug Zongkereef39442009-04-02 12:14:19 -070079
80OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -070081OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -070082OPTIONS.incremental_source = None
83OPTIONS.require_verbatim = set()
84OPTIONS.prohibit_verbatim = set(("system/build.prop",))
85OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -070086OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -070087OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -070088OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -070089OPTIONS.aslr_mode = True
Doug Zongker761e6422009-09-25 10:45:39 -070090OPTIONS.worker_threads = 3
Doug Zongkereef39442009-04-02 12:14:19 -070091
92def MostPopularKey(d, default):
93 """Given a dict, return the key corresponding to the largest
94 value. Returns 'default' if the dict is empty."""
95 x = [(v, k) for (k, v) in d.iteritems()]
96 if not x: return default
97 x.sort()
98 return x[-1][1]
99
100
101def IsSymlink(info):
102 """Return true if the zipfile.ZipInfo object passed in represents a
103 symlink."""
104 return (info.external_attr >> 16) == 0120777
105
Hristo Bojinov96be7202010-08-02 10:26:17 -0700106def IsRegular(info):
107 """Return true if the zipfile.ZipInfo object passed in represents a
108 symlink."""
109 return (info.external_attr >> 28) == 010
Doug Zongkereef39442009-04-02 12:14:19 -0700110
Doug Zongkereef39442009-04-02 12:14:19 -0700111class Item:
112 """Items represent the metadata (user, group, mode) of files and
113 directories in the system image."""
114 ITEMS = {}
115 def __init__(self, name, dir=False):
116 self.name = name
117 self.uid = None
118 self.gid = None
119 self.mode = None
120 self.dir = dir
121
122 if name:
123 self.parent = Item.Get(os.path.dirname(name), dir=True)
124 self.parent.children.append(self)
125 else:
126 self.parent = None
127 if dir:
128 self.children = []
129
130 def Dump(self, indent=0):
131 if self.uid is not None:
132 print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode)
133 else:
134 print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode)
135 if self.dir:
136 print "%s%s" % (" "*indent, self.descendants)
137 print "%s%s" % (" "*indent, self.best_subtree)
138 for i in self.children:
139 i.Dump(indent=indent+1)
140
141 @classmethod
142 def Get(cls, name, dir=False):
143 if name not in cls.ITEMS:
144 cls.ITEMS[name] = Item(name, dir=dir)
145 return cls.ITEMS[name]
146
147 @classmethod
Doug Zongker283e2a12010-03-15 17:52:32 -0700148 def GetMetadata(cls, input_zip):
149
150 try:
151 # See if the target_files contains a record of what the uid,
152 # gid, and mode is supposed to be.
153 output = input_zip.read("META/filesystem_config.txt")
154 except KeyError:
155 # Run the external 'fs_config' program to determine the desired
156 # uid, gid, and mode for every Item object. Note this uses the
157 # one in the client now, which might not be the same as the one
158 # used when this target_files was built.
159 p = common.Run(["fs_config"], stdin=subprocess.PIPE,
160 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
161 suffix = { False: "", True: "/" }
162 input = "".join(["%s%s\n" % (i.name, suffix[i.dir])
163 for i in cls.ITEMS.itervalues() if i.name])
Doug Zongker3475d362010-03-17 16:39:30 -0700164 output, error = p.communicate(input)
Doug Zongker283e2a12010-03-15 17:52:32 -0700165 assert not error
Doug Zongkereef39442009-04-02 12:14:19 -0700166
167 for line in output.split("\n"):
168 if not line: continue
Michael Rungefb9bb202013-07-22 20:42:44 +0000169 name, uid, gid, mode = line.split()
Doug Zongker283e2a12010-03-15 17:52:32 -0700170 i = cls.ITEMS.get(name, None)
171 if i is not None:
172 i.uid = int(uid)
173 i.gid = int(gid)
174 i.mode = int(mode, 8)
175 if i.dir:
176 i.children.sort(key=lambda i: i.name)
177
178 # set metadata for the files generated by this script.
179 i = cls.ITEMS.get("system/recovery-from-boot.p", None)
Michael Rungefb9bb202013-07-22 20:42:44 +0000180 if i: i.uid, i.gid, i.mode = 0, 0, 0644
Doug Zongker283e2a12010-03-15 17:52:32 -0700181 i = cls.ITEMS.get("system/etc/install-recovery.sh", None)
Michael Rungefb9bb202013-07-22 20:42:44 +0000182 if i: i.uid, i.gid, i.mode = 0, 0, 0544
Doug Zongkereef39442009-04-02 12:14:19 -0700183
184 def CountChildMetadata(self):
Michael Rungefb9bb202013-07-22 20:42:44 +0000185 """Count up the (uid, gid, mode) tuples for all children and
Doug Zongkereef39442009-04-02 12:14:19 -0700186 determine the best strategy for using set_perm_recursive and
187 set_perm to correctly chown/chmod all the files to their desired
188 values. Recursively calls itself for all descendants.
189
Michael Rungefb9bb202013-07-22 20:42:44 +0000190 Returns a dict of {(uid, gid, dmode, fmode): count} counting up
Doug Zongkereef39442009-04-02 12:14:19 -0700191 all descendants of this node. (dmode or fmode may be None.) Also
192 sets the best_subtree of each directory Item to the (uid, gid,
Michael Rungefb9bb202013-07-22 20:42:44 +0000193 dmode, fmode) tuple that will match the most descendants of that
Doug Zongkereef39442009-04-02 12:14:19 -0700194 Item.
195 """
196
197 assert self.dir
Michael Rungefb9bb202013-07-22 20:42:44 +0000198 d = self.descendants = {(self.uid, self.gid, self.mode, None): 1}
Doug Zongkereef39442009-04-02 12:14:19 -0700199 for i in self.children:
200 if i.dir:
201 for k, v in i.CountChildMetadata().iteritems():
202 d[k] = d.get(k, 0) + v
203 else:
Michael Rungefb9bb202013-07-22 20:42:44 +0000204 k = (i.uid, i.gid, None, i.mode)
Doug Zongkereef39442009-04-02 12:14:19 -0700205 d[k] = d.get(k, 0) + 1
206
Michael Rungefb9bb202013-07-22 20:42:44 +0000207 # Find the (uid, gid, dmode, fmode) tuple that matches the most
Doug Zongkereef39442009-04-02 12:14:19 -0700208 # descendants.
209
210 # First, find the (uid, gid) pair that matches the most
211 # descendants.
212 ug = {}
Michael Rungefb9bb202013-07-22 20:42:44 +0000213 for (uid, gid, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700214 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
215 ug = MostPopularKey(ug, (0, 0))
216
Michael Rungefb9bb202013-07-22 20:42:44 +0000217 # Now find the dmode and fmode that match the most descendants
Doug Zongkereef39442009-04-02 12:14:19 -0700218 # with that (uid, gid), and choose those.
219 best_dmode = (0, 0755)
220 best_fmode = (0, 0644)
221 for k, count in d.iteritems():
222 if k[:2] != ug: continue
223 if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2])
224 if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3])
Michael Rungefb9bb202013-07-22 20:42:44 +0000225 self.best_subtree = ug + (best_dmode[1], best_fmode[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700226
227 return d
228
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700229 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700230 """Append set_perm/set_perm_recursive commands to 'script' to
231 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700232 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700233
234 self.CountChildMetadata()
235
236 def recurse(item, current):
Michael Rungefb9bb202013-07-22 20:42:44 +0000237 # current is the (uid, gid, dmode, fmode) tuple that the current
Doug Zongkereef39442009-04-02 12:14:19 -0700238 # item (and all its children) have already been set to. We only
239 # need to issue set_perm/set_perm_recursive commands if we're
240 # supposed to be something different.
241 if item.dir:
242 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700243 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700244 current = item.best_subtree
245
246 if item.uid != current[0] or item.gid != current[1] or \
Michael Rungefb9bb202013-07-22 20:42:44 +0000247 item.mode != current[2]:
248 script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode)
Doug Zongkereef39442009-04-02 12:14:19 -0700249
250 for i in item.children:
251 recurse(i, current)
252 else:
253 if item.uid != current[0] or item.gid != current[1] or \
Michael Rungefb9bb202013-07-22 20:42:44 +0000254 item.mode != current[3]:
255 script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode)
Doug Zongkereef39442009-04-02 12:14:19 -0700256
Michael Rungefb9bb202013-07-22 20:42:44 +0000257 recurse(self, (-1, -1, -1, -1))
Doug Zongkereef39442009-04-02 12:14:19 -0700258
259
260def CopySystemFiles(input_zip, output_zip=None,
261 substitute=None):
262 """Copies files underneath system/ in the input zip to the output
263 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800264 list of symlinks. output_zip may be None, in which case the copy is
265 skipped (but the other side effects still happen). substitute is an
266 optional dict of {output filename: contents} to be output instead of
267 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700268 """
269
270 symlinks = []
271
272 for info in input_zip.infolist():
273 if info.filename.startswith("SYSTEM/"):
274 basefilename = info.filename[7:]
275 if IsSymlink(info):
276 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700277 "/system/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700278 else:
279 info2 = copy.copy(info)
280 fn = info2.filename = "system/" + basefilename
281 if substitute and fn in substitute and substitute[fn] is None:
282 continue
283 if output_zip is not None:
284 if substitute and fn in substitute:
285 data = substitute[fn]
286 else:
287 data = input_zip.read(info.filename)
288 output_zip.writestr(info2, data)
289 if fn.endswith("/"):
290 Item.Get(fn[:-1], dir=True)
291 else:
292 Item.Get(fn, dir=False)
293
294 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800295 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700296
297
Doug Zongkereef39442009-04-02 12:14:19 -0700298def SignOutput(temp_zip_name, output_zip_name):
299 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
300 pw = key_passwords[OPTIONS.package_key]
301
Doug Zongker951495f2009-08-14 12:44:19 -0700302 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
303 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700304
305
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700306def AppendAssertions(script, info_dict):
307 device = GetBuildProp("ro.product.device", info_dict)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700308 script.AssertDevice(device)
Doug Zongkereef39442009-04-02 12:14:19 -0700309
Doug Zongkereef39442009-04-02 12:14:19 -0700310
Doug Zongkerb32161a2012-08-21 10:33:44 -0700311def MakeRecoveryPatch(input_tmp, output_zip, recovery_img, boot_img):
Doug Zongker73ef8252009-07-23 15:12:53 -0700312 """Generate a binary patch that creates the recovery image starting
313 with the boot image. (Most of the space in these images is just the
314 kernel, which is identical for the two, so the resulting patch
315 should be efficient.) Add it to the output zip, along with a shell
316 script that is run from init.rc on first boot to actually do the
317 patching and install the new recovery image.
318
319 recovery_img and boot_img should be File objects for the
Doug Zongker67369982010-07-07 13:53:32 -0700320 corresponding images. info should be the dictionary returned by
321 common.LoadInfoDict() on the input target_files.
Doug Zongker73ef8252009-07-23 15:12:53 -0700322
323 Returns an Item for the shell script, which must be made
324 executable.
325 """
326
Doug Zongkerb32161a2012-08-21 10:33:44 -0700327 diff_program = ["imgdiff"]
328 path = os.path.join(input_tmp, "SYSTEM", "etc", "recovery-resource.dat")
329 if os.path.exists(path):
330 diff_program.append("-b")
331 diff_program.append(path)
332 bonus_args = "-b /system/etc/recovery-resource.dat"
333 else:
334 bonus_args = ""
335
336 d = common.Difference(recovery_img, boot_img, diff_program=diff_program)
Doug Zongker761e6422009-09-25 10:45:39 -0700337 _, _, patch = d.ComputePatch()
Doug Zongkercfd7db62009-10-07 11:35:53 -0700338 common.ZipWriteStr(output_zip, "recovery/recovery-from-boot.p", patch)
Doug Zongker73ef8252009-07-23 15:12:53 -0700339 Item.Get("system/recovery-from-boot.p", dir=False)
340
Doug Zongker96a57e72010-09-26 14:57:41 -0700341 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
342 recovery_type, recovery_device = common.GetTypeAndDevice("/recovery", OPTIONS.info_dict)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700343
Doug Zongker73ef8252009-07-23 15:12:53 -0700344 sh = """#!/system/bin/sh
Doug Zongker0276d182011-12-02 10:46:59 -0800345if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then
Doug Zongker73ef8252009-07-23 15:12:53 -0700346 log -t recovery "Installing new recovery image"
Doug Zongkerb32161a2012-08-21 10:33:44 -0700347 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 -0700348else
349 log -t recovery "Recovery image already installed"
350fi
351""" % { 'boot_size': boot_img.size,
352 'boot_sha1': boot_img.sha1,
Doug Zongker73ef8252009-07-23 15:12:53 -0700353 'recovery_size': recovery_img.size,
Doug Zongker67369982010-07-07 13:53:32 -0700354 'recovery_sha1': recovery_img.sha1,
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700355 'boot_type': boot_type,
356 'boot_device': boot_device,
357 'recovery_type': recovery_type,
358 'recovery_device': recovery_device,
Doug Zongkerb32161a2012-08-21 10:33:44 -0700359 'bonus_args': bonus_args,
Doug Zongker67369982010-07-07 13:53:32 -0700360 }
Doug Zongkercfd7db62009-10-07 11:35:53 -0700361 common.ZipWriteStr(output_zip, "recovery/etc/install-recovery.sh", sh)
Doug Zongker73ef8252009-07-23 15:12:53 -0700362 return Item.Get("system/etc/install-recovery.sh", dir=False)
363
364
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700365def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700366 # TODO: how to determine this? We don't know what version it will
367 # be installed on top of. For now, we expect the API just won't
368 # change very often.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700369 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700370
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700371 metadata = {"post-build": GetBuildProp("ro.build.fingerprint",
372 OPTIONS.info_dict),
373 "pre-device": GetBuildProp("ro.product.device",
374 OPTIONS.info_dict),
375 "post-timestamp": GetBuildProp("ro.build.date.utc",
376 OPTIONS.info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700377 }
378
Doug Zongker05d3dea2009-06-22 11:32:31 -0700379 device_specific = common.DeviceSpecificParams(
380 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700381 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700382 output_zip=output_zip,
383 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700384 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700385 metadata=metadata,
386 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700387
Doug Zongker962069c2009-04-23 11:41:58 -0700388 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700389 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700390 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
391 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700392
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700393 AppendAssertions(script, OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700394 device_specific.FullOTA_Assertions()
Doug Zongkere5ff5902012-01-17 10:55:37 -0800395 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700396
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700397 script.ShowProgress(0.5, 0)
Doug Zongkereef39442009-04-02 12:14:19 -0700398
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700399 if OPTIONS.wipe_user_data:
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700400 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700401
Kenny Rootf32dc712012-04-08 10:42:34 -0700402 if "selinux_fc" in OPTIONS.info_dict:
403 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500404
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700405 script.FormatPartition("/system")
406 script.Mount("/system")
Doug Zongkercfd7db62009-10-07 11:35:53 -0700407 script.UnpackPackageDir("recovery", "/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700408 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700409
Doug Zongker1807e702012-02-28 12:21:08 -0800410 symlinks = CopySystemFiles(input_zip, output_zip)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700411 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700412
Doug Zongker55d93282011-01-25 17:03:34 -0800413 boot_img = common.GetBootableImage("boot.img", "boot.img",
414 OPTIONS.input_tmp, "BOOT")
415 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
416 OPTIONS.input_tmp, "RECOVERY")
Doug Zongkerb32161a2012-08-21 10:33:44 -0700417 MakeRecoveryPatch(OPTIONS.input_tmp, output_zip, recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700418
Doug Zongker283e2a12010-03-15 17:52:32 -0700419 Item.GetMetadata(input_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700420 Item.Get("system").SetPermissions(script)
421
Doug Zongker37974732010-09-16 17:44:38 -0700422 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700423 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700424 script.ShowProgress(0.2, 0)
425
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700426 script.ShowProgress(0.2, 10)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700427 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700428
429 script.ShowProgress(0.1, 0)
430 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700431
Doug Zongker1c390a22009-05-14 19:06:36 -0700432 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700433 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700434
Doug Zongker14833602010-02-02 13:12:04 -0800435 script.UnmountAll()
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700436 script.AddToZip(input_zip, output_zip)
Doug Zongker2ea21062010-04-28 16:05:21 -0700437 WriteMetadata(metadata, output_zip)
438
Stephen Smalley56882bf2012-02-09 13:36:21 -0500439def WritePolicyConfig(file_context, output_zip):
440 f = open(file_context, 'r');
441 basename = os.path.basename(file_context)
442 common.ZipWriteStr(output_zip, basename, f.read())
443
Doug Zongker2ea21062010-04-28 16:05:21 -0700444
445def WriteMetadata(metadata, output_zip):
446 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
447 "".join(["%s=%s\n" % kv
448 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700449
Doug Zongkereef39442009-04-02 12:14:19 -0700450def LoadSystemFiles(z):
451 """Load all the files from SYSTEM/... in a given target-files
452 ZipFile, and return a dict of {filename: File object}."""
453 out = {}
454 for info in z.infolist():
455 if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
Hristo Bojinov96be7202010-08-02 10:26:17 -0700456 basefilename = info.filename[7:]
457 fn = "system/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700458 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700459 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800460 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700461
462
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700463def GetBuildProp(prop, info_dict):
464 """Return the fingerprint of the build of a given target-files info_dict."""
465 try:
466 return info_dict.get("build.prop", {})[prop]
467 except KeyError:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700468 raise common.ExternalError("couldn't find %s in build.prop" % (property,))
Doug Zongkereef39442009-04-02 12:14:19 -0700469
470
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700471def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Doug Zongker37974732010-09-16 17:44:38 -0700472 source_version = OPTIONS.source_info_dict["recovery_api_version"]
473 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700474
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700475 if source_version == 0:
476 print ("WARNING: generating edify script for a source that "
477 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700478 script = edify_generator.EdifyGenerator(source_version,
479 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700480
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700481 metadata = {"pre-device": GetBuildProp("ro.product.device",
482 OPTIONS.source_info_dict),
483 "post-timestamp": GetBuildProp("ro.build.date.utc",
484 OPTIONS.target_info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700485 }
486
Doug Zongker05d3dea2009-06-22 11:32:31 -0700487 device_specific = common.DeviceSpecificParams(
488 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800489 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700490 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800491 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700492 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -0700493 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -0700494 metadata=metadata,
495 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700496
Doug Zongkereef39442009-04-02 12:14:19 -0700497 print "Loading target..."
Doug Zongker1807e702012-02-28 12:21:08 -0800498 target_data = LoadSystemFiles(target_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700499 print "Loading source..."
Doug Zongker1807e702012-02-28 12:21:08 -0800500 source_data = LoadSystemFiles(source_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700501
502 verbatim_targets = []
503 patch_list = []
Doug Zongker761e6422009-09-25 10:45:39 -0700504 diffs = []
Doug Zongkereef39442009-04-02 12:14:19 -0700505 largest_source_size = 0
506 for fn in sorted(target_data.keys()):
507 tf = target_data[fn]
Doug Zongker761e6422009-09-25 10:45:39 -0700508 assert fn == tf.name
Doug Zongkereef39442009-04-02 12:14:19 -0700509 sf = source_data.get(fn, None)
510
511 if sf is None or fn in OPTIONS.require_verbatim:
512 # This file should be included verbatim
513 if fn in OPTIONS.prohibit_verbatim:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700514 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
Doug Zongkereef39442009-04-02 12:14:19 -0700515 print "send", fn, "verbatim"
516 tf.AddToZip(output_zip)
517 verbatim_targets.append((fn, tf.size))
518 elif tf.sha1 != sf.sha1:
519 # File is different; consider sending as a patch
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700520 diffs.append(common.Difference(tf, sf))
Doug Zongkereef39442009-04-02 12:14:19 -0700521 else:
522 # Target file identical to source.
523 pass
524
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700525 common.ComputeDifferences(diffs)
Doug Zongker761e6422009-09-25 10:45:39 -0700526
527 for diff in diffs:
528 tf, sf, d = diff.GetPatch()
529 if d is None or len(d) > tf.size * OPTIONS.patch_threshold:
530 # patch is almost as big as the file; don't bother patching
531 tf.AddToZip(output_zip)
532 verbatim_targets.append((tf.name, tf.size))
533 else:
534 common.ZipWriteStr(output_zip, "patch/" + tf.name + ".p", d)
Doug Zongker55d93282011-01-25 17:03:34 -0800535 patch_list.append((tf.name, tf, sf, tf.size, common.sha1(d).hexdigest()))
Doug Zongker761e6422009-09-25 10:45:39 -0700536 largest_source_size = max(largest_source_size, sf.size)
Doug Zongkereef39442009-04-02 12:14:19 -0700537
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700538 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
539 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
Doug Zongker2ea21062010-04-28 16:05:21 -0700540 metadata["pre-build"] = source_fp
541 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -0700542
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700543 script.Mount("/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700544 script.AssertSomeFingerprint(source_fp, target_fp)
Doug Zongkereef39442009-04-02 12:14:19 -0700545
Doug Zongker55d93282011-01-25 17:03:34 -0800546 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700547 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
548 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -0800549 target_boot = common.GetBootableImage(
550 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker5da317e2009-06-02 13:38:17 -0700551 updating_boot = (source_boot.data != target_boot.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700552
Doug Zongker55d93282011-01-25 17:03:34 -0800553 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700554 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
555 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -0800556 target_recovery = common.GetBootableImage(
557 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -0700558 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700559
Doug Zongker881dd402009-09-20 14:03:55 -0700560 # Here's how we divide up the progress bar:
561 # 0.1 for verifying the start state (PatchCheck calls)
562 # 0.8 for applying patches (ApplyPatch calls)
563 # 0.1 for unpacking verbatim files, symlinking, and doing the
564 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -0700565
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700566 AppendAssertions(script, OPTIONS.target_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700567 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -0700568
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700569 script.Print("Verifying current system...")
570
Doug Zongkere5ff5902012-01-17 10:55:37 -0800571 device_specific.IncrementalOTA_VerifyBegin()
572
Doug Zongker881dd402009-09-20 14:03:55 -0700573 script.ShowProgress(0.1, 0)
574 total_verify_size = float(sum([i[2].size for i in patch_list]) + 1)
575 if updating_boot:
576 total_verify_size += source_boot.size
577 so_far = 0
Doug Zongkereef39442009-04-02 12:14:19 -0700578
Doug Zongker5a482092010-02-17 16:09:18 -0800579 for fn, tf, sf, size, patch_sha in patch_list:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700580 script.PatchCheck("/"+fn, tf.sha1, sf.sha1)
Doug Zongker881dd402009-09-20 14:03:55 -0700581 so_far += sf.size
582 script.SetProgress(so_far / total_verify_size)
Doug Zongkereef39442009-04-02 12:14:19 -0700583
Doug Zongker5da317e2009-06-02 13:38:17 -0700584 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700585 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -0700586 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -0700587 print "boot target: %d source: %d diff: %d" % (
588 target_boot.size, source_boot.size, len(d))
589
Doug Zongker048e7ca2009-06-15 14:31:53 -0700590 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -0700591
Doug Zongker96a57e72010-09-26 14:57:41 -0700592 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -0700593
594 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
595 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -0700596 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700597 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -0700598 so_far += source_boot.size
599 script.SetProgress(so_far / total_verify_size)
Doug Zongker5da317e2009-06-02 13:38:17 -0700600
601 if patch_list or updating_recovery or updating_boot:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700602 script.CacheFreeSpaceCheck(largest_source_size)
Doug Zongker5a482092010-02-17 16:09:18 -0800603
Doug Zongker05d3dea2009-06-22 11:32:31 -0700604 device_specific.IncrementalOTA_VerifyEnd()
605
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700606 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -0700607
Doug Zongkere5ff5902012-01-17 10:55:37 -0800608 device_specific.IncrementalOTA_InstallBegin()
609
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700610 if OPTIONS.wipe_user_data:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700611 script.Print("Erasing user data...")
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700612 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700613
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700614 script.Print("Removing unneeded files...")
Doug Zongker0f3298a2009-06-30 08:16:58 -0700615 script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
616 ["/"+i for i in sorted(source_data)
Doug Zongker3b949f02009-08-24 10:24:32 -0700617 if i not in target_data] +
618 ["/system/recovery.img"])
Doug Zongkereef39442009-04-02 12:14:19 -0700619
Doug Zongker881dd402009-09-20 14:03:55 -0700620 script.ShowProgress(0.8, 0)
621 total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
622 if updating_boot:
623 total_patch_size += target_boot.size
624 so_far = 0
625
626 script.Print("Patching system files...")
Doug Zongkere92f15a2011-08-26 13:46:40 -0700627 deferred_patch_list = []
628 for item in patch_list:
629 fn, tf, sf, size, _ = item
630 if tf.name == "system/build.prop":
631 deferred_patch_list.append(item)
632 continue
Doug Zongkerc8d446b2010-02-22 15:41:53 -0800633 script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
Doug Zongker881dd402009-09-20 14:03:55 -0700634 so_far += tf.size
635 script.SetProgress(so_far / total_patch_size)
636
Doug Zongkereef39442009-04-02 12:14:19 -0700637 if updating_boot:
Doug Zongker5da317e2009-06-02 13:38:17 -0700638 # Produce the boot image by applying a patch to the current
639 # contents of the boot partition, and write it back to the
640 # partition.
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700641 script.Print("Patching boot image...")
Doug Zongkerf2ab2902010-09-22 10:12:54 -0700642 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
643 % (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -0700644 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700645 target_boot.size, target_boot.sha1),
646 "-",
647 target_boot.size, target_boot.sha1,
Doug Zongkerc8d446b2010-02-22 15:41:53 -0800648 source_boot.sha1, "patch/boot.img.p")
Doug Zongker881dd402009-09-20 14:03:55 -0700649 so_far += target_boot.size
650 script.SetProgress(so_far / total_patch_size)
Doug Zongkereef39442009-04-02 12:14:19 -0700651 print "boot image changed; including."
652 else:
653 print "boot image unchanged; skipping."
654
655 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -0700656 # Recovery is generated as a patch using both the boot image
657 # (which contains the same linux kernel as recovery) and the file
658 # /system/etc/recovery-resource.dat (which contains all the images
659 # used in the recovery UI) as sources. This lets us minimize the
660 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -0700661 #
Doug Zongkerb32161a2012-08-21 10:33:44 -0700662 # For older builds where recovery-resource.dat is not present, we
663 # use only the boot image as the source.
664
665 MakeRecoveryPatch(OPTIONS.target_tmp, output_zip,
666 target_recovery, target_boot)
Doug Zongker42265392010-02-12 10:21:00 -0800667 script.DeleteFiles(["/system/recovery-from-boot.p",
668 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -0700669 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -0700670 else:
671 print "recovery image unchanged; skipping."
672
Doug Zongker881dd402009-09-20 14:03:55 -0700673 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -0700674
Doug Zongker1807e702012-02-28 12:21:08 -0800675 target_symlinks = CopySystemFiles(target_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700676
677 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700678 temp_script = script.MakeTemporary()
Doug Zongker283e2a12010-03-15 17:52:32 -0700679 Item.GetMetadata(target_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -0700680 Item.Get("system").SetPermissions(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -0700681
682 # Note that this call will mess up the tree of Items, so make sure
683 # we're done with it.
Doug Zongker1807e702012-02-28 12:21:08 -0800684 source_symlinks = CopySystemFiles(source_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700685 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
686
687 # Delete all the symlinks in source that aren't in target. This
688 # needs to happen before verbatim files are unpacked, in case a
689 # symlink in the source is replaced by a real file in the target.
690 to_delete = []
691 for dest, link in source_symlinks:
692 if link not in target_symlinks_d:
693 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700694 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -0700695
696 if verbatim_targets:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700697 script.Print("Unpacking new files...")
698 script.UnpackPackageDir("system", "/system")
699
Doug Zongker42265392010-02-12 10:21:00 -0800700 if updating_recovery:
701 script.Print("Unpacking new recovery...")
702 script.UnpackPackageDir("recovery", "/system")
703
Doug Zongker05d3dea2009-06-22 11:32:31 -0700704 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -0700705
706 # Create all the symlinks that don't already exist, or point to
707 # somewhere different than what we want. Delete each symlink before
708 # creating it, since the 'symlink' command won't overwrite.
709 to_create = []
710 for dest, link in target_symlinks:
711 if link in source_symlinks_d:
712 if dest != source_symlinks_d[link]:
713 to_create.append((dest, link))
714 else:
715 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700716 script.DeleteFiles([i[1] for i in to_create])
717 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -0700718
719 # Now that the symlinks are created, we can set all the
720 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700721 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -0700722
Doug Zongker881dd402009-09-20 14:03:55 -0700723 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -0700724 device_specific.IncrementalOTA_InstallEnd()
725
Doug Zongker1c390a22009-05-14 19:06:36 -0700726 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -0700727 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700728
Doug Zongkere92f15a2011-08-26 13:46:40 -0700729 # Patch the build.prop file last, so if something fails but the
730 # device can still come up, it appears to be the old build and will
731 # get set the OTA package again to retry.
732 script.Print("Patching remaining system files...")
733 for item in deferred_patch_list:
734 fn, tf, sf, size, _ = item
735 script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
Michael Rungefb9bb202013-07-22 20:42:44 +0000736 script.SetPermissions("/system/build.prop", 0, 0, 0644)
Doug Zongkere92f15a2011-08-26 13:46:40 -0700737
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700738 script.AddToZip(target_zip, output_zip)
Doug Zongker2ea21062010-04-28 16:05:21 -0700739 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700740
741
742def main(argv):
743
744 def option_handler(o, a):
745 if o in ("-b", "--board_config"):
Doug Zongkerfdd8e692009-08-03 17:27:48 -0700746 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -0700747 elif o in ("-k", "--package_key"):
748 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -0700749 elif o in ("-i", "--incremental_from"):
750 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700751 elif o in ("-w", "--wipe_user_data"):
752 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -0700753 elif o in ("-n", "--no_prereq"):
754 OPTIONS.omit_prereq = True
Doug Zongker1c390a22009-05-14 19:06:36 -0700755 elif o in ("-e", "--extra_script"):
756 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700757 elif o in ("-a", "--aslr_mode"):
758 if a in ("on", "On", "true", "True", "yes", "Yes"):
759 OPTIONS.aslr_mode = True
760 else:
761 OPTIONS.aslr_mode = False
Doug Zongker761e6422009-09-25 10:45:39 -0700762 elif o in ("--worker_threads"):
763 OPTIONS.worker_threads = int(a)
Doug Zongkereef39442009-04-02 12:14:19 -0700764 else:
765 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700766 return True
Doug Zongkereef39442009-04-02 12:14:19 -0700767
768 args = common.ParseOptions(argv, __doc__,
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700769 extra_opts="b:k:i:d:wne:a:",
Doug Zongkereef39442009-04-02 12:14:19 -0700770 extra_long_opts=["board_config=",
771 "package_key=",
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700772 "incremental_from=",
Doug Zongker962069c2009-04-23 11:41:58 -0700773 "wipe_user_data",
Doug Zongker1c390a22009-05-14 19:06:36 -0700774 "no_prereq",
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700775 "extra_script=",
Hristo Bojinov96be7202010-08-02 10:26:17 -0700776 "worker_threads=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -0700777 "aslr_mode=",
778 ],
Doug Zongkereef39442009-04-02 12:14:19 -0700779 extra_option_handler=option_handler)
780
781 if len(args) != 2:
782 common.Usage(__doc__)
783 sys.exit(1)
784
Doug Zongker1c390a22009-05-14 19:06:36 -0700785 if OPTIONS.extra_script is not None:
786 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
787
Doug Zongkereef39442009-04-02 12:14:19 -0700788 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -0800789 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -0700790
Doug Zongkereef39442009-04-02 12:14:19 -0700791 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -0700792 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -0700793
794 # If this image was originally labelled with SELinux contexts, make sure we
795 # also apply the labels in our new image. During building, the "file_contexts"
796 # is in the out/ directory tree, but for repacking from target-files.zip it's
797 # in the root directory of the ramdisk.
798 if "selinux_fc" in OPTIONS.info_dict:
799 OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK",
800 "file_contexts")
801
Doug Zongker37974732010-09-16 17:44:38 -0700802 if OPTIONS.verbose:
803 print "--- target info ---"
804 common.DumpInfoDict(OPTIONS.info_dict)
805
806 if OPTIONS.device_specific is None:
807 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
808 if OPTIONS.device_specific is not None:
809 OPTIONS.device_specific = os.path.normpath(OPTIONS.device_specific)
810 print "using device-specific extensions in", OPTIONS.device_specific
811
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700812 temp_zip_file = tempfile.NamedTemporaryFile()
813 output_zip = zipfile.ZipFile(temp_zip_file, "w",
814 compression=zipfile.ZIP_DEFLATED)
Doug Zongkereef39442009-04-02 12:14:19 -0700815
816 if OPTIONS.incremental_source is None:
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700817 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700818 if OPTIONS.package_key is None:
819 OPTIONS.package_key = OPTIONS.info_dict.get(
820 "default_system_dev_certificate",
821 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -0700822 else:
823 print "unzipping source target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -0800824 OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
Doug Zongker37974732010-09-16 17:44:38 -0700825 OPTIONS.target_info_dict = OPTIONS.info_dict
826 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700827 if OPTIONS.package_key is None:
Doug Zongker91b4f8a2011-09-23 12:48:33 -0700828 OPTIONS.package_key = OPTIONS.source_info_dict.get(
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700829 "default_system_dev_certificate",
830 "build/target/product/security/testkey")
Doug Zongker37974732010-09-16 17:44:38 -0700831 if OPTIONS.verbose:
832 print "--- source info ---"
833 common.DumpInfoDict(OPTIONS.source_info_dict)
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700834 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700835
836 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700837
838 SignOutput(temp_zip_file.name, args[1])
839 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -0700840
841 common.Cleanup()
842
843 print "done."
844
845
846if __name__ == '__main__':
847 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -0800848 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -0700849 main(sys.argv[1:])
850 except common.ExternalError, e:
851 print
852 print " ERROR: %s" % (e,)
853 print
854 sys.exit(1)