blob: 768f4cb5926352e6dda5c7be504df2db2fbbb168 [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
Tao Bao007979e2015-05-12 11:42:31 -0700460 # Bug: http://b/20939131
461 # In ext4 filesystems, block 0 might be changed even being mounted
462 # R/O. We add it to clobbered_blocks so that it will be written to the
463 # target unconditionally. Note that they are still part of care_map.
464 clobbered_blocks = "0"
465
466 return sparse_img.SparseImage(path, mappath, clobbered_blocks)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700467
468
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700469def WriteFullOTAPackage(input_zip, output_zip):
Doug Zongker9ce2ebf2010-04-21 14:08:44 -0700470 # TODO: how to determine this? We don't know what version it will
471 # be installed on top of. For now, we expect the API just won't
472 # change very often.
Doug Zongkerc77a9ad2010-09-16 11:28:43 -0700473 script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -0700474
Michael Runge6e836112014-04-15 17:40:21 -0700475 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700476 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -0700477 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700478 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -0700479 if OPTIONS.oem_source is None:
480 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700481 script.Mount("/oem", recovery_mount_options)
Michael Runge6e836112014-04-15 17:40:21 -0700482 oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
483
484 metadata = {"post-build": CalculateFingerprint(
485 oem_props, oem_dict, OPTIONS.info_dict),
486 "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700487 OPTIONS.info_dict),
488 "post-timestamp": GetBuildProp("ro.build.date.utc",
489 OPTIONS.info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -0700490 }
491
Doug Zongker05d3dea2009-06-22 11:32:31 -0700492 device_specific = common.DeviceSpecificParams(
493 input_zip=input_zip,
Doug Zongker37974732010-09-16 17:44:38 -0700494 input_version=OPTIONS.info_dict["recovery_api_version"],
Doug Zongker05d3dea2009-06-22 11:32:31 -0700495 output_zip=output_zip,
496 script=script,
Doug Zongker2ea21062010-04-28 16:05:21 -0700497 input_tmp=OPTIONS.input_tmp,
Doug Zongker96a57e72010-09-26 14:57:41 -0700498 metadata=metadata,
499 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700500
Doug Zongkerc9253822014-02-04 12:17:58 -0800501 has_recovery_patch = HasRecoveryPatch(input_zip)
Doug Zongker26e66192014-02-20 13:22:07 -0800502 block_based = OPTIONS.block_based and has_recovery_patch
Doug Zongkerc9253822014-02-04 12:17:58 -0800503
Doug Zongker962069c2009-04-23 11:41:58 -0700504 if not OPTIONS.omit_prereq:
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700505 ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700506 ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
507 script.AssertOlderBuild(ts, ts_text)
Doug Zongkereef39442009-04-02 12:14:19 -0700508
Michael Runge6e836112014-04-15 17:40:21 -0700509 AppendAssertions(script, OPTIONS.info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700510 device_specific.FullOTA_Assertions()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800511
512 # Two-step package strategy (in chronological order, which is *not*
513 # the order in which the generated script has things):
514 #
515 # if stage is not "2/3" or "3/3":
516 # write recovery image to boot partition
517 # set stage to "2/3"
518 # reboot to boot partition and restart recovery
519 # else if stage is "2/3":
520 # write recovery image to recovery partition
521 # set stage to "3/3"
522 # reboot to recovery partition and restart recovery
523 # else:
524 # (stage must be "3/3")
525 # set stage to ""
526 # do normal full package installation:
527 # wipe and install system, boot image, etc.
528 # set up system to update recovery partition on first boot
529 # complete script normally (allow recovery to mark itself finished and reboot)
530
531 recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
532 OPTIONS.input_tmp, "RECOVERY")
533 if OPTIONS.two_step:
534 if not OPTIONS.info_dict.get("multistage_support", None):
535 assert False, "two-step packages not supported by this build"
536 fs = OPTIONS.info_dict["fstab"]["/misc"]
537 assert fs.fs_type.upper() == "EMMC", \
538 "two-step packages only supported on devices with EMMC /misc partitions"
539 bcb_dev = {"bcb_dev": fs.device}
540 common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
541 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700542if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800543""" % bcb_dev)
544 script.WriteRawImage("/recovery", "recovery.img")
545 script.AppendExtra("""
546set_stage("%(bcb_dev)s", "3/3");
547reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700548else if get_stage("%(bcb_dev)s") == "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800549""" % bcb_dev)
550
Doug Zongkere5ff5902012-01-17 10:55:37 -0800551 device_specific.FullOTA_InstallBegin()
Doug Zongker171f1cd2009-06-15 22:36:37 -0700552
Doug Zongker01ce19c2014-02-04 13:48:15 -0800553 system_progress = 0.75
Doug Zongkereef39442009-04-02 12:14:19 -0700554
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700555 if OPTIONS.wipe_user_data:
Doug Zongker01ce19c2014-02-04 13:48:15 -0800556 system_progress -= 0.1
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700557 if HasVendorPartition(input_zip):
558 system_progress -= 0.1
Doug Zongkerdbfaae52009-04-21 17:12:54 -0700559
Kenny Rootf32dc712012-04-08 10:42:34 -0700560 if "selinux_fc" in OPTIONS.info_dict:
561 WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
Stephen Smalley56882bf2012-02-09 13:36:21 -0500562
Michael Runge7cd99ba2014-10-22 17:21:48 -0700563 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
564
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700565 system_items = ItemSet("system", "META/filesystem_config.txt")
Doug Zongker4b9596f2014-06-09 14:15:45 -0700566 script.ShowProgress(system_progress, 0)
Jesse Zhao75bcea02015-01-06 10:59:53 -0800567
Doug Zongker26e66192014-02-20 13:22:07 -0800568 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700569 # Full OTA is done as an "incremental" against an empty source
570 # image. This has the effect of writing new data from the package
571 # to the entire partition, but lets us reuse the updater code that
572 # writes incrementals to do it.
573 system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
574 system_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700575 system_diff = common.BlockDifference("system", system_tgt, src=None)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700576 system_diff.WriteScript(script, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800577 else:
578 script.FormatPartition("/system")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700579 script.Mount("/system", recovery_mount_options)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800580 if not has_recovery_patch:
581 script.UnpackPackageDir("recovery", "/system")
Doug Zongker26e66192014-02-20 13:22:07 -0800582 script.UnpackPackageDir("system", "/system")
Doug Zongkereef39442009-04-02 12:14:19 -0700583
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700584 symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
Doug Zongker01ce19c2014-02-04 13:48:15 -0800585 script.MakeSymlinks(symlinks)
Doug Zongkereef39442009-04-02 12:14:19 -0700586
Doug Zongker55d93282011-01-25 17:03:34 -0800587 boot_img = common.GetBootableImage("boot.img", "boot.img",
588 OPTIONS.input_tmp, "BOOT")
Doug Zongkerc9253822014-02-04 12:17:58 -0800589
Doug Zongker91a99c22014-05-09 13:15:01 -0700590 if not block_based:
Doug Zongkerc9253822014-02-04 12:17:58 -0800591 def output_sink(fn, data):
592 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700593 system_items.Get("system/" + fn, dir=False)
Doug Zongkerc9253822014-02-04 12:17:58 -0800594
595 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
596 recovery_img, boot_img)
Doug Zongkereef39442009-04-02 12:14:19 -0700597
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700598 system_items.GetMetadata(input_zip)
599 system_items.Get("system").SetPermissions(script)
600
601 if HasVendorPartition(input_zip):
602 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
603 script.ShowProgress(0.1, 0)
604
605 if block_based:
Doug Zongkerfc44a512014-08-26 13:10:25 -0700606 vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
607 vendor_tgt.ResetFileMap()
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700608 vendor_diff = common.BlockDifference("vendor", vendor_tgt)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700609 vendor_diff.WriteScript(script, output_zip)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700610 else:
611 script.FormatPartition("/vendor")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700612 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700613 script.UnpackPackageDir("vendor", "/vendor")
614
615 symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
616 script.MakeSymlinks(symlinks)
617
618 vendor_items.GetMetadata(input_zip)
619 vendor_items.Get("vendor").SetPermissions(script)
Doug Zongker73ef8252009-07-23 15:12:53 -0700620
Doug Zongker37974732010-09-16 17:44:38 -0700621 common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
Doug Zongker73ef8252009-07-23 15:12:53 -0700622 common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700623
Doug Zongker01ce19c2014-02-04 13:48:15 -0800624 script.ShowProgress(0.05, 5)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700625 script.WriteRawImage("/boot", "boot.img")
Doug Zongker05d3dea2009-06-22 11:32:31 -0700626
Doug Zongker01ce19c2014-02-04 13:48:15 -0800627 script.ShowProgress(0.2, 10)
Doug Zongker05d3dea2009-06-22 11:32:31 -0700628 device_specific.FullOTA_InstallEnd()
Doug Zongkereef39442009-04-02 12:14:19 -0700629
Doug Zongker1c390a22009-05-14 19:06:36 -0700630 if OPTIONS.extra_script is not None:
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700631 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -0700632
Doug Zongker14833602010-02-02 13:12:04 -0800633 script.UnmountAll()
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800634
Doug Zongker922206e2014-03-04 13:16:24 -0800635 if OPTIONS.wipe_user_data:
636 script.ShowProgress(0.1, 10)
637 script.FormatPartition("/data")
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700638
Doug Zongker9b23f2c2013-11-25 14:44:12 -0800639 if OPTIONS.two_step:
640 script.AppendExtra("""
641set_stage("%(bcb_dev)s", "");
642""" % bcb_dev)
643 script.AppendExtra("else\n")
644 script.WriteRawImage("/boot", "recovery.img")
645 script.AppendExtra("""
646set_stage("%(bcb_dev)s", "2/3");
647reboot_now("%(bcb_dev)s", "");
648endif;
649endif;
650""" % bcb_dev)
Doug Zongker25568482014-03-03 10:21:27 -0800651 script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
Doug Zongker2ea21062010-04-28 16:05:21 -0700652 WriteMetadata(metadata, output_zip)
653
Doug Zongkerfc44a512014-08-26 13:10:25 -0700654
Justin Harrison2de68bb2015-02-13 18:47:51 +0000655def WritePolicyConfig(file_context, output_zip):
656 f = open(file_context, 'r');
657 basename = os.path.basename(file_context)
658 common.ZipWriteStr(output_zip, basename, f.read())
Stephen Smalley56882bf2012-02-09 13:36:21 -0500659
Doug Zongker2ea21062010-04-28 16:05:21 -0700660
661def WriteMetadata(metadata, output_zip):
662 common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
663 "".join(["%s=%s\n" % kv
664 for kv in sorted(metadata.iteritems())]))
Doug Zongkereef39442009-04-02 12:14:19 -0700665
Doug Zongkerfc44a512014-08-26 13:10:25 -0700666
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700667def LoadPartitionFiles(z, partition):
668 """Load all the files from the given partition in a given target-files
Doug Zongkereef39442009-04-02 12:14:19 -0700669 ZipFile, and return a dict of {filename: File object}."""
670 out = {}
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700671 prefix = partition.upper() + "/"
Doug Zongkereef39442009-04-02 12:14:19 -0700672 for info in z.infolist():
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700673 if info.filename.startswith(prefix) and not IsSymlink(info):
Hristo Bojinov96be7202010-08-02 10:26:17 -0700674 basefilename = info.filename[7:]
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700675 fn = partition + "/" + basefilename
Doug Zongkereef39442009-04-02 12:14:19 -0700676 data = z.read(info.filename)
Doug Zongkerea5d7a92010-09-12 15:26:16 -0700677 out[fn] = common.File(fn, data)
Doug Zongker1807e702012-02-28 12:21:08 -0800678 return out
Doug Zongkereef39442009-04-02 12:14:19 -0700679
680
Doug Zongker1eb74dd2012-08-16 16:19:00 -0700681def GetBuildProp(prop, info_dict):
682 """Return the fingerprint of the build of a given target-files info_dict."""
683 try:
684 return info_dict.get("build.prop", {})[prop]
685 except KeyError:
Ying Wangc73e4612014-04-15 15:27:43 -0700686 raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
Doug Zongkereef39442009-04-02 12:14:19 -0700687
Doug Zongkerfc44a512014-08-26 13:10:25 -0700688
Michael Runge4038aa82013-12-13 18:06:28 -0800689def AddToKnownPaths(filename, known_paths):
690 if filename[-1] == "/":
691 return
692 dirs = filename.split("/")[:-1]
693 while len(dirs) > 0:
694 path = "/".join(dirs)
695 if path in known_paths:
696 break;
697 known_paths.add(path)
698 dirs.pop()
Doug Zongkereef39442009-04-02 12:14:19 -0700699
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700700
Geremy Condra36bd3652014-02-06 19:45:10 -0800701def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
702 source_version = OPTIONS.source_info_dict["recovery_api_version"]
703 target_version = OPTIONS.target_info_dict["recovery_api_version"]
704
705 if source_version == 0:
706 print ("WARNING: generating edify script for a source that "
707 "can't install it.")
708 script = edify_generator.EdifyGenerator(source_version,
709 OPTIONS.target_info_dict)
710
711 metadata = {"pre-device": GetBuildProp("ro.product.device",
712 OPTIONS.source_info_dict),
713 "post-timestamp": GetBuildProp("ro.build.date.utc",
714 OPTIONS.target_info_dict),
715 }
716
717 device_specific = common.DeviceSpecificParams(
718 source_zip=source_zip,
719 source_version=source_version,
720 target_zip=target_zip,
721 target_version=target_version,
722 output_zip=output_zip,
723 script=script,
724 metadata=metadata,
725 info_dict=OPTIONS.info_dict)
726
727 source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
728 target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
729 metadata["pre-build"] = source_fp
730 metadata["post-build"] = target_fp
731
732 source_boot = common.GetBootableImage(
733 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
734 OPTIONS.source_info_dict)
735 target_boot = common.GetBootableImage(
736 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
737 updating_boot = (not OPTIONS.two_step and
738 (source_boot.data != target_boot.data))
739
740 source_recovery = common.GetBootableImage(
741 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
742 OPTIONS.source_info_dict)
743 target_recovery = common.GetBootableImage(
744 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
745 updating_recovery = (source_recovery.data != target_recovery.data)
746
Doug Zongkerfc44a512014-08-26 13:10:25 -0700747 system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
748 system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Tao Baodaebaa62015-03-12 12:32:37 -0700749
750 blockimgdiff_version = 1
751 if OPTIONS.info_dict:
752 blockimgdiff_version = max(
753 int(i) for i in
754 OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(","))
755
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700756 system_diff = common.BlockDifference("system", system_tgt, system_src,
Tao Bao007979e2015-05-12 11:42:31 -0700757 check_first_block=False,
Tao Baodaebaa62015-03-12 12:32:37 -0700758 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700759
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700760 if HasVendorPartition(target_zip):
761 if not HasVendorPartition(source_zip):
762 raise RuntimeError("can't generate incremental that adds /vendor")
Doug Zongkerfc44a512014-08-26 13:10:25 -0700763 vendor_src = GetImage("vendor", OPTIONS.source_tmp, OPTIONS.source_info_dict)
764 vendor_tgt = GetImage("vendor", OPTIONS.target_tmp, OPTIONS.target_info_dict)
Doug Zongkerb34fcce2014-09-11 09:34:56 -0700765 vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
Tao Bao007979e2015-05-12 11:42:31 -0700766 check_first_block=False,
Tao Baodaebaa62015-03-12 12:32:37 -0700767 version=blockimgdiff_version)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700768 else:
769 vendor_diff = None
Geremy Condra36bd3652014-02-06 19:45:10 -0800770
Michael Rungec6e3afd2014-05-05 11:55:47 -0700771 oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700772 recovery_mount_options = OPTIONS.target_info_dict.get("recovery_mount_options")
Michael Rungec6e3afd2014-05-05 11:55:47 -0700773 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -0700774 if oem_props is not None and len(oem_props) > 0:
Michael Rungec6e3afd2014-05-05 11:55:47 -0700775 if OPTIONS.oem_source is None:
776 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -0700777 script.Mount("/oem", recovery_mount_options)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700778 oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
779
780 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800781 device_specific.IncrementalOTA_Assertions()
782
783 # Two-step incremental package strategy (in chronological order,
784 # which is *not* the order in which the generated script has
785 # things):
786 #
787 # if stage is not "2/3" or "3/3":
788 # do verification on current system
789 # write recovery image to boot partition
790 # set stage to "2/3"
791 # reboot to boot partition and restart recovery
792 # else if stage is "2/3":
793 # write recovery image to recovery partition
794 # set stage to "3/3"
795 # reboot to recovery partition and restart recovery
796 # else:
797 # (stage must be "3/3")
798 # perform update:
799 # patch system files, etc.
800 # force full install of new boot image
801 # set up system to update recovery partition on first boot
802 # complete script normally (allow recovery to mark itself finished and reboot)
803
804 if OPTIONS.two_step:
805 if not OPTIONS.info_dict.get("multistage_support", None):
806 assert False, "two-step packages not supported by this build"
807 fs = OPTIONS.info_dict["fstab"]["/misc"]
808 assert fs.fs_type.upper() == "EMMC", \
809 "two-step packages only supported on devices with EMMC /misc partitions"
810 bcb_dev = {"bcb_dev": fs.device}
811 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
812 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -0700813if get_stage("%(bcb_dev)s") == "2/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800814""" % bcb_dev)
815 script.AppendExtra("sleep(20);\n");
816 script.WriteRawImage("/recovery", "recovery.img")
817 script.AppendExtra("""
818set_stage("%(bcb_dev)s", "3/3");
819reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -0700820else if get_stage("%(bcb_dev)s") != "3/3" then
Geremy Condra36bd3652014-02-06 19:45:10 -0800821""" % bcb_dev)
822
823 script.Print("Verifying current system...")
824
825 device_specific.IncrementalOTA_VerifyBegin()
826
Michael Rungec6e3afd2014-05-05 11:55:47 -0700827 if oem_props is None:
Tao Baodaebaa62015-03-12 12:32:37 -0700828 # When blockimgdiff version is less than 3 (non-resumable block-based OTA),
829 # patching on a device that's already on the target build will damage the
830 # system. Because operations like move don't check the block state, they
831 # always apply the changes unconditionally.
832 if blockimgdiff_version <= 2:
833 script.AssertSomeFingerprint(source_fp)
834 else:
835 script.AssertSomeFingerprint(source_fp, target_fp)
Michael Rungec6e3afd2014-05-05 11:55:47 -0700836 else:
Tao Baodaebaa62015-03-12 12:32:37 -0700837 if blockimgdiff_version <= 2:
838 script.AssertSomeThumbprint(
839 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
840 else:
841 script.AssertSomeThumbprint(
842 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
843 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
Geremy Condra36bd3652014-02-06 19:45:10 -0800844
845 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700846 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Geremy Condra36bd3652014-02-06 19:45:10 -0800847 d = common.Difference(target_boot, source_boot)
848 _, _, d = d.ComputePatch()
Doug Zongkerf8340082014-08-05 10:39:37 -0700849 if d is None:
850 include_full_boot = True
851 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
852 else:
853 include_full_boot = False
Geremy Condra36bd3652014-02-06 19:45:10 -0800854
Doug Zongkerf8340082014-08-05 10:39:37 -0700855 print "boot target: %d source: %d diff: %d" % (
856 target_boot.size, source_boot.size, len(d))
Geremy Condra36bd3652014-02-06 19:45:10 -0800857
Doug Zongkerf8340082014-08-05 10:39:37 -0700858 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Geremy Condra36bd3652014-02-06 19:45:10 -0800859
Doug Zongkerf8340082014-08-05 10:39:37 -0700860 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
861 (boot_type, boot_device,
862 source_boot.size, source_boot.sha1,
863 target_boot.size, target_boot.sha1))
Geremy Condra36bd3652014-02-06 19:45:10 -0800864
865 device_specific.IncrementalOTA_VerifyEnd()
866
867 if OPTIONS.two_step:
868 script.WriteRawImage("/boot", "recovery.img")
869 script.AppendExtra("""
870set_stage("%(bcb_dev)s", "2/3");
871reboot_now("%(bcb_dev)s", "");
872else
873""" % bcb_dev)
874
Jesse Zhao75bcea02015-01-06 10:59:53 -0800875 # Verify the existing partitions.
876 system_diff.WriteVerifyScript(script)
877 if vendor_diff:
878 vendor_diff.WriteVerifyScript(script)
879
Geremy Condra36bd3652014-02-06 19:45:10 -0800880 script.Comment("---- start making changes here ----")
881
882 device_specific.IncrementalOTA_InstallBegin()
883
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700884 system_diff.WriteScript(script, output_zip,
885 progress=0.8 if vendor_diff else 0.9)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700886 if vendor_diff:
Doug Zongkerab7ca1d2014-08-26 10:40:28 -0700887 vendor_diff.WriteScript(script, output_zip, progress=0.1)
Geremy Condra36bd3652014-02-06 19:45:10 -0800888
889 if OPTIONS.two_step:
890 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
891 script.WriteRawImage("/boot", "boot.img")
892 print "writing full boot image (forced by two-step mode)"
893
894 if not OPTIONS.two_step:
895 if updating_boot:
Doug Zongkerf8340082014-08-05 10:39:37 -0700896 if include_full_boot:
897 print "boot image changed; including full."
898 script.Print("Installing boot image...")
899 script.WriteRawImage("/boot", "boot.img")
900 else:
901 # Produce the boot image by applying a patch to the current
902 # contents of the boot partition, and write it back to the
903 # partition.
904 print "boot image changed; including patch."
905 script.Print("Patching boot image...")
906 script.ShowProgress(0.1, 10)
907 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
908 % (boot_type, boot_device,
909 source_boot.size, source_boot.sha1,
910 target_boot.size, target_boot.sha1),
911 "-",
912 target_boot.size, target_boot.sha1,
913 source_boot.sha1, "patch/boot.img.p")
Geremy Condra36bd3652014-02-06 19:45:10 -0800914 else:
915 print "boot image unchanged; skipping."
916
917 # Do device-specific installation (eg, write radio image).
918 device_specific.IncrementalOTA_InstallEnd()
919
920 if OPTIONS.extra_script is not None:
921 script.AppendExtra(OPTIONS.extra_script)
922
Doug Zongker922206e2014-03-04 13:16:24 -0800923 if OPTIONS.wipe_user_data:
924 script.Print("Erasing user data...")
925 script.FormatPartition("/data")
926
Geremy Condra36bd3652014-02-06 19:45:10 -0800927 if OPTIONS.two_step:
928 script.AppendExtra("""
929set_stage("%(bcb_dev)s", "");
930endif;
931endif;
932""" % bcb_dev)
933
934 script.SetProgress(1)
Doug Zongker25568482014-03-03 10:21:27 -0800935 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Geremy Condra36bd3652014-02-06 19:45:10 -0800936 WriteMetadata(metadata, output_zip)
937
Doug Zongker32b527d2014-03-04 10:03:02 -0800938
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700939class FileDifference:
940 def __init__(self, partition, source_zip, target_zip, output_zip):
941 print "Loading target..."
942 self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
943 print "Loading source..."
944 self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
945
946 self.verbatim_targets = verbatim_targets = []
947 self.patch_list = patch_list = []
948 diffs = []
949 self.renames = renames = {}
950 known_paths = set()
951 largest_source_size = 0
952
953 matching_file_cache = {}
954 for fn, sf in source_data.items():
955 assert fn == sf.name
956 matching_file_cache["path:" + fn] = sf
957 if fn in target_data.keys():
958 AddToKnownPaths(fn, known_paths)
959 # Only allow eligibility for filename/sha matching
960 # if there isn't a perfect path match.
961 if target_data.get(sf.name) is None:
962 matching_file_cache["file:" + fn.split("/")[-1]] = sf
963 matching_file_cache["sha:" + sf.sha1] = sf
964
965 for fn in sorted(target_data.keys()):
966 tf = target_data[fn]
967 assert fn == tf.name
968 sf = ClosestFileMatch(tf, matching_file_cache, renames)
969 if sf is not None and sf.name != tf.name:
970 print "File has moved from " + sf.name + " to " + tf.name
971 renames[sf.name] = tf
972
973 if sf is None or fn in OPTIONS.require_verbatim:
974 # This file should be included verbatim
975 if fn in OPTIONS.prohibit_verbatim:
976 raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
977 print "send", fn, "verbatim"
978 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -0700979 verbatim_targets.append((fn, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700980 if fn in target_data.keys():
981 AddToKnownPaths(fn, known_paths)
982 elif tf.sha1 != sf.sha1:
983 # File is different; consider sending as a patch
984 diffs.append(common.Difference(tf, sf))
985 else:
986 # Target file data identical to source (may still be renamed)
987 pass
988
989 common.ComputeDifferences(diffs)
990
991 for diff in diffs:
992 tf, sf, d = diff.GetPatch()
993 path = "/".join(tf.name.split("/")[:-1])
994 if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
995 path not in known_paths:
996 # patch is almost as big as the file; don't bother patching
997 # or a patch + rename cannot take place due to the target
998 # directory not existing
999 tf.AddToZip(output_zip)
Michael Runge63f01de2014-10-28 19:24:19 -07001000 verbatim_targets.append((tf.name, tf.size, tf.sha1))
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001001 if sf.name in renames:
1002 del renames[sf.name]
1003 AddToKnownPaths(tf.name, known_paths)
1004 else:
1005 common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
1006 patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
1007 largest_source_size = max(largest_source_size, sf.size)
1008
1009 self.largest_source_size = largest_source_size
1010
1011 def EmitVerification(self, script):
1012 so_far = 0
1013 for tf, sf, size, patch_sha in self.patch_list:
1014 if tf.name != sf.name:
1015 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1016 script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
1017 so_far += sf.size
1018 return so_far
1019
Michael Runge63f01de2014-10-28 19:24:19 -07001020 def EmitExplicitTargetVerification(self, script):
1021 for fn, size, sha1 in self.verbatim_targets:
1022 if (fn[-1] != "/"):
1023 script.FileCheck("/"+fn, sha1)
1024 for tf, _, _, _ in self.patch_list:
1025 script.FileCheck(tf.name, tf.sha1)
1026
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001027 def RemoveUnneededFiles(self, script, extras=()):
1028 script.DeleteFiles(["/"+i[0] for i in self.verbatim_targets] +
1029 ["/"+i for i in sorted(self.source_data)
1030 if i not in self.target_data and
1031 i not in self.renames] +
1032 list(extras))
1033
1034 def TotalPatchSize(self):
1035 return sum(i[1].size for i in self.patch_list)
1036
1037 def EmitPatches(self, script, total_patch_size, so_far):
1038 self.deferred_patch_list = deferred_patch_list = []
1039 for item in self.patch_list:
1040 tf, sf, size, _ = item
1041 if tf.name == "system/build.prop":
1042 deferred_patch_list.append(item)
1043 continue
1044 if (sf.name != tf.name):
1045 script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1046 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
1047 so_far += tf.size
1048 script.SetProgress(so_far / total_patch_size)
1049 return so_far
1050
1051 def EmitDeferredPatches(self, script):
1052 for item in self.deferred_patch_list:
1053 tf, sf, size, _ = item
1054 script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
1055 script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None)
1056
1057 def EmitRenames(self, script):
1058 if len(self.renames) > 0:
1059 script.Print("Renaming files...")
1060 for src, tgt in self.renames.iteritems():
1061 print "Renaming " + src + " to " + tgt.name
1062 script.RenameFile(src, tgt.name)
1063
1064
1065
1066
Doug Zongkerc77a9ad2010-09-16 11:28:43 -07001067def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
Geremy Condra36bd3652014-02-06 19:45:10 -08001068 target_has_recovery_patch = HasRecoveryPatch(target_zip)
1069 source_has_recovery_patch = HasRecoveryPatch(source_zip)
1070
Doug Zongker26e66192014-02-20 13:22:07 -08001071 if (OPTIONS.block_based and
1072 target_has_recovery_patch and
1073 source_has_recovery_patch):
Geremy Condra36bd3652014-02-06 19:45:10 -08001074 return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
1075
Doug Zongker37974732010-09-16 17:44:38 -07001076 source_version = OPTIONS.source_info_dict["recovery_api_version"]
1077 target_version = OPTIONS.target_info_dict["recovery_api_version"]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001078
Doug Zongker9ce2ebf2010-04-21 14:08:44 -07001079 if source_version == 0:
1080 print ("WARNING: generating edify script for a source that "
1081 "can't install it.")
Doug Zongker1eb74dd2012-08-16 16:19:00 -07001082 script = edify_generator.EdifyGenerator(source_version,
1083 OPTIONS.target_info_dict)
Doug Zongkereef39442009-04-02 12:14:19 -07001084
Michael Runge6e836112014-04-15 17:40:21 -07001085 oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001086 recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
Michael Runge6e836112014-04-15 17:40:21 -07001087 oem_dict = None
Michael Runge560569a2014-09-18 15:12:45 -07001088 if oem_props is not None and len(oem_props) > 0:
Michael Runge6e836112014-04-15 17:40:21 -07001089 if OPTIONS.oem_source is None:
1090 raise common.ExternalError("OEM source required for this build")
Michael Runge7cd99ba2014-10-22 17:21:48 -07001091 script.Mount("/oem", recovery_mount_options)
Michael Runge6e836112014-04-15 17:40:21 -07001092 oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
1093
1094 metadata = {"pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
Doug Zongker1eb74dd2012-08-16 16:19:00 -07001095 OPTIONS.source_info_dict),
1096 "post-timestamp": GetBuildProp("ro.build.date.utc",
1097 OPTIONS.target_info_dict),
Doug Zongker2ea21062010-04-28 16:05:21 -07001098 }
1099
Doug Zongker05d3dea2009-06-22 11:32:31 -07001100 device_specific = common.DeviceSpecificParams(
1101 source_zip=source_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001102 source_version=source_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001103 target_zip=target_zip,
Doug Zongker14833602010-02-02 13:12:04 -08001104 target_version=target_version,
Doug Zongker05d3dea2009-06-22 11:32:31 -07001105 output_zip=output_zip,
Doug Zongker2ea21062010-04-28 16:05:21 -07001106 script=script,
Doug Zongker96a57e72010-09-26 14:57:41 -07001107 metadata=metadata,
1108 info_dict=OPTIONS.info_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001109
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001110 system_diff = FileDifference("system", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001111 script.Mount("/system", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001112 if HasVendorPartition(target_zip):
1113 vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
Michael Runge7cd99ba2014-10-22 17:21:48 -07001114 script.Mount("/vendor", recovery_mount_options)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001115 else:
1116 vendor_diff = None
Michael Runge6e836112014-04-15 17:40:21 -07001117
1118 target_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.target_info_dict)
1119 source_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.source_info_dict)
1120
1121 if oem_props is None:
1122 script.AssertSomeFingerprint(source_fp, target_fp)
1123 else:
1124 script.AssertSomeThumbprint(
1125 GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
1126 GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
1127
Doug Zongker2ea21062010-04-28 16:05:21 -07001128 metadata["pre-build"] = source_fp
1129 metadata["post-build"] = target_fp
Doug Zongkereef39442009-04-02 12:14:19 -07001130
Doug Zongker55d93282011-01-25 17:03:34 -08001131 source_boot = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001132 "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1133 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001134 target_boot = common.GetBootableImage(
1135 "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001136 updating_boot = (not OPTIONS.two_step and
1137 (source_boot.data != target_boot.data))
Doug Zongkereef39442009-04-02 12:14:19 -07001138
Doug Zongker55d93282011-01-25 17:03:34 -08001139 source_recovery = common.GetBootableImage(
Doug Zongkerd5131602012-08-02 14:46:42 -07001140 "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1141 OPTIONS.source_info_dict)
Doug Zongker55d93282011-01-25 17:03:34 -08001142 target_recovery = common.GetBootableImage(
1143 "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
Doug Zongkerf6a8bad2009-05-29 11:41:21 -07001144 updating_recovery = (source_recovery.data != target_recovery.data)
Doug Zongkereef39442009-04-02 12:14:19 -07001145
Doug Zongker881dd402009-09-20 14:03:55 -07001146 # Here's how we divide up the progress bar:
1147 # 0.1 for verifying the start state (PatchCheck calls)
1148 # 0.8 for applying patches (ApplyPatch calls)
1149 # 0.1 for unpacking verbatim files, symlinking, and doing the
1150 # device-specific commands.
Doug Zongkereef39442009-04-02 12:14:19 -07001151
Michael Runge6e836112014-04-15 17:40:21 -07001152 AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
Doug Zongker05d3dea2009-06-22 11:32:31 -07001153 device_specific.IncrementalOTA_Assertions()
Doug Zongkereef39442009-04-02 12:14:19 -07001154
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001155 # Two-step incremental package strategy (in chronological order,
1156 # which is *not* the order in which the generated script has
1157 # things):
1158 #
1159 # if stage is not "2/3" or "3/3":
1160 # do verification on current system
1161 # write recovery image to boot partition
1162 # set stage to "2/3"
1163 # reboot to boot partition and restart recovery
1164 # else if stage is "2/3":
1165 # write recovery image to recovery partition
1166 # set stage to "3/3"
1167 # reboot to recovery partition and restart recovery
1168 # else:
1169 # (stage must be "3/3")
1170 # perform update:
1171 # patch system files, etc.
1172 # force full install of new boot image
1173 # set up system to update recovery partition on first boot
1174 # complete script normally (allow recovery to mark itself finished and reboot)
1175
1176 if OPTIONS.two_step:
1177 if not OPTIONS.info_dict.get("multistage_support", None):
1178 assert False, "two-step packages not supported by this build"
1179 fs = OPTIONS.info_dict["fstab"]["/misc"]
1180 assert fs.fs_type.upper() == "EMMC", \
1181 "two-step packages only supported on devices with EMMC /misc partitions"
1182 bcb_dev = {"bcb_dev": fs.device}
1183 common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
1184 script.AppendExtra("""
Michael Rungefb8886d2014-10-23 13:51:04 -07001185if get_stage("%(bcb_dev)s") == "2/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001186""" % bcb_dev)
1187 script.AppendExtra("sleep(20);\n");
1188 script.WriteRawImage("/recovery", "recovery.img")
1189 script.AppendExtra("""
1190set_stage("%(bcb_dev)s", "3/3");
1191reboot_now("%(bcb_dev)s", "recovery");
Michael Rungefb8886d2014-10-23 13:51:04 -07001192else if get_stage("%(bcb_dev)s") != "3/3" then
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001193""" % bcb_dev)
1194
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001195 script.Print("Verifying current system...")
1196
Doug Zongkere5ff5902012-01-17 10:55:37 -08001197 device_specific.IncrementalOTA_VerifyBegin()
1198
Doug Zongker881dd402009-09-20 14:03:55 -07001199 script.ShowProgress(0.1, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001200 so_far = system_diff.EmitVerification(script)
1201 if vendor_diff:
1202 so_far += vendor_diff.EmitVerification(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001203
Doug Zongker5da317e2009-06-02 13:38:17 -07001204 if updating_boot:
Doug Zongkerea5d7a92010-09-12 15:26:16 -07001205 d = common.Difference(target_boot, source_boot)
Doug Zongker761e6422009-09-25 10:45:39 -07001206 _, _, d = d.ComputePatch()
Doug Zongker5da317e2009-06-02 13:38:17 -07001207 print "boot target: %d source: %d diff: %d" % (
1208 target_boot.size, source_boot.size, len(d))
1209
Doug Zongker048e7ca2009-06-15 14:31:53 -07001210 common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
Doug Zongker5da317e2009-06-02 13:38:17 -07001211
Doug Zongker96a57e72010-09-26 14:57:41 -07001212 boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
Doug Zongkerf2ab2902010-09-22 10:12:54 -07001213
1214 script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1215 (boot_type, boot_device,
Doug Zongker67369982010-07-07 13:53:32 -07001216 source_boot.size, source_boot.sha1,
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001217 target_boot.size, target_boot.sha1))
Doug Zongker881dd402009-09-20 14:03:55 -07001218 so_far += source_boot.size
Doug Zongker5da317e2009-06-02 13:38:17 -07001219
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001220 size = []
1221 if system_diff.patch_list: size.append(system_diff.largest_source_size)
1222 if vendor_diff:
1223 if vendor_diff.patch_list: size.append(vendor_diff.largest_source_size)
1224 if size or updating_recovery or updating_boot:
1225 script.CacheFreeSpaceCheck(max(size))
Doug Zongker5a482092010-02-17 16:09:18 -08001226
Doug Zongker05d3dea2009-06-22 11:32:31 -07001227 device_specific.IncrementalOTA_VerifyEnd()
1228
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001229 if OPTIONS.two_step:
1230 script.WriteRawImage("/boot", "recovery.img")
1231 script.AppendExtra("""
1232set_stage("%(bcb_dev)s", "2/3");
1233reboot_now("%(bcb_dev)s", "");
1234else
1235""" % bcb_dev)
1236
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001237 script.Comment("---- start making changes here ----")
Doug Zongkereef39442009-04-02 12:14:19 -07001238
Doug Zongkere5ff5902012-01-17 10:55:37 -08001239 device_specific.IncrementalOTA_InstallBegin()
1240
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001241 if OPTIONS.two_step:
1242 common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
1243 script.WriteRawImage("/boot", "boot.img")
1244 print "writing full boot image (forced by two-step mode)"
1245
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001246 script.Print("Removing unneeded files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001247 system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1248 if vendor_diff:
1249 vendor_diff.RemoveUnneededFiles(script)
Doug Zongkereef39442009-04-02 12:14:19 -07001250
Doug Zongker881dd402009-09-20 14:03:55 -07001251 script.ShowProgress(0.8, 0)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001252 total_patch_size = 1.0 + system_diff.TotalPatchSize()
1253 if vendor_diff:
1254 total_patch_size += vendor_diff.TotalPatchSize()
Doug Zongker881dd402009-09-20 14:03:55 -07001255 if updating_boot:
1256 total_patch_size += target_boot.size
Doug Zongker881dd402009-09-20 14:03:55 -07001257
1258 script.Print("Patching system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001259 so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1260 if vendor_diff:
1261 script.Print("Patching vendor files...")
1262 so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
Doug Zongker881dd402009-09-20 14:03:55 -07001263
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001264 if not OPTIONS.two_step:
1265 if updating_boot:
1266 # Produce the boot image by applying a patch to the current
1267 # contents of the boot partition, and write it back to the
1268 # partition.
1269 script.Print("Patching boot image...")
1270 script.ApplyPatch("%s:%s:%d:%s:%d:%s"
1271 % (boot_type, boot_device,
1272 source_boot.size, source_boot.sha1,
1273 target_boot.size, target_boot.sha1),
1274 "-",
1275 target_boot.size, target_boot.sha1,
1276 source_boot.sha1, "patch/boot.img.p")
1277 so_far += target_boot.size
1278 script.SetProgress(so_far / total_patch_size)
1279 print "boot image changed; including."
1280 else:
1281 print "boot image unchanged; skipping."
Doug Zongkereef39442009-04-02 12:14:19 -07001282
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001283 system_items = ItemSet("system", "META/filesystem_config.txt")
1284 if vendor_diff:
1285 vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1286
Doug Zongkereef39442009-04-02 12:14:19 -07001287 if updating_recovery:
Doug Zongkerb32161a2012-08-21 10:33:44 -07001288 # Recovery is generated as a patch using both the boot image
1289 # (which contains the same linux kernel as recovery) and the file
1290 # /system/etc/recovery-resource.dat (which contains all the images
1291 # used in the recovery UI) as sources. This lets us minimize the
1292 # size of the patch, which must be included in every OTA package.
Doug Zongker73ef8252009-07-23 15:12:53 -07001293 #
Doug Zongkerb32161a2012-08-21 10:33:44 -07001294 # For older builds where recovery-resource.dat is not present, we
1295 # use only the boot image as the source.
1296
Doug Zongkerc9253822014-02-04 12:17:58 -08001297 if not target_has_recovery_patch:
1298 def output_sink(fn, data):
1299 common.ZipWriteStr(output_zip, "recovery/" + fn, data)
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001300 system_items.Get("system/" + fn, dir=False)
Doug Zongkerc9253822014-02-04 12:17:58 -08001301
1302 common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1303 target_recovery, target_boot)
1304 script.DeleteFiles(["/system/recovery-from-boot.p",
1305 "/system/etc/install-recovery.sh"])
Doug Zongker73ef8252009-07-23 15:12:53 -07001306 print "recovery image changed; including as patch from boot."
Doug Zongkereef39442009-04-02 12:14:19 -07001307 else:
1308 print "recovery image unchanged; skipping."
1309
Doug Zongker881dd402009-09-20 14:03:55 -07001310 script.ShowProgress(0.1, 10)
Doug Zongkereef39442009-04-02 12:14:19 -07001311
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001312 target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1313 if vendor_diff:
1314 target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1315
1316 temp_script = script.MakeTemporary()
1317 system_items.GetMetadata(target_zip)
1318 system_items.Get("system").SetPermissions(temp_script)
1319 if vendor_diff:
1320 vendor_items.GetMetadata(target_zip)
1321 vendor_items.Get("vendor").SetPermissions(temp_script)
1322
1323 # Note that this call will mess up the trees of Items, so make sure
1324 # we're done with them.
1325 source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1326 if vendor_diff:
1327 source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
Doug Zongkereef39442009-04-02 12:14:19 -07001328
1329 target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
Doug Zongkereef39442009-04-02 12:14:19 -07001330 source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1331
1332 # Delete all the symlinks in source that aren't in target. This
1333 # needs to happen before verbatim files are unpacked, in case a
1334 # symlink in the source is replaced by a real file in the target.
1335 to_delete = []
1336 for dest, link in source_symlinks:
1337 if link not in target_symlinks_d:
1338 to_delete.append(link)
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001339 script.DeleteFiles(to_delete)
Doug Zongkereef39442009-04-02 12:14:19 -07001340
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001341 if system_diff.verbatim_targets:
1342 script.Print("Unpacking new system files...")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001343 script.UnpackPackageDir("system", "/system")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001344 if vendor_diff and vendor_diff.verbatim_targets:
1345 script.Print("Unpacking new vendor files...")
1346 script.UnpackPackageDir("vendor", "/vendor")
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001347
Doug Zongkerc9253822014-02-04 12:17:58 -08001348 if updating_recovery and not target_has_recovery_patch:
Doug Zongker42265392010-02-12 10:21:00 -08001349 script.Print("Unpacking new recovery...")
1350 script.UnpackPackageDir("recovery", "/system")
1351
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001352 system_diff.EmitRenames(script)
1353 if vendor_diff:
1354 vendor_diff.EmitRenames(script)
Michael Runge4038aa82013-12-13 18:06:28 -08001355
Doug Zongker05d3dea2009-06-22 11:32:31 -07001356 script.Print("Symlinks and permissions...")
Doug Zongkereef39442009-04-02 12:14:19 -07001357
1358 # Create all the symlinks that don't already exist, or point to
1359 # somewhere different than what we want. Delete each symlink before
1360 # creating it, since the 'symlink' command won't overwrite.
1361 to_create = []
1362 for dest, link in target_symlinks:
1363 if link in source_symlinks_d:
1364 if dest != source_symlinks_d[link]:
1365 to_create.append((dest, link))
1366 else:
1367 to_create.append((dest, link))
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001368 script.DeleteFiles([i[1] for i in to_create])
1369 script.MakeSymlinks(to_create)
Doug Zongkereef39442009-04-02 12:14:19 -07001370
1371 # Now that the symlinks are created, we can set all the
1372 # permissions.
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001373 script.AppendScript(temp_script)
Doug Zongkereef39442009-04-02 12:14:19 -07001374
Doug Zongker881dd402009-09-20 14:03:55 -07001375 # Do device-specific installation (eg, write radio image).
Doug Zongker05d3dea2009-06-22 11:32:31 -07001376 device_specific.IncrementalOTA_InstallEnd()
1377
Doug Zongker1c390a22009-05-14 19:06:36 -07001378 if OPTIONS.extra_script is not None:
Doug Zongker67369982010-07-07 13:53:32 -07001379 script.AppendExtra(OPTIONS.extra_script)
Doug Zongker1c390a22009-05-14 19:06:36 -07001380
Doug Zongkere92f15a2011-08-26 13:46:40 -07001381 # Patch the build.prop file last, so if something fails but the
1382 # device can still come up, it appears to be the old build and will
1383 # get set the OTA package again to retry.
1384 script.Print("Patching remaining system files...")
Doug Zongkerc8b4e842014-06-16 15:16:31 -07001385 system_diff.EmitDeferredPatches(script)
Doug Zongkere92f15a2011-08-26 13:46:40 -07001386
Doug Zongker922206e2014-03-04 13:16:24 -08001387 if OPTIONS.wipe_user_data:
1388 script.Print("Erasing user data...")
1389 script.FormatPartition("/data")
1390
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001391 if OPTIONS.two_step:
1392 script.AppendExtra("""
1393set_stage("%(bcb_dev)s", "");
1394endif;
1395endif;
1396""" % bcb_dev)
1397
Michael Runge63f01de2014-10-28 19:24:19 -07001398 if OPTIONS.verify and system_diff:
1399 script.Print("Remounting and verifying system partition files...")
1400 script.Unmount("/system")
1401 script.Mount("/system")
1402 system_diff.EmitExplicitTargetVerification(script)
1403
1404 if OPTIONS.verify and vendor_diff:
1405 script.Print("Remounting and verifying vendor partition files...")
1406 script.Unmount("/vendor")
1407 script.Mount("/vendor")
1408 vendor_diff.EmitExplicitTargetVerification(script)
Doug Zongker25568482014-03-03 10:21:27 -08001409 script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
Michael Runge63f01de2014-10-28 19:24:19 -07001410
Doug Zongker2ea21062010-04-28 16:05:21 -07001411 WriteMetadata(metadata, output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001412
1413
1414def main(argv):
1415
1416 def option_handler(o, a):
Doug Zongker25568482014-03-03 10:21:27 -08001417 if o == "--board_config":
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001418 pass # deprecated
Doug Zongkereef39442009-04-02 12:14:19 -07001419 elif o in ("-k", "--package_key"):
1420 OPTIONS.package_key = a
Doug Zongkereef39442009-04-02 12:14:19 -07001421 elif o in ("-i", "--incremental_from"):
1422 OPTIONS.incremental_source = a
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001423 elif o in ("-w", "--wipe_user_data"):
1424 OPTIONS.wipe_user_data = True
Doug Zongker962069c2009-04-23 11:41:58 -07001425 elif o in ("-n", "--no_prereq"):
1426 OPTIONS.omit_prereq = True
Michael Runge6e836112014-04-15 17:40:21 -07001427 elif o in ("-o", "--oem_settings"):
1428 OPTIONS.oem_source = a
Doug Zongker1c390a22009-05-14 19:06:36 -07001429 elif o in ("-e", "--extra_script"):
1430 OPTIONS.extra_script = a
Hristo Bojinovdafb0422010-08-26 14:35:16 -07001431 elif o in ("-a", "--aslr_mode"):
1432 if a in ("on", "On", "true", "True", "yes", "Yes"):
1433 OPTIONS.aslr_mode = True
1434 else:
1435 OPTIONS.aslr_mode = False
Martin Blumenstingl374e1142014-05-31 20:42:55 +02001436 elif o in ("-t", "--worker_threads"):
1437 if a.isdigit():
1438 OPTIONS.worker_threads = int(a)
1439 else:
1440 raise ValueError("Cannot parse value %r for option %r - only "
1441 "integers are allowed." % (a, o))
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001442 elif o in ("-2", "--two_step"):
1443 OPTIONS.two_step = True
Doug Zongker26e66192014-02-20 13:22:07 -08001444 elif o == "--no_signing":
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001445 OPTIONS.no_signing = True
Michael Runge63f01de2014-10-28 19:24:19 -07001446 elif o in ("--verify"):
1447 OPTIONS.verify = True
Doug Zongker26e66192014-02-20 13:22:07 -08001448 elif o == "--block":
1449 OPTIONS.block_based = True
Doug Zongker25568482014-03-03 10:21:27 -08001450 elif o in ("-b", "--binary"):
1451 OPTIONS.updater_binary = a
Doug Zongker62d4f182014-08-04 16:06:43 -07001452 elif o in ("--no_fallback_to_full",):
1453 OPTIONS.fallback_to_full = False
Doug Zongkereef39442009-04-02 12:14:19 -07001454 else:
1455 return False
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001456 return True
Doug Zongkereef39442009-04-02 12:14:19 -07001457
1458 args = common.ParseOptions(argv, __doc__,
Ying Wangf5770d72014-06-19 10:32:35 -07001459 extra_opts="b:k:i:d:wne:t:a:2o:",
Doug Zongkereef39442009-04-02 12:14:19 -07001460 extra_long_opts=["board_config=",
1461 "package_key=",
Doug Zongkerdbfaae52009-04-21 17:12:54 -07001462 "incremental_from=",
Doug Zongker962069c2009-04-23 11:41:58 -07001463 "wipe_user_data",
Doug Zongker1c390a22009-05-14 19:06:36 -07001464 "no_prereq",
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001465 "extra_script=",
Hristo Bojinov96be7202010-08-02 10:26:17 -07001466 "worker_threads=",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001467 "aslr_mode=",
Doug Zongker9b23f2c2013-11-25 14:44:12 -08001468 "two_step",
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001469 "no_signing",
Doug Zongker26e66192014-02-20 13:22:07 -08001470 "block",
Doug Zongker25568482014-03-03 10:21:27 -08001471 "binary=",
Michael Runge6e836112014-04-15 17:40:21 -07001472 "oem_settings=",
Michael Runge63f01de2014-10-28 19:24:19 -07001473 "verify",
Doug Zongker62d4f182014-08-04 16:06:43 -07001474 "no_fallback_to_full",
Doug Zongkerc60c1ba2010-09-03 13:22:38 -07001475 ],
Doug Zongkereef39442009-04-02 12:14:19 -07001476 extra_option_handler=option_handler)
1477
1478 if len(args) != 2:
1479 common.Usage(__doc__)
1480 sys.exit(1)
1481
Doug Zongker1c390a22009-05-14 19:06:36 -07001482 if OPTIONS.extra_script is not None:
1483 OPTIONS.extra_script = open(OPTIONS.extra_script).read()
1484
Doug Zongkereef39442009-04-02 12:14:19 -07001485 print "unzipping target target-files..."
Doug Zongker55d93282011-01-25 17:03:34 -08001486 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
Doug Zongkerfdd8e692009-08-03 17:27:48 -07001487
Doug Zongkereef39442009-04-02 12:14:19 -07001488 OPTIONS.target_tmp = OPTIONS.input_tmp
Doug Zongker37974732010-09-16 17:44:38 -07001489 OPTIONS.info_dict = common.LoadInfoDict(input_zip)
Kenny Roote2e9f612013-05-29 12:59:35 -07001490
1491 # If this image was originally labelled with SELinux contexts, make sure we
1492 # also apply the labels in our new image. During building, the "file_contexts"
1493 # is in the out/ directory tree, but for repacking from target-files.zip it's
1494 # in the root directory of the ramdisk.
1495 if "selinux_fc" in OPTIONS.info_dict:
1496 OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK",
1497 "file_contexts")
1498
Doug Zongker37974732010-09-16 17:44:38 -07001499 if OPTIONS.verbose:
1500 print "--- target info ---"
1501 common.DumpInfoDict(OPTIONS.info_dict)
1502
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001503 # If the caller explicitly specified the device-specific extensions
1504 # path via -s/--device_specific, use that. Otherwise, use
1505 # META/releasetools.py if it is present in the target target_files.
1506 # Otherwise, take the path of the file from 'tool_extensions' in the
1507 # info dict and look for that in the local filesystem, relative to
1508 # the current directory.
1509
Doug Zongker37974732010-09-16 17:44:38 -07001510 if OPTIONS.device_specific is None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001511 from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1512 if os.path.exists(from_input):
1513 print "(using device-specific extensions from target_files)"
1514 OPTIONS.device_specific = from_input
1515 else:
1516 OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1517
Doug Zongker37974732010-09-16 17:44:38 -07001518 if OPTIONS.device_specific is not None:
Doug Zongkereb0a78a2014-01-27 10:01:06 -08001519 OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
Doug Zongker37974732010-09-16 17:44:38 -07001520
Doug Zongker62d4f182014-08-04 16:06:43 -07001521 while True:
Doug Zongkereef39442009-04-02 12:14:19 -07001522
Doug Zongker62d4f182014-08-04 16:06:43 -07001523 if OPTIONS.no_signing:
1524 if os.path.exists(args[1]): os.unlink(args[1])
1525 output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
1526 else:
1527 temp_zip_file = tempfile.NamedTemporaryFile()
1528 output_zip = zipfile.ZipFile(temp_zip_file, "w",
1529 compression=zipfile.ZIP_DEFLATED)
1530
1531 if OPTIONS.incremental_source is None:
1532 WriteFullOTAPackage(input_zip, output_zip)
1533 if OPTIONS.package_key is None:
1534 OPTIONS.package_key = OPTIONS.info_dict.get(
1535 "default_system_dev_certificate",
1536 "build/target/product/security/testkey")
1537 break
1538
1539 else:
1540 print "unzipping source target-files..."
1541 OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
1542 OPTIONS.target_info_dict = OPTIONS.info_dict
1543 OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
1544 if "selinux_fc" in OPTIONS.source_info_dict:
1545 OPTIONS.source_info_dict["selinux_fc"] = os.path.join(OPTIONS.source_tmp, "BOOT", "RAMDISK",
1546 "file_contexts")
1547 if OPTIONS.package_key is None:
1548 OPTIONS.package_key = OPTIONS.source_info_dict.get(
1549 "default_system_dev_certificate",
1550 "build/target/product/security/testkey")
1551 if OPTIONS.verbose:
1552 print "--- source info ---"
1553 common.DumpInfoDict(OPTIONS.source_info_dict)
1554 try:
1555 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
1556 break
1557 except ValueError:
1558 if not OPTIONS.fallback_to_full: raise
1559 print "--- failed to build incremental; falling back to full ---"
1560 OPTIONS.incremental_source = None
1561 output_zip.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001562
1563 output_zip.close()
Doug Zongkerafb32ea2011-09-22 10:28:04 -07001564
Takeshi Kanemotoe153b342013-11-14 17:20:50 +09001565 if not OPTIONS.no_signing:
1566 SignOutput(temp_zip_file.name, args[1])
1567 temp_zip_file.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001568
Doug Zongkereef39442009-04-02 12:14:19 -07001569 print "done."
1570
1571
1572if __name__ == '__main__':
1573 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -08001574 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -07001575 main(sys.argv[1:])
1576 except common.ExternalError, e:
1577 print
1578 print " ERROR: %s" % (e,)
1579 print
1580 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -07001581 finally:
1582 common.Cleanup()