blob: 59dd06e7f26536a98ea6dceca532ac4d24ded3f3 [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
456 script.ShowProgress(0.1, 10)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700457 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700458
Kenny Rootf32dc712012-04-08 10:42:34 -0700459 if "selinux_fc" in OPTIONS.info_dict:
460 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500461
Doug Zongker01ce19c2014-02-04 13:48:15 -0800462 script.ShowProgress(system_progress, 30)
Doug Zongker26e66192014-02-20 13:22:07 -0800463 if block_based:
Doug Zongker5fad2032014-02-24 08:13:45 -0800464 mapdata, data = img_from_target_files.BuildSystem(
465 OPTIONS.input_tmp, OPTIONS.info_dict,
466 sparse=False, map_file=True)
467
468 common.ZipWriteStr(output_zip, "system.map", mapdata)
469 common.ZipWriteStr(output_zip, "system.muimg", data)
470 script.WipeBlockDevice("/system")
471 script.WriteRawImage("/system", "system.muimg", mapfn="system.map")
Doug Zongker01ce19c2014-02-04 13:48:15 -0800472 else:
473 script.FormatPartition("/system")
474 script.Mount("/system")
475 if not has_recovery_patch:
476 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800477 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700478
Doug Zongker01ce19c2014-02-04 13:48:15 -0800479 symlinks = CopySystemFiles(input_zip, output_zip)
480 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700481
Doug Zongker55d93282011-01-25 17:03:34 -0800482 boot_img = common.GetBootableImage("boot.img", "boot.img",
483 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800484
485 if not has_recovery_patch:
486 def output_sink(fn, data):
487 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
488 Item.Get("system/" + fn, dir=False)
489
490 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
491 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700492
Doug Zongker01ce19c2014-02-04 13:48:15 -0800493 Item.GetMetadata(input_zip)
494 Item.Get("system").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700495
Doug Zongker37974732010-09-16 17:44:38 -0700496 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700497 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700498
Doug Zongker01ce19c2014-02-04 13:48:15 -0800499 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700500 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700501
Doug Zongker01ce19c2014-02-04 13:48:15 -0800502 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700503 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700504
Doug Zongker1c390a22009-05-14 19:06:36 -0700505 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700506 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700507
Doug Zongker14833602010-02-02 13:12:04 -0800508 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800509
510 if OPTIONS.two_step:
511 script.AppendExtra("""
512set_stage("%(bcb_dev)s", "");
513""" % bcb_dev)
514 script.AppendExtra("else\n")
515 script.WriteRawImage("/boot", "recovery.img")
516 script.AppendExtra("""
517set_stage("%(bcb_dev)s", "2/3");
518reboot_now("%(bcb_dev)s", "");
519endif;
520endif;
521""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800522 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700523 WriteMetadata(metadata, output_zip)
524
Stephen Smalley56882bf2012-02-09 13:36:21 -0500525def WritePolicyConfig(file_context, output_zip):
526 f = open(file_context, 'r');
527 basename = os.path.basename(file_context)
528 common.ZipWriteStr(output_zip, basename, f.read())
529
Doug Zongker2ea21062010-04-28 16:05:21 -0700530
531def WriteMetadata(metadata, output_zip):
532 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
533 "".join(["%s=%s\n" % kv
534 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700535
Doug Zongkereef39442009-04-02 12:14:19 -0700536def LoadSystemFiles(z):
537 """Load all the files from SYSTEM/... in a given target-files
538 ZipFile, and return a dict of {filename: File object}."""
539 out = {}
540 for info in z.infolist():
541 if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
Hristo Bojinov96be7202010-08-02 10:26:17 -0700542 basefilename = info.filename[7:]
543 fn = "system/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700544 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700545 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800546 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700547
548
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700549def GetBuildProp(prop, info_dict):
550 """Return the fingerprint of the build of a given target-files info_dict."""
551 try:
552 return info_dict.get("build.prop", {})[prop]
553 except KeyError:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700554 raise common.ExternalError("couldn't find %s in build.prop" % (property,))
Doug Zongkereef39442009-04-02 12:14:19 -0700555
Michael Runge4038aa82013-12-13 18:06:28 -0800556def AddToKnownPaths(filename, known_paths):
557 if filename[-1] == "/":
558 return
559 dirs = filename.split("/")[:-1]
560 while len(dirs) > 0:
561 path = "/".join(dirs)
562 if path in known_paths:
563 break;
564 known_paths.add(path)
565 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700566
Geremy Condra36bd3652014-02-06 19:45:10 -0800567def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
568 source_version = OPTIONS.source_info_dict["recovery_api_version"]
569 target_version = OPTIONS.target_info_dict["recovery_api_version"]
570
571 if source_version == 0:
572 print ("WARNING: generating edify script for a source that "
573 "can't install it.")
574 script = edify_generator.EdifyGenerator(source_version,
575 OPTIONS.target_info_dict)
576
577 metadata = {"pre-device": GetBuildProp("ro.product.device",
578 OPTIONS.source_info_dict),
579 "post-timestamp": GetBuildProp("ro.build.date.utc",
580 OPTIONS.target_info_dict),
581 }
582
583 device_specific = common.DeviceSpecificParams(
584 source_zip=source_zip,
585 source_version=source_version,
586 target_zip=target_zip,
587 target_version=target_version,
588 output_zip=output_zip,
589 script=script,
590 metadata=metadata,
591 info_dict=OPTIONS.info_dict)
592
593 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
594 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
595 metadata["pre-build"] = source_fp
596 metadata["post-build"] = target_fp
597
598 source_boot = common.GetBootableImage(
599 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
600 OPTIONS.source_info_dict)
601 target_boot = common.GetBootableImage(
602 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
603 updating_boot = (not OPTIONS.two_step and
604 (source_boot.data != target_boot.data))
605
606 source_recovery = common.GetBootableImage(
607 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
608 OPTIONS.source_info_dict)
609 target_recovery = common.GetBootableImage(
610 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
611 updating_recovery = (source_recovery.data != target_recovery.data)
612
613 with tempfile.NamedTemporaryFile() as src_file:
614 with tempfile.NamedTemporaryFile() as tgt_file:
615 print "building source system image..."
616 src_file = tempfile.NamedTemporaryFile()
Doug Zongker5fad2032014-02-24 08:13:45 -0800617 src_mapdata, src_data = img_from_target_files.BuildSystem(
618 OPTIONS.source_tmp, OPTIONS.source_info_dict,
619 sparse=False, map_file=True)
620
Geremy Condra36bd3652014-02-06 19:45:10 -0800621 src_sys_sha1 = sha1(src_data).hexdigest()
622 print "source system sha1:", src_sys_sha1
623 src_file.write(src_data)
624 src_data = None
625
626 print "building target system image..."
627 tgt_file = tempfile.NamedTemporaryFile()
Doug Zongker5fad2032014-02-24 08:13:45 -0800628 tgt_mapdata, tgt_data = img_from_target_files.BuildSystem(
629 OPTIONS.target_tmp, OPTIONS.target_info_dict,
630 sparse=False, map_file=True)
Geremy Condra36bd3652014-02-06 19:45:10 -0800631 tgt_sys_sha1 = sha1(tgt_data).hexdigest()
632 print "target system sha1:", tgt_sys_sha1
633 tgt_sys_len = len(tgt_data)
634 tgt_file.write(tgt_data)
635 tgt_data = None
636
637 system_type, system_device = common.GetTypeAndDevice("/system", OPTIONS.info_dict)
638 system_patch = common.MakeSystemPatch(src_file, tgt_file)
639 system_patch.AddToZip(output_zip, compression=zipfile.ZIP_STORED)
Doug Zongker5fad2032014-02-24 08:13:45 -0800640 src_mapfilename = system_patch.name + ".src.map"
641 common.ZipWriteStr(output_zip, src_mapfilename, src_mapdata)
642 tgt_mapfilename = system_patch.name + ".tgt.map"
643 common.ZipWriteStr(output_zip, tgt_mapfilename, tgt_mapdata)
Geremy Condra36bd3652014-02-06 19:45:10 -0800644
645 AppendAssertions(script, OPTIONS.target_info_dict)
646 device_specific.IncrementalOTA_Assertions()
647
648 # Two-step incremental package strategy (in chronological order,
649 # which is *not* the order in which the generated script has
650 # things):
651 #
652 # if stage is not "2/3" or "3/3":
653 # do verification on current system
654 # write recovery image to boot partition
655 # set stage to "2/3"
656 # reboot to boot partition and restart recovery
657 # else if stage is "2/3":
658 # write recovery image to recovery partition
659 # set stage to "3/3"
660 # reboot to recovery partition and restart recovery
661 # else:
662 # (stage must be "3/3")
663 # perform update:
664 # patch system files, etc.
665 # force full install of new boot image
666 # set up system to update recovery partition on first boot
667 # complete script normally (allow recovery to mark itself finished and reboot)
668
669 if OPTIONS.two_step:
670 if not OPTIONS.info_dict.get("multistage_support", None):
671 assert False, "two-step packages not supported by this build"
672 fs = OPTIONS.info_dict["fstab"]["/misc"]
673 assert fs.fs_type.upper() == "EMMC", \
674 "two-step packages only supported on devices with EMMC /misc partitions"
675 bcb_dev = {"bcb_dev": fs.device}
676 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
677 script.AppendExtra("""
678if get_stage("%(bcb_dev)s", "stage") == "2/3" then
679""" % bcb_dev)
680 script.AppendExtra("sleep(20);\n");
681 script.WriteRawImage("/recovery", "recovery.img")
682 script.AppendExtra("""
683set_stage("%(bcb_dev)s", "3/3");
684reboot_now("%(bcb_dev)s", "recovery");
685else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
686""" % bcb_dev)
687
688 script.Print("Verifying current system...")
689
690 device_specific.IncrementalOTA_VerifyBegin()
691
692 script.AssertRecoveryFingerprint(source_fp, target_fp)
693
694 if updating_boot:
Geremy Condra36bd3652014-02-06 19:45:10 -0800695 d = common.Difference(target_boot, source_boot)
696 _, _, d = d.ComputePatch()
697 print "boot target: %d source: %d diff: %d" % (
698 target_boot.size, source_boot.size, len(d))
699
700 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
701
702 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
703
704 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
705 (boot_type, boot_device,
706 source_boot.size, source_boot.sha1,
707 target_boot.size, target_boot.sha1))
708
709 device_specific.IncrementalOTA_VerifyEnd()
710
711 if OPTIONS.two_step:
712 script.WriteRawImage("/boot", "recovery.img")
713 script.AppendExtra("""
714set_stage("%(bcb_dev)s", "2/3");
715reboot_now("%(bcb_dev)s", "");
716else
717""" % bcb_dev)
718
719 script.Comment("---- start making changes here ----")
720
721 device_specific.IncrementalOTA_InstallBegin()
722
723 if OPTIONS.wipe_user_data:
724 script.Print("Erasing user data...")
725 script.FormatPartition("/data")
726
727 script.Print("Patching system image...")
728 script.Syspatch(system_device,
Doug Zongker5fad2032014-02-24 08:13:45 -0800729 tgt_mapfilename, tgt_sys_sha1,
730 src_mapfilename, src_sys_sha1,
Geremy Condra36bd3652014-02-06 19:45:10 -0800731 system_patch.name)
732
733 if OPTIONS.two_step:
734 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
735 script.WriteRawImage("/boot", "boot.img")
736 print "writing full boot image (forced by two-step mode)"
737
738 if not OPTIONS.two_step:
739 if updating_boot:
740 # Produce the boot image by applying a patch to the current
741 # contents of the boot partition, and write it back to the
742 # partition.
743 script.Print("Patching boot image...")
744 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
745 % (boot_type, boot_device,
746 source_boot.size, source_boot.sha1,
747 target_boot.size, target_boot.sha1),
748 "-",
749 target_boot.size, target_boot.sha1,
750 source_boot.sha1, "patch/boot.img.p")
751 print "boot image changed; including."
752 else:
753 print "boot image unchanged; skipping."
754
755 # Do device-specific installation (eg, write radio image).
756 device_specific.IncrementalOTA_InstallEnd()
757
758 if OPTIONS.extra_script is not None:
759 script.AppendExtra(OPTIONS.extra_script)
760
761 if OPTIONS.two_step:
762 script.AppendExtra("""
763set_stage("%(bcb_dev)s", "");
764endif;
765endif;
766""" % bcb_dev)
767
768 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800769 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800770 WriteMetadata(metadata, output_zip)
771
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700772def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -0800773 target_has_recovery_patch = HasRecoveryPatch(target_zip)
774 source_has_recovery_patch = HasRecoveryPatch(source_zip)
775
Doug Zongker26e66192014-02-20 13:22:07 -0800776 if (OPTIONS.block_based and
777 target_has_recovery_patch and
778 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -0800779 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
780
Doug Zongker37974732010-09-16 17:44:38 -0700781 source_version = OPTIONS.source_info_dict["recovery_api_version"]
782 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700783
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700784 if source_version == 0:
785 print ("WARNING: generating edify script for a source that "
786 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700787 script = edify_generator.EdifyGenerator(source_version,
788 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700789
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700790 metadata = {"pre-device": GetBuildProp("ro.product.device",
791 OPTIONS.source_info_dict),
792 "post-timestamp": GetBuildProp("ro.build.date.utc",
793 OPTIONS.target_info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700794 }
795
Doug Zongker05d3dea2009-06-22 11:32:31 -0700796 device_specific = common.DeviceSpecificParams(
797 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800798 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700799 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800800 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700801 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -0700802 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -0700803 metadata=metadata,
804 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700805
Doug Zongkereef39442009-04-02 12:14:19 -0700806 print "Loading target..."
Doug Zongker1807e702012-02-28 12:21:08 -0800807 target_data = LoadSystemFiles(target_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700808 print "Loading source..."
Doug Zongker1807e702012-02-28 12:21:08 -0800809 source_data = LoadSystemFiles(source_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700810
811 verbatim_targets = []
812 patch_list = []
Doug Zongker761e6422009-09-25 10:45:39 -0700813 diffs = []
Michael Runge4038aa82013-12-13 18:06:28 -0800814 renames = {}
815 known_paths = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700816 largest_source_size = 0
Michael Runge4038aa82013-12-13 18:06:28 -0800817
818 matching_file_cache = {}
819 for fn, sf in source_data.items():
820 assert fn == sf.name
821 matching_file_cache["path:" + fn] = sf
822 if fn in target_data.keys():
823 AddToKnownPaths(fn, known_paths)
824 # Only allow eligibility for filename/sha matching
825 # if there isn't a perfect path match.
826 if target_data.get(sf.name) is None:
827 matching_file_cache["file:" + fn.split("/")[-1]] = sf
828 matching_file_cache["sha:" + sf.sha1] = sf
829
Doug Zongkereef39442009-04-02 12:14:19 -0700830 for fn in sorted(target_data.keys()):
831 tf = target_data[fn]
Doug Zongker761e6422009-09-25 10:45:39 -0700832 assert fn == tf.name
Michael Runge4038aa82013-12-13 18:06:28 -0800833 sf = ClosestFileMatch(tf, matching_file_cache, renames)
834 if sf is not None and sf.name != tf.name:
835 print "File has moved from " + sf.name + " to " + tf.name
836 renames[sf.name] = tf
Doug Zongkereef39442009-04-02 12:14:19 -0700837
838 if sf is None or fn in OPTIONS.require_verbatim:
839 # This file should be included verbatim
840 if fn in OPTIONS.prohibit_verbatim:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700841 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
Doug Zongkereef39442009-04-02 12:14:19 -0700842 print "send", fn, "verbatim"
843 tf.AddToZip(output_zip)
844 verbatim_targets.append((fn, tf.size))
Michael Runge4038aa82013-12-13 18:06:28 -0800845 if fn in target_data.keys():
846 AddToKnownPaths(fn, known_paths)
Doug Zongkereef39442009-04-02 12:14:19 -0700847 elif tf.sha1 != sf.sha1:
848 # File is different; consider sending as a patch
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700849 diffs.append(common.Difference(tf, sf))
Doug Zongkereef39442009-04-02 12:14:19 -0700850 else:
Michael Runge4038aa82013-12-13 18:06:28 -0800851 # Target file data identical to source (may still be renamed)
Doug Zongkereef39442009-04-02 12:14:19 -0700852 pass
853
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700854 common.ComputeDifferences(diffs)
Doug Zongker761e6422009-09-25 10:45:39 -0700855
856 for diff in diffs:
857 tf, sf, d = diff.GetPatch()
Michael Runge4038aa82013-12-13 18:06:28 -0800858 path = "/".join(tf.name.split("/")[:-1])
859 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
860 path not in known_paths:
Doug Zongker761e6422009-09-25 10:45:39 -0700861 # patch is almost as big as the file; don't bother patching
Michael Runge4038aa82013-12-13 18:06:28 -0800862 # or a patch + rename cannot take place due to the target
863 # directory not existing
Doug Zongker761e6422009-09-25 10:45:39 -0700864 tf.AddToZip(output_zip)
865 verbatim_targets.append((tf.name, tf.size))
Michael Runge4038aa82013-12-13 18:06:28 -0800866 if sf.name in renames:
867 del renames[sf.name]
868 AddToKnownPaths(tf.name, known_paths)
Doug Zongker761e6422009-09-25 10:45:39 -0700869 else:
Michael Runge4038aa82013-12-13 18:06:28 -0800870 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
871 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
Doug Zongker761e6422009-09-25 10:45:39 -0700872 largest_source_size = max(largest_source_size, sf.size)
Doug Zongkereef39442009-04-02 12:14:19 -0700873
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700874 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
875 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
Doug Zongker2ea21062010-04-28 16:05:21 -0700876 metadata["pre-build"] = source_fp
877 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -0700878
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700879 script.Mount("/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700880 script.AssertSomeFingerprint(source_fp, target_fp)
Doug Zongkereef39442009-04-02 12:14:19 -0700881
Doug Zongker55d93282011-01-25 17:03:34 -0800882 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700883 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
884 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -0800885 target_boot = common.GetBootableImage(
886 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800887 updating_boot = (not OPTIONS.two_step and
888 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -0700889
Doug Zongker55d93282011-01-25 17:03:34 -0800890 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700891 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
892 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -0800893 target_recovery = common.GetBootableImage(
894 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -0700895 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700896
Doug Zongker881dd402009-09-20 14:03:55 -0700897 # Here's how we divide up the progress bar:
898 # 0.1 for verifying the start state (PatchCheck calls)
899 # 0.8 for applying patches (ApplyPatch calls)
900 # 0.1 for unpacking verbatim files, symlinking, and doing the
901 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -0700902
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700903 AppendAssertions(script, OPTIONS.target_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700904 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -0700905
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800906 # Two-step incremental package strategy (in chronological order,
907 # which is *not* the order in which the generated script has
908 # things):
909 #
910 # if stage is not "2/3" or "3/3":
911 # do verification on current system
912 # write recovery image to boot partition
913 # set stage to "2/3"
914 # reboot to boot partition and restart recovery
915 # else if stage is "2/3":
916 # write recovery image to recovery partition
917 # set stage to "3/3"
918 # reboot to recovery partition and restart recovery
919 # else:
920 # (stage must be "3/3")
921 # perform update:
922 # patch system files, etc.
923 # force full install of new boot image
924 # set up system to update recovery partition on first boot
925 # complete script normally (allow recovery to mark itself finished and reboot)
926
927 if OPTIONS.two_step:
928 if not OPTIONS.info_dict.get("multistage_support", None):
929 assert False, "two-step packages not supported by this build"
930 fs = OPTIONS.info_dict["fstab"]["/misc"]
931 assert fs.fs_type.upper() == "EMMC", \
932 "two-step packages only supported on devices with EMMC /misc partitions"
933 bcb_dev = {"bcb_dev": fs.device}
934 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
935 script.AppendExtra("""
936if get_stage("%(bcb_dev)s", "stage") == "2/3" then
937""" % bcb_dev)
938 script.AppendExtra("sleep(20);\n");
939 script.WriteRawImage("/recovery", "recovery.img")
940 script.AppendExtra("""
941set_stage("%(bcb_dev)s", "3/3");
942reboot_now("%(bcb_dev)s", "recovery");
943else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
944""" % bcb_dev)
945
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700946 script.Print("Verifying current system...")
947
Doug Zongkere5ff5902012-01-17 10:55:37 -0800948 device_specific.IncrementalOTA_VerifyBegin()
949
Doug Zongker881dd402009-09-20 14:03:55 -0700950 script.ShowProgress(0.1, 0)
Doug Zongker881dd402009-09-20 14:03:55 -0700951 so_far = 0
Doug Zongkereef39442009-04-02 12:14:19 -0700952
Michael Runge4038aa82013-12-13 18:06:28 -0800953 for tf, sf, size, patch_sha in patch_list:
954 if tf.name != sf.name:
955 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
956 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
Doug Zongker881dd402009-09-20 14:03:55 -0700957 so_far += sf.size
Doug Zongkereef39442009-04-02 12:14:19 -0700958
Doug Zongker5da317e2009-06-02 13:38:17 -0700959 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700960 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -0700961 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -0700962 print "boot target: %d source: %d diff: %d" % (
963 target_boot.size, source_boot.size, len(d))
964
Doug Zongker048e7ca2009-06-15 14:31:53 -0700965 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -0700966
Doug Zongker96a57e72010-09-26 14:57:41 -0700967 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -0700968
969 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
970 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -0700971 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700972 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -0700973 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -0700974
975 if patch_list or updating_recovery or updating_boot:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700976 script.CacheFreeSpaceCheck(largest_source_size)
Doug Zongker5a482092010-02-17 16:09:18 -0800977
Doug Zongker05d3dea2009-06-22 11:32:31 -0700978 device_specific.IncrementalOTA_VerifyEnd()
979
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800980 if OPTIONS.two_step:
981 script.WriteRawImage("/boot", "recovery.img")
982 script.AppendExtra("""
983set_stage("%(bcb_dev)s", "2/3");
984reboot_now("%(bcb_dev)s", "");
985else
986""" % bcb_dev)
987
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700988 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -0700989
Doug Zongkere5ff5902012-01-17 10:55:37 -0800990 device_specific.IncrementalOTA_InstallBegin()
991
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800992 if OPTIONS.two_step:
993 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
994 script.WriteRawImage("/boot", "boot.img")
995 print "writing full boot image (forced by two-step mode)"
996
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700997 if OPTIONS.wipe_user_data:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700998 script.Print("Erasing user data...")
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700999 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001000
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001001 script.Print("Removing unneeded files...")
Doug Zongker0f3298a2009-06-30 08:16:58 -07001002 script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
1003 ["/"+i for i in sorted(source_data)
Michael Runge4038aa82013-12-13 18:06:28 -08001004 if i not in target_data and
1005 i not in renames] +
Doug Zongker3b949f02009-08-24 10:24:32 -07001006 ["/system/recovery.img"])
Doug Zongkereef39442009-04-02 12:14:19 -07001007
Doug Zongker881dd402009-09-20 14:03:55 -07001008 script.ShowProgress(0.8, 0)
1009 total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
1010 if updating_boot:
1011 total_patch_size += target_boot.size
1012 so_far = 0
1013
1014 script.Print("Patching system files...")
Doug Zongkere92f15a2011-08-26 13:46:40 -07001015 deferred_patch_list = []
1016 for item in patch_list:
Michael Runge4038aa82013-12-13 18:06:28 -08001017 tf, sf, size, _ = item
Doug Zongkere92f15a2011-08-26 13:46:40 -07001018 if tf.name == "system/build.prop":
1019 deferred_patch_list.append(item)
1020 continue
Michael Runge4038aa82013-12-13 18:06:28 -08001021 if (sf.name != tf.name):
1022 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1023 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
Doug Zongker881dd402009-09-20 14:03:55 -07001024 so_far += tf.size
1025 script.SetProgress(so_far / total_patch_size)
1026
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001027 if not OPTIONS.two_step:
1028 if updating_boot:
1029 # Produce the boot image by applying a patch to the current
1030 # contents of the boot partition, and write it back to the
1031 # partition.
1032 script.Print("Patching boot image...")
1033 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1034 % (boot_type, boot_device,
1035 source_boot.size, source_boot.sha1,
1036 target_boot.size, target_boot.sha1),
1037 "-",
1038 target_boot.size, target_boot.sha1,
1039 source_boot.sha1, "patch/boot.img.p")
1040 so_far += target_boot.size
1041 script.SetProgress(so_far / total_patch_size)
1042 print "boot image changed; including."
1043 else:
1044 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001045
1046 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001047 # Recovery is generated as a patch using both the boot image
1048 # (which contains the same linux kernel as recovery) and the file
1049 # /system/etc/recovery-resource.dat (which contains all the images
1050 # used in the recovery UI) as sources. This lets us minimize the
1051 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001052 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001053 # For older builds where recovery-resource.dat is not present, we
1054 # use only the boot image as the source.
1055
Doug Zongkerc9253822014-02-04 12:17:58 -08001056 if not target_has_recovery_patch:
1057 def output_sink(fn, data):
1058 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
1059 Item.Get("system/" + fn, dir=False)
1060
1061 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1062 target_recovery, target_boot)
1063 script.DeleteFiles(["/system/recovery-from-boot.p",
1064 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001065 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001066 else:
1067 print "recovery image unchanged; skipping."
1068
Doug Zongker881dd402009-09-20 14:03:55 -07001069 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001070
Doug Zongker1807e702012-02-28 12:21:08 -08001071 target_symlinks = CopySystemFiles(target_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -07001072
1073 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001074 temp_script = script.MakeTemporary()
Doug Zongker283e2a12010-03-15 17:52:32 -07001075 Item.GetMetadata(target_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -07001076 Item.Get("system").SetPermissions(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001077
1078 # Note that this call will mess up the tree of Items, so make sure
1079 # we're done with it.
Doug Zongker1807e702012-02-28 12:21:08 -08001080 source_symlinks = CopySystemFiles(source_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -07001081 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1082
1083 # Delete all the symlinks in source that aren't in target. This
1084 # needs to happen before verbatim files are unpacked, in case a
1085 # symlink in the source is replaced by a real file in the target.
1086 to_delete = []
1087 for dest, link in source_symlinks:
1088 if link not in target_symlinks_d:
1089 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001090 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001091
1092 if verbatim_targets:
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001093 script.Print("Unpacking new files...")
1094 script.UnpackPackageDir("system", "/system")
1095
Doug Zongkerc9253822014-02-04 12:17:58 -08001096 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001097 script.Print("Unpacking new recovery...")
1098 script.UnpackPackageDir("recovery", "/system")
1099
Michael Runge4038aa82013-12-13 18:06:28 -08001100 if len(renames) > 0:
1101 script.Print("Renaming files...")
1102
1103 for src in renames:
1104 print "Renaming " + src + " to " + renames[src].name
1105 script.RenameFile(src, renames[src].name)
1106
Doug Zongker05d3dea2009-06-22 11:32:31 -07001107 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001108
1109 # Create all the symlinks that don't already exist, or point to
1110 # somewhere different than what we want. Delete each symlink before
1111 # creating it, since the 'symlink' command won't overwrite.
1112 to_create = []
1113 for dest, link in target_symlinks:
1114 if link in source_symlinks_d:
1115 if dest != source_symlinks_d[link]:
1116 to_create.append((dest, link))
1117 else:
1118 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001119 script.DeleteFiles([i[1] for i in to_create])
1120 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001121
1122 # Now that the symlinks are created, we can set all the
1123 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001124 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001125
Doug Zongker881dd402009-09-20 14:03:55 -07001126 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001127 device_specific.IncrementalOTA_InstallEnd()
1128
Doug Zongker1c390a22009-05-14 19:06:36 -07001129 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001130 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001131
Doug Zongkere92f15a2011-08-26 13:46:40 -07001132 # Patch the build.prop file last, so if something fails but the
1133 # device can still come up, it appears to be the old build and will
1134 # get set the OTA package again to retry.
1135 script.Print("Patching remaining system files...")
1136 for item in deferred_patch_list:
Michael Runge4038aa82013-12-13 18:06:28 -08001137 tf, sf, size, _ = item
1138 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
Nick Kralevich0eb17d92013-09-07 17:10:29 -07001139 script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001140
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001141 if OPTIONS.two_step:
1142 script.AppendExtra("""
1143set_stage("%(bcb_dev)s", "");
1144endif;
1145endif;
1146""" % bcb_dev)
1147
Doug Zongker25568482014-03-03 10:21:27 -08001148 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -07001149 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001150
1151
1152def main(argv):
1153
1154 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001155 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001156 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001157 elif o in ("-k", "--package_key"):
1158 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001159 elif o in ("-i", "--incremental_from"):
1160 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001161 elif o in ("-w", "--wipe_user_data"):
1162 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001163 elif o in ("-n", "--no_prereq"):
1164 OPTIONS.omit_prereq = True
Doug Zongker1c390a22009-05-14 19:06:36 -07001165 elif o in ("-e", "--extra_script"):
1166 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001167 elif o in ("-a", "--aslr_mode"):
1168 if a in ("on", "On", "true", "True", "yes", "Yes"):
1169 OPTIONS.aslr_mode = True
1170 else:
1171 OPTIONS.aslr_mode = False
Doug Zongker761e6422009-09-25 10:45:39 -07001172 elif o in ("--worker_threads"):
1173 OPTIONS.worker_threads = int(a)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001174 elif o in ("-2", "--two_step"):
1175 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001176 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001177 OPTIONS.no_signing = True
Doug Zongker26e66192014-02-20 13:22:07 -08001178 elif o == "--block":
1179 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001180 elif o in ("-b", "--binary"):
1181 OPTIONS.updater_binary = a
Doug Zongkereef39442009-04-02 12:14:19 -07001182 else:
1183 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001184 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001185
1186 args = common.ParseOptions(argv, __doc__,
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001187 extra_opts="b:k:i:d:wne:a:2",
Doug Zongkereef39442009-04-02 12:14:19 -07001188 extra_long_opts=["board_config=",
1189 "package_key=",
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001190 "incremental_from=",
Doug Zongker962069c2009-04-23 11:41:58 -07001191 "wipe_user_data",
Doug Zongker1c390a22009-05-14 19:06:36 -07001192 "no_prereq",
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001193 "extra_script=",
Hristo Bojinov96be7202010-08-02 10:26:17 -07001194 "worker_threads=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001195 "aslr_mode=",
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001196 "two_step",
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001197 "no_signing",
Doug Zongker26e66192014-02-20 13:22:07 -08001198 "block",
Doug Zongker25568482014-03-03 10:21:27 -08001199 "binary=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001200 ],
Doug Zongkereef39442009-04-02 12:14:19 -07001201 extra_option_handler=option_handler)
1202
1203 if len(args) != 2:
1204 common.Usage(__doc__)
1205 sys.exit(1)
1206
Doug Zongker1c390a22009-05-14 19:06:36 -07001207 if OPTIONS.extra_script is not None:
1208 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1209
Doug Zongkereef39442009-04-02 12:14:19 -07001210 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001211 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001212
Doug Zongkereef39442009-04-02 12:14:19 -07001213 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001214 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001215
1216 # If this image was originally labelled with SELinux contexts, make sure we
1217 # also apply the labels in our new image. During building, the "file_contexts"
1218 # is in the out/ directory tree, but for repacking from target-files.zip it's
1219 # in the root directory of the ramdisk.
1220 if "selinux_fc" in OPTIONS.info_dict:
1221 OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK",
1222 "file_contexts")
1223
Doug Zongker37974732010-09-16 17:44:38 -07001224 if OPTIONS.verbose:
1225 print "--- target info ---"
1226 common.DumpInfoDict(OPTIONS.info_dict)
1227
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001228 # If the caller explicitly specified the device-specific extensions
1229 # path via -s/--device_specific, use that. Otherwise, use
1230 # META/releasetools.py if it is present in the target target_files.
1231 # Otherwise, take the path of the file from 'tool_extensions' in the
1232 # info dict and look for that in the local filesystem, relative to
1233 # the current directory.
1234
Doug Zongker37974732010-09-16 17:44:38 -07001235 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001236 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1237 if os.path.exists(from_input):
1238 print "(using device-specific extensions from target_files)"
1239 OPTIONS.device_specific = from_input
1240 else:
1241 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1242
Doug Zongker37974732010-09-16 17:44:38 -07001243 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001244 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001245
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001246 if OPTIONS.no_signing:
1247 output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
1248 else:
1249 temp_zip_file = tempfile.NamedTemporaryFile()
1250 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1251 compression=zipfile.ZIP_DEFLATED)
Doug Zongkereef39442009-04-02 12:14:19 -07001252
1253 if OPTIONS.incremental_source is None:
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001254 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001255 if OPTIONS.package_key is None:
1256 OPTIONS.package_key = OPTIONS.info_dict.get(
1257 "default_system_dev_certificate",
1258 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -07001259 else:
1260 print "unzipping source target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001261 OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
Doug Zongker37974732010-09-16 17:44:38 -07001262 OPTIONS.target_info_dict = OPTIONS.info_dict
1263 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
Doug Zongker5fad2032014-02-24 08:13:45 -08001264 if "selinux_fc" in OPTIONS.source_info_dict:
1265 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(OPTIONS.source_tmp, "BOOT", "RAMDISK",
1266 "file_contexts")
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001267 if OPTIONS.package_key is None:
Doug Zongker91b4f8a2011-09-23 12:48:33 -07001268 OPTIONS.package_key = OPTIONS.source_info_dict.get(
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001269 "default_system_dev_certificate",
1270 "build/target/product/security/testkey")
Doug Zongker37974732010-09-16 17:44:38 -07001271 if OPTIONS.verbose:
1272 print "--- source info ---"
1273 common.DumpInfoDict(OPTIONS.source_info_dict)
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001274 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001275
1276 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001277
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001278 if not OPTIONS.no_signing:
1279 SignOutput(temp_zip_file.name, args[1])
1280 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001281
1282 common.Cleanup()
1283
1284 print "done."
1285
1286
1287if __name__ == '__main__':
1288 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001289 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001290 main(sys.argv[1:])
1291 except common.ExternalError, e:
1292 print
1293 print " ERROR: %s" % (e,)
1294 print
1295 sys.exit(1)