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