blob: 9f701679b9ff6b504988f1f186a054c64cc0e2ad [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
Martin Blumenstingl374e1142014-05-31 20:42:55 +020074 -t (--worker_threads) <int>
75 Specifies the number of worker-threads that will be used when
76 generating patches for incremental updates (defaults to 3).
77
Doug Zongkereef39442009-04-02 12:14:19 -070078"""
79
80import sys
81
Doug Zongkercf6d5a92014-02-18 10:57:07 -080082if sys.hexversion < 0x02070000:
83 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -070084 sys.exit(1)
85
86import copy
Doug Zongkerc18736b2009-09-30 09:20:32 -070087import errno
Doug Zongkereef39442009-04-02 12:14:19 -070088import os
89import re
Doug Zongkereef39442009-04-02 12:14:19 -070090import subprocess
91import tempfile
92import time
93import zipfile
94
davidcad0bb92011-03-15 14:21:38 +000095try:
96 from hashlib import sha1 as sha1
97except ImportError:
98 from sha import sha as sha1
99
Doug Zongkereef39442009-04-02 12:14:19 -0700100import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700101import edify_generator
Geremy Condra36bd3652014-02-06 19:45:10 -0800102import build_image
Doug Zongkereef39442009-04-02 12:14:19 -0700103
104OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700105OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700106OPTIONS.incremental_source = None
107OPTIONS.require_verbatim = set()
108OPTIONS.prohibit_verbatim = set(("system/build.prop",))
109OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700110OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700111OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700112OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700113OPTIONS.aslr_mode = True
Doug Zongker761e6422009-09-25 10:45:39 -0700114OPTIONS.worker_threads = 3
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800115OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900116OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800117OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800118OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700119OPTIONS.oem_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -0700120OPTIONS.fallback_to_full = True
Doug Zongkereef39442009-04-02 12:14:19 -0700121
122def MostPopularKey(d, default):
123 """Given a dict, return the key corresponding to the largest
124 value. Returns 'default' if the dict is empty."""
125 x = [(v, k) for (k, v) in d.iteritems()]
126 if not x: return default
127 x.sort()
128 return x[-1][1]
129
130
131def IsSymlink(info):
132 """Return true if the zipfile.ZipInfo object passed in represents a
133 symlink."""
134 return (info.external_attr >> 16) == 0120777
135
Hristo Bojinov96be7202010-08-02 10:26:17 -0700136def IsRegular(info):
137 """Return true if the zipfile.ZipInfo object passed in represents a
138 symlink."""
139 return (info.external_attr >> 28) == 010
Doug Zongkereef39442009-04-02 12:14:19 -0700140
Michael Runge4038aa82013-12-13 18:06:28 -0800141def ClosestFileMatch(src, tgtfiles, existing):
142 """Returns the closest file match between a source file and list
143 of potential matches. The exact filename match is preferred,
144 then the sha1 is searched for, and finally a file with the same
145 basename is evaluated. Rename support in the updater-binary is
146 required for the latter checks to be used."""
147
148 result = tgtfiles.get("path:" + src.name)
149 if result is not None:
150 return result
151
152 if not OPTIONS.target_info_dict.get("update_rename_support", False):
153 return None
154
155 if src.size < 1000:
156 return None
157
158 result = tgtfiles.get("sha1:" + src.sha1)
159 if result is not None and existing.get(result.name) is None:
160 return result
161 result = tgtfiles.get("file:" + src.name.split("/")[-1])
162 if result is not None and existing.get(result.name) is None:
163 return result
164 return None
165
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700166class ItemSet:
167 def __init__(self, partition, fs_config):
168 self.partition = partition
169 self.fs_config = fs_config
170 self.ITEMS = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700171
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700172 def Get(self, name, dir=False):
173 if name not in self.ITEMS:
174 self.ITEMS[name] = Item(self, name, dir=dir)
175 return self.ITEMS[name]
Doug Zongkereef39442009-04-02 12:14:19 -0700176
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700177 def GetMetadata(self, input_zip):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700178 # The target_files contains a record of what the uid,
179 # gid, and mode are supposed to be.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700180 output = input_zip.read(self.fs_config)
Doug Zongkereef39442009-04-02 12:14:19 -0700181
182 for line in output.split("\n"):
183 if not line: continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700184 columns = line.split()
185 name, uid, gid, mode = columns[:4]
186 selabel = None
187 capabilities = None
188
189 # After the first 4 columns, there are a series of key=value
190 # pairs. Extract out the fields we care about.
191 for element in columns[4:]:
192 key, value = element.split("=")
193 if key == "selabel":
194 selabel = value
195 if key == "capabilities":
196 capabilities = value
197
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700198 i = self.ITEMS.get(name, None)
Doug Zongker283e2a12010-03-15 17:52:32 -0700199 if i is not None:
200 i.uid = int(uid)
201 i.gid = int(gid)
202 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700203 i.selabel = selabel
204 i.capabilities = capabilities
Doug Zongker283e2a12010-03-15 17:52:32 -0700205 if i.dir:
206 i.children.sort(key=lambda i: i.name)
207
208 # set metadata for the files generated by this script.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700209 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700210 if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700211 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700212 if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700213
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700214
215class Item:
216 """Items represent the metadata (user, group, mode) of files and
217 directories in the system image."""
218 def __init__(self, itemset, name, dir=False):
219 self.itemset = itemset
220 self.name = name
221 self.uid = None
222 self.gid = None
223 self.mode = None
224 self.selabel = None
225 self.capabilities = None
226 self.dir = dir
227
228 if name:
229 self.parent = itemset.Get(os.path.dirname(name), dir=True)
230 self.parent.children.append(self)
231 else:
232 self.parent = None
233 if dir:
234 self.children = []
235
236 def Dump(self, indent=0):
237 if self.uid is not None:
238 print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode)
239 else:
240 print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode)
241 if self.dir:
242 print "%s%s" % (" "*indent, self.descendants)
243 print "%s%s" % (" "*indent, self.best_subtree)
244 for i in self.children:
245 i.Dump(indent=indent+1)
246
Doug Zongkereef39442009-04-02 12:14:19 -0700247 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700248 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
249 all children and determine the best strategy for using set_perm_recursive and
Doug Zongkereef39442009-04-02 12:14:19 -0700250 set_perm to correctly chown/chmod all the files to their desired
251 values. Recursively calls itself for all descendants.
252
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700253 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count} counting up
Doug Zongkereef39442009-04-02 12:14:19 -0700254 all descendants of this node. (dmode or fmode may be None.) Also
255 sets the best_subtree of each directory Item to the (uid, gid,
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700256 dmode, fmode, selabel, capabilities) tuple that will match the most
257 descendants of that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700258 """
259
260 assert self.dir
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700261 d = self.descendants = {(self.uid, self.gid, self.mode, None, self.selabel, self.capabilities): 1}
Doug Zongkereef39442009-04-02 12:14:19 -0700262 for i in self.children:
263 if i.dir:
264 for k, v in i.CountChildMetadata().iteritems():
265 d[k] = d.get(k, 0) + v
266 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700267 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700268 d[k] = d.get(k, 0) + 1
269
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700270 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
271 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700272
273 # First, find the (uid, gid) pair that matches the most
274 # descendants.
275 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700276 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700277 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
278 ug = MostPopularKey(ug, (0, 0))
279
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700280 # Now find the dmode, fmode, selabel, and capabilities that match
281 # the most descendants with that (uid, gid), and choose those.
Doug Zongkereef39442009-04-02 12:14:19 -0700282 best_dmode = (0, 0755)
283 best_fmode = (0, 0644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700284 best_selabel = (0, None)
285 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700286 for k, count in d.iteritems():
287 if k[:2] != ug: continue
288 if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2])
289 if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3])
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700290 if k[4] is not None and count >= best_selabel[0]: best_selabel = (count, k[4])
291 if k[5] is not None and count >= best_capabilities[0]: best_capabilities = (count, k[5])
292 self.best_subtree = ug + (best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700293
294 return d
295
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700296 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700297 """Append set_perm/set_perm_recursive commands to 'script' to
298 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700299 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700300
301 self.CountChildMetadata()
302
303 def recurse(item, current):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700304 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple that the current
Doug Zongkereef39442009-04-02 12:14:19 -0700305 # item (and all its children) have already been set to. We only
306 # need to issue set_perm/set_perm_recursive commands if we're
307 # supposed to be something different.
308 if item.dir:
309 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700310 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700311 current = item.best_subtree
312
313 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700314 item.mode != current[2] or item.selabel != current[4] or \
315 item.capabilities != current[5]:
316 script.SetPermissions("/"+item.name, item.uid, item.gid,
317 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700318
319 for i in item.children:
320 recurse(i, current)
321 else:
322 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700323 item.mode != current[3] or item.selabel != current[4] or \
324 item.capabilities != current[5]:
325 script.SetPermissions("/"+item.name, item.uid, item.gid,
326 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700327
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700328 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700329
330
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700331def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
332 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700333 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800334 list of symlinks. output_zip may be None, in which case the copy is
335 skipped (but the other side effects still happen). substitute is an
336 optional dict of {output filename: contents} to be output instead of
337 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700338 """
339
340 symlinks = []
341
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700342 partition = itemset.partition
343
Doug Zongkereef39442009-04-02 12:14:19 -0700344 for info in input_zip.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700345 if info.filename.startswith(partition.upper() + "/"):
Doug Zongkereef39442009-04-02 12:14:19 -0700346 basefilename = info.filename[7:]
347 if IsSymlink(info):
348 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700349 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700350 else:
351 info2 = copy.copy(info)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700352 fn = info2.filename = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700353 if substitute and fn in substitute and substitute[fn] is None:
354 continue
355 if output_zip is not None:
356 if substitute and fn in substitute:
357 data = substitute[fn]
358 else:
359 data = input_zip.read(info.filename)
360 output_zip.writestr(info2, data)
361 if fn.endswith("/"):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700362 itemset.Get(fn[:-1], dir=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700363 else:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700364 itemset.Get(fn, dir=False)
Doug Zongkereef39442009-04-02 12:14:19 -0700365
366 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800367 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700368
369
Doug Zongkereef39442009-04-02 12:14:19 -0700370def SignOutput(temp_zip_name, output_zip_name):
371 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
372 pw = key_passwords[OPTIONS.package_key]
373
Doug Zongker951495f2009-08-14 12:44:19 -0700374 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
375 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700376
377
Michael Rungec6e3afd2014-05-05 11:55:47 -0700378def AppendAssertions(script, info_dict, oem_dict = None):
Michael Runge6e836112014-04-15 17:40:21 -0700379 oem_props = info_dict.get("oem_fingerprint_properties")
380 if oem_props is None:
381 device = GetBuildProp("ro.product.device", info_dict)
382 script.AssertDevice(device)
383 else:
384 if oem_dict is None:
385 raise common.ExternalError("No OEM file provided to answer expected assertions")
386 for prop in oem_props.split():
387 if oem_dict.get(prop) is None:
388 raise common.ExternalError("The OEM file is missing the property %s" % prop)
389 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700390
Doug Zongkereef39442009-04-02 12:14:19 -0700391
Doug Zongkerc9253822014-02-04 12:17:58 -0800392def HasRecoveryPatch(target_files_zip):
393 try:
394 target_files_zip.getinfo("SYSTEM/recovery-from-boot.p")
395 return True
396 except KeyError:
397 return False
Doug Zongker73ef8252009-07-23 15:12:53 -0700398
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700399def HasVendorPartition(target_files_zip):
400 try:
401 target_files_zip.getinfo("VENDOR/")
402 return True
403 except KeyError:
404 return False
405
Michael Runge6e836112014-04-15 17:40:21 -0700406def GetOemProperty(name, oem_props, oem_dict, info_dict):
407 if oem_props is not None and name in oem_props:
408 return oem_dict[name]
409 return GetBuildProp(name, info_dict)
410
411
412def CalculateFingerprint(oem_props, oem_dict, info_dict):
413 if oem_props is None:
414 return GetBuildProp("ro.build.fingerprint", info_dict)
415 return "%s/%s/%s:%s" % (
416 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
417 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
418 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
419 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700420
Doug Zongker3c84f562014-07-31 11:06:30 -0700421def GetImage(which, tmpdir, info_dict):
422 # Return (mapdata, data) for the given image. which should be
423 # "system" or "vendor".
424
425 assert which in ("system", "vendor")
426
427 path = os.path.join(tmpdir, "IMAGES", which + ".img")
428 if os.path.exists(path):
429 print "using %s.img from target-files" % (which,)
430
431 # This is a 'new' target-files, which already has the image in it.
432 # The image is a sparse image, though, so we need to unsparse it
433 # and extract the map data.
434
435 success, name = build_image.UnsparseImage(path, replace=False)
436 if not success:
437 assert False, "unsparsing " + which + ".img failed"
438
439 mmap = tempfile.NamedTemporaryFile()
440 mimg = tempfile.NamedTemporaryFile(delete=False)
441 success = build_image.MappedUnsparseImage(
442 path, name, mmap.name, mimg.name)
443 if not success:
444 assert False, "creating sparse map failed"
445 os.unlink(name)
446 name = mimg.name
447
448 with open(mmap.name) as f:
449 mapdata = f.read()
450
451 try:
452 with open(name) as f:
453 data = f.read()
454 finally:
455 os.unlink(name)
456
457 print "unsparsed data sha1 is " + sha1(data).hexdigest()
458 return mapdata, data
459
460 else:
461 print "building %s.img from target-files" % (which,)
462
463 # This is an 'old' target-files, which does not contain images
464 # already built. Build them.
465
466 import add_img_to_target_files
467 if which == "system":
468 mapdata, data = add_img_to_target_files.BuildSystem(
469 tmpdir, info_dict, sparse=False, map_file=True)
470 elif which == "vendor":
471 mapdata, data = add_img_to_target_files.BuildVendor(
472 tmpdir, info_dict, sparse=False, map_file=True)
473
474 print "built data sha1 is " + sha1(data).hexdigest()
475 return mapdata, data
476
477
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700478def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700479 # TODO: how to determine this? We don't know what version it will
480 # be installed on top of. For now, we expect the API just won't
481 # change very often.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700482 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700483
Michael Runge6e836112014-04-15 17:40:21 -0700484 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
485 oem_dict = None
486 if oem_props is not None:
487 if OPTIONS.oem_source is None:
488 raise common.ExternalError("OEM source required for this build")
489 script.Mount("/oem")
490 oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
491
492 metadata = {"post-build": CalculateFingerprint(
493 oem_props, oem_dict, OPTIONS.info_dict),
494 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700495 OPTIONS.info_dict),
496 "post-timestamp": GetBuildProp("ro.build.date.utc",
497 OPTIONS.info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700498 }
499
Doug Zongker05d3dea2009-06-22 11:32:31 -0700500 device_specific = common.DeviceSpecificParams(
501 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700502 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700503 output_zip=output_zip,
504 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700505 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700506 metadata=metadata,
507 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700508
Doug Zongkerc9253822014-02-04 12:17:58 -0800509 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800510 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800511
Doug Zongker962069c2009-04-23 11:41:58 -0700512 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700513 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700514 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
515 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700516
Michael Runge6e836112014-04-15 17:40:21 -0700517 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700518 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800519
520 # Two-step package strategy (in chronological order, which is *not*
521 # the order in which the generated script has things):
522 #
523 # if stage is not "2/3" or "3/3":
524 # write recovery image to boot partition
525 # set stage to "2/3"
526 # reboot to boot partition and restart recovery
527 # else if stage is "2/3":
528 # write recovery image to recovery partition
529 # set stage to "3/3"
530 # reboot to recovery partition and restart recovery
531 # else:
532 # (stage must be "3/3")
533 # set stage to ""
534 # do normal full package installation:
535 # wipe and install system, boot image, etc.
536 # set up system to update recovery partition on first boot
537 # complete script normally (allow recovery to mark itself finished and reboot)
538
539 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
540 OPTIONS.input_tmp, "RECOVERY")
541 if OPTIONS.two_step:
542 if not OPTIONS.info_dict.get("multistage_support", None):
543 assert False, "two-step packages not supported by this build"
544 fs = OPTIONS.info_dict["fstab"]["/misc"]
545 assert fs.fs_type.upper() == "EMMC", \
546 "two-step packages only supported on devices with EMMC /misc partitions"
547 bcb_dev = {"bcb_dev": fs.device}
548 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
549 script.AppendExtra("""
550if get_stage("%(bcb_dev)s", "stage") == "2/3" then
551""" % bcb_dev)
552 script.WriteRawImage("/recovery", "recovery.img")
553 script.AppendExtra("""
554set_stage("%(bcb_dev)s", "3/3");
555reboot_now("%(bcb_dev)s", "recovery");
556else if get_stage("%(bcb_dev)s", "stage") == "3/3" then
557""" % bcb_dev)
558
Doug Zongkere5ff5902012-01-17 10:55:37 -0800559 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700560
Doug Zongker01ce19c2014-02-04 13:48:15 -0800561 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700562
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700563 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800564 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700565 if HasVendorPartition(input_zip):
566 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700567
Kenny Rootf32dc712012-04-08 10:42:34 -0700568 if "selinux_fc" in OPTIONS.info_dict:
569 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500570
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700571 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700572 script.ShowProgress(system_progress, 0)
Doug Zongker26e66192014-02-20 13:22:07 -0800573 if block_based:
Doug Zongker3c84f562014-07-31 11:06:30 -0700574 mapdata, data = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
Doug Zongker5fad2032014-02-24 08:13:45 -0800575
576 common.ZipWriteStr(output_zip, "system.map", mapdata)
577 common.ZipWriteStr(output_zip, "system.muimg", data)
578 script.WipeBlockDevice("/system")
579 script.WriteRawImage("/system", "system.muimg", mapfn="system.map")
Doug Zongker01ce19c2014-02-04 13:48:15 -0800580 else:
581 script.FormatPartition("/system")
582 script.Mount("/system")
583 if not has_recovery_patch:
584 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800585 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700586
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700587 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800588 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700589
Doug Zongker55d93282011-01-25 17:03:34 -0800590 boot_img = common.GetBootableImage("boot.img", "boot.img",
591 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800592
Doug Zongker91a99c22014-05-09 13:15:01 -0700593 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800594 def output_sink(fn, data):
595 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700596 system_items.Get("system/" + fn, dir=False)
Doug Zongkerc9253822014-02-04 12:17:58 -0800597
598 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
599 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700600
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700601 system_items.GetMetadata(input_zip)
602 system_items.Get("system").SetPermissions(script)
603
604 if HasVendorPartition(input_zip):
605 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
606 script.ShowProgress(0.1, 0)
607
608 if block_based:
Doug Zongker3c84f562014-07-31 11:06:30 -0700609 mapdata, data = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700610
611 common.ZipWriteStr(output_zip, "vendor.map", mapdata)
612 common.ZipWriteStr(output_zip, "vendor.muimg", data)
613 script.WipeBlockDevice("/vendor")
614 script.WriteRawImage("/vendor", "vendor.muimg", mapfn="vendor.map")
615 else:
616 script.FormatPartition("/vendor")
617 script.Mount("/vendor")
618 script.UnpackPackageDir("vendor", "/vendor")
619
620 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
621 script.MakeSymlinks(symlinks)
622
623 vendor_items.GetMetadata(input_zip)
624 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700625
Doug Zongker37974732010-09-16 17:44:38 -0700626 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700627 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700628
Doug Zongker01ce19c2014-02-04 13:48:15 -0800629 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700630 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700631
Doug Zongker01ce19c2014-02-04 13:48:15 -0800632 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700633 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700634
Doug Zongker1c390a22009-05-14 19:06:36 -0700635 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700636 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700637
Doug Zongker14833602010-02-02 13:12:04 -0800638 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800639
Doug Zongker922206e2014-03-04 13:16:24 -0800640 if OPTIONS.wipe_user_data:
641 script.ShowProgress(0.1, 10)
642 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700643
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800644 if OPTIONS.two_step:
645 script.AppendExtra("""
646set_stage("%(bcb_dev)s", "");
647""" % bcb_dev)
648 script.AppendExtra("else\n")
649 script.WriteRawImage("/boot", "recovery.img")
650 script.AppendExtra("""
651set_stage("%(bcb_dev)s", "2/3");
652reboot_now("%(bcb_dev)s", "");
653endif;
654endif;
655""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800656 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700657 WriteMetadata(metadata, output_zip)
658
Stephen Smalley56882bf2012-02-09 13:36:21 -0500659def WritePolicyConfig(file_context, output_zip):
660 f = open(file_context, 'r');
661 basename = os.path.basename(file_context)
662 common.ZipWriteStr(output_zip, basename, f.read())
663
Doug Zongker2ea21062010-04-28 16:05:21 -0700664
665def WriteMetadata(metadata, output_zip):
666 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
667 "".join(["%s=%s\n" % kv
668 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700669
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700670def LoadPartitionFiles(z, partition):
671 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700672 ZipFile, and return a dict of {filename: File object}."""
673 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700674 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700675 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700676 if info.filename.startswith(prefix) and not IsSymlink(info):
Hristo Bojinov96be7202010-08-02 10:26:17 -0700677 basefilename = info.filename[7:]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700678 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700679 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700680 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800681 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700682
683
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700684def GetBuildProp(prop, info_dict):
685 """Return the fingerprint of the build of a given target-files info_dict."""
686 try:
687 return info_dict.get("build.prop", {})[prop]
688 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700689 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700690
Michael Runge4038aa82013-12-13 18:06:28 -0800691def AddToKnownPaths(filename, known_paths):
692 if filename[-1] == "/":
693 return
694 dirs = filename.split("/")[:-1]
695 while len(dirs) > 0:
696 path = "/".join(dirs)
697 if path in known_paths:
698 break;
699 known_paths.add(path)
700 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700701
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700702class BlockDifference:
Doug Zongker3c84f562014-07-31 11:06:30 -0700703 def __init__(self, partition, output_zip):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700704 with tempfile.NamedTemporaryFile() as src_file:
705 with tempfile.NamedTemporaryFile() as tgt_file:
706 print "building source " + partition + " image..."
707 src_file = tempfile.NamedTemporaryFile()
Doug Zongker3c84f562014-07-31 11:06:30 -0700708 src_mapdata, src_data = GetImage(partition,
709 OPTIONS.source_tmp,
710 OPTIONS.source_info_dict)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700711
712 self.src_sha1 = sha1(src_data).hexdigest()
713 print "source " + partition + " sha1:", self.src_sha1
714 src_file.write(src_data)
715
716 print "building target " + partition + " image..."
717 tgt_file = tempfile.NamedTemporaryFile()
Doug Zongker3c84f562014-07-31 11:06:30 -0700718 tgt_mapdata, tgt_data = GetImage(partition,
719 OPTIONS.target_tmp,
720 OPTIONS.target_info_dict)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700721 self.tgt_sha1 = sha1(tgt_data).hexdigest()
722 print "target " + partition + " sha1:", self.tgt_sha1
723 tgt_len = len(tgt_data)
724 tgt_file.write(tgt_data)
725
726 system_type, self.device = common.GetTypeAndDevice("/" + partition,
727 OPTIONS.info_dict)
728 self.patch = common.MakePartitionPatch(src_file, tgt_file, partition)
729
730 TestBlockPatch(src_data, src_mapdata, self.patch.data,
731 tgt_mapdata, self.tgt_sha1)
732 src_data = None
733 tgt_data = None
734
735 self.patch.AddToZip(output_zip, compression=zipfile.ZIP_STORED)
736 self.src_mapfilename = self.patch.name + ".src.map"
737 common.ZipWriteStr(output_zip, self.src_mapfilename, src_mapdata)
738 self.tgt_mapfilename = self.patch.name + ".tgt.map"
739 common.ZipWriteStr(output_zip, self.tgt_mapfilename, tgt_mapdata)
740
Geremy Condra36bd3652014-02-06 19:45:10 -0800741def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
742 source_version = OPTIONS.source_info_dict["recovery_api_version"]
743 target_version = OPTIONS.target_info_dict["recovery_api_version"]
744
745 if source_version == 0:
746 print ("WARNING: generating edify script for a source that "
747 "can't install it.")
748 script = edify_generator.EdifyGenerator(source_version,
749 OPTIONS.target_info_dict)
750
751 metadata = {"pre-device": GetBuildProp("ro.product.device",
752 OPTIONS.source_info_dict),
753 "post-timestamp": GetBuildProp("ro.build.date.utc",
754 OPTIONS.target_info_dict),
755 }
756
757 device_specific = common.DeviceSpecificParams(
758 source_zip=source_zip,
759 source_version=source_version,
760 target_zip=target_zip,
761 target_version=target_version,
762 output_zip=output_zip,
763 script=script,
764 metadata=metadata,
765 info_dict=OPTIONS.info_dict)
766
767 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
768 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
769 metadata["pre-build"] = source_fp
770 metadata["post-build"] = target_fp
771
772 source_boot = common.GetBootableImage(
773 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
774 OPTIONS.source_info_dict)
775 target_boot = common.GetBootableImage(
776 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
777 updating_boot = (not OPTIONS.two_step and
778 (source_boot.data != target_boot.data))
779
780 source_recovery = common.GetBootableImage(
781 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
782 OPTIONS.source_info_dict)
783 target_recovery = common.GetBootableImage(
784 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
785 updating_recovery = (source_recovery.data != target_recovery.data)
786
Doug Zongker3c84f562014-07-31 11:06:30 -0700787 system_diff = BlockDifference("system", output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700788 if HasVendorPartition(target_zip):
789 if not HasVendorPartition(source_zip):
790 raise RuntimeError("can't generate incremental that adds /vendor")
Doug Zongker3c84f562014-07-31 11:06:30 -0700791 vendor_diff = BlockDifference("vendor", output_zip)
Geremy Condra36bd3652014-02-06 19:45:10 -0800792
Michael Rungec6e3afd2014-05-05 11:55:47 -0700793 oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
794 oem_dict = None
795 if oem_props is not None:
796 if OPTIONS.oem_source is None:
797 raise common.ExternalError("OEM source required for this build")
798 script.Mount("/oem")
799 oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
800
801 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800802 device_specific.IncrementalOTA_Assertions()
803
804 # Two-step incremental package strategy (in chronological order,
805 # which is *not* the order in which the generated script has
806 # things):
807 #
808 # if stage is not "2/3" or "3/3":
809 # do verification on current system
810 # write recovery image to boot partition
811 # set stage to "2/3"
812 # reboot to boot partition and restart recovery
813 # else if stage is "2/3":
814 # write recovery image to recovery partition
815 # set stage to "3/3"
816 # reboot to recovery partition and restart recovery
817 # else:
818 # (stage must be "3/3")
819 # perform update:
820 # patch system files, etc.
821 # force full install of new boot image
822 # set up system to update recovery partition on first boot
823 # complete script normally (allow recovery to mark itself finished and reboot)
824
825 if OPTIONS.two_step:
826 if not OPTIONS.info_dict.get("multistage_support", None):
827 assert False, "two-step packages not supported by this build"
828 fs = OPTIONS.info_dict["fstab"]["/misc"]
829 assert fs.fs_type.upper() == "EMMC", \
830 "two-step packages only supported on devices with EMMC /misc partitions"
831 bcb_dev = {"bcb_dev": fs.device}
832 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
833 script.AppendExtra("""
834if get_stage("%(bcb_dev)s", "stage") == "2/3" then
835""" % bcb_dev)
836 script.AppendExtra("sleep(20);\n");
837 script.WriteRawImage("/recovery", "recovery.img")
838 script.AppendExtra("""
839set_stage("%(bcb_dev)s", "3/3");
840reboot_now("%(bcb_dev)s", "recovery");
841else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
842""" % bcb_dev)
843
844 script.Print("Verifying current system...")
845
846 device_specific.IncrementalOTA_VerifyBegin()
847
Michael Rungec6e3afd2014-05-05 11:55:47 -0700848 if oem_props is None:
849 script.AssertSomeFingerprint(source_fp, target_fp)
850 else:
851 script.AssertSomeThumbprint(
852 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
853 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800854
855 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700856 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800857 d = common.Difference(target_boot, source_boot)
858 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700859 if d is None:
860 include_full_boot = True
861 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
862 else:
863 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800864
Doug Zongkerf8340082014-08-05 10:39:37 -0700865 print "boot target: %d source: %d diff: %d" % (
866 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800867
Doug Zongkerf8340082014-08-05 10:39:37 -0700868 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800869
Doug Zongkerf8340082014-08-05 10:39:37 -0700870 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
871 (boot_type, boot_device,
872 source_boot.size, source_boot.sha1,
873 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800874
875 device_specific.IncrementalOTA_VerifyEnd()
876
877 if OPTIONS.two_step:
878 script.WriteRawImage("/boot", "recovery.img")
879 script.AppendExtra("""
880set_stage("%(bcb_dev)s", "2/3");
881reboot_now("%(bcb_dev)s", "");
882else
883""" % bcb_dev)
884
885 script.Comment("---- start making changes here ----")
886
887 device_specific.IncrementalOTA_InstallBegin()
888
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700889 if HasVendorPartition(target_zip):
890 script.Print("Patching vendor image...")
891 script.ShowProgress(0.1, 0)
892 script.Syspatch(vendor_diff.device,
893 vendor_diff.tgt_mapfilename, vendor_diff.tgt_sha1,
894 vendor_diff.src_mapfilename, vendor_diff.src_sha1,
895 vendor_diff.patch.name)
896 sys_progress = 0.8
897 else:
898 sys_progress = 0.9
899
Geremy Condra36bd3652014-02-06 19:45:10 -0800900 script.Print("Patching system image...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700901 script.ShowProgress(sys_progress, 0)
902 script.Syspatch(system_diff.device,
903 system_diff.tgt_mapfilename, system_diff.tgt_sha1,
904 system_diff.src_mapfilename, system_diff.src_sha1,
905 system_diff.patch.name)
Geremy Condra36bd3652014-02-06 19:45:10 -0800906
907 if OPTIONS.two_step:
908 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
909 script.WriteRawImage("/boot", "boot.img")
910 print "writing full boot image (forced by two-step mode)"
911
912 if not OPTIONS.two_step:
913 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700914 if include_full_boot:
915 print "boot image changed; including full."
916 script.Print("Installing boot image...")
917 script.WriteRawImage("/boot", "boot.img")
918 else:
919 # Produce the boot image by applying a patch to the current
920 # contents of the boot partition, and write it back to the
921 # partition.
922 print "boot image changed; including patch."
923 script.Print("Patching boot image...")
924 script.ShowProgress(0.1, 10)
925 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
926 % (boot_type, boot_device,
927 source_boot.size, source_boot.sha1,
928 target_boot.size, target_boot.sha1),
929 "-",
930 target_boot.size, target_boot.sha1,
931 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800932 else:
933 print "boot image unchanged; skipping."
934
935 # Do device-specific installation (eg, write radio image).
936 device_specific.IncrementalOTA_InstallEnd()
937
938 if OPTIONS.extra_script is not None:
939 script.AppendExtra(OPTIONS.extra_script)
940
Doug Zongker922206e2014-03-04 13:16:24 -0800941 if OPTIONS.wipe_user_data:
942 script.Print("Erasing user data...")
943 script.FormatPartition("/data")
944
Geremy Condra36bd3652014-02-06 19:45:10 -0800945 if OPTIONS.two_step:
946 script.AppendExtra("""
947set_stage("%(bcb_dev)s", "");
948endif;
949endif;
950""" % bcb_dev)
951
952 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800953 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800954 WriteMetadata(metadata, output_zip)
955
Doug Zongker32b527d2014-03-04 10:03:02 -0800956def ParseMap(map_str):
957 x = map_str.split()
958 assert int(x[0]) == 4096
959 assert int(x[1]) == len(x)-2
960 return int(x[0]), [int(i) for i in x[2:]]
961
962def TestBlockPatch(src_muimg, src_map, patch_data, tgt_map, tgt_sha1):
963 src_blksize, src_regions = ParseMap(src_map)
964 tgt_blksize, tgt_regions = ParseMap(tgt_map)
965
966 with tempfile.NamedTemporaryFile() as src_file,\
967 tempfile.NamedTemporaryFile() as patch_file,\
Doug Zongker32b527d2014-03-04 10:03:02 -0800968 tempfile.NamedTemporaryFile() as src_map_file,\
969 tempfile.NamedTemporaryFile() as tgt_map_file:
970
971 src_total = sum(src_regions) * src_blksize
972 src_file.truncate(src_total)
973 p = 0
974 for i in range(0, len(src_regions), 2):
975 c, dc = src_regions[i:i+2]
976 src_file.write(src_muimg[p:(p+c*src_blksize)])
977 p += c*src_blksize
978 src_file.seek(dc*src_blksize, 1)
979 assert src_file.tell() == src_total
980
981 patch_file.write(patch_data)
982
Doug Zongker32b527d2014-03-04 10:03:02 -0800983 src_map_file.write(src_map)
984 tgt_map_file.write(tgt_map)
985
986 src_file.flush()
987 src_map_file.flush()
988 patch_file.flush()
Doug Zongker32b527d2014-03-04 10:03:02 -0800989 tgt_map_file.flush()
990
991 p = common.Run(["syspatch_host", src_file.name, src_map_file.name,
Doug Zongker1113e382014-06-13 10:38:32 -0700992 patch_file.name, src_file.name, tgt_map_file.name],
Doug Zongker32b527d2014-03-04 10:03:02 -0800993 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
994 stdoutdata, _ = p.communicate()
995 if p.returncode != 0:
996 print stdoutdata
997 raise ValueError("failed to reconstruct target system image from patch")
998
999 h = sha1()
Doug Zongker1113e382014-06-13 10:38:32 -07001000 src_file.seek(0, 0)
Doug Zongker32b527d2014-03-04 10:03:02 -08001001 for i in range(0, len(tgt_regions), 2):
1002 c, dc = tgt_regions[i:i+2]
Doug Zongker1113e382014-06-13 10:38:32 -07001003 h.update(src_file.read(c*tgt_blksize))
1004 src_file.seek(dc*tgt_blksize, 1)
Doug Zongker32b527d2014-03-04 10:03:02 -08001005
1006 if h.hexdigest() != tgt_sha1:
1007 raise ValueError("patch reconstructed incorrect target system image")
1008
1009 print "test of system image patch succeeded"
1010
1011
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001012class FileDifference:
1013 def __init__(self, partition, source_zip, target_zip, output_zip):
1014 print "Loading target..."
1015 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
1016 print "Loading source..."
1017 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
1018
1019 self.verbatim_targets = verbatim_targets = []
1020 self.patch_list = patch_list = []
1021 diffs = []
1022 self.renames = renames = {}
1023 known_paths = set()
1024 largest_source_size = 0
1025
1026 matching_file_cache = {}
1027 for fn, sf in source_data.items():
1028 assert fn == sf.name
1029 matching_file_cache["path:" + fn] = sf
1030 if fn in target_data.keys():
1031 AddToKnownPaths(fn, known_paths)
1032 # Only allow eligibility for filename/sha matching
1033 # if there isn't a perfect path match.
1034 if target_data.get(sf.name) is None:
1035 matching_file_cache["file:" + fn.split("/")[-1]] = sf
1036 matching_file_cache["sha:" + sf.sha1] = sf
1037
1038 for fn in sorted(target_data.keys()):
1039 tf = target_data[fn]
1040 assert fn == tf.name
1041 sf = ClosestFileMatch(tf, matching_file_cache, renames)
1042 if sf is not None and sf.name != tf.name:
1043 print "File has moved from " + sf.name + " to " + tf.name
1044 renames[sf.name] = tf
1045
1046 if sf is None or fn in OPTIONS.require_verbatim:
1047 # This file should be included verbatim
1048 if fn in OPTIONS.prohibit_verbatim:
1049 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
1050 print "send", fn, "verbatim"
1051 tf.AddToZip(output_zip)
1052 verbatim_targets.append((fn, tf.size))
1053 if fn in target_data.keys():
1054 AddToKnownPaths(fn, known_paths)
1055 elif tf.sha1 != sf.sha1:
1056 # File is different; consider sending as a patch
1057 diffs.append(common.Difference(tf, sf))
1058 else:
1059 # Target file data identical to source (may still be renamed)
1060 pass
1061
1062 common.ComputeDifferences(diffs)
1063
1064 for diff in diffs:
1065 tf, sf, d = diff.GetPatch()
1066 path = "/".join(tf.name.split("/")[:-1])
1067 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
1068 path not in known_paths:
1069 # patch is almost as big as the file; don't bother patching
1070 # or a patch + rename cannot take place due to the target
1071 # directory not existing
1072 tf.AddToZip(output_zip)
1073 verbatim_targets.append((tf.name, tf.size))
1074 if sf.name in renames:
1075 del renames[sf.name]
1076 AddToKnownPaths(tf.name, known_paths)
1077 else:
1078 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1079 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1080 largest_source_size = max(largest_source_size, sf.size)
1081
1082 self.largest_source_size = largest_source_size
1083
1084 def EmitVerification(self, script):
1085 so_far = 0
1086 for tf, sf, size, patch_sha in self.patch_list:
1087 if tf.name != sf.name:
1088 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1089 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1090 so_far += sf.size
1091 return so_far
1092
1093 def RemoveUnneededFiles(self, script, extras=()):
1094 script.DeleteFiles(["/"+i[0] for i in self.verbatim_targets] +
1095 ["/"+i for i in sorted(self.source_data)
1096 if i not in self.target_data and
1097 i not in self.renames] +
1098 list(extras))
1099
1100 def TotalPatchSize(self):
1101 return sum(i[1].size for i in self.patch_list)
1102
1103 def EmitPatches(self, script, total_patch_size, so_far):
1104 self.deferred_patch_list = deferred_patch_list = []
1105 for item in self.patch_list:
1106 tf, sf, size, _ = item
1107 if tf.name == "system/build.prop":
1108 deferred_patch_list.append(item)
1109 continue
1110 if (sf.name != tf.name):
1111 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1112 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
1113 so_far += tf.size
1114 script.SetProgress(so_far / total_patch_size)
1115 return so_far
1116
1117 def EmitDeferredPatches(self, script):
1118 for item in self.deferred_patch_list:
1119 tf, sf, size, _ = item
1120 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
1121 script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None)
1122
1123 def EmitRenames(self, script):
1124 if len(self.renames) > 0:
1125 script.Print("Renaming files...")
1126 for src, tgt in self.renames.iteritems():
1127 print "Renaming " + src + " to " + tgt.name
1128 script.RenameFile(src, tgt.name)
1129
1130
1131
1132
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001133def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001134 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1135 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1136
Doug Zongker26e66192014-02-20 13:22:07 -08001137 if (OPTIONS.block_based and
1138 target_has_recovery_patch and
1139 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001140 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1141
Doug Zongker37974732010-09-16 17:44:38 -07001142 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1143 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001144
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001145 if source_version == 0:
1146 print ("WARNING: generating edify script for a source that "
1147 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -07001148 script = edify_generator.EdifyGenerator(source_version,
1149 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -07001150
Michael Runge6e836112014-04-15 17:40:21 -07001151 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
1152 oem_dict = None
1153 if oem_props is not None:
1154 if OPTIONS.oem_source is None:
1155 raise common.ExternalError("OEM source required for this build")
1156 script.Mount("/oem")
1157 oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
1158
1159 metadata = {"pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -07001160 OPTIONS.source_info_dict),
1161 "post-timestamp": GetBuildProp("ro.build.date.utc",
1162 OPTIONS.target_info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -07001163 }
1164
Doug Zongker05d3dea2009-06-22 11:32:31 -07001165 device_specific = common.DeviceSpecificParams(
1166 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001167 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001168 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001169 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001170 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001171 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001172 metadata=metadata,
1173 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001174
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001175 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge6e836112014-04-15 17:40:21 -07001176 script.Mount("/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001177 if HasVendorPartition(target_zip):
1178 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
1179 script.Mount("/vendor")
1180 else:
1181 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001182
1183 target_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.target_info_dict)
1184 source_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.source_info_dict)
1185
1186 if oem_props is None:
1187 script.AssertSomeFingerprint(source_fp, target_fp)
1188 else:
1189 script.AssertSomeThumbprint(
1190 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1191 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1192
Doug Zongker2ea21062010-04-28 16:05:21 -07001193 metadata["pre-build"] = source_fp
1194 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001195
Doug Zongker55d93282011-01-25 17:03:34 -08001196 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001197 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1198 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001199 target_boot = common.GetBootableImage(
1200 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001201 updating_boot = (not OPTIONS.two_step and
1202 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001203
Doug Zongker55d93282011-01-25 17:03:34 -08001204 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001205 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1206 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001207 target_recovery = common.GetBootableImage(
1208 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001209 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001210
Doug Zongker881dd402009-09-20 14:03:55 -07001211 # Here's how we divide up the progress bar:
1212 # 0.1 for verifying the start state (PatchCheck calls)
1213 # 0.8 for applying patches (ApplyPatch calls)
1214 # 0.1 for unpacking verbatim files, symlinking, and doing the
1215 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001216
Michael Runge6e836112014-04-15 17:40:21 -07001217 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001218 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001219
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001220 # Two-step incremental package strategy (in chronological order,
1221 # which is *not* the order in which the generated script has
1222 # things):
1223 #
1224 # if stage is not "2/3" or "3/3":
1225 # do verification on current system
1226 # write recovery image to boot partition
1227 # set stage to "2/3"
1228 # reboot to boot partition and restart recovery
1229 # else if stage is "2/3":
1230 # write recovery image to recovery partition
1231 # set stage to "3/3"
1232 # reboot to recovery partition and restart recovery
1233 # else:
1234 # (stage must be "3/3")
1235 # perform update:
1236 # patch system files, etc.
1237 # force full install of new boot image
1238 # set up system to update recovery partition on first boot
1239 # complete script normally (allow recovery to mark itself finished and reboot)
1240
1241 if OPTIONS.two_step:
1242 if not OPTIONS.info_dict.get("multistage_support", None):
1243 assert False, "two-step packages not supported by this build"
1244 fs = OPTIONS.info_dict["fstab"]["/misc"]
1245 assert fs.fs_type.upper() == "EMMC", \
1246 "two-step packages only supported on devices with EMMC /misc partitions"
1247 bcb_dev = {"bcb_dev": fs.device}
1248 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1249 script.AppendExtra("""
1250if get_stage("%(bcb_dev)s", "stage") == "2/3" then
1251""" % bcb_dev)
1252 script.AppendExtra("sleep(20);\n");
1253 script.WriteRawImage("/recovery", "recovery.img")
1254 script.AppendExtra("""
1255set_stage("%(bcb_dev)s", "3/3");
1256reboot_now("%(bcb_dev)s", "recovery");
1257else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
1258""" % bcb_dev)
1259
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001260 script.Print("Verifying current system...")
1261
Doug Zongkere5ff5902012-01-17 10:55:37 -08001262 device_specific.IncrementalOTA_VerifyBegin()
1263
Doug Zongker881dd402009-09-20 14:03:55 -07001264 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001265 so_far = system_diff.EmitVerification(script)
1266 if vendor_diff:
1267 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001268
Doug Zongker5da317e2009-06-02 13:38:17 -07001269 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001270 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001271 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001272 print "boot target: %d source: %d diff: %d" % (
1273 target_boot.size, source_boot.size, len(d))
1274
Doug Zongker048e7ca2009-06-15 14:31:53 -07001275 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001276
Doug Zongker96a57e72010-09-26 14:57:41 -07001277 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001278
1279 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1280 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001281 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001282 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001283 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001284
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001285 size = []
1286 if system_diff.patch_list: size.append(system_diff.largest_source_size)
1287 if vendor_diff:
1288 if vendor_diff.patch_list: size.append(vendor_diff.largest_source_size)
1289 if size or updating_recovery or updating_boot:
1290 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001291
Doug Zongker05d3dea2009-06-22 11:32:31 -07001292 device_specific.IncrementalOTA_VerifyEnd()
1293
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001294 if OPTIONS.two_step:
1295 script.WriteRawImage("/boot", "recovery.img")
1296 script.AppendExtra("""
1297set_stage("%(bcb_dev)s", "2/3");
1298reboot_now("%(bcb_dev)s", "");
1299else
1300""" % bcb_dev)
1301
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001302 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001303
Doug Zongkere5ff5902012-01-17 10:55:37 -08001304 device_specific.IncrementalOTA_InstallBegin()
1305
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001306 if OPTIONS.two_step:
1307 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1308 script.WriteRawImage("/boot", "boot.img")
1309 print "writing full boot image (forced by two-step mode)"
1310
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001311 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001312 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1313 if vendor_diff:
1314 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001315
Doug Zongker881dd402009-09-20 14:03:55 -07001316 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001317 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1318 if vendor_diff:
1319 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001320 if updating_boot:
1321 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001322
1323 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001324 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1325 if vendor_diff:
1326 script.Print("Patching vendor files...")
1327 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001328
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001329 if not OPTIONS.two_step:
1330 if updating_boot:
1331 # Produce the boot image by applying a patch to the current
1332 # contents of the boot partition, and write it back to the
1333 # partition.
1334 script.Print("Patching boot image...")
1335 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1336 % (boot_type, boot_device,
1337 source_boot.size, source_boot.sha1,
1338 target_boot.size, target_boot.sha1),
1339 "-",
1340 target_boot.size, target_boot.sha1,
1341 source_boot.sha1, "patch/boot.img.p")
1342 so_far += target_boot.size
1343 script.SetProgress(so_far / total_patch_size)
1344 print "boot image changed; including."
1345 else:
1346 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001347
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001348 system_items = ItemSet("system", "META/filesystem_config.txt")
1349 if vendor_diff:
1350 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1351
Doug Zongkereef39442009-04-02 12:14:19 -07001352 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001353 # Recovery is generated as a patch using both the boot image
1354 # (which contains the same linux kernel as recovery) and the file
1355 # /system/etc/recovery-resource.dat (which contains all the images
1356 # used in the recovery UI) as sources. This lets us minimize the
1357 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001358 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001359 # For older builds where recovery-resource.dat is not present, we
1360 # use only the boot image as the source.
1361
Doug Zongkerc9253822014-02-04 12:17:58 -08001362 if not target_has_recovery_patch:
1363 def output_sink(fn, data):
1364 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001365 system_items.Get("system/" + fn, dir=False)
Doug Zongkerc9253822014-02-04 12:17:58 -08001366
1367 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1368 target_recovery, target_boot)
1369 script.DeleteFiles(["/system/recovery-from-boot.p",
1370 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001371 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001372 else:
1373 print "recovery image unchanged; skipping."
1374
Doug Zongker881dd402009-09-20 14:03:55 -07001375 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001376
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001377 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1378 if vendor_diff:
1379 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1380
1381 temp_script = script.MakeTemporary()
1382 system_items.GetMetadata(target_zip)
1383 system_items.Get("system").SetPermissions(temp_script)
1384 if vendor_diff:
1385 vendor_items.GetMetadata(target_zip)
1386 vendor_items.Get("vendor").SetPermissions(temp_script)
1387
1388 # Note that this call will mess up the trees of Items, so make sure
1389 # we're done with them.
1390 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1391 if vendor_diff:
1392 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001393
1394 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001395 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1396
1397 # Delete all the symlinks in source that aren't in target. This
1398 # needs to happen before verbatim files are unpacked, in case a
1399 # symlink in the source is replaced by a real file in the target.
1400 to_delete = []
1401 for dest, link in source_symlinks:
1402 if link not in target_symlinks_d:
1403 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001404 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001405
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001406 if system_diff.verbatim_targets:
1407 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001408 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001409 if vendor_diff and vendor_diff.verbatim_targets:
1410 script.Print("Unpacking new vendor files...")
1411 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001412
Doug Zongkerc9253822014-02-04 12:17:58 -08001413 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001414 script.Print("Unpacking new recovery...")
1415 script.UnpackPackageDir("recovery", "/system")
1416
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001417 system_diff.EmitRenames(script)
1418 if vendor_diff:
1419 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001420
Doug Zongker05d3dea2009-06-22 11:32:31 -07001421 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001422
1423 # Create all the symlinks that don't already exist, or point to
1424 # somewhere different than what we want. Delete each symlink before
1425 # creating it, since the 'symlink' command won't overwrite.
1426 to_create = []
1427 for dest, link in target_symlinks:
1428 if link in source_symlinks_d:
1429 if dest != source_symlinks_d[link]:
1430 to_create.append((dest, link))
1431 else:
1432 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001433 script.DeleteFiles([i[1] for i in to_create])
1434 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001435
1436 # Now that the symlinks are created, we can set all the
1437 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001438 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001439
Doug Zongker881dd402009-09-20 14:03:55 -07001440 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001441 device_specific.IncrementalOTA_InstallEnd()
1442
Doug Zongker1c390a22009-05-14 19:06:36 -07001443 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001444 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001445
Doug Zongkere92f15a2011-08-26 13:46:40 -07001446 # Patch the build.prop file last, so if something fails but the
1447 # device can still come up, it appears to be the old build and will
1448 # get set the OTA package again to retry.
1449 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001450 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001451
Doug Zongker922206e2014-03-04 13:16:24 -08001452 if OPTIONS.wipe_user_data:
1453 script.Print("Erasing user data...")
1454 script.FormatPartition("/data")
1455
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001456 if OPTIONS.two_step:
1457 script.AppendExtra("""
1458set_stage("%(bcb_dev)s", "");
1459endif;
1460endif;
1461""" % bcb_dev)
1462
Doug Zongker25568482014-03-03 10:21:27 -08001463 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -07001464 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001465
1466
1467def main(argv):
1468
1469 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001470 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001471 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001472 elif o in ("-k", "--package_key"):
1473 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001474 elif o in ("-i", "--incremental_from"):
1475 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001476 elif o in ("-w", "--wipe_user_data"):
1477 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001478 elif o in ("-n", "--no_prereq"):
1479 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001480 elif o in ("-o", "--oem_settings"):
1481 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001482 elif o in ("-e", "--extra_script"):
1483 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001484 elif o in ("-a", "--aslr_mode"):
1485 if a in ("on", "On", "true", "True", "yes", "Yes"):
1486 OPTIONS.aslr_mode = True
1487 else:
1488 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001489 elif o in ("-t", "--worker_threads"):
1490 if a.isdigit():
1491 OPTIONS.worker_threads = int(a)
1492 else:
1493 raise ValueError("Cannot parse value %r for option %r - only "
1494 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001495 elif o in ("-2", "--two_step"):
1496 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001497 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001498 OPTIONS.no_signing = True
Doug Zongker26e66192014-02-20 13:22:07 -08001499 elif o == "--block":
1500 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001501 elif o in ("-b", "--binary"):
1502 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001503 elif o in ("--no_fallback_to_full",):
1504 OPTIONS.fallback_to_full = False
Doug Zongkereef39442009-04-02 12:14:19 -07001505 else:
1506 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001507 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001508
1509 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001510 extra_opts="b:k:i:d:wne:t:a:2o:",
Doug Zongkereef39442009-04-02 12:14:19 -07001511 extra_long_opts=["board_config=",
1512 "package_key=",
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001513 "incremental_from=",
Doug Zongker962069c2009-04-23 11:41:58 -07001514 "wipe_user_data",
Doug Zongker1c390a22009-05-14 19:06:36 -07001515 "no_prereq",
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001516 "extra_script=",
Hristo Bojinov96be7202010-08-02 10:26:17 -07001517 "worker_threads=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001518 "aslr_mode=",
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001519 "two_step",
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001520 "no_signing",
Doug Zongker26e66192014-02-20 13:22:07 -08001521 "block",
Doug Zongker25568482014-03-03 10:21:27 -08001522 "binary=",
Michael Runge6e836112014-04-15 17:40:21 -07001523 "oem_settings=",
Doug Zongker62d4f182014-08-04 16:06:43 -07001524 "no_fallback_to_full",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001525 ],
Doug Zongkereef39442009-04-02 12:14:19 -07001526 extra_option_handler=option_handler)
1527
1528 if len(args) != 2:
1529 common.Usage(__doc__)
1530 sys.exit(1)
1531
Doug Zongker1c390a22009-05-14 19:06:36 -07001532 if OPTIONS.extra_script is not None:
1533 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1534
Doug Zongkereef39442009-04-02 12:14:19 -07001535 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001536 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001537
Doug Zongkereef39442009-04-02 12:14:19 -07001538 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001539 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001540
1541 # If this image was originally labelled with SELinux contexts, make sure we
1542 # also apply the labels in our new image. During building, the "file_contexts"
1543 # is in the out/ directory tree, but for repacking from target-files.zip it's
1544 # in the root directory of the ramdisk.
1545 if "selinux_fc" in OPTIONS.info_dict:
1546 OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK",
1547 "file_contexts")
1548
Doug Zongker37974732010-09-16 17:44:38 -07001549 if OPTIONS.verbose:
1550 print "--- target info ---"
1551 common.DumpInfoDict(OPTIONS.info_dict)
1552
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001553 # If the caller explicitly specified the device-specific extensions
1554 # path via -s/--device_specific, use that. Otherwise, use
1555 # META/releasetools.py if it is present in the target target_files.
1556 # Otherwise, take the path of the file from 'tool_extensions' in the
1557 # info dict and look for that in the local filesystem, relative to
1558 # the current directory.
1559
Doug Zongker37974732010-09-16 17:44:38 -07001560 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001561 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1562 if os.path.exists(from_input):
1563 print "(using device-specific extensions from target_files)"
1564 OPTIONS.device_specific = from_input
1565 else:
1566 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1567
Doug Zongker37974732010-09-16 17:44:38 -07001568 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001569 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001570
Doug Zongker62d4f182014-08-04 16:06:43 -07001571 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001572
Doug Zongker62d4f182014-08-04 16:06:43 -07001573 if OPTIONS.no_signing:
1574 if os.path.exists(args[1]): os.unlink(args[1])
1575 output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
1576 else:
1577 temp_zip_file = tempfile.NamedTemporaryFile()
1578 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1579 compression=zipfile.ZIP_DEFLATED)
1580
1581 if OPTIONS.incremental_source is None:
1582 WriteFullOTAPackage(input_zip, output_zip)
1583 if OPTIONS.package_key is None:
1584 OPTIONS.package_key = OPTIONS.info_dict.get(
1585 "default_system_dev_certificate",
1586 "build/target/product/security/testkey")
1587 break
1588
1589 else:
1590 print "unzipping source target-files..."
1591 OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
1592 OPTIONS.target_info_dict = OPTIONS.info_dict
1593 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1594 if "selinux_fc" in OPTIONS.source_info_dict:
1595 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(OPTIONS.source_tmp, "BOOT", "RAMDISK",
1596 "file_contexts")
1597 if OPTIONS.package_key is None:
1598 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1599 "default_system_dev_certificate",
1600 "build/target/product/security/testkey")
1601 if OPTIONS.verbose:
1602 print "--- source info ---"
1603 common.DumpInfoDict(OPTIONS.source_info_dict)
1604 try:
1605 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
1606 break
1607 except ValueError:
1608 if not OPTIONS.fallback_to_full: raise
1609 print "--- failed to build incremental; falling back to full ---"
1610 OPTIONS.incremental_source = None
1611 output_zip.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001612
1613 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001614
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001615 if not OPTIONS.no_signing:
1616 SignOutput(temp_zip_file.name, args[1])
1617 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001618
1619 common.Cleanup()
1620
1621 print "done."
1622
1623
1624if __name__ == '__main__':
1625 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001626 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001627 main(sys.argv[1:])
1628 except common.ExternalError, e:
1629 print
1630 print " ERROR: %s" % (e,)
1631 print
1632 sys.exit(1)