blob: f71bd1f6f5f251c6efded81e83546723a57b1892 [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)
Geremy Condra36bd3652014-02-06 19:45:10 -0800624
625 print "building target system image..."
626 tgt_file = tempfile.NamedTemporaryFile()
Doug Zongker5fad2032014-02-24 08:13:45 -0800627 tgt_mapdata, tgt_data = img_from_target_files.BuildSystem(
628 OPTIONS.target_tmp, OPTIONS.target_info_dict,
629 sparse=False, map_file=True)
Geremy Condra36bd3652014-02-06 19:45:10 -0800630 tgt_sys_sha1 = sha1(tgt_data).hexdigest()
631 print "target system sha1:", tgt_sys_sha1
632 tgt_sys_len = len(tgt_data)
633 tgt_file.write(tgt_data)
Geremy Condra36bd3652014-02-06 19:45:10 -0800634
635 system_type, system_device = common.GetTypeAndDevice("/system", OPTIONS.info_dict)
636 system_patch = common.MakeSystemPatch(src_file, tgt_file)
Doug Zongker32b527d2014-03-04 10:03:02 -0800637
638 TestBlockPatch(src_data, src_mapdata, system_patch.data, tgt_mapdata, tgt_sys_sha1)
639 src_data = None
640 tgt_data = None
641
Geremy Condra36bd3652014-02-06 19:45:10 -0800642 system_patch.AddToZip(output_zip, compression=zipfile.ZIP_STORED)
Doug Zongker5fad2032014-02-24 08:13:45 -0800643 src_mapfilename = system_patch.name + ".src.map"
644 common.ZipWriteStr(output_zip, src_mapfilename, src_mapdata)
645 tgt_mapfilename = system_patch.name + ".tgt.map"
646 common.ZipWriteStr(output_zip, tgt_mapfilename, tgt_mapdata)
Geremy Condra36bd3652014-02-06 19:45:10 -0800647
648 AppendAssertions(script, OPTIONS.target_info_dict)
649 device_specific.IncrementalOTA_Assertions()
650
651 # Two-step incremental package strategy (in chronological order,
652 # which is *not* the order in which the generated script has
653 # things):
654 #
655 # if stage is not "2/3" or "3/3":
656 # do verification on current system
657 # write recovery image to boot partition
658 # set stage to "2/3"
659 # reboot to boot partition and restart recovery
660 # else if stage is "2/3":
661 # write recovery image to recovery partition
662 # set stage to "3/3"
663 # reboot to recovery partition and restart recovery
664 # else:
665 # (stage must be "3/3")
666 # perform update:
667 # patch system files, etc.
668 # force full install of new boot image
669 # set up system to update recovery partition on first boot
670 # complete script normally (allow recovery to mark itself finished and reboot)
671
672 if OPTIONS.two_step:
673 if not OPTIONS.info_dict.get("multistage_support", None):
674 assert False, "two-step packages not supported by this build"
675 fs = OPTIONS.info_dict["fstab"]["/misc"]
676 assert fs.fs_type.upper() == "EMMC", \
677 "two-step packages only supported on devices with EMMC /misc partitions"
678 bcb_dev = {"bcb_dev": fs.device}
679 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
680 script.AppendExtra("""
681if get_stage("%(bcb_dev)s", "stage") == "2/3" then
682""" % bcb_dev)
683 script.AppendExtra("sleep(20);\n");
684 script.WriteRawImage("/recovery", "recovery.img")
685 script.AppendExtra("""
686set_stage("%(bcb_dev)s", "3/3");
687reboot_now("%(bcb_dev)s", "recovery");
688else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
689""" % bcb_dev)
690
691 script.Print("Verifying current system...")
692
693 device_specific.IncrementalOTA_VerifyBegin()
694
695 script.AssertRecoveryFingerprint(source_fp, target_fp)
696
697 if updating_boot:
Geremy Condra36bd3652014-02-06 19:45:10 -0800698 d = common.Difference(target_boot, source_boot)
699 _, _, d = d.ComputePatch()
700 print "boot target: %d source: %d diff: %d" % (
701 target_boot.size, source_boot.size, len(d))
702
703 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
704
705 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
706
707 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
708 (boot_type, boot_device,
709 source_boot.size, source_boot.sha1,
710 target_boot.size, target_boot.sha1))
711
712 device_specific.IncrementalOTA_VerifyEnd()
713
714 if OPTIONS.two_step:
715 script.WriteRawImage("/boot", "recovery.img")
716 script.AppendExtra("""
717set_stage("%(bcb_dev)s", "2/3");
718reboot_now("%(bcb_dev)s", "");
719else
720""" % bcb_dev)
721
722 script.Comment("---- start making changes here ----")
723
724 device_specific.IncrementalOTA_InstallBegin()
725
726 if OPTIONS.wipe_user_data:
727 script.Print("Erasing user data...")
728 script.FormatPartition("/data")
729
730 script.Print("Patching system image...")
731 script.Syspatch(system_device,
Doug Zongker5fad2032014-02-24 08:13:45 -0800732 tgt_mapfilename, tgt_sys_sha1,
733 src_mapfilename, src_sys_sha1,
Geremy Condra36bd3652014-02-06 19:45:10 -0800734 system_patch.name)
735
736 if OPTIONS.two_step:
737 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
738 script.WriteRawImage("/boot", "boot.img")
739 print "writing full boot image (forced by two-step mode)"
740
741 if not OPTIONS.two_step:
742 if updating_boot:
743 # Produce the boot image by applying a patch to the current
744 # contents of the boot partition, and write it back to the
745 # partition.
746 script.Print("Patching boot image...")
747 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
748 % (boot_type, boot_device,
749 source_boot.size, source_boot.sha1,
750 target_boot.size, target_boot.sha1),
751 "-",
752 target_boot.size, target_boot.sha1,
753 source_boot.sha1, "patch/boot.img.p")
754 print "boot image changed; including."
755 else:
756 print "boot image unchanged; skipping."
757
758 # Do device-specific installation (eg, write radio image).
759 device_specific.IncrementalOTA_InstallEnd()
760
761 if OPTIONS.extra_script is not None:
762 script.AppendExtra(OPTIONS.extra_script)
763
764 if OPTIONS.two_step:
765 script.AppendExtra("""
766set_stage("%(bcb_dev)s", "");
767endif;
768endif;
769""" % bcb_dev)
770
771 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800772 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800773 WriteMetadata(metadata, output_zip)
774
Doug Zongker32b527d2014-03-04 10:03:02 -0800775def ParseMap(map_str):
776 x = map_str.split()
777 assert int(x[0]) == 4096
778 assert int(x[1]) == len(x)-2
779 return int(x[0]), [int(i) for i in x[2:]]
780
781def TestBlockPatch(src_muimg, src_map, patch_data, tgt_map, tgt_sha1):
782 src_blksize, src_regions = ParseMap(src_map)
783 tgt_blksize, tgt_regions = ParseMap(tgt_map)
784
785 with tempfile.NamedTemporaryFile() as src_file,\
786 tempfile.NamedTemporaryFile() as patch_file,\
787 tempfile.NamedTemporaryFile() as tgt_file,\
788 tempfile.NamedTemporaryFile() as src_map_file,\
789 tempfile.NamedTemporaryFile() as tgt_map_file:
790
791 src_total = sum(src_regions) * src_blksize
792 src_file.truncate(src_total)
793 p = 0
794 for i in range(0, len(src_regions), 2):
795 c, dc = src_regions[i:i+2]
796 src_file.write(src_muimg[p:(p+c*src_blksize)])
797 p += c*src_blksize
798 src_file.seek(dc*src_blksize, 1)
799 assert src_file.tell() == src_total
800
801 patch_file.write(patch_data)
802
803 tgt_total = sum(tgt_regions) * tgt_blksize
804 tgt_file.truncate(tgt_total)
805
806 src_map_file.write(src_map)
807 tgt_map_file.write(tgt_map)
808
809 src_file.flush()
810 src_map_file.flush()
811 patch_file.flush()
812 tgt_file.flush()
813 tgt_map_file.flush()
814
815 p = common.Run(["syspatch_host", src_file.name, src_map_file.name,
816 patch_file.name, tgt_file.name, tgt_map_file.name],
817 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
818 stdoutdata, _ = p.communicate()
819 if p.returncode != 0:
820 print stdoutdata
821 raise ValueError("failed to reconstruct target system image from patch")
822
823 h = sha1()
824 for i in range(0, len(tgt_regions), 2):
825 c, dc = tgt_regions[i:i+2]
826 h.update(tgt_file.read(c*tgt_blksize))
827 tgt_file.seek(dc*tgt_blksize, 1)
828
829 if h.hexdigest() != tgt_sha1:
830 raise ValueError("patch reconstructed incorrect target system image")
831
832 print "test of system image patch succeeded"
833
834
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700835def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -0800836 target_has_recovery_patch = HasRecoveryPatch(target_zip)
837 source_has_recovery_patch = HasRecoveryPatch(source_zip)
838
Doug Zongker26e66192014-02-20 13:22:07 -0800839 if (OPTIONS.block_based and
840 target_has_recovery_patch and
841 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -0800842 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
843
Doug Zongker37974732010-09-16 17:44:38 -0700844 source_version = OPTIONS.source_info_dict["recovery_api_version"]
845 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700846
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700847 if source_version == 0:
848 print ("WARNING: generating edify script for a source that "
849 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700850 script = edify_generator.EdifyGenerator(source_version,
851 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700852
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700853 metadata = {"pre-device": GetBuildProp("ro.product.device",
854 OPTIONS.source_info_dict),
855 "post-timestamp": GetBuildProp("ro.build.date.utc",
856 OPTIONS.target_info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700857 }
858
Doug Zongker05d3dea2009-06-22 11:32:31 -0700859 device_specific = common.DeviceSpecificParams(
860 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800861 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700862 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800863 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700864 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -0700865 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -0700866 metadata=metadata,
867 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700868
Doug Zongkereef39442009-04-02 12:14:19 -0700869 print "Loading target..."
Doug Zongker1807e702012-02-28 12:21:08 -0800870 target_data = LoadSystemFiles(target_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700871 print "Loading source..."
Doug Zongker1807e702012-02-28 12:21:08 -0800872 source_data = LoadSystemFiles(source_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700873
874 verbatim_targets = []
875 patch_list = []
Doug Zongker761e6422009-09-25 10:45:39 -0700876 diffs = []
Michael Runge4038aa82013-12-13 18:06:28 -0800877 renames = {}
878 known_paths = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700879 largest_source_size = 0
Michael Runge4038aa82013-12-13 18:06:28 -0800880
881 matching_file_cache = {}
882 for fn, sf in source_data.items():
883 assert fn == sf.name
884 matching_file_cache["path:" + fn] = sf
885 if fn in target_data.keys():
886 AddToKnownPaths(fn, known_paths)
887 # Only allow eligibility for filename/sha matching
888 # if there isn't a perfect path match.
889 if target_data.get(sf.name) is None:
890 matching_file_cache["file:" + fn.split("/")[-1]] = sf
891 matching_file_cache["sha:" + sf.sha1] = sf
892
Doug Zongkereef39442009-04-02 12:14:19 -0700893 for fn in sorted(target_data.keys()):
894 tf = target_data[fn]
Doug Zongker761e6422009-09-25 10:45:39 -0700895 assert fn == tf.name
Michael Runge4038aa82013-12-13 18:06:28 -0800896 sf = ClosestFileMatch(tf, matching_file_cache, renames)
897 if sf is not None and sf.name != tf.name:
898 print "File has moved from " + sf.name + " to " + tf.name
899 renames[sf.name] = tf
Doug Zongkereef39442009-04-02 12:14:19 -0700900
901 if sf is None or fn in OPTIONS.require_verbatim:
902 # This file should be included verbatim
903 if fn in OPTIONS.prohibit_verbatim:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700904 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
Doug Zongkereef39442009-04-02 12:14:19 -0700905 print "send", fn, "verbatim"
906 tf.AddToZip(output_zip)
907 verbatim_targets.append((fn, tf.size))
Michael Runge4038aa82013-12-13 18:06:28 -0800908 if fn in target_data.keys():
909 AddToKnownPaths(fn, known_paths)
Doug Zongkereef39442009-04-02 12:14:19 -0700910 elif tf.sha1 != sf.sha1:
911 # File is different; consider sending as a patch
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700912 diffs.append(common.Difference(tf, sf))
Doug Zongkereef39442009-04-02 12:14:19 -0700913 else:
Michael Runge4038aa82013-12-13 18:06:28 -0800914 # Target file data identical to source (may still be renamed)
Doug Zongkereef39442009-04-02 12:14:19 -0700915 pass
916
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700917 common.ComputeDifferences(diffs)
Doug Zongker761e6422009-09-25 10:45:39 -0700918
919 for diff in diffs:
920 tf, sf, d = diff.GetPatch()
Michael Runge4038aa82013-12-13 18:06:28 -0800921 path = "/".join(tf.name.split("/")[:-1])
922 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
923 path not in known_paths:
Doug Zongker761e6422009-09-25 10:45:39 -0700924 # patch is almost as big as the file; don't bother patching
Doug Zongker32b527d2014-03-04 10:03:02 -0800925 # or a patch + rename cannot take place due to the target
Michael Runge4038aa82013-12-13 18:06:28 -0800926 # directory not existing
Doug Zongker761e6422009-09-25 10:45:39 -0700927 tf.AddToZip(output_zip)
928 verbatim_targets.append((tf.name, tf.size))
Michael Runge4038aa82013-12-13 18:06:28 -0800929 if sf.name in renames:
930 del renames[sf.name]
931 AddToKnownPaths(tf.name, known_paths)
Doug Zongker761e6422009-09-25 10:45:39 -0700932 else:
Michael Runge4038aa82013-12-13 18:06:28 -0800933 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
934 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
Doug Zongker761e6422009-09-25 10:45:39 -0700935 largest_source_size = max(largest_source_size, sf.size)
Doug Zongkereef39442009-04-02 12:14:19 -0700936
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700937 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
938 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
Doug Zongker2ea21062010-04-28 16:05:21 -0700939 metadata["pre-build"] = source_fp
940 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -0700941
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700942 script.Mount("/system")
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700943 script.AssertSomeFingerprint(source_fp, target_fp)
Doug Zongkereef39442009-04-02 12:14:19 -0700944
Doug Zongker55d93282011-01-25 17:03:34 -0800945 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700946 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
947 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -0800948 target_boot = common.GetBootableImage(
949 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800950 updating_boot = (not OPTIONS.two_step and
951 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -0700952
Doug Zongker55d93282011-01-25 17:03:34 -0800953 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700954 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
955 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -0800956 target_recovery = common.GetBootableImage(
957 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -0700958 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -0700959
Doug Zongker881dd402009-09-20 14:03:55 -0700960 # Here's how we divide up the progress bar:
961 # 0.1 for verifying the start state (PatchCheck calls)
962 # 0.8 for applying patches (ApplyPatch calls)
963 # 0.1 for unpacking verbatim files, symlinking, and doing the
964 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -0700965
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700966 AppendAssertions(script, OPTIONS.target_info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700967 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -0700968
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800969 # Two-step incremental package strategy (in chronological order,
970 # which is *not* the order in which the generated script has
971 # things):
972 #
973 # if stage is not "2/3" or "3/3":
974 # do verification on current system
975 # write recovery image to boot partition
976 # set stage to "2/3"
977 # reboot to boot partition and restart recovery
978 # else if stage is "2/3":
979 # write recovery image to recovery partition
980 # set stage to "3/3"
981 # reboot to recovery partition and restart recovery
982 # else:
983 # (stage must be "3/3")
984 # perform update:
985 # patch system files, etc.
986 # force full install of new boot image
987 # set up system to update recovery partition on first boot
988 # complete script normally (allow recovery to mark itself finished and reboot)
989
990 if OPTIONS.two_step:
991 if not OPTIONS.info_dict.get("multistage_support", None):
992 assert False, "two-step packages not supported by this build"
993 fs = OPTIONS.info_dict["fstab"]["/misc"]
994 assert fs.fs_type.upper() == "EMMC", \
995 "two-step packages only supported on devices with EMMC /misc partitions"
996 bcb_dev = {"bcb_dev": fs.device}
997 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
998 script.AppendExtra("""
999if get_stage("%(bcb_dev)s", "stage") == "2/3" then
1000""" % bcb_dev)
1001 script.AppendExtra("sleep(20);\n");
1002 script.WriteRawImage("/recovery", "recovery.img")
1003 script.AppendExtra("""
1004set_stage("%(bcb_dev)s", "3/3");
1005reboot_now("%(bcb_dev)s", "recovery");
1006else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
1007""" % bcb_dev)
1008
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001009 script.Print("Verifying current system...")
1010
Doug Zongkere5ff5902012-01-17 10:55:37 -08001011 device_specific.IncrementalOTA_VerifyBegin()
1012
Doug Zongker881dd402009-09-20 14:03:55 -07001013 script.ShowProgress(0.1, 0)
Doug Zongker881dd402009-09-20 14:03:55 -07001014 so_far = 0
Doug Zongkereef39442009-04-02 12:14:19 -07001015
Michael Runge4038aa82013-12-13 18:06:28 -08001016 for tf, sf, size, patch_sha in patch_list:
1017 if tf.name != sf.name:
1018 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1019 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
Doug Zongker881dd402009-09-20 14:03:55 -07001020 so_far += sf.size
Doug Zongkereef39442009-04-02 12:14:19 -07001021
Doug Zongker5da317e2009-06-02 13:38:17 -07001022 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001023 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001024 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001025 print "boot target: %d source: %d diff: %d" % (
1026 target_boot.size, source_boot.size, len(d))
1027
Doug Zongker048e7ca2009-06-15 14:31:53 -07001028 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001029
Doug Zongker96a57e72010-09-26 14:57:41 -07001030 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001031
1032 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1033 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001034 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001035 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001036 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001037
1038 if patch_list or updating_recovery or updating_boot:
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001039 script.CacheFreeSpaceCheck(largest_source_size)
Doug Zongker5a482092010-02-17 16:09:18 -08001040
Doug Zongker05d3dea2009-06-22 11:32:31 -07001041 device_specific.IncrementalOTA_VerifyEnd()
1042
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001043 if OPTIONS.two_step:
1044 script.WriteRawImage("/boot", "recovery.img")
1045 script.AppendExtra("""
1046set_stage("%(bcb_dev)s", "2/3");
1047reboot_now("%(bcb_dev)s", "");
1048else
1049""" % bcb_dev)
1050
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001051 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001052
Doug Zongkere5ff5902012-01-17 10:55:37 -08001053 device_specific.IncrementalOTA_InstallBegin()
1054
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001055 if OPTIONS.two_step:
1056 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1057 script.WriteRawImage("/boot", "boot.img")
1058 print "writing full boot image (forced by two-step mode)"
1059
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001060 if OPTIONS.wipe_user_data:
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001061 script.Print("Erasing user data...")
Doug Zongker9ce0fb62010-09-20 18:04:41 -07001062 script.FormatPartition("/data")
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001063
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001064 script.Print("Removing unneeded files...")
Doug Zongker0f3298a2009-06-30 08:16:58 -07001065 script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
1066 ["/"+i for i in sorted(source_data)
Michael Runge4038aa82013-12-13 18:06:28 -08001067 if i not in target_data and
1068 i not in renames] +
Doug Zongker3b949f02009-08-24 10:24:32 -07001069 ["/system/recovery.img"])
Doug Zongkereef39442009-04-02 12:14:19 -07001070
Doug Zongker881dd402009-09-20 14:03:55 -07001071 script.ShowProgress(0.8, 0)
1072 total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
1073 if updating_boot:
1074 total_patch_size += target_boot.size
1075 so_far = 0
1076
1077 script.Print("Patching system files...")
Doug Zongkere92f15a2011-08-26 13:46:40 -07001078 deferred_patch_list = []
1079 for item in patch_list:
Michael Runge4038aa82013-12-13 18:06:28 -08001080 tf, sf, size, _ = item
Doug Zongkere92f15a2011-08-26 13:46:40 -07001081 if tf.name == "system/build.prop":
1082 deferred_patch_list.append(item)
1083 continue
Michael Runge4038aa82013-12-13 18:06:28 -08001084 if (sf.name != tf.name):
1085 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1086 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
Doug Zongker881dd402009-09-20 14:03:55 -07001087 so_far += tf.size
1088 script.SetProgress(so_far / total_patch_size)
1089
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001090 if not OPTIONS.two_step:
1091 if updating_boot:
1092 # Produce the boot image by applying a patch to the current
1093 # contents of the boot partition, and write it back to the
1094 # partition.
1095 script.Print("Patching boot image...")
1096 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1097 % (boot_type, boot_device,
1098 source_boot.size, source_boot.sha1,
1099 target_boot.size, target_boot.sha1),
1100 "-",
1101 target_boot.size, target_boot.sha1,
1102 source_boot.sha1, "patch/boot.img.p")
1103 so_far += target_boot.size
1104 script.SetProgress(so_far / total_patch_size)
1105 print "boot image changed; including."
1106 else:
1107 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001108
1109 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001110 # Recovery is generated as a patch using both the boot image
1111 # (which contains the same linux kernel as recovery) and the file
1112 # /system/etc/recovery-resource.dat (which contains all the images
1113 # used in the recovery UI) as sources. This lets us minimize the
1114 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001115 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001116 # For older builds where recovery-resource.dat is not present, we
1117 # use only the boot image as the source.
1118
Doug Zongkerc9253822014-02-04 12:17:58 -08001119 if not target_has_recovery_patch:
1120 def output_sink(fn, data):
1121 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
1122 Item.Get("system/" + fn, dir=False)
1123
1124 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1125 target_recovery, target_boot)
1126 script.DeleteFiles(["/system/recovery-from-boot.p",
1127 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001128 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001129 else:
1130 print "recovery image unchanged; skipping."
1131
Doug Zongker881dd402009-09-20 14:03:55 -07001132 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001133
Doug Zongker1807e702012-02-28 12:21:08 -08001134 target_symlinks = CopySystemFiles(target_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -07001135
1136 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001137 temp_script = script.MakeTemporary()
Doug Zongker283e2a12010-03-15 17:52:32 -07001138 Item.GetMetadata(target_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -07001139 Item.Get("system").SetPermissions(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001140
1141 # Note that this call will mess up the tree of Items, so make sure
1142 # we're done with it.
Doug Zongker1807e702012-02-28 12:21:08 -08001143 source_symlinks = CopySystemFiles(source_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -07001144 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1145
1146 # Delete all the symlinks in source that aren't in target. This
1147 # needs to happen before verbatim files are unpacked, in case a
1148 # symlink in the source is replaced by a real file in the target.
1149 to_delete = []
1150 for dest, link in source_symlinks:
1151 if link not in target_symlinks_d:
1152 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001153 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001154
1155 if verbatim_targets:
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001156 script.Print("Unpacking new files...")
1157 script.UnpackPackageDir("system", "/system")
1158
Doug Zongkerc9253822014-02-04 12:17:58 -08001159 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001160 script.Print("Unpacking new recovery...")
1161 script.UnpackPackageDir("recovery", "/system")
1162
Michael Runge4038aa82013-12-13 18:06:28 -08001163 if len(renames) > 0:
1164 script.Print("Renaming files...")
1165
1166 for src in renames:
1167 print "Renaming " + src + " to " + renames[src].name
1168 script.RenameFile(src, renames[src].name)
1169
Doug Zongker05d3dea2009-06-22 11:32:31 -07001170 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001171
1172 # Create all the symlinks that don't already exist, or point to
1173 # somewhere different than what we want. Delete each symlink before
1174 # creating it, since the 'symlink' command won't overwrite.
1175 to_create = []
1176 for dest, link in target_symlinks:
1177 if link in source_symlinks_d:
1178 if dest != source_symlinks_d[link]:
1179 to_create.append((dest, link))
1180 else:
1181 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001182 script.DeleteFiles([i[1] for i in to_create])
1183 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001184
1185 # Now that the symlinks are created, we can set all the
1186 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001187 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001188
Doug Zongker881dd402009-09-20 14:03:55 -07001189 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001190 device_specific.IncrementalOTA_InstallEnd()
1191
Doug Zongker1c390a22009-05-14 19:06:36 -07001192 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001193 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001194
Doug Zongkere92f15a2011-08-26 13:46:40 -07001195 # Patch the build.prop file last, so if something fails but the
1196 # device can still come up, it appears to be the old build and will
1197 # get set the OTA package again to retry.
1198 script.Print("Patching remaining system files...")
1199 for item in deferred_patch_list:
Michael Runge4038aa82013-12-13 18:06:28 -08001200 tf, sf, size, _ = item
1201 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
Nick Kralevich0eb17d92013-09-07 17:10:29 -07001202 script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001203
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001204 if OPTIONS.two_step:
1205 script.AppendExtra("""
1206set_stage("%(bcb_dev)s", "");
1207endif;
1208endif;
1209""" % bcb_dev)
1210
Doug Zongker25568482014-03-03 10:21:27 -08001211 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -07001212 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001213
1214
1215def main(argv):
1216
1217 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001218 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001219 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001220 elif o in ("-k", "--package_key"):
1221 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001222 elif o in ("-i", "--incremental_from"):
1223 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001224 elif o in ("-w", "--wipe_user_data"):
1225 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001226 elif o in ("-n", "--no_prereq"):
1227 OPTIONS.omit_prereq = True
Doug Zongker1c390a22009-05-14 19:06:36 -07001228 elif o in ("-e", "--extra_script"):
1229 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001230 elif o in ("-a", "--aslr_mode"):
1231 if a in ("on", "On", "true", "True", "yes", "Yes"):
1232 OPTIONS.aslr_mode = True
1233 else:
1234 OPTIONS.aslr_mode = False
Doug Zongker761e6422009-09-25 10:45:39 -07001235 elif o in ("--worker_threads"):
1236 OPTIONS.worker_threads = int(a)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001237 elif o in ("-2", "--two_step"):
1238 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001239 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001240 OPTIONS.no_signing = True
Doug Zongker26e66192014-02-20 13:22:07 -08001241 elif o == "--block":
1242 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001243 elif o in ("-b", "--binary"):
1244 OPTIONS.updater_binary = a
Doug Zongkereef39442009-04-02 12:14:19 -07001245 else:
1246 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001247 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001248
1249 args = common.ParseOptions(argv, __doc__,
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001250 extra_opts="b:k:i:d:wne:a:2",
Doug Zongkereef39442009-04-02 12:14:19 -07001251 extra_long_opts=["board_config=",
1252 "package_key=",
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001253 "incremental_from=",
Doug Zongker962069c2009-04-23 11:41:58 -07001254 "wipe_user_data",
Doug Zongker1c390a22009-05-14 19:06:36 -07001255 "no_prereq",
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001256 "extra_script=",
Hristo Bojinov96be7202010-08-02 10:26:17 -07001257 "worker_threads=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001258 "aslr_mode=",
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001259 "two_step",
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001260 "no_signing",
Doug Zongker26e66192014-02-20 13:22:07 -08001261 "block",
Doug Zongker25568482014-03-03 10:21:27 -08001262 "binary=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001263 ],
Doug Zongkereef39442009-04-02 12:14:19 -07001264 extra_option_handler=option_handler)
1265
1266 if len(args) != 2:
1267 common.Usage(__doc__)
1268 sys.exit(1)
1269
Doug Zongker1c390a22009-05-14 19:06:36 -07001270 if OPTIONS.extra_script is not None:
1271 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1272
Doug Zongkereef39442009-04-02 12:14:19 -07001273 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001274 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001275
Doug Zongkereef39442009-04-02 12:14:19 -07001276 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001277 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001278
1279 # If this image was originally labelled with SELinux contexts, make sure we
1280 # also apply the labels in our new image. During building, the "file_contexts"
1281 # is in the out/ directory tree, but for repacking from target-files.zip it's
1282 # in the root directory of the ramdisk.
1283 if "selinux_fc" in OPTIONS.info_dict:
1284 OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK",
1285 "file_contexts")
1286
Doug Zongker37974732010-09-16 17:44:38 -07001287 if OPTIONS.verbose:
1288 print "--- target info ---"
1289 common.DumpInfoDict(OPTIONS.info_dict)
1290
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001291 # If the caller explicitly specified the device-specific extensions
1292 # path via -s/--device_specific, use that. Otherwise, use
1293 # META/releasetools.py if it is present in the target target_files.
1294 # Otherwise, take the path of the file from 'tool_extensions' in the
1295 # info dict and look for that in the local filesystem, relative to
1296 # the current directory.
1297
Doug Zongker37974732010-09-16 17:44:38 -07001298 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001299 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1300 if os.path.exists(from_input):
1301 print "(using device-specific extensions from target_files)"
1302 OPTIONS.device_specific = from_input
1303 else:
1304 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1305
Doug Zongker37974732010-09-16 17:44:38 -07001306 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001307 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001308
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001309 if OPTIONS.no_signing:
1310 output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
1311 else:
1312 temp_zip_file = tempfile.NamedTemporaryFile()
1313 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1314 compression=zipfile.ZIP_DEFLATED)
Doug Zongkereef39442009-04-02 12:14:19 -07001315
1316 if OPTIONS.incremental_source is None:
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001317 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001318 if OPTIONS.package_key is None:
1319 OPTIONS.package_key = OPTIONS.info_dict.get(
1320 "default_system_dev_certificate",
1321 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -07001322 else:
1323 print "unzipping source target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001324 OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
Doug Zongker37974732010-09-16 17:44:38 -07001325 OPTIONS.target_info_dict = OPTIONS.info_dict
1326 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
Doug Zongker5fad2032014-02-24 08:13:45 -08001327 if "selinux_fc" in OPTIONS.source_info_dict:
1328 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(OPTIONS.source_tmp, "BOOT", "RAMDISK",
1329 "file_contexts")
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001330 if OPTIONS.package_key is None:
Doug Zongker91b4f8a2011-09-23 12:48:33 -07001331 OPTIONS.package_key = OPTIONS.source_info_dict.get(
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001332 "default_system_dev_certificate",
1333 "build/target/product/security/testkey")
Doug Zongker37974732010-09-16 17:44:38 -07001334 if OPTIONS.verbose:
1335 print "--- source info ---"
1336 common.DumpInfoDict(OPTIONS.source_info_dict)
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001337 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001338
1339 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001340
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001341 if not OPTIONS.no_signing:
1342 SignOutput(temp_zip_file.name, args[1])
1343 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001344
1345 common.Cleanup()
1346
1347 print "done."
1348
1349
1350if __name__ == '__main__':
1351 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001352 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001353 main(sys.argv[1:])
1354 except common.ExternalError, e:
1355 print
1356 print " ERROR: %s" % (e,)
1357 print
1358 sys.exit(1)