ota_from_target_files.py revision 951495fc4802a3603f654c02c7acceda4859f5e1
1c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu#!/usr/bin/env python 2c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu# 3c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu# Copyright (C) 2008 The Android Open Source Project 4c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu# 5c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu# Licensed under the Apache License, Version 2.0 (the "License"); 6c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu# you may not use this file except in compliance with the License. 7c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu# You may obtain a copy of the License at 8c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu# 9c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu# http://www.apache.org/licenses/LICENSE-2.0 10c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu# 11c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu# Unless required by applicable law or agreed to in writing, software 12c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu# distributed under the License is distributed on an "AS IS" BASIS, 13c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu# See the License for the specific language governing permissions and 15c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu# limitations under the License. 1640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 1740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu""" 1840daa01c4c8d772889d9c4167dee312869152174Prathmesh PrabhuGiven a target-files zipfile, produces an OTA package that installs 1940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhuthat build. An incremental OTA is produced if -i is given, otherwise 2022f1fbc11b69ee41af8370ec38f1b90577db6c3cBen Chana full OTA is produced. 2122f1fbc11b69ee41af8370ec38f1b90577db6c3cBen Chan 2240daa01c4c8d772889d9c4167dee312869152174Prathmesh PrabhuUsage: ota_from_target_files [flags] input_target_files output_ota_package 2340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 2440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu -b (--board_config) <file> 2540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu Deprecated. 2640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 27ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu -k (--package_key) <key> 283e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu Key to use to sign the package (default is 2940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu "build/target/product/security/testkey"). 3040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 3140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu -i (--incremental_from) <file> 3240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu Generate an incremental OTA using the given target-files zip as 3340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu the starting build. 34a41ab517725d036b63420f8445550246f8f50b99Alex Vakulenko 3540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu -w (--wipe_user_data) 363e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu Generate an OTA package that will wipe the user data partition 37ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu when installed. 3840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 398d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu -n (--no_prereq) 40a92b0a0438803ebb3432d7b42672fbb7fb6bccf4Peter Qiu Omit the timestamp prereq check normally included at the top of 4140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu the build scripts (used for developer OTA packages which 4240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu legitimately need to go back and forth). 4340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 44ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu -e (--extra_script) <file> 4540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu Insert the contents of file at the end of the update script. 4640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 4740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu -m (--script_mode) <mode> 48ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu Specify 'amend' or 'edify' scripts, or 'auto' to pick 4940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu automatically (this is the default). 5040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 5140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu""" 5240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 5340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhuimport sys 5440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 5540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhuif sys.hexversion < 0x02040000: 56ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu print >> sys.stderr, "Python 2.4 or newer is required." 5740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu sys.exit(1) 5840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 5940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhuimport copy 6040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhuimport os 6140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhuimport re 6240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhuimport sha 6340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhuimport subprocess 6440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhuimport tempfile 6540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhuimport time 6640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhuimport zipfile 6740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 6840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhuimport common 6940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhuimport amend_generator 7040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhuimport edify_generator 7140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhuimport both_generator 7240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 738a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex VakulenkoOPTIONS = common.OPTIONS 748a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex VakulenkoOPTIONS.package_key = "build/target/product/security/testkey" 758a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex VakulenkoOPTIONS.incremental_source = None 7640daa01c4c8d772889d9c4167dee312869152174Prathmesh PrabhuOPTIONS.require_verbatim = set() 7740daa01c4c8d772889d9c4167dee312869152174Prathmesh PrabhuOPTIONS.prohibit_verbatim = set(("system/build.prop",)) 7840daa01c4c8d772889d9c4167dee312869152174Prathmesh PrabhuOPTIONS.patch_threshold = 0.95 7940daa01c4c8d772889d9c4167dee312869152174Prathmesh PrabhuOPTIONS.wipe_user_data = False 8040daa01c4c8d772889d9c4167dee312869152174Prathmesh PrabhuOPTIONS.omit_prereq = False 8140daa01c4c8d772889d9c4167dee312869152174Prathmesh PrabhuOPTIONS.extra_script = None 8240daa01c4c8d772889d9c4167dee312869152174Prathmesh PrabhuOPTIONS.script_mode = 'auto' 8340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 8440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhudef MostPopularKey(d, default): 85cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan """Given a dict, return the key corresponding to the largest 863e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu value. Returns 'default' if the dict is empty.""" 87cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan x = [(v, k) for (k, v) in d.iteritems()] 8840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if not x: return default 8940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu x.sort() 903b30ca58d13cf66b75ba0729b222ddc42ae68b33Paul Stewart return x[-1][1] 9140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 9240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 9340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhudef IsSymlink(info): 9440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu """Return true if the zipfile.ZipInfo object passed in represents a 9540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu symlink.""" 9640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu return (info.external_attr >> 16) == 0120777 9740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 9840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 9940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 10040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhuclass Item: 10140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu """Items represent the metadata (user, group, mode) of files and 1023b30ca58d13cf66b75ba0729b222ddc42ae68b33Paul Stewart directories in the system image.""" 1033b30ca58d13cf66b75ba0729b222ddc42ae68b33Paul Stewart ITEMS = {} 10440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu def __init__(self, name, dir=False): 10540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu self.name = name 10640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu self.uid = None 10740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu self.gid = None 10840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu self.mode = None 10940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu self.dir = dir 11040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 11140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if name: 11240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu self.parent = Item.Get(os.path.dirname(name), dir=True) 11340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu self.parent.children.append(self) 11440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu else: 11540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu self.parent = None 11640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if dir: 11740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu self.children = [] 11840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 1193e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu def Dump(self, indent=0): 1203e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu if self.uid is not None: 1213e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode) 1223e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu else: 1233e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode) 1243e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu if self.dir: 1253b30ca58d13cf66b75ba0729b222ddc42ae68b33Paul Stewart print "%s%s" % (" "*indent, self.descendants) 1263e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu print "%s%s" % (" "*indent, self.best_subtree) 1273e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu for i in self.children: 1283e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu i.Dump(indent=indent+1) 1293e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 13040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu @classmethod 13140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu def Get(cls, name, dir=False): 13240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if name not in cls.ITEMS: 13340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu cls.ITEMS[name] = Item(name, dir=dir) 1343e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu return cls.ITEMS[name] 1353e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 136ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu @classmethod 137ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu def GetMetadata(cls): 13840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu """Run the external 'fs_config' program to determine the desired 13940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu uid, gid, and mode for every Item object.""" 14040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu p = common.Run(["fs_config"], stdin=subprocess.PIPE, 14140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu stdout=subprocess.PIPE, stderr=subprocess.PIPE) 142ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu suffix = { False: "", True: "/" } 14340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu input = "".join(["%s%s\n" % (i.name, suffix[i.dir]) 14440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu for i in cls.ITEMS.itervalues() if i.name]) 145ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu output, error = p.communicate(input) 14640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu assert not error 14740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 14840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu for line in output.split("\n"): 14940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if not line: continue 15040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu name, uid, gid, mode = line.split() 15140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu i = cls.ITEMS[name] 15240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu i.uid = int(uid) 1533e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu i.gid = int(gid) 15440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu i.mode = int(mode, 8) 15540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if i.dir: 15640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu i.children.sort(key=lambda i: i.name) 157ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu 15840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu def CountChildMetadata(self): 15940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu """Count up the (uid, gid, mode) tuples for all children and 16040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu determine the best strategy for using set_perm_recursive and 1613b30ca58d13cf66b75ba0729b222ddc42ae68b33Paul Stewart set_perm to correctly chown/chmod all the files to their desired 16240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu values. Recursively calls itself for all descendants. 16340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 1643b30ca58d13cf66b75ba0729b222ddc42ae68b33Paul Stewart Returns a dict of {(uid, gid, dmode, fmode): count} counting up 1653e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu all descendants of this node. (dmode or fmode may be None.) Also 1663e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu sets the best_subtree of each directory Item to the (uid, gid, 1673b30ca58d13cf66b75ba0729b222ddc42ae68b33Paul Stewart dmode, fmode) tuple that will match the most descendants of that 1683e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu Item. 1693e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu """ 1703e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 1713e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu assert self.dir 1723e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu d = self.descendants = {(self.uid, self.gid, self.mode, None): 1} 173ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu for i in self.children: 174ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu if i.dir: 175ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu for k, v in i.CountChildMetadata().iteritems(): 176ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu d[k] = d.get(k, 0) + v 177ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu else: 178ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu k = (i.uid, i.gid, None, i.mode) 179ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu d[k] = d.get(k, 0) + 1 180ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 181ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # Find the (uid, gid, dmode, fmode) tuple that matches the most 182ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # descendants. 183ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 184ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # First, find the (uid, gid) pair that matches the most 18581404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu # descendants. 18681404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu ug = {} 18781404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu for (uid, gid, _, _), count in d.iteritems(): 18840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu ug[(uid, gid)] = ug.get((uid, gid), 0) + count 18940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu ug = MostPopularKey(ug, (0, 0)) 19040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 19140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # Now find the dmode and fmode that match the most descendants 19240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # with that (uid, gid), and choose those. 19340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu best_dmode = (0, 0755) 1943b30ca58d13cf66b75ba0729b222ddc42ae68b33Paul Stewart best_fmode = (0, 0644) 19540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu for k, count in d.iteritems(): 19640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if k[:2] != ug: continue 19740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2]) 19840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3]) 19940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu self.best_subtree = ug + (best_dmode[1], best_fmode[1]) 20040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 20140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu return d 20240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 20340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu def SetPermissions(self, script): 20440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu """Append set_perm/set_perm_recursive commands to 'script' to 20540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu set all permissions, users, and groups for the tree of files 20640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu rooted at 'self'.""" 20740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 20840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu self.CountChildMetadata() 20940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 21040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu def recurse(item, current): 21140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # current is the (uid, gid, dmode, fmode) tuple that the current 21240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # item (and all its children) have already been set to. We only 21340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # need to issue set_perm/set_perm_recursive commands if we're 21440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # supposed to be something different. 21540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if item.dir: 21640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if current != item.best_subtree: 21740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu script.SetPermissionsRecursive("/"+item.name, *item.best_subtree) 21840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu current = item.best_subtree 21940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 22040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if item.uid != current[0] or item.gid != current[1] or \ 22140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu item.mode != current[2]: 22240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode) 22340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 22440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu for i in item.children: 22540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu recurse(i, current) 22640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu else: 227ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu if item.uid != current[0] or item.gid != current[1] or \ 2287fab89734d88724a288e96a9996b15548c5294c7Ben Chan item.mode != current[3]: 22940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode) 23040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 23140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu recurse(self, (-1, -1, -1, -1)) 23240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 23340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 23440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhudef CopySystemFiles(input_zip, output_zip=None, 23540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu substitute=None): 23640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu """Copies files underneath system/ in the input zip to the output 237ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu zip. Populates the Item class with their metadata, and returns a 23840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu list of symlinks. output_zip may be None, in which case the copy is 23940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu skipped (but the other side effects still happen). substitute is an 240ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu optional dict of {output filename: contents} to be output instead of 24140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu certain input files. 24240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu """ 24340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 24440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu symlinks = [] 24540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 246cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan for info in input_zip.infolist(): 24740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if info.filename.startswith("SYSTEM/"): 248cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan basefilename = info.filename[7:] 24940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if IsSymlink(info): 25040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu symlinks.append((input_zip.read(info.filename), 251cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan "/system/" + basefilename)) 25240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu else: 25340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu info2 = copy.copy(info) 254ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu fn = info2.filename = "system/" + basefilename 25540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if substitute and fn in substitute and substitute[fn] is None: 25640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu continue 25740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if output_zip is not None: 25840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if substitute and fn in substitute: 25940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu data = substitute[fn] 26040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu else: 26140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu data = input_zip.read(info.filename) 26240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu output_zip.writestr(info2, data) 26340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if fn.endswith("/"): 26440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu Item.Get(fn[:-1], dir=True) 26540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu else: 26640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu Item.Get(fn, dir=False) 26740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 26840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu symlinks.sort() 26940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu return symlinks 27040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 27140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 272ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhudef SignOutput(temp_zip_name, output_zip_name): 273ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu key_passwords = common.GetKeyPasswords([OPTIONS.package_key]) 274ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu pw = key_passwords[OPTIONS.package_key] 27540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 27640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw, 27740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu whole_file=True) 27840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 27940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 28040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhudef AppendAssertions(script, input_zip): 28140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu device = GetBuildProp("ro.product.device", input_zip) 28240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu script.AssertDevice(device) 28340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 28440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu info = input_zip.read("OTA/android-info.txt") 28540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu m = re.search(r"require\s+version-bootloader\s*=\s*(\S+)", info) 28640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if m: 28740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu bootloaders = m.group(1).split("|") 28840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if "*" not in bootloaders: 28940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu script.AssertSomeBootloader(*bootloaders) 29040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 29140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 292ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhudef MakeRecoveryPatch(output_zip, recovery_img, boot_img): 293ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu """Generate a binary patch that creates the recovery image starting 294ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu with the boot image. (Most of the space in these images is just the 295ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu kernel, which is identical for the two, so the resulting patch 29640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu should be efficient.) Add it to the output zip, along with a shell 29740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu script that is run from init.rc on first boot to actually do the 29840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu patching and install the new recovery image. 29940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 30040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu recovery_img and boot_img should be File objects for the 30140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu corresponding images. 30240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 30340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu Returns an Item for the shell script, which must be made 304ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu executable. 305ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu """ 306ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 307ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu patch = Difference(recovery_img, boot_img, "imgdiff") 308ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu common.ZipWriteStr(output_zip, "system/recovery-from-boot.p", patch) 309ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu Item.Get("system/recovery-from-boot.p", dir=False) 310ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 31140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # Images with different content will have a different first page, so 31240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # we check to see if this recovery has already been installed by 31340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # testing just the first 2k. 31440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu HEADER_SIZE = 2048 31540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu header_sha1 = sha.sha(recovery_img.data[:HEADER_SIZE]).hexdigest() 31640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu sh = """#!/system/bin/sh 317e2ee5e009081a392fb31596c1d0cfb30bc7bad6eBen Chanif ! applypatch -c MTD:recovery:%(header_size)d:%(header_sha1)s; then 318a92b0a0438803ebb3432d7b42672fbb7fb6bccf4Peter Qiu log -t recovery "Installing new recovery image" 319ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu 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 3203b30ca58d13cf66b75ba0729b222ddc42ae68b33Paul Stewartelse 3213b30ca58d13cf66b75ba0729b222ddc42ae68b33Paul Stewart log -t recovery "Recovery image already installed" 3223b30ca58d13cf66b75ba0729b222ddc42ae68b33Paul Stewartfi 3233e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu""" % { 'boot_size': boot_img.size, 32440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 'boot_sha1': boot_img.sha1, 32540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 'header_size': HEADER_SIZE, 32640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 'header_sha1': header_sha1, 32722f1fbc11b69ee41af8370ec38f1b90577db6c3cBen Chan 'recovery_size': recovery_img.size, 32840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 'recovery_sha1': recovery_img.sha1 } 32940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu common.ZipWriteStr(output_zip, "system/etc/install-recovery.sh", sh) 33040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu return Item.Get("system/etc/install-recovery.sh", dir=False) 33140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 33240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 33340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhudef WriteFullOTAPackage(input_zip, output_zip): 334ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu if OPTIONS.script_mode == "auto": 335e2ee5e009081a392fb31596c1d0cfb30bc7bad6eBen Chan script = both_generator.BothGenerator(2) 336e2ee5e009081a392fb31596c1d0cfb30bc7bad6eBen Chan elif OPTIONS.script_mode == "amend": 337ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu script = amend_generator.AmendGenerator() 338ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu else: 339ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu # TODO: how to determine this? We don't know what version it will 340ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu # be installed on top of. For now, we expect the API just won't 341ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu # change very often. 34241a071e432b09ab1945f5c9ae74c998726142810Paul Stewart script = edify_generator.EdifyGenerator(2) 343ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu 344ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu device_specific = common.DeviceSpecificParams( 345ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu input_zip=input_zip, 346ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu output_zip=output_zip, 347ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu script=script, 348ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu input_tmp=OPTIONS.input_tmp) 349ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu 350ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu if not OPTIONS.omit_prereq: 351ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu ts = GetBuildProp("ro.build.date.utc", input_zip) 352ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu script.AssertOlderBuild(ts) 353ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu 354cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan AppendAssertions(script, input_zip) 35541a071e432b09ab1945f5c9ae74c998726142810Paul Stewart device_specific.FullOTA_Assertions() 35641a071e432b09ab1945f5c9ae74c998726142810Paul Stewart 3573e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu script.ShowProgress(0.5, 0) 3583e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 3593e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu if OPTIONS.wipe_user_data: 3603e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu script.FormatPartition("userdata") 3613e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 3623e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu script.FormatPartition("system") 3633b30ca58d13cf66b75ba0729b222ddc42ae68b33Paul Stewart script.Mount("MTD", "system", "/system") 3643e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu script.UnpackPackageDir("system", "/system") 3653e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 3663e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu symlinks = CopySystemFiles(input_zip, output_zip) 3673e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu script.MakeSymlinks(symlinks) 3683e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 3693e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu boot_img = File("boot.img", common.BuildBootableImage( 3703e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu os.path.join(OPTIONS.input_tmp, "BOOT"))) 3713e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu recovery_img = File("recovery.img", common.BuildBootableImage( 3723b30ca58d13cf66b75ba0729b222ddc42ae68b33Paul Stewart os.path.join(OPTIONS.input_tmp, "RECOVERY"))) 3733e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu i = MakeRecoveryPatch(output_zip, recovery_img, boot_img) 3743e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 3753e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu Item.GetMetadata() 3763e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 3773e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu # GetMetadata uses the data in android_filesystem_config.h to assign 37840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # the uid/gid/mode of all files. We want to override that for the 3793e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu # recovery patching shell script to make it executable. 3803e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu i.uid = 0 3813e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu i.gid = 0 3823e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu i.mode = 0544 3833e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu Item.Get("system").SetPermissions(script) 3843e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 3853e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu common.CheckSize(boot_img.data, "boot.img") 3863e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu common.ZipWriteStr(output_zip, "boot.img", boot_img.data) 38740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu script.ShowProgress(0.2, 0) 3883e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 3893e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu script.ShowProgress(0.2, 10) 3903e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu script.WriteRawImage("boot", "boot.img") 3913e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 3923e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu script.ShowProgress(0.1, 0) 3933e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu device_specific.FullOTA_InstallEnd() 3943e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 3953b30ca58d13cf66b75ba0729b222ddc42ae68b33Paul Stewart if OPTIONS.extra_script is not None: 3963e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu script.AppendExtra(OPTIONS.extra_script) 3973b30ca58d13cf66b75ba0729b222ddc42ae68b33Paul Stewart 3983e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu script.AddToZip(input_zip, output_zip) 3993e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 4003e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 4013b30ca58d13cf66b75ba0729b222ddc42ae68b33Paul Stewartclass File(object): 4023e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu def __init__(self, name, data): 4033e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu self.name = name 4043e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu self.data = data 4053e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu self.size = len(data) 4063e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu self.sha1 = sha.sha(data).hexdigest() 4073e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 4088a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko def WriteToTemp(self): 4093e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu t = tempfile.NamedTemporaryFile() 4103e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu t.write(self.data) 4113e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu t.flush() 412ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu return t 41340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 4143e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu def AddToZip(self, z): 415ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu common.ZipWriteStr(z, self.name, self.data) 4163e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 4173e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 4183e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhudef LoadSystemFiles(z): 4193e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu """Load all the files from SYSTEM/... in a given target-files 4203e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu ZipFile, and return a dict of {filename: File object}.""" 4213b30ca58d13cf66b75ba0729b222ddc42ae68b33Paul Stewart out = {} 4223e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu for info in z.infolist(): 4233e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu if info.filename.startswith("SYSTEM/") and not IsSymlink(info): 4243e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu fn = "system/" + info.filename[7:] 4253e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu data = z.read(info.filename) 4263e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu out[fn] = File(fn, data) 4273e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu return out 4288a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko 4293e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 4303e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhudef Difference(tf, sf, diff_program): 4313e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu """Return the patch (as a string of data) needed to turn sf into tf. 432ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu diff_program is the name of an external program (or list, if 43340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu additional arguments are desired) to run to generate the diff. 4348a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko """ 4353e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 4363e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu ttemp = tf.WriteToTemp() 4373e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu stemp = sf.WriteToTemp() 4383e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 439ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu ext = os.path.splitext(tf.name)[1] 4403e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 4413e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu try: 4423e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu ptemp = tempfile.NamedTemporaryFile() 4433e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu if isinstance(diff_program, list): 4443e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu cmd = copy.copy(diff_program) 4453b30ca58d13cf66b75ba0729b222ddc42ae68b33Paul Stewart else: 4463e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu cmd = [diff_program] 4473e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu cmd.append(stemp.name) 4483e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu cmd.append(ttemp.name) 4493e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu cmd.append(ptemp.name) 4503e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu p = common.Run(cmd) 4513e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu _, err = p.communicate() 4528a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko if err or p.returncode != 0: 4533e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu print "WARNING: failure running %s:\n%s\n" % (diff_program, err) 4543e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu return None 4553e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu diff = ptemp.read() 456ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu finally: 457ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu ptemp.close() 4583e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu stemp.close() 4593e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu ttemp.close() 4603e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 4613e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu return diff 4623e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 4633e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu 464ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhudef GetBuildProp(property, z): 4653e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu """Return the fingerprint of the build of a given target-files 4663e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu ZipFile object.""" 46740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu bp = z.read("SYSTEM/build.prop") 46840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if not property: 46940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu return bp 47040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu m = re.search(re.escape(property) + r"=(.*)\n", bp) 47140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if not m: 47240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu raise common.ExternalError("couldn't find %s in build.prop" % (property,)) 47340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu return m.group(1).strip() 4748a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko 47540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 47640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhudef GetRecoveryAPIVersion(zip): 47740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu """Returns the version of the recovery API. Version 0 is the older 47840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu amend code (no separate binary).""" 47940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu try: 4808a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko version = zip.read("META/recovery-api-version.txt") 48140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu return int(version) 48240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu except KeyError: 48340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu try: 48440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # version one didn't have the recovery-api-version.txt file, but 48540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # it did include an updater binary. 48640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu zip.getinfo("OTA/bin/updater") 48740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu return 1 48840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu except KeyError: 48940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu return 0 49040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 49140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhudef WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): 49240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu source_version = GetRecoveryAPIVersion(source_zip) 49340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 49440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if OPTIONS.script_mode == 'amend': 49540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu script = amend_generator.AmendGenerator() 49640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu elif OPTIONS.script_mode == 'edify': 49740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if source_version == 0: 49840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu print ("WARNING: generating edify script for a source that " 49940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu "can't install it.") 50040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu script = edify_generator.EdifyGenerator(source_version) 50140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu elif OPTIONS.script_mode == 'auto': 50240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if source_version > 0: 50340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu script = edify_generator.EdifyGenerator(source_version) 50440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu else: 50540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu script = amend_generator.AmendGenerator() 50640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu else: 50740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu raise ValueError('unknown script mode "%s"' % (OPTIONS.script_mode,)) 50840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 50940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu device_specific = common.DeviceSpecificParams( 51040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu source_zip=source_zip, 51140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu target_zip=target_zip, 51240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu output_zip=output_zip, 51340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu script=script) 51440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 51540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu print "Loading target..." 51640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu target_data = LoadSystemFiles(target_zip) 51740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu print "Loading source..." 51840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu source_data = LoadSystemFiles(source_zip) 51940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 52040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu verbatim_targets = [] 52140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu patch_list = [] 52240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu largest_source_size = 0 52340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu for fn in sorted(target_data.keys()): 52440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu tf = target_data[fn] 52540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu sf = source_data.get(fn, None) 52640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 52740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if sf is None or fn in OPTIONS.require_verbatim: 52840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # This file should be included verbatim 52940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if fn in OPTIONS.prohibit_verbatim: 53040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,)) 53140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu print "send", fn, "verbatim" 53240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu tf.AddToZip(output_zip) 53340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu verbatim_targets.append((fn, tf.size)) 53440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu elif tf.sha1 != sf.sha1: 53540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # File is different; consider sending as a patch 53640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu diff_method = "bsdiff" 53740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if tf.name.endswith(".gz"): 53840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu diff_method = "imgdiff" 53940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu d = Difference(tf, sf, diff_method) 54040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if d is not None: 54140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu print fn, tf.size, len(d), (float(len(d)) / tf.size) 54240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if d is None or len(d) > tf.size * OPTIONS.patch_threshold: 54340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # patch is almost as big as the file; don't bother patching 54440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu tf.AddToZip(output_zip) 54540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu verbatim_targets.append((fn, tf.size)) 54640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu else: 54740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu common.ZipWriteStr(output_zip, "patch/" + fn + ".p", d) 54840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu patch_list.append((fn, tf, sf, tf.size)) 54940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu largest_source_size = max(largest_source_size, sf.size) 55040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu else: 55140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # Target file identical to source. 55240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu pass 55340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 55440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu total_verbatim_size = sum([i[1] for i in verbatim_targets]) 55540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu total_patched_size = sum([i[3] for i in patch_list]) 55640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 55740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu source_fp = GetBuildProp("ro.build.fingerprint", source_zip) 55840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu target_fp = GetBuildProp("ro.build.fingerprint", target_zip) 55940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 56040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu script.Mount("MTD", "system", "/system") 56140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu script.AssertSomeFingerprint(source_fp, target_fp) 56240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 56340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu source_boot = File("/tmp/boot.img", 56440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu common.BuildBootableImage( 56540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu os.path.join(OPTIONS.source_tmp, "BOOT"))) 566ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu target_boot = File("/tmp/boot.img", 567ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu common.BuildBootableImage( 568ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu os.path.join(OPTIONS.target_tmp, "BOOT"))) 569ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu updating_boot = (source_boot.data != target_boot.data) 57040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 571ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu source_recovery = File("system/recovery.img", 572ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu common.BuildBootableImage( 573ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu os.path.join(OPTIONS.source_tmp, "RECOVERY"))) 574ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu target_recovery = File("system/recovery.img", 575ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu common.BuildBootableImage( 576ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu os.path.join(OPTIONS.target_tmp, "RECOVERY"))) 577ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu updating_recovery = (source_recovery.data != target_recovery.data) 578ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 57940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # We reserve the last 0.3 of the progress bar for the 580ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # device-specific IncrementalOTA_InstallEnd() call at the end, which 581ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # will typically install a radio image. 582ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu progress_bar_total = 0.7 583ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu if updating_boot: 584ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu progress_bar_total -= 0.1 585ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 586ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu AppendAssertions(script, target_zip) 587ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu device_specific.IncrementalOTA_Assertions() 588ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 58940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu script.Print("Verifying current system...") 590ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 591ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu pb_verify = progress_bar_total * 0.3 * \ 592ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu (total_patched_size / 593ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu float(total_patched_size+total_verbatim_size+1)) 594ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 595ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu for i, (fn, tf, sf, size) in enumerate(patch_list): 596ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu if i % 5 == 0: 597ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu next_sizes = sum([i[3] for i in patch_list[i:i+5]]) 59840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu script.ShowProgress(next_sizes * pb_verify / (total_patched_size+1), 1) 5998a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko 600ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu script.PatchCheck("/"+fn, tf.sha1, sf.sha1) 601ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 60240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if updating_boot: 603ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu d = Difference(target_boot, source_boot, "imgdiff") 604ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu print "boot target: %d source: %d diff: %d" % ( 6058a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko target_boot.size, source_boot.size, len(d)) 606ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 607ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu common.ZipWriteStr(output_zip, "patch/boot.img.p", d) 6088a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko 609ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu script.PatchCheck("MTD:boot:%d:%s:%d:%s" % 610ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu (source_boot.size, source_boot.sha1, 611ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu target_boot.size, target_boot.sha1)) 61240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 61340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if patch_list or updating_recovery or updating_boot: 614ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu script.CacheFreeSpaceCheck(largest_source_size) 615ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu script.Print("Unpacking patches...") 616ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu script.UnpackPackageDir("patch", "/tmp/patchtmp") 617ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 618ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu device_specific.IncrementalOTA_VerifyEnd() 619ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 620ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu script.Comment("---- start making changes here ----") 621ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 622ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu if OPTIONS.wipe_user_data: 623ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu script.Print("Erasing user data...") 624ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu script.FormatPartition("userdata") 625ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 62640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu script.Print("Removing unneeded files...") 627ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu script.DeleteFiles(["/"+i[0] for i in verbatim_targets] + 628ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu ["/"+i for i in sorted(source_data) 629ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu if i not in target_data]) 63040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 631ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu if updating_boot: 632ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # Produce the boot image by applying a patch to the current 633ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # contents of the boot partition, and write it back to the 634ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # partition. 635ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu script.Print("Patching boot image...") 636ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu script.ApplyPatch("MTD:boot:%d:%s:%d:%s" 637ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu % (source_boot.size, source_boot.sha1, 638ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu target_boot.size, target_boot.sha1), 639ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu "-", 64040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu target_boot.size, target_boot.sha1, 641ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu source_boot.sha1, "/tmp/patchtmp/boot.img.p") 642ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu print "boot image changed; including." 643ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu else: 64440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu print "boot image unchanged; skipping." 64540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 646ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu if updating_recovery: 647ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # Is it better to generate recovery as a patch from the current 648ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # boot image, or from the previous recovery image? For large 649ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # updates with significant kernel changes, probably the former. 650ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # For small updates where the kernel hasn't changed, almost 651ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # certainly the latter. We pick the first option. Future 652ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # complicated schemes may let us effectively use both. 653ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # 654ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # A wacky possibility: as long as there is room in the boot 65540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # partition, include the binaries and image files from recovery in 656ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # the boot image (though not in the ramdisk) so they can be used 657ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # as fodder for constructing the recovery image. 658ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu recovery_sh_item = MakeRecoveryPatch(output_zip, 659ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu target_recovery, target_boot) 660ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu print "recovery image changed; including as patch from boot." 66140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu else: 662ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu print "recovery image unchanged; skipping." 663ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 664ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu script.Print("Patching system files...") 665ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu pb_apply = progress_bar_total * 0.7 * \ 666ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu (total_patched_size / 667ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu float(total_patched_size+total_verbatim_size+1)) 668ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu for i, (fn, tf, sf, size) in enumerate(patch_list): 669ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu if i % 5 == 0: 670ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu next_sizes = sum([i[3] for i in patch_list[i:i+5]]) 671ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu script.ShowProgress(next_sizes * pb_apply / (total_patched_size+1), 1) 67240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, 673ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu sf.sha1, "/tmp/patchtmp/"+fn+".p") 674ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 675ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu target_symlinks = CopySystemFiles(target_zip, None) 676ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 677ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks]) 678ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu temp_script = script.MakeTemporary() 679ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu Item.GetMetadata() 68040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if updating_recovery: 681ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu recovery_sh_item.uid = 0 682ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu recovery_sh_item.gid = 0 683ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu recovery_sh_item.mode = 0544 684ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu Item.Get("system").SetPermissions(temp_script) 685ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 686ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # Note that this call will mess up the tree of Items, so make sure 687ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # we're done with it. 688ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu source_symlinks = CopySystemFiles(source_zip, None) 689ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks]) 690ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 691ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # Delete all the symlinks in source that aren't in target. This 692ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu # needs to happen before verbatim files are unpacked, in case a 69340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu # symlink in the source is replaced by a real file in the target. 694ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu to_delete = [] 695ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu for dest, link in source_symlinks: 696ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu if link not in target_symlinks_d: 69740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu to_delete.append(link) 698ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu script.DeleteFiles(to_delete) 699ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 700ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu if verbatim_targets: 701ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu pb_verbatim = progress_bar_total * \ 702ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu (total_verbatim_size / 703ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu float(total_patched_size+total_verbatim_size+1)) 704ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu script.ShowProgress(pb_verbatim, 5) 705ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu script.Print("Unpacking new files...") 706ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu script.UnpackPackageDir("system", "/system") 707ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 708ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu script.Print("Symlinks and permissions...") 709ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu 71081404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu # Create all the symlinks that don't already exist, or point to 71181404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu # somewhere different than what we want. Delete each symlink before 71281404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu # creating it, since the 'symlink' command won't overwrite. 71381404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu to_create = [] 71481404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu for dest, link in target_symlinks: 71581404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu if link in source_symlinks_d: 71681404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu if dest != source_symlinks_d[link]: 71781404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu to_create.append((dest, link)) 71881404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu else: 71981404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu to_create.append((dest, link)) 72081404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu script.DeleteFiles([i[1] for i in to_create]) 72181404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu script.MakeSymlinks(to_create) 72281404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu 72381404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu # Now that the symlinks are created, we can set all the 72481404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu # permissions. 72581404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu script.AppendScript(temp_script) 72681404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu 72781404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu # Write the radio image, if necessary. 72881404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu script.ShowProgress(0.3, 10) 72981404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu device_specific.IncrementalOTA_InstallEnd() 73081404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu 73181404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu if OPTIONS.extra_script is not None: 73281404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu scirpt.AppendExtra(OPTIONS.extra_script) 73381404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu 73481404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu script.AddToZip(target_zip, output_zip) 73581404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu 73681404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu 73781404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhudef main(argv): 73881404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu 73981404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu def option_handler(o, a): 74081404c674c82f0ac2c958715b451b84521148b7ePrathmesh Prabhu if o in ("-b", "--board_config"): 74140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu pass # deprecated 74240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu elif o in ("-k", "--package_key"): 74340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu OPTIONS.package_key = a 74440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu elif o in ("-i", "--incremental_from"): 74540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu OPTIONS.incremental_source = a 7468a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko elif o in ("-w", "--wipe_user_data"): 74740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu OPTIONS.wipe_user_data = True 748ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu elif o in ("-n", "--no_prereq"): 749ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu OPTIONS.omit_prereq = True 750ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu elif o in ("-e", "--extra_script"): 75140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu OPTIONS.extra_script = a 75240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu elif o in ("-m", "--script_mode"): 75340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu OPTIONS.script_mode = a 75440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu else: 75540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu return False 75640daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu return True 75740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 75840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu args = common.ParseOptions(argv, __doc__, 7598a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko extra_opts="b:k:i:d:wne:m:", 76040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu extra_long_opts=["board_config=", 761ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu "package_key=", 76240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu "incremental_from=", 76340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu "wipe_user_data", 764ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu "no_prereq", 765ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu "extra_script=", 766ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu "script_mode="], 76740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu extra_option_handler=option_handler) 76840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 76940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if len(args) != 2: 77040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu common.Usage(__doc__) 77140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu sys.exit(1) 77240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 77340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if OPTIONS.script_mode not in ("amend", "edify", "auto"): 77440daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu raise ValueError('unknown script mode "%s"' % (OPTIONS.script_mode,)) 775ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu 776ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu if OPTIONS.extra_script is not None: 77740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu OPTIONS.extra_script = open(OPTIONS.extra_script).read() 778ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu 77940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu print "unzipping target target-files..." 78040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu OPTIONS.input_tmp = common.UnzipTemp(args[0]) 781ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu 78240daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu common.LoadMaxSizes() 78340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if not OPTIONS.max_image_size: 784ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu print 785ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu print " WARNING: Failed to load max image sizes; will not enforce" 786ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu print " image size limits." 78740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu print 78840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 78940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu OPTIONS.target_tmp = OPTIONS.input_tmp 790ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu input_zip = zipfile.ZipFile(args[0], "r") 7913e452f8c41b7983f1068a4b7229998c7e7de4334Prathmesh Prabhu if OPTIONS.package_key: 792ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu temp_zip_file = tempfile.NamedTemporaryFile() 79340daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu output_zip = zipfile.ZipFile(temp_zip_file, "w", 794ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu compression=zipfile.ZIP_DEFLATED) 79540daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu else: 796ade9b9a914efaeac3b2f4d4888ffdfb3e76b76f6Prathmesh Prabhu output_zip = zipfile.ZipFile(args[1], "w", 79740daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu compression=zipfile.ZIP_DEFLATED) 79840daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu 79940daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu if OPTIONS.incremental_source is None: 80040daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu WriteFullOTAPackage(input_zip, output_zip) 80140daa01c4c8d772889d9c4167dee312869152174Prathmesh Prabhu else: 802 print "unzipping source target-files..." 803 OPTIONS.source_tmp = common.UnzipTemp(OPTIONS.incremental_source) 804 source_zip = zipfile.ZipFile(OPTIONS.incremental_source, "r") 805 WriteIncrementalOTAPackage(input_zip, source_zip, output_zip) 806 807 output_zip.close() 808 if OPTIONS.package_key: 809 SignOutput(temp_zip_file.name, args[1]) 810 temp_zip_file.close() 811 812 common.Cleanup() 813 814 print "done." 815 816 817if __name__ == '__main__': 818 try: 819 main(sys.argv[1:]) 820 except common.ExternalError, e: 821 print 822 print " ERROR: %s" % (e,) 823 print 824 sys.exit(1) 825