blob: d3701e75842e48729f0252d6a3e23602b80fb44d [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 Runge6e836112014-04-15 17:40:21 -0700369def AppendAssertions(script, info_dict, oem_dict):
370 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
686 AppendAssertions(script, OPTIONS.target_info_dict)
687 device_specific.IncrementalOTA_Assertions()
688
689 # Two-step incremental package strategy (in chronological order,
690 # which is *not* the order in which the generated script has
691 # things):
692 #
693 # if stage is not "2/3" or "3/3":
694 # do verification on current system
695 # write recovery image to boot partition
696 # set stage to "2/3"
697 # reboot to boot partition and restart recovery
698 # else if stage is "2/3":
699 # write recovery image to recovery partition
700 # set stage to "3/3"
701 # reboot to recovery partition and restart recovery
702 # else:
703 # (stage must be "3/3")
704 # perform update:
705 # patch system files, etc.
706 # force full install of new boot image
707 # set up system to update recovery partition on first boot
708 # complete script normally (allow recovery to mark itself finished and reboot)
709
710 if OPTIONS.two_step:
711 if not OPTIONS.info_dict.get("multistage_support", None):
712 assert False, "two-step packages not supported by this build"
713 fs = OPTIONS.info_dict["fstab"]["/misc"]
714 assert fs.fs_type.upper() == "EMMC", \
715 "two-step packages only supported on devices with EMMC /misc partitions"
716 bcb_dev = {"bcb_dev": fs.device}
717 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
718 script.AppendExtra("""
719if get_stage("%(bcb_dev)s", "stage") == "2/3" then
720""" % bcb_dev)
721 script.AppendExtra("sleep(20);\n");
722 script.WriteRawImage("/recovery", "recovery.img")
723 script.AppendExtra("""
724set_stage("%(bcb_dev)s", "3/3");
725reboot_now("%(bcb_dev)s", "recovery");
726else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
727""" % bcb_dev)
728
729 script.Print("Verifying current system...")
730
731 device_specific.IncrementalOTA_VerifyBegin()
732
733 script.AssertRecoveryFingerprint(source_fp, target_fp)
734
735 if updating_boot:
Geremy Condra36bd3652014-02-06 19:45:10 -0800736 d = common.Difference(target_boot, source_boot)
737 _, _, d = d.ComputePatch()
738 print "boot target: %d source: %d diff: %d" % (
739 target_boot.size, source_boot.size, len(d))
740
741 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
742
743 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
744
745 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
746 (boot_type, boot_device,
747 source_boot.size, source_boot.sha1,
748 target_boot.size, target_boot.sha1))
749
750 device_specific.IncrementalOTA_VerifyEnd()
751
752 if OPTIONS.two_step:
753 script.WriteRawImage("/boot", "recovery.img")
754 script.AppendExtra("""
755set_stage("%(bcb_dev)s", "2/3");
756reboot_now("%(bcb_dev)s", "");
757else
758""" % bcb_dev)
759
760 script.Comment("---- start making changes here ----")
761
762 device_specific.IncrementalOTA_InstallBegin()
763
Geremy Condra36bd3652014-02-06 19:45:10 -0800764 script.Print("Patching system image...")
765 script.Syspatch(system_device,
Doug Zongker5fad2032014-02-24 08:13:45 -0800766 tgt_mapfilename, tgt_sys_sha1,
767 src_mapfilename, src_sys_sha1,
Geremy Condra36bd3652014-02-06 19:45:10 -0800768 system_patch.name)
769
770 if OPTIONS.two_step:
771 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
772 script.WriteRawImage("/boot", "boot.img")
773 print "writing full boot image (forced by two-step mode)"
774
775 if not OPTIONS.two_step:
776 if updating_boot:
777 # Produce the boot image by applying a patch to the current
778 # contents of the boot partition, and write it back to the
779 # partition.
780 script.Print("Patching boot image...")
781 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
782 % (boot_type, boot_device,
783 source_boot.size, source_boot.sha1,
784 target_boot.size, target_boot.sha1),
785 "-",
786 target_boot.size, target_boot.sha1,
787 source_boot.sha1, "patch/boot.img.p")
788 print "boot image changed; including."
789 else:
790 print "boot image unchanged; skipping."
791
792 # Do device-specific installation (eg, write radio image).
793 device_specific.IncrementalOTA_InstallEnd()
794
795 if OPTIONS.extra_script is not None:
796 script.AppendExtra(OPTIONS.extra_script)
797
Doug Zongker922206e2014-03-04 13:16:24 -0800798 if OPTIONS.wipe_user_data:
799 script.Print("Erasing user data...")
800 script.FormatPartition("/data")
801
Geremy Condra36bd3652014-02-06 19:45:10 -0800802 if OPTIONS.two_step:
803 script.AppendExtra("""
804set_stage("%(bcb_dev)s", "");
805endif;
806endif;
807""" % bcb_dev)
808
809 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800810 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800811 WriteMetadata(metadata, output_zip)
812
Doug Zongker32b527d2014-03-04 10:03:02 -0800813def ParseMap(map_str):
814 x = map_str.split()
815 assert int(x[0]) == 4096
816 assert int(x[1]) == len(x)-2
817 return int(x[0]), [int(i) for i in x[2:]]
818
819def TestBlockPatch(src_muimg, src_map, patch_data, tgt_map, tgt_sha1):
820 src_blksize, src_regions = ParseMap(src_map)
821 tgt_blksize, tgt_regions = ParseMap(tgt_map)
822
823 with tempfile.NamedTemporaryFile() as src_file,\
824 tempfile.NamedTemporaryFile() as patch_file,\
825 tempfile.NamedTemporaryFile() as tgt_file,\
826 tempfile.NamedTemporaryFile() as src_map_file,\
827 tempfile.NamedTemporaryFile() as tgt_map_file:
828
829 src_total = sum(src_regions) * src_blksize
830 src_file.truncate(src_total)
831 p = 0
832 for i in range(0, len(src_regions), 2):
833 c, dc = src_regions[i:i+2]
834 src_file.write(src_muimg[p:(p+c*src_blksize)])
835 p += c*src_blksize
836 src_file.seek(dc*src_blksize, 1)
837 assert src_file.tell() == src_total
838
839 patch_file.write(patch_data)
840
841 tgt_total = sum(tgt_regions) * tgt_blksize
842 tgt_file.truncate(tgt_total)
843
844 src_map_file.write(src_map)
845 tgt_map_file.write(tgt_map)
846
847 src_file.flush()
848 src_map_file.flush()
849 patch_file.flush()
850 tgt_file.flush()
851 tgt_map_file.flush()
852
853 p = common.Run(["syspatch_host", src_file.name, src_map_file.name,
854 patch_file.name, tgt_file.name, tgt_map_file.name],
855 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
856 stdoutdata, _ = p.communicate()
857 if p.returncode != 0:
858 print stdoutdata
859 raise ValueError("failed to reconstruct target system image from patch")
860
861 h = sha1()
862 for i in range(0, len(tgt_regions), 2):
863 c, dc = tgt_regions[i:i+2]
864 h.update(tgt_file.read(c*tgt_blksize))
865 tgt_file.seek(dc*tgt_blksize, 1)
866
867 if h.hexdigest() != tgt_sha1:
868 raise ValueError("patch reconstructed incorrect target system image")
869
870 print "test of system image patch succeeded"
871
872
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700873def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -0800874 target_has_recovery_patch = HasRecoveryPatch(target_zip)
875 source_has_recovery_patch = HasRecoveryPatch(source_zip)
876
Doug Zongker26e66192014-02-20 13:22:07 -0800877 if (OPTIONS.block_based and
878 target_has_recovery_patch and
879 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -0800880 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
881
Doug Zongker37974732010-09-16 17:44:38 -0700882 source_version = OPTIONS.source_info_dict["recovery_api_version"]
883 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700884
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700885 if source_version == 0:
886 print ("WARNING: generating edify script for a source that "
887 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700888 script = edify_generator.EdifyGenerator(source_version,
889 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700890
Michael Runge6e836112014-04-15 17:40:21 -0700891 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
892 oem_dict = None
893 if oem_props is not None:
894 if OPTIONS.oem_source is None:
895 raise common.ExternalError("OEM source required for this build")
896 script.Mount("/oem")
897 oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
898
899 metadata = {"pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700900 OPTIONS.source_info_dict),
901 "post-timestamp": GetBuildProp("ro.build.date.utc",
902 OPTIONS.target_info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700903 }
904
Doug Zongker05d3dea2009-06-22 11:32:31 -0700905 device_specific = common.DeviceSpecificParams(
906 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800907 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700908 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800909 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700910 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -0700911 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -0700912 metadata=metadata,
913 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700914
Doug Zongkereef39442009-04-02 12:14:19 -0700915 print "Loading target..."
Doug Zongker1807e702012-02-28 12:21:08 -0800916 target_data = LoadSystemFiles(target_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700917 print "Loading source..."
Doug Zongker1807e702012-02-28 12:21:08 -0800918 source_data = LoadSystemFiles(source_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700919
920 verbatim_targets = []
921 patch_list = []
Doug Zongker761e6422009-09-25 10:45:39 -0700922 diffs = []
Michael Runge4038aa82013-12-13 18:06:28 -0800923 renames = {}
924 known_paths = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700925 largest_source_size = 0
Michael Runge4038aa82013-12-13 18:06:28 -0800926
927 matching_file_cache = {}
928 for fn, sf in source_data.items():
929 assert fn == sf.name
930 matching_file_cache["path:" + fn] = sf
931 if fn in target_data.keys():
932 AddToKnownPaths(fn, known_paths)
933 # Only allow eligibility for filename/sha matching
934 # if there isn't a perfect path match.
935 if target_data.get(sf.name) is None:
936 matching_file_cache["file:" + fn.split("/")[-1]] = sf
937 matching_file_cache["sha:" + sf.sha1] = sf
938
Doug Zongkereef39442009-04-02 12:14:19 -0700939 for fn in sorted(target_data.keys()):
940 tf = target_data[fn]
Doug Zongker761e6422009-09-25 10:45:39 -0700941 assert fn == tf.name
Michael Runge4038aa82013-12-13 18:06:28 -0800942 sf = ClosestFileMatch(tf, matching_file_cache, renames)
943 if sf is not None and sf.name != tf.name:
944 print "File has moved from " + sf.name + " to " + tf.name
945 renames[sf.name] = tf
Doug Zongkereef39442009-04-02 12:14:19 -0700946
947 if sf is None or fn in OPTIONS.require_verbatim:
948 # This file should be included verbatim
949 if fn in OPTIONS.prohibit_verbatim:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700950 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
Doug Zongkereef39442009-04-02 12:14:19 -0700951 print "send", fn, "verbatim"
952 tf.AddToZip(output_zip)
953 verbatim_targets.append((fn, tf.size))
Michael Runge4038aa82013-12-13 18:06:28 -0800954 if fn in target_data.keys():
955 AddToKnownPaths(fn, known_paths)
Doug Zongkereef39442009-04-02 12:14:19 -0700956 elif tf.sha1 != sf.sha1:
957 # File is different; consider sending as a patch
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700958 diffs.append(common.Difference(tf, sf))
Doug Zongkereef39442009-04-02 12:14:19 -0700959 else:
Michael Runge4038aa82013-12-13 18:06:28 -0800960 # Target file data identical to source (may still be renamed)
Doug Zongkereef39442009-04-02 12:14:19 -0700961 pass
962
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700963 common.ComputeDifferences(diffs)
Doug Zongker761e6422009-09-25 10:45:39 -0700964
965 for diff in diffs:
966 tf, sf, d = diff.GetPatch()
Michael Runge4038aa82013-12-13 18:06:28 -0800967 path = "/".join(tf.name.split("/")[:-1])
968 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
969 path not in known_paths:
Doug Zongker761e6422009-09-25 10:45:39 -0700970 # patch is almost as big as the file; don't bother patching
Doug Zongker32b527d2014-03-04 10:03:02 -0800971 # or a patch + rename cannot take place due to the target
Michael Runge4038aa82013-12-13 18:06:28 -0800972 # directory not existing
Doug Zongker761e6422009-09-25 10:45:39 -0700973 tf.AddToZip(output_zip)
974 verbatim_targets.append((tf.name, tf.size))
Michael Runge4038aa82013-12-13 18:06:28 -0800975 if sf.name in renames:
976 del renames[sf.name]
977 AddToKnownPaths(tf.name, known_paths)
Doug Zongker761e6422009-09-25 10:45:39 -0700978 else:
Michael Runge4038aa82013-12-13 18:06:28 -0800979 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
980 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
Doug Zongker761e6422009-09-25 10:45:39 -0700981 largest_source_size = max(largest_source_size, sf.size)
Doug Zongkereef39442009-04-02 12:14:19 -0700982
Michael Runge6e836112014-04-15 17:40:21 -0700983 script.Mount("/system")
984
985 target_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.target_info_dict)
986 source_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.source_info_dict)
987
988 if oem_props is None:
989 script.AssertSomeFingerprint(source_fp, target_fp)
990 else:
991 script.AssertSomeThumbprint(
992 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
993 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
994
Doug Zongker2ea21062010-04-28 16:05:21 -0700995 metadata["pre-build"] = source_fp
996 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -0700997
Doug Zongker55d93282011-01-25 17:03:34 -0800998 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -0700999 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1000 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001001 target_boot = common.GetBootableImage(
1002 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001003 updating_boot = (not OPTIONS.two_step and
1004 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001005
Doug Zongker55d93282011-01-25 17:03:34 -08001006 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001007 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1008 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001009 target_recovery = common.GetBootableImage(
1010 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001011 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001012
Doug Zongker881dd402009-09-20 14:03:55 -07001013 # Here's how we divide up the progress bar:
1014 # 0.1 for verifying the start state (PatchCheck calls)
1015 # 0.8 for applying patches (ApplyPatch calls)
1016 # 0.1 for unpacking verbatim files, symlinking, and doing the
1017 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001018
Michael Runge6e836112014-04-15 17:40:21 -07001019 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001020 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001021
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001022 # Two-step incremental package strategy (in chronological order,
1023 # which is *not* the order in which the generated script has
1024 # things):
1025 #
1026 # if stage is not "2/3" or "3/3":
1027 # do verification on current system
1028 # write recovery image to boot partition
1029 # set stage to "2/3"
1030 # reboot to boot partition and restart recovery
1031 # else if stage is "2/3":
1032 # write recovery image to recovery partition
1033 # set stage to "3/3"
1034 # reboot to recovery partition and restart recovery
1035 # else:
1036 # (stage must be "3/3")
1037 # perform update:
1038 # patch system files, etc.
1039 # force full install of new boot image
1040 # set up system to update recovery partition on first boot
1041 # complete script normally (allow recovery to mark itself finished and reboot)
1042
1043 if OPTIONS.two_step:
1044 if not OPTIONS.info_dict.get("multistage_support", None):
1045 assert False, "two-step packages not supported by this build"
1046 fs = OPTIONS.info_dict["fstab"]["/misc"]
1047 assert fs.fs_type.upper() == "EMMC", \
1048 "two-step packages only supported on devices with EMMC /misc partitions"
1049 bcb_dev = {"bcb_dev": fs.device}
1050 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1051 script.AppendExtra("""
1052if get_stage("%(bcb_dev)s", "stage") == "2/3" then
1053""" % bcb_dev)
1054 script.AppendExtra("sleep(20);\n");
1055 script.WriteRawImage("/recovery", "recovery.img")
1056 script.AppendExtra("""
1057set_stage("%(bcb_dev)s", "3/3");
1058reboot_now("%(bcb_dev)s", "recovery");
1059else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
1060""" % bcb_dev)
1061
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001062 script.Print("Verifying current system...")
1063
Doug Zongkere5ff5902012-01-17 10:55:37 -08001064 device_specific.IncrementalOTA_VerifyBegin()
1065
Doug Zongker881dd402009-09-20 14:03:55 -07001066 script.ShowProgress(0.1, 0)
Doug Zongker881dd402009-09-20 14:03:55 -07001067 so_far = 0
Doug Zongkereef39442009-04-02 12:14:19 -07001068
Michael Runge4038aa82013-12-13 18:06:28 -08001069 for tf, sf, size, patch_sha in patch_list:
1070 if tf.name != sf.name:
1071 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1072 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
Doug Zongker881dd402009-09-20 14:03:55 -07001073 so_far += sf.size
Doug Zongkereef39442009-04-02 12:14:19 -07001074
Doug Zongker5da317e2009-06-02 13:38:17 -07001075 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001076 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001077 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001078 print "boot target: %d source: %d diff: %d" % (
1079 target_boot.size, source_boot.size, len(d))
1080
Doug Zongker048e7ca2009-06-15 14:31:53 -07001081 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001082
Doug Zongker96a57e72010-09-26 14:57:41 -07001083 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001084
1085 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1086 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001087 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001088 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001089 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001090
1091 if patch_list or updating_recovery or updating_boot:
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001092 script.CacheFreeSpaceCheck(largest_source_size)
Doug Zongker5a482092010-02-17 16:09:18 -08001093
Doug Zongker05d3dea2009-06-22 11:32:31 -07001094 device_specific.IncrementalOTA_VerifyEnd()
1095
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001096 if OPTIONS.two_step:
1097 script.WriteRawImage("/boot", "recovery.img")
1098 script.AppendExtra("""
1099set_stage("%(bcb_dev)s", "2/3");
1100reboot_now("%(bcb_dev)s", "");
1101else
1102""" % bcb_dev)
1103
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001104 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001105
Doug Zongkere5ff5902012-01-17 10:55:37 -08001106 device_specific.IncrementalOTA_InstallBegin()
1107
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001108 if OPTIONS.two_step:
1109 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1110 script.WriteRawImage("/boot", "boot.img")
1111 print "writing full boot image (forced by two-step mode)"
1112
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001113 script.Print("Removing unneeded files...")
Doug Zongker0f3298a2009-06-30 08:16:58 -07001114 script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
1115 ["/"+i for i in sorted(source_data)
Michael Runge4038aa82013-12-13 18:06:28 -08001116 if i not in target_data and
1117 i not in renames] +
Doug Zongker3b949f02009-08-24 10:24:32 -07001118 ["/system/recovery.img"])
Doug Zongkereef39442009-04-02 12:14:19 -07001119
Doug Zongker881dd402009-09-20 14:03:55 -07001120 script.ShowProgress(0.8, 0)
1121 total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
1122 if updating_boot:
1123 total_patch_size += target_boot.size
1124 so_far = 0
1125
1126 script.Print("Patching system files...")
Doug Zongkere92f15a2011-08-26 13:46:40 -07001127 deferred_patch_list = []
1128 for item in patch_list:
Michael Runge4038aa82013-12-13 18:06:28 -08001129 tf, sf, size, _ = item
Doug Zongkere92f15a2011-08-26 13:46:40 -07001130 if tf.name == "system/build.prop":
1131 deferred_patch_list.append(item)
1132 continue
Michael Runge4038aa82013-12-13 18:06:28 -08001133 if (sf.name != tf.name):
1134 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1135 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
Doug Zongker881dd402009-09-20 14:03:55 -07001136 so_far += tf.size
1137 script.SetProgress(so_far / total_patch_size)
1138
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001139 if not OPTIONS.two_step:
1140 if updating_boot:
1141 # Produce the boot image by applying a patch to the current
1142 # contents of the boot partition, and write it back to the
1143 # partition.
1144 script.Print("Patching boot image...")
1145 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1146 % (boot_type, boot_device,
1147 source_boot.size, source_boot.sha1,
1148 target_boot.size, target_boot.sha1),
1149 "-",
1150 target_boot.size, target_boot.sha1,
1151 source_boot.sha1, "patch/boot.img.p")
1152 so_far += target_boot.size
1153 script.SetProgress(so_far / total_patch_size)
1154 print "boot image changed; including."
1155 else:
1156 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001157
1158 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001159 # Recovery is generated as a patch using both the boot image
1160 # (which contains the same linux kernel as recovery) and the file
1161 # /system/etc/recovery-resource.dat (which contains all the images
1162 # used in the recovery UI) as sources. This lets us minimize the
1163 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001164 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001165 # For older builds where recovery-resource.dat is not present, we
1166 # use only the boot image as the source.
1167
Doug Zongkerc9253822014-02-04 12:17:58 -08001168 if not target_has_recovery_patch:
1169 def output_sink(fn, data):
1170 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
1171 Item.Get("system/" + fn, dir=False)
1172
1173 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1174 target_recovery, target_boot)
1175 script.DeleteFiles(["/system/recovery-from-boot.p",
1176 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001177 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001178 else:
1179 print "recovery image unchanged; skipping."
1180
Doug Zongker881dd402009-09-20 14:03:55 -07001181 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001182
Doug Zongker1807e702012-02-28 12:21:08 -08001183 target_symlinks = CopySystemFiles(target_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -07001184
1185 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001186 temp_script = script.MakeTemporary()
Doug Zongker283e2a12010-03-15 17:52:32 -07001187 Item.GetMetadata(target_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -07001188 Item.Get("system").SetPermissions(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001189
1190 # Note that this call will mess up the tree of Items, so make sure
1191 # we're done with it.
Doug Zongker1807e702012-02-28 12:21:08 -08001192 source_symlinks = CopySystemFiles(source_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -07001193 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1194
1195 # Delete all the symlinks in source that aren't in target. This
1196 # needs to happen before verbatim files are unpacked, in case a
1197 # symlink in the source is replaced by a real file in the target.
1198 to_delete = []
1199 for dest, link in source_symlinks:
1200 if link not in target_symlinks_d:
1201 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001202 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001203
1204 if verbatim_targets:
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001205 script.Print("Unpacking new files...")
1206 script.UnpackPackageDir("system", "/system")
1207
Doug Zongkerc9253822014-02-04 12:17:58 -08001208 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001209 script.Print("Unpacking new recovery...")
1210 script.UnpackPackageDir("recovery", "/system")
1211
Michael Runge4038aa82013-12-13 18:06:28 -08001212 if len(renames) > 0:
1213 script.Print("Renaming files...")
1214
1215 for src in renames:
1216 print "Renaming " + src + " to " + renames[src].name
1217 script.RenameFile(src, renames[src].name)
1218
Doug Zongker05d3dea2009-06-22 11:32:31 -07001219 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001220
1221 # Create all the symlinks that don't already exist, or point to
1222 # somewhere different than what we want. Delete each symlink before
1223 # creating it, since the 'symlink' command won't overwrite.
1224 to_create = []
1225 for dest, link in target_symlinks:
1226 if link in source_symlinks_d:
1227 if dest != source_symlinks_d[link]:
1228 to_create.append((dest, link))
1229 else:
1230 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001231 script.DeleteFiles([i[1] for i in to_create])
1232 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001233
1234 # Now that the symlinks are created, we can set all the
1235 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001236 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001237
Doug Zongker881dd402009-09-20 14:03:55 -07001238 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001239 device_specific.IncrementalOTA_InstallEnd()
1240
Doug Zongker1c390a22009-05-14 19:06:36 -07001241 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001242 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001243
Doug Zongkere92f15a2011-08-26 13:46:40 -07001244 # Patch the build.prop file last, so if something fails but the
1245 # device can still come up, it appears to be the old build and will
1246 # get set the OTA package again to retry.
1247 script.Print("Patching remaining system files...")
1248 for item in deferred_patch_list:
Michael Runge4038aa82013-12-13 18:06:28 -08001249 tf, sf, size, _ = item
1250 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
Nick Kralevich0eb17d92013-09-07 17:10:29 -07001251 script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001252
Doug Zongker922206e2014-03-04 13:16:24 -08001253 if OPTIONS.wipe_user_data:
1254 script.Print("Erasing user data...")
1255 script.FormatPartition("/data")
1256
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001257 if OPTIONS.two_step:
1258 script.AppendExtra("""
1259set_stage("%(bcb_dev)s", "");
1260endif;
1261endif;
1262""" % bcb_dev)
1263
Doug Zongker25568482014-03-03 10:21:27 -08001264 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -07001265 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001266
1267
1268def main(argv):
1269
1270 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001271 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001272 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001273 elif o in ("-k", "--package_key"):
1274 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001275 elif o in ("-i", "--incremental_from"):
1276 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001277 elif o in ("-w", "--wipe_user_data"):
1278 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001279 elif o in ("-n", "--no_prereq"):
1280 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001281 elif o in ("-o", "--oem_settings"):
1282 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001283 elif o in ("-e", "--extra_script"):
1284 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001285 elif o in ("-a", "--aslr_mode"):
1286 if a in ("on", "On", "true", "True", "yes", "Yes"):
1287 OPTIONS.aslr_mode = True
1288 else:
1289 OPTIONS.aslr_mode = False
Doug Zongker761e6422009-09-25 10:45:39 -07001290 elif o in ("--worker_threads"):
1291 OPTIONS.worker_threads = int(a)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001292 elif o in ("-2", "--two_step"):
1293 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001294 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001295 OPTIONS.no_signing = True
Doug Zongker26e66192014-02-20 13:22:07 -08001296 elif o == "--block":
1297 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001298 elif o in ("-b", "--binary"):
1299 OPTIONS.updater_binary = a
Doug Zongkereef39442009-04-02 12:14:19 -07001300 else:
1301 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001302 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001303
1304 args = common.ParseOptions(argv, __doc__,
Michael Runge6e836112014-04-15 17:40:21 -07001305 extra_opts="b:k:i:d:wne:a:2o:",
Doug Zongkereef39442009-04-02 12:14:19 -07001306 extra_long_opts=["board_config=",
1307 "package_key=",
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001308 "incremental_from=",
Doug Zongker962069c2009-04-23 11:41:58 -07001309 "wipe_user_data",
Doug Zongker1c390a22009-05-14 19:06:36 -07001310 "no_prereq",
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001311 "extra_script=",
Hristo Bojinov96be7202010-08-02 10:26:17 -07001312 "worker_threads=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001313 "aslr_mode=",
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001314 "two_step",
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001315 "no_signing",
Doug Zongker26e66192014-02-20 13:22:07 -08001316 "block",
Doug Zongker25568482014-03-03 10:21:27 -08001317 "binary=",
Michael Runge6e836112014-04-15 17:40:21 -07001318 "oem_settings=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001319 ],
Doug Zongkereef39442009-04-02 12:14:19 -07001320 extra_option_handler=option_handler)
1321
1322 if len(args) != 2:
1323 common.Usage(__doc__)
1324 sys.exit(1)
1325
Doug Zongker1c390a22009-05-14 19:06:36 -07001326 if OPTIONS.extra_script is not None:
1327 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1328
Doug Zongkereef39442009-04-02 12:14:19 -07001329 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001330 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001331
Doug Zongkereef39442009-04-02 12:14:19 -07001332 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001333 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001334
1335 # If this image was originally labelled with SELinux contexts, make sure we
1336 # also apply the labels in our new image. During building, the "file_contexts"
1337 # is in the out/ directory tree, but for repacking from target-files.zip it's
1338 # in the root directory of the ramdisk.
1339 if "selinux_fc" in OPTIONS.info_dict:
1340 OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK",
1341 "file_contexts")
1342
Doug Zongker37974732010-09-16 17:44:38 -07001343 if OPTIONS.verbose:
1344 print "--- target info ---"
1345 common.DumpInfoDict(OPTIONS.info_dict)
1346
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001347 # If the caller explicitly specified the device-specific extensions
1348 # path via -s/--device_specific, use that. Otherwise, use
1349 # META/releasetools.py if it is present in the target target_files.
1350 # Otherwise, take the path of the file from 'tool_extensions' in the
1351 # info dict and look for that in the local filesystem, relative to
1352 # the current directory.
1353
Doug Zongker37974732010-09-16 17:44:38 -07001354 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001355 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1356 if os.path.exists(from_input):
1357 print "(using device-specific extensions from target_files)"
1358 OPTIONS.device_specific = from_input
1359 else:
1360 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1361
Doug Zongker37974732010-09-16 17:44:38 -07001362 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001363 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001364
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001365 if OPTIONS.no_signing:
1366 output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
1367 else:
1368 temp_zip_file = tempfile.NamedTemporaryFile()
1369 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1370 compression=zipfile.ZIP_DEFLATED)
Doug Zongkereef39442009-04-02 12:14:19 -07001371
1372 if OPTIONS.incremental_source is None:
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001373 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001374 if OPTIONS.package_key is None:
1375 OPTIONS.package_key = OPTIONS.info_dict.get(
1376 "default_system_dev_certificate",
1377 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -07001378 else:
1379 print "unzipping source target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001380 OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
Doug Zongker37974732010-09-16 17:44:38 -07001381 OPTIONS.target_info_dict = OPTIONS.info_dict
1382 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
Doug Zongker5fad2032014-02-24 08:13:45 -08001383 if "selinux_fc" in OPTIONS.source_info_dict:
1384 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(OPTIONS.source_tmp, "BOOT", "RAMDISK",
1385 "file_contexts")
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001386 if OPTIONS.package_key is None:
Doug Zongker91b4f8a2011-09-23 12:48:33 -07001387 OPTIONS.package_key = OPTIONS.source_info_dict.get(
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001388 "default_system_dev_certificate",
1389 "build/target/product/security/testkey")
Doug Zongker37974732010-09-16 17:44:38 -07001390 if OPTIONS.verbose:
1391 print "--- source info ---"
1392 common.DumpInfoDict(OPTIONS.source_info_dict)
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001393 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001394
1395 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001396
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001397 if not OPTIONS.no_signing:
1398 SignOutput(temp_zip_file.name, args[1])
1399 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001400
1401 common.Cleanup()
1402
1403 print "done."
1404
1405
1406if __name__ == '__main__':
1407 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001408 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001409 main(sys.argv[1:])
1410 except common.ExternalError, e:
1411 print
1412 print " ERROR: %s" % (e,)
1413 print
1414 sys.exit(1)