1eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker#!/usr/bin/env python
2eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker#
3eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# Copyright (C) 2008 The Android Open Source Project
4eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker#
5eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# Licensed under the Apache License, Version 2.0 (the "License");
6eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# you may not use this file except in compliance with the License.
7eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# You may obtain a copy of the License at
8eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker#
9eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker#      http://www.apache.org/licenses/LICENSE-2.0
10eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker#
11eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# Unless required by applicable law or agreed to in writing, software
12eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# distributed under the License is distributed on an "AS IS" BASIS,
13eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# See the License for the specific language governing permissions and
15eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker# limitations under the License.
16eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
17eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker"""
18eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerGiven a target-files zipfile, produces an OTA package that installs
19eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerthat build.  An incremental OTA is produced if -i is given, otherwise
20eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkera full OTA is produced.
21eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
22eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerUsage:  ota_from_target_files [flags] input_target_files output_ota_package
23eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
2425568486e5777f416d2fcb6cc7aa96caafc66880Doug Zongker  --board_config  <file>
25fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker      Deprecated.
26eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
27afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker  -k (--package_key) <key> Key to use to sign the package (default is
28afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker      the value of default_system_dev_certificate from the input
29afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker      target-files's META/misc_info.txt, or
30afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker      "build/target/product/security/testkey" if that value is not
31afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker      specified).
32afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker
33afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker      For incremental OTAs, the default value is based on the source
34afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker      target-file, not the target build.
35eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
36eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  -i  (--incremental_from)  <file>
37eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      Generate an incremental OTA using the given target-files zip as
38eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      the starting build.
39eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
40e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge  -v  (--verify)
41e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge      Remount and verify the checksums of the files written to the
42e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge      system and vendor (if used) partitions.  Incremental builds only.
43e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge
446e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  -o  (--oem_settings)  <file>
456e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge      Use the file to specify the expected OEM-specific properties
466e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge      on the OEM partition of the intended device.
476e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge
48dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker  -w  (--wipe_user_data)
49dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker      Generate an OTA package that will wipe the user data partition
50dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker      when installed.
51dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker
52962069ce59c85949d147874df2728a5ffd9193beDoug Zongker  -n  (--no_prereq)
53962069ce59c85949d147874df2728a5ffd9193beDoug Zongker      Omit the timestamp prereq check normally included at the top of
54962069ce59c85949d147874df2728a5ffd9193beDoug Zongker      the build scripts (used for developer OTA packages which
55962069ce59c85949d147874df2728a5ffd9193beDoug Zongker      legitimately need to go back and forth).
56962069ce59c85949d147874df2728a5ffd9193beDoug Zongker
571c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker  -e  (--extra_script)  <file>
581c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker      Insert the contents of file at the end of the update script.
591c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker
60dafb04275588fff8248b6a5360ca047cdffd14a5Hristo Bojinov  -a  (--aslr_mode)  <on|off>
61dafb04275588fff8248b6a5360ca047cdffd14a5Hristo Bojinov      Specify whether to turn on ASLR for the package (on by default).
6256882bf9b41dc7f8b98f1dea82633144546450b2Stephen Smalley
639b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  -2  (--two_step)
649b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker      Generate a 'two-step' OTA package, where recovery is updated
659b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker      first, so that any changes made to the system partition are done
669b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker      using the new recovery (new kernel, etc.).
679b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker
6826e6619c37e294fe2ee63aaa759e0ac861775ce8Doug Zongker  --block
6926e6619c37e294fe2ee63aaa759e0ac861775ce8Doug Zongker      Generate a block-based OTA if possible.  Will fall back to a
7026e6619c37e294fe2ee63aaa759e0ac861775ce8Doug Zongker      file-based OTA if the target_files is older and doesn't support
7126e6619c37e294fe2ee63aaa759e0ac861775ce8Doug Zongker      block-based OTAs.
7226e6619c37e294fe2ee63aaa759e0ac861775ce8Doug Zongker
7325568486e5777f416d2fcb6cc7aa96caafc66880Doug Zongker  -b  (--binary)  <file>
7425568486e5777f416d2fcb6cc7aa96caafc66880Doug Zongker      Use the given binary as the update-binary in the output package,
7525568486e5777f416d2fcb6cc7aa96caafc66880Doug Zongker      instead of the binary in the build's target_files.  Use for
7625568486e5777f416d2fcb6cc7aa96caafc66880Doug Zongker      development only.
7725568486e5777f416d2fcb6cc7aa96caafc66880Doug Zongker
78374e114d1691a47918a3972dc287615f25650725Martin Blumenstingl  -t  (--worker_threads) <int>
79374e114d1691a47918a3972dc287615f25650725Martin Blumenstingl      Specifies the number of worker-threads that will be used when
80374e114d1691a47918a3972dc287615f25650725Martin Blumenstingl      generating patches for incremental updates (defaults to 3).
81374e114d1691a47918a3972dc287615f25650725Martin Blumenstingl
82eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker"""
83eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
84eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport sys
85eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
86cf6d5a90740e50e03d9f16c6fd449d90d396f924Doug Zongkerif sys.hexversion < 0x02070000:
87cf6d5a90740e50e03d9f16c6fd449d90d396f924Doug Zongker  print >> sys.stderr, "Python 2.7 or newer is required."
88eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  sys.exit(1)
89eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
90eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport copy
91c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongkerimport errno
92fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongkerimport multiprocessing
93eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport os
94eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport re
95eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport subprocess
96eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport tempfile
97eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport time
98eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport zipfile
99eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
100fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongkerfrom hashlib import sha1 as sha1
101cad0bb9f621ff1ccfb584e18249b09768c30a0c0david
102eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport common
103c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongkerimport edify_generator
10436bd365625e6beba77698a93795a603180a5b476Geremy Condraimport build_image
105fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongkerimport blockimgdiff
106fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongkerimport sparse_img
107eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
108eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS = common.OPTIONS
109afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug ZongkerOPTIONS.package_key = None
110eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.incremental_source = None
111e8269481084df086a04c6bdcd3477d4209d4a7cbMichael RungeOPTIONS.verify = False
112eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.require_verbatim = set()
113eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.prohibit_verbatim = set(("system/build.prop",))
114eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.patch_threshold = 0.95
115dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug ZongkerOPTIONS.wipe_user_data = False
116962069ce59c85949d147874df2728a5ffd9193beDoug ZongkerOPTIONS.omit_prereq = False
1171c390a2aa97127ef8af8b0df1d4028f501fdce64Doug ZongkerOPTIONS.extra_script = None
118dafb04275588fff8248b6a5360ca047cdffd14a5Hristo BojinovOPTIONS.aslr_mode = True
119fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug ZongkerOPTIONS.worker_threads = multiprocessing.cpu_count() // 2
120fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongkerif OPTIONS.worker_threads == 0:
121fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker  OPTIONS.worker_threads = 1
1229b23f2cd786b46991b7c0198e69264b17875288dDoug ZongkerOPTIONS.two_step = False
123e153b3464374155d03bfe47092faaab555b89e81Takeshi KanemotoOPTIONS.no_signing = False
12426e6619c37e294fe2ee63aaa759e0ac861775ce8Doug ZongkerOPTIONS.block_based = False
12525568486e5777f416d2fcb6cc7aa96caafc66880Doug ZongkerOPTIONS.updater_binary = None
1266e836116f764cf5cebf1654df2f17d8222554f6eMichael RungeOPTIONS.oem_source = None
12762d4f18a30aeade677ca814cf6f2aa329cf5066dDoug ZongkerOPTIONS.fallback_to_full = True
128eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
129eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef MostPopularKey(d, default):
130eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  """Given a dict, return the key corresponding to the largest
131eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  value.  Returns 'default' if the dict is empty."""
132eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  x = [(v, k) for (k, v) in d.iteritems()]
133eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  if not x: return default
134eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  x.sort()
135eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  return x[-1][1]
136eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
137eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
138eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef IsSymlink(info):
139eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  """Return true if the zipfile.ZipInfo object passed in represents a
140eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  symlink."""
141eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  return (info.external_attr >> 16) == 0120777
142eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
14396be7205dce97977909e93b73f48779fcce3bc65Hristo Bojinovdef IsRegular(info):
14496be7205dce97977909e93b73f48779fcce3bc65Hristo Bojinov  """Return true if the zipfile.ZipInfo object passed in represents a
14596be7205dce97977909e93b73f48779fcce3bc65Hristo Bojinov  symlink."""
14696be7205dce97977909e93b73f48779fcce3bc65Hristo Bojinov  return (info.external_attr >> 28) == 010
147eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1484038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Rungedef ClosestFileMatch(src, tgtfiles, existing):
1494038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge  """Returns the closest file match between a source file and list
1504038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge     of potential matches.  The exact filename match is preferred,
1514038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge     then the sha1 is searched for, and finally a file with the same
1524038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge     basename is evaluated.  Rename support in the updater-binary is
1534038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge     required for the latter checks to be used."""
1544038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge
1554038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge  result = tgtfiles.get("path:" + src.name)
1564038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge  if result is not None:
1574038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge    return result
1584038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge
1594038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge  if not OPTIONS.target_info_dict.get("update_rename_support", False):
1604038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge    return None
1614038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge
1624038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge  if src.size < 1000:
1634038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge    return None
1644038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge
1654038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge  result = tgtfiles.get("sha1:" + src.sha1)
1664038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge  if result is not None and existing.get(result.name) is None:
1674038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge    return result
1684038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge  result = tgtfiles.get("file:" + src.name.split("/")[-1])
1694038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge  if result is not None and existing.get(result.name) is None:
1704038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge    return result
1714038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge  return None
1724038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge
173c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongkerclass ItemSet:
174c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  def __init__(self, partition, fs_config):
175c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    self.partition = partition
176c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    self.fs_config = fs_config
177c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    self.ITEMS = {}
178c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
179c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  def Get(self, name, dir=False):
180c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    if name not in self.ITEMS:
181c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      self.ITEMS[name] = Item(self, name, dir=dir)
182c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    return self.ITEMS[name]
183c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
184c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  def GetMetadata(self, input_zip):
1850eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    # The target_files contains a record of what the uid,
1860eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    # gid, and mode are supposed to be.
187c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    output = input_zip.read(self.fs_config)
188eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
189eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    for line in output.split("\n"):
190eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if not line: continue
1910eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      columns = line.split()
1920eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      name, uid, gid, mode = columns[:4]
1930eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      selabel = None
1940eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      capabilities = None
1950eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich
1960eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      # After the first 4 columns, there are a series of key=value
1970eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      # pairs. Extract out the fields we care about.
1980eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      for element in columns[4:]:
1990eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich        key, value = element.split("=")
2000eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich        if key == "selabel":
2010eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich          selabel = value
2020eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich        if key == "capabilities":
2030eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich          capabilities = value
2040eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich
205c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      i = self.ITEMS.get(name, None)
206283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker      if i is not None:
207283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker        i.uid = int(uid)
208283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker        i.gid = int(gid)
209283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker        i.mode = int(mode, 8)
2100eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich        i.selabel = selabel
2110eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich        i.capabilities = capabilities
212283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker        if i.dir:
213283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker          i.children.sort(key=lambda i: i.name)
214283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker
215283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker    # set metadata for the files generated by this script.
216c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    i = self.ITEMS.get("system/recovery-from-boot.p", None)
2170eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0644, None, None
218c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    i = self.ITEMS.get("system/etc/install-recovery.sh", None)
2190eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0544, None, None
220eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
221c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
222c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongkerclass Item:
223c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  """Items represent the metadata (user, group, mode) of files and
224c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  directories in the system image."""
225c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  def __init__(self, itemset, name, dir=False):
226c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    self.itemset = itemset
227c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    self.name = name
228c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    self.uid = None
229c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    self.gid = None
230c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    self.mode = None
231c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    self.selabel = None
232c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    self.capabilities = None
233c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    self.dir = dir
234c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
235c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    if name:
236c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      self.parent = itemset.Get(os.path.dirname(name), dir=True)
237c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      self.parent.children.append(self)
238c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    else:
239c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      self.parent = None
240c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    if dir:
241c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      self.children = []
242c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
243c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  def Dump(self, indent=0):
244c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    if self.uid is not None:
245c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      print "%s%s %d %d %o" % ("  "*indent, self.name, self.uid, self.gid, self.mode)
246c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    else:
247c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      print "%s%s %s %s %s" % ("  "*indent, self.name, self.uid, self.gid, self.mode)
248c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    if self.dir:
249c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      print "%s%s" % ("  "*indent, self.descendants)
250c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      print "%s%s" % ("  "*indent, self.best_subtree)
251c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      for i in self.children:
252c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        i.Dump(indent=indent+1)
253c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
254eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  def CountChildMetadata(self):
2550eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    """Count up the (uid, gid, mode, selabel, capabilities) tuples for
2560eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    all children and determine the best strategy for using set_perm_recursive and
257eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    set_perm to correctly chown/chmod all the files to their desired
258eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    values.  Recursively calls itself for all descendants.
259eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
2600eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count} counting up
261eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    all descendants of this node.  (dmode or fmode may be None.)  Also
262eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    sets the best_subtree of each directory Item to the (uid, gid,
2630eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    dmode, fmode, selabel, capabilities) tuple that will match the most
2640eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    descendants of that Item.
265eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    """
266eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
267eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    assert self.dir
2680eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    d = self.descendants = {(self.uid, self.gid, self.mode, None, self.selabel, self.capabilities): 1}
269eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    for i in self.children:
270eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if i.dir:
271eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        for k, v in i.CountChildMetadata().iteritems():
272eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          d[k] = d.get(k, 0) + v
273eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      else:
2740eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich        k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
275eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        d[k] = d.get(k, 0) + 1
276eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
2770eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    # Find the (uid, gid, dmode, fmode, selabel, capabilities)
2780eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    # tuple that matches the most descendants.
279eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
280eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    # First, find the (uid, gid) pair that matches the most
281eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    # descendants.
282eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    ug = {}
2830eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    for (uid, gid, _, _, _, _), count in d.iteritems():
284eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      ug[(uid, gid)] = ug.get((uid, gid), 0) + count
285eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    ug = MostPopularKey(ug, (0, 0))
286eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
2870eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    # Now find the dmode, fmode, selabel, and capabilities that match
2880eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    # the most descendants with that (uid, gid), and choose those.
289eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    best_dmode = (0, 0755)
290eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    best_fmode = (0, 0644)
2910eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    best_selabel = (0, None)
2920eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    best_capabilities = (0, None)
293eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    for k, count in d.iteritems():
294eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if k[:2] != ug: continue
295eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2])
296eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3])
2970eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      if k[4] is not None and count >= best_selabel[0]: best_selabel = (count, k[4])
2980eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      if k[5] is not None and count >= best_capabilities[0]: best_capabilities = (count, k[5])
2990eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    self.best_subtree = ug + (best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
300eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
301eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    return d
302eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
303c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def SetPermissions(self, script):
304eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    """Append set_perm/set_perm_recursive commands to 'script' to
305eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    set all permissions, users, and groups for the tree of files
306c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    rooted at 'self'."""
307eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
308eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    self.CountChildMetadata()
309eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
310eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    def recurse(item, current):
3110eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple that the current
312eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      # item (and all its children) have already been set to.  We only
313eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      # need to issue set_perm/set_perm_recursive commands if we're
314eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      # supposed to be something different.
315eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if item.dir:
316eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        if current != item.best_subtree:
317c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker          script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
318eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          current = item.best_subtree
319eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
320eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        if item.uid != current[0] or item.gid != current[1] or \
3210eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich           item.mode != current[2] or item.selabel != current[4] or \
3220eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich           item.capabilities != current[5]:
3230eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich          script.SetPermissions("/"+item.name, item.uid, item.gid,
3240eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich                                item.mode, item.selabel, item.capabilities)
325eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
326eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        for i in item.children:
327eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          recurse(i, current)
328eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      else:
329eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        if item.uid != current[0] or item.gid != current[1] or \
3300eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich               item.mode != current[3] or item.selabel != current[4] or \
3310eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich               item.capabilities != current[5]:
3320eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich          script.SetPermissions("/"+item.name, item.uid, item.gid,
3330eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich                                item.mode, item.selabel, item.capabilities)
334eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
3350eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    recurse(self, (-1, -1, -1, -1, None, None))
336eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
337eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
338c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongkerdef CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None):
339c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  """Copies files for the partition in the input zip to the output
340eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  zip.  Populates the Item class with their metadata, and returns a
3411807e700a568d57901b835370d1b1ae05c3dbb0fDoug Zongker  list of symlinks.  output_zip may be None, in which case the copy is
3421807e700a568d57901b835370d1b1ae05c3dbb0fDoug Zongker  skipped (but the other side effects still happen).  substitute is an
3431807e700a568d57901b835370d1b1ae05c3dbb0fDoug Zongker  optional dict of {output filename: contents} to be output instead of
3441807e700a568d57901b835370d1b1ae05c3dbb0fDoug Zongker  certain input files.
345eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  """
346eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
347eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  symlinks = []
348eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
349c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  partition = itemset.partition
350c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
351eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  for info in input_zip.infolist():
352c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    if info.filename.startswith(partition.upper() + "/"):
353eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      basefilename = info.filename[7:]
354eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if IsSymlink(info):
355eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        symlinks.append((input_zip.read(info.filename),
356c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker                         "/" + partition + "/" + basefilename))
357eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      else:
358eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        info2 = copy.copy(info)
359c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        fn = info2.filename = partition + "/" + basefilename
360eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        if substitute and fn in substitute and substitute[fn] is None:
361eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          continue
362eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        if output_zip is not None:
363eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          if substitute and fn in substitute:
364eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker            data = substitute[fn]
365eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          else:
366eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker            data = input_zip.read(info.filename)
367eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          output_zip.writestr(info2, data)
368eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        if fn.endswith("/"):
369c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker          itemset.Get(fn[:-1], dir=True)
370eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        else:
371c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker          itemset.Get(fn, dir=False)
372eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
373eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  symlinks.sort()
3741807e700a568d57901b835370d1b1ae05c3dbb0fDoug Zongker  return symlinks
375eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
376eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
377eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef SignOutput(temp_zip_name, output_zip_name):
378eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
379eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  pw = key_passwords[OPTIONS.package_key]
380eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
381951495fc4802a3603f654c02c7acceda4859f5e1Doug Zongker  common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
382951495fc4802a3603f654c02c7acceda4859f5e1Doug Zongker                  whole_file=True)
383eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
384eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
385c6e3afd26db72bedcb1d89a71769138a731646a5Michael Rungedef AppendAssertions(script, info_dict, oem_dict = None):
3866e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  oem_props = info_dict.get("oem_fingerprint_properties")
387560569a617c86be7985bd699e20fd19c6b2715c8Michael Runge  if oem_props is None or len(oem_props) == 0:
3886e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge    device = GetBuildProp("ro.product.device", info_dict)
3896e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge    script.AssertDevice(device)
3906e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  else:
3916e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge    if oem_dict is None:
3926e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge      raise common.ExternalError("No OEM file provided to answer expected assertions")
3936e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge    for prop in oem_props.split():
3946e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge      if oem_dict.get(prop) is None:
3956e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge        raise common.ExternalError("The OEM file is missing the property %s" % prop)
3966e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge      script.AssertOemProperty(prop, oem_dict.get(prop))
397eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
398eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
399c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongkerdef HasRecoveryPatch(target_files_zip):
400c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker  try:
401c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker    target_files_zip.getinfo("SYSTEM/recovery-from-boot.p")
402c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker    return True
403c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker  except KeyError:
404c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker    return False
40573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker
406c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongkerdef HasVendorPartition(target_files_zip):
407c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  try:
408c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    target_files_zip.getinfo("VENDOR/")
409c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    return True
410c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  except KeyError:
411c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    return False
412c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
4136e836116f764cf5cebf1654df2f17d8222554f6eMichael Rungedef GetOemProperty(name, oem_props, oem_dict, info_dict):
4146e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  if oem_props is not None and name in oem_props:
4156e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge    return oem_dict[name]
4166e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  return GetBuildProp(name, info_dict)
4176e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge
4186e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge
4196e836116f764cf5cebf1654df2f17d8222554f6eMichael Rungedef CalculateFingerprint(oem_props, oem_dict, info_dict):
4206e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  if oem_props is None:
4216e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge    return GetBuildProp("ro.build.fingerprint", info_dict)
4226e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  return "%s/%s/%s:%s" % (
4236e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge    GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict),
4246e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge    GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict),
4256e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge    GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict),
4266e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge    GetBuildProp("ro.build.thumbprint", info_dict))
42773ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker
428fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker
4293c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongkerdef GetImage(which, tmpdir, info_dict):
430fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker  # Return an image object (suitable for passing to BlockImageDiff)
431fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker  # for the 'which' partition (most be "system" or "vendor").  If a
432fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker  # prebuilt image and file map are found in tmpdir they are used,
433fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker  # otherwise they are reconstructed from the individual files.
4343c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker
4353c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker  assert which in ("system", "vendor")
4363c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker
4373c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker  path = os.path.join(tmpdir, "IMAGES", which + ".img")
438fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker  mappath = os.path.join(tmpdir, "IMAGES", which + ".map")
439fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker  if os.path.exists(path) and os.path.exists(mappath):
4403c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker    print "using %s.img from target-files" % (which,)
4413c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker    # This is a 'new' target-files, which already has the image in it.
4423c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker
4433c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker  else:
4443c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker    print "building %s.img from target-files" % (which,)
4453c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker
4463c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker    # This is an 'old' target-files, which does not contain images
4473c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker    # already built.  Build them.
4483c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker
449fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker    mappath = tempfile.mkstemp()[1]
450fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker    OPTIONS.tempfiles.append(mappath)
451fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker
4523c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker    import add_img_to_target_files
4533c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker    if which == "system":
454fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker      path = add_img_to_target_files.BuildSystem(
455fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker          tmpdir, info_dict, block_list=mappath)
4563c84f569487c4e59baa332be33b5430fdefb76b3Doug Zongker    elif which == "vendor":
457fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker      path = add_img_to_target_files.BuildVendor(
458fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker          tmpdir, info_dict, block_list=mappath)
459fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker
460fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker  return sparse_img.SparseImage(path, mappath)
461fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker
462fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker
463c77a9ad444d49e2ad777678cf5671f0a94f44ffbDoug Zongkerdef WriteFullOTAPackage(input_zip, output_zip):
4649ce2ebf5d300eba5f6086583b0941ef68a3e4b42Doug Zongker  # TODO: how to determine this?  We don't know what version it will
4659ce2ebf5d300eba5f6086583b0941ef68a3e4b42Doug Zongker  # be installed on top of.  For now, we expect the API just won't
4669ce2ebf5d300eba5f6086583b0941ef68a3e4b42Doug Zongker  # change very often.
467c77a9ad444d49e2ad777678cf5671f0a94f44ffbDoug Zongker  script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
468eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
4696e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
47065f3282099a16e266bc61e0ed3016e15f6bd8959Michael Runge  recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
4716e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  oem_dict = None
472560569a617c86be7985bd699e20fd19c6b2715c8Michael Runge  if oem_props is not None and len(oem_props) > 0:
4736e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge    if OPTIONS.oem_source is None:
4746e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge      raise common.ExternalError("OEM source required for this build")
47565f3282099a16e266bc61e0ed3016e15f6bd8959Michael Runge    script.Mount("/oem", recovery_mount_options)
4766e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge    oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
4776e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge
4786e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  metadata = {"post-build": CalculateFingerprint(
4796e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge                               oem_props, oem_dict, OPTIONS.info_dict),
4806e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge              "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
4811eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker                                         OPTIONS.info_dict),
4821eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker              "post-timestamp": GetBuildProp("ro.build.date.utc",
4831eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker                                             OPTIONS.info_dict),
4842ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker              }
4852ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker
48605d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker  device_specific = common.DeviceSpecificParams(
48705d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker      input_zip=input_zip,
48837974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker      input_version=OPTIONS.info_dict["recovery_api_version"],
48905d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker      output_zip=output_zip,
49005d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker      script=script,
4912ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker      input_tmp=OPTIONS.input_tmp,
49296a57e737707d05333dced5b657c4ef21c44088aDoug Zongker      metadata=metadata,
49396a57e737707d05333dced5b657c4ef21c44088aDoug Zongker      info_dict=OPTIONS.info_dict)
49405d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker
495c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker  has_recovery_patch = HasRecoveryPatch(input_zip)
49626e6619c37e294fe2ee63aaa759e0ac861775ce8Doug Zongker  block_based = OPTIONS.block_based and has_recovery_patch
497c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker
498962069ce59c85949d147874df2728a5ffd9193beDoug Zongker  if not OPTIONS.omit_prereq:
4991eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker    ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
5000d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker    ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
5010d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker    script.AssertOlderBuild(ts, ts_text)
502eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
5036e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  AppendAssertions(script, OPTIONS.info_dict, oem_dict)
50405d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker  device_specific.FullOTA_Assertions()
5059b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker
5069b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  # Two-step package strategy (in chronological order, which is *not*
5079b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  # the order in which the generated script has things):
5089b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #
5099b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  # if stage is not "2/3" or "3/3":
5109b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    write recovery image to boot partition
5119b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    set stage to "2/3"
5129b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    reboot to boot partition and restart recovery
5139b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  # else if stage is "2/3":
5149b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    write recovery image to recovery partition
5159b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    set stage to "3/3"
5169b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    reboot to recovery partition and restart recovery
5179b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  # else:
5189b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    (stage must be "3/3")
5199b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    set stage to ""
5209b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    do normal full package installation:
5219b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #       wipe and install system, boot image, etc.
5229b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #       set up system to update recovery partition on first boot
5239b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    complete script normally (allow recovery to mark itself finished and reboot)
5249b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker
5259b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
5269b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker                                         OPTIONS.input_tmp, "RECOVERY")
5279b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  if OPTIONS.two_step:
5289b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    if not OPTIONS.info_dict.get("multistage_support", None):
5299b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker      assert False, "two-step packages not supported by this build"
5309b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    fs = OPTIONS.info_dict["fstab"]["/misc"]
5319b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    assert fs.fs_type.upper() == "EMMC", \
5329b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker        "two-step packages only supported on devices with EMMC /misc partitions"
5339b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    bcb_dev = {"bcb_dev": fs.device}
5349b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data)
5359b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    script.AppendExtra("""
536f9d181979097af3f4a62dad9fff318a916759597Michael Rungeif get_stage("%(bcb_dev)s") == "2/3" then
5379b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker""" % bcb_dev)
5389b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    script.WriteRawImage("/recovery", "recovery.img")
5399b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    script.AppendExtra("""
5409b23f2cd786b46991b7c0198e69264b17875288dDoug Zongkerset_stage("%(bcb_dev)s", "3/3");
5419b23f2cd786b46991b7c0198e69264b17875288dDoug Zongkerreboot_now("%(bcb_dev)s", "recovery");
542f9d181979097af3f4a62dad9fff318a916759597Michael Rungeelse if get_stage("%(bcb_dev)s") == "3/3" then
5439b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker""" % bcb_dev)
5449b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker
545e5ff5907bef42fa9f3eff2e90ad941423dcc91dcDoug Zongker  device_specific.FullOTA_InstallBegin()
546171f1cde104891840b0c3c271935fae5433f1b25Doug Zongker
54701ce19c95f358ac8ef9bb939d2637ac976320401Doug Zongker  system_progress = 0.75
548eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
549dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker  if OPTIONS.wipe_user_data:
55001ce19c95f358ac8ef9bb939d2637ac976320401Doug Zongker    system_progress -= 0.1
551c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  if HasVendorPartition(input_zip):
552c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    system_progress -= 0.1
553dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker
554f32dc71e49656e16fc8e178f7436706a47e8af52Kenny Root  if "selinux_fc" in OPTIONS.info_dict:
555f32dc71e49656e16fc8e178f7436706a47e8af52Kenny Root    WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
55656882bf9b41dc7f8b98f1dea82633144546450b2Stephen Smalley
55765f3282099a16e266bc61e0ed3016e15f6bd8959Michael Runge  recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
55865f3282099a16e266bc61e0ed3016e15f6bd8959Michael Runge
559c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  system_items = ItemSet("system", "META/filesystem_config.txt")
5604b9596fe00e3012c8d4b44844ac53b10ee27b579Doug Zongker  script.ShowProgress(system_progress, 0)
56126e6619c37e294fe2ee63aaa759e0ac861775ce8Doug Zongker  if block_based:
562fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker    # Full OTA is done as an "incremental" against an empty source
563fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker    # image.  This has the effect of writing new data from the package
564fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker    # to the entire partition, but lets us reuse the updater code that
565fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker    # writes incrementals to do it.
566fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker    system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict)
567fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker    system_tgt.ResetFileMap()
568ab7ca1d2861e70d8ef8673d350b634111414039eDoug Zongker    system_diff = common.BlockDifference("system", system_tgt, src=None)
569fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker    system_diff.WriteScript(script, output_zip)
57001ce19c95f358ac8ef9bb939d2637ac976320401Doug Zongker  else:
57101ce19c95f358ac8ef9bb939d2637ac976320401Doug Zongker    script.FormatPartition("/system")
57265f3282099a16e266bc61e0ed3016e15f6bd8959Michael Runge    script.Mount("/system", recovery_mount_options)
57301ce19c95f358ac8ef9bb939d2637ac976320401Doug Zongker    if not has_recovery_patch:
57401ce19c95f358ac8ef9bb939d2637ac976320401Doug Zongker      script.UnpackPackageDir("recovery", "/system")
57526e6619c37e294fe2ee63aaa759e0ac861775ce8Doug Zongker    script.UnpackPackageDir("system", "/system")
576eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
577c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
57801ce19c95f358ac8ef9bb939d2637ac976320401Doug Zongker    script.MakeSymlinks(symlinks)
579eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
58055d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker  boot_img = common.GetBootableImage("boot.img", "boot.img",
58155d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker                                     OPTIONS.input_tmp, "BOOT")
582c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker
58391a99c28e0d15a753bc303982c970c96d6dfe0f5Doug Zongker  if not block_based:
584c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker    def output_sink(fn, data):
585c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker      common.ZipWriteStr(output_zip, "recovery/" + fn, data)
586c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      system_items.Get("system/" + fn, dir=False)
587c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker
588c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker    common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
589c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker                             recovery_img, boot_img)
59073ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker
591c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    system_items.GetMetadata(input_zip)
592c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    system_items.Get("system").SetPermissions(script)
593c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
594c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  if HasVendorPartition(input_zip):
595c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
596c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    script.ShowProgress(0.1, 0)
597c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
598c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    if block_based:
599fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker      vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict)
600fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker      vendor_tgt.ResetFileMap()
601ab7ca1d2861e70d8ef8673d350b634111414039eDoug Zongker      vendor_diff = common.BlockDifference("vendor", vendor_tgt)
602fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker      vendor_diff.WriteScript(script, output_zip)
603c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    else:
604c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      script.FormatPartition("/vendor")
60565f3282099a16e266bc61e0ed3016e15f6bd8959Michael Runge      script.Mount("/vendor", recovery_mount_options)
606c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      script.UnpackPackageDir("vendor", "/vendor")
607c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
608c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip)
609c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      script.MakeSymlinks(symlinks)
610c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
611c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      vendor_items.GetMetadata(input_zip)
612c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      vendor_items.Get("vendor").SetPermissions(script)
613eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
61437974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker  common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
61573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
616c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
61701ce19c95f358ac8ef9bb939d2637ac976320401Doug Zongker  script.ShowProgress(0.05, 5)
6189ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker  script.WriteRawImage("/boot", "boot.img")
61905d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker
62001ce19c95f358ac8ef9bb939d2637ac976320401Doug Zongker  script.ShowProgress(0.2, 10)
62105d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker  device_specific.FullOTA_InstallEnd()
622eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
6231c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker  if OPTIONS.extra_script is not None:
624c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    script.AppendExtra(OPTIONS.extra_script)
6251c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker
62614833605d26bf970cd5335c02af4354b68d93348Doug Zongker  script.UnmountAll()
6279b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker
628922206ec2aeea98491e3edfc297a28b0a39df698Doug Zongker  if OPTIONS.wipe_user_data:
629922206ec2aeea98491e3edfc297a28b0a39df698Doug Zongker    script.ShowProgress(0.1, 10)
630922206ec2aeea98491e3edfc297a28b0a39df698Doug Zongker    script.FormatPartition("/data")
631c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
6329b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  if OPTIONS.two_step:
6339b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    script.AppendExtra("""
6349b23f2cd786b46991b7c0198e69264b17875288dDoug Zongkerset_stage("%(bcb_dev)s", "");
6359b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker""" % bcb_dev)
6369b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    script.AppendExtra("else\n")
6379b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    script.WriteRawImage("/boot", "recovery.img")
6389b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    script.AppendExtra("""
6399b23f2cd786b46991b7c0198e69264b17875288dDoug Zongkerset_stage("%(bcb_dev)s", "2/3");
6409b23f2cd786b46991b7c0198e69264b17875288dDoug Zongkerreboot_now("%(bcb_dev)s", "");
6419b23f2cd786b46991b7c0198e69264b17875288dDoug Zongkerendif;
6429b23f2cd786b46991b7c0198e69264b17875288dDoug Zongkerendif;
6439b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker""" % bcb_dev)
64425568486e5777f416d2fcb6cc7aa96caafc66880Doug Zongker  script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary)
6452ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker  WriteMetadata(metadata, output_zip)
6462ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker
647fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker
64856882bf9b41dc7f8b98f1dea82633144546450b2Stephen Smalleydef WritePolicyConfig(file_context, output_zip):
64956882bf9b41dc7f8b98f1dea82633144546450b2Stephen Smalley  f = open(file_context, 'r');
65056882bf9b41dc7f8b98f1dea82633144546450b2Stephen Smalley  basename = os.path.basename(file_context)
65156882bf9b41dc7f8b98f1dea82633144546450b2Stephen Smalley  common.ZipWriteStr(output_zip, basename, f.read())
65256882bf9b41dc7f8b98f1dea82633144546450b2Stephen Smalley
6532ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker
6542ea21065b66da9819df92b37a79f0f87552ee331Doug Zongkerdef WriteMetadata(metadata, output_zip):
6552ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker  common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
6562ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker                     "".join(["%s=%s\n" % kv
6572ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker                              for kv in sorted(metadata.iteritems())]))
658eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
659fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker
660c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongkerdef LoadPartitionFiles(z, partition):
661c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  """Load all the files from the given partition in a given target-files
662eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  ZipFile, and return a dict of {filename: File object}."""
663eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  out = {}
664c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  prefix = partition.upper() + "/"
665eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  for info in z.infolist():
666c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    if info.filename.startswith(prefix) and not IsSymlink(info):
66796be7205dce97977909e93b73f48779fcce3bc65Hristo Bojinov      basefilename = info.filename[7:]
668c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      fn = partition + "/" + basefilename
669eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      data = z.read(info.filename)
670ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker      out[fn] = common.File(fn, data)
6711807e700a568d57901b835370d1b1ae05c3dbb0fDoug Zongker  return out
672eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
673eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
6741eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongkerdef GetBuildProp(prop, info_dict):
6751eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker  """Return the fingerprint of the build of a given target-files info_dict."""
6761eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker  try:
6771eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker    return info_dict.get("build.prop", {})[prop]
6781eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker  except KeyError:
679c73e461537678af2c29fcc38857e26fa57103710Ying Wang    raise common.ExternalError("couldn't find %s in build.prop" % (prop,))
680eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
681fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker
6824038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Rungedef AddToKnownPaths(filename, known_paths):
6834038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge  if filename[-1] == "/":
6844038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge    return
6854038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge  dirs = filename.split("/")[:-1]
6864038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge  while len(dirs) > 0:
6874038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge    path = "/".join(dirs)
6884038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge    if path in known_paths:
6894038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge      break;
6904038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge    known_paths.add(path)
6914038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge    dirs.pop()
692eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
693c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
69436bd365625e6beba77698a93795a603180a5b476Geremy Condradef WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
69536bd365625e6beba77698a93795a603180a5b476Geremy Condra  source_version = OPTIONS.source_info_dict["recovery_api_version"]
69636bd365625e6beba77698a93795a603180a5b476Geremy Condra  target_version = OPTIONS.target_info_dict["recovery_api_version"]
69736bd365625e6beba77698a93795a603180a5b476Geremy Condra
69836bd365625e6beba77698a93795a603180a5b476Geremy Condra  if source_version == 0:
69936bd365625e6beba77698a93795a603180a5b476Geremy Condra    print ("WARNING: generating edify script for a source that "
70036bd365625e6beba77698a93795a603180a5b476Geremy Condra           "can't install it.")
70136bd365625e6beba77698a93795a603180a5b476Geremy Condra  script = edify_generator.EdifyGenerator(source_version,
70236bd365625e6beba77698a93795a603180a5b476Geremy Condra                                          OPTIONS.target_info_dict)
70336bd365625e6beba77698a93795a603180a5b476Geremy Condra
70436bd365625e6beba77698a93795a603180a5b476Geremy Condra  metadata = {"pre-device": GetBuildProp("ro.product.device",
70536bd365625e6beba77698a93795a603180a5b476Geremy Condra                                         OPTIONS.source_info_dict),
70636bd365625e6beba77698a93795a603180a5b476Geremy Condra              "post-timestamp": GetBuildProp("ro.build.date.utc",
70736bd365625e6beba77698a93795a603180a5b476Geremy Condra                                             OPTIONS.target_info_dict),
70836bd365625e6beba77698a93795a603180a5b476Geremy Condra              }
70936bd365625e6beba77698a93795a603180a5b476Geremy Condra
71036bd365625e6beba77698a93795a603180a5b476Geremy Condra  device_specific = common.DeviceSpecificParams(
71136bd365625e6beba77698a93795a603180a5b476Geremy Condra      source_zip=source_zip,
71236bd365625e6beba77698a93795a603180a5b476Geremy Condra      source_version=source_version,
71336bd365625e6beba77698a93795a603180a5b476Geremy Condra      target_zip=target_zip,
71436bd365625e6beba77698a93795a603180a5b476Geremy Condra      target_version=target_version,
71536bd365625e6beba77698a93795a603180a5b476Geremy Condra      output_zip=output_zip,
71636bd365625e6beba77698a93795a603180a5b476Geremy Condra      script=script,
71736bd365625e6beba77698a93795a603180a5b476Geremy Condra      metadata=metadata,
71836bd365625e6beba77698a93795a603180a5b476Geremy Condra      info_dict=OPTIONS.info_dict)
71936bd365625e6beba77698a93795a603180a5b476Geremy Condra
72036bd365625e6beba77698a93795a603180a5b476Geremy Condra  source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
72136bd365625e6beba77698a93795a603180a5b476Geremy Condra  target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
72236bd365625e6beba77698a93795a603180a5b476Geremy Condra  metadata["pre-build"] = source_fp
72336bd365625e6beba77698a93795a603180a5b476Geremy Condra  metadata["post-build"] = target_fp
72436bd365625e6beba77698a93795a603180a5b476Geremy Condra
72536bd365625e6beba77698a93795a603180a5b476Geremy Condra  source_boot = common.GetBootableImage(
72636bd365625e6beba77698a93795a603180a5b476Geremy Condra      "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
72736bd365625e6beba77698a93795a603180a5b476Geremy Condra      OPTIONS.source_info_dict)
72836bd365625e6beba77698a93795a603180a5b476Geremy Condra  target_boot = common.GetBootableImage(
72936bd365625e6beba77698a93795a603180a5b476Geremy Condra      "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
73036bd365625e6beba77698a93795a603180a5b476Geremy Condra  updating_boot = (not OPTIONS.two_step and
73136bd365625e6beba77698a93795a603180a5b476Geremy Condra                   (source_boot.data != target_boot.data))
73236bd365625e6beba77698a93795a603180a5b476Geremy Condra
73336bd365625e6beba77698a93795a603180a5b476Geremy Condra  source_recovery = common.GetBootableImage(
73436bd365625e6beba77698a93795a603180a5b476Geremy Condra      "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
73536bd365625e6beba77698a93795a603180a5b476Geremy Condra      OPTIONS.source_info_dict)
73636bd365625e6beba77698a93795a603180a5b476Geremy Condra  target_recovery = common.GetBootableImage(
73736bd365625e6beba77698a93795a603180a5b476Geremy Condra      "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
73836bd365625e6beba77698a93795a603180a5b476Geremy Condra  updating_recovery = (source_recovery.data != target_recovery.data)
73936bd365625e6beba77698a93795a603180a5b476Geremy Condra
740fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker  system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict)
741fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker  system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict)
742b34fcce08cc9ab358481e672d83ff16513c4ac37Doug Zongker  system_diff = common.BlockDifference("system", system_tgt, system_src,
743b34fcce08cc9ab358481e672d83ff16513c4ac37Doug Zongker                                       check_first_block=True)
744fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker
745c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  if HasVendorPartition(target_zip):
746c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    if not HasVendorPartition(source_zip):
747c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      raise RuntimeError("can't generate incremental that adds /vendor")
748fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker    vendor_src = GetImage("vendor", OPTIONS.source_tmp, OPTIONS.source_info_dict)
749fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker    vendor_tgt = GetImage("vendor", OPTIONS.target_tmp, OPTIONS.target_info_dict)
750b34fcce08cc9ab358481e672d83ff16513c4ac37Doug Zongker    vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src,
751b34fcce08cc9ab358481e672d83ff16513c4ac37Doug Zongker                                         check_first_block=True)
752fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker  else:
753fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker    vendor_diff = None
75436bd365625e6beba77698a93795a603180a5b476Geremy Condra
755c6e3afd26db72bedcb1d89a71769138a731646a5Michael Runge  oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties")
75665f3282099a16e266bc61e0ed3016e15f6bd8959Michael Runge  recovery_mount_options = OPTIONS.target_info_dict.get("recovery_mount_options")
757c6e3afd26db72bedcb1d89a71769138a731646a5Michael Runge  oem_dict = None
758560569a617c86be7985bd699e20fd19c6b2715c8Michael Runge  if oem_props is not None and len(oem_props) > 0:
759c6e3afd26db72bedcb1d89a71769138a731646a5Michael Runge    if OPTIONS.oem_source is None:
760c6e3afd26db72bedcb1d89a71769138a731646a5Michael Runge      raise common.ExternalError("OEM source required for this build")
76165f3282099a16e266bc61e0ed3016e15f6bd8959Michael Runge    script.Mount("/oem", recovery_mount_options)
762c6e3afd26db72bedcb1d89a71769138a731646a5Michael Runge    oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
763c6e3afd26db72bedcb1d89a71769138a731646a5Michael Runge
764c6e3afd26db72bedcb1d89a71769138a731646a5Michael Runge  AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
76536bd365625e6beba77698a93795a603180a5b476Geremy Condra  device_specific.IncrementalOTA_Assertions()
76636bd365625e6beba77698a93795a603180a5b476Geremy Condra
76736bd365625e6beba77698a93795a603180a5b476Geremy Condra  # Two-step incremental package strategy (in chronological order,
76836bd365625e6beba77698a93795a603180a5b476Geremy Condra  # which is *not* the order in which the generated script has
76936bd365625e6beba77698a93795a603180a5b476Geremy Condra  # things):
77036bd365625e6beba77698a93795a603180a5b476Geremy Condra  #
77136bd365625e6beba77698a93795a603180a5b476Geremy Condra  # if stage is not "2/3" or "3/3":
77236bd365625e6beba77698a93795a603180a5b476Geremy Condra  #    do verification on current system
77336bd365625e6beba77698a93795a603180a5b476Geremy Condra  #    write recovery image to boot partition
77436bd365625e6beba77698a93795a603180a5b476Geremy Condra  #    set stage to "2/3"
77536bd365625e6beba77698a93795a603180a5b476Geremy Condra  #    reboot to boot partition and restart recovery
77636bd365625e6beba77698a93795a603180a5b476Geremy Condra  # else if stage is "2/3":
77736bd365625e6beba77698a93795a603180a5b476Geremy Condra  #    write recovery image to recovery partition
77836bd365625e6beba77698a93795a603180a5b476Geremy Condra  #    set stage to "3/3"
77936bd365625e6beba77698a93795a603180a5b476Geremy Condra  #    reboot to recovery partition and restart recovery
78036bd365625e6beba77698a93795a603180a5b476Geremy Condra  # else:
78136bd365625e6beba77698a93795a603180a5b476Geremy Condra  #    (stage must be "3/3")
78236bd365625e6beba77698a93795a603180a5b476Geremy Condra  #    perform update:
78336bd365625e6beba77698a93795a603180a5b476Geremy Condra  #       patch system files, etc.
78436bd365625e6beba77698a93795a603180a5b476Geremy Condra  #       force full install of new boot image
78536bd365625e6beba77698a93795a603180a5b476Geremy Condra  #       set up system to update recovery partition on first boot
78636bd365625e6beba77698a93795a603180a5b476Geremy Condra  #    complete script normally (allow recovery to mark itself finished and reboot)
78736bd365625e6beba77698a93795a603180a5b476Geremy Condra
78836bd365625e6beba77698a93795a603180a5b476Geremy Condra  if OPTIONS.two_step:
78936bd365625e6beba77698a93795a603180a5b476Geremy Condra    if not OPTIONS.info_dict.get("multistage_support", None):
79036bd365625e6beba77698a93795a603180a5b476Geremy Condra      assert False, "two-step packages not supported by this build"
79136bd365625e6beba77698a93795a603180a5b476Geremy Condra    fs = OPTIONS.info_dict["fstab"]["/misc"]
79236bd365625e6beba77698a93795a603180a5b476Geremy Condra    assert fs.fs_type.upper() == "EMMC", \
79336bd365625e6beba77698a93795a603180a5b476Geremy Condra        "two-step packages only supported on devices with EMMC /misc partitions"
79436bd365625e6beba77698a93795a603180a5b476Geremy Condra    bcb_dev = {"bcb_dev": fs.device}
79536bd365625e6beba77698a93795a603180a5b476Geremy Condra    common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
79636bd365625e6beba77698a93795a603180a5b476Geremy Condra    script.AppendExtra("""
797f9d181979097af3f4a62dad9fff318a916759597Michael Rungeif get_stage("%(bcb_dev)s") == "2/3" then
79836bd365625e6beba77698a93795a603180a5b476Geremy Condra""" % bcb_dev)
79936bd365625e6beba77698a93795a603180a5b476Geremy Condra    script.AppendExtra("sleep(20);\n");
80036bd365625e6beba77698a93795a603180a5b476Geremy Condra    script.WriteRawImage("/recovery", "recovery.img")
80136bd365625e6beba77698a93795a603180a5b476Geremy Condra    script.AppendExtra("""
80236bd365625e6beba77698a93795a603180a5b476Geremy Condraset_stage("%(bcb_dev)s", "3/3");
80336bd365625e6beba77698a93795a603180a5b476Geremy Condrareboot_now("%(bcb_dev)s", "recovery");
804f9d181979097af3f4a62dad9fff318a916759597Michael Rungeelse if get_stage("%(bcb_dev)s") != "3/3" then
80536bd365625e6beba77698a93795a603180a5b476Geremy Condra""" % bcb_dev)
80636bd365625e6beba77698a93795a603180a5b476Geremy Condra
80736bd365625e6beba77698a93795a603180a5b476Geremy Condra  script.Print("Verifying current system...")
80836bd365625e6beba77698a93795a603180a5b476Geremy Condra
80936bd365625e6beba77698a93795a603180a5b476Geremy Condra  device_specific.IncrementalOTA_VerifyBegin()
81036bd365625e6beba77698a93795a603180a5b476Geremy Condra
811c6e3afd26db72bedcb1d89a71769138a731646a5Michael Runge  if oem_props is None:
812c6e3afd26db72bedcb1d89a71769138a731646a5Michael Runge    script.AssertSomeFingerprint(source_fp, target_fp)
813c6e3afd26db72bedcb1d89a71769138a731646a5Michael Runge  else:
814c6e3afd26db72bedcb1d89a71769138a731646a5Michael Runge    script.AssertSomeThumbprint(
815c6e3afd26db72bedcb1d89a71769138a731646a5Michael Runge        GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
816c6e3afd26db72bedcb1d89a71769138a731646a5Michael Runge        GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
81736bd365625e6beba77698a93795a603180a5b476Geremy Condra
81836bd365625e6beba77698a93795a603180a5b476Geremy Condra  if updating_boot:
819f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker    boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
82036bd365625e6beba77698a93795a603180a5b476Geremy Condra    d = common.Difference(target_boot, source_boot)
82136bd365625e6beba77698a93795a603180a5b476Geremy Condra    _, _, d = d.ComputePatch()
822f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker    if d is None:
823f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker      include_full_boot = True
824f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker      common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
825f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker    else:
826f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker      include_full_boot = False
82736bd365625e6beba77698a93795a603180a5b476Geremy Condra
828f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker      print "boot      target: %d  source: %d  diff: %d" % (
829f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker          target_boot.size, source_boot.size, len(d))
83036bd365625e6beba77698a93795a603180a5b476Geremy Condra
831f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker      common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
83236bd365625e6beba77698a93795a603180a5b476Geremy Condra
833f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker      script.PatchCheck("%s:%s:%d:%s:%d:%s" %
834f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker                        (boot_type, boot_device,
835f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker                         source_boot.size, source_boot.sha1,
836f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker                         target_boot.size, target_boot.sha1))
83736bd365625e6beba77698a93795a603180a5b476Geremy Condra
83836bd365625e6beba77698a93795a603180a5b476Geremy Condra  device_specific.IncrementalOTA_VerifyEnd()
83936bd365625e6beba77698a93795a603180a5b476Geremy Condra
84036bd365625e6beba77698a93795a603180a5b476Geremy Condra  if OPTIONS.two_step:
84136bd365625e6beba77698a93795a603180a5b476Geremy Condra    script.WriteRawImage("/boot", "recovery.img")
84236bd365625e6beba77698a93795a603180a5b476Geremy Condra    script.AppendExtra("""
84336bd365625e6beba77698a93795a603180a5b476Geremy Condraset_stage("%(bcb_dev)s", "2/3");
84436bd365625e6beba77698a93795a603180a5b476Geremy Condrareboot_now("%(bcb_dev)s", "");
84536bd365625e6beba77698a93795a603180a5b476Geremy Condraelse
84636bd365625e6beba77698a93795a603180a5b476Geremy Condra""" % bcb_dev)
84736bd365625e6beba77698a93795a603180a5b476Geremy Condra
84836bd365625e6beba77698a93795a603180a5b476Geremy Condra  script.Comment("---- start making changes here ----")
84936bd365625e6beba77698a93795a603180a5b476Geremy Condra
85036bd365625e6beba77698a93795a603180a5b476Geremy Condra  device_specific.IncrementalOTA_InstallBegin()
85136bd365625e6beba77698a93795a603180a5b476Geremy Condra
852ab7ca1d2861e70d8ef8673d350b634111414039eDoug Zongker  system_diff.WriteScript(script, output_zip,
853ab7ca1d2861e70d8ef8673d350b634111414039eDoug Zongker                          progress=0.8 if vendor_diff else 0.9)
854fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker  if vendor_diff:
855ab7ca1d2861e70d8ef8673d350b634111414039eDoug Zongker    vendor_diff.WriteScript(script, output_zip, progress=0.1)
85636bd365625e6beba77698a93795a603180a5b476Geremy Condra
85736bd365625e6beba77698a93795a603180a5b476Geremy Condra  if OPTIONS.two_step:
85836bd365625e6beba77698a93795a603180a5b476Geremy Condra    common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
85936bd365625e6beba77698a93795a603180a5b476Geremy Condra    script.WriteRawImage("/boot", "boot.img")
86036bd365625e6beba77698a93795a603180a5b476Geremy Condra    print "writing full boot image (forced by two-step mode)"
86136bd365625e6beba77698a93795a603180a5b476Geremy Condra
86236bd365625e6beba77698a93795a603180a5b476Geremy Condra  if not OPTIONS.two_step:
86336bd365625e6beba77698a93795a603180a5b476Geremy Condra    if updating_boot:
864f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker      if include_full_boot:
865f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker        print "boot image changed; including full."
866f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker        script.Print("Installing boot image...")
867f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker        script.WriteRawImage("/boot", "boot.img")
868f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker      else:
869f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker        # Produce the boot image by applying a patch to the current
870f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker        # contents of the boot partition, and write it back to the
871f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker        # partition.
872f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker        print "boot image changed; including patch."
873f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker        script.Print("Patching boot image...")
874f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker        script.ShowProgress(0.1, 10)
875f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker        script.ApplyPatch("%s:%s:%d:%s:%d:%s"
876f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker                          % (boot_type, boot_device,
877f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker                             source_boot.size, source_boot.sha1,
878f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker                             target_boot.size, target_boot.sha1),
879f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker                          "-",
880f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker                          target_boot.size, target_boot.sha1,
881f83400896de5e8bc2b21a0dce98382d9ed0ab537Doug Zongker                          source_boot.sha1, "patch/boot.img.p")
88236bd365625e6beba77698a93795a603180a5b476Geremy Condra    else:
88336bd365625e6beba77698a93795a603180a5b476Geremy Condra      print "boot image unchanged; skipping."
88436bd365625e6beba77698a93795a603180a5b476Geremy Condra
88536bd365625e6beba77698a93795a603180a5b476Geremy Condra  # Do device-specific installation (eg, write radio image).
88636bd365625e6beba77698a93795a603180a5b476Geremy Condra  device_specific.IncrementalOTA_InstallEnd()
88736bd365625e6beba77698a93795a603180a5b476Geremy Condra
88836bd365625e6beba77698a93795a603180a5b476Geremy Condra  if OPTIONS.extra_script is not None:
88936bd365625e6beba77698a93795a603180a5b476Geremy Condra    script.AppendExtra(OPTIONS.extra_script)
89036bd365625e6beba77698a93795a603180a5b476Geremy Condra
891922206ec2aeea98491e3edfc297a28b0a39df698Doug Zongker  if OPTIONS.wipe_user_data:
892922206ec2aeea98491e3edfc297a28b0a39df698Doug Zongker    script.Print("Erasing user data...")
893922206ec2aeea98491e3edfc297a28b0a39df698Doug Zongker    script.FormatPartition("/data")
894922206ec2aeea98491e3edfc297a28b0a39df698Doug Zongker
89536bd365625e6beba77698a93795a603180a5b476Geremy Condra  if OPTIONS.two_step:
89636bd365625e6beba77698a93795a603180a5b476Geremy Condra    script.AppendExtra("""
89736bd365625e6beba77698a93795a603180a5b476Geremy Condraset_stage("%(bcb_dev)s", "");
89836bd365625e6beba77698a93795a603180a5b476Geremy Condraendif;
89936bd365625e6beba77698a93795a603180a5b476Geremy Condraendif;
90036bd365625e6beba77698a93795a603180a5b476Geremy Condra""" % bcb_dev)
90136bd365625e6beba77698a93795a603180a5b476Geremy Condra
90236bd365625e6beba77698a93795a603180a5b476Geremy Condra  script.SetProgress(1)
90325568486e5777f416d2fcb6cc7aa96caafc66880Doug Zongker  script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
90436bd365625e6beba77698a93795a603180a5b476Geremy Condra  WriteMetadata(metadata, output_zip)
90536bd365625e6beba77698a93795a603180a5b476Geremy Condra
90632b527d6cb951335f06c37c4d9a7a8216974a86aDoug Zongker
907c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongkerclass FileDifference:
908c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  def __init__(self, partition, source_zip, target_zip, output_zip):
909c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    print "Loading target..."
910c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    self.target_data = target_data = LoadPartitionFiles(target_zip, partition)
911c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    print "Loading source..."
912c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    self.source_data = source_data = LoadPartitionFiles(source_zip, partition)
913c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
914c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    self.verbatim_targets = verbatim_targets = []
915c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    self.patch_list = patch_list = []
916c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    diffs = []
917c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    self.renames = renames = {}
918c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    known_paths = set()
919c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    largest_source_size = 0
920c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
921c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    matching_file_cache = {}
922c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    for fn, sf in source_data.items():
923c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      assert fn == sf.name
924c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      matching_file_cache["path:" + fn] = sf
925c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      if fn in target_data.keys():
926c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        AddToKnownPaths(fn, known_paths)
927c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      # Only allow eligibility for filename/sha matching
928c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      # if there isn't a perfect path match.
929c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      if target_data.get(sf.name) is None:
930c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        matching_file_cache["file:" + fn.split("/")[-1]] = sf
931c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        matching_file_cache["sha:" + sf.sha1] = sf
932c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
933c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    for fn in sorted(target_data.keys()):
934c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      tf = target_data[fn]
935c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      assert fn == tf.name
936c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      sf = ClosestFileMatch(tf, matching_file_cache, renames)
937c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      if sf is not None and sf.name != tf.name:
938c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        print "File has moved from " + sf.name + " to " + tf.name
939c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        renames[sf.name] = tf
940c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
941c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      if sf is None or fn in OPTIONS.require_verbatim:
942c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        # This file should be included verbatim
943c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        if fn in OPTIONS.prohibit_verbatim:
944c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker          raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
945c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        print "send", fn, "verbatim"
946c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        tf.AddToZip(output_zip)
947e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge        verbatim_targets.append((fn, tf.size, tf.sha1))
948c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        if fn in target_data.keys():
949c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker          AddToKnownPaths(fn, known_paths)
950c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      elif tf.sha1 != sf.sha1:
951c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        # File is different; consider sending as a patch
952c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        diffs.append(common.Difference(tf, sf))
953c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      else:
954c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        # Target file data identical to source (may still be renamed)
955c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        pass
956c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
957c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    common.ComputeDifferences(diffs)
958c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
959c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    for diff in diffs:
960c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      tf, sf, d = diff.GetPatch()
961c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      path = "/".join(tf.name.split("/")[:-1])
962c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \
963c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker          path not in known_paths:
964c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        # patch is almost as big as the file; don't bother patching
965c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        # or a patch + rename cannot take place due to the target
966c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        # directory not existing
967c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        tf.AddToZip(output_zip)
968e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge        verbatim_targets.append((tf.name, tf.size, tf.sha1))
969c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        if sf.name in renames:
970c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker          del renames[sf.name]
971c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        AddToKnownPaths(tf.name, known_paths)
972c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      else:
973c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d)
974c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest()))
975c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        largest_source_size = max(largest_source_size, sf.size)
976c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
977c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    self.largest_source_size = largest_source_size
978c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
979c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  def EmitVerification(self, script):
980c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    so_far = 0
981c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    for tf, sf, size, patch_sha in self.patch_list:
982c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      if tf.name != sf.name:
983c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
984c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1)
985c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      so_far += sf.size
986c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    return so_far
987c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
988e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge  def EmitExplicitTargetVerification(self, script):
989e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge    for fn, size, sha1 in self.verbatim_targets:
990e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge      if (fn[-1] != "/"):
991e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge        script.FileCheck("/"+fn, sha1)
992e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge    for tf, _, _, _ in self.patch_list:
993e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge      script.FileCheck(tf.name, tf.sha1)
994e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge
995c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  def RemoveUnneededFiles(self, script, extras=()):
996c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    script.DeleteFiles(["/"+i[0] for i in self.verbatim_targets] +
997c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker                       ["/"+i for i in sorted(self.source_data)
998c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker                              if i not in self.target_data and
999c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker                              i not in self.renames] +
1000c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker                       list(extras))
1001c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
1002c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  def TotalPatchSize(self):
1003c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    return sum(i[1].size for i in self.patch_list)
1004c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
1005c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  def EmitPatches(self, script, total_patch_size, so_far):
1006c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    self.deferred_patch_list = deferred_patch_list = []
1007c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    for item in self.patch_list:
1008c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      tf, sf, size, _ = item
1009c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      if tf.name == "system/build.prop":
1010c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        deferred_patch_list.append(item)
1011c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        continue
1012c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      if (sf.name != tf.name):
1013c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        script.SkipNextActionIfTargetExists(tf.name, tf.sha1)
1014c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
1015c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      so_far += tf.size
1016c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      script.SetProgress(so_far / total_patch_size)
1017c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    return so_far
1018c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
1019c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  def EmitDeferredPatches(self, script):
1020c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    for item in self.deferred_patch_list:
1021c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      tf, sf, size, _ = item
1022c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p")
1023c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None)
1024c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
1025c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  def EmitRenames(self, script):
1026c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    if len(self.renames) > 0:
1027c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      script.Print("Renaming files...")
1028c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker      for src, tgt in self.renames.iteritems():
1029c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        print "Renaming " + src + " to " + tgt.name
1030c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        script.RenameFile(src, tgt.name)
1031c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
1032c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
1033c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
1034c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
1035c77a9ad444d49e2ad777678cf5671f0a94f44ffbDoug Zongkerdef WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
103636bd365625e6beba77698a93795a603180a5b476Geremy Condra  target_has_recovery_patch = HasRecoveryPatch(target_zip)
103736bd365625e6beba77698a93795a603180a5b476Geremy Condra  source_has_recovery_patch = HasRecoveryPatch(source_zip)
103836bd365625e6beba77698a93795a603180a5b476Geremy Condra
103926e6619c37e294fe2ee63aaa759e0ac861775ce8Doug Zongker  if (OPTIONS.block_based and
104026e6619c37e294fe2ee63aaa759e0ac861775ce8Doug Zongker      target_has_recovery_patch and
104126e6619c37e294fe2ee63aaa759e0ac861775ce8Doug Zongker      source_has_recovery_patch):
104236bd365625e6beba77698a93795a603180a5b476Geremy Condra    return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
104336bd365625e6beba77698a93795a603180a5b476Geremy Condra
104437974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker  source_version = OPTIONS.source_info_dict["recovery_api_version"]
104537974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker  target_version = OPTIONS.target_info_dict["recovery_api_version"]
1046c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
10479ce2ebf5d300eba5f6086583b0941ef68a3e4b42Doug Zongker  if source_version == 0:
10489ce2ebf5d300eba5f6086583b0941ef68a3e4b42Doug Zongker    print ("WARNING: generating edify script for a source that "
10499ce2ebf5d300eba5f6086583b0941ef68a3e4b42Doug Zongker           "can't install it.")
10501eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker  script = edify_generator.EdifyGenerator(source_version,
10511eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker                                          OPTIONS.target_info_dict)
1052eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
10536e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties")
105465f3282099a16e266bc61e0ed3016e15f6bd8959Michael Runge  recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options")
10556e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  oem_dict = None
1056560569a617c86be7985bd699e20fd19c6b2715c8Michael Runge  if oem_props is not None and len(oem_props) > 0:
10576e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge    if OPTIONS.oem_source is None:
10586e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge      raise common.ExternalError("OEM source required for this build")
105965f3282099a16e266bc61e0ed3016e15f6bd8959Michael Runge    script.Mount("/oem", recovery_mount_options)
10606e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge    oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines())
10616e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge
10626e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  metadata = {"pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict,
10631eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker                                         OPTIONS.source_info_dict),
10641eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker              "post-timestamp": GetBuildProp("ro.build.date.utc",
10651eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker                                             OPTIONS.target_info_dict),
10662ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker              }
10672ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker
106805d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker  device_specific = common.DeviceSpecificParams(
106905d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker      source_zip=source_zip,
107014833605d26bf970cd5335c02af4354b68d93348Doug Zongker      source_version=source_version,
107105d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker      target_zip=target_zip,
107214833605d26bf970cd5335c02af4354b68d93348Doug Zongker      target_version=target_version,
107305d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker      output_zip=output_zip,
10742ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker      script=script,
107596a57e737707d05333dced5b657c4ef21c44088aDoug Zongker      metadata=metadata,
107696a57e737707d05333dced5b657c4ef21c44088aDoug Zongker      info_dict=OPTIONS.info_dict)
107705d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker
1078c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  system_diff = FileDifference("system", source_zip, target_zip, output_zip)
107965f3282099a16e266bc61e0ed3016e15f6bd8959Michael Runge  script.Mount("/system", recovery_mount_options)
1080c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  if HasVendorPartition(target_zip):
1081c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip)
108265f3282099a16e266bc61e0ed3016e15f6bd8959Michael Runge    script.Mount("/vendor", recovery_mount_options)
1083c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  else:
1084c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    vendor_diff = None
10856e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge
10866e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  target_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.target_info_dict)
10876e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  source_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.source_info_dict)
10886e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge
10896e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  if oem_props is None:
10906e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge    script.AssertSomeFingerprint(source_fp, target_fp)
10916e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  else:
10926e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge    script.AssertSomeThumbprint(
10936e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge        GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict),
10946e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge        GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict))
10956e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge
10962ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker  metadata["pre-build"] = source_fp
10972ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker  metadata["post-build"] = target_fp
1098eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
109955d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker  source_boot = common.GetBootableImage(
1100d513160b76a189899ba01f87a3987b4c6f428caeDoug Zongker      "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
1101d513160b76a189899ba01f87a3987b4c6f428caeDoug Zongker      OPTIONS.source_info_dict)
110255d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker  target_boot = common.GetBootableImage(
110355d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker      "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
11049b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  updating_boot = (not OPTIONS.two_step and
11059b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker                   (source_boot.data != target_boot.data))
1106eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
110755d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker  source_recovery = common.GetBootableImage(
1108d513160b76a189899ba01f87a3987b4c6f428caeDoug Zongker      "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
1109d513160b76a189899ba01f87a3987b4c6f428caeDoug Zongker      OPTIONS.source_info_dict)
111055d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker  target_recovery = common.GetBootableImage(
111155d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker      "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
1112f6a8bada5f0966762eadaec96de6430d0cd577e3Doug Zongker  updating_recovery = (source_recovery.data != target_recovery.data)
1113eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1114881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  # Here's how we divide up the progress bar:
1115881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  #  0.1 for verifying the start state (PatchCheck calls)
1116881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  #  0.8 for applying patches (ApplyPatch calls)
1117881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  #  0.1 for unpacking verbatim files, symlinking, and doing the
1118881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  #      device-specific commands.
1119eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
11206e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge  AppendAssertions(script, OPTIONS.target_info_dict, oem_dict)
112105d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker  device_specific.IncrementalOTA_Assertions()
1122eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
11239b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  # Two-step incremental package strategy (in chronological order,
11249b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  # which is *not* the order in which the generated script has
11259b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  # things):
11269b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #
11279b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  # if stage is not "2/3" or "3/3":
11289b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    do verification on current system
11299b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    write recovery image to boot partition
11309b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    set stage to "2/3"
11319b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    reboot to boot partition and restart recovery
11329b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  # else if stage is "2/3":
11339b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    write recovery image to recovery partition
11349b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    set stage to "3/3"
11359b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    reboot to recovery partition and restart recovery
11369b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  # else:
11379b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    (stage must be "3/3")
11389b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    perform update:
11399b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #       patch system files, etc.
11409b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #       force full install of new boot image
11419b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #       set up system to update recovery partition on first boot
11429b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  #    complete script normally (allow recovery to mark itself finished and reboot)
11439b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker
11449b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  if OPTIONS.two_step:
11459b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    if not OPTIONS.info_dict.get("multistage_support", None):
11469b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker      assert False, "two-step packages not supported by this build"
11479b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    fs = OPTIONS.info_dict["fstab"]["/misc"]
11489b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    assert fs.fs_type.upper() == "EMMC", \
11499b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker        "two-step packages only supported on devices with EMMC /misc partitions"
11509b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    bcb_dev = {"bcb_dev": fs.device}
11519b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
11529b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    script.AppendExtra("""
1153f9d181979097af3f4a62dad9fff318a916759597Michael Rungeif get_stage("%(bcb_dev)s") == "2/3" then
11549b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker""" % bcb_dev)
11559b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    script.AppendExtra("sleep(20);\n");
11569b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    script.WriteRawImage("/recovery", "recovery.img")
11579b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    script.AppendExtra("""
11589b23f2cd786b46991b7c0198e69264b17875288dDoug Zongkerset_stage("%(bcb_dev)s", "3/3");
11599b23f2cd786b46991b7c0198e69264b17875288dDoug Zongkerreboot_now("%(bcb_dev)s", "recovery");
1160f9d181979097af3f4a62dad9fff318a916759597Michael Rungeelse if get_stage("%(bcb_dev)s") != "3/3" then
11619b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker""" % bcb_dev)
11629b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker
1163c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.Print("Verifying current system...")
1164c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
1165e5ff5907bef42fa9f3eff2e90ad941423dcc91dcDoug Zongker  device_specific.IncrementalOTA_VerifyBegin()
1166e5ff5907bef42fa9f3eff2e90ad941423dcc91dcDoug Zongker
1167881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  script.ShowProgress(0.1, 0)
1168c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  so_far = system_diff.EmitVerification(script)
1169c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  if vendor_diff:
1170c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    so_far += vendor_diff.EmitVerification(script)
1171eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
11725da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker  if updating_boot:
1173ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker    d = common.Difference(target_boot, source_boot)
1174761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker    _, _, d = d.ComputePatch()
11755da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker    print "boot      target: %d  source: %d  diff: %d" % (
11765da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker        target_boot.size, source_boot.size, len(d))
11775da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker
1178048e7ca15f6391681490ce564bc71194adf146aaDoug Zongker    common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
11795da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker
118096a57e737707d05333dced5b657c4ef21c44088aDoug Zongker    boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
1181f2ab290550d6f1b1ea9bab91eb4c3c77ceeb5df4Doug Zongker
1182f2ab290550d6f1b1ea9bab91eb4c3c77ceeb5df4Doug Zongker    script.PatchCheck("%s:%s:%d:%s:%d:%s" %
1183f2ab290550d6f1b1ea9bab91eb4c3c77ceeb5df4Doug Zongker                      (boot_type, boot_device,
118467369983cf23e12724c135c3850c98326558256bDoug Zongker                       source_boot.size, source_boot.sha1,
1185c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                       target_boot.size, target_boot.sha1))
1186881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    so_far += source_boot.size
11875da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker
1188c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  size = []
1189c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  if system_diff.patch_list: size.append(system_diff.largest_source_size)
1190c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  if vendor_diff:
1191c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    if vendor_diff.patch_list: size.append(vendor_diff.largest_source_size)
1192c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  if size or updating_recovery or updating_boot:
1193c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    script.CacheFreeSpaceCheck(max(size))
11945a48209541d5eed602bfb8e2c4ff51e31443daf2Doug Zongker
119505d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker  device_specific.IncrementalOTA_VerifyEnd()
119605d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker
11979b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  if OPTIONS.two_step:
11989b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    script.WriteRawImage("/boot", "recovery.img")
11999b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    script.AppendExtra("""
12009b23f2cd786b46991b7c0198e69264b17875288dDoug Zongkerset_stage("%(bcb_dev)s", "2/3");
12019b23f2cd786b46991b7c0198e69264b17875288dDoug Zongkerreboot_now("%(bcb_dev)s", "");
12029b23f2cd786b46991b7c0198e69264b17875288dDoug Zongkerelse
12039b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker""" % bcb_dev)
12049b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker
1205c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.Comment("---- start making changes here ----")
1206eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1207e5ff5907bef42fa9f3eff2e90ad941423dcc91dcDoug Zongker  device_specific.IncrementalOTA_InstallBegin()
1208e5ff5907bef42fa9f3eff2e90ad941423dcc91dcDoug Zongker
12099b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  if OPTIONS.two_step:
12109b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
12119b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    script.WriteRawImage("/boot", "boot.img")
12129b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    print "writing full boot image (forced by two-step mode)"
12139b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker
1214c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.Print("Removing unneeded files...")
1215c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",))
1216c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  if vendor_diff:
1217c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    vendor_diff.RemoveUnneededFiles(script)
1218eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1219881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  script.ShowProgress(0.8, 0)
1220c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  total_patch_size = 1.0 + system_diff.TotalPatchSize()
1221c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  if vendor_diff:
1222c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    total_patch_size += vendor_diff.TotalPatchSize()
1223881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  if updating_boot:
1224881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    total_patch_size += target_boot.size
1225881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker
1226881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  script.Print("Patching system files...")
1227c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  so_far = system_diff.EmitPatches(script, total_patch_size, 0)
1228c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  if vendor_diff:
1229c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    script.Print("Patching vendor files...")
1230c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far)
1231881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker
12329b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  if not OPTIONS.two_step:
12339b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    if updating_boot:
12349b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker      # Produce the boot image by applying a patch to the current
12359b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker      # contents of the boot partition, and write it back to the
12369b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker      # partition.
12379b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker      script.Print("Patching boot image...")
12389b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker      script.ApplyPatch("%s:%s:%d:%s:%d:%s"
12399b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker                        % (boot_type, boot_device,
12409b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker                           source_boot.size, source_boot.sha1,
12419b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker                           target_boot.size, target_boot.sha1),
12429b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker                        "-",
12439b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker                        target_boot.size, target_boot.sha1,
12449b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker                        source_boot.sha1, "patch/boot.img.p")
12459b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker      so_far += target_boot.size
12469b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker      script.SetProgress(so_far / total_patch_size)
12479b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker      print "boot image changed; including."
12489b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    else:
12499b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker      print "boot image unchanged; skipping."
1250eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1251c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  system_items = ItemSet("system", "META/filesystem_config.txt")
1252c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  if vendor_diff:
1253c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt")
1254c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
1255eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  if updating_recovery:
1256b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    # Recovery is generated as a patch using both the boot image
1257b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    # (which contains the same linux kernel as recovery) and the file
1258b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    # /system/etc/recovery-resource.dat (which contains all the images
1259b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    # used in the recovery UI) as sources.  This lets us minimize the
1260b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    # size of the patch, which must be included in every OTA package.
126173ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker    #
1262b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    # For older builds where recovery-resource.dat is not present, we
1263b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    # use only the boot image as the source.
1264b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker
1265c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker    if not target_has_recovery_patch:
1266c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker      def output_sink(fn, data):
1267c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker        common.ZipWriteStr(output_zip, "recovery/" + fn, data)
1268c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker        system_items.Get("system/" + fn, dir=False)
1269c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker
1270c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker      common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink,
1271c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker                               target_recovery, target_boot)
1272c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker      script.DeleteFiles(["/system/recovery-from-boot.p",
1273c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker                          "/system/etc/install-recovery.sh"])
127473ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker    print "recovery image changed; including as patch from boot."
1275eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  else:
1276eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print "recovery image unchanged; skipping."
1277eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1278881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  script.ShowProgress(0.1, 10)
1279eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1280c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  target_symlinks = CopyPartitionFiles(system_items, target_zip, None)
1281c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  if vendor_diff:
1282c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None))
1283eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1284c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  temp_script = script.MakeTemporary()
1285c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  system_items.GetMetadata(target_zip)
1286c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  system_items.Get("system").SetPermissions(temp_script)
1287c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  if vendor_diff:
1288c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    vendor_items.GetMetadata(target_zip)
1289c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    vendor_items.Get("vendor").SetPermissions(temp_script)
1290c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker
1291c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  # Note that this call will mess up the trees of Items, so make sure
1292c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  # we're done with them.
1293c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  source_symlinks = CopyPartitionFiles(system_items, source_zip, None)
1294c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  if vendor_diff:
1295c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None))
1296eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1297c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
1298eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
1299eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1300eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  # Delete all the symlinks in source that aren't in target.  This
1301eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  # needs to happen before verbatim files are unpacked, in case a
1302eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  # symlink in the source is replaced by a real file in the target.
1303eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  to_delete = []
1304eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  for dest, link in source_symlinks:
1305eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if link not in target_symlinks_d:
1306eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      to_delete.append(link)
1307c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.DeleteFiles(to_delete)
1308eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1309c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  if system_diff.verbatim_targets:
1310c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    script.Print("Unpacking new system files...")
1311c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    script.UnpackPackageDir("system", "/system")
1312c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  if vendor_diff and vendor_diff.verbatim_targets:
1313c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    script.Print("Unpacking new vendor files...")
1314c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    script.UnpackPackageDir("vendor", "/vendor")
1315c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
1316c9253822ea31c1d35d3fc2b495b45b476c240a1dDoug Zongker  if updating_recovery and not target_has_recovery_patch:
131742265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker    script.Print("Unpacking new recovery...")
131842265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker    script.UnpackPackageDir("recovery", "/system")
131942265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker
1320c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  system_diff.EmitRenames(script)
1321c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  if vendor_diff:
1322c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker    vendor_diff.EmitRenames(script)
13234038aa8fff8c68733bff8b55d8c8d1b59713ca37Michael Runge
132405d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker  script.Print("Symlinks and permissions...")
1325eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1326eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  # Create all the symlinks that don't already exist, or point to
1327eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  # somewhere different than what we want.  Delete each symlink before
1328eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  # creating it, since the 'symlink' command won't overwrite.
1329eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  to_create = []
1330eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  for dest, link in target_symlinks:
1331eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if link in source_symlinks_d:
1332eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if dest != source_symlinks_d[link]:
1333eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        to_create.append((dest, link))
1334eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    else:
1335eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      to_create.append((dest, link))
1336c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.DeleteFiles([i[1] for i in to_create])
1337c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.MakeSymlinks(to_create)
1338eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1339eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  # Now that the symlinks are created, we can set all the
1340eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  # permissions.
1341c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.AppendScript(temp_script)
1342eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1343881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  # Do device-specific installation (eg, write radio image).
134405d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker  device_specific.IncrementalOTA_InstallEnd()
134505d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker
13461c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker  if OPTIONS.extra_script is not None:
134767369983cf23e12724c135c3850c98326558256bDoug Zongker    script.AppendExtra(OPTIONS.extra_script)
13481c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker
1349e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker  # Patch the build.prop file last, so if something fails but the
1350e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker  # device can still come up, it appears to be the old build and will
1351e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker  # get set the OTA package again to retry.
1352e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker  script.Print("Patching remaining system files...")
1353c8b4e849f10f3a382694b00453b3f49608c83b48Doug Zongker  system_diff.EmitDeferredPatches(script)
1354e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker
1355922206ec2aeea98491e3edfc297a28b0a39df698Doug Zongker  if OPTIONS.wipe_user_data:
1356922206ec2aeea98491e3edfc297a28b0a39df698Doug Zongker    script.Print("Erasing user data...")
1357922206ec2aeea98491e3edfc297a28b0a39df698Doug Zongker    script.FormatPartition("/data")
1358922206ec2aeea98491e3edfc297a28b0a39df698Doug Zongker
13599b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker  if OPTIONS.two_step:
13609b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    script.AppendExtra("""
13619b23f2cd786b46991b7c0198e69264b17875288dDoug Zongkerset_stage("%(bcb_dev)s", "");
13629b23f2cd786b46991b7c0198e69264b17875288dDoug Zongkerendif;
13639b23f2cd786b46991b7c0198e69264b17875288dDoug Zongkerendif;
13649b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker""" % bcb_dev)
13659b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker
1366e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge  if OPTIONS.verify and system_diff:
1367e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge    script.Print("Remounting and verifying system partition files...")
1368e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge    script.Unmount("/system")
1369e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge    script.Mount("/system")
1370e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge    system_diff.EmitExplicitTargetVerification(script)
1371e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge
1372e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge  if OPTIONS.verify and vendor_diff:
1373e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge    script.Print("Remounting and verifying vendor partition files...")
1374e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge    script.Unmount("/vendor")
1375e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge    script.Mount("/vendor")
1376e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge    vendor_diff.EmitExplicitTargetVerification(script)
137725568486e5777f416d2fcb6cc7aa96caafc66880Doug Zongker  script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
1378e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge
13792ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker  WriteMetadata(metadata, output_zip)
1380eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1381eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1382eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef main(argv):
1383eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1384eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  def option_handler(o, a):
138525568486e5777f416d2fcb6cc7aa96caafc66880Doug Zongker    if o == "--board_config":
1386fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker      pass   # deprecated
1387eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    elif o in ("-k", "--package_key"):
1388eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      OPTIONS.package_key = a
1389eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    elif o in ("-i", "--incremental_from"):
1390eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      OPTIONS.incremental_source = a
1391dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker    elif o in ("-w", "--wipe_user_data"):
1392dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker      OPTIONS.wipe_user_data = True
1393962069ce59c85949d147874df2728a5ffd9193beDoug Zongker    elif o in ("-n", "--no_prereq"):
1394962069ce59c85949d147874df2728a5ffd9193beDoug Zongker      OPTIONS.omit_prereq = True
13956e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge    elif o in ("-o", "--oem_settings"):
13966e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge      OPTIONS.oem_source = a
13971c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker    elif o in ("-e", "--extra_script"):
13981c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker      OPTIONS.extra_script = a
1399dafb04275588fff8248b6a5360ca047cdffd14a5Hristo Bojinov    elif o in ("-a", "--aslr_mode"):
1400dafb04275588fff8248b6a5360ca047cdffd14a5Hristo Bojinov      if a in ("on", "On", "true", "True", "yes", "Yes"):
1401dafb04275588fff8248b6a5360ca047cdffd14a5Hristo Bojinov        OPTIONS.aslr_mode = True
1402dafb04275588fff8248b6a5360ca047cdffd14a5Hristo Bojinov      else:
1403dafb04275588fff8248b6a5360ca047cdffd14a5Hristo Bojinov        OPTIONS.aslr_mode = False
1404374e114d1691a47918a3972dc287615f25650725Martin Blumenstingl    elif o in ("-t", "--worker_threads"):
1405374e114d1691a47918a3972dc287615f25650725Martin Blumenstingl      if a.isdigit():
1406374e114d1691a47918a3972dc287615f25650725Martin Blumenstingl        OPTIONS.worker_threads = int(a)
1407374e114d1691a47918a3972dc287615f25650725Martin Blumenstingl      else:
1408374e114d1691a47918a3972dc287615f25650725Martin Blumenstingl        raise ValueError("Cannot parse value %r for option %r - only "
1409374e114d1691a47918a3972dc287615f25650725Martin Blumenstingl                         "integers are allowed." % (a, o))
14109b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker    elif o in ("-2", "--two_step"):
14119b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker      OPTIONS.two_step = True
141226e6619c37e294fe2ee63aaa759e0ac861775ce8Doug Zongker    elif o == "--no_signing":
1413e153b3464374155d03bfe47092faaab555b89e81Takeshi Kanemoto      OPTIONS.no_signing = True
1414e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge    elif o in ("--verify"):
1415e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge      OPTIONS.verify = True
141626e6619c37e294fe2ee63aaa759e0ac861775ce8Doug Zongker    elif o == "--block":
141726e6619c37e294fe2ee63aaa759e0ac861775ce8Doug Zongker      OPTIONS.block_based = True
141825568486e5777f416d2fcb6cc7aa96caafc66880Doug Zongker    elif o in ("-b", "--binary"):
141925568486e5777f416d2fcb6cc7aa96caafc66880Doug Zongker      OPTIONS.updater_binary = a
142062d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker    elif o in ("--no_fallback_to_full",):
142162d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker      OPTIONS.fallback_to_full = False
1422eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    else:
1423eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      return False
1424dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker    return True
1425eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1426eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  args = common.ParseOptions(argv, __doc__,
1427f5770d78da76ce49ca1ab8334874abdaa6cc7115Ying Wang                             extra_opts="b:k:i:d:wne:t:a:2o:",
1428eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                             extra_long_opts=["board_config=",
1429eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                                              "package_key=",
1430dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker                                              "incremental_from=",
1431962069ce59c85949d147874df2728a5ffd9193beDoug Zongker                                              "wipe_user_data",
14321c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker                                              "no_prereq",
1433c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                                              "extra_script=",
143496be7205dce97977909e93b73f48779fcce3bc65Hristo Bojinov                                              "worker_threads=",
1435c60c1bafa0c20166c53666655e2dea7ff5bfd157Doug Zongker                                              "aslr_mode=",
14369b23f2cd786b46991b7c0198e69264b17875288dDoug Zongker                                              "two_step",
1437e153b3464374155d03bfe47092faaab555b89e81Takeshi Kanemoto                                              "no_signing",
143826e6619c37e294fe2ee63aaa759e0ac861775ce8Doug Zongker                                              "block",
143925568486e5777f416d2fcb6cc7aa96caafc66880Doug Zongker                                              "binary=",
14406e836116f764cf5cebf1654df2f17d8222554f6eMichael Runge                                              "oem_settings=",
1441e8269481084df086a04c6bdcd3477d4209d4a7cbMichael Runge                                              "verify",
144262d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker                                              "no_fallback_to_full",
1443c60c1bafa0c20166c53666655e2dea7ff5bfd157Doug Zongker                                              ],
1444eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                             extra_option_handler=option_handler)
1445eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1446eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  if len(args) != 2:
1447eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    common.Usage(__doc__)
1448eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    sys.exit(1)
1449eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
14501c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker  if OPTIONS.extra_script is not None:
14511c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker    OPTIONS.extra_script = open(OPTIONS.extra_script).read()
14521c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker
1453eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  print "unzipping target target-files..."
145455d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker  OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
1455fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker
1456eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  OPTIONS.target_tmp = OPTIONS.input_tmp
145737974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker  OPTIONS.info_dict = common.LoadInfoDict(input_zip)
1458e2e9f613b5259313c5216d4dad719998a2fbf014Kenny Root
1459e2e9f613b5259313c5216d4dad719998a2fbf014Kenny Root  # If this image was originally labelled with SELinux contexts, make sure we
1460e2e9f613b5259313c5216d4dad719998a2fbf014Kenny Root  # also apply the labels in our new image. During building, the "file_contexts"
1461e2e9f613b5259313c5216d4dad719998a2fbf014Kenny Root  # is in the out/ directory tree, but for repacking from target-files.zip it's
1462e2e9f613b5259313c5216d4dad719998a2fbf014Kenny Root  # in the root directory of the ramdisk.
1463e2e9f613b5259313c5216d4dad719998a2fbf014Kenny Root  if "selinux_fc" in OPTIONS.info_dict:
1464e2e9f613b5259313c5216d4dad719998a2fbf014Kenny Root    OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK",
1465e2e9f613b5259313c5216d4dad719998a2fbf014Kenny Root        "file_contexts")
1466e2e9f613b5259313c5216d4dad719998a2fbf014Kenny Root
146737974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker  if OPTIONS.verbose:
146837974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker    print "--- target info ---"
146937974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker    common.DumpInfoDict(OPTIONS.info_dict)
147037974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker
1471eb0a78afc00265479c002364fa62c9e09c3f613dDoug Zongker  # If the caller explicitly specified the device-specific extensions
1472eb0a78afc00265479c002364fa62c9e09c3f613dDoug Zongker  # path via -s/--device_specific, use that.  Otherwise, use
1473eb0a78afc00265479c002364fa62c9e09c3f613dDoug Zongker  # META/releasetools.py if it is present in the target target_files.
1474eb0a78afc00265479c002364fa62c9e09c3f613dDoug Zongker  # Otherwise, take the path of the file from 'tool_extensions' in the
1475eb0a78afc00265479c002364fa62c9e09c3f613dDoug Zongker  # info dict and look for that in the local filesystem, relative to
1476eb0a78afc00265479c002364fa62c9e09c3f613dDoug Zongker  # the current directory.
1477eb0a78afc00265479c002364fa62c9e09c3f613dDoug Zongker
147837974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker  if OPTIONS.device_specific is None:
1479eb0a78afc00265479c002364fa62c9e09c3f613dDoug Zongker    from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
1480eb0a78afc00265479c002364fa62c9e09c3f613dDoug Zongker    if os.path.exists(from_input):
1481eb0a78afc00265479c002364fa62c9e09c3f613dDoug Zongker      print "(using device-specific extensions from target_files)"
1482eb0a78afc00265479c002364fa62c9e09c3f613dDoug Zongker      OPTIONS.device_specific = from_input
1483eb0a78afc00265479c002364fa62c9e09c3f613dDoug Zongker    else:
1484eb0a78afc00265479c002364fa62c9e09c3f613dDoug Zongker      OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
1485eb0a78afc00265479c002364fa62c9e09c3f613dDoug Zongker
148637974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker  if OPTIONS.device_specific is not None:
1487eb0a78afc00265479c002364fa62c9e09c3f613dDoug Zongker    OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
148837974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker
148962d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker  while True:
149062d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker
149162d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker    if OPTIONS.no_signing:
149262d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker      if os.path.exists(args[1]): os.unlink(args[1])
149362d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker      output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
149462d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker    else:
149562d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker      temp_zip_file = tempfile.NamedTemporaryFile()
149662d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker      output_zip = zipfile.ZipFile(temp_zip_file, "w",
149762d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker                                   compression=zipfile.ZIP_DEFLATED)
149862d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker
149962d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker    if OPTIONS.incremental_source is None:
150062d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker      WriteFullOTAPackage(input_zip, output_zip)
150162d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker      if OPTIONS.package_key is None:
150262d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker        OPTIONS.package_key = OPTIONS.info_dict.get(
150362d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker            "default_system_dev_certificate",
150462d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker            "build/target/product/security/testkey")
150562d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker      break
150662d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker
150762d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker    else:
150862d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker      print "unzipping source target-files..."
150962d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker      OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
151062d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker      OPTIONS.target_info_dict = OPTIONS.info_dict
151162d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker      OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
151262d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker      if "selinux_fc" in OPTIONS.source_info_dict:
151362d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker        OPTIONS.source_info_dict["selinux_fc"] = os.path.join(OPTIONS.source_tmp, "BOOT", "RAMDISK",
151462d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker                                                              "file_contexts")
151562d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker      if OPTIONS.package_key is None:
151662d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker        OPTIONS.package_key = OPTIONS.source_info_dict.get(
151762d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker            "default_system_dev_certificate",
151862d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker            "build/target/product/security/testkey")
151962d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker      if OPTIONS.verbose:
152062d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker        print "--- source info ---"
152162d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker        common.DumpInfoDict(OPTIONS.source_info_dict)
152262d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker      try:
152362d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker        WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
152462d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker        break
152562d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker      except ValueError:
152662d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker        if not OPTIONS.fallback_to_full: raise
152762d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker        print "--- failed to build incremental; falling back to full ---"
152862d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker        OPTIONS.incremental_source = None
152962d4f18a30aeade677ca814cf6f2aa329cf5066dDoug Zongker        output_zip.close()
1530eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1531eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  output_zip.close()
1532afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker
1533e153b3464374155d03bfe47092faaab555b89e81Takeshi Kanemoto  if not OPTIONS.no_signing:
1534e153b3464374155d03bfe47092faaab555b89e81Takeshi Kanemoto    SignOutput(temp_zip_file.name, args[1])
1535e153b3464374155d03bfe47092faaab555b89e81Takeshi Kanemoto    temp_zip_file.close()
1536eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1537eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  print "done."
1538eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1539eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1540eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerif __name__ == '__main__':
1541eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  try:
15427e6d4e45d92fd51f42812ae63ac6e532887bfe0aYing Wang    common.CloseInheritedPipes()
1543eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    main(sys.argv[1:])
1544eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  except common.ExternalError, e:
1545eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print
1546eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print "   ERROR: %s" % (e,)
1547eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print
1548eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    sys.exit(1)
1549fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker  finally:
1550fc44a515d46e6f4d5eaa0d32659b1cf3b9492305Doug Zongker    common.Cleanup()
1551