blob: cbfc087b40e56040641725e66ba31986f852c1af [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
Michael Runge6e836112014-04-15 17:40:21 -070040 -o (--oem_settings) <file>
41 Use the file to specify the expected OEM-specific properties
42 on the OEM partition of the intended device.
43
Doug Zongkerdbfaae52009-04-21 17:12:54 -070044 -w (--wipe_user_data)
45 Generate an OTA package that will wipe the user data partition
46 when installed.
47
Doug Zongker962069c2009-04-23 11:41:58 -070048 -n (--no_prereq)
49 Omit the timestamp prereq check normally included at the top of
50 the build scripts (used for developer OTA packages which
51 legitimately need to go back and forth).
52
Doug Zongker1c390a22009-05-14 19:06:36 -070053 -e (--extra_script) <file>
54 Insert the contents of file at the end of the update script.
55
Hristo Bojinovdafb0422010-08-26 14:35:16 -070056 -a (--aslr_mode) <on|off>
57 Specify whether to turn on ASLR for the package (on by default).
Stephen Smalley56882bf2012-02-09 13:36:21 -050058
Doug Zongker9b23f2c2013-11-25 14:44:12 -080059 -2 (--two_step)
60 Generate a 'two-step' OTA package, where recovery is updated
61 first, so that any changes made to the system partition are done
62 using the new recovery (new kernel, etc.).
63
Doug Zongker26e66192014-02-20 13:22:07 -080064 --block
65 Generate a block-based OTA if possible. Will fall back to a
66 file-based OTA if the target_files is older and doesn't support
67 block-based OTAs.
68
Doug Zongker25568482014-03-03 10:21:27 -080069 -b (--binary) <file>
70 Use the given binary as the update-binary in the output package,
71 instead of the binary in the build's target_files. Use for
72 development only.
73
Doug Zongkereef39442009-04-02 12:14:19 -070074"""
75
76import sys
77
Doug Zongkercf6d5a92014-02-18 10:57:07 -080078if sys.hexversion < 0x02070000:
79 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -070080 sys.exit(1)
81
82import copy
Doug Zongkerc18736b2009-09-30 09:20:32 -070083import errno
Doug Zongkereef39442009-04-02 12:14:19 -070084import os
85import re
Doug Zongkereef39442009-04-02 12:14:19 -070086import subprocess
87import tempfile
88import time
89import zipfile
90
davidcad0bb92011-03-15 14:21:38 +000091try:
92 from hashlib import sha1 as sha1
93except ImportError:
94 from sha import sha as sha1
95
Doug Zongkereef39442009-04-02 12:14:19 -070096import common
Doug Zongker01ce19c2014-02-04 13:48:15 -080097import img_from_target_files
Doug Zongkerc494d7c2009-06-18 08:43:44 -070098import edify_generator
Geremy Condra36bd3652014-02-06 19:45:10 -080099import build_image
Doug Zongkereef39442009-04-02 12:14:19 -0700100
101OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700102OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700103OPTIONS.incremental_source = None
104OPTIONS.require_verbatim = set()
105OPTIONS.prohibit_verbatim = set(("system/build.prop",))
106OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700107OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700108OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700109OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700110OPTIONS.aslr_mode = True
Doug Zongker761e6422009-09-25 10:45:39 -0700111OPTIONS.worker_threads = 3
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800112OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900113OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800114OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800115OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700116OPTIONS.oem_source = None
Doug Zongkereef39442009-04-02 12:14:19 -0700117
118def MostPopularKey(d, default):
119 """Given a dict, return the key corresponding to the largest
120 value. Returns 'default' if the dict is empty."""
121 x = [(v, k) for (k, v) in d.iteritems()]
122 if not x: return default
123 x.sort()
124 return x[-1][1]
125
126
127def IsSymlink(info):
128 """Return true if the zipfile.ZipInfo object passed in represents a
129 symlink."""
130 return (info.external_attr >> 16) == 0120777
131
Hristo Bojinov96be7202010-08-02 10:26:17 -0700132def IsRegular(info):
133 """Return true if the zipfile.ZipInfo object passed in represents a
134 symlink."""
135 return (info.external_attr >> 28) == 010
Doug Zongkereef39442009-04-02 12:14:19 -0700136
Michael Runge4038aa82013-12-13 18:06:28 -0800137def ClosestFileMatch(src, tgtfiles, existing):
138 """Returns the closest file match between a source file and list
139 of potential matches. The exact filename match is preferred,
140 then the sha1 is searched for, and finally a file with the same
141 basename is evaluated. Rename support in the updater-binary is
142 required for the latter checks to be used."""
143
144 result = tgtfiles.get("path:" + src.name)
145 if result is not None:
146 return result
147
148 if not OPTIONS.target_info_dict.get("update_rename_support", False):
149 return None
150
151 if src.size < 1000:
152 return None
153
154 result = tgtfiles.get("sha1:" + src.sha1)
155 if result is not None and existing.get(result.name) is None:
156 return result
157 result = tgtfiles.get("file:" + src.name.split("/")[-1])
158 if result is not None and existing.get(result.name) is None:
159 return result
160 return None
161
Doug Zongkereef39442009-04-02 12:14:19 -0700162class Item:
163 """Items represent the metadata (user, group, mode) of files and
164 directories in the system image."""
165 ITEMS = {}
166 def __init__(self, name, dir=False):
167 self.name = name
168 self.uid = None
169 self.gid = None
170 self.mode = None
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700171 self.selabel = None
172 self.capabilities = None
Doug Zongkereef39442009-04-02 12:14:19 -0700173 self.dir = dir
174
175 if name:
176 self.parent = Item.Get(os.path.dirname(name), dir=True)
177 self.parent.children.append(self)
178 else:
179 self.parent = None
180 if dir:
181 self.children = []
182
183 def Dump(self, indent=0):
184 if self.uid is not None:
185 print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode)
186 else:
187 print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode)
188 if self.dir:
189 print "%s%s" % (" "*indent, self.descendants)
190 print "%s%s" % (" "*indent, self.best_subtree)
191 for i in self.children:
192 i.Dump(indent=indent+1)
193
194 @classmethod
195 def Get(cls, name, dir=False):
196 if name not in cls.ITEMS:
197 cls.ITEMS[name] = Item(name, dir=dir)
198 return cls.ITEMS[name]
199
200 @classmethod
Doug Zongker283e2a12010-03-15 17:52:32 -0700201 def GetMetadata(cls, input_zip):
202
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700203 # The target_files contains a record of what the uid,
204 # gid, and mode are supposed to be.
205 output = input_zip.read("META/filesystem_config.txt")
Doug Zongkereef39442009-04-02 12:14:19 -0700206
207 for line in output.split("\n"):
208 if not line: continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700209 columns = line.split()
210 name, uid, gid, mode = columns[:4]
211 selabel = None
212 capabilities = None
213
214 # After the first 4 columns, there are a series of key=value
215 # pairs. Extract out the fields we care about.
216 for element in columns[4:]:
217 key, value = element.split("=")
218 if key == "selabel":
219 selabel = value
220 if key == "capabilities":
221 capabilities = value
222
Doug Zongker283e2a12010-03-15 17:52:32 -0700223 i = cls.ITEMS.get(name, None)
224 if i is not None:
225 i.uid = int(uid)
226 i.gid = int(gid)
227 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700228 i.selabel = selabel
229 i.capabilities = capabilities
Doug Zongker283e2a12010-03-15 17:52:32 -0700230 if i.dir:
231 i.children.sort(key=lambda i: i.name)
232
233 # set metadata for the files generated by this script.
234 i = cls.ITEMS.get("system/recovery-from-boot.p", None)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700235 if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0644, None, None
Doug Zongker283e2a12010-03-15 17:52:32 -0700236 i = cls.ITEMS.get("system/etc/install-recovery.sh", None)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700237 if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700238
239 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700240 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
241 all children and determine the best strategy for using set_perm_recursive and
Doug Zongkereef39442009-04-02 12:14:19 -0700242 set_perm to correctly chown/chmod all the files to their desired
243 values. Recursively calls itself for all descendants.
244
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700245 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count} counting up
Doug Zongkereef39442009-04-02 12:14:19 -0700246 all descendants of this node. (dmode or fmode may be None.) Also
247 sets the best_subtree of each directory Item to the (uid, gid,
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700248 dmode, fmode, selabel, capabilities) tuple that will match the most
249 descendants of that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700250 """
251
252 assert self.dir
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700253 d = self.descendants = {(self.uid, self.gid, self.mode, None, self.selabel, self.capabilities): 1}
Doug Zongkereef39442009-04-02 12:14:19 -0700254 for i in self.children:
255 if i.dir:
256 for k, v in i.CountChildMetadata().iteritems():
257 d[k] = d.get(k, 0) + v
258 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700259 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700260 d[k] = d.get(k, 0) + 1
261
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700262 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
263 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700264
265 # First, find the (uid, gid) pair that matches the most
266 # descendants.
267 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700268 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700269 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
270 ug = MostPopularKey(ug, (0, 0))
271
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700272 # Now find the dmode, fmode, selabel, and capabilities that match
273 # the most descendants with that (uid, gid), and choose those.
Doug Zongkereef39442009-04-02 12:14:19 -0700274 best_dmode = (0, 0755)
275 best_fmode = (0, 0644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700276 best_selabel = (0, None)
277 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700278 for k, count in d.iteritems():
279 if k[:2] != ug: continue
280 if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2])
281 if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3])
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700282 if k[4] is not None and count >= best_selabel[0]: best_selabel = (count, k[4])
283 if k[5] is not None and count >= best_capabilities[0]: best_capabilities = (count, k[5])
284 self.best_subtree = ug + (best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700285
286 return d
287
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700288 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700289 """Append set_perm/set_perm_recursive commands to 'script' to
290 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700291 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700292
293 self.CountChildMetadata()
294
295 def recurse(item, current):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700296 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple that the current
Doug Zongkereef39442009-04-02 12:14:19 -0700297 # item (and all its children) have already been set to. We only
298 # need to issue set_perm/set_perm_recursive commands if we're
299 # supposed to be something different.
300 if item.dir:
301 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700302 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700303 current = item.best_subtree
304
305 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700306 item.mode != current[2] or item.selabel != current[4] or \
307 item.capabilities != current[5]:
308 script.SetPermissions("/"+item.name, item.uid, item.gid,
309 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700310
311 for i in item.children:
312 recurse(i, current)
313 else:
314 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700315 item.mode != current[3] or item.selabel != current[4] or \
316 item.capabilities != current[5]:
317 script.SetPermissions("/"+item.name, item.uid, item.gid,
318 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700319
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700320 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700321
322
323def CopySystemFiles(input_zip, output_zip=None,
324 substitute=None):
325 """Copies files underneath system/ in the input zip to the output
326 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800327 list of symlinks. output_zip may be None, in which case the copy is
328 skipped (but the other side effects still happen). substitute is an
329 optional dict of {output filename: contents} to be output instead of
330 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700331 """
332
333 symlinks = []
334
335 for info in input_zip.infolist():
336 if info.filename.startswith("SYSTEM/"):
337 basefilename = info.filename[7:]
338 if IsSymlink(info):
339 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700340 "/system/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700341 else:
342 info2 = copy.copy(info)
343 fn = info2.filename = "system/" + basefilename
344 if substitute and fn in substitute and substitute[fn] is None:
345 continue
346 if output_zip is not None:
347 if substitute and fn in substitute:
348 data = substitute[fn]
349 else:
350 data = input_zip.read(info.filename)
351 output_zip.writestr(info2, data)
352 if fn.endswith("/"):
353 Item.Get(fn[:-1], dir=True)
354 else:
355 Item.Get(fn, dir=False)
356
357 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800358 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700359
360
Doug Zongkereef39442009-04-02 12:14:19 -0700361def SignOutput(temp_zip_name, output_zip_name):
362 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
363 pw = key_passwords[OPTIONS.package_key]
364
Doug Zongker951495f2009-08-14 12:44:19 -0700365 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
366 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700367
368
Michael Rungec6e3afd2014-05-05 11:55:47 -0700369def AppendAssertions(script, info_dict, oem_dict = None):
Michael Runge6e836112014-04-15 17:40:21 -0700370 oem_props = info_dict.get("oem_fingerprint_properties")
371 if oem_props is None:
372 device = GetBuildProp("ro.product.device", info_dict)
373 script.AssertDevice(device)
374 else:
375 if oem_dict is None:
376 raise common.ExternalError("No OEM file provided to answer expected assertions")
377 for prop in oem_props.split():
378 if oem_dict.get(prop) is None:
379 raise common.ExternalError("The OEM file is missing the property %s" % prop)
380 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700381
Doug Zongkereef39442009-04-02 12:14:19 -0700382
Doug Zongkerc9253822014-02-04 12:17:58 -0800383def HasRecoveryPatch(target_files_zip):
384 try:
385 target_files_zip.getinfo("SYSTEM/recovery-from-boot.p")
386 return True
387 except KeyError:
388 return False
Doug Zongker73ef8252009-07-23 15:12:53 -0700389
Michael Runge6e836112014-04-15 17:40:21 -0700390def GetOemProperty(name, oem_props, oem_dict, info_dict):
391 if oem_props is not None and name in oem_props:
392 return oem_dict[name]
393 return GetBuildProp(name, info_dict)
394
395
396def CalculateFingerprint(oem_props, oem_dict, info_dict):
397 if oem_props is None:
398 return GetBuildProp("ro.build.fingerprint", info_dict)
399 return "%s/%s/%s:%s" % (
400 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
401 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
402 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
403 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700404
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700405def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700406 # TODO: how to determine this? We don't know what version it will
407 # be installed on top of. For now, we expect the API just won't
408 # change very often.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700409 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700410
Michael Runge6e836112014-04-15 17:40:21 -0700411 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
412 oem_dict = None
413 if oem_props is not None:
414 if OPTIONS.oem_source is None:
415 raise common.ExternalError("OEM source required for this build")
416 script.Mount("/oem")
417 oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
418
419 metadata = {"post-build": CalculateFingerprint(
420 oem_props, oem_dict, OPTIONS.info_dict),
421 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700422 OPTIONS.info_dict),
423 "post-timestamp": GetBuildProp("ro.build.date.utc",
424 OPTIONS.info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700425 }
426
Doug Zongker05d3dea2009-06-22 11:32:31 -0700427 device_specific = common.DeviceSpecificParams(
428 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700429 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700430 output_zip=output_zip,
431 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700432 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700433 metadata=metadata,
434 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700435
Doug Zongkerc9253822014-02-04 12:17:58 -0800436 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800437 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800438
Doug Zongker962069c2009-04-23 11:41:58 -0700439 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700440 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700441 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
442 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700443
Michael Runge6e836112014-04-15 17:40:21 -0700444 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700445 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800446
447 # Two-step package strategy (in chronological order, which is *not*
448 # the order in which the generated script has things):
449 #
450 # if stage is not "2/3" or "3/3":
451 # write recovery image to boot partition
452 # set stage to "2/3"
453 # reboot to boot partition and restart recovery
454 # else if stage is "2/3":
455 # write recovery image to recovery partition
456 # set stage to "3/3"
457 # reboot to recovery partition and restart recovery
458 # else:
459 # (stage must be "3/3")
460 # set stage to ""
461 # do normal full package installation:
462 # wipe and install system, boot image, etc.
463 # set up system to update recovery partition on first boot
464 # complete script normally (allow recovery to mark itself finished and reboot)
465
466 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
467 OPTIONS.input_tmp, "RECOVERY")
468 if OPTIONS.two_step:
469 if not OPTIONS.info_dict.get("multistage_support", None):
470 assert False, "two-step packages not supported by this build"
471 fs = OPTIONS.info_dict["fstab"]["/misc"]
472 assert fs.fs_type.upper() == "EMMC", \
473 "two-step packages only supported on devices with EMMC /misc partitions"
474 bcb_dev = {"bcb_dev": fs.device}
475 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
476 script.AppendExtra("""
477if get_stage("%(bcb_dev)s", "stage") == "2/3" then
478""" % bcb_dev)
479 script.WriteRawImage("/recovery", "recovery.img")
480 script.AppendExtra("""
481set_stage("%(bcb_dev)s", "3/3");
482reboot_now("%(bcb_dev)s", "recovery");
483else if get_stage("%(bcb_dev)s", "stage") == "3/3" then
484""" % bcb_dev)
485
Doug Zongkere5ff5902012-01-17 10:55:37 -0800486 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700487
Doug Zongker01ce19c2014-02-04 13:48:15 -0800488 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700489
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700490 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800491 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700492
Kenny Rootf32dc712012-04-08 10:42:34 -0700493 if "selinux_fc" in OPTIONS.info_dict:
494 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500495
Doug Zongker01ce19c2014-02-04 13:48:15 -0800496 script.ShowProgress(system_progress, 30)
Doug Zongker26e66192014-02-20 13:22:07 -0800497 if block_based:
Doug Zongker5fad2032014-02-24 08:13:45 -0800498 mapdata, data = img_from_target_files.BuildSystem(
499 OPTIONS.input_tmp, OPTIONS.info_dict,
500 sparse=False, map_file=True)
501
502 common.ZipWriteStr(output_zip, "system.map", mapdata)
503 common.ZipWriteStr(output_zip, "system.muimg", data)
504 script.WipeBlockDevice("/system")
505 script.WriteRawImage("/system", "system.muimg", mapfn="system.map")
Doug Zongker01ce19c2014-02-04 13:48:15 -0800506 else:
507 script.FormatPartition("/system")
508 script.Mount("/system")
509 if not has_recovery_patch:
510 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800511 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700512
Doug Zongker01ce19c2014-02-04 13:48:15 -0800513 symlinks = CopySystemFiles(input_zip, output_zip)
514 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700515
Doug Zongker55d93282011-01-25 17:03:34 -0800516 boot_img = common.GetBootableImage("boot.img", "boot.img",
517 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800518
519 if not has_recovery_patch:
520 def output_sink(fn, data):
521 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
522 Item.Get("system/" + fn, dir=False)
523
524 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
525 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700526
Doug Zongker01ce19c2014-02-04 13:48:15 -0800527 Item.GetMetadata(input_zip)
528 Item.Get("system").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700529
Doug Zongker37974732010-09-16 17:44:38 -0700530 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700531 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700532
Doug Zongker01ce19c2014-02-04 13:48:15 -0800533 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700534 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700535
Doug Zongker01ce19c2014-02-04 13:48:15 -0800536 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700537 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700538
Doug Zongker1c390a22009-05-14 19:06:36 -0700539 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700540 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700541
Doug Zongker14833602010-02-02 13:12:04 -0800542 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800543
Doug Zongker922206e2014-03-04 13:16:24 -0800544 if OPTIONS.wipe_user_data:
545 script.ShowProgress(0.1, 10)
546 script.FormatPartition("/data")
547
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800548 if OPTIONS.two_step:
549 script.AppendExtra("""
550set_stage("%(bcb_dev)s", "");
551""" % bcb_dev)
552 script.AppendExtra("else\n")
553 script.WriteRawImage("/boot", "recovery.img")
554 script.AppendExtra("""
555set_stage("%(bcb_dev)s", "2/3");
556reboot_now("%(bcb_dev)s", "");
557endif;
558endif;
559""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800560 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700561 WriteMetadata(metadata, output_zip)
562
Stephen Smalley56882bf2012-02-09 13:36:21 -0500563def WritePolicyConfig(file_context, output_zip):
564 f = open(file_context, 'r');
565 basename = os.path.basename(file_context)
566 common.ZipWriteStr(output_zip, basename, f.read())
567
Doug Zongker2ea21062010-04-28 16:05:21 -0700568
569def WriteMetadata(metadata, output_zip):
570 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
571 "".join(["%s=%s\n" % kv
572 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700573
Doug Zongkereef39442009-04-02 12:14:19 -0700574def LoadSystemFiles(z):
575 """Load all the files from SYSTEM/... in a given target-files
576 ZipFile, and return a dict of {filename: File object}."""
577 out = {}
578 for info in z.infolist():
579 if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
Hristo Bojinov96be7202010-08-02 10:26:17 -0700580 basefilename = info.filename[7:]
581 fn = "system/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700582 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700583 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800584 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700585
586
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700587def GetBuildProp(prop, info_dict):
588 """Return the fingerprint of the build of a given target-files info_dict."""
589 try:
590 return info_dict.get("build.prop", {})[prop]
591 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700592 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700593
Michael Runge4038aa82013-12-13 18:06:28 -0800594def AddToKnownPaths(filename, known_paths):
595 if filename[-1] == "/":
596 return
597 dirs = filename.split("/")[:-1]
598 while len(dirs) > 0:
599 path = "/".join(dirs)
600 if path in known_paths:
601 break;
602 known_paths.add(path)
603 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700604
Geremy Condra36bd3652014-02-06 19:45:10 -0800605def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
606 source_version = OPTIONS.source_info_dict["recovery_api_version"]
607 target_version = OPTIONS.target_info_dict["recovery_api_version"]
608
609 if source_version == 0:
610 print ("WARNING: generating edify script for a source that "
611 "can't install it.")
612 script = edify_generator.EdifyGenerator(source_version,
613 OPTIONS.target_info_dict)
614
615 metadata = {"pre-device": GetBuildProp("ro.product.device",
616 OPTIONS.source_info_dict),
617 "post-timestamp": GetBuildProp("ro.build.date.utc",
618 OPTIONS.target_info_dict),
619 }
620
621 device_specific = common.DeviceSpecificParams(
622 source_zip=source_zip,
623 source_version=source_version,
624 target_zip=target_zip,
625 target_version=target_version,
626 output_zip=output_zip,
627 script=script,
628 metadata=metadata,
629 info_dict=OPTIONS.info_dict)
630
631 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
632 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
633 metadata["pre-build"] = source_fp
634 metadata["post-build"] = target_fp
635
636 source_boot = common.GetBootableImage(
637 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
638 OPTIONS.source_info_dict)
639 target_boot = common.GetBootableImage(
640 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
641 updating_boot = (not OPTIONS.two_step and
642 (source_boot.data != target_boot.data))
643
644 source_recovery = common.GetBootableImage(
645 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
646 OPTIONS.source_info_dict)
647 target_recovery = common.GetBootableImage(
648 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
649 updating_recovery = (source_recovery.data != target_recovery.data)
650
651 with tempfile.NamedTemporaryFile() as src_file:
652 with tempfile.NamedTemporaryFile() as tgt_file:
653 print "building source system image..."
654 src_file = tempfile.NamedTemporaryFile()
Doug Zongker5fad2032014-02-24 08:13:45 -0800655 src_mapdata, src_data = img_from_target_files.BuildSystem(
656 OPTIONS.source_tmp, OPTIONS.source_info_dict,
657 sparse=False, map_file=True)
658
Geremy Condra36bd3652014-02-06 19:45:10 -0800659 src_sys_sha1 = sha1(src_data).hexdigest()
660 print "source system sha1:", src_sys_sha1
661 src_file.write(src_data)
Geremy Condra36bd3652014-02-06 19:45:10 -0800662
663 print "building target system image..."
664 tgt_file = tempfile.NamedTemporaryFile()
Doug Zongker5fad2032014-02-24 08:13:45 -0800665 tgt_mapdata, tgt_data = img_from_target_files.BuildSystem(
666 OPTIONS.target_tmp, OPTIONS.target_info_dict,
667 sparse=False, map_file=True)
Geremy Condra36bd3652014-02-06 19:45:10 -0800668 tgt_sys_sha1 = sha1(tgt_data).hexdigest()
669 print "target system sha1:", tgt_sys_sha1
670 tgt_sys_len = len(tgt_data)
671 tgt_file.write(tgt_data)
Geremy Condra36bd3652014-02-06 19:45:10 -0800672
673 system_type, system_device = common.GetTypeAndDevice("/system", OPTIONS.info_dict)
674 system_patch = common.MakeSystemPatch(src_file, tgt_file)
Doug Zongker32b527d2014-03-04 10:03:02 -0800675
676 TestBlockPatch(src_data, src_mapdata, system_patch.data, tgt_mapdata, tgt_sys_sha1)
677 src_data = None
678 tgt_data = None
679
Geremy Condra36bd3652014-02-06 19:45:10 -0800680 system_patch.AddToZip(output_zip, compression=zipfile.ZIP_STORED)
Doug Zongker5fad2032014-02-24 08:13:45 -0800681 src_mapfilename = system_patch.name + ".src.map"
682 common.ZipWriteStr(output_zip, src_mapfilename, src_mapdata)
683 tgt_mapfilename = system_patch.name + ".tgt.map"
684 common.ZipWriteStr(output_zip, tgt_mapfilename, tgt_mapdata)
Geremy Condra36bd3652014-02-06 19:45:10 -0800685
Michael Rungec6e3afd2014-05-05 11:55:47 -0700686 oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
687 oem_dict = None
688 if oem_props is not None:
689 if OPTIONS.oem_source is None:
690 raise common.ExternalError("OEM source required for this build")
691 script.Mount("/oem")
692 oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
693
694 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800695 device_specific.IncrementalOTA_Assertions()
696
697 # Two-step incremental package strategy (in chronological order,
698 # which is *not* the order in which the generated script has
699 # things):
700 #
701 # if stage is not "2/3" or "3/3":
702 # do verification on current system
703 # write recovery image to boot partition
704 # set stage to "2/3"
705 # reboot to boot partition and restart recovery
706 # else if stage is "2/3":
707 # write recovery image to recovery partition
708 # set stage to "3/3"
709 # reboot to recovery partition and restart recovery
710 # else:
711 # (stage must be "3/3")
712 # perform update:
713 # patch system files, etc.
714 # force full install of new boot image
715 # set up system to update recovery partition on first boot
716 # complete script normally (allow recovery to mark itself finished and reboot)
717
718 if OPTIONS.two_step:
719 if not OPTIONS.info_dict.get("multistage_support", None):
720 assert False, "two-step packages not supported by this build"
721 fs = OPTIONS.info_dict["fstab"]["/misc"]
722 assert fs.fs_type.upper() == "EMMC", \
723 "two-step packages only supported on devices with EMMC /misc partitions"
724 bcb_dev = {"bcb_dev": fs.device}
725 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
726 script.AppendExtra("""
727if get_stage("%(bcb_dev)s", "stage") == "2/3" then
728""" % bcb_dev)
729 script.AppendExtra("sleep(20);\n");
730 script.WriteRawImage("/recovery", "recovery.img")
731 script.AppendExtra("""
732set_stage("%(bcb_dev)s", "3/3");
733reboot_now("%(bcb_dev)s", "recovery");
734else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
735""" % bcb_dev)
736
737 script.Print("Verifying current system...")
738
739 device_specific.IncrementalOTA_VerifyBegin()
740
Michael Rungec6e3afd2014-05-05 11:55:47 -0700741 if oem_props is None:
742 script.AssertSomeFingerprint(source_fp, target_fp)
743 else:
744 script.AssertSomeThumbprint(
745 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
746 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800747
748 if updating_boot:
Geremy Condra36bd3652014-02-06 19:45:10 -0800749 d = common.Difference(target_boot, source_boot)
750 _, _, d = d.ComputePatch()
751 print "boot target: %d source: %d diff: %d" % (
752 target_boot.size, source_boot.size, len(d))
753
754 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
755
756 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
757
758 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
759 (boot_type, boot_device,
760 source_boot.size, source_boot.sha1,
761 target_boot.size, target_boot.sha1))
762
763 device_specific.IncrementalOTA_VerifyEnd()
764
765 if OPTIONS.two_step:
766 script.WriteRawImage("/boot", "recovery.img")
767 script.AppendExtra("""
768set_stage("%(bcb_dev)s", "2/3");
769reboot_now("%(bcb_dev)s", "");
770else
771""" % bcb_dev)
772
773 script.Comment("---- start making changes here ----")
774
775 device_specific.IncrementalOTA_InstallBegin()
776
Geremy Condra36bd3652014-02-06 19:45:10 -0800777 script.Print("Patching system image...")
778 script.Syspatch(system_device,
Doug Zongker5fad2032014-02-24 08:13:45 -0800779 tgt_mapfilename, tgt_sys_sha1,
780 src_mapfilename, src_sys_sha1,
Geremy Condra36bd3652014-02-06 19:45:10 -0800781 system_patch.name)
782
783 if OPTIONS.two_step:
784 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
785 script.WriteRawImage("/boot", "boot.img")
786 print "writing full boot image (forced by two-step mode)"
787
788 if not OPTIONS.two_step:
789 if updating_boot:
790 # Produce the boot image by applying a patch to the current
791 # contents of the boot partition, and write it back to the
792 # partition.
793 script.Print("Patching boot image...")
794 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
795 % (boot_type, boot_device,
796 source_boot.size, source_boot.sha1,
797 target_boot.size, target_boot.sha1),
798 "-",
799 target_boot.size, target_boot.sha1,
800 source_boot.sha1, "patch/boot.img.p")
801 print "boot image changed; including."
802 else:
803 print "boot image unchanged; skipping."
804
805 # Do device-specific installation (eg, write radio image).
806 device_specific.IncrementalOTA_InstallEnd()
807
808 if OPTIONS.extra_script is not None:
809 script.AppendExtra(OPTIONS.extra_script)
810
Doug Zongker922206e2014-03-04 13:16:24 -0800811 if OPTIONS.wipe_user_data:
812 script.Print("Erasing user data...")
813 script.FormatPartition("/data")
814
Geremy Condra36bd3652014-02-06 19:45:10 -0800815 if OPTIONS.two_step:
816 script.AppendExtra("""
817set_stage("%(bcb_dev)s", "");
818endif;
819endif;
820""" % bcb_dev)
821
822 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800823 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800824 WriteMetadata(metadata, output_zip)
825
Doug Zongker32b527d2014-03-04 10:03:02 -0800826def ParseMap(map_str):
827 x = map_str.split()
828 assert int(x[0]) == 4096
829 assert int(x[1]) == len(x)-2
830 return int(x[0]), [int(i) for i in x[2:]]
831
832def TestBlockPatch(src_muimg, src_map, patch_data, tgt_map, tgt_sha1):
833 src_blksize, src_regions = ParseMap(src_map)
834 tgt_blksize, tgt_regions = ParseMap(tgt_map)
835
836 with tempfile.NamedTemporaryFile() as src_file,\
837 tempfile.NamedTemporaryFile() as patch_file,\
838 tempfile.NamedTemporaryFile() as tgt_file,\
839 tempfile.NamedTemporaryFile() as src_map_file,\
840 tempfile.NamedTemporaryFile() as tgt_map_file:
841
842 src_total = sum(src_regions) * src_blksize
843 src_file.truncate(src_total)
844 p = 0
845 for i in range(0, len(src_regions), 2):
846 c, dc = src_regions[i:i+2]
847 src_file.write(src_muimg[p:(p+c*src_blksize)])
848 p += c*src_blksize
849 src_file.seek(dc*src_blksize, 1)
850 assert src_file.tell() == src_total
851
852 patch_file.write(patch_data)
853
854 tgt_total = sum(tgt_regions) * tgt_blksize
855 tgt_file.truncate(tgt_total)
856
857 src_map_file.write(src_map)
858 tgt_map_file.write(tgt_map)
859
860 src_file.flush()
861 src_map_file.flush()
862 patch_file.flush()
863 tgt_file.flush()
864 tgt_map_file.flush()
865
866 p = common.Run(["syspatch_host", src_file.name, src_map_file.name,
867 patch_file.name, tgt_file.name, tgt_map_file.name],
868 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
869 stdoutdata, _ = p.communicate()
870 if p.returncode != 0:
871 print stdoutdata
872 raise ValueError("failed to reconstruct target system image from patch")
873
874 h = sha1()
875 for i in range(0, len(tgt_regions), 2):
876 c, dc = tgt_regions[i:i+2]
877 h.update(tgt_file.read(c*tgt_blksize))
878 tgt_file.seek(dc*tgt_blksize, 1)
879
880 if h.hexdigest() != tgt_sha1:
881 raise ValueError("patch reconstructed incorrect target system image")
882
883 print "test of system image patch succeeded"
884
885
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700886def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -0800887 target_has_recovery_patch = HasRecoveryPatch(target_zip)
888 source_has_recovery_patch = HasRecoveryPatch(source_zip)
889
Doug Zongker26e66192014-02-20 13:22:07 -0800890 if (OPTIONS.block_based and
891 target_has_recovery_patch and
892 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -0800893 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
894
Doug Zongker37974732010-09-16 17:44:38 -0700895 source_version = OPTIONS.source_info_dict["recovery_api_version"]
896 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700897
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700898 if source_version == 0:
899 print ("WARNING: generating edify script for a source that "
900 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700901 script = edify_generator.EdifyGenerator(source_version,
902 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700903
Michael Runge6e836112014-04-15 17:40:21 -0700904 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
905 oem_dict = None
906 if oem_props is not None:
907 if OPTIONS.oem_source is None:
908 raise common.ExternalError("OEM source required for this build")
909 script.Mount("/oem")
910 oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
911
912 metadata = {"pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700913 OPTIONS.source_info_dict),
914 "post-timestamp": GetBuildProp("ro.build.date.utc",
915 OPTIONS.target_info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700916 }
917
Doug Zongker05d3dea2009-06-22 11:32:31 -0700918 device_specific = common.DeviceSpecificParams(
919 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800920 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700921 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800922 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700923 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -0700924 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -0700925 metadata=metadata,
926 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700927
Doug Zongkereef39442009-04-02 12:14:19 -0700928 print "Loading target..."
Doug Zongker1807e702012-02-28 12:21:08 -0800929 target_data = LoadSystemFiles(target_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700930 print "Loading source..."
Doug Zongker1807e702012-02-28 12:21:08 -0800931 source_data = LoadSystemFiles(source_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700932
933 verbatim_targets = []
934 patch_list = []
Doug Zongker761e6422009-09-25 10:45:39 -0700935 diffs = []
Michael Runge4038aa82013-12-13 18:06:28 -0800936 renames = {}
937 known_paths = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700938 largest_source_size = 0
Michael Runge4038aa82013-12-13 18:06:28 -0800939
940 matching_file_cache = {}
941 for fn, sf in source_data.items():
942 assert fn == sf.name
943 matching_file_cache["path:" + fn] = sf
944 if fn in target_data.keys():
945 AddToKnownPaths(fn, known_paths)
946 # Only allow eligibility for filename/sha matching
947 # if there isn't a perfect path match.
948 if target_data.get(sf.name) is None:
949 matching_file_cache["file:" + fn.split("/")[-1]] = sf
950 matching_file_cache["sha:" + sf.sha1] = sf
951
Doug Zongkereef39442009-04-02 12:14:19 -0700952 for fn in sorted(target_data.keys()):
953 tf = target_data[fn]
Doug Zongker761e6422009-09-25 10:45:39 -0700954 assert fn == tf.name
Michael Runge4038aa82013-12-13 18:06:28 -0800955 sf = ClosestFileMatch(tf, matching_file_cache, renames)
956 if sf is not None and sf.name != tf.name:
957 print "File has moved from " + sf.name + " to " + tf.name
958 renames[sf.name] = tf
Doug Zongkereef39442009-04-02 12:14:19 -0700959
960 if sf is None or fn in OPTIONS.require_verbatim:
961 # This file should be included verbatim
962 if fn in OPTIONS.prohibit_verbatim:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700963 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
Doug Zongkereef39442009-04-02 12:14:19 -0700964 print "send", fn, "verbatim"
965 tf.AddToZip(output_zip)
966 verbatim_targets.append((fn, tf.size))
Michael Runge4038aa82013-12-13 18:06:28 -0800967 if fn in target_data.keys():
968 AddToKnownPaths(fn, known_paths)
Doug Zongkereef39442009-04-02 12:14:19 -0700969 elif tf.sha1 != sf.sha1:
970 # File is different; consider sending as a patch
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700971 diffs.append(common.Difference(tf, sf))
Doug Zongkereef39442009-04-02 12:14:19 -0700972 else:
Michael Runge4038aa82013-12-13 18:06:28 -0800973 # Target file data identical to source (may still be renamed)
Doug Zongkereef39442009-04-02 12:14:19 -0700974 pass
975
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700976 common.ComputeDifferences(diffs)
Doug Zongker761e6422009-09-25 10:45:39 -0700977
978 for diff in diffs:
979 tf, sf, d = diff.GetPatch()
Michael Runge4038aa82013-12-13 18:06:28 -0800980 path = "/".join(tf.name.split("/")[:-1])
981 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
982 path not in known_paths:
Doug Zongker761e6422009-09-25 10:45:39 -0700983 # patch is almost as big as the file; don't bother patching
Doug Zongker32b527d2014-03-04 10:03:02 -0800984 # or a patch + rename cannot take place due to the target
Michael Runge4038aa82013-12-13 18:06:28 -0800985 # directory not existing
Doug Zongker761e6422009-09-25 10:45:39 -0700986 tf.AddToZip(output_zip)
987 verbatim_targets.append((tf.name, tf.size))
Michael Runge4038aa82013-12-13 18:06:28 -0800988 if sf.name in renames:
989 del renames[sf.name]
990 AddToKnownPaths(tf.name, known_paths)
Doug Zongker761e6422009-09-25 10:45:39 -0700991 else:
Michael Runge4038aa82013-12-13 18:06:28 -0800992 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
993 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
Doug Zongker761e6422009-09-25 10:45:39 -0700994 largest_source_size = max(largest_source_size, sf.size)
Doug Zongkereef39442009-04-02 12:14:19 -0700995
Michael Runge6e836112014-04-15 17:40:21 -0700996 script.Mount("/system")
997
998 target_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.target_info_dict)
999 source_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.source_info_dict)
1000
1001 if oem_props is None:
1002 script.AssertSomeFingerprint(source_fp, target_fp)
1003 else:
1004 script.AssertSomeThumbprint(
1005 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1006 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1007
Doug Zongker2ea21062010-04-28 16:05:21 -07001008 metadata["pre-build"] = source_fp
1009 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001010
Doug Zongker55d93282011-01-25 17:03:34 -08001011 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001012 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1013 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001014 target_boot = common.GetBootableImage(
1015 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001016 updating_boot = (not OPTIONS.two_step and
1017 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001018
Doug Zongker55d93282011-01-25 17:03:34 -08001019 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001020 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1021 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001022 target_recovery = common.GetBootableImage(
1023 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001024 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001025
Doug Zongker881dd402009-09-20 14:03:55 -07001026 # Here's how we divide up the progress bar:
1027 # 0.1 for verifying the start state (PatchCheck calls)
1028 # 0.8 for applying patches (ApplyPatch calls)
1029 # 0.1 for unpacking verbatim files, symlinking, and doing the
1030 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001031
Michael Runge6e836112014-04-15 17:40:21 -07001032 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001033 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001034
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001035 # Two-step incremental package strategy (in chronological order,
1036 # which is *not* the order in which the generated script has
1037 # things):
1038 #
1039 # if stage is not "2/3" or "3/3":
1040 # do verification on current system
1041 # write recovery image to boot partition
1042 # set stage to "2/3"
1043 # reboot to boot partition and restart recovery
1044 # else if stage is "2/3":
1045 # write recovery image to recovery partition
1046 # set stage to "3/3"
1047 # reboot to recovery partition and restart recovery
1048 # else:
1049 # (stage must be "3/3")
1050 # perform update:
1051 # patch system files, etc.
1052 # force full install of new boot image
1053 # set up system to update recovery partition on first boot
1054 # complete script normally (allow recovery to mark itself finished and reboot)
1055
1056 if OPTIONS.two_step:
1057 if not OPTIONS.info_dict.get("multistage_support", None):
1058 assert False, "two-step packages not supported by this build"
1059 fs = OPTIONS.info_dict["fstab"]["/misc"]
1060 assert fs.fs_type.upper() == "EMMC", \
1061 "two-step packages only supported on devices with EMMC /misc partitions"
1062 bcb_dev = {"bcb_dev": fs.device}
1063 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1064 script.AppendExtra("""
1065if get_stage("%(bcb_dev)s", "stage") == "2/3" then
1066""" % bcb_dev)
1067 script.AppendExtra("sleep(20);\n");
1068 script.WriteRawImage("/recovery", "recovery.img")
1069 script.AppendExtra("""
1070set_stage("%(bcb_dev)s", "3/3");
1071reboot_now("%(bcb_dev)s", "recovery");
1072else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
1073""" % bcb_dev)
1074
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001075 script.Print("Verifying current system...")
1076
Doug Zongkere5ff5902012-01-17 10:55:37 -08001077 device_specific.IncrementalOTA_VerifyBegin()
1078
Doug Zongker881dd402009-09-20 14:03:55 -07001079 script.ShowProgress(0.1, 0)
Doug Zongker881dd402009-09-20 14:03:55 -07001080 so_far = 0
Doug Zongkereef39442009-04-02 12:14:19 -07001081
Michael Runge4038aa82013-12-13 18:06:28 -08001082 for tf, sf, size, patch_sha in patch_list:
1083 if tf.name != sf.name:
1084 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1085 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
Doug Zongker881dd402009-09-20 14:03:55 -07001086 so_far += sf.size
Doug Zongkereef39442009-04-02 12:14:19 -07001087
Doug Zongker5da317e2009-06-02 13:38:17 -07001088 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001089 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001090 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001091 print "boot target: %d source: %d diff: %d" % (
1092 target_boot.size, source_boot.size, len(d))
1093
Doug Zongker048e7ca2009-06-15 14:31:53 -07001094 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001095
Doug Zongker96a57e72010-09-26 14:57:41 -07001096 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001097
1098 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1099 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001100 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001101 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001102 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001103
1104 if patch_list or updating_recovery or updating_boot:
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001105 script.CacheFreeSpaceCheck(largest_source_size)
Doug Zongker5a482092010-02-17 16:09:18 -08001106
Doug Zongker05d3dea2009-06-22 11:32:31 -07001107 device_specific.IncrementalOTA_VerifyEnd()
1108
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001109 if OPTIONS.two_step:
1110 script.WriteRawImage("/boot", "recovery.img")
1111 script.AppendExtra("""
1112set_stage("%(bcb_dev)s", "2/3");
1113reboot_now("%(bcb_dev)s", "");
1114else
1115""" % bcb_dev)
1116
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001117 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001118
Doug Zongkere5ff5902012-01-17 10:55:37 -08001119 device_specific.IncrementalOTA_InstallBegin()
1120
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001121 if OPTIONS.two_step:
1122 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1123 script.WriteRawImage("/boot", "boot.img")
1124 print "writing full boot image (forced by two-step mode)"
1125
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001126 script.Print("Removing unneeded files...")
Doug Zongker0f3298a2009-06-30 08:16:58 -07001127 script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
1128 ["/"+i for i in sorted(source_data)
Michael Runge4038aa82013-12-13 18:06:28 -08001129 if i not in target_data and
1130 i not in renames] +
Doug Zongker3b949f02009-08-24 10:24:32 -07001131 ["/system/recovery.img"])
Doug Zongkereef39442009-04-02 12:14:19 -07001132
Doug Zongker881dd402009-09-20 14:03:55 -07001133 script.ShowProgress(0.8, 0)
1134 total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
1135 if updating_boot:
1136 total_patch_size += target_boot.size
1137 so_far = 0
1138
1139 script.Print("Patching system files...")
Doug Zongkere92f15a2011-08-26 13:46:40 -07001140 deferred_patch_list = []
1141 for item in patch_list:
Michael Runge4038aa82013-12-13 18:06:28 -08001142 tf, sf, size, _ = item
Doug Zongkere92f15a2011-08-26 13:46:40 -07001143 if tf.name == "system/build.prop":
1144 deferred_patch_list.append(item)
1145 continue
Michael Runge4038aa82013-12-13 18:06:28 -08001146 if (sf.name != tf.name):
1147 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1148 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
Doug Zongker881dd402009-09-20 14:03:55 -07001149 so_far += tf.size
1150 script.SetProgress(so_far / total_patch_size)
1151
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001152 if not OPTIONS.two_step:
1153 if updating_boot:
1154 # Produce the boot image by applying a patch to the current
1155 # contents of the boot partition, and write it back to the
1156 # partition.
1157 script.Print("Patching boot image...")
1158 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1159 % (boot_type, boot_device,
1160 source_boot.size, source_boot.sha1,
1161 target_boot.size, target_boot.sha1),
1162 "-",
1163 target_boot.size, target_boot.sha1,
1164 source_boot.sha1, "patch/boot.img.p")
1165 so_far += target_boot.size
1166 script.SetProgress(so_far / total_patch_size)
1167 print "boot image changed; including."
1168 else:
1169 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001170
1171 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001172 # Recovery is generated as a patch using both the boot image
1173 # (which contains the same linux kernel as recovery) and the file
1174 # /system/etc/recovery-resource.dat (which contains all the images
1175 # used in the recovery UI) as sources. This lets us minimize the
1176 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001177 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001178 # For older builds where recovery-resource.dat is not present, we
1179 # use only the boot image as the source.
1180
Doug Zongkerc9253822014-02-04 12:17:58 -08001181 if not target_has_recovery_patch:
1182 def output_sink(fn, data):
1183 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
1184 Item.Get("system/" + fn, dir=False)
1185
1186 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1187 target_recovery, target_boot)
1188 script.DeleteFiles(["/system/recovery-from-boot.p",
1189 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001190 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001191 else:
1192 print "recovery image unchanged; skipping."
1193
Doug Zongker881dd402009-09-20 14:03:55 -07001194 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001195
Doug Zongker1807e702012-02-28 12:21:08 -08001196 target_symlinks = CopySystemFiles(target_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -07001197
1198 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001199 temp_script = script.MakeTemporary()
Doug Zongker283e2a12010-03-15 17:52:32 -07001200 Item.GetMetadata(target_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -07001201 Item.Get("system").SetPermissions(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001202
1203 # Note that this call will mess up the tree of Items, so make sure
1204 # we're done with it.
Doug Zongker1807e702012-02-28 12:21:08 -08001205 source_symlinks = CopySystemFiles(source_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -07001206 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1207
1208 # Delete all the symlinks in source that aren't in target. This
1209 # needs to happen before verbatim files are unpacked, in case a
1210 # symlink in the source is replaced by a real file in the target.
1211 to_delete = []
1212 for dest, link in source_symlinks:
1213 if link not in target_symlinks_d:
1214 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001215 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001216
1217 if verbatim_targets:
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001218 script.Print("Unpacking new files...")
1219 script.UnpackPackageDir("system", "/system")
1220
Doug Zongkerc9253822014-02-04 12:17:58 -08001221 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001222 script.Print("Unpacking new recovery...")
1223 script.UnpackPackageDir("recovery", "/system")
1224
Michael Runge4038aa82013-12-13 18:06:28 -08001225 if len(renames) > 0:
1226 script.Print("Renaming files...")
1227
1228 for src in renames:
1229 print "Renaming " + src + " to " + renames[src].name
1230 script.RenameFile(src, renames[src].name)
1231
Doug Zongker05d3dea2009-06-22 11:32:31 -07001232 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001233
1234 # Create all the symlinks that don't already exist, or point to
1235 # somewhere different than what we want. Delete each symlink before
1236 # creating it, since the 'symlink' command won't overwrite.
1237 to_create = []
1238 for dest, link in target_symlinks:
1239 if link in source_symlinks_d:
1240 if dest != source_symlinks_d[link]:
1241 to_create.append((dest, link))
1242 else:
1243 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001244 script.DeleteFiles([i[1] for i in to_create])
1245 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001246
1247 # Now that the symlinks are created, we can set all the
1248 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001249 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001250
Doug Zongker881dd402009-09-20 14:03:55 -07001251 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001252 device_specific.IncrementalOTA_InstallEnd()
1253
Doug Zongker1c390a22009-05-14 19:06:36 -07001254 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001255 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001256
Doug Zongkere92f15a2011-08-26 13:46:40 -07001257 # Patch the build.prop file last, so if something fails but the
1258 # device can still come up, it appears to be the old build and will
1259 # get set the OTA package again to retry.
1260 script.Print("Patching remaining system files...")
1261 for item in deferred_patch_list:
Michael Runge4038aa82013-12-13 18:06:28 -08001262 tf, sf, size, _ = item
1263 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
Nick Kralevich0eb17d92013-09-07 17:10:29 -07001264 script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001265
Doug Zongker922206e2014-03-04 13:16:24 -08001266 if OPTIONS.wipe_user_data:
1267 script.Print("Erasing user data...")
1268 script.FormatPartition("/data")
1269
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001270 if OPTIONS.two_step:
1271 script.AppendExtra("""
1272set_stage("%(bcb_dev)s", "");
1273endif;
1274endif;
1275""" % bcb_dev)
1276
Doug Zongker25568482014-03-03 10:21:27 -08001277 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -07001278 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001279
1280
1281def main(argv):
1282
1283 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001284 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001285 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001286 elif o in ("-k", "--package_key"):
1287 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001288 elif o in ("-i", "--incremental_from"):
1289 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001290 elif o in ("-w", "--wipe_user_data"):
1291 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001292 elif o in ("-n", "--no_prereq"):
1293 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001294 elif o in ("-o", "--oem_settings"):
1295 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001296 elif o in ("-e", "--extra_script"):
1297 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001298 elif o in ("-a", "--aslr_mode"):
1299 if a in ("on", "On", "true", "True", "yes", "Yes"):
1300 OPTIONS.aslr_mode = True
1301 else:
1302 OPTIONS.aslr_mode = False
Doug Zongker761e6422009-09-25 10:45:39 -07001303 elif o in ("--worker_threads"):
1304 OPTIONS.worker_threads = int(a)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001305 elif o in ("-2", "--two_step"):
1306 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001307 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001308 OPTIONS.no_signing = True
Doug Zongker26e66192014-02-20 13:22:07 -08001309 elif o == "--block":
1310 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001311 elif o in ("-b", "--binary"):
1312 OPTIONS.updater_binary = a
Doug Zongkereef39442009-04-02 12:14:19 -07001313 else:
1314 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001315 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001316
1317 args = common.ParseOptions(argv, __doc__,
Michael Runge6e836112014-04-15 17:40:21 -07001318 extra_opts="b:k:i:d:wne:a:2o:",
Doug Zongkereef39442009-04-02 12:14:19 -07001319 extra_long_opts=["board_config=",
1320 "package_key=",
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001321 "incremental_from=",
Doug Zongker962069c2009-04-23 11:41:58 -07001322 "wipe_user_data",
Doug Zongker1c390a22009-05-14 19:06:36 -07001323 "no_prereq",
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001324 "extra_script=",
Hristo Bojinov96be7202010-08-02 10:26:17 -07001325 "worker_threads=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001326 "aslr_mode=",
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001327 "two_step",
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001328 "no_signing",
Doug Zongker26e66192014-02-20 13:22:07 -08001329 "block",
Doug Zongker25568482014-03-03 10:21:27 -08001330 "binary=",
Michael Runge6e836112014-04-15 17:40:21 -07001331 "oem_settings=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001332 ],
Doug Zongkereef39442009-04-02 12:14:19 -07001333 extra_option_handler=option_handler)
1334
1335 if len(args) != 2:
1336 common.Usage(__doc__)
1337 sys.exit(1)
1338
Doug Zongker1c390a22009-05-14 19:06:36 -07001339 if OPTIONS.extra_script is not None:
1340 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1341
Doug Zongkereef39442009-04-02 12:14:19 -07001342 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001343 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001344
Doug Zongkereef39442009-04-02 12:14:19 -07001345 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001346 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001347
1348 # If this image was originally labelled with SELinux contexts, make sure we
1349 # also apply the labels in our new image. During building, the "file_contexts"
1350 # is in the out/ directory tree, but for repacking from target-files.zip it's
1351 # in the root directory of the ramdisk.
1352 if "selinux_fc" in OPTIONS.info_dict:
1353 OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK",
1354 "file_contexts")
1355
Doug Zongker37974732010-09-16 17:44:38 -07001356 if OPTIONS.verbose:
1357 print "--- target info ---"
1358 common.DumpInfoDict(OPTIONS.info_dict)
1359
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001360 # If the caller explicitly specified the device-specific extensions
1361 # path via -s/--device_specific, use that. Otherwise, use
1362 # META/releasetools.py if it is present in the target target_files.
1363 # Otherwise, take the path of the file from 'tool_extensions' in the
1364 # info dict and look for that in the local filesystem, relative to
1365 # the current directory.
1366
Doug Zongker37974732010-09-16 17:44:38 -07001367 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001368 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1369 if os.path.exists(from_input):
1370 print "(using device-specific extensions from target_files)"
1371 OPTIONS.device_specific = from_input
1372 else:
1373 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1374
Doug Zongker37974732010-09-16 17:44:38 -07001375 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001376 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001377
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001378 if OPTIONS.no_signing:
1379 output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
1380 else:
1381 temp_zip_file = tempfile.NamedTemporaryFile()
1382 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1383 compression=zipfile.ZIP_DEFLATED)
Doug Zongkereef39442009-04-02 12:14:19 -07001384
1385 if OPTIONS.incremental_source is None:
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001386 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001387 if OPTIONS.package_key is None:
1388 OPTIONS.package_key = OPTIONS.info_dict.get(
1389 "default_system_dev_certificate",
1390 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -07001391 else:
1392 print "unzipping source target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001393 OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
Doug Zongker37974732010-09-16 17:44:38 -07001394 OPTIONS.target_info_dict = OPTIONS.info_dict
1395 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
Doug Zongker5fad2032014-02-24 08:13:45 -08001396 if "selinux_fc" in OPTIONS.source_info_dict:
1397 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(OPTIONS.source_tmp, "BOOT", "RAMDISK",
1398 "file_contexts")
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001399 if OPTIONS.package_key is None:
Doug Zongker91b4f8a2011-09-23 12:48:33 -07001400 OPTIONS.package_key = OPTIONS.source_info_dict.get(
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001401 "default_system_dev_certificate",
1402 "build/target/product/security/testkey")
Doug Zongker37974732010-09-16 17:44:38 -07001403 if OPTIONS.verbose:
1404 print "--- source info ---"
1405 common.DumpInfoDict(OPTIONS.source_info_dict)
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001406 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001407
1408 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001409
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001410 if not OPTIONS.no_signing:
1411 SignOutput(temp_zip_file.name, args[1])
1412 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001413
1414 common.Cleanup()
1415
1416 print "done."
1417
1418
1419if __name__ == '__main__':
1420 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001421 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001422 main(sys.argv[1:])
1423 except common.ExternalError, e:
1424 print
1425 print " ERROR: %s" % (e,)
1426 print
1427 sys.exit(1)