blob: 25309a49ce67d4d69a421a5004198fe4438d1cb2 [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 Runge63f01de2014-10-28 19:24:19 -070040 -v (--verify)
41 Remount and verify the checksums of the files written to the
42 system and vendor (if used) partitions. Incremental builds only.
43
Michael Runge6e836112014-04-15 17:40:21 -070044 -o (--oem_settings) <file>
45 Use the file to specify the expected OEM-specific properties
46 on the OEM partition of the intended device.
47
Doug Zongkerdbfaae52009-04-21 17:12:54 -070048 -w (--wipe_user_data)
49 Generate an OTA package that will wipe the user data partition
50 when installed.
51
Doug Zongker962069c2009-04-23 11:41:58 -070052 -n (--no_prereq)
53 Omit the timestamp prereq check normally included at the top of
54 the build scripts (used for developer OTA packages which
55 legitimately need to go back and forth).
56
Doug Zongker1c390a22009-05-14 19:06:36 -070057 -e (--extra_script) <file>
58 Insert the contents of file at the end of the update script.
59
Hristo Bojinovdafb0422010-08-26 14:35:16 -070060 -a (--aslr_mode) <on|off>
61 Specify whether to turn on ASLR for the package (on by default).
Stephen Smalley56882bf2012-02-09 13:36:21 -050062
Doug Zongker9b23f2c2013-11-25 14:44:12 -080063 -2 (--two_step)
64 Generate a 'two-step' OTA package, where recovery is updated
65 first, so that any changes made to the system partition are done
66 using the new recovery (new kernel, etc.).
67
Doug Zongker26e66192014-02-20 13:22:07 -080068 --block
69 Generate a block-based OTA if possible. Will fall back to a
70 file-based OTA if the target_files is older and doesn't support
71 block-based OTAs.
72
Doug Zongker25568482014-03-03 10:21:27 -080073 -b (--binary) <file>
74 Use the given binary as the update-binary in the output package,
75 instead of the binary in the build's target_files. Use for
76 development only.
77
Martin Blumenstingl374e1142014-05-31 20:42:55 +020078 -t (--worker_threads) <int>
79 Specifies the number of worker-threads that will be used when
80 generating patches for incremental updates (defaults to 3).
81
Doug Zongkereef39442009-04-02 12:14:19 -070082"""
83
84import sys
85
Doug Zongkercf6d5a92014-02-18 10:57:07 -080086if sys.hexversion < 0x02070000:
87 print >> sys.stderr, "Python 2.7 or newer is required."
Doug Zongkereef39442009-04-02 12:14:19 -070088 sys.exit(1)
89
90import copy
Doug Zongkerc18736b2009-09-30 09:20:32 -070091import errno
Doug Zongkerfc44a512014-08-26 13:10:25 -070092import multiprocessing
Doug Zongkereef39442009-04-02 12:14:19 -070093import os
94import re
Doug Zongkereef39442009-04-02 12:14:19 -070095import subprocess
96import tempfile
97import time
98import zipfile
99
Doug Zongkerfc44a512014-08-26 13:10:25 -0700100from hashlib import sha1 as sha1
davidcad0bb92011-03-15 14:21:38 +0000101
Doug Zongkereef39442009-04-02 12:14:19 -0700102import common
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700103import edify_generator
Geremy Condra36bd3652014-02-06 19:45:10 -0800104import build_image
Doug Zongkerfc44a512014-08-26 13:10:25 -0700105import blockimgdiff
106import sparse_img
Doug Zongkereef39442009-04-02 12:14:19 -0700107
108OPTIONS = common.OPTIONS
Doug Zongkerafb32ea2011-09-22 10:28:04 -0700109OPTIONS.package_key = None
Doug Zongkereef39442009-04-02 12:14:19 -0700110OPTIONS.incremental_source = None
Michael Runge63f01de2014-10-28 19:24:19 -0700111OPTIONS.verify = False
Doug Zongkereef39442009-04-02 12:14:19 -0700112OPTIONS.require_verbatim = set()
113OPTIONS.prohibit_verbatim = set(("system/build.prop",))
114OPTIONS.patch_threshold = 0.95
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700115OPTIONS.wipe_user_data = False
Doug Zongker962069c2009-04-23 11:41:58 -0700116OPTIONS.omit_prereq = False
Doug Zongker1c390a22009-05-14 19:06:36 -0700117OPTIONS.extra_script = None
Hristo Bojinovdafb0422010-08-26 14:35:16 -0700118OPTIONS.aslr_mode = True
Doug Zongkerfc44a512014-08-26 13:10:25 -0700119OPTIONS.worker_threads = multiprocessing.cpu_count() // 2
120if OPTIONS.worker_threads == 0:
121 OPTIONS.worker_threads = 1
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800122OPTIONS.two_step = False
Takeshi Kanemotoe153b342013-11-14 17:20:50 +0900123OPTIONS.no_signing = False
Doug Zongker26e66192014-02-20 13:22:07 -0800124OPTIONS.block_based = False
Doug Zongker25568482014-03-03 10:21:27 -0800125OPTIONS.updater_binary = None
Michael Runge6e836112014-04-15 17:40:21 -0700126OPTIONS.oem_source = None
Doug Zongker62d4f182014-08-04 16:06:43 -0700127OPTIONS.fallback_to_full = True
Doug Zongkereef39442009-04-02 12:14:19 -0700128
129def MostPopularKey(d, default):
130 """Given a dict, return the key corresponding to the largest
131 value. Returns 'default' if the dict is empty."""
132 x = [(v, k) for (k, v) in d.iteritems()]
133 if not x: return default
134 x.sort()
135 return x[-1][1]
136
137
138def IsSymlink(info):
139 """Return true if the zipfile.ZipInfo object passed in represents a
140 symlink."""
141 return (info.external_attr >> 16) == 0120777
142
Hristo Bojinov96be7202010-08-02 10:26:17 -0700143def IsRegular(info):
144 """Return true if the zipfile.ZipInfo object passed in represents a
145 symlink."""
146 return (info.external_attr >> 28) == 010
Doug Zongkereef39442009-04-02 12:14:19 -0700147
Michael Runge4038aa82013-12-13 18:06:28 -0800148def ClosestFileMatch(src, tgtfiles, existing):
149 """Returns the closest file match between a source file and list
150 of potential matches. The exact filename match is preferred,
151 then the sha1 is searched for, and finally a file with the same
152 basename is evaluated. Rename support in the updater-binary is
153 required for the latter checks to be used."""
154
155 result = tgtfiles.get("path:" + src.name)
156 if result is not None:
157 return result
158
159 if not OPTIONS.target_info_dict.get("update_rename_support", False):
160 return None
161
162 if src.size < 1000:
163 return None
164
165 result = tgtfiles.get("sha1:" + src.sha1)
166 if result is not None and existing.get(result.name) is None:
167 return result
168 result = tgtfiles.get("file:" + src.name.split("/")[-1])
169 if result is not None and existing.get(result.name) is None:
170 return result
171 return None
172
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700173class ItemSet:
174 def __init__(self, partition, fs_config):
175 self.partition = partition
176 self.fs_config = fs_config
177 self.ITEMS = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700178
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700179 def Get(self, name, dir=False):
180 if name not in self.ITEMS:
181 self.ITEMS[name] = Item(self, name, dir=dir)
182 return self.ITEMS[name]
Doug Zongkereef39442009-04-02 12:14:19 -0700183
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700184 def GetMetadata(self, input_zip):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700185 # The target_files contains a record of what the uid,
186 # gid, and mode are supposed to be.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700187 output = input_zip.read(self.fs_config)
Doug Zongkereef39442009-04-02 12:14:19 -0700188
189 for line in output.split("\n"):
190 if not line: continue
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700191 columns = line.split()
192 name, uid, gid, mode = columns[:4]
193 selabel = None
194 capabilities = None
195
196 # After the first 4 columns, there are a series of key=value
197 # pairs. Extract out the fields we care about.
198 for element in columns[4:]:
199 key, value = element.split("=")
200 if key == "selabel":
201 selabel = value
202 if key == "capabilities":
203 capabilities = value
204
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700205 i = self.ITEMS.get(name, None)
Doug Zongker283e2a12010-03-15 17:52:32 -0700206 if i is not None:
207 i.uid = int(uid)
208 i.gid = int(gid)
209 i.mode = int(mode, 8)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700210 i.selabel = selabel
211 i.capabilities = capabilities
Doug Zongker283e2a12010-03-15 17:52:32 -0700212 if i.dir:
213 i.children.sort(key=lambda i: i.name)
214
215 # set metadata for the files generated by this script.
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700216 i = self.ITEMS.get("system/recovery-from-boot.p", None)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700217 if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0644, None, None
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700218 i = self.ITEMS.get("system/etc/install-recovery.sh", None)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700219 if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0544, None, None
Doug Zongkereef39442009-04-02 12:14:19 -0700220
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700221
222class Item:
223 """Items represent the metadata (user, group, mode) of files and
224 directories in the system image."""
225 def __init__(self, itemset, name, dir=False):
226 self.itemset = itemset
227 self.name = name
228 self.uid = None
229 self.gid = None
230 self.mode = None
231 self.selabel = None
232 self.capabilities = None
233 self.dir = dir
234
235 if name:
236 self.parent = itemset.Get(os.path.dirname(name), dir=True)
237 self.parent.children.append(self)
238 else:
239 self.parent = None
240 if dir:
241 self.children = []
242
243 def Dump(self, indent=0):
244 if self.uid is not None:
245 print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode)
246 else:
247 print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode)
248 if self.dir:
249 print "%s%s" % (" "*indent, self.descendants)
250 print "%s%s" % (" "*indent, self.best_subtree)
251 for i in self.children:
252 i.Dump(indent=indent+1)
253
Doug Zongkereef39442009-04-02 12:14:19 -0700254 def CountChildMetadata(self):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700255 """Count up the (uid, gid, mode, selabel, capabilities) tuples for
256 all children and determine the best strategy for using set_perm_recursive and
Doug Zongkereef39442009-04-02 12:14:19 -0700257 set_perm to correctly chown/chmod all the files to their desired
258 values. Recursively calls itself for all descendants.
259
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700260 Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count} counting up
Doug Zongkereef39442009-04-02 12:14:19 -0700261 all descendants of this node. (dmode or fmode may be None.) Also
262 sets the best_subtree of each directory Item to the (uid, gid,
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700263 dmode, fmode, selabel, capabilities) tuple that will match the most
264 descendants of that Item.
Doug Zongkereef39442009-04-02 12:14:19 -0700265 """
266
267 assert self.dir
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700268 d = self.descendants = {(self.uid, self.gid, self.mode, None, self.selabel, self.capabilities): 1}
Doug Zongkereef39442009-04-02 12:14:19 -0700269 for i in self.children:
270 if i.dir:
271 for k, v in i.CountChildMetadata().iteritems():
272 d[k] = d.get(k, 0) + v
273 else:
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700274 k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700275 d[k] = d.get(k, 0) + 1
276
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700277 # Find the (uid, gid, dmode, fmode, selabel, capabilities)
278 # tuple that matches the most descendants.
Doug Zongkereef39442009-04-02 12:14:19 -0700279
280 # First, find the (uid, gid) pair that matches the most
281 # descendants.
282 ug = {}
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700283 for (uid, gid, _, _, _, _), count in d.iteritems():
Doug Zongkereef39442009-04-02 12:14:19 -0700284 ug[(uid, gid)] = ug.get((uid, gid), 0) + count
285 ug = MostPopularKey(ug, (0, 0))
286
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700287 # Now find the dmode, fmode, selabel, and capabilities that match
288 # the most descendants with that (uid, gid), and choose those.
Doug Zongkereef39442009-04-02 12:14:19 -0700289 best_dmode = (0, 0755)
290 best_fmode = (0, 0644)
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700291 best_selabel = (0, None)
292 best_capabilities = (0, None)
Doug Zongkereef39442009-04-02 12:14:19 -0700293 for k, count in d.iteritems():
294 if k[:2] != ug: continue
295 if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2])
296 if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3])
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700297 if k[4] is not None and count >= best_selabel[0]: best_selabel = (count, k[4])
298 if k[5] is not None and count >= best_capabilities[0]: best_capabilities = (count, k[5])
299 self.best_subtree = ug + (best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700300
301 return d
302
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700303 def SetPermissions(self, script):
Doug Zongkereef39442009-04-02 12:14:19 -0700304 """Append set_perm/set_perm_recursive commands to 'script' to
305 set all permissions, users, and groups for the tree of files
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700306 rooted at 'self'."""
Doug Zongkereef39442009-04-02 12:14:19 -0700307
308 self.CountChildMetadata()
309
310 def recurse(item, current):
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700311 # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple that the current
Doug Zongkereef39442009-04-02 12:14:19 -0700312 # item (and all its children) have already been set to. We only
313 # need to issue set_perm/set_perm_recursive commands if we're
314 # supposed to be something different.
315 if item.dir:
316 if current != item.best_subtree:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700317 script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
Doug Zongkereef39442009-04-02 12:14:19 -0700318 current = item.best_subtree
319
320 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700321 item.mode != current[2] or item.selabel != current[4] or \
322 item.capabilities != current[5]:
323 script.SetPermissions("/"+item.name, item.uid, item.gid,
324 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700325
326 for i in item.children:
327 recurse(i, current)
328 else:
329 if item.uid != current[0] or item.gid != current[1] or \
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700330 item.mode != current[3] or item.selabel != current[4] or \
331 item.capabilities != current[5]:
332 script.SetPermissions("/"+item.name, item.uid, item.gid,
333 item.mode, item.selabel, item.capabilities)
Doug Zongkereef39442009-04-02 12:14:19 -0700334
Nick Kralevich0eb17d92013-09-07 17:10:29 -0700335 recurse(self, (-1, -1, -1, -1, None, None))
Doug Zongkereef39442009-04-02 12:14:19 -0700336
337
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700338def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
339 """Copies files for the partition in the input zip to the output
Doug Zongkereef39442009-04-02 12:14:19 -0700340 zip. Populates the Item class with their metadata, and returns a
Doug Zongker1807e702012-02-28 12:21:08 -0800341 list of symlinks. output_zip may be None, in which case the copy is
342 skipped (but the other side effects still happen). substitute is an
343 optional dict of {output filename: contents} to be output instead of
344 certain input files.
Doug Zongkereef39442009-04-02 12:14:19 -0700345 """
346
347 symlinks = []
348
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700349 partition = itemset.partition
350
Doug Zongkereef39442009-04-02 12:14:19 -0700351 for info in input_zip.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700352 if info.filename.startswith(partition.upper() + "/"):
Doug Zongkereef39442009-04-02 12:14:19 -0700353 basefilename = info.filename[7:]
354 if IsSymlink(info):
355 symlinks.append((input_zip.read(info.filename),
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700356 "/" + partition + "/" + basefilename))
Doug Zongkereef39442009-04-02 12:14:19 -0700357 else:
358 info2 = copy.copy(info)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700359 fn = info2.filename = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700360 if substitute and fn in substitute and substitute[fn] is None:
361 continue
362 if output_zip is not None:
363 if substitute and fn in substitute:
364 data = substitute[fn]
365 else:
366 data = input_zip.read(info.filename)
367 output_zip.writestr(info2, data)
368 if fn.endswith("/"):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700369 itemset.Get(fn[:-1], dir=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700370 else:
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700371 itemset.Get(fn, dir=False)
Doug Zongkereef39442009-04-02 12:14:19 -0700372
373 symlinks.sort()
Doug Zongker1807e702012-02-28 12:21:08 -0800374 return symlinks
Doug Zongkereef39442009-04-02 12:14:19 -0700375
376
Doug Zongkereef39442009-04-02 12:14:19 -0700377def SignOutput(temp_zip_name, output_zip_name):
378 key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
379 pw = key_passwords[OPTIONS.package_key]
380
Doug Zongker951495f2009-08-14 12:44:19 -0700381 common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
382 whole_file=True)
Doug Zongkereef39442009-04-02 12:14:19 -0700383
384
Michael Rungec6e3afd2014-05-05 11:55:47 -0700385def AppendAssertions(script, info_dict, oem_dict = None):
Michael Runge6e836112014-04-15 17:40:21 -0700386 oem_props = info_dict.get("oem_fingerprint_properties")
Michael Runge560569a2014-09-18 15:12:45 -0700387 if oem_props is None or len(oem_props) == 0:
Michael Runge6e836112014-04-15 17:40:21 -0700388 device = GetBuildProp("ro.product.device", info_dict)
389 script.AssertDevice(device)
390 else:
391 if oem_dict is None:
392 raise common.ExternalError("No OEM file provided to answer expected assertions")
393 for prop in oem_props.split():
394 if oem_dict.get(prop) is None:
395 raise common.ExternalError("The OEM file is missing the property %s" % prop)
396 script.AssertOemProperty(prop, oem_dict.get(prop))
Doug Zongkereef39442009-04-02 12:14:19 -0700397
Doug Zongkereef39442009-04-02 12:14:19 -0700398
Doug Zongkerc9253822014-02-04 12:17:58 -0800399def HasRecoveryPatch(target_files_zip):
400 try:
401 target_files_zip.getinfo("SYSTEM/recovery-from-boot.p")
402 return True
403 except KeyError:
404 return False
Doug Zongker73ef8252009-07-23 15:12:53 -0700405
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700406def HasVendorPartition(target_files_zip):
407 try:
408 target_files_zip.getinfo("VENDOR/")
409 return True
410 except KeyError:
411 return False
412
Michael Runge6e836112014-04-15 17:40:21 -0700413def GetOemProperty(name, oem_props, oem_dict, info_dict):
414 if oem_props is not None and name in oem_props:
415 return oem_dict[name]
416 return GetBuildProp(name, info_dict)
417
418
419def CalculateFingerprint(oem_props, oem_dict, info_dict):
420 if oem_props is None:
421 return GetBuildProp("ro.build.fingerprint", info_dict)
422 return "%s/%s/%s:%s" % (
423 GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
424 GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
425 GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
426 GetBuildProp("ro.build.thumbprint", info_dict))
Doug Zongker73ef8252009-07-23 15:12:53 -0700427
Doug Zongkerfc44a512014-08-26 13:10:25 -0700428
Doug Zongker3c84f562014-07-31 11:06:30 -0700429def GetImage(which, tmpdir, info_dict):
Doug Zongkerfc44a512014-08-26 13:10:25 -0700430 # Return an image object (suitable for passing to BlockImageDiff)
431 # for the 'which' partition (most be "system" or "vendor"). If a
432 # prebuilt image and file map are found in tmpdir they are used,
433 # otherwise they are reconstructed from the individual files.
Doug Zongker3c84f562014-07-31 11:06:30 -0700434
435 assert which in ("system", "vendor")
436
437 path = os.path.join(tmpdir, "IMAGES", which + ".img")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700438 mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
439 if os.path.exists(path) and os.path.exists(mappath):
Doug Zongker3c84f562014-07-31 11:06:30 -0700440 print "using %s.img from target-files" % (which,)
Doug Zongker3c84f562014-07-31 11:06:30 -0700441 # This is a 'new' target-files, which already has the image in it.
Doug Zongker3c84f562014-07-31 11:06:30 -0700442
443 else:
444 print "building %s.img from target-files" % (which,)
445
446 # This is an 'old' target-files, which does not contain images
447 # already built. Build them.
448
Doug Zongkerfc44a512014-08-26 13:10:25 -0700449 mappath = tempfile.mkstemp()[1]
450 OPTIONS.tempfiles.append(mappath)
451
Doug Zongker3c84f562014-07-31 11:06:30 -0700452 import add_img_to_target_files
453 if which == "system":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700454 path = add_img_to_target_files.BuildSystem(
455 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700456 elif which == "vendor":
Doug Zongkerfc44a512014-08-26 13:10:25 -0700457 path = add_img_to_target_files.BuildVendor(
458 tmpdir, info_dict, block_list=mappath)
Doug Zongker3c84f562014-07-31 11:06:30 -0700459
Doug Zongkerfc44a512014-08-26 13:10:25 -0700460 return sparse_img.SparseImage(path, mappath)
461
462
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700463def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700464 # TODO: how to determine this? We don't know what version it will
465 # be installed on top of. For now, we expect the API just won't
466 # change very often.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700467 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700468
Michael Runge6e836112014-04-15 17:40:21 -0700469 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700470 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700471 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700472 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700473 if OPTIONS.oem_source is None:
474 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700475 script.Mount("/oem", recovery_mount_options)
Michael Runge6e836112014-04-15 17:40:21 -0700476 oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
477
478 metadata = {"post-build": CalculateFingerprint(
479 oem_props, oem_dict, OPTIONS.info_dict),
480 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700481 OPTIONS.info_dict),
482 "post-timestamp": GetBuildProp("ro.build.date.utc",
483 OPTIONS.info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700484 }
485
Doug Zongker05d3dea2009-06-22 11:32:31 -0700486 device_specific = common.DeviceSpecificParams(
487 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700488 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700489 output_zip=output_zip,
490 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700491 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700492 metadata=metadata,
493 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700494
Doug Zongkerc9253822014-02-04 12:17:58 -0800495 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800496 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800497
Doug Zongker962069c2009-04-23 11:41:58 -0700498 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700499 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700500 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
501 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700502
Michael Runge6e836112014-04-15 17:40:21 -0700503 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700504 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800505
506 # Two-step package strategy (in chronological order, which is *not*
507 # the order in which the generated script has things):
508 #
509 # if stage is not "2/3" or "3/3":
510 # write recovery image to boot partition
511 # set stage to "2/3"
512 # reboot to boot partition and restart recovery
513 # else if stage is "2/3":
514 # write recovery image to recovery partition
515 # set stage to "3/3"
516 # reboot to recovery partition and restart recovery
517 # else:
518 # (stage must be "3/3")
519 # set stage to ""
520 # do normal full package installation:
521 # wipe and install system, boot image, etc.
522 # set up system to update recovery partition on first boot
523 # complete script normally (allow recovery to mark itself finished and reboot)
524
525 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
526 OPTIONS.input_tmp, "RECOVERY")
527 if OPTIONS.two_step:
528 if not OPTIONS.info_dict.get("multistage_support", None):
529 assert False, "two-step packages not supported by this build"
530 fs = OPTIONS.info_dict["fstab"]["/misc"]
531 assert fs.fs_type.upper() == "EMMC", \
532 "two-step packages only supported on devices with EMMC /misc partitions"
533 bcb_dev = {"bcb_dev": fs.device}
534 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
535 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700536if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800537""" % bcb_dev)
538 script.WriteRawImage("/recovery", "recovery.img")
539 script.AppendExtra("""
540set_stage("%(bcb_dev)s", "3/3");
541reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700542else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800543""" % bcb_dev)
544
Doug Zongkere5ff5902012-01-17 10:55:37 -0800545 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700546
Doug Zongker01ce19c2014-02-04 13:48:15 -0800547 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700548
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700549 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800550 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700551 if HasVendorPartition(input_zip):
552 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700553
Kenny Rootf32dc712012-04-08 10:42:34 -0700554 if "selinux_fc" in OPTIONS.info_dict:
555 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500556
Michael Runge7cd99ba2014-10-22 17:21:48 -0700557 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
558
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700559 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700560 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800561
Doug Zongker26e66192014-02-20 13:22:07 -0800562 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700563 # Full OTA is done as an "incremental" against an empty source
564 # image. This has the effect of writing new data from the package
565 # to the entire partition, but lets us reuse the updater code that
566 # writes incrementals to do it.
567 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
568 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700569 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700570 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800571 else:
572 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700573 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800574 if not has_recovery_patch:
575 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800576 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700577
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700578 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800579 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700580
Doug Zongker55d93282011-01-25 17:03:34 -0800581 boot_img = common.GetBootableImage("boot.img", "boot.img",
582 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800583
Doug Zongker91a99c22014-05-09 13:15:01 -0700584 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800585 def output_sink(fn, data):
586 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700587 system_items.Get("system/" + fn, dir=False)
Doug Zongkerc9253822014-02-04 12:17:58 -0800588
589 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
590 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700591
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700592 system_items.GetMetadata(input_zip)
593 system_items.Get("system").SetPermissions(script)
594
595 if HasVendorPartition(input_zip):
596 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
597 script.ShowProgress(0.1, 0)
598
599 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700600 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
601 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700602 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700603 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700604 else:
605 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700606 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700607 script.UnpackPackageDir("vendor", "/vendor")
608
609 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
610 script.MakeSymlinks(symlinks)
611
612 vendor_items.GetMetadata(input_zip)
613 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700614
Doug Zongker37974732010-09-16 17:44:38 -0700615 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700616 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700617
Doug Zongker01ce19c2014-02-04 13:48:15 -0800618 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700619 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700620
Doug Zongker01ce19c2014-02-04 13:48:15 -0800621 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700622 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700623
Doug Zongker1c390a22009-05-14 19:06:36 -0700624 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700625 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700626
Doug Zongker14833602010-02-02 13:12:04 -0800627 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800628
Doug Zongker922206e2014-03-04 13:16:24 -0800629 if OPTIONS.wipe_user_data:
630 script.ShowProgress(0.1, 10)
631 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700632
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800633 if OPTIONS.two_step:
634 script.AppendExtra("""
635set_stage("%(bcb_dev)s", "");
636""" % bcb_dev)
637 script.AppendExtra("else\n")
638 script.WriteRawImage("/boot", "recovery.img")
639 script.AppendExtra("""
640set_stage("%(bcb_dev)s", "2/3");
641reboot_now("%(bcb_dev)s", "");
642endif;
643endif;
644""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800645 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700646 WriteMetadata(metadata, output_zip)
647
Doug Zongkerfc44a512014-08-26 13:10:25 -0700648
Justin Harrison2de68bb2015-02-13 18:47:51 +0000649def WritePolicyConfig(file_context, output_zip):
650 f = open(file_context, 'r');
651 basename = os.path.basename(file_context)
652 common.ZipWriteStr(output_zip, basename, f.read())
Stephen Smalley56882bf2012-02-09 13:36:21 -0500653
Doug Zongker2ea21062010-04-28 16:05:21 -0700654
655def WriteMetadata(metadata, output_zip):
656 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
657 "".join(["%s=%s\n" % kv
658 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700659
Doug Zongkerfc44a512014-08-26 13:10:25 -0700660
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700661def LoadPartitionFiles(z, partition):
662 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700663 ZipFile, and return a dict of {filename: File object}."""
664 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700665 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700666 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700667 if info.filename.startswith(prefix) and not IsSymlink(info):
Hristo Bojinov96be7202010-08-02 10:26:17 -0700668 basefilename = info.filename[7:]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700669 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700670 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700671 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800672 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700673
674
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700675def GetBuildProp(prop, info_dict):
676 """Return the fingerprint of the build of a given target-files info_dict."""
677 try:
678 return info_dict.get("build.prop", {})[prop]
679 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700680 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700681
Doug Zongkerfc44a512014-08-26 13:10:25 -0700682
Michael Runge4038aa82013-12-13 18:06:28 -0800683def AddToKnownPaths(filename, known_paths):
684 if filename[-1] == "/":
685 return
686 dirs = filename.split("/")[:-1]
687 while len(dirs) > 0:
688 path = "/".join(dirs)
689 if path in known_paths:
690 break;
691 known_paths.add(path)
692 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700693
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700694
Geremy Condra36bd3652014-02-06 19:45:10 -0800695def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
696 source_version = OPTIONS.source_info_dict["recovery_api_version"]
697 target_version = OPTIONS.target_info_dict["recovery_api_version"]
698
699 if source_version == 0:
700 print ("WARNING: generating edify script for a source that "
701 "can't install it.")
702 script = edify_generator.EdifyGenerator(source_version,
703 OPTIONS.target_info_dict)
704
705 metadata = {"pre-device": GetBuildProp("ro.product.device",
706 OPTIONS.source_info_dict),
707 "post-timestamp": GetBuildProp("ro.build.date.utc",
708 OPTIONS.target_info_dict),
709 }
710
711 device_specific = common.DeviceSpecificParams(
712 source_zip=source_zip,
713 source_version=source_version,
714 target_zip=target_zip,
715 target_version=target_version,
716 output_zip=output_zip,
717 script=script,
718 metadata=metadata,
719 info_dict=OPTIONS.info_dict)
720
721 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
722 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
723 metadata["pre-build"] = source_fp
724 metadata["post-build"] = target_fp
725
726 source_boot = common.GetBootableImage(
727 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
728 OPTIONS.source_info_dict)
729 target_boot = common.GetBootableImage(
730 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
731 updating_boot = (not OPTIONS.two_step and
732 (source_boot.data != target_boot.data))
733
734 source_recovery = common.GetBootableImage(
735 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
736 OPTIONS.source_info_dict)
737 target_recovery = common.GetBootableImage(
738 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
739 updating_recovery = (source_recovery.data != target_recovery.data)
740
Doug Zongkerfc44a512014-08-26 13:10:25 -0700741 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
742 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodd2a5892015-03-12 12:32:37 -0700743
744 blockimgdiff_version = 1
745 if OPTIONS.info_dict:
746 blockimgdiff_version = max(
747 int(i) for i in
748 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
749
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700750 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700751 check_first_block=True,
752 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700753
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700754 if HasVendorPartition(target_zip):
755 if not HasVendorPartition(source_zip):
756 raise RuntimeError("can't generate incremental that adds /vendor")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700757 vendor_src = GetImage("vendor", OPTIONS.source_tmp, OPTIONS.source_info_dict)
758 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700759 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Baodd2a5892015-03-12 12:32:37 -0700760 check_first_block=True,
761 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700762 else:
763 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800764
Michael Rungec6e3afd2014-05-05 11:55:47 -0700765 oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700766 recovery_mount_options = OPTIONS.target_info_dict.get("recovery_mount_options")
Michael Rungec6e3afd2014-05-05 11:55:47 -0700767 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700768 if oem_props is not None and len(oem_props) > 0:
Michael Rungec6e3afd2014-05-05 11:55:47 -0700769 if OPTIONS.oem_source is None:
770 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700771 script.Mount("/oem", recovery_mount_options)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700772 oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
773
774 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800775 device_specific.IncrementalOTA_Assertions()
776
777 # Two-step incremental package strategy (in chronological order,
778 # which is *not* the order in which the generated script has
779 # things):
780 #
781 # if stage is not "2/3" or "3/3":
782 # do verification on current system
783 # write recovery image to boot partition
784 # set stage to "2/3"
785 # reboot to boot partition and restart recovery
786 # else if stage is "2/3":
787 # write recovery image to recovery partition
788 # set stage to "3/3"
789 # reboot to recovery partition and restart recovery
790 # else:
791 # (stage must be "3/3")
792 # perform update:
793 # patch system files, etc.
794 # force full install of new boot image
795 # set up system to update recovery partition on first boot
796 # complete script normally (allow recovery to mark itself finished and reboot)
797
798 if OPTIONS.two_step:
799 if not OPTIONS.info_dict.get("multistage_support", None):
800 assert False, "two-step packages not supported by this build"
801 fs = OPTIONS.info_dict["fstab"]["/misc"]
802 assert fs.fs_type.upper() == "EMMC", \
803 "two-step packages only supported on devices with EMMC /misc partitions"
804 bcb_dev = {"bcb_dev": fs.device}
805 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
806 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700807if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800808""" % bcb_dev)
809 script.AppendExtra("sleep(20);\n");
810 script.WriteRawImage("/recovery", "recovery.img")
811 script.AppendExtra("""
812set_stage("%(bcb_dev)s", "3/3");
813reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700814else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800815""" % bcb_dev)
816
817 script.Print("Verifying current system...")
818
819 device_specific.IncrementalOTA_VerifyBegin()
820
Michael Rungec6e3afd2014-05-05 11:55:47 -0700821 if oem_props is None:
Tao Baodd2a5892015-03-12 12:32:37 -0700822 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
823 # patching on a device that's already on the target build will damage the
824 # system. Because operations like move don't check the block state, they
825 # always apply the changes unconditionally.
826 if blockimgdiff_version <= 2:
827 script.AssertSomeFingerprint(source_fp)
828 else:
829 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700830 else:
Tao Baodd2a5892015-03-12 12:32:37 -0700831 if blockimgdiff_version <= 2:
832 script.AssertSomeThumbprint(
833 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
834 else:
835 script.AssertSomeThumbprint(
836 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
837 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800838
839 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700840 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800841 d = common.Difference(target_boot, source_boot)
842 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700843 if d is None:
844 include_full_boot = True
845 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
846 else:
847 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800848
Doug Zongkerf8340082014-08-05 10:39:37 -0700849 print "boot target: %d source: %d diff: %d" % (
850 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800851
Doug Zongkerf8340082014-08-05 10:39:37 -0700852 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800853
Doug Zongkerf8340082014-08-05 10:39:37 -0700854 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
855 (boot_type, boot_device,
856 source_boot.size, source_boot.sha1,
857 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800858
859 device_specific.IncrementalOTA_VerifyEnd()
860
861 if OPTIONS.two_step:
862 script.WriteRawImage("/boot", "recovery.img")
863 script.AppendExtra("""
864set_stage("%(bcb_dev)s", "2/3");
865reboot_now("%(bcb_dev)s", "");
866else
867""" % bcb_dev)
868
Jesse Zhao75bcea02015-01-06 10:59:53 -0800869 # Verify the existing partitions.
870 system_diff.WriteVerifyScript(script)
871 if vendor_diff:
872 vendor_diff.WriteVerifyScript(script)
873
Geremy Condra36bd3652014-02-06 19:45:10 -0800874 script.Comment("---- start making changes here ----")
875
876 device_specific.IncrementalOTA_InstallBegin()
877
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700878 system_diff.WriteScript(script, output_zip,
879 progress=0.8 if vendor_diff else 0.9)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700880 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700881 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800882
883 if OPTIONS.two_step:
884 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
885 script.WriteRawImage("/boot", "boot.img")
886 print "writing full boot image (forced by two-step mode)"
887
888 if not OPTIONS.two_step:
889 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700890 if include_full_boot:
891 print "boot image changed; including full."
892 script.Print("Installing boot image...")
893 script.WriteRawImage("/boot", "boot.img")
894 else:
895 # Produce the boot image by applying a patch to the current
896 # contents of the boot partition, and write it back to the
897 # partition.
898 print "boot image changed; including patch."
899 script.Print("Patching boot image...")
900 script.ShowProgress(0.1, 10)
901 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
902 % (boot_type, boot_device,
903 source_boot.size, source_boot.sha1,
904 target_boot.size, target_boot.sha1),
905 "-",
906 target_boot.size, target_boot.sha1,
907 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800908 else:
909 print "boot image unchanged; skipping."
910
911 # Do device-specific installation (eg, write radio image).
912 device_specific.IncrementalOTA_InstallEnd()
913
914 if OPTIONS.extra_script is not None:
915 script.AppendExtra(OPTIONS.extra_script)
916
Doug Zongker922206e2014-03-04 13:16:24 -0800917 if OPTIONS.wipe_user_data:
918 script.Print("Erasing user data...")
919 script.FormatPartition("/data")
920
Geremy Condra36bd3652014-02-06 19:45:10 -0800921 if OPTIONS.two_step:
922 script.AppendExtra("""
923set_stage("%(bcb_dev)s", "");
924endif;
925endif;
926""" % bcb_dev)
927
928 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800929 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800930 WriteMetadata(metadata, output_zip)
931
Doug Zongker32b527d2014-03-04 10:03:02 -0800932
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700933class FileDifference:
934 def __init__(self, partition, source_zip, target_zip, output_zip):
935 print "Loading target..."
936 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
937 print "Loading source..."
938 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
939
940 self.verbatim_targets = verbatim_targets = []
941 self.patch_list = patch_list = []
942 diffs = []
943 self.renames = renames = {}
944 known_paths = set()
945 largest_source_size = 0
946
947 matching_file_cache = {}
948 for fn, sf in source_data.items():
949 assert fn == sf.name
950 matching_file_cache["path:" + fn] = sf
951 if fn in target_data.keys():
952 AddToKnownPaths(fn, known_paths)
953 # Only allow eligibility for filename/sha matching
954 # if there isn't a perfect path match.
955 if target_data.get(sf.name) is None:
956 matching_file_cache["file:" + fn.split("/")[-1]] = sf
957 matching_file_cache["sha:" + sf.sha1] = sf
958
959 for fn in sorted(target_data.keys()):
960 tf = target_data[fn]
961 assert fn == tf.name
962 sf = ClosestFileMatch(tf, matching_file_cache, renames)
963 if sf is not None and sf.name != tf.name:
964 print "File has moved from " + sf.name + " to " + tf.name
965 renames[sf.name] = tf
966
967 if sf is None or fn in OPTIONS.require_verbatim:
968 # This file should be included verbatim
969 if fn in OPTIONS.prohibit_verbatim:
970 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
971 print "send", fn, "verbatim"
972 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -0700973 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700974 if fn in target_data.keys():
975 AddToKnownPaths(fn, known_paths)
976 elif tf.sha1 != sf.sha1:
977 # File is different; consider sending as a patch
978 diffs.append(common.Difference(tf, sf))
979 else:
980 # Target file data identical to source (may still be renamed)
981 pass
982
983 common.ComputeDifferences(diffs)
984
985 for diff in diffs:
986 tf, sf, d = diff.GetPatch()
987 path = "/".join(tf.name.split("/")[:-1])
988 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
989 path not in known_paths:
990 # patch is almost as big as the file; don't bother patching
991 # or a patch + rename cannot take place due to the target
992 # directory not existing
993 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -0700994 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700995 if sf.name in renames:
996 del renames[sf.name]
997 AddToKnownPaths(tf.name, known_paths)
998 else:
999 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1000 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1001 largest_source_size = max(largest_source_size, sf.size)
1002
1003 self.largest_source_size = largest_source_size
1004
1005 def EmitVerification(self, script):
1006 so_far = 0
1007 for tf, sf, size, patch_sha in self.patch_list:
1008 if tf.name != sf.name:
1009 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1010 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1011 so_far += sf.size
1012 return so_far
1013
Michael Runge63f01de2014-10-28 19:24:19 -07001014 def EmitExplicitTargetVerification(self, script):
1015 for fn, size, sha1 in self.verbatim_targets:
1016 if (fn[-1] != "/"):
1017 script.FileCheck("/"+fn, sha1)
1018 for tf, _, _, _ in self.patch_list:
1019 script.FileCheck(tf.name, tf.sha1)
1020
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001021 def RemoveUnneededFiles(self, script, extras=()):
1022 script.DeleteFiles(["/"+i[0] for i in self.verbatim_targets] +
1023 ["/"+i for i in sorted(self.source_data)
1024 if i not in self.target_data and
1025 i not in self.renames] +
1026 list(extras))
1027
1028 def TotalPatchSize(self):
1029 return sum(i[1].size for i in self.patch_list)
1030
1031 def EmitPatches(self, script, total_patch_size, so_far):
1032 self.deferred_patch_list = deferred_patch_list = []
1033 for item in self.patch_list:
1034 tf, sf, size, _ = item
1035 if tf.name == "system/build.prop":
1036 deferred_patch_list.append(item)
1037 continue
1038 if (sf.name != tf.name):
1039 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1040 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
1041 so_far += tf.size
1042 script.SetProgress(so_far / total_patch_size)
1043 return so_far
1044
1045 def EmitDeferredPatches(self, script):
1046 for item in self.deferred_patch_list:
1047 tf, sf, size, _ = item
1048 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
1049 script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None)
1050
1051 def EmitRenames(self, script):
1052 if len(self.renames) > 0:
1053 script.Print("Renaming files...")
1054 for src, tgt in self.renames.iteritems():
1055 print "Renaming " + src + " to " + tgt.name
1056 script.RenameFile(src, tgt.name)
1057
1058
1059
1060
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001061def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001062 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1063 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1064
Doug Zongker26e66192014-02-20 13:22:07 -08001065 if (OPTIONS.block_based and
1066 target_has_recovery_patch and
1067 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001068 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1069
Doug Zongker37974732010-09-16 17:44:38 -07001070 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1071 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001072
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001073 if source_version == 0:
1074 print ("WARNING: generating edify script for a source that "
1075 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -07001076 script = edify_generator.EdifyGenerator(source_version,
1077 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -07001078
Michael Runge6e836112014-04-15 17:40:21 -07001079 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001080 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001081 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001082 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001083 if OPTIONS.oem_source is None:
1084 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001085 script.Mount("/oem", recovery_mount_options)
Michael Runge6e836112014-04-15 17:40:21 -07001086 oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
1087
1088 metadata = {"pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -07001089 OPTIONS.source_info_dict),
1090 "post-timestamp": GetBuildProp("ro.build.date.utc",
1091 OPTIONS.target_info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -07001092 }
1093
Doug Zongker05d3dea2009-06-22 11:32:31 -07001094 device_specific = common.DeviceSpecificParams(
1095 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001096 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001097 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001098 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001099 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001100 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001101 metadata=metadata,
1102 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001103
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001104 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001105 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001106 if HasVendorPartition(target_zip):
1107 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001108 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001109 else:
1110 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001111
1112 target_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.target_info_dict)
1113 source_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.source_info_dict)
1114
1115 if oem_props is None:
1116 script.AssertSomeFingerprint(source_fp, target_fp)
1117 else:
1118 script.AssertSomeThumbprint(
1119 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1120 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1121
Doug Zongker2ea21062010-04-28 16:05:21 -07001122 metadata["pre-build"] = source_fp
1123 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001124
Doug Zongker55d93282011-01-25 17:03:34 -08001125 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001126 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1127 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001128 target_boot = common.GetBootableImage(
1129 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001130 updating_boot = (not OPTIONS.two_step and
1131 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001132
Doug Zongker55d93282011-01-25 17:03:34 -08001133 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001134 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1135 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001136 target_recovery = common.GetBootableImage(
1137 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001138 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001139
Doug Zongker881dd402009-09-20 14:03:55 -07001140 # Here's how we divide up the progress bar:
1141 # 0.1 for verifying the start state (PatchCheck calls)
1142 # 0.8 for applying patches (ApplyPatch calls)
1143 # 0.1 for unpacking verbatim files, symlinking, and doing the
1144 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001145
Michael Runge6e836112014-04-15 17:40:21 -07001146 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001147 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001148
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001149 # Two-step incremental package strategy (in chronological order,
1150 # which is *not* the order in which the generated script has
1151 # things):
1152 #
1153 # if stage is not "2/3" or "3/3":
1154 # do verification on current system
1155 # write recovery image to boot partition
1156 # set stage to "2/3"
1157 # reboot to boot partition and restart recovery
1158 # else if stage is "2/3":
1159 # write recovery image to recovery partition
1160 # set stage to "3/3"
1161 # reboot to recovery partition and restart recovery
1162 # else:
1163 # (stage must be "3/3")
1164 # perform update:
1165 # patch system files, etc.
1166 # force full install of new boot image
1167 # set up system to update recovery partition on first boot
1168 # complete script normally (allow recovery to mark itself finished and reboot)
1169
1170 if OPTIONS.two_step:
1171 if not OPTIONS.info_dict.get("multistage_support", None):
1172 assert False, "two-step packages not supported by this build"
1173 fs = OPTIONS.info_dict["fstab"]["/misc"]
1174 assert fs.fs_type.upper() == "EMMC", \
1175 "two-step packages only supported on devices with EMMC /misc partitions"
1176 bcb_dev = {"bcb_dev": fs.device}
1177 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1178 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001179if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001180""" % bcb_dev)
1181 script.AppendExtra("sleep(20);\n");
1182 script.WriteRawImage("/recovery", "recovery.img")
1183 script.AppendExtra("""
1184set_stage("%(bcb_dev)s", "3/3");
1185reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001186else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001187""" % bcb_dev)
1188
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001189 script.Print("Verifying current system...")
1190
Doug Zongkere5ff5902012-01-17 10:55:37 -08001191 device_specific.IncrementalOTA_VerifyBegin()
1192
Doug Zongker881dd402009-09-20 14:03:55 -07001193 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001194 so_far = system_diff.EmitVerification(script)
1195 if vendor_diff:
1196 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001197
Doug Zongker5da317e2009-06-02 13:38:17 -07001198 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001199 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001200 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001201 print "boot target: %d source: %d diff: %d" % (
1202 target_boot.size, source_boot.size, len(d))
1203
Doug Zongker048e7ca2009-06-15 14:31:53 -07001204 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001205
Doug Zongker96a57e72010-09-26 14:57:41 -07001206 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001207
1208 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1209 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001210 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001211 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001212 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001213
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001214 size = []
1215 if system_diff.patch_list: size.append(system_diff.largest_source_size)
1216 if vendor_diff:
1217 if vendor_diff.patch_list: size.append(vendor_diff.largest_source_size)
1218 if size or updating_recovery or updating_boot:
1219 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001220
Doug Zongker05d3dea2009-06-22 11:32:31 -07001221 device_specific.IncrementalOTA_VerifyEnd()
1222
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001223 if OPTIONS.two_step:
1224 script.WriteRawImage("/boot", "recovery.img")
1225 script.AppendExtra("""
1226set_stage("%(bcb_dev)s", "2/3");
1227reboot_now("%(bcb_dev)s", "");
1228else
1229""" % bcb_dev)
1230
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001231 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001232
Doug Zongkere5ff5902012-01-17 10:55:37 -08001233 device_specific.IncrementalOTA_InstallBegin()
1234
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001235 if OPTIONS.two_step:
1236 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1237 script.WriteRawImage("/boot", "boot.img")
1238 print "writing full boot image (forced by two-step mode)"
1239
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001240 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001241 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1242 if vendor_diff:
1243 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001244
Doug Zongker881dd402009-09-20 14:03:55 -07001245 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001246 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1247 if vendor_diff:
1248 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001249 if updating_boot:
1250 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001251
1252 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001253 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1254 if vendor_diff:
1255 script.Print("Patching vendor files...")
1256 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001257
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001258 if not OPTIONS.two_step:
1259 if updating_boot:
1260 # Produce the boot image by applying a patch to the current
1261 # contents of the boot partition, and write it back to the
1262 # partition.
1263 script.Print("Patching boot image...")
1264 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1265 % (boot_type, boot_device,
1266 source_boot.size, source_boot.sha1,
1267 target_boot.size, target_boot.sha1),
1268 "-",
1269 target_boot.size, target_boot.sha1,
1270 source_boot.sha1, "patch/boot.img.p")
1271 so_far += target_boot.size
1272 script.SetProgress(so_far / total_patch_size)
1273 print "boot image changed; including."
1274 else:
1275 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001276
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001277 system_items = ItemSet("system", "META/filesystem_config.txt")
1278 if vendor_diff:
1279 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1280
Doug Zongkereef39442009-04-02 12:14:19 -07001281 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001282 # Recovery is generated as a patch using both the boot image
1283 # (which contains the same linux kernel as recovery) and the file
1284 # /system/etc/recovery-resource.dat (which contains all the images
1285 # used in the recovery UI) as sources. This lets us minimize the
1286 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001287 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001288 # For older builds where recovery-resource.dat is not present, we
1289 # use only the boot image as the source.
1290
Doug Zongkerc9253822014-02-04 12:17:58 -08001291 if not target_has_recovery_patch:
1292 def output_sink(fn, data):
1293 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001294 system_items.Get("system/" + fn, dir=False)
Doug Zongkerc9253822014-02-04 12:17:58 -08001295
1296 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1297 target_recovery, target_boot)
1298 script.DeleteFiles(["/system/recovery-from-boot.p",
1299 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001300 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001301 else:
1302 print "recovery image unchanged; skipping."
1303
Doug Zongker881dd402009-09-20 14:03:55 -07001304 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001305
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001306 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1307 if vendor_diff:
1308 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1309
1310 temp_script = script.MakeTemporary()
1311 system_items.GetMetadata(target_zip)
1312 system_items.Get("system").SetPermissions(temp_script)
1313 if vendor_diff:
1314 vendor_items.GetMetadata(target_zip)
1315 vendor_items.Get("vendor").SetPermissions(temp_script)
1316
1317 # Note that this call will mess up the trees of Items, so make sure
1318 # we're done with them.
1319 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1320 if vendor_diff:
1321 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001322
1323 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001324 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1325
1326 # Delete all the symlinks in source that aren't in target. This
1327 # needs to happen before verbatim files are unpacked, in case a
1328 # symlink in the source is replaced by a real file in the target.
1329 to_delete = []
1330 for dest, link in source_symlinks:
1331 if link not in target_symlinks_d:
1332 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001333 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001334
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001335 if system_diff.verbatim_targets:
1336 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001337 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001338 if vendor_diff and vendor_diff.verbatim_targets:
1339 script.Print("Unpacking new vendor files...")
1340 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001341
Doug Zongkerc9253822014-02-04 12:17:58 -08001342 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001343 script.Print("Unpacking new recovery...")
1344 script.UnpackPackageDir("recovery", "/system")
1345
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001346 system_diff.EmitRenames(script)
1347 if vendor_diff:
1348 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001349
Doug Zongker05d3dea2009-06-22 11:32:31 -07001350 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001351
1352 # Create all the symlinks that don't already exist, or point to
1353 # somewhere different than what we want. Delete each symlink before
1354 # creating it, since the 'symlink' command won't overwrite.
1355 to_create = []
1356 for dest, link in target_symlinks:
1357 if link in source_symlinks_d:
1358 if dest != source_symlinks_d[link]:
1359 to_create.append((dest, link))
1360 else:
1361 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001362 script.DeleteFiles([i[1] for i in to_create])
1363 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001364
1365 # Now that the symlinks are created, we can set all the
1366 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001367 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001368
Doug Zongker881dd402009-09-20 14:03:55 -07001369 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001370 device_specific.IncrementalOTA_InstallEnd()
1371
Doug Zongker1c390a22009-05-14 19:06:36 -07001372 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001373 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001374
Doug Zongkere92f15a2011-08-26 13:46:40 -07001375 # Patch the build.prop file last, so if something fails but the
1376 # device can still come up, it appears to be the old build and will
1377 # get set the OTA package again to retry.
1378 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001379 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001380
Doug Zongker922206e2014-03-04 13:16:24 -08001381 if OPTIONS.wipe_user_data:
1382 script.Print("Erasing user data...")
1383 script.FormatPartition("/data")
1384
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001385 if OPTIONS.two_step:
1386 script.AppendExtra("""
1387set_stage("%(bcb_dev)s", "");
1388endif;
1389endif;
1390""" % bcb_dev)
1391
Michael Runge63f01de2014-10-28 19:24:19 -07001392 if OPTIONS.verify and system_diff:
1393 script.Print("Remounting and verifying system partition files...")
1394 script.Unmount("/system")
1395 script.Mount("/system")
1396 system_diff.EmitExplicitTargetVerification(script)
1397
1398 if OPTIONS.verify and vendor_diff:
1399 script.Print("Remounting and verifying vendor partition files...")
1400 script.Unmount("/vendor")
1401 script.Mount("/vendor")
1402 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001403 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001404
Doug Zongker2ea21062010-04-28 16:05:21 -07001405 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001406
1407
1408def main(argv):
1409
1410 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001411 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001412 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001413 elif o in ("-k", "--package_key"):
1414 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001415 elif o in ("-i", "--incremental_from"):
1416 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001417 elif o in ("-w", "--wipe_user_data"):
1418 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001419 elif o in ("-n", "--no_prereq"):
1420 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001421 elif o in ("-o", "--oem_settings"):
1422 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001423 elif o in ("-e", "--extra_script"):
1424 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001425 elif o in ("-a", "--aslr_mode"):
1426 if a in ("on", "On", "true", "True", "yes", "Yes"):
1427 OPTIONS.aslr_mode = True
1428 else:
1429 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001430 elif o in ("-t", "--worker_threads"):
1431 if a.isdigit():
1432 OPTIONS.worker_threads = int(a)
1433 else:
1434 raise ValueError("Cannot parse value %r for option %r - only "
1435 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001436 elif o in ("-2", "--two_step"):
1437 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001438 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001439 OPTIONS.no_signing = True
Michael Runge63f01de2014-10-28 19:24:19 -07001440 elif o in ("--verify"):
1441 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001442 elif o == "--block":
1443 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001444 elif o in ("-b", "--binary"):
1445 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001446 elif o in ("--no_fallback_to_full",):
1447 OPTIONS.fallback_to_full = False
Doug Zongkereef39442009-04-02 12:14:19 -07001448 else:
1449 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001450 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001451
1452 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001453 extra_opts="b:k:i:d:wne:t:a:2o:",
Doug Zongkereef39442009-04-02 12:14:19 -07001454 extra_long_opts=["board_config=",
1455 "package_key=",
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001456 "incremental_from=",
Doug Zongker962069c2009-04-23 11:41:58 -07001457 "wipe_user_data",
Doug Zongker1c390a22009-05-14 19:06:36 -07001458 "no_prereq",
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001459 "extra_script=",
Hristo Bojinov96be7202010-08-02 10:26:17 -07001460 "worker_threads=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001461 "aslr_mode=",
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001462 "two_step",
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001463 "no_signing",
Doug Zongker26e66192014-02-20 13:22:07 -08001464 "block",
Doug Zongker25568482014-03-03 10:21:27 -08001465 "binary=",
Michael Runge6e836112014-04-15 17:40:21 -07001466 "oem_settings=",
Michael Runge63f01de2014-10-28 19:24:19 -07001467 "verify",
Doug Zongker62d4f182014-08-04 16:06:43 -07001468 "no_fallback_to_full",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001469 ],
Doug Zongkereef39442009-04-02 12:14:19 -07001470 extra_option_handler=option_handler)
1471
1472 if len(args) != 2:
1473 common.Usage(__doc__)
1474 sys.exit(1)
1475
Doug Zongker1c390a22009-05-14 19:06:36 -07001476 if OPTIONS.extra_script is not None:
1477 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1478
Doug Zongkereef39442009-04-02 12:14:19 -07001479 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001480 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001481
Doug Zongkereef39442009-04-02 12:14:19 -07001482 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001483 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001484
1485 # If this image was originally labelled with SELinux contexts, make sure we
1486 # also apply the labels in our new image. During building, the "file_contexts"
1487 # is in the out/ directory tree, but for repacking from target-files.zip it's
1488 # in the root directory of the ramdisk.
1489 if "selinux_fc" in OPTIONS.info_dict:
1490 OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK",
1491 "file_contexts")
1492
Doug Zongker37974732010-09-16 17:44:38 -07001493 if OPTIONS.verbose:
1494 print "--- target info ---"
1495 common.DumpInfoDict(OPTIONS.info_dict)
1496
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001497 # If the caller explicitly specified the device-specific extensions
1498 # path via -s/--device_specific, use that. Otherwise, use
1499 # META/releasetools.py if it is present in the target target_files.
1500 # Otherwise, take the path of the file from 'tool_extensions' in the
1501 # info dict and look for that in the local filesystem, relative to
1502 # the current directory.
1503
Doug Zongker37974732010-09-16 17:44:38 -07001504 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001505 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1506 if os.path.exists(from_input):
1507 print "(using device-specific extensions from target_files)"
1508 OPTIONS.device_specific = from_input
1509 else:
1510 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1511
Doug Zongker37974732010-09-16 17:44:38 -07001512 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001513 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001514
Doug Zongker62d4f182014-08-04 16:06:43 -07001515 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001516
Doug Zongker62d4f182014-08-04 16:06:43 -07001517 if OPTIONS.no_signing:
1518 if os.path.exists(args[1]): os.unlink(args[1])
1519 output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
1520 else:
1521 temp_zip_file = tempfile.NamedTemporaryFile()
1522 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1523 compression=zipfile.ZIP_DEFLATED)
1524
1525 if OPTIONS.incremental_source is None:
1526 WriteFullOTAPackage(input_zip, output_zip)
1527 if OPTIONS.package_key is None:
1528 OPTIONS.package_key = OPTIONS.info_dict.get(
1529 "default_system_dev_certificate",
1530 "build/target/product/security/testkey")
1531 break
1532
1533 else:
1534 print "unzipping source target-files..."
1535 OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
1536 OPTIONS.target_info_dict = OPTIONS.info_dict
1537 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1538 if "selinux_fc" in OPTIONS.source_info_dict:
1539 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(OPTIONS.source_tmp, "BOOT", "RAMDISK",
1540 "file_contexts")
1541 if OPTIONS.package_key is None:
1542 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1543 "default_system_dev_certificate",
1544 "build/target/product/security/testkey")
1545 if OPTIONS.verbose:
1546 print "--- source info ---"
1547 common.DumpInfoDict(OPTIONS.source_info_dict)
1548 try:
1549 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
1550 break
1551 except ValueError:
1552 if not OPTIONS.fallback_to_full: raise
1553 print "--- failed to build incremental; falling back to full ---"
1554 OPTIONS.incremental_source = None
1555 output_zip.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001556
1557 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001558
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001559 if not OPTIONS.no_signing:
1560 SignOutput(temp_zip_file.name, args[1])
1561 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001562
Doug Zongkereef39442009-04-02 12:14:19 -07001563 print "done."
1564
1565
1566if __name__ == '__main__':
1567 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001568 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001569 main(sys.argv[1:])
1570 except common.ExternalError, e:
1571 print
1572 print " ERROR: %s" % (e,)
1573 print
1574 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001575 finally:
1576 common.Cleanup()