blob: 15c21282ddc6cdd7cb5c3514d7f376166543fbbe [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:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700556 raise common.ExternalError("couldn't find %s in build.prop" % (property,))
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)
626 src_data = None
627
628 print "building target system image..."
629 tgt_file = tempfile.NamedTemporaryFile()
Doug Zongker5fad2032014-02-24 08:13:45 -0800630 tgt_mapdata, tgt_data = img_from_target_files.BuildSystem(
631 OPTIONS.target_tmp, OPTIONS.target_info_dict,
632 sparse=False, map_file=True)
Geremy Condra36bd3652014-02-06 19:45:10 -0800633 tgt_sys_sha1 = sha1(tgt_data).hexdigest()
634 print "target system sha1:", tgt_sys_sha1
635 tgt_sys_len = len(tgt_data)
636 tgt_file.write(tgt_data)
637 tgt_data = None
638
639 system_type, system_device = common.GetTypeAndDevice("/system", OPTIONS.info_dict)
640 system_patch = common.MakeSystemPatch(src_file, tgt_file)
641 system_patch.AddToZip(output_zip, compression=zipfile.ZIP_STORED)
Doug Zongker5fad2032014-02-24 08:13:45 -0800642 src_mapfilename = system_patch.name + ".src.map"
643 common.ZipWriteStr(output_zip, src_mapfilename, src_mapdata)
644 tgt_mapfilename = system_patch.name + ".tgt.map"
645 common.ZipWriteStr(output_zip, tgt_mapfilename, tgt_mapdata)
Geremy Condra36bd3652014-02-06 19:45:10 -0800646
647 AppendAssertions(script, OPTIONS.target_info_dict)
648 device_specific.IncrementalOTA_Assertions()
649
650 # Two-step incremental package strategy (in chronological order,
651 # which is *not* the order in which the generated script has
652 # things):
653 #
654 # if stage is not "2/3" or "3/3":
655 # do verification on current system
656 # write recovery image to boot partition
657 # set stage to "2/3"
658 # reboot to boot partition and restart recovery
659 # else if stage is "2/3":
660 # write recovery image to recovery partition
661 # set stage to "3/3"
662 # reboot to recovery partition and restart recovery
663 # else:
664 # (stage must be "3/3")
665 # perform update:
666 # patch system files, etc.
667 # force full install of new boot image
668 # set up system to update recovery partition on first boot
669 # complete script normally (allow recovery to mark itself finished and reboot)
670
671 if OPTIONS.two_step:
672 if not OPTIONS.info_dict.get("multistage_support", None):
673 assert False, "two-step packages not supported by this build"
674 fs = OPTIONS.info_dict["fstab"]["/misc"]
675 assert fs.fs_type.upper() == "EMMC", \
676 "two-step packages only supported on devices with EMMC /misc partitions"
677 bcb_dev = {"bcb_dev": fs.device}
678 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
679 script.AppendExtra("""
680if get_stage("%(bcb_dev)s", "stage") == "2/3" then
681""" % bcb_dev)
682 script.AppendExtra("sleep(20);\n");
683 script.WriteRawImage("/recovery", "recovery.img")
684 script.AppendExtra("""
685set_stage("%(bcb_dev)s", "3/3");
686reboot_now("%(bcb_dev)s", "recovery");
687else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
688""" % bcb_dev)
689
690 script.Print("Verifying current system...")
691
692 device_specific.IncrementalOTA_VerifyBegin()
693
694 script.AssertRecoveryFingerprint(source_fp, target_fp)
695
696 if updating_boot:
Geremy Condra36bd3652014-02-06 19:45:10 -0800697 d = common.Difference(target_boot, source_boot)
698 _, _, d = d.ComputePatch()
699 print "boot target: %d source: %d diff: %d" % (
700 target_boot.size, source_boot.size, len(d))
701
702 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
703
704 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
705
706 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
707 (boot_type, boot_device,
708 source_boot.size, source_boot.sha1,
709 target_boot.size, target_boot.sha1))
710
711 device_specific.IncrementalOTA_VerifyEnd()
712
713 if OPTIONS.two_step:
714 script.WriteRawImage("/boot", "recovery.img")
715 script.AppendExtra("""
716set_stage("%(bcb_dev)s", "2/3");
717reboot_now("%(bcb_dev)s", "");
718else
719""" % bcb_dev)
720
721 script.Comment("---- start making changes here ----")
722
723 device_specific.IncrementalOTA_InstallBegin()
724
Geremy Condra36bd3652014-02-06 19:45:10 -0800725 script.Print("Patching system image...")
726 script.Syspatch(system_device,
Doug Zongker5fad2032014-02-24 08:13:45 -0800727 tgt_mapfilename, tgt_sys_sha1,
728 src_mapfilename, src_sys_sha1,
Geremy Condra36bd3652014-02-06 19:45:10 -0800729 system_patch.name)
730
731 if OPTIONS.two_step:
732 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
733 script.WriteRawImage("/boot", "boot.img")
734 print "writing full boot image (forced by two-step mode)"
735
736 if not OPTIONS.two_step:
737 if updating_boot:
738 # Produce the boot image by applying a patch to the current
739 # contents of the boot partition, and write it back to the
740 # partition.
741 script.Print("Patching boot image...")
742 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
743 % (boot_type, boot_device,
744 source_boot.size, source_boot.sha1,
745 target_boot.size, target_boot.sha1),
746 "-",
747 target_boot.size, target_boot.sha1,
748 source_boot.sha1, "patch/boot.img.p")
749 print "boot image changed; including."
750 else:
751 print "boot image unchanged; skipping."
752
753 # Do device-specific installation (eg, write radio image).
754 device_specific.IncrementalOTA_InstallEnd()
755
756 if OPTIONS.extra_script is not None:
757 script.AppendExtra(OPTIONS.extra_script)
758
Doug Zongker922206e2014-03-04 13:16:24 -0800759 if OPTIONS.wipe_user_data:
760 script.Print("Erasing user data...")
761 script.FormatPartition("/data")
762
Geremy Condra36bd3652014-02-06 19:45:10 -0800763 if OPTIONS.two_step:
764 script.AppendExtra("""
765set_stage("%(bcb_dev)s", "");
766endif;
767endif;
768""" % bcb_dev)
769
770 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800771 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800772 WriteMetadata(metadata, output_zip)
773
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700774def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -0800775 target_has_recovery_patch = HasRecoveryPatch(target_zip)
776 source_has_recovery_patch = HasRecoveryPatch(source_zip)
777
Doug Zongker26e66192014-02-20 13:22:07 -0800778 if (OPTIONS.block_based and
779 target_has_recovery_patch and
780 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -0800781 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
782
Doug Zongker37974732010-09-16 17:44:38 -0700783 source_version = OPTIONS.source_info_dict["recovery_api_version"]
784 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700785
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700786 if source_version == 0:
787 print ("WARNING: generating edify script for a source that "
788 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700789 script = edify_generator.EdifyGenerator(source_version,
790 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700791
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700792 metadata = {"pre-device": GetBuildProp("ro.product.device",
793 OPTIONS.source_info_dict),
794 "post-timestamp": GetBuildProp("ro.build.date.utc",
795 OPTIONS.target_info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700796 }
797
Doug Zongker05d3dea2009-06-22 11:32:31 -0700798 device_specific = common.DeviceSpecificParams(
799 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800800 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700801 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800802 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700803 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -0700804 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -0700805 metadata=metadata,
806 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700807
Doug Zongkereef39442009-04-02 12:14:19 -0700808 print "Loading target..."
Doug Zongker1807e702012-02-28 12:21:08 -0800809 target_data = LoadSystemFiles(target_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700810 print "Loading source..."
Doug Zongker1807e702012-02-28 12:21:08 -0800811 source_data = LoadSystemFiles(source_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700812
813 verbatim_targets = []
814 patch_list = []
Doug Zongker761e6422009-09-25 10:45:39 -0700815 diffs = []
Michael Runge4038aa82013-12-13 18:06:28 -0800816 renames = {}
817 known_paths = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700818 largest_source_size = 0
Michael Runge4038aa82013-12-13 18:06:28 -0800819
820 matching_file_cache = {}
821 for fn, sf in source_data.items():
822 assert fn == sf.name
823 matching_file_cache["path:" + fn] = sf
824 if fn in target_data.keys():
825 AddToKnownPaths(fn, known_paths)
826 # Only allow eligibility for filename/sha matching
827 # if there isn't a perfect path match.
828 if target_data.get(sf.name) is None:
829 matching_file_cache["file:" + fn.split("/")[-1]] = sf
830 matching_file_cache["sha:" + sf.sha1] = sf
831
Doug Zongkereef39442009-04-02 12:14:19 -0700832 for fn in sorted(target_data.keys()):
833 tf = target_data[fn]
Doug Zongker761e6422009-09-25 10:45:39 -0700834 assert fn == tf.name
Michael Runge4038aa82013-12-13 18:06:28 -0800835 sf = ClosestFileMatch(tf, matching_file_cache, renames)
836 if sf is not None and sf.name != tf.name:
837 print "File has moved from " + sf.name + " to " + tf.name
838 renames[sf.name] = tf
Doug Zongkereef39442009-04-02 12:14:19 -0700839
840 if sf is None or fn in OPTIONS.require_verbatim:
841 # This file should be included verbatim
842 if fn in OPTIONS.prohibit_verbatim:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700843 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
Doug Zongkereef39442009-04-02 12:14:19 -0700844 print "send", fn, "verbatim"
845 tf.AddToZip(output_zip)
846 verbatim_targets.append((fn, tf.size))
Michael Runge4038aa82013-12-13 18:06:28 -0800847 if fn in target_data.keys():
848 AddToKnownPaths(fn, known_paths)
Doug Zongkereef39442009-04-02 12:14:19 -0700849 elif tf.sha1 != sf.sha1:
850 # File is different; consider sending as a patch
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700851 diffs.append(common.Difference(tf, sf))
Doug Zongkereef39442009-04-02 12:14:19 -0700852 else:
Michael Runge4038aa82013-12-13 18:06:28 -0800853 # Target file data identical to source (may still be renamed)
Doug Zongkereef39442009-04-02 12:14:19 -0700854 pass
855
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700856 common.ComputeDifferences(diffs)
Doug Zongker761e6422009-09-25 10:45:39 -0700857
858 for diff in diffs:
859 tf, sf, d = diff.GetPatch()
Michael Runge4038aa82013-12-13 18:06:28 -0800860 path = "/".join(tf.name.split("/")[:-1])
861 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
862 path not in known_paths:
Doug Zongker761e6422009-09-25 10:45:39 -0700863 # patch is almost as big as the file; don't bother patching
Michael Runge4038aa82013-12-13 18:06:28 -0800864 # or a patch + rename cannot take place due to the target
865 # directory not existing
Doug Zongker761e6422009-09-25 10:45:39 -0700866 tf.AddToZip(output_zip)
867 verbatim_targets.append((tf.name, tf.size))
Michael Runge4038aa82013-12-13 18:06:28 -0800868 if sf.name in renames:
869 del renames[sf.name]
870 AddToKnownPaths(tf.name, known_paths)
Doug Zongker761e6422009-09-25 10:45:39 -0700871 else:
Michael Runge4038aa82013-12-13 18:06:28 -0800872 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
873 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
Doug Zongker761e6422009-09-25 10:45:39 -0700874 largest_source_size = max(largest_source_size, sf.size)
Doug Zongkereef39442009-04-02 12:14:19 -0700875
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700876 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
877 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
Doug Zongker2ea21062010-04-28 16:05:21 -0700878 metadata["pre-build"] = source_fp
879 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -0700880
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700881 script.Mount("/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700882 script.AssertSomeFingerprint(source_fp, target_fp)
Doug Zongkereef39442009-04-02 12:14:19 -0700883
Doug Zongker55d93282011-01-25 17:03:34 -0800884 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700885 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
886 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -0800887 target_boot = common.GetBootableImage(
888 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800889 updating_boot = (not OPTIONS.two_step and
890 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -0700891
Doug Zongker55d93282011-01-25 17:03:34 -0800892 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700893 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
894 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -0800895 target_recovery = common.GetBootableImage(
896 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -0700897 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700898
Doug Zongker881dd402009-09-20 14:03:55 -0700899 # Here's how we divide up the progress bar:
900 # 0.1 for verifying the start state (PatchCheck calls)
901 # 0.8 for applying patches (ApplyPatch calls)
902 # 0.1 for unpacking verbatim files, symlinking, and doing the
903 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -0700904
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700905 AppendAssertions(script, OPTIONS.target_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700906 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -0700907
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800908 # Two-step incremental package strategy (in chronological order,
909 # which is *not* the order in which the generated script has
910 # things):
911 #
912 # if stage is not "2/3" or "3/3":
913 # do verification on current system
914 # write recovery image to boot partition
915 # set stage to "2/3"
916 # reboot to boot partition and restart recovery
917 # else if stage is "2/3":
918 # write recovery image to recovery partition
919 # set stage to "3/3"
920 # reboot to recovery partition and restart recovery
921 # else:
922 # (stage must be "3/3")
923 # perform update:
924 # patch system files, etc.
925 # force full install of new boot image
926 # set up system to update recovery partition on first boot
927 # complete script normally (allow recovery to mark itself finished and reboot)
928
929 if OPTIONS.two_step:
930 if not OPTIONS.info_dict.get("multistage_support", None):
931 assert False, "two-step packages not supported by this build"
932 fs = OPTIONS.info_dict["fstab"]["/misc"]
933 assert fs.fs_type.upper() == "EMMC", \
934 "two-step packages only supported on devices with EMMC /misc partitions"
935 bcb_dev = {"bcb_dev": fs.device}
936 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
937 script.AppendExtra("""
938if get_stage("%(bcb_dev)s", "stage") == "2/3" then
939""" % bcb_dev)
940 script.AppendExtra("sleep(20);\n");
941 script.WriteRawImage("/recovery", "recovery.img")
942 script.AppendExtra("""
943set_stage("%(bcb_dev)s", "3/3");
944reboot_now("%(bcb_dev)s", "recovery");
945else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
946""" % bcb_dev)
947
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700948 script.Print("Verifying current system...")
949
Doug Zongkere5ff5902012-01-17 10:55:37 -0800950 device_specific.IncrementalOTA_VerifyBegin()
951
Doug Zongker881dd402009-09-20 14:03:55 -0700952 script.ShowProgress(0.1, 0)
Doug Zongker881dd402009-09-20 14:03:55 -0700953 so_far = 0
Doug Zongkereef39442009-04-02 12:14:19 -0700954
Michael Runge4038aa82013-12-13 18:06:28 -0800955 for tf, sf, size, patch_sha in patch_list:
956 if tf.name != sf.name:
957 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
958 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
Doug Zongker881dd402009-09-20 14:03:55 -0700959 so_far += sf.size
Doug Zongkereef39442009-04-02 12:14:19 -0700960
Doug Zongker5da317e2009-06-02 13:38:17 -0700961 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700962 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -0700963 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -0700964 print "boot target: %d source: %d diff: %d" % (
965 target_boot.size, source_boot.size, len(d))
966
Doug Zongker048e7ca2009-06-15 14:31:53 -0700967 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -0700968
Doug Zongker96a57e72010-09-26 14:57:41 -0700969 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -0700970
971 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
972 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -0700973 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700974 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -0700975 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -0700976
977 if patch_list or updating_recovery or updating_boot:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700978 script.CacheFreeSpaceCheck(largest_source_size)
Doug Zongker5a482092010-02-17 16:09:18 -0800979
Doug Zongker05d3dea2009-06-22 11:32:31 -0700980 device_specific.IncrementalOTA_VerifyEnd()
981
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800982 if OPTIONS.two_step:
983 script.WriteRawImage("/boot", "recovery.img")
984 script.AppendExtra("""
985set_stage("%(bcb_dev)s", "2/3");
986reboot_now("%(bcb_dev)s", "");
987else
988""" % bcb_dev)
989
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700990 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -0700991
Doug Zongkere5ff5902012-01-17 10:55:37 -0800992 device_specific.IncrementalOTA_InstallBegin()
993
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800994 if OPTIONS.two_step:
995 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
996 script.WriteRawImage("/boot", "boot.img")
997 print "writing full boot image (forced by two-step mode)"
998
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700999 script.Print("Removing unneeded files...")
Doug Zongker0f3298a2009-06-30 08:16:58 -07001000 script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
1001 ["/"+i for i in sorted(source_data)
Michael Runge4038aa82013-12-13 18:06:28 -08001002 if i not in target_data and
1003 i not in renames] +
Doug Zongker3b949f02009-08-24 10:24:32 -07001004 ["/system/recovery.img"])
Doug Zongkereef39442009-04-02 12:14:19 -07001005
Doug Zongker881dd402009-09-20 14:03:55 -07001006 script.ShowProgress(0.8, 0)
1007 total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
1008 if updating_boot:
1009 total_patch_size += target_boot.size
1010 so_far = 0
1011
1012 script.Print("Patching system files...")
Doug Zongkere92f15a2011-08-26 13:46:40 -07001013 deferred_patch_list = []
1014 for item in patch_list:
Michael Runge4038aa82013-12-13 18:06:28 -08001015 tf, sf, size, _ = item
Doug Zongkere92f15a2011-08-26 13:46:40 -07001016 if tf.name == "system/build.prop":
1017 deferred_patch_list.append(item)
1018 continue
Michael Runge4038aa82013-12-13 18:06:28 -08001019 if (sf.name != tf.name):
1020 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1021 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
Doug Zongker881dd402009-09-20 14:03:55 -07001022 so_far += tf.size
1023 script.SetProgress(so_far / total_patch_size)
1024
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001025 if not OPTIONS.two_step:
1026 if updating_boot:
1027 # Produce the boot image by applying a patch to the current
1028 # contents of the boot partition, and write it back to the
1029 # partition.
1030 script.Print("Patching boot image...")
1031 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1032 % (boot_type, boot_device,
1033 source_boot.size, source_boot.sha1,
1034 target_boot.size, target_boot.sha1),
1035 "-",
1036 target_boot.size, target_boot.sha1,
1037 source_boot.sha1, "patch/boot.img.p")
1038 so_far += target_boot.size
1039 script.SetProgress(so_far / total_patch_size)
1040 print "boot image changed; including."
1041 else:
1042 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001043
1044 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001045 # Recovery is generated as a patch using both the boot image
1046 # (which contains the same linux kernel as recovery) and the file
1047 # /system/etc/recovery-resource.dat (which contains all the images
1048 # used in the recovery UI) as sources. This lets us minimize the
1049 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001050 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001051 # For older builds where recovery-resource.dat is not present, we
1052 # use only the boot image as the source.
1053
Doug Zongkerc9253822014-02-04 12:17:58 -08001054 if not target_has_recovery_patch:
1055 def output_sink(fn, data):
1056 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
1057 Item.Get("system/" + fn, dir=False)
1058
1059 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1060 target_recovery, target_boot)
1061 script.DeleteFiles(["/system/recovery-from-boot.p",
1062 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001063 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001064 else:
1065 print "recovery image unchanged; skipping."
1066
Doug Zongker881dd402009-09-20 14:03:55 -07001067 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001068
Doug Zongker1807e702012-02-28 12:21:08 -08001069 target_symlinks = CopySystemFiles(target_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -07001070
1071 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001072 temp_script = script.MakeTemporary()
Doug Zongker283e2a12010-03-15 17:52:32 -07001073 Item.GetMetadata(target_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -07001074 Item.Get("system").SetPermissions(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001075
1076 # Note that this call will mess up the tree of Items, so make sure
1077 # we're done with it.
Doug Zongker1807e702012-02-28 12:21:08 -08001078 source_symlinks = CopySystemFiles(source_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -07001079 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1080
1081 # Delete all the symlinks in source that aren't in target. This
1082 # needs to happen before verbatim files are unpacked, in case a
1083 # symlink in the source is replaced by a real file in the target.
1084 to_delete = []
1085 for dest, link in source_symlinks:
1086 if link not in target_symlinks_d:
1087 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001088 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001089
1090 if verbatim_targets:
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001091 script.Print("Unpacking new files...")
1092 script.UnpackPackageDir("system", "/system")
1093
Doug Zongkerc9253822014-02-04 12:17:58 -08001094 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001095 script.Print("Unpacking new recovery...")
1096 script.UnpackPackageDir("recovery", "/system")
1097
Michael Runge4038aa82013-12-13 18:06:28 -08001098 if len(renames) > 0:
1099 script.Print("Renaming files...")
1100
1101 for src in renames:
1102 print "Renaming " + src + " to " + renames[src].name
1103 script.RenameFile(src, renames[src].name)
1104
Doug Zongker05d3dea2009-06-22 11:32:31 -07001105 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001106
1107 # Create all the symlinks that don't already exist, or point to
1108 # somewhere different than what we want. Delete each symlink before
1109 # creating it, since the 'symlink' command won't overwrite.
1110 to_create = []
1111 for dest, link in target_symlinks:
1112 if link in source_symlinks_d:
1113 if dest != source_symlinks_d[link]:
1114 to_create.append((dest, link))
1115 else:
1116 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001117 script.DeleteFiles([i[1] for i in to_create])
1118 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001119
1120 # Now that the symlinks are created, we can set all the
1121 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001122 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001123
Doug Zongker881dd402009-09-20 14:03:55 -07001124 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001125 device_specific.IncrementalOTA_InstallEnd()
1126
Doug Zongker1c390a22009-05-14 19:06:36 -07001127 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001128 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001129
Doug Zongkere92f15a2011-08-26 13:46:40 -07001130 # Patch the build.prop file last, so if something fails but the
1131 # device can still come up, it appears to be the old build and will
1132 # get set the OTA package again to retry.
1133 script.Print("Patching remaining system files...")
1134 for item in deferred_patch_list:
Michael Runge4038aa82013-12-13 18:06:28 -08001135 tf, sf, size, _ = item
1136 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
Nick Kralevich0eb17d92013-09-07 17:10:29 -07001137 script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001138
Doug Zongker922206e2014-03-04 13:16:24 -08001139 if OPTIONS.wipe_user_data:
1140 script.Print("Erasing user data...")
1141 script.FormatPartition("/data")
1142
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001143 if OPTIONS.two_step:
1144 script.AppendExtra("""
1145set_stage("%(bcb_dev)s", "");
1146endif;
1147endif;
1148""" % bcb_dev)
1149
Doug Zongker25568482014-03-03 10:21:27 -08001150 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -07001151 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001152
1153
1154def main(argv):
1155
1156 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001157 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001158 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001159 elif o in ("-k", "--package_key"):
1160 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001161 elif o in ("-i", "--incremental_from"):
1162 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001163 elif o in ("-w", "--wipe_user_data"):
1164 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001165 elif o in ("-n", "--no_prereq"):
1166 OPTIONS.omit_prereq = True
Doug Zongker1c390a22009-05-14 19:06:36 -07001167 elif o in ("-e", "--extra_script"):
1168 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001169 elif o in ("-a", "--aslr_mode"):
1170 if a in ("on", "On", "true", "True", "yes", "Yes"):
1171 OPTIONS.aslr_mode = True
1172 else:
1173 OPTIONS.aslr_mode = False
Doug Zongker761e6422009-09-25 10:45:39 -07001174 elif o in ("--worker_threads"):
1175 OPTIONS.worker_threads = int(a)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001176 elif o in ("-2", "--two_step"):
1177 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001178 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001179 OPTIONS.no_signing = True
Doug Zongker26e66192014-02-20 13:22:07 -08001180 elif o == "--block":
1181 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001182 elif o in ("-b", "--binary"):
1183 OPTIONS.updater_binary = a
Doug Zongkereef39442009-04-02 12:14:19 -07001184 else:
1185 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001186 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001187
1188 args = common.ParseOptions(argv, __doc__,
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001189 extra_opts="b:k:i:d:wne:a:2",
Doug Zongkereef39442009-04-02 12:14:19 -07001190 extra_long_opts=["board_config=",
1191 "package_key=",
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001192 "incremental_from=",
Doug Zongker962069c2009-04-23 11:41:58 -07001193 "wipe_user_data",
Doug Zongker1c390a22009-05-14 19:06:36 -07001194 "no_prereq",
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001195 "extra_script=",
Hristo Bojinov96be7202010-08-02 10:26:17 -07001196 "worker_threads=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001197 "aslr_mode=",
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001198 "two_step",
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001199 "no_signing",
Doug Zongker26e66192014-02-20 13:22:07 -08001200 "block",
Doug Zongker25568482014-03-03 10:21:27 -08001201 "binary=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001202 ],
Doug Zongkereef39442009-04-02 12:14:19 -07001203 extra_option_handler=option_handler)
1204
1205 if len(args) != 2:
1206 common.Usage(__doc__)
1207 sys.exit(1)
1208
Doug Zongker1c390a22009-05-14 19:06:36 -07001209 if OPTIONS.extra_script is not None:
1210 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1211
Doug Zongkereef39442009-04-02 12:14:19 -07001212 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001213 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001214
Doug Zongkereef39442009-04-02 12:14:19 -07001215 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001216 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001217
1218 # If this image was originally labelled with SELinux contexts, make sure we
1219 # also apply the labels in our new image. During building, the "file_contexts"
1220 # is in the out/ directory tree, but for repacking from target-files.zip it's
1221 # in the root directory of the ramdisk.
1222 if "selinux_fc" in OPTIONS.info_dict:
1223 OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK",
1224 "file_contexts")
1225
Doug Zongker37974732010-09-16 17:44:38 -07001226 if OPTIONS.verbose:
1227 print "--- target info ---"
1228 common.DumpInfoDict(OPTIONS.info_dict)
1229
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001230 # If the caller explicitly specified the device-specific extensions
1231 # path via -s/--device_specific, use that. Otherwise, use
1232 # META/releasetools.py if it is present in the target target_files.
1233 # Otherwise, take the path of the file from 'tool_extensions' in the
1234 # info dict and look for that in the local filesystem, relative to
1235 # the current directory.
1236
Doug Zongker37974732010-09-16 17:44:38 -07001237 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001238 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1239 if os.path.exists(from_input):
1240 print "(using device-specific extensions from target_files)"
1241 OPTIONS.device_specific = from_input
1242 else:
1243 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1244
Doug Zongker37974732010-09-16 17:44:38 -07001245 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001246 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001247
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001248 if OPTIONS.no_signing:
1249 output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
1250 else:
1251 temp_zip_file = tempfile.NamedTemporaryFile()
1252 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1253 compression=zipfile.ZIP_DEFLATED)
Doug Zongkereef39442009-04-02 12:14:19 -07001254
1255 if OPTIONS.incremental_source is None:
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001256 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001257 if OPTIONS.package_key is None:
1258 OPTIONS.package_key = OPTIONS.info_dict.get(
1259 "default_system_dev_certificate",
1260 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -07001261 else:
1262 print "unzipping source target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001263 OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
Doug Zongker37974732010-09-16 17:44:38 -07001264 OPTIONS.target_info_dict = OPTIONS.info_dict
1265 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
Doug Zongker5fad2032014-02-24 08:13:45 -08001266 if "selinux_fc" in OPTIONS.source_info_dict:
1267 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(OPTIONS.source_tmp, "BOOT", "RAMDISK",
1268 "file_contexts")
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001269 if OPTIONS.package_key is None:
Doug Zongker91b4f8a2011-09-23 12:48:33 -07001270 OPTIONS.package_key = OPTIONS.source_info_dict.get(
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001271 "default_system_dev_certificate",
1272 "build/target/product/security/testkey")
Doug Zongker37974732010-09-16 17:44:38 -07001273 if OPTIONS.verbose:
1274 print "--- source info ---"
1275 common.DumpInfoDict(OPTIONS.source_info_dict)
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001276 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001277
1278 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001279
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001280 if not OPTIONS.no_signing:
1281 SignOutput(temp_zip_file.name, args[1])
1282 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001283
1284 common.Cleanup()
1285
1286 print "done."
1287
1288
1289if __name__ == '__main__':
1290 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001291 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001292 main(sys.argv[1:])
1293 except common.ExternalError, e:
1294 print
1295 print " ERROR: %s" % (e,)
1296 print
1297 sys.exit(1)