blob: 87de2f61b82d00187641981baf0df25cd08fcb42 [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 Zongker4b9596f2014-06-09 14:15:45 -0700496 script.ShowProgress(system_progress, 0)
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
Doug Zongker91a99c22014-05-09 13:15:01 -0700519 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800520 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...")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700778 script.ShowProgress(0.9, 0)
Geremy Condra36bd3652014-02-06 19:45:10 -0800779 script.Syspatch(system_device,
Doug Zongker5fad2032014-02-24 08:13:45 -0800780 tgt_mapfilename, tgt_sys_sha1,
781 src_mapfilename, src_sys_sha1,
Geremy Condra36bd3652014-02-06 19:45:10 -0800782 system_patch.name)
783
784 if OPTIONS.two_step:
785 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
786 script.WriteRawImage("/boot", "boot.img")
787 print "writing full boot image (forced by two-step mode)"
788
789 if not OPTIONS.two_step:
790 if updating_boot:
791 # Produce the boot image by applying a patch to the current
792 # contents of the boot partition, and write it back to the
793 # partition.
794 script.Print("Patching boot image...")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700795 script.ShowProgress(0.1, 10)
Geremy Condra36bd3652014-02-06 19:45:10 -0800796 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
797 % (boot_type, boot_device,
798 source_boot.size, source_boot.sha1,
799 target_boot.size, target_boot.sha1),
800 "-",
801 target_boot.size, target_boot.sha1,
802 source_boot.sha1, "patch/boot.img.p")
803 print "boot image changed; including."
804 else:
805 print "boot image unchanged; skipping."
806
807 # Do device-specific installation (eg, write radio image).
808 device_specific.IncrementalOTA_InstallEnd()
809
810 if OPTIONS.extra_script is not None:
811 script.AppendExtra(OPTIONS.extra_script)
812
Doug Zongker922206e2014-03-04 13:16:24 -0800813 if OPTIONS.wipe_user_data:
814 script.Print("Erasing user data...")
815 script.FormatPartition("/data")
816
Geremy Condra36bd3652014-02-06 19:45:10 -0800817 if OPTIONS.two_step:
818 script.AppendExtra("""
819set_stage("%(bcb_dev)s", "");
820endif;
821endif;
822""" % bcb_dev)
823
824 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800825 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800826 WriteMetadata(metadata, output_zip)
827
Doug Zongker32b527d2014-03-04 10:03:02 -0800828def ParseMap(map_str):
829 x = map_str.split()
830 assert int(x[0]) == 4096
831 assert int(x[1]) == len(x)-2
832 return int(x[0]), [int(i) for i in x[2:]]
833
834def TestBlockPatch(src_muimg, src_map, patch_data, tgt_map, tgt_sha1):
835 src_blksize, src_regions = ParseMap(src_map)
836 tgt_blksize, tgt_regions = ParseMap(tgt_map)
837
838 with tempfile.NamedTemporaryFile() as src_file,\
839 tempfile.NamedTemporaryFile() as patch_file,\
Doug Zongker32b527d2014-03-04 10:03:02 -0800840 tempfile.NamedTemporaryFile() as src_map_file,\
841 tempfile.NamedTemporaryFile() as tgt_map_file:
842
843 src_total = sum(src_regions) * src_blksize
844 src_file.truncate(src_total)
845 p = 0
846 for i in range(0, len(src_regions), 2):
847 c, dc = src_regions[i:i+2]
848 src_file.write(src_muimg[p:(p+c*src_blksize)])
849 p += c*src_blksize
850 src_file.seek(dc*src_blksize, 1)
851 assert src_file.tell() == src_total
852
853 patch_file.write(patch_data)
854
Doug Zongker32b527d2014-03-04 10:03:02 -0800855 src_map_file.write(src_map)
856 tgt_map_file.write(tgt_map)
857
858 src_file.flush()
859 src_map_file.flush()
860 patch_file.flush()
Doug Zongker32b527d2014-03-04 10:03:02 -0800861 tgt_map_file.flush()
862
863 p = common.Run(["syspatch_host", src_file.name, src_map_file.name,
Doug Zongker1113e382014-06-13 10:38:32 -0700864 patch_file.name, src_file.name, tgt_map_file.name],
Doug Zongker32b527d2014-03-04 10:03:02 -0800865 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
866 stdoutdata, _ = p.communicate()
867 if p.returncode != 0:
868 print stdoutdata
869 raise ValueError("failed to reconstruct target system image from patch")
870
871 h = sha1()
Doug Zongker1113e382014-06-13 10:38:32 -0700872 src_file.seek(0, 0)
Doug Zongker32b527d2014-03-04 10:03:02 -0800873 for i in range(0, len(tgt_regions), 2):
874 c, dc = tgt_regions[i:i+2]
Doug Zongker1113e382014-06-13 10:38:32 -0700875 h.update(src_file.read(c*tgt_blksize))
876 src_file.seek(dc*tgt_blksize, 1)
Doug Zongker32b527d2014-03-04 10:03:02 -0800877
878 if h.hexdigest() != tgt_sha1:
879 raise ValueError("patch reconstructed incorrect target system image")
880
881 print "test of system image patch succeeded"
882
883
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700884def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -0800885 target_has_recovery_patch = HasRecoveryPatch(target_zip)
886 source_has_recovery_patch = HasRecoveryPatch(source_zip)
887
Doug Zongker26e66192014-02-20 13:22:07 -0800888 if (OPTIONS.block_based and
889 target_has_recovery_patch and
890 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -0800891 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
892
Doug Zongker37974732010-09-16 17:44:38 -0700893 source_version = OPTIONS.source_info_dict["recovery_api_version"]
894 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700895
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700896 if source_version == 0:
897 print ("WARNING: generating edify script for a source that "
898 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700899 script = edify_generator.EdifyGenerator(source_version,
900 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700901
Michael Runge6e836112014-04-15 17:40:21 -0700902 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
903 oem_dict = None
904 if oem_props is not None:
905 if OPTIONS.oem_source is None:
906 raise common.ExternalError("OEM source required for this build")
907 script.Mount("/oem")
908 oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
909
910 metadata = {"pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700911 OPTIONS.source_info_dict),
912 "post-timestamp": GetBuildProp("ro.build.date.utc",
913 OPTIONS.target_info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700914 }
915
Doug Zongker05d3dea2009-06-22 11:32:31 -0700916 device_specific = common.DeviceSpecificParams(
917 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800918 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700919 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -0800920 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -0700921 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -0700922 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -0700923 metadata=metadata,
924 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700925
Doug Zongkereef39442009-04-02 12:14:19 -0700926 print "Loading target..."
Doug Zongker1807e702012-02-28 12:21:08 -0800927 target_data = LoadSystemFiles(target_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700928 print "Loading source..."
Doug Zongker1807e702012-02-28 12:21:08 -0800929 source_data = LoadSystemFiles(source_zip)
Doug Zongkereef39442009-04-02 12:14:19 -0700930
931 verbatim_targets = []
932 patch_list = []
Doug Zongker761e6422009-09-25 10:45:39 -0700933 diffs = []
Michael Runge4038aa82013-12-13 18:06:28 -0800934 renames = {}
935 known_paths = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700936 largest_source_size = 0
Michael Runge4038aa82013-12-13 18:06:28 -0800937
938 matching_file_cache = {}
939 for fn, sf in source_data.items():
940 assert fn == sf.name
941 matching_file_cache["path:" + fn] = sf
942 if fn in target_data.keys():
943 AddToKnownPaths(fn, known_paths)
944 # Only allow eligibility for filename/sha matching
945 # if there isn't a perfect path match.
946 if target_data.get(sf.name) is None:
947 matching_file_cache["file:" + fn.split("/")[-1]] = sf
948 matching_file_cache["sha:" + sf.sha1] = sf
949
Doug Zongkereef39442009-04-02 12:14:19 -0700950 for fn in sorted(target_data.keys()):
951 tf = target_data[fn]
Doug Zongker761e6422009-09-25 10:45:39 -0700952 assert fn == tf.name
Michael Runge4038aa82013-12-13 18:06:28 -0800953 sf = ClosestFileMatch(tf, matching_file_cache, renames)
954 if sf is not None and sf.name != tf.name:
955 print "File has moved from " + sf.name + " to " + tf.name
956 renames[sf.name] = tf
Doug Zongkereef39442009-04-02 12:14:19 -0700957
958 if sf is None or fn in OPTIONS.require_verbatim:
959 # This file should be included verbatim
960 if fn in OPTIONS.prohibit_verbatim:
Doug Zongker9fc74c72009-06-23 16:27:38 -0700961 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
Doug Zongkereef39442009-04-02 12:14:19 -0700962 print "send", fn, "verbatim"
963 tf.AddToZip(output_zip)
964 verbatim_targets.append((fn, tf.size))
Michael Runge4038aa82013-12-13 18:06:28 -0800965 if fn in target_data.keys():
966 AddToKnownPaths(fn, known_paths)
Doug Zongkereef39442009-04-02 12:14:19 -0700967 elif tf.sha1 != sf.sha1:
968 # File is different; consider sending as a patch
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700969 diffs.append(common.Difference(tf, sf))
Doug Zongkereef39442009-04-02 12:14:19 -0700970 else:
Michael Runge4038aa82013-12-13 18:06:28 -0800971 # Target file data identical to source (may still be renamed)
Doug Zongkereef39442009-04-02 12:14:19 -0700972 pass
973
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700974 common.ComputeDifferences(diffs)
Doug Zongker761e6422009-09-25 10:45:39 -0700975
976 for diff in diffs:
977 tf, sf, d = diff.GetPatch()
Michael Runge4038aa82013-12-13 18:06:28 -0800978 path = "/".join(tf.name.split("/")[:-1])
979 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
980 path not in known_paths:
Doug Zongker761e6422009-09-25 10:45:39 -0700981 # patch is almost as big as the file; don't bother patching
Doug Zongker32b527d2014-03-04 10:03:02 -0800982 # or a patch + rename cannot take place due to the target
Michael Runge4038aa82013-12-13 18:06:28 -0800983 # directory not existing
Doug Zongker761e6422009-09-25 10:45:39 -0700984 tf.AddToZip(output_zip)
985 verbatim_targets.append((tf.name, tf.size))
Michael Runge4038aa82013-12-13 18:06:28 -0800986 if sf.name in renames:
987 del renames[sf.name]
988 AddToKnownPaths(tf.name, known_paths)
Doug Zongker761e6422009-09-25 10:45:39 -0700989 else:
Michael Runge4038aa82013-12-13 18:06:28 -0800990 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
991 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
Doug Zongker761e6422009-09-25 10:45:39 -0700992 largest_source_size = max(largest_source_size, sf.size)
Doug Zongkereef39442009-04-02 12:14:19 -0700993
Michael Runge6e836112014-04-15 17:40:21 -0700994 script.Mount("/system")
995
996 target_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.target_info_dict)
997 source_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.source_info_dict)
998
999 if oem_props is None:
1000 script.AssertSomeFingerprint(source_fp, target_fp)
1001 else:
1002 script.AssertSomeThumbprint(
1003 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1004 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1005
Doug Zongker2ea21062010-04-28 16:05:21 -07001006 metadata["pre-build"] = source_fp
1007 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001008
Doug Zongker55d93282011-01-25 17:03:34 -08001009 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001010 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1011 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001012 target_boot = common.GetBootableImage(
1013 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001014 updating_boot = (not OPTIONS.two_step and
1015 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001016
Doug Zongker55d93282011-01-25 17:03:34 -08001017 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001018 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1019 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001020 target_recovery = common.GetBootableImage(
1021 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001022 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001023
Doug Zongker881dd402009-09-20 14:03:55 -07001024 # Here's how we divide up the progress bar:
1025 # 0.1 for verifying the start state (PatchCheck calls)
1026 # 0.8 for applying patches (ApplyPatch calls)
1027 # 0.1 for unpacking verbatim files, symlinking, and doing the
1028 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001029
Michael Runge6e836112014-04-15 17:40:21 -07001030 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001031 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001032
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001033 # Two-step incremental package strategy (in chronological order,
1034 # which is *not* the order in which the generated script has
1035 # things):
1036 #
1037 # if stage is not "2/3" or "3/3":
1038 # do verification on current system
1039 # write recovery image to boot partition
1040 # set stage to "2/3"
1041 # reboot to boot partition and restart recovery
1042 # else if stage is "2/3":
1043 # write recovery image to recovery partition
1044 # set stage to "3/3"
1045 # reboot to recovery partition and restart recovery
1046 # else:
1047 # (stage must be "3/3")
1048 # perform update:
1049 # patch system files, etc.
1050 # force full install of new boot image
1051 # set up system to update recovery partition on first boot
1052 # complete script normally (allow recovery to mark itself finished and reboot)
1053
1054 if OPTIONS.two_step:
1055 if not OPTIONS.info_dict.get("multistage_support", None):
1056 assert False, "two-step packages not supported by this build"
1057 fs = OPTIONS.info_dict["fstab"]["/misc"]
1058 assert fs.fs_type.upper() == "EMMC", \
1059 "two-step packages only supported on devices with EMMC /misc partitions"
1060 bcb_dev = {"bcb_dev": fs.device}
1061 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1062 script.AppendExtra("""
1063if get_stage("%(bcb_dev)s", "stage") == "2/3" then
1064""" % bcb_dev)
1065 script.AppendExtra("sleep(20);\n");
1066 script.WriteRawImage("/recovery", "recovery.img")
1067 script.AppendExtra("""
1068set_stage("%(bcb_dev)s", "3/3");
1069reboot_now("%(bcb_dev)s", "recovery");
1070else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
1071""" % bcb_dev)
1072
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001073 script.Print("Verifying current system...")
1074
Doug Zongkere5ff5902012-01-17 10:55:37 -08001075 device_specific.IncrementalOTA_VerifyBegin()
1076
Doug Zongker881dd402009-09-20 14:03:55 -07001077 script.ShowProgress(0.1, 0)
Doug Zongker881dd402009-09-20 14:03:55 -07001078 so_far = 0
Doug Zongkereef39442009-04-02 12:14:19 -07001079
Michael Runge4038aa82013-12-13 18:06:28 -08001080 for tf, sf, size, patch_sha in patch_list:
1081 if tf.name != sf.name:
1082 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1083 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
Doug Zongker881dd402009-09-20 14:03:55 -07001084 so_far += sf.size
Doug Zongkereef39442009-04-02 12:14:19 -07001085
Doug Zongker5da317e2009-06-02 13:38:17 -07001086 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001087 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001088 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001089 print "boot target: %d source: %d diff: %d" % (
1090 target_boot.size, source_boot.size, len(d))
1091
Doug Zongker048e7ca2009-06-15 14:31:53 -07001092 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001093
Doug Zongker96a57e72010-09-26 14:57:41 -07001094 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001095
1096 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1097 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001098 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001099 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001100 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001101
1102 if patch_list or updating_recovery or updating_boot:
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001103 script.CacheFreeSpaceCheck(largest_source_size)
Doug Zongker5a482092010-02-17 16:09:18 -08001104
Doug Zongker05d3dea2009-06-22 11:32:31 -07001105 device_specific.IncrementalOTA_VerifyEnd()
1106
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001107 if OPTIONS.two_step:
1108 script.WriteRawImage("/boot", "recovery.img")
1109 script.AppendExtra("""
1110set_stage("%(bcb_dev)s", "2/3");
1111reboot_now("%(bcb_dev)s", "");
1112else
1113""" % bcb_dev)
1114
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001115 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001116
Doug Zongkere5ff5902012-01-17 10:55:37 -08001117 device_specific.IncrementalOTA_InstallBegin()
1118
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001119 if OPTIONS.two_step:
1120 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1121 script.WriteRawImage("/boot", "boot.img")
1122 print "writing full boot image (forced by two-step mode)"
1123
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001124 script.Print("Removing unneeded files...")
Doug Zongker0f3298a2009-06-30 08:16:58 -07001125 script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
1126 ["/"+i for i in sorted(source_data)
Michael Runge4038aa82013-12-13 18:06:28 -08001127 if i not in target_data and
1128 i not in renames] +
Doug Zongker3b949f02009-08-24 10:24:32 -07001129 ["/system/recovery.img"])
Doug Zongkereef39442009-04-02 12:14:19 -07001130
Doug Zongker881dd402009-09-20 14:03:55 -07001131 script.ShowProgress(0.8, 0)
1132 total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
1133 if updating_boot:
1134 total_patch_size += target_boot.size
1135 so_far = 0
1136
1137 script.Print("Patching system files...")
Doug Zongkere92f15a2011-08-26 13:46:40 -07001138 deferred_patch_list = []
1139 for item in patch_list:
Michael Runge4038aa82013-12-13 18:06:28 -08001140 tf, sf, size, _ = item
Doug Zongkere92f15a2011-08-26 13:46:40 -07001141 if tf.name == "system/build.prop":
1142 deferred_patch_list.append(item)
1143 continue
Michael Runge4038aa82013-12-13 18:06:28 -08001144 if (sf.name != tf.name):
1145 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1146 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
Doug Zongker881dd402009-09-20 14:03:55 -07001147 so_far += tf.size
1148 script.SetProgress(so_far / total_patch_size)
1149
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001150 if not OPTIONS.two_step:
1151 if updating_boot:
1152 # Produce the boot image by applying a patch to the current
1153 # contents of the boot partition, and write it back to the
1154 # partition.
1155 script.Print("Patching boot image...")
1156 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1157 % (boot_type, boot_device,
1158 source_boot.size, source_boot.sha1,
1159 target_boot.size, target_boot.sha1),
1160 "-",
1161 target_boot.size, target_boot.sha1,
1162 source_boot.sha1, "patch/boot.img.p")
1163 so_far += target_boot.size
1164 script.SetProgress(so_far / total_patch_size)
1165 print "boot image changed; including."
1166 else:
1167 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001168
1169 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001170 # Recovery is generated as a patch using both the boot image
1171 # (which contains the same linux kernel as recovery) and the file
1172 # /system/etc/recovery-resource.dat (which contains all the images
1173 # used in the recovery UI) as sources. This lets us minimize the
1174 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001175 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001176 # For older builds where recovery-resource.dat is not present, we
1177 # use only the boot image as the source.
1178
Doug Zongkerc9253822014-02-04 12:17:58 -08001179 if not target_has_recovery_patch:
1180 def output_sink(fn, data):
1181 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
1182 Item.Get("system/" + fn, dir=False)
1183
1184 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1185 target_recovery, target_boot)
1186 script.DeleteFiles(["/system/recovery-from-boot.p",
1187 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001188 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001189 else:
1190 print "recovery image unchanged; skipping."
1191
Doug Zongker881dd402009-09-20 14:03:55 -07001192 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001193
Doug Zongker1807e702012-02-28 12:21:08 -08001194 target_symlinks = CopySystemFiles(target_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -07001195
1196 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001197 temp_script = script.MakeTemporary()
Doug Zongker283e2a12010-03-15 17:52:32 -07001198 Item.GetMetadata(target_zip)
Doug Zongker73ef8252009-07-23 15:12:53 -07001199 Item.Get("system").SetPermissions(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001200
1201 # Note that this call will mess up the tree of Items, so make sure
1202 # we're done with it.
Doug Zongker1807e702012-02-28 12:21:08 -08001203 source_symlinks = CopySystemFiles(source_zip, None)
Doug Zongkereef39442009-04-02 12:14:19 -07001204 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1205
1206 # Delete all the symlinks in source that aren't in target. This
1207 # needs to happen before verbatim files are unpacked, in case a
1208 # symlink in the source is replaced by a real file in the target.
1209 to_delete = []
1210 for dest, link in source_symlinks:
1211 if link not in target_symlinks_d:
1212 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001213 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001214
1215 if verbatim_targets:
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001216 script.Print("Unpacking new files...")
1217 script.UnpackPackageDir("system", "/system")
1218
Doug Zongkerc9253822014-02-04 12:17:58 -08001219 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001220 script.Print("Unpacking new recovery...")
1221 script.UnpackPackageDir("recovery", "/system")
1222
Michael Runge4038aa82013-12-13 18:06:28 -08001223 if len(renames) > 0:
1224 script.Print("Renaming files...")
1225
1226 for src in renames:
1227 print "Renaming " + src + " to " + renames[src].name
1228 script.RenameFile(src, renames[src].name)
1229
Doug Zongker05d3dea2009-06-22 11:32:31 -07001230 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001231
1232 # Create all the symlinks that don't already exist, or point to
1233 # somewhere different than what we want. Delete each symlink before
1234 # creating it, since the 'symlink' command won't overwrite.
1235 to_create = []
1236 for dest, link in target_symlinks:
1237 if link in source_symlinks_d:
1238 if dest != source_symlinks_d[link]:
1239 to_create.append((dest, link))
1240 else:
1241 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001242 script.DeleteFiles([i[1] for i in to_create])
1243 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001244
1245 # Now that the symlinks are created, we can set all the
1246 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001247 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001248
Doug Zongker881dd402009-09-20 14:03:55 -07001249 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001250 device_specific.IncrementalOTA_InstallEnd()
1251
Doug Zongker1c390a22009-05-14 19:06:36 -07001252 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001253 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001254
Doug Zongkere92f15a2011-08-26 13:46:40 -07001255 # Patch the build.prop file last, so if something fails but the
1256 # device can still come up, it appears to be the old build and will
1257 # get set the OTA package again to retry.
1258 script.Print("Patching remaining system files...")
1259 for item in deferred_patch_list:
Michael Runge4038aa82013-12-13 18:06:28 -08001260 tf, sf, size, _ = item
1261 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
Nick Kralevich0eb17d92013-09-07 17:10:29 -07001262 script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001263
Doug Zongker922206e2014-03-04 13:16:24 -08001264 if OPTIONS.wipe_user_data:
1265 script.Print("Erasing user data...")
1266 script.FormatPartition("/data")
1267
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001268 if OPTIONS.two_step:
1269 script.AppendExtra("""
1270set_stage("%(bcb_dev)s", "");
1271endif;
1272endif;
1273""" % bcb_dev)
1274
Doug Zongker25568482014-03-03 10:21:27 -08001275 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -07001276 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001277
1278
1279def main(argv):
1280
1281 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001282 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001283 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001284 elif o in ("-k", "--package_key"):
1285 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001286 elif o in ("-i", "--incremental_from"):
1287 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001288 elif o in ("-w", "--wipe_user_data"):
1289 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001290 elif o in ("-n", "--no_prereq"):
1291 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001292 elif o in ("-o", "--oem_settings"):
1293 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001294 elif o in ("-e", "--extra_script"):
1295 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001296 elif o in ("-a", "--aslr_mode"):
1297 if a in ("on", "On", "true", "True", "yes", "Yes"):
1298 OPTIONS.aslr_mode = True
1299 else:
1300 OPTIONS.aslr_mode = False
Doug Zongker761e6422009-09-25 10:45:39 -07001301 elif o in ("--worker_threads"):
1302 OPTIONS.worker_threads = int(a)
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001303 elif o in ("-2", "--two_step"):
1304 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001305 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001306 OPTIONS.no_signing = True
Doug Zongker26e66192014-02-20 13:22:07 -08001307 elif o == "--block":
1308 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001309 elif o in ("-b", "--binary"):
1310 OPTIONS.updater_binary = a
Doug Zongkereef39442009-04-02 12:14:19 -07001311 else:
1312 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001313 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001314
1315 args = common.ParseOptions(argv, __doc__,
Michael Runge6e836112014-04-15 17:40:21 -07001316 extra_opts="b:k:i:d:wne:a:2o:",
Doug Zongkereef39442009-04-02 12:14:19 -07001317 extra_long_opts=["board_config=",
1318 "package_key=",
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001319 "incremental_from=",
Doug Zongker962069c2009-04-23 11:41:58 -07001320 "wipe_user_data",
Doug Zongker1c390a22009-05-14 19:06:36 -07001321 "no_prereq",
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001322 "extra_script=",
Hristo Bojinov96be7202010-08-02 10:26:17 -07001323 "worker_threads=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001324 "aslr_mode=",
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001325 "two_step",
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001326 "no_signing",
Doug Zongker26e66192014-02-20 13:22:07 -08001327 "block",
Doug Zongker25568482014-03-03 10:21:27 -08001328 "binary=",
Michael Runge6e836112014-04-15 17:40:21 -07001329 "oem_settings=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001330 ],
Doug Zongkereef39442009-04-02 12:14:19 -07001331 extra_option_handler=option_handler)
1332
1333 if len(args) != 2:
1334 common.Usage(__doc__)
1335 sys.exit(1)
1336
Doug Zongker1c390a22009-05-14 19:06:36 -07001337 if OPTIONS.extra_script is not None:
1338 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1339
Doug Zongkereef39442009-04-02 12:14:19 -07001340 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001341 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001342
Doug Zongkereef39442009-04-02 12:14:19 -07001343 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001344 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001345
1346 # If this image was originally labelled with SELinux contexts, make sure we
1347 # also apply the labels in our new image. During building, the "file_contexts"
1348 # is in the out/ directory tree, but for repacking from target-files.zip it's
1349 # in the root directory of the ramdisk.
1350 if "selinux_fc" in OPTIONS.info_dict:
1351 OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK",
1352 "file_contexts")
1353
Doug Zongker37974732010-09-16 17:44:38 -07001354 if OPTIONS.verbose:
1355 print "--- target info ---"
1356 common.DumpInfoDict(OPTIONS.info_dict)
1357
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001358 # If the caller explicitly specified the device-specific extensions
1359 # path via -s/--device_specific, use that. Otherwise, use
1360 # META/releasetools.py if it is present in the target target_files.
1361 # Otherwise, take the path of the file from 'tool_extensions' in the
1362 # info dict and look for that in the local filesystem, relative to
1363 # the current directory.
1364
Doug Zongker37974732010-09-16 17:44:38 -07001365 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001366 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1367 if os.path.exists(from_input):
1368 print "(using device-specific extensions from target_files)"
1369 OPTIONS.device_specific = from_input
1370 else:
1371 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1372
Doug Zongker37974732010-09-16 17:44:38 -07001373 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001374 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001375
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001376 if OPTIONS.no_signing:
1377 output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
1378 else:
1379 temp_zip_file = tempfile.NamedTemporaryFile()
1380 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1381 compression=zipfile.ZIP_DEFLATED)
Doug Zongkereef39442009-04-02 12:14:19 -07001382
1383 if OPTIONS.incremental_source is None:
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001384 WriteFullOTAPackage(input_zip, output_zip)
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001385 if OPTIONS.package_key is None:
1386 OPTIONS.package_key = OPTIONS.info_dict.get(
1387 "default_system_dev_certificate",
1388 "build/target/product/security/testkey")
Doug Zongkereef39442009-04-02 12:14:19 -07001389 else:
1390 print "unzipping source target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001391 OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
Doug Zongker37974732010-09-16 17:44:38 -07001392 OPTIONS.target_info_dict = OPTIONS.info_dict
1393 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
Doug Zongker5fad2032014-02-24 08:13:45 -08001394 if "selinux_fc" in OPTIONS.source_info_dict:
1395 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(OPTIONS.source_tmp, "BOOT", "RAMDISK",
1396 "file_contexts")
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001397 if OPTIONS.package_key is None:
Doug Zongker91b4f8a2011-09-23 12:48:33 -07001398 OPTIONS.package_key = OPTIONS.source_info_dict.get(
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001399 "default_system_dev_certificate",
1400 "build/target/product/security/testkey")
Doug Zongker37974732010-09-16 17:44:38 -07001401 if OPTIONS.verbose:
1402 print "--- source info ---"
1403 common.DumpInfoDict(OPTIONS.source_info_dict)
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001404 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001405
1406 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001407
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001408 if not OPTIONS.no_signing:
1409 SignOutput(temp_zip_file.name, args[1])
1410 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001411
1412 common.Cleanup()
1413
1414 print "done."
1415
1416
1417if __name__ == '__main__':
1418 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001419 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001420 main(sys.argv[1:])
1421 except common.ExternalError, e:
1422 print
1423 print " ERROR: %s" % (e,)
1424 print
1425 sys.exit(1)