ota_from_target_files revision 283e2a1e1bae4e21824969a15da6420204633ddd
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 27eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker -k (--package_key) <key> 28eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker Key to use to sign the package (default is 29eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker "build/target/product/security/testkey"). 30eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 31eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker -i (--incremental_from) <file> 32eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker Generate an incremental OTA using the given target-files zip as 33eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker the starting build. 34eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 35dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker -w (--wipe_user_data) 36dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker Generate an OTA package that will wipe the user data partition 37dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker when installed. 38dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker 39962069ce59c85949d147874df2728a5ffd9193beDoug Zongker -n (--no_prereq) 40962069ce59c85949d147874df2728a5ffd9193beDoug Zongker Omit the timestamp prereq check normally included at the top of 41962069ce59c85949d147874df2728a5ffd9193beDoug Zongker the build scripts (used for developer OTA packages which 42962069ce59c85949d147874df2728a5ffd9193beDoug Zongker legitimately need to go back and forth). 43962069ce59c85949d147874df2728a5ffd9193beDoug Zongker 441c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker -e (--extra_script) <file> 451c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker Insert the contents of file at the end of the update script. 461c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker 47c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker -m (--script_mode) <mode> 48c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker Specify 'amend' or 'edify' scripts, or 'auto' to pick 49c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker automatically (this is the default). 50c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker 51eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker""" 52eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 53eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport sys 54eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 55eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerif sys.hexversion < 0x02040000: 56eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print >> sys.stderr, "Python 2.4 or newer is required." 57eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker sys.exit(1) 58eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 59eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport copy 60c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongkerimport errno 61eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport os 62eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport re 63eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport sha 64eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport subprocess 65eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport tempfile 66761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongkerimport threading 67eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport time 68eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport zipfile 69eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 70eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport common 71c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongkerimport amend_generator 72c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongkerimport edify_generator 73030614740c1a22e51c6513058852f9ab368fdf5dDoug Zongkerimport both_generator 74eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 75eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS = common.OPTIONS 76eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.package_key = "build/target/product/security/testkey" 77eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.incremental_source = None 78eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.require_verbatim = set() 79eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.prohibit_verbatim = set(("system/build.prop",)) 80eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.patch_threshold = 0.95 81dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug ZongkerOPTIONS.wipe_user_data = False 82962069ce59c85949d147874df2728a5ffd9193beDoug ZongkerOPTIONS.omit_prereq = False 831c390a2aa97127ef8af8b0df1d4028f501fdce64Doug ZongkerOPTIONS.extra_script = None 84c494d7cee85d980647ca915ea64355b71fe817ebDoug ZongkerOPTIONS.script_mode = 'auto' 85761e642d54eec743699c6c2ce1ea587853d08f33Doug ZongkerOPTIONS.worker_threads = 3 86eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 87eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef MostPopularKey(d, default): 88eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """Given a dict, return the key corresponding to the largest 89eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker value. Returns 'default' if the dict is empty.""" 90eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker x = [(v, k) for (k, v) in d.iteritems()] 91eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if not x: return default 92eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker x.sort() 93eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return x[-1][1] 94eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 95eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 96eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef IsSymlink(info): 97eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """Return true if the zipfile.ZipInfo object passed in represents a 98eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker symlink.""" 99eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return (info.external_attr >> 16) == 0120777 100eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 101eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 102eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 103eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerclass Item: 104eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """Items represent the metadata (user, group, mode) of files and 105eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker directories in the system image.""" 106eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker ITEMS = {} 107eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker def __init__(self, name, dir=False): 108eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.name = name 109eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.uid = None 110eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.gid = None 111eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.mode = None 112eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.dir = dir 113eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 114eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if name: 115eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.parent = Item.Get(os.path.dirname(name), dir=True) 116eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.parent.children.append(self) 117eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 118eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.parent = None 119eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if dir: 120eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.children = [] 121eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 122eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker def Dump(self, indent=0): 123eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if self.uid is not None: 124eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode) 125eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 126eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode) 127eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if self.dir: 128eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "%s%s" % (" "*indent, self.descendants) 129eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "%s%s" % (" "*indent, self.best_subtree) 130eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for i in self.children: 131eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker i.Dump(indent=indent+1) 132eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 133eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker @classmethod 134eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker def Get(cls, name, dir=False): 135eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if name not in cls.ITEMS: 136eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker cls.ITEMS[name] = Item(name, dir=dir) 137eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return cls.ITEMS[name] 138eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 139eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker @classmethod 140283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker def GetMetadata(cls, input_zip): 141283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker 142283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker try: 143283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker # See if the target_files contains a record of what the uid, 144283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker # gid, and mode is supposed to be. 145283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker output = input_zip.read("META/filesystem_config.txt") 146283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker except KeyError: 147283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker # Run the external 'fs_config' program to determine the desired 148283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker # uid, gid, and mode for every Item object. Note this uses the 149283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker # one in the client now, which might not be the same as the one 150283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker # used when this target_files was built. 151283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker p = common.Run(["fs_config"], stdin=subprocess.PIPE, 152283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker stdout=subprocess.PIPE, stderr=subprocess.PIPE) 153283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker suffix = { False: "", True: "/" } 154283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker input = "".join(["%s%s\n" % (i.name, suffix[i.dir]) 155283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker for i in cls.ITEMS.itervalues() if i.name]) 156283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker output2, error = p.communicate(input) 157283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker assert not error 158eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 159eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for line in output.split("\n"): 160eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if not line: continue 161eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker name, uid, gid, mode = line.split() 162283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker i = cls.ITEMS.get(name, None) 163283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker if i is not None: 164283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker i.uid = int(uid) 165283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker i.gid = int(gid) 166283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker i.mode = int(mode, 8) 167283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker if i.dir: 168283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker i.children.sort(key=lambda i: i.name) 169283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker 170283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker # set metadata for the files generated by this script. 171283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker i = cls.ITEMS.get("system/recovery-from-boot.p", None) 172283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker if i: i.uid, i.gid, i.mode = 0, 0, 0644 173283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker i = cls.ITEMS.get("system/etc/install-recovery.sh", None) 174283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker if i: i.uid, i.gid, i.mode = 0, 0, 0544 175eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 176eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker def CountChildMetadata(self): 177eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """Count up the (uid, gid, mode) tuples for all children and 178eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker determine the best strategy for using set_perm_recursive and 179eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker set_perm to correctly chown/chmod all the files to their desired 180eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker values. Recursively calls itself for all descendants. 181eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 182eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker Returns a dict of {(uid, gid, dmode, fmode): count} counting up 183eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker all descendants of this node. (dmode or fmode may be None.) Also 184eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker sets the best_subtree of each directory Item to the (uid, gid, 185eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker dmode, fmode) tuple that will match the most descendants of that 186eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker Item. 187eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """ 188eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 189eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker assert self.dir 190eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker d = self.descendants = {(self.uid, self.gid, self.mode, None): 1} 191eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for i in self.children: 192eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if i.dir: 193eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for k, v in i.CountChildMetadata().iteritems(): 194eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker d[k] = d.get(k, 0) + v 195eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 196eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker k = (i.uid, i.gid, None, i.mode) 197eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker d[k] = d.get(k, 0) + 1 198eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 199eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # Find the (uid, gid, dmode, fmode) tuple that matches the most 200eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # descendants. 201eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 202eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # First, find the (uid, gid) pair that matches the most 203eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # descendants. 204eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker ug = {} 205eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for (uid, gid, _, _), count in d.iteritems(): 206eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker ug[(uid, gid)] = ug.get((uid, gid), 0) + count 207eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker ug = MostPopularKey(ug, (0, 0)) 208eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 209eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # Now find the dmode and fmode that match the most descendants 210eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # with that (uid, gid), and choose those. 211eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker best_dmode = (0, 0755) 212eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker best_fmode = (0, 0644) 213eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for k, count in d.iteritems(): 214eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if k[:2] != ug: continue 215eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2]) 216eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3]) 217eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.best_subtree = ug + (best_dmode[1], best_fmode[1]) 218eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 219eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return d 220eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 221c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker def SetPermissions(self, script): 222eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """Append set_perm/set_perm_recursive commands to 'script' to 223eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker set all permissions, users, and groups for the tree of files 224c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker rooted at 'self'.""" 225eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 226eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.CountChildMetadata() 227eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 228eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker def recurse(item, current): 229eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # current is the (uid, gid, dmode, fmode) tuple that the current 230eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # item (and all its children) have already been set to. We only 231eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # need to issue set_perm/set_perm_recursive commands if we're 232eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # supposed to be something different. 233eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if item.dir: 234eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if current != item.best_subtree: 235c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.SetPermissionsRecursive("/"+item.name, *item.best_subtree) 236eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker current = item.best_subtree 237eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 238eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if item.uid != current[0] or item.gid != current[1] or \ 239eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker item.mode != current[2]: 240c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode) 241eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 242eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for i in item.children: 243eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker recurse(i, current) 244eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 245eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if item.uid != current[0] or item.gid != current[1] or \ 246eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker item.mode != current[3]: 247c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode) 248eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 249eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker recurse(self, (-1, -1, -1, -1)) 250eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 251eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 252eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef CopySystemFiles(input_zip, output_zip=None, 253eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker substitute=None): 254eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """Copies files underneath system/ in the input zip to the output 255eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker zip. Populates the Item class with their metadata, and returns a 256eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker list of symlinks. output_zip may be None, in which case the copy is 257eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker skipped (but the other side effects still happen). substitute is an 258eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker optional dict of {output filename: contents} to be output instead of 259eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker certain input files. 260eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """ 261eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 262eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker symlinks = [] 263eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 264eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for info in input_zip.infolist(): 265eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if info.filename.startswith("SYSTEM/"): 266eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker basefilename = info.filename[7:] 267eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if IsSymlink(info): 268eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker symlinks.append((input_zip.read(info.filename), 269c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker "/system/" + basefilename)) 270eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 271eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker info2 = copy.copy(info) 272eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker fn = info2.filename = "system/" + basefilename 273eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if substitute and fn in substitute and substitute[fn] is None: 274eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker continue 275eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if output_zip is not None: 276eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if substitute and fn in substitute: 277eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker data = substitute[fn] 278eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 279eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker data = input_zip.read(info.filename) 280eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker output_zip.writestr(info2, data) 281eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if fn.endswith("/"): 282eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker Item.Get(fn[:-1], dir=True) 283eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 284eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker Item.Get(fn, dir=False) 285eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 286eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker symlinks.sort() 287eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return symlinks 288eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 289eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 290eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef SignOutput(temp_zip_name, output_zip_name): 291eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker key_passwords = common.GetKeyPasswords([OPTIONS.package_key]) 292eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker pw = key_passwords[OPTIONS.package_key] 293eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 294951495fc4802a3603f654c02c7acceda4859f5e1Doug Zongker common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw, 295951495fc4802a3603f654c02c7acceda4859f5e1Doug Zongker whole_file=True) 296eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 297eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 298c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongkerdef AppendAssertions(script, input_zip): 299eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker device = GetBuildProp("ro.product.device", input_zip) 300c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.AssertDevice(device) 301eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 302eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 30373ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongkerdef MakeRecoveryPatch(output_zip, recovery_img, boot_img): 30473ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker """Generate a binary patch that creates the recovery image starting 30573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker with the boot image. (Most of the space in these images is just the 30673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker kernel, which is identical for the two, so the resulting patch 30773ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker should be efficient.) Add it to the output zip, along with a shell 30873ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker script that is run from init.rc on first boot to actually do the 30973ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker patching and install the new recovery image. 31073ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 31173ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker recovery_img and boot_img should be File objects for the 31273ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker corresponding images. 31373ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 31473ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker Returns an Item for the shell script, which must be made 31573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker executable. 31673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker """ 31773ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 318761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker d = Difference(recovery_img, boot_img) 319761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker _, _, patch = d.ComputePatch() 320cfd7db6d8494c7d3169a4eac0dc63737a24ff1d1Doug Zongker common.ZipWriteStr(output_zip, "recovery/recovery-from-boot.p", patch) 32173ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker Item.Get("system/recovery-from-boot.p", dir=False) 32273ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 32373ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # Images with different content will have a different first page, so 32473ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # we check to see if this recovery has already been installed by 32573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # testing just the first 2k. 32673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker HEADER_SIZE = 2048 32773ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker header_sha1 = sha.sha(recovery_img.data[:HEADER_SIZE]).hexdigest() 32873ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker sh = """#!/system/bin/sh 32973ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongkerif ! applypatch -c MTD:recovery:%(header_size)d:%(header_sha1)s; then 33073ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker log -t recovery "Installing new recovery image" 33173ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker applypatch MTD:boot:%(boot_size)d:%(boot_sha1)s MTD:recovery %(recovery_sha1)s %(recovery_size)d %(boot_sha1)s:/system/recovery-from-boot.p 33273ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongkerelse 33373ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker log -t recovery "Recovery image already installed" 33473ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongkerfi 33573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker""" % { 'boot_size': boot_img.size, 33673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 'boot_sha1': boot_img.sha1, 33773ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 'header_size': HEADER_SIZE, 33873ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 'header_sha1': header_sha1, 33973ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 'recovery_size': recovery_img.size, 34073ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 'recovery_sha1': recovery_img.sha1 } 341cfd7db6d8494c7d3169a4eac0dc63737a24ff1d1Doug Zongker common.ZipWriteStr(output_zip, "recovery/etc/install-recovery.sh", sh) 34273ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker return Item.Get("system/etc/install-recovery.sh", dir=False) 34373ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 34473ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 345eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef WriteFullOTAPackage(input_zip, output_zip): 346030614740c1a22e51c6513058852f9ab368fdf5dDoug Zongker if OPTIONS.script_mode == "auto": 347030614740c1a22e51c6513058852f9ab368fdf5dDoug Zongker script = both_generator.BothGenerator(2) 348030614740c1a22e51c6513058852f9ab368fdf5dDoug Zongker elif OPTIONS.script_mode == "amend": 349c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script = amend_generator.AmendGenerator() 350c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker else: 351c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker # TODO: how to determine this? We don't know what version it will 352c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker # be installed on top of. For now, we expect the API just won't 353c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker # change very often. 354030614740c1a22e51c6513058852f9ab368fdf5dDoug Zongker script = edify_generator.EdifyGenerator(2) 355eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 35605d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker device_specific = common.DeviceSpecificParams( 35705d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker input_zip=input_zip, 35814833605d26bf970cd5335c02af4354b68d93348Doug Zongker input_version=GetRecoveryAPIVersion(input_zip), 35905d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker output_zip=output_zip, 36005d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker script=script, 36105d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker input_tmp=OPTIONS.input_tmp) 36205d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker 363962069ce59c85949d147874df2728a5ffd9193beDoug Zongker if not OPTIONS.omit_prereq: 364962069ce59c85949d147874df2728a5ffd9193beDoug Zongker ts = GetBuildProp("ro.build.date.utc", input_zip) 365c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.AssertOlderBuild(ts) 366eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 367eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker AppendAssertions(script, input_zip) 36805d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker device_specific.FullOTA_Assertions() 369171f1cde104891840b0c3c271935fae5433f1b25Doug Zongker 370c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.ShowProgress(0.5, 0) 371eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 372dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker if OPTIONS.wipe_user_data: 373c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.FormatPartition("userdata") 374dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker 375c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.FormatPartition("system") 376c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.Mount("MTD", "system", "/system") 377cfd7db6d8494c7d3169a4eac0dc63737a24ff1d1Doug Zongker script.UnpackPackageDir("recovery", "/system") 378c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.UnpackPackageDir("system", "/system") 379eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 380eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker symlinks = CopySystemFiles(input_zip, output_zip) 381c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.MakeSymlinks(symlinks) 382eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 38373ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker boot_img = File("boot.img", common.BuildBootableImage( 38473ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker os.path.join(OPTIONS.input_tmp, "BOOT"))) 38573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker recovery_img = File("recovery.img", common.BuildBootableImage( 38673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker os.path.join(OPTIONS.input_tmp, "RECOVERY"))) 387283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker MakeRecoveryPatch(output_zip, recovery_img, boot_img) 38873ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 389283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker Item.GetMetadata(input_zip) 39073ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker Item.Get("system").SetPermissions(script) 391eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 39273ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker common.CheckSize(boot_img.data, "boot.img") 39373ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker common.ZipWriteStr(output_zip, "boot.img", boot_img.data) 394c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.ShowProgress(0.2, 0) 395c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker 396c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.ShowProgress(0.2, 10) 39705d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker script.WriteRawImage("boot", "boot.img") 39805d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker 39905d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker script.ShowProgress(0.1, 0) 40005d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker device_specific.FullOTA_InstallEnd() 401eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 4021c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker if OPTIONS.extra_script is not None: 403c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.AppendExtra(OPTIONS.extra_script) 4041c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker 40514833605d26bf970cd5335c02af4354b68d93348Doug Zongker script.UnmountAll() 406c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.AddToZip(input_zip, output_zip) 407eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 408eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 409eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerclass File(object): 410eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker def __init__(self, name, data): 411eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.name = name 412eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.data = data 413eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.size = len(data) 414eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.sha1 = sha.sha(data).hexdigest() 415eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 416eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker def WriteToTemp(self): 417eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker t = tempfile.NamedTemporaryFile() 418eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker t.write(self.data) 419eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker t.flush() 420eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return t 421eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 422eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker def AddToZip(self, z): 423048e7ca15f6391681490ce564bc71194adf146aaDoug Zongker common.ZipWriteStr(z, self.name, self.data) 424eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 425eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 426eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef LoadSystemFiles(z): 427eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """Load all the files from SYSTEM/... in a given target-files 428eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker ZipFile, and return a dict of {filename: File object}.""" 429eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker out = {} 430eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for info in z.infolist(): 431eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if info.filename.startswith("SYSTEM/") and not IsSymlink(info): 432eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker fn = "system/" + info.filename[7:] 433eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker data = z.read(info.filename) 434eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker out[fn] = File(fn, data) 435eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return out 436eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 437eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 438761e642d54eec743699c6c2ce1ea587853d08f33Doug ZongkerDIFF_PROGRAM_BY_EXT = { 439761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker ".gz" : "imgdiff", 440761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker ".zip" : ["imgdiff", "-z"], 441761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker ".jar" : ["imgdiff", "-z"], 442761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker ".apk" : ["imgdiff", "-z"], 443761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker ".img" : "imgdiff", 444761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker } 445eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 446eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 447761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongkerclass Difference(object): 448761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker def __init__(self, tf, sf): 449761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker self.tf = tf 450761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker self.sf = sf 451761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker self.patch = None 452eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 453761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker def ComputePatch(self): 454761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker """Compute the patch (as a string of data) needed to turn sf into 455761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker tf. Returns the same tuple as GetPatch().""" 456761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker 457761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker tf = self.tf 458761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker sf = self.sf 459761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker 460761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker ext = os.path.splitext(tf.name)[1] 461761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker diff_program = DIFF_PROGRAM_BY_EXT.get(ext, "bsdiff") 462761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker 463761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker ttemp = tf.WriteToTemp() 464761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker stemp = sf.WriteToTemp() 465761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker 466761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker ext = os.path.splitext(tf.name)[1] 467761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker 468761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker try: 469761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker ptemp = tempfile.NamedTemporaryFile() 470761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker if isinstance(diff_program, list): 471761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker cmd = copy.copy(diff_program) 472761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker else: 473761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker cmd = [diff_program] 474761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker cmd.append(stemp.name) 475761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker cmd.append(ttemp.name) 476761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker cmd.append(ptemp.name) 477761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker p = common.Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 478761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker _, err = p.communicate() 479761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker if err or p.returncode != 0: 480761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker print "WARNING: failure running %s:\n%s\n" % (diff_program, err) 481761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker return None 482761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker diff = ptemp.read() 483761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker finally: 484761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker ptemp.close() 485761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker stemp.close() 486761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker ttemp.close() 487761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker 488761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker self.patch = diff 489761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker return self.tf, self.sf, self.patch 490761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker 491761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker 492761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker def GetPatch(self): 493761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker """Return a tuple (target_file, source_file, patch_data). 494761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker patch_data may be None if ComputePatch hasn't been called, or if 495761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker computing the patch failed.""" 496761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker return self.tf, self.sf, self.patch 497761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker 498761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker 499761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongkerdef ComputeDifferences(diffs): 500761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker """Call ComputePatch on all the Difference objects in 'diffs'.""" 501761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker print len(diffs), "diffs to compute" 502761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker 503761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker # Do the largest files first, to try and reduce the long-pole effect. 504761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker by_size = [(i.tf.size, i) for i in diffs] 505761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker by_size.sort(reverse=True) 506761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker by_size = [i[1] for i in by_size] 507761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker 508761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker lock = threading.Lock() 509761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker diff_iter = iter(by_size) # accessed under lock 510761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker 511761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker def worker(): 512761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker try: 513761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker lock.acquire() 514761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker for d in diff_iter: 515761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker lock.release() 516761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker start = time.time() 517761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker d.ComputePatch() 518761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker dur = time.time() - start 519761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker lock.acquire() 520761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker 521761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker tf, sf, patch = d.GetPatch() 522761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker if sf.name == tf.name: 523761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker name = tf.name 524761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker else: 525761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker name = "%s (%s)" % (tf.name, sf.name) 526761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker if patch is None: 527761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker print "patching failed! %s" % (name,) 528761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker else: 529761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker print "%8.2f sec %8d / %8d bytes (%6.2f%%) %s" % ( 530761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker dur, len(patch), tf.size, 100.0 * len(patch) / tf.size, name) 531761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker lock.release() 532481c4e650fe6cdb9c63ad04b35d221a2856ca48dDoug Zongker except Exception, e: 533761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker print e 534761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker raise 535761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker 536761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker # start worker threads; wait for them all to finish. 537761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker threads = [threading.Thread(target=worker) 538761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker for i in range(OPTIONS.worker_threads)] 539761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker for th in threads: 540761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker th.start() 541761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker while threads: 542761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker threads.pop().join() 543eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 544eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 545eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef GetBuildProp(property, z): 546eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """Return the fingerprint of the build of a given target-files 547eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker ZipFile object.""" 548eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker bp = z.read("SYSTEM/build.prop") 549eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if not property: 550eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return bp 551eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker m = re.search(re.escape(property) + r"=(.*)\n", bp) 552eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if not m: 5539fc74c7823182c4121f32114a7f83ae3fa7e4346Doug Zongker raise common.ExternalError("couldn't find %s in build.prop" % (property,)) 554eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return m.group(1).strip() 555eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 556eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 557c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongkerdef GetRecoveryAPIVersion(zip): 558c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker """Returns the version of the recovery API. Version 0 is the older 559c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker amend code (no separate binary).""" 560c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker try: 561c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker version = zip.read("META/recovery-api-version.txt") 562c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker return int(version) 563c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker except KeyError: 564c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker try: 565c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker # version one didn't have the recovery-api-version.txt file, but 566c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker # it did include an updater binary. 567c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker zip.getinfo("OTA/bin/updater") 568c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker return 1 569c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker except KeyError: 570c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker return 0 571c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker 57215604b84e246514da6c9721266919003f734380bDoug Zongker 573eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): 574c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker source_version = GetRecoveryAPIVersion(source_zip) 57514833605d26bf970cd5335c02af4354b68d93348Doug Zongker target_version = GetRecoveryAPIVersion(target_zip) 576c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker 577c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker if OPTIONS.script_mode == 'amend': 578c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script = amend_generator.AmendGenerator() 579c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker elif OPTIONS.script_mode == 'edify': 580c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker if source_version == 0: 581c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker print ("WARNING: generating edify script for a source that " 582c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker "can't install it.") 583c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script = edify_generator.EdifyGenerator(source_version) 584c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker elif OPTIONS.script_mode == 'auto': 585c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker if source_version > 0: 586c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script = edify_generator.EdifyGenerator(source_version) 587c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker else: 588c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script = amend_generator.AmendGenerator() 589c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker else: 590c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker raise ValueError('unknown script mode "%s"' % (OPTIONS.script_mode,)) 591eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 59205d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker device_specific = common.DeviceSpecificParams( 59305d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker source_zip=source_zip, 59414833605d26bf970cd5335c02af4354b68d93348Doug Zongker source_version=source_version, 59505d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker target_zip=target_zip, 59614833605d26bf970cd5335c02af4354b68d93348Doug Zongker target_version=target_version, 59705d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker output_zip=output_zip, 59805d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker script=script) 59905d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker 600eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "Loading target..." 601eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker target_data = LoadSystemFiles(target_zip) 602eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "Loading source..." 603eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker source_data = LoadSystemFiles(source_zip) 604eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 605eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker verbatim_targets = [] 606eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker patch_list = [] 607761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker diffs = [] 608eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker largest_source_size = 0 609eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for fn in sorted(target_data.keys()): 610eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker tf = target_data[fn] 611761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker assert fn == tf.name 612eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker sf = source_data.get(fn, None) 613eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 614eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if sf is None or fn in OPTIONS.require_verbatim: 615eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # This file should be included verbatim 616eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if fn in OPTIONS.prohibit_verbatim: 6179fc74c7823182c4121f32114a7f83ae3fa7e4346Doug Zongker raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,)) 618eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "send", fn, "verbatim" 619eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker tf.AddToZip(output_zip) 620eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker verbatim_targets.append((fn, tf.size)) 621eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker elif tf.sha1 != sf.sha1: 622eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # File is different; consider sending as a patch 623761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker diffs.append(Difference(tf, sf)) 624eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 625eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # Target file identical to source. 626eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker pass 627eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 628761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker ComputeDifferences(diffs) 629761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker 630761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker for diff in diffs: 631761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker tf, sf, d = diff.GetPatch() 632761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker if d is None or len(d) > tf.size * OPTIONS.patch_threshold: 633761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker # patch is almost as big as the file; don't bother patching 634761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker tf.AddToZip(output_zip) 635761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker verbatim_targets.append((tf.name, tf.size)) 636761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker else: 637761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker common.ZipWriteStr(output_zip, "patch/" + tf.name + ".p", d) 6385a48209541d5eed602bfb8e2c4ff51e31443daf2Doug Zongker patch_list.append((tf.name, tf, sf, tf.size, sha.sha(d).hexdigest())) 639761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker largest_source_size = max(largest_source_size, sf.size) 640eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 641eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker source_fp = GetBuildProp("ro.build.fingerprint", source_zip) 642eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker target_fp = GetBuildProp("ro.build.fingerprint", target_zip) 643eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 644c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.Mount("MTD", "system", "/system") 645c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.AssertSomeFingerprint(source_fp, target_fp) 646eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 6475da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker source_boot = File("/tmp/boot.img", 6485da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker common.BuildBootableImage( 6495da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker os.path.join(OPTIONS.source_tmp, "BOOT"))) 6505da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker target_boot = File("/tmp/boot.img", 6515da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker common.BuildBootableImage( 6525da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker os.path.join(OPTIONS.target_tmp, "BOOT"))) 6535da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker updating_boot = (source_boot.data != target_boot.data) 654eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 655f6a8bada5f0966762eadaec96de6430d0cd577e3Doug Zongker source_recovery = File("system/recovery.img", 656f6a8bada5f0966762eadaec96de6430d0cd577e3Doug Zongker common.BuildBootableImage( 657f6a8bada5f0966762eadaec96de6430d0cd577e3Doug Zongker os.path.join(OPTIONS.source_tmp, "RECOVERY"))) 658f6a8bada5f0966762eadaec96de6430d0cd577e3Doug Zongker target_recovery = File("system/recovery.img", 659f6a8bada5f0966762eadaec96de6430d0cd577e3Doug Zongker common.BuildBootableImage( 660f6a8bada5f0966762eadaec96de6430d0cd577e3Doug Zongker os.path.join(OPTIONS.target_tmp, "RECOVERY"))) 661f6a8bada5f0966762eadaec96de6430d0cd577e3Doug Zongker updating_recovery = (source_recovery.data != target_recovery.data) 662eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 663881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker # Here's how we divide up the progress bar: 664881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker # 0.1 for verifying the start state (PatchCheck calls) 665881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker # 0.8 for applying patches (ApplyPatch calls) 666881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker # 0.1 for unpacking verbatim files, symlinking, and doing the 667881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker # device-specific commands. 668eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 669eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker AppendAssertions(script, target_zip) 67005d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker device_specific.IncrementalOTA_Assertions() 671eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 672c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.Print("Verifying current system...") 673c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker 674881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker script.ShowProgress(0.1, 0) 675881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker total_verify_size = float(sum([i[2].size for i in patch_list]) + 1) 676881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker if updating_boot: 677881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker total_verify_size += source_boot.size 678881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker so_far = 0 679c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker 6805a48209541d5eed602bfb8e2c4ff51e31443daf2Doug Zongker for fn, tf, sf, size, patch_sha in patch_list: 681c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.PatchCheck("/"+fn, tf.sha1, sf.sha1) 682881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker so_far += sf.size 683881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker script.SetProgress(so_far / total_verify_size) 684eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 6855da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker if updating_boot: 686761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker d = Difference(target_boot, source_boot) 687761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker _, _, d = d.ComputePatch() 6885da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker print "boot target: %d source: %d diff: %d" % ( 6895da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker target_boot.size, source_boot.size, len(d)) 6905da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker 691048e7ca15f6391681490ce564bc71194adf146aaDoug Zongker common.ZipWriteStr(output_zip, "patch/boot.img.p", d) 6925da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker 693c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.PatchCheck("MTD:boot:%d:%s:%d:%s" % 694c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker (source_boot.size, source_boot.sha1, 695c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker target_boot.size, target_boot.sha1)) 696881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker so_far += source_boot.size 697881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker script.SetProgress(so_far / total_verify_size) 6985da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker 6995da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker if patch_list or updating_recovery or updating_boot: 700c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.CacheFreeSpaceCheck(largest_source_size) 7015a48209541d5eed602bfb8e2c4ff51e31443daf2Doug Zongker 70205d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker device_specific.IncrementalOTA_VerifyEnd() 70305d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker 704c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.Comment("---- start making changes here ----") 705eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 706dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker if OPTIONS.wipe_user_data: 707c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.Print("Erasing user data...") 708c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.FormatPartition("userdata") 709dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker 710c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.Print("Removing unneeded files...") 7110f3298a497e32f6c2325a0071124a62d031fae6fDoug Zongker script.DeleteFiles(["/"+i[0] for i in verbatim_targets] + 7120f3298a497e32f6c2325a0071124a62d031fae6fDoug Zongker ["/"+i for i in sorted(source_data) 7133b949f07259ee8d67b4454627aceab5e6f44bd39Doug Zongker if i not in target_data] + 7143b949f07259ee8d67b4454627aceab5e6f44bd39Doug Zongker ["/system/recovery.img"]) 715eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 716881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker script.ShowProgress(0.8, 0) 717881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker total_patch_size = float(sum([i[1].size for i in patch_list]) + 1) 718881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker if updating_boot: 719881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker total_patch_size += target_boot.size 720881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker so_far = 0 721881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker 722881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker script.Print("Patching system files...") 7235a48209541d5eed602bfb8e2c4ff51e31443daf2Doug Zongker for fn, tf, sf, size, _ in patch_list: 724c8d446bcde877ec94f8e68dd5af68fe34eb1b1f9Doug Zongker script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p") 725881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker so_far += tf.size 726881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker script.SetProgress(so_far / total_patch_size) 727881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker 728eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if updating_boot: 7295da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker # Produce the boot image by applying a patch to the current 7305da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker # contents of the boot partition, and write it back to the 7315da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker # partition. 732c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.Print("Patching boot image...") 733c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.ApplyPatch("MTD:boot:%d:%s:%d:%s" 734c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker % (source_boot.size, source_boot.sha1, 735c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker target_boot.size, target_boot.sha1), 736c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker "-", 737c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker target_boot.size, target_boot.sha1, 738c8d446bcde877ec94f8e68dd5af68fe34eb1b1f9Doug Zongker source_boot.sha1, "patch/boot.img.p") 739881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker so_far += target_boot.size 740881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker script.SetProgress(so_far / total_patch_size) 741eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "boot image changed; including." 742eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 743eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "boot image unchanged; skipping." 744eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 745eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if updating_recovery: 74673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # Is it better to generate recovery as a patch from the current 74773ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # boot image, or from the previous recovery image? For large 74873ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # updates with significant kernel changes, probably the former. 74973ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # For small updates where the kernel hasn't changed, almost 75073ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # certainly the latter. We pick the first option. Future 75173ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # complicated schemes may let us effectively use both. 75273ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # 75373ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # A wacky possibility: as long as there is room in the boot 75473ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # partition, include the binaries and image files from recovery in 75573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # the boot image (though not in the ramdisk) so they can be used 75673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # as fodder for constructing the recovery image. 757283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker MakeRecoveryPatch(output_zip, target_recovery, target_boot) 75842265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker script.DeleteFiles(["/system/recovery-from-boot.p", 75942265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker "/system/etc/install-recovery.sh"]) 76073ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker print "recovery image changed; including as patch from boot." 761eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 762eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "recovery image unchanged; skipping." 763eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 764881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker script.ShowProgress(0.1, 10) 765eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 766eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker target_symlinks = CopySystemFiles(target_zip, None) 767eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 768eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks]) 769c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker temp_script = script.MakeTemporary() 770283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker Item.GetMetadata(target_zip) 77173ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker Item.Get("system").SetPermissions(temp_script) 772eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 773eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # Note that this call will mess up the tree of Items, so make sure 774eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # we're done with it. 775eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker source_symlinks = CopySystemFiles(source_zip, None) 776eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks]) 777eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 778eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # Delete all the symlinks in source that aren't in target. This 779eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # needs to happen before verbatim files are unpacked, in case a 780eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # symlink in the source is replaced by a real file in the target. 781eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker to_delete = [] 782eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for dest, link in source_symlinks: 783eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if link not in target_symlinks_d: 784eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker to_delete.append(link) 785c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.DeleteFiles(to_delete) 786eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 787eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if verbatim_targets: 788c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.Print("Unpacking new files...") 789c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.UnpackPackageDir("system", "/system") 790c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker 79142265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker if updating_recovery: 79242265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker script.Print("Unpacking new recovery...") 79342265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker script.UnpackPackageDir("recovery", "/system") 79442265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker 79505d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker script.Print("Symlinks and permissions...") 796eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 797eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # Create all the symlinks that don't already exist, or point to 798eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # somewhere different than what we want. Delete each symlink before 799eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # creating it, since the 'symlink' command won't overwrite. 800eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker to_create = [] 801eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for dest, link in target_symlinks: 802eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if link in source_symlinks_d: 803eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if dest != source_symlinks_d[link]: 804eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker to_create.append((dest, link)) 805eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 806eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker to_create.append((dest, link)) 807c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.DeleteFiles([i[1] for i in to_create]) 808c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.MakeSymlinks(to_create) 809eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 810eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # Now that the symlinks are created, we can set all the 811eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # permissions. 812c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.AppendScript(temp_script) 813eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 814881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker # Do device-specific installation (eg, write radio image). 81505d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker device_specific.IncrementalOTA_InstallEnd() 81605d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker 8171c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker if OPTIONS.extra_script is not None: 818c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker scirpt.AppendExtra(OPTIONS.extra_script) 8191c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker 820c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.AddToZip(target_zip, output_zip) 821eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 822eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 823eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef main(argv): 824eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 825eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker def option_handler(o, a): 826eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if o in ("-b", "--board_config"): 827fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker pass # deprecated 828eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker elif o in ("-k", "--package_key"): 829eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker OPTIONS.package_key = a 830eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker elif o in ("-i", "--incremental_from"): 831eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker OPTIONS.incremental_source = a 832dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker elif o in ("-w", "--wipe_user_data"): 833dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker OPTIONS.wipe_user_data = True 834962069ce59c85949d147874df2728a5ffd9193beDoug Zongker elif o in ("-n", "--no_prereq"): 835962069ce59c85949d147874df2728a5ffd9193beDoug Zongker OPTIONS.omit_prereq = True 8361c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker elif o in ("-e", "--extra_script"): 8371c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker OPTIONS.extra_script = a 838c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker elif o in ("-m", "--script_mode"): 839c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker OPTIONS.script_mode = a 840761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker elif o in ("--worker_threads"): 841761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker OPTIONS.worker_threads = int(a) 842eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 843eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return False 844dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker return True 845eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 846eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker args = common.ParseOptions(argv, __doc__, 847c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker extra_opts="b:k:i:d:wne:m:", 848eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker extra_long_opts=["board_config=", 849eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker "package_key=", 850dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker "incremental_from=", 851962069ce59c85949d147874df2728a5ffd9193beDoug Zongker "wipe_user_data", 8521c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker "no_prereq", 853c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker "extra_script=", 854761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker "script_mode=", 855761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker "worker_threads="], 856eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker extra_option_handler=option_handler) 857eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 858eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if len(args) != 2: 859eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker common.Usage(__doc__) 860eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker sys.exit(1) 861eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 862c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker if OPTIONS.script_mode not in ("amend", "edify", "auto"): 863c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker raise ValueError('unknown script mode "%s"' % (OPTIONS.script_mode,)) 864c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker 8651c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker if OPTIONS.extra_script is not None: 8661c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker OPTIONS.extra_script = open(OPTIONS.extra_script).read() 8671c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker 868eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "unzipping target target-files..." 869eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker OPTIONS.input_tmp = common.UnzipTemp(args[0]) 870fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker 871c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker if OPTIONS.device_specific is None: 872c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker # look for the device-specific tools extension location in the input 873c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker try: 874c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker f = open(os.path.join(OPTIONS.input_tmp, "META", "tool-extensions.txt")) 875c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker ds = f.read().strip() 876c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker f.close() 877c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker if ds: 878c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker ds = os.path.normpath(ds) 879c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker print "using device-specific extensions in", ds 880c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker OPTIONS.device_specific = ds 881c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker except IOError, e: 882c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker if e.errno == errno.ENOENT: 883c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker # nothing specified in the file 884c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker pass 885c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker else: 886c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker raise 887c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker 888fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker common.LoadMaxSizes() 889fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker if not OPTIONS.max_image_size: 890fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker print 891fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker print " WARNING: Failed to load max image sizes; will not enforce" 892fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker print " image size limits." 893fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker print 894fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker 895eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker OPTIONS.target_tmp = OPTIONS.input_tmp 896eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker input_zip = zipfile.ZipFile(args[0], "r") 897eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if OPTIONS.package_key: 898eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker temp_zip_file = tempfile.NamedTemporaryFile() 899eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker output_zip = zipfile.ZipFile(temp_zip_file, "w", 900eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker compression=zipfile.ZIP_DEFLATED) 901eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 902eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker output_zip = zipfile.ZipFile(args[1], "w", 903eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker compression=zipfile.ZIP_DEFLATED) 904eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 905eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if OPTIONS.incremental_source is None: 906eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker WriteFullOTAPackage(input_zip, output_zip) 907eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 908eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "unzipping source target-files..." 909eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker OPTIONS.source_tmp = common.UnzipTemp(OPTIONS.incremental_source) 910eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker source_zip = zipfile.ZipFile(OPTIONS.incremental_source, "r") 911eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker WriteIncrementalOTAPackage(input_zip, source_zip, output_zip) 912eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 913eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker output_zip.close() 914eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if OPTIONS.package_key: 915eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker SignOutput(temp_zip_file.name, args[1]) 916eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker temp_zip_file.close() 917eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 918eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker common.Cleanup() 919eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 920eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "done." 921eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 922eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 923eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerif __name__ == '__main__': 924eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker try: 925eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker main(sys.argv[1:]) 926eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker except common.ExternalError, e: 927eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print 928eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print " ERROR: %s" % (e,) 929eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print 930eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker sys.exit(1) 931