ota_from_target_files revision c77a9ad444d49e2ad777678cf5671f0a94f44ffb
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 47eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker""" 48eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 49eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport sys 50eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 51eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerif sys.hexversion < 0x02040000: 52eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print >> sys.stderr, "Python 2.4 or newer is required." 53eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker sys.exit(1) 54eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 55eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport copy 56c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongkerimport errno 57eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport os 58eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport re 59eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport sha 60eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport subprocess 61eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport tempfile 62eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport time 63eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport zipfile 64eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 65eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerimport common 66c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongkerimport edify_generator 67eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 68eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS = common.OPTIONS 69eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.package_key = "build/target/product/security/testkey" 70eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.incremental_source = None 71eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.require_verbatim = set() 72eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.prohibit_verbatim = set(("system/build.prop",)) 73eef3944eb3673329b5e89cf188ac592805a0b08dDoug ZongkerOPTIONS.patch_threshold = 0.95 74dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug ZongkerOPTIONS.wipe_user_data = False 75962069ce59c85949d147874df2728a5ffd9193beDoug ZongkerOPTIONS.omit_prereq = False 761c390a2aa97127ef8af8b0df1d4028f501fdce64Doug ZongkerOPTIONS.extra_script = None 77761e642d54eec743699c6c2ce1ea587853d08f33Doug ZongkerOPTIONS.worker_threads = 3 78eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 79eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef MostPopularKey(d, default): 80eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """Given a dict, return the key corresponding to the largest 81eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker value. Returns 'default' if the dict is empty.""" 82eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker x = [(v, k) for (k, v) in d.iteritems()] 83eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if not x: return default 84eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker x.sort() 85eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return x[-1][1] 86eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 87eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 88eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef IsSymlink(info): 89eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """Return true if the zipfile.ZipInfo object passed in represents a 90eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker symlink.""" 91eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return (info.external_attr >> 16) == 0120777 92eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 93eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 94eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 95eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerclass Item: 96eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """Items represent the metadata (user, group, mode) of files and 97eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker directories in the system image.""" 98eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker ITEMS = {} 99eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker def __init__(self, name, dir=False): 100eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.name = name 101eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.uid = None 102eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.gid = None 103eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.mode = None 104eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.dir = dir 105eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 106eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if name: 107eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.parent = Item.Get(os.path.dirname(name), dir=True) 108eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.parent.children.append(self) 109eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 110eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.parent = None 111eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if dir: 112eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.children = [] 113eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 114eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker def Dump(self, indent=0): 115eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if self.uid is not None: 116eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode) 117eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 118eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode) 119eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if self.dir: 120eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "%s%s" % (" "*indent, self.descendants) 121eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "%s%s" % (" "*indent, self.best_subtree) 122eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for i in self.children: 123eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker i.Dump(indent=indent+1) 124eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 125eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker @classmethod 126eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker def Get(cls, name, dir=False): 127eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if name not in cls.ITEMS: 128eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker cls.ITEMS[name] = Item(name, dir=dir) 129eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return cls.ITEMS[name] 130eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 131eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker @classmethod 132283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker def GetMetadata(cls, input_zip): 133283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker 134283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker try: 135283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker # See if the target_files contains a record of what the uid, 136283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker # gid, and mode is supposed to be. 137283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker output = input_zip.read("META/filesystem_config.txt") 138283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker except KeyError: 139283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker # Run the external 'fs_config' program to determine the desired 140283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker # uid, gid, and mode for every Item object. Note this uses the 141283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker # one in the client now, which might not be the same as the one 142283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker # used when this target_files was built. 143283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker p = common.Run(["fs_config"], stdin=subprocess.PIPE, 144283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker stdout=subprocess.PIPE, stderr=subprocess.PIPE) 145283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker suffix = { False: "", True: "/" } 146283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker input = "".join(["%s%s\n" % (i.name, suffix[i.dir]) 147283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker for i in cls.ITEMS.itervalues() if i.name]) 1483475d362a771bcbbca23db527c399c0e5a67f576Doug Zongker output, error = p.communicate(input) 149283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker assert not error 150eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 151eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for line in output.split("\n"): 152eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if not line: continue 153eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker name, uid, gid, mode = line.split() 154283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker i = cls.ITEMS.get(name, None) 155283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker if i is not None: 156283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker i.uid = int(uid) 157283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker i.gid = int(gid) 158283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker i.mode = int(mode, 8) 159283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker if i.dir: 160283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker i.children.sort(key=lambda i: i.name) 161283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker 162283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker # set metadata for the files generated by this script. 163283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker i = cls.ITEMS.get("system/recovery-from-boot.p", None) 164283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker if i: i.uid, i.gid, i.mode = 0, 0, 0644 165283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker i = cls.ITEMS.get("system/etc/install-recovery.sh", None) 166283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker if i: i.uid, i.gid, i.mode = 0, 0, 0544 167eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 168eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker def CountChildMetadata(self): 169eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """Count up the (uid, gid, mode) tuples for all children and 170eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker determine the best strategy for using set_perm_recursive and 171eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker set_perm to correctly chown/chmod all the files to their desired 172eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker values. Recursively calls itself for all descendants. 173eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 174eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker Returns a dict of {(uid, gid, dmode, fmode): count} counting up 175eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker all descendants of this node. (dmode or fmode may be None.) Also 176eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker sets the best_subtree of each directory Item to the (uid, gid, 177eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker dmode, fmode) tuple that will match the most descendants of that 178eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker Item. 179eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """ 180eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 181eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker assert self.dir 182eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker d = self.descendants = {(self.uid, self.gid, self.mode, None): 1} 183eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for i in self.children: 184eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if i.dir: 185eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for k, v in i.CountChildMetadata().iteritems(): 186eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker d[k] = d.get(k, 0) + v 187eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 188eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker k = (i.uid, i.gid, None, i.mode) 189eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker d[k] = d.get(k, 0) + 1 190eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 191eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # Find the (uid, gid, dmode, fmode) tuple that matches the most 192eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # descendants. 193eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 194eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # First, find the (uid, gid) pair that matches the most 195eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # descendants. 196eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker ug = {} 197eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for (uid, gid, _, _), count in d.iteritems(): 198eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker ug[(uid, gid)] = ug.get((uid, gid), 0) + count 199eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker ug = MostPopularKey(ug, (0, 0)) 200eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 201eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # Now find the dmode and fmode that match the most descendants 202eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # with that (uid, gid), and choose those. 203eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker best_dmode = (0, 0755) 204eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker best_fmode = (0, 0644) 205eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for k, count in d.iteritems(): 206eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if k[:2] != ug: continue 207eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2]) 208eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3]) 209eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.best_subtree = ug + (best_dmode[1], best_fmode[1]) 210eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 211eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return d 212eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 213c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker def SetPermissions(self, script): 214eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """Append set_perm/set_perm_recursive commands to 'script' to 215eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker set all permissions, users, and groups for the tree of files 216c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker rooted at 'self'.""" 217eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 218eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker self.CountChildMetadata() 219eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 220eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker def recurse(item, current): 221eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # current is the (uid, gid, dmode, fmode) tuple that the current 222eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # item (and all its children) have already been set to. We only 223eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # need to issue set_perm/set_perm_recursive commands if we're 224eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # supposed to be something different. 225eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if item.dir: 226eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if current != item.best_subtree: 227c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.SetPermissionsRecursive("/"+item.name, *item.best_subtree) 228eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker current = item.best_subtree 229eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 230eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if item.uid != current[0] or item.gid != current[1] or \ 231eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker item.mode != current[2]: 232c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode) 233eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 234eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for i in item.children: 235eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker recurse(i, current) 236eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 237eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if item.uid != current[0] or item.gid != current[1] or \ 238eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker item.mode != current[3]: 239c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode) 240eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 241eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker recurse(self, (-1, -1, -1, -1)) 242eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 243eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 244eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef CopySystemFiles(input_zip, output_zip=None, 245eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker substitute=None): 246eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """Copies files underneath system/ in the input zip to the output 247eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker zip. Populates the Item class with their metadata, and returns a 248eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker list of symlinks. output_zip may be None, in which case the copy is 249eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker skipped (but the other side effects still happen). substitute is an 250eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker optional dict of {output filename: contents} to be output instead of 251eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker certain input files. 252eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """ 253eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 254eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker symlinks = [] 255eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 256eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for info in input_zip.infolist(): 257eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if info.filename.startswith("SYSTEM/"): 258eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker basefilename = info.filename[7:] 259eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if IsSymlink(info): 260eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker symlinks.append((input_zip.read(info.filename), 261c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker "/system/" + basefilename)) 262eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 263eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker info2 = copy.copy(info) 264eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker fn = info2.filename = "system/" + basefilename 265eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if substitute and fn in substitute and substitute[fn] is None: 266eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker continue 267eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if output_zip is not None: 268eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if substitute and fn in substitute: 269eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker data = substitute[fn] 270eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 271eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker data = input_zip.read(info.filename) 272eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker output_zip.writestr(info2, data) 273eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if fn.endswith("/"): 274eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker Item.Get(fn[:-1], dir=True) 275eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 276eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker Item.Get(fn, dir=False) 277eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 278eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker symlinks.sort() 279eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return symlinks 280eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 281eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 282eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef SignOutput(temp_zip_name, output_zip_name): 283eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker key_passwords = common.GetKeyPasswords([OPTIONS.package_key]) 284eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker pw = key_passwords[OPTIONS.package_key] 285eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 286951495fc4802a3603f654c02c7acceda4859f5e1Doug Zongker common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw, 287951495fc4802a3603f654c02c7acceda4859f5e1Doug Zongker whole_file=True) 288eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 289eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 290c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongkerdef AppendAssertions(script, input_zip): 291eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker device = GetBuildProp("ro.product.device", input_zip) 292c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.AssertDevice(device) 293eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 294eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 29573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongkerdef MakeRecoveryPatch(output_zip, recovery_img, boot_img): 29673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker """Generate a binary patch that creates the recovery image starting 29773ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker with the boot image. (Most of the space in these images is just the 29873ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker kernel, which is identical for the two, so the resulting patch 29973ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker should be efficient.) Add it to the output zip, along with a shell 30073ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker script that is run from init.rc on first boot to actually do the 30173ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker patching and install the new recovery image. 30273ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 30373ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker recovery_img and boot_img should be File objects for the 30473ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker corresponding images. 30573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 30673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker Returns an Item for the shell script, which must be made 30773ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker executable. 30873ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker """ 30973ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 310ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker d = common.Difference(recovery_img, boot_img) 311761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker _, _, patch = d.ComputePatch() 312cfd7db6d8494c7d3169a4eac0dc63737a24ff1d1Doug Zongker common.ZipWriteStr(output_zip, "recovery/recovery-from-boot.p", patch) 31373ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker Item.Get("system/recovery-from-boot.p", dir=False) 31473ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 31573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # Images with different content will have a different first page, so 31673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # we check to see if this recovery has already been installed by 31773ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # testing just the first 2k. 31873ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker HEADER_SIZE = 2048 31973ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker header_sha1 = sha.sha(recovery_img.data[:HEADER_SIZE]).hexdigest() 32073ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker sh = """#!/system/bin/sh 32173ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongkerif ! applypatch -c MTD:recovery:%(header_size)d:%(header_sha1)s; then 32273ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker log -t recovery "Installing new recovery image" 32373ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug 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 32473ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongkerelse 32573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker log -t recovery "Recovery image already installed" 32673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongkerfi 32773ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker""" % { 'boot_size': boot_img.size, 32873ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 'boot_sha1': boot_img.sha1, 32973ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 'header_size': HEADER_SIZE, 33073ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 'header_sha1': header_sha1, 33173ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 'recovery_size': recovery_img.size, 33273ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 'recovery_sha1': recovery_img.sha1 } 333cfd7db6d8494c7d3169a4eac0dc63737a24ff1d1Doug Zongker common.ZipWriteStr(output_zip, "recovery/etc/install-recovery.sh", sh) 33473ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker return Item.Get("system/etc/install-recovery.sh", dir=False) 33573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 33673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 337c77a9ad444d49e2ad777678cf5671f0a94f44ffbDoug Zongkerdef WriteFullOTAPackage(input_zip, output_zip): 338c637db16d83b2c248b1cf0122e2ba558ed95762cDoug Zongker # TODO: how to determine this? We don't know what version it will 339c637db16d83b2c248b1cf0122e2ba558ed95762cDoug Zongker # be installed on top of. For now, we expect the API just won't 340c637db16d83b2c248b1cf0122e2ba558ed95762cDoug Zongker # change very often. 341c77a9ad444d49e2ad777678cf5671f0a94f44ffbDoug Zongker script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict) 342eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 3432ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker metadata = {"post-build": GetBuildProp("ro.build.fingerprint", input_zip), 3442ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker "pre-device": GetBuildProp("ro.product.device", input_zip), 3453b85269cfe10ec15e9b544dd6964b8c9f5f761f9Doug Zongker "post-timestamp": GetBuildProp("ro.build.date.utc", input_zip), 3462ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker } 3472ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker 34805d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker device_specific = common.DeviceSpecificParams( 34905d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker input_zip=input_zip, 35014833605d26bf970cd5335c02af4354b68d93348Doug Zongker input_version=GetRecoveryAPIVersion(input_zip), 35105d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker output_zip=output_zip, 35205d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker script=script, 3532ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker input_tmp=OPTIONS.input_tmp, 3542ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker metadata=metadata) 35505d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker 356962069ce59c85949d147874df2728a5ffd9193beDoug Zongker if not OPTIONS.omit_prereq: 357962069ce59c85949d147874df2728a5ffd9193beDoug Zongker ts = GetBuildProp("ro.build.date.utc", input_zip) 358c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.AssertOlderBuild(ts) 359eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 360eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker AppendAssertions(script, input_zip) 36105d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker device_specific.FullOTA_Assertions() 362171f1cde104891840b0c3c271935fae5433f1b25Doug Zongker 363c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.ShowProgress(0.5, 0) 364eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 365dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker if OPTIONS.wipe_user_data: 366c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.FormatPartition("userdata") 367dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker 368c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.FormatPartition("system") 369c19a8d5590a4ffd42b37ceaca2d779b48e481f99Doug Zongker script.Mount("system", "/system") 370cfd7db6d8494c7d3169a4eac0dc63737a24ff1d1Doug Zongker script.UnpackPackageDir("recovery", "/system") 371c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.UnpackPackageDir("system", "/system") 372eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 373eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker symlinks = CopySystemFiles(input_zip, output_zip) 374c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.MakeSymlinks(symlinks) 375eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 376ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker boot_img = common.File("boot.img", common.BuildBootableImage( 37773ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker os.path.join(OPTIONS.input_tmp, "BOOT"))) 378ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker recovery_img = common.File("recovery.img", common.BuildBootableImage( 37973ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker os.path.join(OPTIONS.input_tmp, "RECOVERY"))) 380283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker MakeRecoveryPatch(output_zip, recovery_img, boot_img) 38173ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker 382283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker Item.GetMetadata(input_zip) 38373ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker Item.Get("system").SetPermissions(script) 384eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 38573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker common.CheckSize(boot_img.data, "boot.img") 38673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker common.ZipWriteStr(output_zip, "boot.img", boot_img.data) 387c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.ShowProgress(0.2, 0) 388c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker 389c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.ShowProgress(0.2, 10) 39005d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker script.WriteRawImage("boot", "boot.img") 39105d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker 39205d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker script.ShowProgress(0.1, 0) 39305d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker device_specific.FullOTA_InstallEnd() 394eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 3951c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker if OPTIONS.extra_script is not None: 396c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.AppendExtra(OPTIONS.extra_script) 3971c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker 39814833605d26bf970cd5335c02af4354b68d93348Doug Zongker script.UnmountAll() 399c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.AddToZip(input_zip, output_zip) 4002ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker WriteMetadata(metadata, output_zip) 4012ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker 4022ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker 4032ea21065b66da9819df92b37a79f0f87552ee331Doug Zongkerdef WriteMetadata(metadata, output_zip): 4042ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker common.ZipWriteStr(output_zip, "META-INF/com/android/metadata", 4052ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker "".join(["%s=%s\n" % kv 4062ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker for kv in sorted(metadata.iteritems())])) 407eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 408eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 409eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 410eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 411eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef LoadSystemFiles(z): 412eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """Load all the files from SYSTEM/... in a given target-files 413eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker ZipFile, and return a dict of {filename: File object}.""" 414eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker out = {} 415eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for info in z.infolist(): 416eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if info.filename.startswith("SYSTEM/") and not IsSymlink(info): 417eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker fn = "system/" + info.filename[7:] 418eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker data = z.read(info.filename) 419ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker out[fn] = common.File(fn, data) 420eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return out 421eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 422eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 423eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef GetBuildProp(property, z): 424eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker """Return the fingerprint of the build of a given target-files 425eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker ZipFile object.""" 426eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker bp = z.read("SYSTEM/build.prop") 427eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if not property: 428eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return bp 429eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker m = re.search(re.escape(property) + r"=(.*)\n", bp) 430eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if not m: 4319fc74c7823182c4121f32114a7f83ae3fa7e4346Doug Zongker raise common.ExternalError("couldn't find %s in build.prop" % (property,)) 432eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return m.group(1).strip() 433eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 434eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 435c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongkerdef GetRecoveryAPIVersion(zip): 436c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker """Returns the version of the recovery API. Version 0 is the older 437c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker amend code (no separate binary).""" 438c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker try: 439c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker version = zip.read("META/recovery-api-version.txt") 440c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker return int(version) 441c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker except KeyError: 442c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker try: 443c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker # version one didn't have the recovery-api-version.txt file, but 444c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker # it did include an updater binary. 445c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker zip.getinfo("OTA/bin/updater") 446c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker return 1 447c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker except KeyError: 448c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker return 0 449c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker 45015604b84e246514da6c9721266919003f734380bDoug Zongker 451c77a9ad444d49e2ad777678cf5671f0a94f44ffbDoug Zongkerdef WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): 452c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker source_version = GetRecoveryAPIVersion(source_zip) 45314833605d26bf970cd5335c02af4354b68d93348Doug Zongker target_version = GetRecoveryAPIVersion(target_zip) 454c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker 455c637db16d83b2c248b1cf0122e2ba558ed95762cDoug Zongker if source_version == 0: 456c637db16d83b2c248b1cf0122e2ba558ed95762cDoug Zongker print ("WARNING: generating edify script for a source that " 457c637db16d83b2c248b1cf0122e2ba558ed95762cDoug Zongker "can't install it.") 458c77a9ad444d49e2ad777678cf5671f0a94f44ffbDoug Zongker script = edify_generator.EdifyGenerator(source_version, OPTIONS.info_dict) 459eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 4602ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker metadata = {"pre-device": GetBuildProp("ro.product.device", source_zip), 4613b85269cfe10ec15e9b544dd6964b8c9f5f761f9Doug Zongker "post-timestamp": GetBuildProp("ro.build.date.utc", target_zip), 4622ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker } 4632ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker 46405d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker device_specific = common.DeviceSpecificParams( 46505d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker source_zip=source_zip, 46614833605d26bf970cd5335c02af4354b68d93348Doug Zongker source_version=source_version, 46705d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker target_zip=target_zip, 46814833605d26bf970cd5335c02af4354b68d93348Doug Zongker target_version=target_version, 46905d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker output_zip=output_zip, 4702ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker script=script, 4712ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker metadata=metadata) 47205d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker 473eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "Loading target..." 474eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker target_data = LoadSystemFiles(target_zip) 475eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "Loading source..." 476eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker source_data = LoadSystemFiles(source_zip) 477eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 478eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker verbatim_targets = [] 479eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker patch_list = [] 480761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker diffs = [] 481eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker largest_source_size = 0 482eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for fn in sorted(target_data.keys()): 483eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker tf = target_data[fn] 484761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker assert fn == tf.name 485eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker sf = source_data.get(fn, None) 486eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 487eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if sf is None or fn in OPTIONS.require_verbatim: 488eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # This file should be included verbatim 489eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if fn in OPTIONS.prohibit_verbatim: 4909fc74c7823182c4121f32114a7f83ae3fa7e4346Doug Zongker raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,)) 491eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "send", fn, "verbatim" 492eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker tf.AddToZip(output_zip) 493eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker verbatim_targets.append((fn, tf.size)) 494eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker elif tf.sha1 != sf.sha1: 495eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # File is different; consider sending as a patch 496ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker diffs.append(common.Difference(tf, sf)) 497eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 498eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # Target file identical to source. 499eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker pass 500eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 501ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker common.ComputeDifferences(diffs) 502761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker 503761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker for diff in diffs: 504761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker tf, sf, d = diff.GetPatch() 505761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker if d is None or len(d) > tf.size * OPTIONS.patch_threshold: 506761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker # patch is almost as big as the file; don't bother patching 507761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker tf.AddToZip(output_zip) 508761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker verbatim_targets.append((tf.name, tf.size)) 509761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker else: 510761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker common.ZipWriteStr(output_zip, "patch/" + tf.name + ".p", d) 5115a48209541d5eed602bfb8e2c4ff51e31443daf2Doug Zongker patch_list.append((tf.name, tf, sf, tf.size, sha.sha(d).hexdigest())) 512761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker largest_source_size = max(largest_source_size, sf.size) 513eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 514eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker source_fp = GetBuildProp("ro.build.fingerprint", source_zip) 515eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker target_fp = GetBuildProp("ro.build.fingerprint", target_zip) 5162ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker metadata["pre-build"] = source_fp 5172ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker metadata["post-build"] = target_fp 518eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 519c19a8d5590a4ffd42b37ceaca2d779b48e481f99Doug Zongker script.Mount("system", "/system") 520c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.AssertSomeFingerprint(source_fp, target_fp) 521eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 522ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker source_boot = common.File("/tmp/boot.img", 523ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker common.BuildBootableImage( 524ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker os.path.join(OPTIONS.source_tmp, "BOOT"))) 525ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker target_boot = common.File("/tmp/boot.img", 526ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker common.BuildBootableImage( 527ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker os.path.join(OPTIONS.target_tmp, "BOOT"))) 5285da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker updating_boot = (source_boot.data != target_boot.data) 529eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 530ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker source_recovery = common.File("system/recovery.img", 531ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker common.BuildBootableImage( 532ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker os.path.join(OPTIONS.source_tmp, "RECOVERY"))) 533ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker target_recovery = common.File("system/recovery.img", 534ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker common.BuildBootableImage( 535ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker os.path.join(OPTIONS.target_tmp, "RECOVERY"))) 536f6a8bada5f0966762eadaec96de6430d0cd577e3Doug Zongker updating_recovery = (source_recovery.data != target_recovery.data) 537eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 538881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker # Here's how we divide up the progress bar: 539881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker # 0.1 for verifying the start state (PatchCheck calls) 540881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker # 0.8 for applying patches (ApplyPatch calls) 541881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker # 0.1 for unpacking verbatim files, symlinking, and doing the 542881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker # device-specific commands. 543eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 544eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker AppendAssertions(script, target_zip) 54505d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker device_specific.IncrementalOTA_Assertions() 546eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 547c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.Print("Verifying current system...") 548c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker 549881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker script.ShowProgress(0.1, 0) 550881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker total_verify_size = float(sum([i[2].size for i in patch_list]) + 1) 551881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker if updating_boot: 552881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker total_verify_size += source_boot.size 553881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker so_far = 0 554c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker 5555a48209541d5eed602bfb8e2c4ff51e31443daf2Doug Zongker for fn, tf, sf, size, patch_sha in patch_list: 556c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.PatchCheck("/"+fn, tf.sha1, sf.sha1) 557881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker so_far += sf.size 558881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker script.SetProgress(so_far / total_verify_size) 559eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 5605da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker if updating_boot: 561ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6Doug Zongker d = common.Difference(target_boot, source_boot) 562761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker _, _, d = d.ComputePatch() 5635da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker print "boot target: %d source: %d diff: %d" % ( 5645da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker target_boot.size, source_boot.size, len(d)) 5655da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker 566048e7ca15f6391681490ce564bc71194adf146aaDoug Zongker common.ZipWriteStr(output_zip, "patch/boot.img.p", d) 5675da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker 568c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.PatchCheck("MTD:boot:%d:%s:%d:%s" % 569c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker (source_boot.size, source_boot.sha1, 570c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker target_boot.size, target_boot.sha1)) 571881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker so_far += source_boot.size 572881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker script.SetProgress(so_far / total_verify_size) 5735da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker 5745da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker if patch_list or updating_recovery or updating_boot: 575c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.CacheFreeSpaceCheck(largest_source_size) 5765a48209541d5eed602bfb8e2c4ff51e31443daf2Doug Zongker 57705d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker device_specific.IncrementalOTA_VerifyEnd() 57805d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker 579c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.Comment("---- start making changes here ----") 580eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 581dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker if OPTIONS.wipe_user_data: 582c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.Print("Erasing user data...") 583c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.FormatPartition("userdata") 584dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker 585c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.Print("Removing unneeded files...") 5860f3298a497e32f6c2325a0071124a62d031fae6fDoug Zongker script.DeleteFiles(["/"+i[0] for i in verbatim_targets] + 5870f3298a497e32f6c2325a0071124a62d031fae6fDoug Zongker ["/"+i for i in sorted(source_data) 5883b949f07259ee8d67b4454627aceab5e6f44bd39Doug Zongker if i not in target_data] + 5893b949f07259ee8d67b4454627aceab5e6f44bd39Doug Zongker ["/system/recovery.img"]) 590eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 591881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker script.ShowProgress(0.8, 0) 592881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker total_patch_size = float(sum([i[1].size for i in patch_list]) + 1) 593881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker if updating_boot: 594881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker total_patch_size += target_boot.size 595881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker so_far = 0 596881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker 597881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker script.Print("Patching system files...") 5985a48209541d5eed602bfb8e2c4ff51e31443daf2Doug Zongker for fn, tf, sf, size, _ in patch_list: 599c8d446bcde877ec94f8e68dd5af68fe34eb1b1f9Doug Zongker script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p") 600881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker so_far += tf.size 601881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker script.SetProgress(so_far / total_patch_size) 602881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker 603eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if updating_boot: 6045da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker # Produce the boot image by applying a patch to the current 6055da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker # contents of the boot partition, and write it back to the 6065da317e51d1832cb1ec67dd20fbcff7708bbadb5Doug Zongker # partition. 607c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.Print("Patching boot image...") 608c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.ApplyPatch("MTD:boot:%d:%s:%d:%s" 609c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker % (source_boot.size, source_boot.sha1, 610c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker target_boot.size, target_boot.sha1), 611c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker "-", 612c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker target_boot.size, target_boot.sha1, 613c8d446bcde877ec94f8e68dd5af68fe34eb1b1f9Doug Zongker source_boot.sha1, "patch/boot.img.p") 614881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker so_far += target_boot.size 615881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker script.SetProgress(so_far / total_patch_size) 616eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "boot image changed; including." 617eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 618eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "boot image unchanged; skipping." 619eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 620eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if updating_recovery: 62173ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # Is it better to generate recovery as a patch from the current 62273ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # boot image, or from the previous recovery image? For large 62373ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # updates with significant kernel changes, probably the former. 62473ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # For small updates where the kernel hasn't changed, almost 62573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # certainly the latter. We pick the first option. Future 62673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # complicated schemes may let us effectively use both. 62773ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # 62873ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # A wacky possibility: as long as there is room in the boot 62973ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # partition, include the binaries and image files from recovery in 63073ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # the boot image (though not in the ramdisk) so they can be used 63173ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker # as fodder for constructing the recovery image. 632283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker MakeRecoveryPatch(output_zip, target_recovery, target_boot) 63342265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker script.DeleteFiles(["/system/recovery-from-boot.p", 63442265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker "/system/etc/install-recovery.sh"]) 63573ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker print "recovery image changed; including as patch from boot." 636eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 637eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "recovery image unchanged; skipping." 638eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 639881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker script.ShowProgress(0.1, 10) 640eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 641eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker target_symlinks = CopySystemFiles(target_zip, None) 642eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 643eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks]) 644c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker temp_script = script.MakeTemporary() 645283e2a1e1bae4e21824969a15da6420204633dddDoug Zongker Item.GetMetadata(target_zip) 64673ef8257ce54ce1ddc2d4cfc3b3814ca734c0e11Doug Zongker Item.Get("system").SetPermissions(temp_script) 647eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 648eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # Note that this call will mess up the tree of Items, so make sure 649eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # we're done with it. 650eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker source_symlinks = CopySystemFiles(source_zip, None) 651eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks]) 652eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 653eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # Delete all the symlinks in source that aren't in target. This 654eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # needs to happen before verbatim files are unpacked, in case a 655eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # symlink in the source is replaced by a real file in the target. 656eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker to_delete = [] 657eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for dest, link in source_symlinks: 658eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if link not in target_symlinks_d: 659eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker to_delete.append(link) 660c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.DeleteFiles(to_delete) 661eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 662eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if verbatim_targets: 663c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.Print("Unpacking new files...") 664c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.UnpackPackageDir("system", "/system") 665c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker 66642265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker if updating_recovery: 66742265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker script.Print("Unpacking new recovery...") 66842265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker script.UnpackPackageDir("recovery", "/system") 66942265390d993664e7797abc12d7e6bd1c2a6dc6bDoug Zongker 67005d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker script.Print("Symlinks and permissions...") 671eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 672eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # Create all the symlinks that don't already exist, or point to 673eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # somewhere different than what we want. Delete each symlink before 674eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # creating it, since the 'symlink' command won't overwrite. 675eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker to_create = [] 676eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker for dest, link in target_symlinks: 677eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if link in source_symlinks_d: 678eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if dest != source_symlinks_d[link]: 679eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker to_create.append((dest, link)) 680eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 681eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker to_create.append((dest, link)) 682c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.DeleteFiles([i[1] for i in to_create]) 683c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.MakeSymlinks(to_create) 684eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 685eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # Now that the symlinks are created, we can set all the 686eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker # permissions. 687c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.AppendScript(temp_script) 688eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 689881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker # Do device-specific installation (eg, write radio image). 69005d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker device_specific.IncrementalOTA_InstallEnd() 69105d3dea519688b61d86e30c2d4b99ff494aeca73Doug Zongker 6921c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker if OPTIONS.extra_script is not None: 693c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker scirpt.AppendExtra(OPTIONS.extra_script) 6941c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker 695c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker script.AddToZip(target_zip, output_zip) 6962ea21065b66da9819df92b37a79f0f87552ee331Doug Zongker WriteMetadata(metadata, output_zip) 697eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 698eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 699eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerdef main(argv): 700eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 701eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker def option_handler(o, a): 702eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if o in ("-b", "--board_config"): 703fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker pass # deprecated 704eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker elif o in ("-k", "--package_key"): 705eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker OPTIONS.package_key = a 706eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker elif o in ("-i", "--incremental_from"): 707eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker OPTIONS.incremental_source = a 708dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker elif o in ("-w", "--wipe_user_data"): 709dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker OPTIONS.wipe_user_data = True 710962069ce59c85949d147874df2728a5ffd9193beDoug Zongker elif o in ("-n", "--no_prereq"): 711962069ce59c85949d147874df2728a5ffd9193beDoug Zongker OPTIONS.omit_prereq = True 7121c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker elif o in ("-e", "--extra_script"): 7131c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker OPTIONS.extra_script = a 714761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker elif o in ("--worker_threads"): 715761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker OPTIONS.worker_threads = int(a) 716eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 717eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker return False 718dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker return True 719eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 720eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker args = common.ParseOptions(argv, __doc__, 721c637db16d83b2c248b1cf0122e2ba558ed95762cDoug Zongker extra_opts="b:k:i:d:wne:", 722eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker extra_long_opts=["board_config=", 723eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker "package_key=", 724dbfaae5567dbbfcc17e15b31e65178ad367e6d13Doug Zongker "incremental_from=", 725962069ce59c85949d147874df2728a5ffd9193beDoug Zongker "wipe_user_data", 7261c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker "no_prereq", 727c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker "extra_script=", 728761e642d54eec743699c6c2ce1ea587853d08f33Doug Zongker "worker_threads="], 729eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker extra_option_handler=option_handler) 730eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 731eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if len(args) != 2: 732eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker common.Usage(__doc__) 733eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker sys.exit(1) 734eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 7351c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker if OPTIONS.extra_script is not None: 7361c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker OPTIONS.extra_script = open(OPTIONS.extra_script).read() 7371c390a2aa97127ef8af8b0df1d4028f501fdce64Doug Zongker 738eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "unzipping target target-files..." 739eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker OPTIONS.input_tmp = common.UnzipTemp(args[0]) 740fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker 741c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker if OPTIONS.device_specific is None: 742c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker # look for the device-specific tools extension location in the input 743c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker try: 744c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker f = open(os.path.join(OPTIONS.input_tmp, "META", "tool-extensions.txt")) 745c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker ds = f.read().strip() 746c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker f.close() 747c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker if ds: 748c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker ds = os.path.normpath(ds) 749c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker print "using device-specific extensions in", ds 750c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker OPTIONS.device_specific = ds 751c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker except IOError, e: 752c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker if e.errno == errno.ENOENT: 753c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker # nothing specified in the file 754c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker pass 755c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker else: 756c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker raise 757c18736b1a777c386dc3c5e3f878249770b5edd78Doug Zongker 758c77a9ad444d49e2ad777678cf5671f0a94f44ffbDoug Zongker OPTIONS.info_dict = common.LoadInfoDict() 759c77a9ad444d49e2ad777678cf5671f0a94f44ffbDoug Zongker common.LoadMaxSizes(OPTIONS.info_dict) 760fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker if not OPTIONS.max_image_size: 761fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker print 762fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker print " WARNING: Failed to load max image sizes; will not enforce" 763fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker print " image size limits." 764fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker print 765fdd8e69c42e66fb70384bcaca1747f504f2c021cDoug Zongker 766eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker OPTIONS.target_tmp = OPTIONS.input_tmp 767eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker input_zip = zipfile.ZipFile(args[0], "r") 768eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if OPTIONS.package_key: 769eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker temp_zip_file = tempfile.NamedTemporaryFile() 770eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker output_zip = zipfile.ZipFile(temp_zip_file, "w", 771eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker compression=zipfile.ZIP_DEFLATED) 772eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 773eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker output_zip = zipfile.ZipFile(args[1], "w", 774eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker compression=zipfile.ZIP_DEFLATED) 775eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 776eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if OPTIONS.incremental_source is None: 777c77a9ad444d49e2ad777678cf5671f0a94f44ffbDoug Zongker WriteFullOTAPackage(input_zip, output_zip) 778eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker else: 779eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "unzipping source target-files..." 780eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker OPTIONS.source_tmp = common.UnzipTemp(OPTIONS.incremental_source) 781eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker source_zip = zipfile.ZipFile(OPTIONS.incremental_source, "r") 782c77a9ad444d49e2ad777678cf5671f0a94f44ffbDoug Zongker WriteIncrementalOTAPackage(input_zip, source_zip, output_zip) 783eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 784eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker output_zip.close() 785eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker if OPTIONS.package_key: 786eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker SignOutput(temp_zip_file.name, args[1]) 787eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker temp_zip_file.close() 788eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 789eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker common.Cleanup() 790eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 791eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print "done." 792eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 793eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker 794eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongkerif __name__ == '__main__': 795eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker try: 796eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker main(sys.argv[1:]) 797eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker except common.ExternalError, e: 798eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print 799eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print " ERROR: %s" % (e,) 800eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker print 801eef3944eb3673329b5e89cf188ac592805a0b08dDoug Zongker sys.exit(1) 802