blob: 48631814f17a263d7a7890bae0006f0edf75195c [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
Doug Zongker25568482014-03-03 10:21:27 -080024 --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 Zongker9b23f2c2013-11-25 14:44:12 -080055 -2 (--two_step)
56 Generate a 'two-step' OTA package, where recovery is updated
57 first, so that any changes made to the system partition are done
58 using the new recovery (new kernel, etc.).
59
Doug Zongker26e66192014-02-20 13:22:07 -080060 --block
61 Generate a block-based OTA if possible. Will fall back to a
62 file-based OTA if the target_files is older and doesn't support
63 block-based OTAs.
64
Doug Zongker25568482014-03-03 10:21:27 -080065 -b (--binary) <file>
66 Use the given binary as the update-binary in the output package,
67 instead of the binary in the build's target_files. Use for
68 development only.
69
Doug Zongkereef39442009-04-02 12:14:19 -070070"""
71
72import sys
73
Doug Zongkercf6d5a92014-02-18 10:57:07 -080074if sys.hexversion < 0x02070000:
75 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -070076 sys.exit(1)
77
78import copy
Doug Zongkerc18736b2009-09-30 09:20:32 -070079import errno
Doug Zongkereef39442009-04-02 12:14:19 -070080import os
81import re
Doug Zongkereef39442009-04-02 12:14:19 -070082import subprocess
83import tempfile
84import time
85import zipfile
86
davidcad0bb92011-03-15 14:21:38 +000087try:
88 from hashlib import sha1 as sha1
89except ImportError:
90 from sha import sha as sha1
91
Doug Zongkereef39442009-04-02 12:14:19 -070092import common
Doug Zongker01ce19c2014-02-04 13:48:15 -080093import img_from_target_files
Doug Zongkerc494d7c2009-06-18 08:43:44 -070094import edify_generator
Geremy Condra36bd3652014-02-06 19:45:10 -080095import build_image
Doug Zongkereef39442009-04-02 12:14:19 -070096
97OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -070098OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -070099OPTIONS.incremental_source = None
100OPTIONS.require_verbatim = set()
101OPTIONS.prohibit_verbatim = set(("system/build.prop",))
102OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700103OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700104OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700105OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700106OPTIONS.aslr_mode = True
Doug Zongker761e6422009-09-25 10:45:39 -0700107OPTIONS.worker_threads = 3
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800108OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900109OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800110OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800111OPTIONS.updater_binary = None
Doug Zongkereef39442009-04-02 12:14:19 -0700112
113def MostPopularKey(d, default):
114 """Given a dict, return the key corresponding to the largest
115 value. Returns 'default' if the dict is empty."""
116 x = [(v, k) for (k, v) in d.iteritems()]
117 if not x: return default
118 x.sort()
119 return x[-1][1]
120
121
122def IsSymlink(info):
123 """Return true if the zipfile.ZipInfo object passed in represents a
124 symlink."""
125 return (info.external_attr >> 16) == 0120777
126
Hristo Bojinov96be7202010-08-02 10:26:17 -0700127def IsRegular(info):
128 """Return true if the zipfile.ZipInfo object passed in represents a
129 symlink."""
130 return (info.external_attr >> 28) == 010
Doug Zongkereef39442009-04-02 12:14:19 -0700131
Michael Runge4038aa82013-12-13 18:06:28 -0800132def ClosestFileMatch(src, tgtfiles, existing):
133 """Returns the closest file match between a source file and list
134 of potential matches. The exact filename match is preferred,
135 then the sha1 is searched for, and finally a file with the same
136 basename is evaluated. Rename support in the updater-binary is
137 required for the latter checks to be used."""
138
139 result = tgtfiles.get("path:" + src.name)
140 if result is not None:
141 return result
142
143 if not OPTIONS.target_info_dict.get("update_rename_support", False):
144 return None
145
146 if src.size < 1000:
147 return None
148
149 result = tgtfiles.get("sha1:" + src.sha1)
150 if result is not None and existing.get(result.name) is None:
151 return result
152 result = tgtfiles.get("file:" + src.name.split("/")[-1])
153 if result is not None and existing.get(result.name) is None:
154 return result
155 return None
156
Doug Zongkereef39442009-04-02 12:14:19 -0700157class Item:
158 """Items represent the metadata (user, group, mode) of files and
159 directories in the system image."""
160 ITEMS = {}
161 def __init__(self, name, dir=False):
162 self.name = name
163 self.uid = None
164 self.gid = None
165 self.mode = None
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700166 self.selabel = None
167 self.capabilities = None
Doug Zongkereef39442009-04-02 12:14:19 -0700168 self.dir = dir
169
170 if name:
171 self.parent = Item.Get(os.path.dirname(name), dir=True)
172 self.parent.children.append(self)
173 else:
174 self.parent = None
175 if dir:
176 self.children = []
177
178 def Dump(self, indent=0):
179 if self.uid is not None:
180 print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode)
181 else:
182 print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode)
183 if self.dir:
184 print "%s%s" % (" "*indent, self.descendants)
185 print "%s%s" % (" "*indent, self.best_subtree)
186 for i in self.children:
187 i.Dump(indent=indent+1)
188
189 @classmethod
190 def Get(cls, name, dir=False):
191 if name not in cls.ITEMS:
192 cls.ITEMS[name] = Item(name, dir=dir)
193 return cls.ITEMS[name]
194
195 @classmethod
Doug Zongker283e2a12010-03-15 17:52:32 -0700196 def GetMetadata(cls, input_zip):
197
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700198 # The target_files contains a record of what the uid,
199 # gid, and mode are supposed to be.
200 output = input_zip.read("META/filesystem_config.txt")
Doug Zongkereef39442009-04-02 12:14:19 -0700201
202 for line in output.split("\n"):
203 if not line: continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700204 columns = line.split()
205 name, uid, gid, mode = columns[:4]
206 selabel = None
207 capabilities = None
208
209 # After the first 4 columns, there are a series of key=value
210 # pairs. Extract out the fields we care about.
211 for element in columns[4:]:
212 key, value = element.split("=")
213 if key == "selabel":
214 selabel = value
215 if key == "capabilities":
216 capabilities = value
217
Doug Zongker283e2a12010-03-15 17:52:32 -0700218 i = cls.ITEMS.get(name, None)
219 if i is not None:
220 i.uid = int(uid)
221 i.gid = int(gid)
222 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700223 i.selabel = selabel
224 i.capabilities = capabilities
Doug Zongker283e2a12010-03-15 17:52:32 -0700225 if i.dir:
226 i.children.sort(key=lambda i: i.name)
227
228 # set metadata for the files generated by this script.
229 i = cls.ITEMS.get("system/recovery-from-boot.p", None)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700230 if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0644, None, None
Doug Zongker283e2a12010-03-15 17:52:32 -0700231 i = cls.ITEMS.get("system/etc/install-recovery.sh", None)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700232 if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700233
234 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700235 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
236 all children and determine the best strategy for using set_perm_recursive and
Doug Zongkereef39442009-04-02 12:14:19 -0700237 set_perm to correctly chown/chmod all the files to their desired
238 values. Recursively calls itself for all descendants.
239
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700240 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count} counting up
Doug Zongkereef39442009-04-02 12:14:19 -0700241 all descendants of this node. (dmode or fmode may be None.) Also
242 sets the best_subtree of each directory Item to the (uid, gid,
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700243 dmode, fmode, selabel, capabilities) tuple that will match the most
244 descendants of that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700245 """
246
247 assert self.dir
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700248 d = self.descendants = {(self.uid, self.gid, self.mode, None, self.selabel, self.capabilities): 1}
Doug Zongkereef39442009-04-02 12:14:19 -0700249 for i in self.children:
250 if i.dir:
251 for k, v in i.CountChildMetadata().iteritems():
252 d[k] = d.get(k, 0) + v
253 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700254 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700255 d[k] = d.get(k, 0) + 1
256
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700257 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
258 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700259
260 # First, find the (uid, gid) pair that matches the most
261 # descendants.
262 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700263 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700264 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
265 ug = MostPopularKey(ug, (0, 0))
266
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700267 # Now find the dmode, fmode, selabel, and capabilities that match
268 # the most descendants with that (uid, gid), and choose those.
Doug Zongkereef39442009-04-02 12:14:19 -0700269 best_dmode = (0, 0755)
270 best_fmode = (0, 0644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700271 best_selabel = (0, None)
272 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700273 for k, count in d.iteritems():
274 if k[:2] != ug: continue
275 if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2])
276 if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3])
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700277 if k[4] is not None and count >= best_selabel[0]: best_selabel = (count, k[4])
278 if k[5] is not None and count >= best_capabilities[0]: best_capabilities = (count, k[5])
279 self.best_subtree = ug + (best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700280
281 return d
282
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700283 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700284 """Append set_perm/set_perm_recursive commands to 'script' to
285 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700286 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700287
288 self.CountChildMetadata()
289
290 def recurse(item, current):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700291 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple that the current
Doug Zongkereef39442009-04-02 12:14:19 -0700292 # item (and all its children) have already been set to. We only
293 # need to issue set_perm/set_perm_recursive commands if we're
294 # supposed to be something different.
295 if item.dir:
296 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700297 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700298 current = item.best_subtree
299
300 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700301 item.mode != current[2] or item.selabel != current[4] or \
302 item.capabilities != current[5]:
303 script.SetPermissions("/"+item.name, item.uid, item.gid,
304 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700305
306 for i in item.children:
307 recurse(i, current)
308 else:
309 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700310 item.mode != current[3] or item.selabel != current[4] or \
311 item.capabilities != current[5]:
312 script.SetPermissions("/"+item.name, item.uid, item.gid,
313 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700314
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700315 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700316
317
318def CopySystemFiles(input_zip, output_zip=None,
319 substitute=None):
320 """Copies files underneath system/ in the input zip to the output
321 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800322 list of symlinks. output_zip may be None, in which case the copy is
323 skipped (but the other side effects still happen). substitute is an
324 optional dict of {output filename: contents} to be output instead of
325 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700326 """
327
328 symlinks = []
329
330 for info in input_zip.infolist():
331 if info.filename.startswith("SYSTEM/"):
332 basefilename = info.filename[7:]
333 if IsSymlink(info):
334 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700335 "/system/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700336 else:
337 info2 = copy.copy(info)
338 fn = info2.filename = "system/" + basefilename
339 if substitute and fn in substitute and substitute[fn] is None:
340 continue
341 if output_zip is not None:
342 if substitute and fn in substitute:
343 data = substitute[fn]
344 else:
345 data = input_zip.read(info.filename)
346 output_zip.writestr(info2, data)
347 if fn.endswith("/"):
348 Item.Get(fn[:-1], dir=True)
349 else:
350 Item.Get(fn, dir=False)
351
352 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800353 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700354
355
Doug Zongkereef39442009-04-02 12:14:19 -0700356def SignOutput(temp_zip_name, output_zip_name):
357 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
358 pw = key_passwords[OPTIONS.package_key]
359
Doug Zongker951495f2009-08-14 12:44:19 -0700360 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
361 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700362
363
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700364def AppendAssertions(script, info_dict):
365 device = GetBuildProp("ro.product.device", info_dict)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700366 script.AssertDevice(device)
Doug Zongkereef39442009-04-02 12:14:19 -0700367
Doug Zongkereef39442009-04-02 12:14:19 -0700368
Doug Zongkerc9253822014-02-04 12:17:58 -0800369def HasRecoveryPatch(target_files_zip):
370 try:
371 target_files_zip.getinfo("SYSTEM/recovery-from-boot.p")
372 return True
373 except KeyError:
374 return False
Doug Zongker73ef8252009-07-23 15:12:53 -0700375
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 Zongkerc9253822014-02-04 12:17:58 -0800400 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800401 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800402
Doug Zongker962069c2009-04-23 11:41:58 -0700403 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700404 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700405 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
406 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700407
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700408 AppendAssertions(script, OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700409 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800410
411 # Two-step package strategy (in chronological order, which is *not*
412 # the order in which the generated script has things):
413 #
414 # if stage is not "2/3" or "3/3":
415 # write recovery image to boot partition
416 # set stage to "2/3"
417 # reboot to boot partition and restart recovery
418 # else if stage is "2/3":
419 # write recovery image to recovery partition
420 # set stage to "3/3"
421 # reboot to recovery partition and restart recovery
422 # else:
423 # (stage must be "3/3")
424 # set stage to ""
425 # do normal full package installation:
426 # wipe and install system, boot image, etc.
427 # set up system to update recovery partition on first boot
428 # complete script normally (allow recovery to mark itself finished and reboot)
429
430 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
431 OPTIONS.input_tmp, "RECOVERY")
432 if OPTIONS.two_step:
433 if not OPTIONS.info_dict.get("multistage_support", None):
434 assert False, "two-step packages not supported by this build"
435 fs = OPTIONS.info_dict["fstab"]["/misc"]
436 assert fs.fs_type.upper() == "EMMC", \
437 "two-step packages only supported on devices with EMMC /misc partitions"
438 bcb_dev = {"bcb_dev": fs.device}
439 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
440 script.AppendExtra("""
441if get_stage("%(bcb_dev)s", "stage") == "2/3" then
442""" % bcb_dev)
443 script.WriteRawImage("/recovery", "recovery.img")
444 script.AppendExtra("""
445set_stage("%(bcb_dev)s", "3/3");
446reboot_now("%(bcb_dev)s", "recovery");
447else if get_stage("%(bcb_dev)s", "stage") == "3/3" then
448""" % bcb_dev)
449
Doug Zongkere5ff5902012-01-17 10:55:37 -0800450 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700451
Doug Zongker01ce19c2014-02-04 13:48:15 -0800452 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700453
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700454 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800455 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700456
Kenny Rootf32dc712012-04-08 10:42:34 -0700457 if "selinux_fc" in OPTIONS.info_dict:
458 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500459
Doug Zongker01ce19c2014-02-04 13:48:15 -0800460 script.ShowProgress(system_progress, 30)
Doug Zongker26e66192014-02-20 13:22:07 -0800461 if block_based:
Doug Zongker5fad2032014-02-24 08:13:45 -0800462 mapdata, data = img_from_target_files.BuildSystem(
463 OPTIONS.input_tmp, OPTIONS.info_dict,
464 sparse=False, map_file=True)
465
466 common.ZipWriteStr(output_zip, "system.map", mapdata)
467 common.ZipWriteStr(output_zip, "system.muimg", data)
468 script.WipeBlockDevice("/system")
469 script.WriteRawImage("/system", "system.muimg", mapfn="system.map")
Doug Zongker01ce19c2014-02-04 13:48:15 -0800470 else:
471 script.FormatPartition("/system")
472 script.Mount("/system")
473 if not has_recovery_patch:
474 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800475 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700476
Doug Zongker01ce19c2014-02-04 13:48:15 -0800477 symlinks = CopySystemFiles(input_zip, output_zip)
478 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700479
Doug Zongker55d93282011-01-25 17:03:34 -0800480 boot_img = common.GetBootableImage("boot.img", "boot.img",
481 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800482
483 if not has_recovery_patch:
484 def output_sink(fn, data):
485 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
486 Item.Get("system/" + fn, dir=False)
487
488 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
489 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700490
Doug Zongker01ce19c2014-02-04 13:48:15 -0800491 Item.GetMetadata(input_zip)
492 Item.Get("system").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700493
Doug Zongker37974732010-09-16 17:44:38 -0700494 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700495 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700496
Doug Zongker01ce19c2014-02-04 13:48:15 -0800497 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700498 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700499
Doug Zongker01ce19c2014-02-04 13:48:15 -0800500 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700501 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700502
Doug Zongker1c390a22009-05-14 19:06:36 -0700503 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700504 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700505
Doug Zongker14833602010-02-02 13:12:04 -0800506 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800507
Doug Zongker922206e2014-03-04 13:16:24 -0800508 if OPTIONS.wipe_user_data:
509 script.ShowProgress(0.1, 10)
510 script.FormatPartition("/data")
511
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800512 if OPTIONS.two_step:
513 script.AppendExtra("""
514set_stage("%(bcb_dev)s", "");
515""" % bcb_dev)
516 script.AppendExtra("else\n")
517 script.WriteRawImage("/boot", "recovery.img")
518 script.AppendExtra("""
519set_stage("%(bcb_dev)s", "2/3");
520reboot_now("%(bcb_dev)s", "");
521endif;
522endif;
523""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800524 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700525 WriteMetadata(metadata, output_zip)
526
Stephen Smalley56882bf2012-02-09 13:36:21 -0500527def WritePolicyConfig(file_context, output_zip):
528 f = open(file_context, 'r');
529 basename = os.path.basename(file_context)
530 common.ZipWriteStr(output_zip, basename, f.read())
531
Doug Zongker2ea21062010-04-28 16:05:21 -0700532
533def WriteMetadata(metadata, output_zip):
534 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
535 "".join(["%s=%s\n" % kv
536 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700537
Doug Zongkereef39442009-04-02 12:14:19 -0700538def LoadSystemFiles(z):
539 """Load all the files from SYSTEM/... in a given target-files
540 ZipFile, and return a dict of {filename: File object}."""
541 out = {}
542 for info in z.infolist():
543 if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
Hristo Bojinov96be7202010-08-02 10:26:17 -0700544 basefilename = info.filename[7:]
545 fn = "system/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700546 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700547 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800548 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700549
550
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700551def GetBuildProp(prop, info_dict):
552 """Return the fingerprint of the build of a given target-files info_dict."""
553 try:
554 return info_dict.get("build.prop", {})[prop]
555 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700556 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700557
Michael Runge4038aa82013-12-13 18:06:28 -0800558def AddToKnownPaths(filename, known_paths):
559 if filename[-1] == "/":
560 return
561 dirs = filename.split("/")[:-1]
562 while len(dirs) > 0:
563 path = "/".join(dirs)
564 if path in known_paths:
565 break;
566 known_paths.add(path)
567 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700568
Geremy Condra36bd3652014-02-06 19:45:10 -0800569def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
570 source_version = OPTIONS.source_info_dict["recovery_api_version"]
571 target_version = OPTIONS.target_info_dict["recovery_api_version"]
572
573 if source_version == 0:
574 print ("WARNING: generating edify script for a source that "
575 "can't install it.")
576 script = edify_generator.EdifyGenerator(source_version,
577 OPTIONS.target_info_dict)
578
579 metadata = {"pre-device": GetBuildProp("ro.product.device",
580 OPTIONS.source_info_dict),
581 "post-timestamp": GetBuildProp("ro.build.date.utc",
582 OPTIONS.target_info_dict),
583 }
584
585 device_specific = common.DeviceSpecificParams(
586 source_zip=source_zip,
587 source_version=source_version,
588 target_zip=target_zip,
589 target_version=target_version,
590 output_zip=output_zip,
591 script=script,
592 metadata=metadata,
593 info_dict=OPTIONS.info_dict)
594
595 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
596 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
597 metadata["pre-build"] = source_fp
598 metadata["post-build"] = target_fp
599
600 source_boot = common.GetBootableImage(
601 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
602 OPTIONS.source_info_dict)
603 target_boot = common.GetBootableImage(
604 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
605 updating_boot = (not OPTIONS.two_step and
606 (source_boot.data != target_boot.data))
607
608 source_recovery = common.GetBootableImage(
609 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
610 OPTIONS.source_info_dict)
611 target_recovery = common.GetBootableImage(
612 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
613 updating_recovery = (source_recovery.data != target_recovery.data)
614
615 with tempfile.NamedTemporaryFile() as src_file:
616 with tempfile.NamedTemporaryFile() as tgt_file:
617 print "building source system image..."
618 src_file = tempfile.NamedTemporaryFile()
Doug Zongker5fad2032014-02-24 08:13:45 -0800619 src_mapdata, src_data = img_from_target_files.BuildSystem(
620 OPTIONS.source_tmp, OPTIONS.source_info_dict,
621 sparse=False, map_file=True)
622
Geremy Condra36bd3652014-02-06 19:45:10 -0800623 src_sys_sha1 = sha1(src_data).hexdigest()
624 print "source system sha1:", src_sys_sha1
625 src_file.write(src_data)
Geremy Condra36bd3652014-02-06 19:45:10 -0800626
627 print "building target system image..."
628 tgt_file = tempfile.NamedTemporaryFile()
Doug Zongker5fad2032014-02-24 08:13:45 -0800629 tgt_mapdata, tgt_data = img_from_target_files.BuildSystem(
630 OPTIONS.target_tmp, OPTIONS.target_info_dict,
631 sparse=False, map_file=True)
Geremy Condra36bd3652014-02-06 19:45:10 -0800632 tgt_sys_sha1 = sha1(tgt_data).hexdigest()
633 print "target system sha1:", tgt_sys_sha1
634 tgt_sys_len = len(tgt_data)
635 tgt_file.write(tgt_data)
Geremy Condra36bd3652014-02-06 19:45:10 -0800636
637 system_type, system_device = common.GetTypeAndDevice("/system", OPTIONS.info_dict)
638 system_patch = common.MakeSystemPatch(src_file, tgt_file)
Doug Zongker32b527d2014-03-04 10:03:02 -0800639
640 TestBlockPatch(src_data, src_mapdata, system_patch.data, tgt_mapdata, tgt_sys_sha1)
641 src_data = None
642 tgt_data = None
643
Geremy Condra36bd3652014-02-06 19:45:10 -0800644 system_patch.AddToZip(output_zip, compression=zipfile.ZIP_STORED)
Doug Zongker5fad2032014-02-24 08:13:45 -0800645 src_mapfilename = system_patch.name + ".src.map"
646 common.ZipWriteStr(output_zip, src_mapfilename, src_mapdata)
647 tgt_mapfilename = system_patch.name + ".tgt.map"
648 common.ZipWriteStr(output_zip, tgt_mapfilename, tgt_mapdata)
Geremy Condra36bd3652014-02-06 19:45:10 -0800649
650 AppendAssertions(script, OPTIONS.target_info_dict)
651 device_specific.IncrementalOTA_Assertions()
652
653 # Two-step incremental package strategy (in chronological order,
654 # which is *not* the order in which the generated script has
655 # things):
656 #
657 # if stage is not "2/3" or "3/3":
658 # do verification on current system
659 # write recovery image to boot partition
660 # set stage to "2/3"
661 # reboot to boot partition and restart recovery
662 # else if stage is "2/3":
663 # write recovery image to recovery partition
664 # set stage to "3/3"
665 # reboot to recovery partition and restart recovery
666 # else:
667 # (stage must be "3/3")
668 # perform update:
669 # patch system files, etc.
670 # force full install of new boot image
671 # set up system to update recovery partition on first boot
672 # complete script normally (allow recovery to mark itself finished and reboot)
673
674 if OPTIONS.two_step:
675 if not OPTIONS.info_dict.get("multistage_support", None):
676 assert False, "two-step packages not supported by this build"
677 fs = OPTIONS.info_dict["fstab"]["/misc"]
678 assert fs.fs_type.upper() == "EMMC", \
679 "two-step packages only supported on devices with EMMC /misc partitions"
680 bcb_dev = {"bcb_dev": fs.device}
681 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
682 script.AppendExtra("""
683if get_stage("%(bcb_dev)s", "stage") == "2/3" then
684""" % bcb_dev)
685 script.AppendExtra("sleep(20);\n");
686 script.WriteRawImage("/recovery", "recovery.img")
687 script.AppendExtra("""
688set_stage("%(bcb_dev)s", "3/3");
689reboot_now("%(bcb_dev)s", "recovery");
690else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
691""" % bcb_dev)
692
693 script.Print("Verifying current system...")
694
695 device_specific.IncrementalOTA_VerifyBegin()
696
697 script.AssertRecoveryFingerprint(source_fp, target_fp)
698
699 if updating_boot:
Geremy Condra36bd3652014-02-06 19:45:10 -0800700 d = common.Difference(target_boot, source_boot)
701 _, _, d = d.ComputePatch()
702 print "boot target: %d source: %d diff: %d" % (
703 target_boot.size, source_boot.size, len(d))
704
705 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
706
707 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
708
709 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
710 (boot_type, boot_device,
711 source_boot.size, source_boot.sha1,
712 target_boot.size, target_boot.sha1))
713
714 device_specific.IncrementalOTA_VerifyEnd()
715
716 if OPTIONS.two_step:
717 script.WriteRawImage("/boot", "recovery.img")
718 script.AppendExtra("""
719set_stage("%(bcb_dev)s", "2/3");
720reboot_now("%(bcb_dev)s", "");
721else
722""" % bcb_dev)
723
724 script.Comment("---- start making changes here ----")
725
726 device_specific.IncrementalOTA_InstallBegin()
727
Geremy Condra36bd3652014-02-06 19:45:10 -0800728 script.Print("Patching system image...")
729 script.Syspatch(system_device,
Doug Zongker5fad2032014-02-24 08:13:45 -0800730 tgt_mapfilename, tgt_sys_sha1,
731 src_mapfilename, src_sys_sha1,
Geremy Condra36bd3652014-02-06 19:45:10 -0800732 system_patch.name)
733
734 if OPTIONS.two_step:
735 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
736 script.WriteRawImage("/boot", "boot.img")
737 print "writing full boot image (forced by two-step mode)"
738
739 if not OPTIONS.two_step:
740 if updating_boot:
741 # Produce the boot image by applying a patch to the current
742 # contents of the boot partition, and write it back to the
743 # partition.
744 script.Print("Patching boot image...")
745 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
746 % (boot_type, boot_device,
747 source_boot.size, source_boot.sha1,
748 target_boot.size, target_boot.sha1),
749 "-",
750 target_boot.size, target_boot.sha1,
751 source_boot.sha1, "patch/boot.img.p")
752 print "boot image changed; including."
753 else:
754 print "boot image unchanged; skipping."
755
756 # Do device-specific installation (eg, write radio image).
757 device_specific.IncrementalOTA_InstallEnd()
758
759 if OPTIONS.extra_script is not None:
760 script.AppendExtra(OPTIONS.extra_script)
761
Doug Zongker922206e2014-03-04 13:16:24 -0800762 if OPTIONS.wipe_user_data:
763 script.Print("Erasing user data...")
764 script.FormatPartition("/data")
765
Geremy Condra36bd3652014-02-06 19:45:10 -0800766 if OPTIONS.two_step:
767 script.AppendExtra("""
768set_stage("%(bcb_dev)s", "");
769endif;
770endif;
771""" % bcb_dev)
772
773 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800774 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800775 WriteMetadata(metadata, output_zip)
776
Doug Zongker32b527d2014-03-04 10:03:02 -0800777def ParseMap(map_str):
778 x = map_str.split()
779 assert int(x[0]) == 4096
780 assert int(x[1]) == len(x)-2
781 return int(x[0]), [int(i) for i in x[2:]]
782
783def TestBlockPatch(src_muimg, src_map, patch_data, tgt_map, tgt_sha1):
784 src_blksize, src_regions = ParseMap(src_map)
785 tgt_blksize, tgt_regions = ParseMap(tgt_map)
786
787 with tempfile.NamedTemporaryFile() as src_file,\
788 tempfile.NamedTemporaryFile() as patch_file,\
789 tempfile.NamedTemporaryFile() as tgt_file,\
790 tempfile.NamedTemporaryFile() as src_map_file,\
791 tempfile.NamedTemporaryFile() as tgt_map_file:
792
793 src_total = sum(src_regions) * src_blksize
794 src_file.truncate(src_total)
795 p = 0
796 for i in range(0, len(src_regions), 2):
797 c, dc = src_regions[i:i+2]
798 src_file.write(src_muimg[p:(p+c*src_blksize)])
799 p += c*src_blksize
800 src_file.seek(dc*src_blksize, 1)
801 assert src_file.tell() == src_total
802
803 patch_file.write(patch_data)
804
805 tgt_total = sum(tgt_regions) * tgt_blksize
806 tgt_file.truncate(tgt_total)
807
808 src_map_file.write(src_map)
809 tgt_map_file.write(tgt_map)
810
811 src_file.flush()
812 src_map_file.flush()
813 patch_file.flush()
814 tgt_file.flush()
815 tgt_map_file.flush()
816
817 p = common.Run(["syspatch_host", src_file.name, src_map_file.name,
818 patch_file.name, tgt_file.name, tgt_map_file.name],
819 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
820 stdoutdata, _ = p.communicate()
821 if p.returncode != 0:
822 print stdoutdata
823 raise ValueError("failed to reconstruct target system image from patch")
824
825 h = sha1()
826 for i in range(0, len(tgt_regions), 2):
827 c, dc = tgt_regions[i:i+2]
828 h.update(tgt_file.read(c*tgt_blksize))
829 tgt_file.seek(dc*tgt_blksize, 1)
830
831 if h.hexdigest() != tgt_sha1:
832 raise ValueError("patch reconstructed incorrect target system image")
833
834 print "test of system image patch succeeded"
835
836
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700837def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -0800838 target_has_recovery_patch = HasRecoveryPatch(target_zip)
839 source_has_recovery_patch = HasRecoveryPatch(source_zip)
840
Doug Zongker26e66192014-02-20 13:22:07 -0800841 if (OPTIONS.block_based and
842 target_has_recovery_patch and
843 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -0800844 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
845
Doug Zongker37974732010-09-16 17:44:38 -0700846 source_version = OPTIONS.source_info_dict["recovery_api_version"]
847 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700848
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700849 if source_version == 0:
850 print ("WARNING: generating edify script for a source that "
851 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700852 script = edify_generator.EdifyGenerator(source_version,
853 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700854
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700855 metadata = {"pre-device": GetBuildProp("ro.product.device",
856 OPTIONS.source_info_dict),
857 "post-timestamp": GetBuildProp("ro.build.date.utc",
858 OPTIONS.target_info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700859 }
860
Doug Zongker05d3dea2009-06-22 11:32:31 -0700861 device_specific = common.DeviceSpecificParams(
862 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800863 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700864 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800865 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700866 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -0700867 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -0700868 metadata=metadata,
869 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700870
Doug Zongkereef39442009-04-02 12:14:19 -0700871 print "Loading target..."
Doug Zongker1807e702012-02-28 12:21:08 -0800872 target_data = LoadSystemFiles(target_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700873 print "Loading source..."
Doug Zongker1807e702012-02-28 12:21:08 -0800874 source_data = LoadSystemFiles(source_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700875
876 verbatim_targets = []
877 patch_list = []
Doug Zongker761e6422009-09-25 10:45:39 -0700878 diffs = []
Michael Runge4038aa82013-12-13 18:06:28 -0800879 renames = {}
880 known_paths = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700881 largest_source_size = 0
Michael Runge4038aa82013-12-13 18:06:28 -0800882
883 matching_file_cache = {}
884 for fn, sf in source_data.items():
885 assert fn == sf.name
886 matching_file_cache["path:" + fn] = sf
887 if fn in target_data.keys():
888 AddToKnownPaths(fn, known_paths)
889 # Only allow eligibility for filename/sha matching
890 # if there isn't a perfect path match.
891 if target_data.get(sf.name) is None:
892 matching_file_cache["file:" + fn.split("/")[-1]] = sf
893 matching_file_cache["sha:" + sf.sha1] = sf
894
Doug Zongkereef39442009-04-02 12:14:19 -0700895 for fn in sorted(target_data.keys()):
896 tf = target_data[fn]
Doug Zongker761e6422009-09-25 10:45:39 -0700897 assert fn == tf.name
Michael Runge4038aa82013-12-13 18:06:28 -0800898 sf = ClosestFileMatch(tf, matching_file_cache, renames)
899 if sf is not None and sf.name != tf.name:
900 print "File has moved from " + sf.name + " to " + tf.name
901 renames[sf.name] = tf
Doug Zongkereef39442009-04-02 12:14:19 -0700902
903 if sf is None or fn in OPTIONS.require_verbatim:
904 # This file should be included verbatim
905 if fn in OPTIONS.prohibit_verbatim:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700906 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
Doug Zongkereef39442009-04-02 12:14:19 -0700907 print "send", fn, "verbatim"
908 tf.AddToZip(output_zip)
909 verbatim_targets.append((fn, tf.size))
Michael Runge4038aa82013-12-13 18:06:28 -0800910 if fn in target_data.keys():
911 AddToKnownPaths(fn, known_paths)
Doug Zongkereef39442009-04-02 12:14:19 -0700912 elif tf.sha1 != sf.sha1:
913 # File is different; consider sending as a patch
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700914 diffs.append(common.Difference(tf, sf))
Doug Zongkereef39442009-04-02 12:14:19 -0700915 else:
Michael Runge4038aa82013-12-13 18:06:28 -0800916 # Target file data identical to source (may still be renamed)
Doug Zongkereef39442009-04-02 12:14:19 -0700917 pass
918
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700919 common.ComputeDifferences(diffs)
Doug Zongker761e6422009-09-25 10:45:39 -0700920
921 for diff in diffs:
922 tf, sf, d = diff.GetPatch()
Michael Runge4038aa82013-12-13 18:06:28 -0800923 path = "/".join(tf.name.split("/")[:-1])
924 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
925 path not in known_paths:
Doug Zongker761e6422009-09-25 10:45:39 -0700926 # patch is almost as big as the file; don't bother patching
Doug Zongker32b527d2014-03-04 10:03:02 -0800927 # or a patch + rename cannot take place due to the target
Michael Runge4038aa82013-12-13 18:06:28 -0800928 # directory not existing
Doug Zongker761e6422009-09-25 10:45:39 -0700929 tf.AddToZip(output_zip)
930 verbatim_targets.append((tf.name, tf.size))
Michael Runge4038aa82013-12-13 18:06:28 -0800931 if sf.name in renames:
932 del renames[sf.name]
933 AddToKnownPaths(tf.name, known_paths)
Doug Zongker761e6422009-09-25 10:45:39 -0700934 else:
Michael Runge4038aa82013-12-13 18:06:28 -0800935 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
936 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
Doug Zongker761e6422009-09-25 10:45:39 -0700937 largest_source_size = max(largest_source_size, sf.size)
Doug Zongkereef39442009-04-02 12:14:19 -0700938
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700939 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
940 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
Doug Zongker2ea21062010-04-28 16:05:21 -0700941 metadata["pre-build"] = source_fp
942 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -0700943
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700944 script.Mount("/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700945 script.AssertSomeFingerprint(source_fp, target_fp)
Doug Zongkereef39442009-04-02 12:14:19 -0700946
Doug Zongker55d93282011-01-25 17:03:34 -0800947 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700948 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
949 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -0800950 target_boot = common.GetBootableImage(
951 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800952 updating_boot = (not OPTIONS.two_step and
953 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -0700954
Doug Zongker55d93282011-01-25 17:03:34 -0800955 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700956 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
957 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -0800958 target_recovery = common.GetBootableImage(
959 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -0700960 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700961
Doug Zongker881dd402009-09-20 14:03:55 -0700962 # Here's how we divide up the progress bar:
963 # 0.1 for verifying the start state (PatchCheck calls)
964 # 0.8 for applying patches (ApplyPatch calls)
965 # 0.1 for unpacking verbatim files, symlinking, and doing the
966 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -0700967
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700968 AppendAssertions(script, OPTIONS.target_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700969 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -0700970
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800971 # Two-step incremental package strategy (in chronological order,
972 # which is *not* the order in which the generated script has
973 # things):
974 #
975 # if stage is not "2/3" or "3/3":
976 # do verification on current system
977 # write recovery image to boot partition
978 # set stage to "2/3"
979 # reboot to boot partition and restart recovery
980 # else if stage is "2/3":
981 # write recovery image to recovery partition
982 # set stage to "3/3"
983 # reboot to recovery partition and restart recovery
984 # else:
985 # (stage must be "3/3")
986 # perform update:
987 # patch system files, etc.
988 # force full install of new boot image
989 # set up system to update recovery partition on first boot
990 # complete script normally (allow recovery to mark itself finished and reboot)
991
992 if OPTIONS.two_step:
993 if not OPTIONS.info_dict.get("multistage_support", None):
994 assert False, "two-step packages not supported by this build"
995 fs = OPTIONS.info_dict["fstab"]["/misc"]
996 assert fs.fs_type.upper() == "EMMC", \
997 "two-step packages only supported on devices with EMMC /misc partitions"
998 bcb_dev = {"bcb_dev": fs.device}
999 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1000 script.AppendExtra("""
1001if get_stage("%(bcb_dev)s", "stage") == "2/3" then
1002""" % bcb_dev)
1003 script.AppendExtra("sleep(20);\n");
1004 script.WriteRawImage("/recovery", "recovery.img")
1005 script.AppendExtra("""
1006set_stage("%(bcb_dev)s", "3/3");
1007reboot_now("%(bcb_dev)s", "recovery");
1008else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
1009""" % bcb_dev)
1010
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001011 script.Print("Verifying current system...")
1012
Doug Zongkere5ff5902012-01-17 10:55:37 -08001013 device_specific.IncrementalOTA_VerifyBegin()
1014
Doug Zongker881dd402009-09-20 14:03:55 -07001015 script.ShowProgress(0.1, 0)
Doug Zongker881dd402009-09-20 14:03:55 -07001016 so_far = 0
Doug Zongkereef39442009-04-02 12:14:19 -07001017
Michael Runge4038aa82013-12-13 18:06:28 -08001018 for tf, sf, size, patch_sha in patch_list:
1019 if tf.name != sf.name:
1020 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1021 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
Doug Zongker881dd402009-09-20 14:03:55 -07001022 so_far += sf.size
Doug Zongkereef39442009-04-02 12:14:19 -07001023
Doug Zongker5da317e2009-06-02 13:38:17 -07001024 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001025 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001026 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001027 print "boot target: %d source: %d diff: %d" % (
1028 target_boot.size, source_boot.size, len(d))
1029
Doug Zongker048e7ca2009-06-15 14:31:53 -07001030 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001031
Doug Zongker96a57e72010-09-26 14:57:41 -07001032 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001033
1034 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1035 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001036 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001037 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001038 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001039
1040 if patch_list or updating_recovery or updating_boot:
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001041 script.CacheFreeSpaceCheck(largest_source_size)
Doug Zongker5a482092010-02-17 16:09:18 -08001042
Doug Zongker05d3dea2009-06-22 11:32:31 -07001043 device_specific.IncrementalOTA_VerifyEnd()
1044
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001045 if OPTIONS.two_step:
1046 script.WriteRawImage("/boot", "recovery.img")
1047 script.AppendExtra("""
1048set_stage("%(bcb_dev)s", "2/3");
1049reboot_now("%(bcb_dev)s", "");
1050else
1051""" % bcb_dev)
1052
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001053 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001054
Doug Zongkere5ff5902012-01-17 10:55:37 -08001055 device_specific.IncrementalOTA_InstallBegin()
1056
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001057 if OPTIONS.two_step:
1058 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1059 script.WriteRawImage("/boot", "boot.img")
1060 print "writing full boot image (forced by two-step mode)"
1061
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001062 script.Print("Removing unneeded files...")
Doug Zongker0f3298a2009-06-30 08:16:58 -07001063 script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
1064 ["/"+i for i in sorted(source_data)
Michael Runge4038aa82013-12-13 18:06:28 -08001065 if i not in target_data and
1066 i not in renames] +
Doug Zongker3b949f02009-08-24 10:24:32 -07001067 ["/system/recovery.img"])
Doug Zongkereef39442009-04-02 12:14:19 -07001068
Doug Zongker881dd402009-09-20 14:03:55 -07001069 script.ShowProgress(0.8, 0)
1070 total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
1071 if updating_boot:
1072 total_patch_size += target_boot.size
1073 so_far = 0
1074
1075 script.Print("Patching system files...")
Doug Zongkere92f15a2011-08-26 13:46:40 -07001076 deferred_patch_list = []
1077 for item in patch_list:
Michael Runge4038aa82013-12-13 18:06:28 -08001078 tf, sf, size, _ = item
Doug Zongkere92f15a2011-08-26 13:46:40 -07001079 if tf.name == "system/build.prop":
1080 deferred_patch_list.append(item)
1081 continue
Michael Runge4038aa82013-12-13 18:06:28 -08001082 if (sf.name != tf.name):
1083 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1084 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
Doug Zongker881dd402009-09-20 14:03:55 -07001085 so_far += tf.size
1086 script.SetProgress(so_far / total_patch_size)
1087
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001088 if not OPTIONS.two_step:
1089 if updating_boot:
1090 # Produce the boot image by applying a patch to the current
1091 # contents of the boot partition, and write it back to the
1092 # partition.
1093 script.Print("Patching boot image...")
1094 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1095 % (boot_type, boot_device,
1096 source_boot.size, source_boot.sha1,
1097 target_boot.size, target_boot.sha1),
1098 "-",
1099 target_boot.size, target_boot.sha1,
1100 source_boot.sha1, "patch/boot.img.p")
1101 so_far += target_boot.size
1102 script.SetProgress(so_far / total_patch_size)
1103 print "boot image changed; including."
1104 else:
1105 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001106
1107 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001108 # Recovery is generated as a patch using both the boot image
1109 # (which contains the same linux kernel as recovery) and the file
1110 # /system/etc/recovery-resource.dat (which contains all the images
1111 # used in the recovery UI) as sources. This lets us minimize the
1112 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001113 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001114 # For older builds where recovery-resource.dat is not present, we
1115 # use only the boot image as the source.
1116
Doug Zongkerc9253822014-02-04 12:17:58 -08001117 if not target_has_recovery_patch:
1118 def output_sink(fn, data):
1119 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
1120 Item.Get("system/" + fn, dir=False)
1121
1122 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1123 target_recovery, target_boot)
1124 script.DeleteFiles(["/system/recovery-from-boot.p",
1125 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001126 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001127 else:
1128 print "recovery image unchanged; skipping."
1129
Doug Zongker881dd402009-09-20 14:03:55 -07001130 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001131
Doug Zongker1807e702012-02-28 12:21:08 -08001132 target_symlinks = CopySystemFiles(target_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -07001133
1134 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001135 temp_script = script.MakeTemporary()
Doug Zongker283e2a12010-03-15 17:52:32 -07001136 Item.GetMetadata(target_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -07001137 Item.Get("system").SetPermissions(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001138
1139 # Note that this call will mess up the tree of Items, so make sure
1140 # we're done with it.
Doug Zongker1807e702012-02-28 12:21:08 -08001141 source_symlinks = CopySystemFiles(source_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -07001142 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1143
1144 # Delete all the symlinks in source that aren't in target. This
1145 # needs to happen before verbatim files are unpacked, in case a
1146 # symlink in the source is replaced by a real file in the target.
1147 to_delete = []
1148 for dest, link in source_symlinks:
1149 if link not in target_symlinks_d:
1150 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001151 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001152
1153 if verbatim_targets:
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001154 script.Print("Unpacking new files...")
1155 script.UnpackPackageDir("system", "/system")
1156
Doug Zongkerc9253822014-02-04 12:17:58 -08001157 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001158 script.Print("Unpacking new recovery...")
1159 script.UnpackPackageDir("recovery", "/system")
1160
Michael Runge4038aa82013-12-13 18:06:28 -08001161 if len(renames) > 0:
1162 script.Print("Renaming files...")
1163
1164 for src in renames:
1165 print "Renaming " + src + " to " + renames[src].name
1166 script.RenameFile(src, renames[src].name)
1167
Doug Zongker05d3dea2009-06-22 11:32:31 -07001168 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001169
1170 # Create all the symlinks that don't already exist, or point to
1171 # somewhere different than what we want. Delete each symlink before
1172 # creating it, since the 'symlink' command won't overwrite.
1173 to_create = []
1174 for dest, link in target_symlinks:
1175 if link in source_symlinks_d:
1176 if dest != source_symlinks_d[link]:
1177 to_create.append((dest, link))
1178 else:
1179 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001180 script.DeleteFiles([i[1] for i in to_create])
1181 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001182
1183 # Now that the symlinks are created, we can set all the
1184 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001185 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001186
Doug Zongker881dd402009-09-20 14:03:55 -07001187 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001188 device_specific.IncrementalOTA_InstallEnd()
1189
Doug Zongker1c390a22009-05-14 19:06:36 -07001190 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001191 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001192
Doug Zongkere92f15a2011-08-26 13:46:40 -07001193 # Patch the build.prop file last, so if something fails but the
1194 # device can still come up, it appears to be the old build and will
1195 # get set the OTA package again to retry.
1196 script.Print("Patching remaining system files...")
1197 for item in deferred_patch_list:
Michael Runge4038aa82013-12-13 18:06:28 -08001198 tf, sf, size, _ = item
1199 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
Nick Kralevich0eb17d92013-09-07 17:10:29 -07001200 script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001201
Doug Zongker922206e2014-03-04 13:16:24 -08001202 if OPTIONS.wipe_user_data:
1203 script.Print("Erasing user data...")
1204 script.FormatPartition("/data")
1205
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001206 if OPTIONS.two_step:
1207 script.AppendExtra("""
1208set_stage("%(bcb_dev)s", "");
1209endif;
1210endif;
1211""" % bcb_dev)
1212
Doug Zongker25568482014-03-03 10:21:27 -08001213 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -07001214 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001215
1216
1217def main(argv):
1218
1219 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001220 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001221 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001222 elif o in ("-k", "--package_key"):
1223 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001224 elif o in ("-i", "--incremental_from"):
1225 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001226 elif o in ("-w", "--wipe_user_data"):
1227 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001228 elif o in ("-n", "--no_prereq"):
1229 OPTIONS.omit_prereq = True
Doug Zongker1c390a22009-05-14 19:06:36 -07001230 elif o in ("-e", "--extra_script"):
1231 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001232 elif o in ("-a", "--aslr_mode"):
1233 if a in ("on", "On", "true", "True", "yes", "Yes"):
1234 OPTIONS.aslr_mode = True
1235 else:
1236 OPTIONS.aslr_mode = False
Doug Zongker761e6422009-09-25 10:45:39 -07001237 elif o in ("--worker_threads"):
1238 OPTIONS.worker_threads = int(a)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001239 elif o in ("-2", "--two_step"):
1240 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001241 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001242 OPTIONS.no_signing = True
Doug Zongker26e66192014-02-20 13:22:07 -08001243 elif o == "--block":
1244 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001245 elif o in ("-b", "--binary"):
1246 OPTIONS.updater_binary = a
Doug Zongkereef39442009-04-02 12:14:19 -07001247 else:
1248 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001249 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001250
1251 args = common.ParseOptions(argv, __doc__,
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001252 extra_opts="b:k:i:d:wne:a:2",
Doug Zongkereef39442009-04-02 12:14:19 -07001253 extra_long_opts=["board_config=",
1254 "package_key=",
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001255 "incremental_from=",
Doug Zongker962069c2009-04-23 11:41:58 -07001256 "wipe_user_data",
Doug Zongker1c390a22009-05-14 19:06:36 -07001257 "no_prereq",
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001258 "extra_script=",
Hristo Bojinov96be7202010-08-02 10:26:17 -07001259 "worker_threads=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001260 "aslr_mode=",
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001261 "two_step",
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001262 "no_signing",
Doug Zongker26e66192014-02-20 13:22:07 -08001263 "block",
Doug Zongker25568482014-03-03 10:21:27 -08001264 "binary=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001265 ],
Doug Zongkereef39442009-04-02 12:14:19 -07001266 extra_option_handler=option_handler)
1267
1268 if len(args) != 2:
1269 common.Usage(__doc__)
1270 sys.exit(1)
1271
Doug Zongker1c390a22009-05-14 19:06:36 -07001272 if OPTIONS.extra_script is not None:
1273 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1274
Doug Zongkereef39442009-04-02 12:14:19 -07001275 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001276 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001277
Doug Zongkereef39442009-04-02 12:14:19 -07001278 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001279 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001280
1281 # If this image was originally labelled with SELinux contexts, make sure we
1282 # also apply the labels in our new image. During building, the "file_contexts"
1283 # is in the out/ directory tree, but for repacking from target-files.zip it's
1284 # in the root directory of the ramdisk.
1285 if "selinux_fc" in OPTIONS.info_dict:
1286 OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK",
1287 "file_contexts")
1288
Doug Zongker37974732010-09-16 17:44:38 -07001289 if OPTIONS.verbose:
1290 print "--- target info ---"
1291 common.DumpInfoDict(OPTIONS.info_dict)
1292
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001293 # If the caller explicitly specified the device-specific extensions
1294 # path via -s/--device_specific, use that. Otherwise, use
1295 # META/releasetools.py if it is present in the target target_files.
1296 # Otherwise, take the path of the file from 'tool_extensions' in the
1297 # info dict and look for that in the local filesystem, relative to
1298 # the current directory.
1299
Doug Zongker37974732010-09-16 17:44:38 -07001300 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001301 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1302 if os.path.exists(from_input):
1303 print "(using device-specific extensions from target_files)"
1304 OPTIONS.device_specific = from_input
1305 else:
1306 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1307
Doug Zongker37974732010-09-16 17:44:38 -07001308 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001309 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001310
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001311 if OPTIONS.no_signing:
1312 output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
1313 else:
1314 temp_zip_file = tempfile.NamedTemporaryFile()
1315 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1316 compression=zipfile.ZIP_DEFLATED)
Doug Zongkereef39442009-04-02 12:14:19 -07001317
1318 if OPTIONS.incremental_source is None:
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001319 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001320 if OPTIONS.package_key is None:
1321 OPTIONS.package_key = OPTIONS.info_dict.get(
1322 "default_system_dev_certificate",
1323 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -07001324 else:
1325 print "unzipping source target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001326 OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
Doug Zongker37974732010-09-16 17:44:38 -07001327 OPTIONS.target_info_dict = OPTIONS.info_dict
1328 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
Doug Zongker5fad2032014-02-24 08:13:45 -08001329 if "selinux_fc" in OPTIONS.source_info_dict:
1330 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(OPTIONS.source_tmp, "BOOT", "RAMDISK",
1331 "file_contexts")
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001332 if OPTIONS.package_key is None:
Doug Zongker91b4f8a2011-09-23 12:48:33 -07001333 OPTIONS.package_key = OPTIONS.source_info_dict.get(
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001334 "default_system_dev_certificate",
1335 "build/target/product/security/testkey")
Doug Zongker37974732010-09-16 17:44:38 -07001336 if OPTIONS.verbose:
1337 print "--- source info ---"
1338 common.DumpInfoDict(OPTIONS.source_info_dict)
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001339 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001340
1341 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001342
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001343 if not OPTIONS.no_signing:
1344 SignOutput(temp_zip_file.name, args[1])
1345 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001346
1347 common.Cleanup()
1348
1349 print "done."
1350
1351
1352if __name__ == '__main__':
1353 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001354 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001355 main(sys.argv[1:])
1356 except common.ExternalError, e:
1357 print
1358 print " ERROR: %s" % (e,)
1359 print
1360 sys.exit(1)