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
24eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  -b  (--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
40dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker  -w  (--wipe_user_data)
41dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker      Generate an OTA package that will wipe the user data partition
42dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker      when installed.
43dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker
44962069ce59c85949d147874df2728a5ffd9193beDoug Zongker  -n  (--no_prereq)
45962069ce59c85949d147874df2728a5ffd9193beDoug Zongker      Omit the timestamp prereq check normally included at the top of
46962069ce59c85949d147874df2728a5ffd9193beDoug Zongker      the build scripts (used for developer OTA packages which
47962069ce59c85949d147874df2728a5ffd9193beDoug Zongker      legitimately need to go back and forth).
48962069ce59c85949d147874df2728a5ffd9193beDoug Zongker
491c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker  -e  (--extra_script)  <file>
501c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker      Insert the contents of file at the end of the update script.
511c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker
52dafb04275588fff8248b6a5360ca047cdffd14a5Hristo Bojinov  -a  (--aslr_mode)  <on|off>
53dafb04275588fff8248b6a5360ca047cdffd14a5Hristo Bojinov      Specify whether to turn on ASLR for the package (on by default).
5456882bf9b41dc7f8b98f1dea82633144546450b2Stephen Smalley
55eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker"""
56eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
57eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport sys
58eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
59eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerif sys.hexversion < 0x02040000:
60eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  print >> sys.stderr, "Python 2.4 or newer is required."
61eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  sys.exit(1)
62eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
63eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport copy
64c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongkerimport errno
65eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport os
66eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport re
67eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport subprocess
68eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport tempfile
69eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport time
70eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport zipfile
71eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
72cad0bb9f621ff1ccfb584e18249b09768c30a0c0davidtry:
73cad0bb9f621ff1ccfb584e18249b09768c30a0c0david  from hashlib import sha1 as sha1
74cad0bb9f621ff1ccfb584e18249b09768c30a0c0davidexcept ImportError:
75cad0bb9f621ff1ccfb584e18249b09768c30a0c0david  from sha import sha as sha1
76cad0bb9f621ff1ccfb584e18249b09768c30a0c0david
77eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport common
78c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongkerimport edify_generator
79eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
80eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS = common.OPTIONS
81afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug ZongkerOPTIONS.package_key = None
82eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.incremental_source = None
83eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.require_verbatim = set()
84eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.prohibit_verbatim = set(("system/build.prop",))
85eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.patch_threshold = 0.95
86dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug ZongkerOPTIONS.wipe_user_data = False
87962069ce59c85949d147874df2728a5ffd9193beDoug ZongkerOPTIONS.omit_prereq = False
881c390a2aa97127ef8af8b0df1d4028f501fdce64Doug ZongkerOPTIONS.extra_script = None
89dafb04275588fff8248b6a5360ca047cdffd14a5Hristo BojinovOPTIONS.aslr_mode = True
90761e642d54eec743699c6c2ce1ea587853d08f33Doug ZongkerOPTIONS.worker_threads = 3
91eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
92eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef MostPopularKey(d, default):
93eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  """Given a dict, return the key corresponding to the largest
94eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  value.  Returns 'default' if the dict is empty."""
95eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  x = [(v, k) for (k, v) in d.iteritems()]
96eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  if not x: return default
97eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  x.sort()
98eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  return x[-1][1]
99eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
100eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
101eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef IsSymlink(info):
102eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  """Return true if the zipfile.ZipInfo object passed in represents a
103eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  symlink."""
104eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  return (info.external_attr >> 16) == 0120777
105eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
10696be7205dce97977909e93b73f48779fcce3bc65Hristo Bojinovdef IsRegular(info):
10796be7205dce97977909e93b73f48779fcce3bc65Hristo Bojinov  """Return true if the zipfile.ZipInfo object passed in represents a
10896be7205dce97977909e93b73f48779fcce3bc65Hristo Bojinov  symlink."""
10996be7205dce97977909e93b73f48779fcce3bc65Hristo Bojinov  return (info.external_attr >> 28) == 010
110eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
111eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerclass Item:
112eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  """Items represent the metadata (user, group, mode) of files and
113eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  directories in the system image."""
114eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  ITEMS = {}
115eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  def __init__(self, name, dir=False):
116eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    self.name = name
117eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    self.uid = None
118eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    self.gid = None
119eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    self.mode = None
1200eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    self.selabel = None
1210eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    self.capabilities = None
122eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    self.dir = dir
123eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
124eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if name:
125eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      self.parent = Item.Get(os.path.dirname(name), dir=True)
126eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      self.parent.children.append(self)
127eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    else:
128eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      self.parent = None
129eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if dir:
130eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      self.children = []
131eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
132eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  def Dump(self, indent=0):
133eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if self.uid is not None:
134eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      print "%s%s %d %d %o" % ("  "*indent, self.name, self.uid, self.gid, self.mode)
135eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    else:
136eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      print "%s%s %s %s %s" % ("  "*indent, self.name, self.uid, self.gid, self.mode)
137eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if self.dir:
138eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      print "%s%s" % ("  "*indent, self.descendants)
139eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      print "%s%s" % ("  "*indent, self.best_subtree)
140eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      for i in self.children:
141eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        i.Dump(indent=indent+1)
142eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
143eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  @classmethod
144eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  def Get(cls, name, dir=False):
145eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if name not in cls.ITEMS:
146eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      cls.ITEMS[name] = Item(name, dir=dir)
147eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    return cls.ITEMS[name]
148eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
149eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  @classmethod
150283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker  def GetMetadata(cls, input_zip):
151283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker
1520eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    # The target_files contains a record of what the uid,
1530eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    # gid, and mode are supposed to be.
1540eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    output = input_zip.read("META/filesystem_config.txt")
155eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
156eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    for line in output.split("\n"):
157eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if not line: continue
1580eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      columns = line.split()
1590eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      name, uid, gid, mode = columns[:4]
1600eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      selabel = None
1610eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      capabilities = None
1620eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich
1630eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      # After the first 4 columns, there are a series of key=value
1640eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      # pairs. Extract out the fields we care about.
1650eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      for element in columns[4:]:
1660eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich        key, value = element.split("=")
1670eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich        if key == "selabel":
1680eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich          selabel = value
1690eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich        if key == "capabilities":
1700eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich          capabilities = value
1710eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich
172283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker      i = cls.ITEMS.get(name, None)
173283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker      if i is not None:
174283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker        i.uid = int(uid)
175283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker        i.gid = int(gid)
176283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker        i.mode = int(mode, 8)
1770eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich        i.selabel = selabel
1780eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich        i.capabilities = capabilities
179283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker        if i.dir:
180283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker          i.children.sort(key=lambda i: i.name)
181283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker
182283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker    # set metadata for the files generated by this script.
183283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker    i = cls.ITEMS.get("system/recovery-from-boot.p", None)
1840eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0644, None, None
185283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker    i = cls.ITEMS.get("system/etc/install-recovery.sh", None)
1860eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0544, None, None
187eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
188eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  def CountChildMetadata(self):
1890eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    """Count up the (uid, gid, mode, selabel, capabilities) tuples for
1900eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    all children and determine the best strategy for using set_perm_recursive and
191eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    set_perm to correctly chown/chmod all the files to their desired
192eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    values.  Recursively calls itself for all descendants.
193eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
1940eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count} counting up
195eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    all descendants of this node.  (dmode or fmode may be None.)  Also
196eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    sets the best_subtree of each directory Item to the (uid, gid,
1970eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    dmode, fmode, selabel, capabilities) tuple that will match the most
1980eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    descendants of that Item.
199eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    """
200eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
201eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    assert self.dir
2020eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    d = self.descendants = {(self.uid, self.gid, self.mode, None, self.selabel, self.capabilities): 1}
203eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    for i in self.children:
204eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if i.dir:
205eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        for k, v in i.CountChildMetadata().iteritems():
206eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          d[k] = d.get(k, 0) + v
207eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      else:
2080eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich        k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities)
209eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        d[k] = d.get(k, 0) + 1
210eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
2110eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    # Find the (uid, gid, dmode, fmode, selabel, capabilities)
2120eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    # tuple that matches the most descendants.
213eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
214eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    # First, find the (uid, gid) pair that matches the most
215eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    # descendants.
216eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    ug = {}
2170eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    for (uid, gid, _, _, _, _), count in d.iteritems():
218eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      ug[(uid, gid)] = ug.get((uid, gid), 0) + count
219eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    ug = MostPopularKey(ug, (0, 0))
220eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
2210eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    # Now find the dmode, fmode, selabel, and capabilities that match
2220eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    # the most descendants with that (uid, gid), and choose those.
223eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    best_dmode = (0, 0755)
224eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    best_fmode = (0, 0644)
2250eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    best_selabel = (0, None)
2260eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    best_capabilities = (0, None)
227eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    for k, count in d.iteritems():
228eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if k[:2] != ug: continue
229eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2])
230eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3])
2310eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      if k[4] is not None and count >= best_selabel[0]: best_selabel = (count, k[4])
2320eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      if k[5] is not None and count >= best_capabilities[0]: best_capabilities = (count, k[5])
2330eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    self.best_subtree = ug + (best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1])
234eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
235eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    return d
236eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
237c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def SetPermissions(self, script):
238eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    """Append set_perm/set_perm_recursive commands to 'script' to
239eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    set all permissions, users, and groups for the tree of files
240c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    rooted at 'self'."""
241eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
242eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    self.CountChildMetadata()
243eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
244eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    def recurse(item, current):
2450eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple that the current
246eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      # item (and all its children) have already been set to.  We only
247eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      # need to issue set_perm/set_perm_recursive commands if we're
248eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      # supposed to be something different.
249eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if item.dir:
250eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        if current != item.best_subtree:
251c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker          script.SetPermissionsRecursive("/"+item.name, *item.best_subtree)
252eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          current = item.best_subtree
253eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
254eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        if item.uid != current[0] or item.gid != current[1] or \
2550eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich           item.mode != current[2] or item.selabel != current[4] or \
2560eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich           item.capabilities != current[5]:
2570eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich          script.SetPermissions("/"+item.name, item.uid, item.gid,
2580eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich                                item.mode, item.selabel, item.capabilities)
259eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
260eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        for i in item.children:
261eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          recurse(i, current)
262eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      else:
263eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        if item.uid != current[0] or item.gid != current[1] or \
2640eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich               item.mode != current[3] or item.selabel != current[4] or \
2650eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich               item.capabilities != current[5]:
2660eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich          script.SetPermissions("/"+item.name, item.uid, item.gid,
2670eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich                                item.mode, item.selabel, item.capabilities)
268eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
2690eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    recurse(self, (-1, -1, -1, -1, None, None))
270eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
271eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
272eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef CopySystemFiles(input_zip, output_zip=None,
273eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                    substitute=None):
274eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  """Copies files underneath system/ in the input zip to the output
275eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  zip.  Populates the Item class with their metadata, and returns a
2761807e700a568d57901b835370d1b1ae05c3dbb0fDoug Zongker  list of symlinks.  output_zip may be None, in which case the copy is
2771807e700a568d57901b835370d1b1ae05c3dbb0fDoug Zongker  skipped (but the other side effects still happen).  substitute is an
2781807e700a568d57901b835370d1b1ae05c3dbb0fDoug Zongker  optional dict of {output filename: contents} to be output instead of
2791807e700a568d57901b835370d1b1ae05c3dbb0fDoug Zongker  certain input files.
280eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  """
281eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
282eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  symlinks = []
283eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
284eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  for info in input_zip.infolist():
285eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if info.filename.startswith("SYSTEM/"):
286eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      basefilename = info.filename[7:]
287eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if IsSymlink(info):
288eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        symlinks.append((input_zip.read(info.filename),
289c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                         "/system/" + basefilename))
290eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      else:
291eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        info2 = copy.copy(info)
292eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        fn = info2.filename = "system/" + basefilename
293eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        if substitute and fn in substitute and substitute[fn] is None:
294eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          continue
295eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        if output_zip is not None:
296eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          if substitute and fn in substitute:
297eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker            data = substitute[fn]
298eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          else:
299eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker            data = input_zip.read(info.filename)
300eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          output_zip.writestr(info2, data)
301eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        if fn.endswith("/"):
302eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          Item.Get(fn[:-1], dir=True)
303eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        else:
304eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker          Item.Get(fn, dir=False)
305eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
306eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  symlinks.sort()
3071807e700a568d57901b835370d1b1ae05c3dbb0fDoug Zongker  return symlinks
308eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
309eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
310eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef SignOutput(temp_zip_name, output_zip_name):
311eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
312eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  pw = key_passwords[OPTIONS.package_key]
313eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
314951495fc4802a3603f654c02c7acceda4859f5e1Doug Zongker  common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw,
315951495fc4802a3603f654c02c7acceda4859f5e1Doug Zongker                  whole_file=True)
316eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
317eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
3181eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongkerdef AppendAssertions(script, info_dict):
3191eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker  device = GetBuildProp("ro.product.device", info_dict)
320c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.AssertDevice(device)
321eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
322eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
323b32161a2a54706efc0d3493123a971aae93e5261Doug Zongkerdef MakeRecoveryPatch(input_tmp, output_zip, recovery_img, boot_img):
32473ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  """Generate a binary patch that creates the recovery image starting
32573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  with the boot image.  (Most of the space in these images is just the
32673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  kernel, which is identical for the two, so the resulting patch
32773ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  should be efficient.)  Add it to the output zip, along with a shell
32873ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  script that is run from init.rc on first boot to actually do the
32973ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  patching and install the new recovery image.
33073ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker
33173ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  recovery_img and boot_img should be File objects for the
33267369983cf23e12724c135c3850c98326558256bDoug Zongker  corresponding images.  info should be the dictionary returned by
33367369983cf23e12724c135c3850c98326558256bDoug Zongker  common.LoadInfoDict() on the input target_files.
33473ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker
33573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  Returns an Item for the shell script, which must be made
33673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  executable.
33773ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  """
33873ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker
339b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker  diff_program = ["imgdiff"]
340b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker  path = os.path.join(input_tmp, "SYSTEM", "etc", "recovery-resource.dat")
341b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker  if os.path.exists(path):
342b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    diff_program.append("-b")
343b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    diff_program.append(path)
344b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    bonus_args = "-b /system/etc/recovery-resource.dat"
345b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker  else:
346b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    bonus_args = ""
347b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker
348b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker  d = common.Difference(recovery_img, boot_img, diff_program=diff_program)
349761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker  _, _, patch = d.ComputePatch()
350cfd7db6d8494c7d3169a4eac0dc63737a24ff1d1Doug Zongker  common.ZipWriteStr(output_zip, "recovery/recovery-from-boot.p", patch)
35173ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  Item.Get("system/recovery-from-boot.p", dir=False)
35273ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker
35396a57e737707d05333dced5b657c4ef21c44088aDoug Zongker  boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
35496a57e737707d05333dced5b657c4ef21c44088aDoug Zongker  recovery_type, recovery_device = common.GetTypeAndDevice("/recovery", OPTIONS.info_dict)
3559ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker
35673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  sh = """#!/system/bin/sh
3570276d1887374fe5a09f57d7f1c8bbdbc9f3e6c3fDoug Zongkerif ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then
35873ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  log -t recovery "Installing new recovery image"
359b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker  applypatch %(bonus_args)s %(boot_type)s:%(boot_device)s:%(boot_size)d:%(boot_sha1)s %(recovery_type)s:%(recovery_device)s %(recovery_sha1)s %(recovery_size)d %(boot_sha1)s:/system/recovery-from-boot.p
36073ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongkerelse
36173ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  log -t recovery "Recovery image already installed"
36273ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongkerfi
36373ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker""" % { 'boot_size': boot_img.size,
36473ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker        'boot_sha1': boot_img.sha1,
36573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker        'recovery_size': recovery_img.size,
36667369983cf23e12724c135c3850c98326558256bDoug Zongker        'recovery_sha1': recovery_img.sha1,
3679ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker        'boot_type': boot_type,
3689ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker        'boot_device': boot_device,
3699ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker        'recovery_type': recovery_type,
3709ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker        'recovery_device': recovery_device,
371b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker        'bonus_args': bonus_args,
37267369983cf23e12724c135c3850c98326558256bDoug Zongker        }
373cfd7db6d8494c7d3169a4eac0dc63737a24ff1d1Doug Zongker  common.ZipWriteStr(output_zip, "recovery/etc/install-recovery.sh", sh)
37473ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  return Item.Get("system/etc/install-recovery.sh", dir=False)
37573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker
37673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker
377c77a9ad444d49e2ad777678cf5671f0a94f44ffbDoug Zongkerdef WriteFullOTAPackage(input_zip, output_zip):
3789ce2ebf5d300eba5f6086583b0941ef68a3e4b42Doug Zongker  # TODO: how to determine this?  We don't know what version it will
3799ce2ebf5d300eba5f6086583b0941ef68a3e4b42Doug Zongker  # be installed on top of.  For now, we expect the API just won't
3809ce2ebf5d300eba5f6086583b0941ef68a3e4b42Doug Zongker  # change very often.
381c77a9ad444d49e2ad777678cf5671f0a94f44ffbDoug Zongker  script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)
382eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
3831eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker  metadata = {"post-build": GetBuildProp("ro.build.fingerprint",
3841eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker                                         OPTIONS.info_dict),
3851eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker              "pre-device": GetBuildProp("ro.product.device",
3861eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker                                         OPTIONS.info_dict),
3871eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker              "post-timestamp": GetBuildProp("ro.build.date.utc",
3881eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker                                             OPTIONS.info_dict),
3892ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker              }
3902ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker
39105d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker  device_specific = common.DeviceSpecificParams(
39205d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker      input_zip=input_zip,
39337974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker      input_version=OPTIONS.info_dict["recovery_api_version"],
39405d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker      output_zip=output_zip,
39505d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker      script=script,
3962ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker      input_tmp=OPTIONS.input_tmp,
39796a57e737707d05333dced5b657c4ef21c44088aDoug Zongker      metadata=metadata,
39896a57e737707d05333dced5b657c4ef21c44088aDoug Zongker      info_dict=OPTIONS.info_dict)
39905d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker
400962069ce59c85949d147874df2728a5ffd9193beDoug Zongker  if not OPTIONS.omit_prereq:
4011eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker    ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict)
4020d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker    ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict)
4030d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker    script.AssertOlderBuild(ts, ts_text)
404eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
4051eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker  AppendAssertions(script, OPTIONS.info_dict)
40605d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker  device_specific.FullOTA_Assertions()
407e5ff5907bef42fa9f3eff2e90ad941423dcc91dcDoug Zongker  device_specific.FullOTA_InstallBegin()
408171f1cde104891840b0c3c271935fae5433f1b25Doug Zongker
409c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.ShowProgress(0.5, 0)
410eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
411dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker  if OPTIONS.wipe_user_data:
4129ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker    script.FormatPartition("/data")
413dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker
414f32dc71e49656e16fc8e178f7436706a47e8af52Kenny Root  if "selinux_fc" in OPTIONS.info_dict:
415f32dc71e49656e16fc8e178f7436706a47e8af52Kenny Root    WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
41656882bf9b41dc7f8b98f1dea82633144546450b2Stephen Smalley
4179ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker  script.FormatPartition("/system")
4189ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker  script.Mount("/system")
419cfd7db6d8494c7d3169a4eac0dc63737a24ff1d1Doug Zongker  script.UnpackPackageDir("recovery", "/system")
420c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.UnpackPackageDir("system", "/system")
421eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
4221807e700a568d57901b835370d1b1ae05c3dbb0fDoug Zongker  symlinks = CopySystemFiles(input_zip, output_zip)
423c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.MakeSymlinks(symlinks)
424eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
42555d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker  boot_img = common.GetBootableImage("boot.img", "boot.img",
42655d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker                                     OPTIONS.input_tmp, "BOOT")
42755d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker  recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
42855d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker                                         OPTIONS.input_tmp, "RECOVERY")
429b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker  MakeRecoveryPatch(OPTIONS.input_tmp, output_zip, recovery_img, boot_img)
43073ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker
431283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker  Item.GetMetadata(input_zip)
43273ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  Item.Get("system").SetPermissions(script)
433eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
43437974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker  common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
43573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
436c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.ShowProgress(0.2, 0)
437c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
438c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.ShowProgress(0.2, 10)
4399ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker  script.WriteRawImage("/boot", "boot.img")
44005d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker
44105d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker  script.ShowProgress(0.1, 0)
44205d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker  device_specific.FullOTA_InstallEnd()
443eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
4441c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker  if OPTIONS.extra_script is not None:
445c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    script.AppendExtra(OPTIONS.extra_script)
4461c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker
44714833605d26bf970cd5335c02af4354b68d93348Doug Zongker  script.UnmountAll()
448c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.AddToZip(input_zip, output_zip)
4492ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker  WriteMetadata(metadata, output_zip)
4502ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker
45156882bf9b41dc7f8b98f1dea82633144546450b2Stephen Smalleydef WritePolicyConfig(file_context, output_zip):
45256882bf9b41dc7f8b98f1dea82633144546450b2Stephen Smalley  f = open(file_context, 'r');
45356882bf9b41dc7f8b98f1dea82633144546450b2Stephen Smalley  basename = os.path.basename(file_context)
45456882bf9b41dc7f8b98f1dea82633144546450b2Stephen Smalley  common.ZipWriteStr(output_zip, basename, f.read())
45556882bf9b41dc7f8b98f1dea82633144546450b2Stephen Smalley
4562ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker
4572ea21065b66da9819df92b37a79f0f87552ee331Doug Zongkerdef WriteMetadata(metadata, output_zip):
4582ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker  common.ZipWriteStr(output_zip, "META-INF/com/android/metadata",
4592ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker                     "".join(["%s=%s\n" % kv
4602ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker                              for kv in sorted(metadata.iteritems())]))
461eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
462eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef LoadSystemFiles(z):
463eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  """Load all the files from SYSTEM/... in a given target-files
464eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  ZipFile, and return a dict of {filename: File object}."""
465eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  out = {}
466eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  for info in z.infolist():
467eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
46896be7205dce97977909e93b73f48779fcce3bc65Hristo Bojinov      basefilename = info.filename[7:]
46996be7205dce97977909e93b73f48779fcce3bc65Hristo Bojinov      fn = "system/" + basefilename
470eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      data = z.read(info.filename)
471ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker      out[fn] = common.File(fn, data)
4721807e700a568d57901b835370d1b1ae05c3dbb0fDoug Zongker  return out
473eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
474eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
4751eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongkerdef GetBuildProp(prop, info_dict):
4761eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker  """Return the fingerprint of the build of a given target-files info_dict."""
4771eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker  try:
4781eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker    return info_dict.get("build.prop", {})[prop]
4791eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker  except KeyError:
4809fc74c7823182c4121f32114a7f83ae3fa7e4346Doug Zongker    raise common.ExternalError("couldn't find %s in build.prop" % (property,))
481eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
482eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
483c77a9ad444d49e2ad777678cf5671f0a94f44ffbDoug Zongkerdef WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
48437974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker  source_version = OPTIONS.source_info_dict["recovery_api_version"]
48537974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker  target_version = OPTIONS.target_info_dict["recovery_api_version"]
486c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
4879ce2ebf5d300eba5f6086583b0941ef68a3e4b42Doug Zongker  if source_version == 0:
4889ce2ebf5d300eba5f6086583b0941ef68a3e4b42Doug Zongker    print ("WARNING: generating edify script for a source that "
4899ce2ebf5d300eba5f6086583b0941ef68a3e4b42Doug Zongker           "can't install it.")
4901eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker  script = edify_generator.EdifyGenerator(source_version,
4911eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker                                          OPTIONS.target_info_dict)
492eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
4931eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker  metadata = {"pre-device": GetBuildProp("ro.product.device",
4941eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker                                         OPTIONS.source_info_dict),
4951eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker              "post-timestamp": GetBuildProp("ro.build.date.utc",
4961eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker                                             OPTIONS.target_info_dict),
4972ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker              }
4982ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker
49905d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker  device_specific = common.DeviceSpecificParams(
50005d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker      source_zip=source_zip,
50114833605d26bf970cd5335c02af4354b68d93348Doug Zongker      source_version=source_version,
50205d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker      target_zip=target_zip,
50314833605d26bf970cd5335c02af4354b68d93348Doug Zongker      target_version=target_version,
50405d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker      output_zip=output_zip,
5052ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker      script=script,
50696a57e737707d05333dced5b657c4ef21c44088aDoug Zongker      metadata=metadata,
50796a57e737707d05333dced5b657c4ef21c44088aDoug Zongker      info_dict=OPTIONS.info_dict)
50805d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker
509eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  print "Loading target..."
5101807e700a568d57901b835370d1b1ae05c3dbb0fDoug Zongker  target_data = LoadSystemFiles(target_zip)
511eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  print "Loading source..."
5121807e700a568d57901b835370d1b1ae05c3dbb0fDoug Zongker  source_data = LoadSystemFiles(source_zip)
513eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
514eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  verbatim_targets = []
515eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  patch_list = []
516761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker  diffs = []
517eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  largest_source_size = 0
518eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  for fn in sorted(target_data.keys()):
519eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    tf = target_data[fn]
520761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker    assert fn == tf.name
521eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    sf = source_data.get(fn, None)
522eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
523eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if sf is None or fn in OPTIONS.require_verbatim:
524eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      # This file should be included verbatim
525eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if fn in OPTIONS.prohibit_verbatim:
5269fc74c7823182c4121f32114a7f83ae3fa7e4346Doug Zongker        raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,))
527eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      print "send", fn, "verbatim"
528eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      tf.AddToZip(output_zip)
529eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      verbatim_targets.append((fn, tf.size))
530eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    elif tf.sha1 != sf.sha1:
531eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      # File is different; consider sending as a patch
532ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker      diffs.append(common.Difference(tf, sf))
533eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    else:
534eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      # Target file identical to source.
535eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      pass
536eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
537ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker  common.ComputeDifferences(diffs)
538761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker
539761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker  for diff in diffs:
540761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker    tf, sf, d = diff.GetPatch()
541761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker    if d is None or len(d) > tf.size * OPTIONS.patch_threshold:
542761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker      # patch is almost as big as the file; don't bother patching
543761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker      tf.AddToZip(output_zip)
544761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker      verbatim_targets.append((tf.name, tf.size))
545761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker    else:
546761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker      common.ZipWriteStr(output_zip, "patch/" + tf.name + ".p", d)
54755d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker      patch_list.append((tf.name, tf, sf, tf.size, common.sha1(d).hexdigest()))
548761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker      largest_source_size = max(largest_source_size, sf.size)
549eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
5501eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker  source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
5511eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker  target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
5522ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker  metadata["pre-build"] = source_fp
5532ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker  metadata["post-build"] = target_fp
554eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
5559ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker  script.Mount("/system")
556c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.AssertSomeFingerprint(source_fp, target_fp)
557eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
55855d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker  source_boot = common.GetBootableImage(
559d513160b76a189899ba01f87a3987b4c6f428caeDoug Zongker      "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
560d513160b76a189899ba01f87a3987b4c6f428caeDoug Zongker      OPTIONS.source_info_dict)
56155d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker  target_boot = common.GetBootableImage(
56255d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker      "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
5635da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker  updating_boot = (source_boot.data != target_boot.data)
564eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
56555d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker  source_recovery = common.GetBootableImage(
566d513160b76a189899ba01f87a3987b4c6f428caeDoug Zongker      "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
567d513160b76a189899ba01f87a3987b4c6f428caeDoug Zongker      OPTIONS.source_info_dict)
56855d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker  target_recovery = common.GetBootableImage(
56955d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker      "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
570f6a8bada5f0966762eadaec96de6430d0cd577e3Doug Zongker  updating_recovery = (source_recovery.data != target_recovery.data)
571eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
572881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  # Here's how we divide up the progress bar:
573881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  #  0.1 for verifying the start state (PatchCheck calls)
574881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  #  0.8 for applying patches (ApplyPatch calls)
575881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  #  0.1 for unpacking verbatim files, symlinking, and doing the
576881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  #      device-specific commands.
577eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
5781eb74dd9a01ec14a2e41309986ef7efba790be8fDoug Zongker  AppendAssertions(script, OPTIONS.target_info_dict)
57905d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker  device_specific.IncrementalOTA_Assertions()
580eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
581c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.Print("Verifying current system...")
582c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
583e5ff5907bef42fa9f3eff2e90ad941423dcc91dcDoug Zongker  device_specific.IncrementalOTA_VerifyBegin()
584e5ff5907bef42fa9f3eff2e90ad941423dcc91dcDoug Zongker
585881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  script.ShowProgress(0.1, 0)
586881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  total_verify_size = float(sum([i[2].size for i in patch_list]) + 1)
587881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  if updating_boot:
588881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    total_verify_size += source_boot.size
589881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  so_far = 0
590c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
5915a48209541d5eed602bfb8e2c4ff51e31443daf2Doug Zongker  for fn, tf, sf, size, patch_sha in patch_list:
592c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    script.PatchCheck("/"+fn, tf.sha1, sf.sha1)
593881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    so_far += sf.size
594881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    script.SetProgress(so_far / total_verify_size)
595eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
5965da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker  if updating_boot:
597ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker    d = common.Difference(target_boot, source_boot)
598761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker    _, _, d = d.ComputePatch()
5995da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker    print "boot      target: %d  source: %d  diff: %d" % (
6005da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker        target_boot.size, source_boot.size, len(d))
6015da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker
602048e7ca15f6391681490ce564bc71194adf146aaDoug Zongker    common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
6035da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker
60496a57e737707d05333dced5b657c4ef21c44088aDoug Zongker    boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
605f2ab290550d6f1b1ea9bab91eb4c3c77ceeb5df4Doug Zongker
606f2ab290550d6f1b1ea9bab91eb4c3c77ceeb5df4Doug Zongker    script.PatchCheck("%s:%s:%d:%s:%d:%s" %
607f2ab290550d6f1b1ea9bab91eb4c3c77ceeb5df4Doug Zongker                      (boot_type, boot_device,
60867369983cf23e12724c135c3850c98326558256bDoug Zongker                       source_boot.size, source_boot.sha1,
609c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                       target_boot.size, target_boot.sha1))
610881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    so_far += source_boot.size
611881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    script.SetProgress(so_far / total_verify_size)
6125da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker
6135da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker  if patch_list or updating_recovery or updating_boot:
614c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    script.CacheFreeSpaceCheck(largest_source_size)
6155a48209541d5eed602bfb8e2c4ff51e31443daf2Doug Zongker
61605d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker  device_specific.IncrementalOTA_VerifyEnd()
61705d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker
618c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.Comment("---- start making changes here ----")
619eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
620e5ff5907bef42fa9f3eff2e90ad941423dcc91dcDoug Zongker  device_specific.IncrementalOTA_InstallBegin()
621e5ff5907bef42fa9f3eff2e90ad941423dcc91dcDoug Zongker
622dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker  if OPTIONS.wipe_user_data:
623c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    script.Print("Erasing user data...")
6249ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker    script.FormatPartition("/data")
625dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker
626c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.Print("Removing unneeded files...")
6270f3298a497e32f6c2325a0071124a62d031fae6fDoug Zongker  script.DeleteFiles(["/"+i[0] for i in verbatim_targets] +
6280f3298a497e32f6c2325a0071124a62d031fae6fDoug Zongker                     ["/"+i for i in sorted(source_data)
6293b949f07259ee8d67b4454627aceab5e6f44bd39Doug Zongker                            if i not in target_data] +
6303b949f07259ee8d67b4454627aceab5e6f44bd39Doug Zongker                     ["/system/recovery.img"])
631eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
632881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  script.ShowProgress(0.8, 0)
633881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  total_patch_size = float(sum([i[1].size for i in patch_list]) + 1)
634881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  if updating_boot:
635881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    total_patch_size += target_boot.size
636881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  so_far = 0
637881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker
638881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  script.Print("Patching system files...")
639e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker  deferred_patch_list = []
640e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker  for item in patch_list:
641e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker    fn, tf, sf, size, _ = item
642e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker    if tf.name == "system/build.prop":
643e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker      deferred_patch_list.append(item)
644e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker      continue
645c8d446bcde877ec94f8e68dd5af68fe34eb1b1f9Doug Zongker    script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
646881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    so_far += tf.size
647881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    script.SetProgress(so_far / total_patch_size)
648881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker
649eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  if updating_boot:
6505da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker    # Produce the boot image by applying a patch to the current
6515da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker    # contents of the boot partition, and write it back to the
6525da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker    # partition.
653c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    script.Print("Patching boot image...")
654f2ab290550d6f1b1ea9bab91eb4c3c77ceeb5df4Doug Zongker    script.ApplyPatch("%s:%s:%d:%s:%d:%s"
655f2ab290550d6f1b1ea9bab91eb4c3c77ceeb5df4Doug Zongker                      % (boot_type, boot_device,
65667369983cf23e12724c135c3850c98326558256bDoug Zongker                         source_boot.size, source_boot.sha1,
657c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                         target_boot.size, target_boot.sha1),
658c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                      "-",
659c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                      target_boot.size, target_boot.sha1,
660c8d446bcde877ec94f8e68dd5af68fe34eb1b1f9Doug Zongker                      source_boot.sha1, "patch/boot.img.p")
661881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    so_far += target_boot.size
662881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    script.SetProgress(so_far / total_patch_size)
663eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print "boot image changed; including."
664eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  else:
665eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print "boot image unchanged; skipping."
666eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
667eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  if updating_recovery:
668b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    # Recovery is generated as a patch using both the boot image
669b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    # (which contains the same linux kernel as recovery) and the file
670b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    # /system/etc/recovery-resource.dat (which contains all the images
671b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    # used in the recovery UI) as sources.  This lets us minimize the
672b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    # size of the patch, which must be included in every OTA package.
67373ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker    #
674b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    # For older builds where recovery-resource.dat is not present, we
675b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    # use only the boot image as the source.
676b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker
677b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker    MakeRecoveryPatch(OPTIONS.target_tmp, output_zip,
678b32161a2a54706efc0d3493123a971aae93e5261Doug Zongker                      target_recovery, target_boot)
67942265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker    script.DeleteFiles(["/system/recovery-from-boot.p",
68042265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker                        "/system/etc/install-recovery.sh"])
68173ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker    print "recovery image changed; including as patch from boot."
682eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  else:
683eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print "recovery image unchanged; skipping."
684eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
685881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  script.ShowProgress(0.1, 10)
686eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
6871807e700a568d57901b835370d1b1ae05c3dbb0fDoug Zongker  target_symlinks = CopySystemFiles(target_zip, None)
688eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
689eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks])
690c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  temp_script = script.MakeTemporary()
691283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker  Item.GetMetadata(target_zip)
69273ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker  Item.Get("system").SetPermissions(temp_script)
693eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
694eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  # Note that this call will mess up the tree of Items, so make sure
695eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  # we're done with it.
6961807e700a568d57901b835370d1b1ae05c3dbb0fDoug Zongker  source_symlinks = CopySystemFiles(source_zip, None)
697eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks])
698eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
699eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  # Delete all the symlinks in source that aren't in target.  This
700eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  # needs to happen before verbatim files are unpacked, in case a
701eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  # symlink in the source is replaced by a real file in the target.
702eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  to_delete = []
703eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  for dest, link in source_symlinks:
704eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if link not in target_symlinks_d:
705eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      to_delete.append(link)
706c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.DeleteFiles(to_delete)
707eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
708eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  if verbatim_targets:
709c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    script.Print("Unpacking new files...")
710c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    script.UnpackPackageDir("system", "/system")
711c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
71242265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker  if updating_recovery:
71342265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker    script.Print("Unpacking new recovery...")
71442265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker    script.UnpackPackageDir("recovery", "/system")
71542265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker
71605d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker  script.Print("Symlinks and permissions...")
717eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
718eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  # Create all the symlinks that don't already exist, or point to
719eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  # somewhere different than what we want.  Delete each symlink before
720eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  # creating it, since the 'symlink' command won't overwrite.
721eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  to_create = []
722eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  for dest, link in target_symlinks:
723eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if link in source_symlinks_d:
724eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      if dest != source_symlinks_d[link]:
725eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker        to_create.append((dest, link))
726eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    else:
727eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      to_create.append((dest, link))
728c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.DeleteFiles([i[1] for i in to_create])
729c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.MakeSymlinks(to_create)
730eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
731eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  # Now that the symlinks are created, we can set all the
732eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  # permissions.
733c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.AppendScript(temp_script)
734eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
735881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  # Do device-specific installation (eg, write radio image).
73605d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker  device_specific.IncrementalOTA_InstallEnd()
73705d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker
7381c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker  if OPTIONS.extra_script is not None:
73967369983cf23e12724c135c3850c98326558256bDoug Zongker    script.AppendExtra(OPTIONS.extra_script)
7401c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker
741e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker  # Patch the build.prop file last, so if something fails but the
742e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker  # device can still come up, it appears to be the old build and will
743e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker  # get set the OTA package again to retry.
744e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker  script.Print("Patching remaining system files...")
745e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker  for item in deferred_patch_list:
746e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker    fn, tf, sf, size, _ = item
747e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker    script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p")
7480eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich  script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None)
749e92f15a85885de8db24b6f2ab536d25cf20a5ca5Doug Zongker
750c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  script.AddToZip(target_zip, output_zip)
7512ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker  WriteMetadata(metadata, output_zip)
752eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
753eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
754eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef main(argv):
755eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
756eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  def option_handler(o, a):
757eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    if o in ("-b", "--board_config"):
758fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker      pass   # deprecated
759eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    elif o in ("-k", "--package_key"):
760eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      OPTIONS.package_key = a
761eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    elif o in ("-i", "--incremental_from"):
762eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      OPTIONS.incremental_source = a
763dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker    elif o in ("-w", "--wipe_user_data"):
764dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker      OPTIONS.wipe_user_data = True
765962069ce59c85949d147874df2728a5ffd9193beDoug Zongker    elif o in ("-n", "--no_prereq"):
766962069ce59c85949d147874df2728a5ffd9193beDoug Zongker      OPTIONS.omit_prereq = True
7671c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker    elif o in ("-e", "--extra_script"):
7681c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker      OPTIONS.extra_script = a
769dafb04275588fff8248b6a5360ca047cdffd14a5Hristo Bojinov    elif o in ("-a", "--aslr_mode"):
770dafb04275588fff8248b6a5360ca047cdffd14a5Hristo Bojinov      if a in ("on", "On", "true", "True", "yes", "Yes"):
771dafb04275588fff8248b6a5360ca047cdffd14a5Hristo Bojinov        OPTIONS.aslr_mode = True
772dafb04275588fff8248b6a5360ca047cdffd14a5Hristo Bojinov      else:
773dafb04275588fff8248b6a5360ca047cdffd14a5Hristo Bojinov        OPTIONS.aslr_mode = False
774761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker    elif o in ("--worker_threads"):
775761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker      OPTIONS.worker_threads = int(a)
776eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    else:
777eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker      return False
778dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker    return True
779eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
780eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  args = common.ParseOptions(argv, __doc__,
781dafb04275588fff8248b6a5360ca047cdffd14a5Hristo Bojinov                             extra_opts="b:k:i:d:wne:a:",
782eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                             extra_long_opts=["board_config=",
783eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                                              "package_key=",
784dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker                                              "incremental_from=",
785962069ce59c85949d147874df2728a5ffd9193beDoug Zongker                                              "wipe_user_data",
7861c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker                                              "no_prereq",
787c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                                              "extra_script=",
78896be7205dce97977909e93b73f48779fcce3bc65Hristo Bojinov                                              "worker_threads=",
789c60c1bafa0c20166c53666655e2dea7ff5bfd157Doug Zongker                                              "aslr_mode=",
790c60c1bafa0c20166c53666655e2dea7ff5bfd157Doug Zongker                                              ],
791eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker                             extra_option_handler=option_handler)
792eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
793eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  if len(args) != 2:
794eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    common.Usage(__doc__)
795eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    sys.exit(1)
796eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
7971c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker  if OPTIONS.extra_script is not None:
7981c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker    OPTIONS.extra_script = open(OPTIONS.extra_script).read()
7991c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker
800eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  print "unzipping target target-files..."
80155d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker  OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
802fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker
803eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  OPTIONS.target_tmp = OPTIONS.input_tmp
80437974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker  OPTIONS.info_dict = common.LoadInfoDict(input_zip)
805e2e9f613b5259313c5216d4dad719998a2fbf014Kenny Root
806e2e9f613b5259313c5216d4dad719998a2fbf014Kenny Root  # If this image was originally labelled with SELinux contexts, make sure we
807e2e9f613b5259313c5216d4dad719998a2fbf014Kenny Root  # also apply the labels in our new image. During building, the "file_contexts"
808e2e9f613b5259313c5216d4dad719998a2fbf014Kenny Root  # is in the out/ directory tree, but for repacking from target-files.zip it's
809e2e9f613b5259313c5216d4dad719998a2fbf014Kenny Root  # in the root directory of the ramdisk.
810e2e9f613b5259313c5216d4dad719998a2fbf014Kenny Root  if "selinux_fc" in OPTIONS.info_dict:
811e2e9f613b5259313c5216d4dad719998a2fbf014Kenny Root    OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK",
812e2e9f613b5259313c5216d4dad719998a2fbf014Kenny Root        "file_contexts")
813e2e9f613b5259313c5216d4dad719998a2fbf014Kenny Root
81437974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker  if OPTIONS.verbose:
81537974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker    print "--- target info ---"
81637974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker    common.DumpInfoDict(OPTIONS.info_dict)
81737974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker
81837974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker  if OPTIONS.device_specific is None:
81937974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker    OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)
82037974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker  if OPTIONS.device_specific is not None:
82137974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker    OPTIONS.device_specific = os.path.normpath(OPTIONS.device_specific)
82237974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker    print "using device-specific extensions in", OPTIONS.device_specific
82337974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker
824afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker  temp_zip_file = tempfile.NamedTemporaryFile()
825afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker  output_zip = zipfile.ZipFile(temp_zip_file, "w",
826afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker                               compression=zipfile.ZIP_DEFLATED)
827eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
828eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  if OPTIONS.incremental_source is None:
829c77a9ad444d49e2ad777678cf5671f0a94f44ffbDoug Zongker    WriteFullOTAPackage(input_zip, output_zip)
830afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker    if OPTIONS.package_key is None:
831afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker      OPTIONS.package_key = OPTIONS.info_dict.get(
832afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker          "default_system_dev_certificate",
833afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker          "build/target/product/security/testkey")
834eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  else:
835eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print "unzipping source target-files..."
83655d932840f1a5b412f2961f79368ecec2d28f647Doug Zongker    OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source)
83737974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker    OPTIONS.target_info_dict = OPTIONS.info_dict
83837974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker    OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
839afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker    if OPTIONS.package_key is None:
84091b4f8a8504711153b5a0126407d3683a9ab75beDoug Zongker      OPTIONS.package_key = OPTIONS.source_info_dict.get(
841afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker          "default_system_dev_certificate",
842afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker          "build/target/product/security/testkey")
84337974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker    if OPTIONS.verbose:
84437974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker      print "--- source info ---"
84537974731fcb4e32b1de5f213d34bd832ca889869Doug Zongker      common.DumpInfoDict(OPTIONS.source_info_dict)
846c77a9ad444d49e2ad777678cf5671f0a94f44ffbDoug Zongker    WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
847eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
848eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  output_zip.close()
849afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker
850afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker  SignOutput(temp_zip_file.name, args[1])
851afb32eaca0b0f424f7d7fc5f5979d1b8acf042e4Doug Zongker  temp_zip_file.close()
852eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
853eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  common.Cleanup()
854eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
855eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  print "done."
856eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
857eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker
858eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerif __name__ == '__main__':
859eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  try:
8607e6d4e45d92fd51f42812ae63ac6e532887bfe0aYing Wang    common.CloseInheritedPipes()
861eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    main(sys.argv[1:])
862eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker  except common.ExternalError, e:
863eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print
864eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print "   ERROR: %s" % (e,)
865eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    print
866eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker    sys.exit(1)
867