1*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2009 The Android Open Source Project 2*9e94795aSAndroid Build Coastguard Worker# 3*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 4*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 5*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at 6*9e94795aSAndroid Build Coastguard Worker# 7*9e94795aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 8*9e94795aSAndroid Build Coastguard Worker# 9*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 10*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 11*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 13*9e94795aSAndroid Build Coastguard Worker# limitations under the License. 14*9e94795aSAndroid Build Coastguard Worker 15*9e94795aSAndroid Build Coastguard Workerimport re 16*9e94795aSAndroid Build Coastguard Worker 17*9e94795aSAndroid Build Coastguard Workerimport common 18*9e94795aSAndroid Build Coastguard Worker 19*9e94795aSAndroid Build Coastguard Workerclass EdifyGenerator(object): 20*9e94795aSAndroid Build Coastguard Worker """Class to generate scripts in the 'edify' recovery script language 21*9e94795aSAndroid Build Coastguard Worker used from donut onwards.""" 22*9e94795aSAndroid Build Coastguard Worker 23*9e94795aSAndroid Build Coastguard Worker def __init__(self, version, info, fstab=None): 24*9e94795aSAndroid Build Coastguard Worker self.script = [] 25*9e94795aSAndroid Build Coastguard Worker self.mounts = set() 26*9e94795aSAndroid Build Coastguard Worker self._required_cache = 0 27*9e94795aSAndroid Build Coastguard Worker self.version = version 28*9e94795aSAndroid Build Coastguard Worker self.info = info 29*9e94795aSAndroid Build Coastguard Worker if fstab is None: 30*9e94795aSAndroid Build Coastguard Worker self.fstab = self.info.get("fstab", None) 31*9e94795aSAndroid Build Coastguard Worker else: 32*9e94795aSAndroid Build Coastguard Worker self.fstab = fstab 33*9e94795aSAndroid Build Coastguard Worker 34*9e94795aSAndroid Build Coastguard Worker @property 35*9e94795aSAndroid Build Coastguard Worker def required_cache(self): 36*9e94795aSAndroid Build Coastguard Worker """Return the minimum cache size to apply the update.""" 37*9e94795aSAndroid Build Coastguard Worker return self._required_cache 38*9e94795aSAndroid Build Coastguard Worker 39*9e94795aSAndroid Build Coastguard Worker @staticmethod 40*9e94795aSAndroid Build Coastguard Worker def WordWrap(cmd, linelen=80): 41*9e94795aSAndroid Build Coastguard Worker """'cmd' should be a function call with null characters after each 42*9e94795aSAndroid Build Coastguard Worker parameter (eg, "somefun(foo,\0bar,\0baz)"). This function wraps cmd 43*9e94795aSAndroid Build Coastguard Worker to a given line length, replacing nulls with spaces and/or newlines 44*9e94795aSAndroid Build Coastguard Worker to format it nicely.""" 45*9e94795aSAndroid Build Coastguard Worker indent = cmd.index("(")+1 46*9e94795aSAndroid Build Coastguard Worker out = [] 47*9e94795aSAndroid Build Coastguard Worker first = True 48*9e94795aSAndroid Build Coastguard Worker x = re.compile("^(.{,%d})\0" % (linelen-indent,)) 49*9e94795aSAndroid Build Coastguard Worker while True: 50*9e94795aSAndroid Build Coastguard Worker if not first: 51*9e94795aSAndroid Build Coastguard Worker out.append(" " * indent) 52*9e94795aSAndroid Build Coastguard Worker first = False 53*9e94795aSAndroid Build Coastguard Worker m = x.search(cmd) 54*9e94795aSAndroid Build Coastguard Worker if not m: 55*9e94795aSAndroid Build Coastguard Worker parts = cmd.split("\0", 1) 56*9e94795aSAndroid Build Coastguard Worker out.append(parts[0]+"\n") 57*9e94795aSAndroid Build Coastguard Worker if len(parts) == 1: 58*9e94795aSAndroid Build Coastguard Worker break 59*9e94795aSAndroid Build Coastguard Worker else: 60*9e94795aSAndroid Build Coastguard Worker cmd = parts[1] 61*9e94795aSAndroid Build Coastguard Worker continue 62*9e94795aSAndroid Build Coastguard Worker out.append(m.group(1)+"\n") 63*9e94795aSAndroid Build Coastguard Worker cmd = cmd[m.end():] 64*9e94795aSAndroid Build Coastguard Worker 65*9e94795aSAndroid Build Coastguard Worker return "".join(out).replace("\0", " ").rstrip("\n") 66*9e94795aSAndroid Build Coastguard Worker 67*9e94795aSAndroid Build Coastguard Worker def AppendScript(self, other): 68*9e94795aSAndroid Build Coastguard Worker """Append the contents of another script (which should be created 69*9e94795aSAndroid Build Coastguard Worker with temporary=True) to this one.""" 70*9e94795aSAndroid Build Coastguard Worker self.script.extend(other.script) 71*9e94795aSAndroid Build Coastguard Worker 72*9e94795aSAndroid Build Coastguard Worker def AssertOemProperty(self, name, values, oem_no_mount): 73*9e94795aSAndroid Build Coastguard Worker """Assert that a property on the OEM paritition matches allowed values.""" 74*9e94795aSAndroid Build Coastguard Worker if not name: 75*9e94795aSAndroid Build Coastguard Worker raise ValueError("must specify an OEM property") 76*9e94795aSAndroid Build Coastguard Worker if not values: 77*9e94795aSAndroid Build Coastguard Worker raise ValueError("must specify the OEM value") 78*9e94795aSAndroid Build Coastguard Worker 79*9e94795aSAndroid Build Coastguard Worker if oem_no_mount: 80*9e94795aSAndroid Build Coastguard Worker get_prop_command = 'getprop("%s")' % name 81*9e94795aSAndroid Build Coastguard Worker else: 82*9e94795aSAndroid Build Coastguard Worker get_prop_command = 'file_getprop("/oem/oem.prop", "%s")' % name 83*9e94795aSAndroid Build Coastguard Worker 84*9e94795aSAndroid Build Coastguard Worker cmd = '' 85*9e94795aSAndroid Build Coastguard Worker for value in values: 86*9e94795aSAndroid Build Coastguard Worker cmd += '%s == "%s" || ' % (get_prop_command, value) 87*9e94795aSAndroid Build Coastguard Worker cmd += ( 88*9e94795aSAndroid Build Coastguard Worker 'abort("E{code}: This package expects the value \\"{values}\\" for ' 89*9e94795aSAndroid Build Coastguard Worker '\\"{name}\\"; this has value \\"" + ' 90*9e94795aSAndroid Build Coastguard Worker '{get_prop_command} + "\\".");').format( 91*9e94795aSAndroid Build Coastguard Worker code=common.ErrorCode.OEM_PROP_MISMATCH, 92*9e94795aSAndroid Build Coastguard Worker get_prop_command=get_prop_command, name=name, 93*9e94795aSAndroid Build Coastguard Worker values='\\" or \\"'.join(values)) 94*9e94795aSAndroid Build Coastguard Worker self.script.append(cmd) 95*9e94795aSAndroid Build Coastguard Worker 96*9e94795aSAndroid Build Coastguard Worker def AssertSomeFingerprint(self, *fp): 97*9e94795aSAndroid Build Coastguard Worker """Assert that the current recovery build fingerprint is one of *fp.""" 98*9e94795aSAndroid Build Coastguard Worker if not fp: 99*9e94795aSAndroid Build Coastguard Worker raise ValueError("must specify some fingerprints") 100*9e94795aSAndroid Build Coastguard Worker cmd = (' ||\n '.join([('getprop("ro.build.fingerprint") == "%s"') % i 101*9e94795aSAndroid Build Coastguard Worker for i in fp]) + 102*9e94795aSAndroid Build Coastguard Worker ' ||\n abort("E%d: Package expects build fingerprint of %s; ' 103*9e94795aSAndroid Build Coastguard Worker 'this device has " + getprop("ro.build.fingerprint") + ".");') % ( 104*9e94795aSAndroid Build Coastguard Worker common.ErrorCode.FINGERPRINT_MISMATCH, " or ".join(fp)) 105*9e94795aSAndroid Build Coastguard Worker self.script.append(cmd) 106*9e94795aSAndroid Build Coastguard Worker 107*9e94795aSAndroid Build Coastguard Worker def AssertSomeThumbprint(self, *fp): 108*9e94795aSAndroid Build Coastguard Worker """Assert that the current recovery build thumbprint is one of *fp.""" 109*9e94795aSAndroid Build Coastguard Worker if not fp: 110*9e94795aSAndroid Build Coastguard Worker raise ValueError("must specify some thumbprints") 111*9e94795aSAndroid Build Coastguard Worker cmd = (' ||\n '.join([('getprop("ro.build.thumbprint") == "%s"') % i 112*9e94795aSAndroid Build Coastguard Worker for i in fp]) + 113*9e94795aSAndroid Build Coastguard Worker ' ||\n abort("E%d: Package expects build thumbprint of %s; this ' 114*9e94795aSAndroid Build Coastguard Worker 'device has " + getprop("ro.build.thumbprint") + ".");') % ( 115*9e94795aSAndroid Build Coastguard Worker common.ErrorCode.THUMBPRINT_MISMATCH, " or ".join(fp)) 116*9e94795aSAndroid Build Coastguard Worker self.script.append(cmd) 117*9e94795aSAndroid Build Coastguard Worker 118*9e94795aSAndroid Build Coastguard Worker def AssertFingerprintOrThumbprint(self, fp, tp): 119*9e94795aSAndroid Build Coastguard Worker """Assert that the current recovery build fingerprint is fp, or thumbprint 120*9e94795aSAndroid Build Coastguard Worker is tp.""" 121*9e94795aSAndroid Build Coastguard Worker cmd = ('getprop("ro.build.fingerprint") == "{fp}" ||\n' 122*9e94795aSAndroid Build Coastguard Worker ' getprop("ro.build.thumbprint") == "{tp}" ||\n' 123*9e94795aSAndroid Build Coastguard Worker ' abort("Package expects build fingerprint of {fp} or ' 124*9e94795aSAndroid Build Coastguard Worker 'thumbprint of {tp}; this device has a fingerprint of " ' 125*9e94795aSAndroid Build Coastguard Worker '+ getprop("ro.build.fingerprint") + " and a thumbprint of " ' 126*9e94795aSAndroid Build Coastguard Worker '+ getprop("ro.build.thumbprint") + ".");').format(fp=fp, tp=tp) 127*9e94795aSAndroid Build Coastguard Worker self.script.append(cmd) 128*9e94795aSAndroid Build Coastguard Worker 129*9e94795aSAndroid Build Coastguard Worker def AssertOlderBuild(self, timestamp, timestamp_text): 130*9e94795aSAndroid Build Coastguard Worker """Assert that the build on the device is older (or the same as) 131*9e94795aSAndroid Build Coastguard Worker the given timestamp.""" 132*9e94795aSAndroid Build Coastguard Worker self.script.append( 133*9e94795aSAndroid Build Coastguard Worker ('(!less_than_int(%s, getprop("ro.build.date.utc"))) || ' 134*9e94795aSAndroid Build Coastguard Worker 'abort("E%d: Can\'t install this package (%s) over newer ' 135*9e94795aSAndroid Build Coastguard Worker 'build (" + getprop("ro.build.date") + ").");') % ( 136*9e94795aSAndroid Build Coastguard Worker timestamp, common.ErrorCode.OLDER_BUILD, timestamp_text)) 137*9e94795aSAndroid Build Coastguard Worker 138*9e94795aSAndroid Build Coastguard Worker def AssertDevice(self, device): 139*9e94795aSAndroid Build Coastguard Worker """Assert that the device identifier is the given string.""" 140*9e94795aSAndroid Build Coastguard Worker cmd = ('getprop("ro.product.device") == "%s" || ' 141*9e94795aSAndroid Build Coastguard Worker 'abort("E%d: This package is for \\"%s\\" devices; ' 142*9e94795aSAndroid Build Coastguard Worker 'this is a \\"" + getprop("ro.product.device") + "\\".");') % ( 143*9e94795aSAndroid Build Coastguard Worker device, common.ErrorCode.DEVICE_MISMATCH, device) 144*9e94795aSAndroid Build Coastguard Worker self.script.append(cmd) 145*9e94795aSAndroid Build Coastguard Worker 146*9e94795aSAndroid Build Coastguard Worker def AssertSomeBootloader(self, *bootloaders): 147*9e94795aSAndroid Build Coastguard Worker """Asert that the bootloader version is one of *bootloaders.""" 148*9e94795aSAndroid Build Coastguard Worker cmd = ("assert(" + 149*9e94795aSAndroid Build Coastguard Worker " ||\0".join(['getprop("ro.bootloader") == "%s"' % (b,) 150*9e94795aSAndroid Build Coastguard Worker for b in bootloaders]) + 151*9e94795aSAndroid Build Coastguard Worker ");") 152*9e94795aSAndroid Build Coastguard Worker self.script.append(self.WordWrap(cmd)) 153*9e94795aSAndroid Build Coastguard Worker 154*9e94795aSAndroid Build Coastguard Worker def ShowProgress(self, frac, dur): 155*9e94795aSAndroid Build Coastguard Worker """Update the progress bar, advancing it over 'frac' over the next 156*9e94795aSAndroid Build Coastguard Worker 'dur' seconds. 'dur' may be zero to advance it via SetProgress 157*9e94795aSAndroid Build Coastguard Worker commands instead of by time.""" 158*9e94795aSAndroid Build Coastguard Worker self.script.append("show_progress(%f, %d);" % (frac, int(dur))) 159*9e94795aSAndroid Build Coastguard Worker 160*9e94795aSAndroid Build Coastguard Worker def SetProgress(self, frac): 161*9e94795aSAndroid Build Coastguard Worker """Set the position of the progress bar within the chunk defined 162*9e94795aSAndroid Build Coastguard Worker by the most recent ShowProgress call. 'frac' should be in 163*9e94795aSAndroid Build Coastguard Worker [0,1].""" 164*9e94795aSAndroid Build Coastguard Worker self.script.append("set_progress(%f);" % (frac,)) 165*9e94795aSAndroid Build Coastguard Worker 166*9e94795aSAndroid Build Coastguard Worker def PatchCheck(self, filename, *sha1): # pylint: disable=unused-argument 167*9e94795aSAndroid Build Coastguard Worker """Checks that the given partition has the desired checksum. 168*9e94795aSAndroid Build Coastguard Worker 169*9e94795aSAndroid Build Coastguard Worker The call to this function is being deprecated in favor of 170*9e94795aSAndroid Build Coastguard Worker PatchPartitionCheck(). It will try to parse and handle the old format, 171*9e94795aSAndroid Build Coastguard Worker unless the format is unknown. 172*9e94795aSAndroid Build Coastguard Worker """ 173*9e94795aSAndroid Build Coastguard Worker tokens = filename.split(':') 174*9e94795aSAndroid Build Coastguard Worker assert len(tokens) == 6 and tokens[0] == 'EMMC', \ 175*9e94795aSAndroid Build Coastguard Worker "Failed to handle unknown format. Use PatchPartitionCheck() instead." 176*9e94795aSAndroid Build Coastguard Worker source = '{}:{}:{}:{}'.format(tokens[0], tokens[1], tokens[2], tokens[3]) 177*9e94795aSAndroid Build Coastguard Worker target = '{}:{}:{}:{}'.format(tokens[0], tokens[1], tokens[4], tokens[5]) 178*9e94795aSAndroid Build Coastguard Worker self.PatchPartitionCheck(target, source) 179*9e94795aSAndroid Build Coastguard Worker 180*9e94795aSAndroid Build Coastguard Worker def PatchPartitionCheck(self, target, source): 181*9e94795aSAndroid Build Coastguard Worker """Checks whether updater can patch the given partitions. 182*9e94795aSAndroid Build Coastguard Worker 183*9e94795aSAndroid Build Coastguard Worker It checks the checksums of the given partitions. If none of them matches the 184*9e94795aSAndroid Build Coastguard Worker expected checksum, updater will additionally look for a backup on /cache. 185*9e94795aSAndroid Build Coastguard Worker """ 186*9e94795aSAndroid Build Coastguard Worker self._CheckSecondTokenNotSlotSuffixed(target, "PatchPartitionExprCheck") 187*9e94795aSAndroid Build Coastguard Worker self._CheckSecondTokenNotSlotSuffixed(source, "PatchPartitionExprCheck") 188*9e94795aSAndroid Build Coastguard Worker self.PatchPartitionExprCheck('"%s"' % target, '"%s"' % source) 189*9e94795aSAndroid Build Coastguard Worker 190*9e94795aSAndroid Build Coastguard Worker def PatchPartitionExprCheck(self, target_expr, source_expr): 191*9e94795aSAndroid Build Coastguard Worker """Checks whether updater can patch the given partitions. 192*9e94795aSAndroid Build Coastguard Worker 193*9e94795aSAndroid Build Coastguard Worker It checks the checksums of the given partitions. If none of them matches the 194*9e94795aSAndroid Build Coastguard Worker expected checksum, updater will additionally look for a backup on /cache. 195*9e94795aSAndroid Build Coastguard Worker 196*9e94795aSAndroid Build Coastguard Worker Args: 197*9e94795aSAndroid Build Coastguard Worker target_expr: an Edify expression that serves as the target arg to 198*9e94795aSAndroid Build Coastguard Worker patch_partition. Must be evaluated to a string in the form of 199*9e94795aSAndroid Build Coastguard Worker foo:bar:baz:quux 200*9e94795aSAndroid Build Coastguard Worker source_expr: an Edify expression that serves as the source arg to 201*9e94795aSAndroid Build Coastguard Worker patch_partition. Must be evaluated to a string in the form of 202*9e94795aSAndroid Build Coastguard Worker foo:bar:baz:quux 203*9e94795aSAndroid Build Coastguard Worker """ 204*9e94795aSAndroid Build Coastguard Worker self.script.append(self.WordWrap(( 205*9e94795aSAndroid Build Coastguard Worker 'patch_partition_check({target},\0{source}) ||\n abort(' 206*9e94795aSAndroid Build Coastguard Worker 'concat("E{code}: \\"",{target},"\\" or \\"",{source},"\\" has ' 207*9e94795aSAndroid Build Coastguard Worker 'unexpected contents."));').format( 208*9e94795aSAndroid Build Coastguard Worker target=target_expr, 209*9e94795aSAndroid Build Coastguard Worker source=source_expr, 210*9e94795aSAndroid Build Coastguard Worker code=common.ErrorCode.BAD_PATCH_FILE))) 211*9e94795aSAndroid Build Coastguard Worker 212*9e94795aSAndroid Build Coastguard Worker def CacheFreeSpaceCheck(self, amount): 213*9e94795aSAndroid Build Coastguard Worker """Check that there's at least 'amount' space that can be made 214*9e94795aSAndroid Build Coastguard Worker available on /cache.""" 215*9e94795aSAndroid Build Coastguard Worker self._required_cache = max(self._required_cache, amount) 216*9e94795aSAndroid Build Coastguard Worker self.script.append(('apply_patch_space(%d) || abort("E%d: Not enough free ' 217*9e94795aSAndroid Build Coastguard Worker 'space on /cache to apply patches.");') % ( 218*9e94795aSAndroid Build Coastguard Worker amount, 219*9e94795aSAndroid Build Coastguard Worker common.ErrorCode.INSUFFICIENT_CACHE_SPACE)) 220*9e94795aSAndroid Build Coastguard Worker 221*9e94795aSAndroid Build Coastguard Worker def Mount(self, mount_point, mount_options_by_format=""): 222*9e94795aSAndroid Build Coastguard Worker """Mount the partition with the given mount_point. 223*9e94795aSAndroid Build Coastguard Worker mount_options_by_format: 224*9e94795aSAndroid Build Coastguard Worker [fs_type=option[,option]...[|fs_type=option[,option]...]...] 225*9e94795aSAndroid Build Coastguard Worker where option is optname[=optvalue] 226*9e94795aSAndroid Build Coastguard Worker E.g. ext4=barrier=1,nodelalloc,errors=panic|f2fs=errors=recover 227*9e94795aSAndroid Build Coastguard Worker """ 228*9e94795aSAndroid Build Coastguard Worker fstab = self.fstab 229*9e94795aSAndroid Build Coastguard Worker if fstab: 230*9e94795aSAndroid Build Coastguard Worker p = fstab[mount_point] 231*9e94795aSAndroid Build Coastguard Worker mount_dict = {} 232*9e94795aSAndroid Build Coastguard Worker if mount_options_by_format is not None: 233*9e94795aSAndroid Build Coastguard Worker for option in mount_options_by_format.split("|"): 234*9e94795aSAndroid Build Coastguard Worker if "=" in option: 235*9e94795aSAndroid Build Coastguard Worker key, value = option.split("=", 1) 236*9e94795aSAndroid Build Coastguard Worker mount_dict[key] = value 237*9e94795aSAndroid Build Coastguard Worker mount_flags = mount_dict.get(p.fs_type, "") 238*9e94795aSAndroid Build Coastguard Worker if p.context is not None: 239*9e94795aSAndroid Build Coastguard Worker mount_flags = p.context + ("," + mount_flags if mount_flags else "") 240*9e94795aSAndroid Build Coastguard Worker self.script.append('mount("%s", "%s", %s, "%s", "%s");' % ( 241*9e94795aSAndroid Build Coastguard Worker p.fs_type, common.PARTITION_TYPES[p.fs_type], 242*9e94795aSAndroid Build Coastguard Worker self._GetSlotSuffixDeviceForEntry(p), 243*9e94795aSAndroid Build Coastguard Worker p.mount_point, mount_flags)) 244*9e94795aSAndroid Build Coastguard Worker self.mounts.add(p.mount_point) 245*9e94795aSAndroid Build Coastguard Worker 246*9e94795aSAndroid Build Coastguard Worker def Comment(self, comment): 247*9e94795aSAndroid Build Coastguard Worker """Write a comment into the update script.""" 248*9e94795aSAndroid Build Coastguard Worker self.script.append("") 249*9e94795aSAndroid Build Coastguard Worker for i in comment.split("\n"): 250*9e94795aSAndroid Build Coastguard Worker self.script.append("# " + i) 251*9e94795aSAndroid Build Coastguard Worker self.script.append("") 252*9e94795aSAndroid Build Coastguard Worker 253*9e94795aSAndroid Build Coastguard Worker def Print(self, message): 254*9e94795aSAndroid Build Coastguard Worker """Log a message to the screen (if the logs are visible).""" 255*9e94795aSAndroid Build Coastguard Worker self.script.append('ui_print("%s");' % (message,)) 256*9e94795aSAndroid Build Coastguard Worker 257*9e94795aSAndroid Build Coastguard Worker def TunePartition(self, partition, *options): 258*9e94795aSAndroid Build Coastguard Worker fstab = self.fstab 259*9e94795aSAndroid Build Coastguard Worker if fstab: 260*9e94795aSAndroid Build Coastguard Worker p = fstab[partition] 261*9e94795aSAndroid Build Coastguard Worker if p.fs_type not in ("ext2", "ext3", "ext4"): 262*9e94795aSAndroid Build Coastguard Worker raise ValueError("Partition %s cannot be tuned\n" % (partition,)) 263*9e94795aSAndroid Build Coastguard Worker self.script.append( 264*9e94795aSAndroid Build Coastguard Worker 'tune2fs(' + "".join(['"%s", ' % (i,) for i in options]) + 265*9e94795aSAndroid Build Coastguard Worker '%s) || abort("E%d: Failed to tune partition %s");' % ( 266*9e94795aSAndroid Build Coastguard Worker self._GetSlotSuffixDeviceForEntry(p), 267*9e94795aSAndroid Build Coastguard Worker common.ErrorCode.TUNE_PARTITION_FAILURE, partition)) 268*9e94795aSAndroid Build Coastguard Worker 269*9e94795aSAndroid Build Coastguard Worker def FormatPartition(self, partition): 270*9e94795aSAndroid Build Coastguard Worker """Format the given partition, specified by its mount point (eg, 271*9e94795aSAndroid Build Coastguard Worker "/system").""" 272*9e94795aSAndroid Build Coastguard Worker 273*9e94795aSAndroid Build Coastguard Worker fstab = self.fstab 274*9e94795aSAndroid Build Coastguard Worker if fstab: 275*9e94795aSAndroid Build Coastguard Worker p = fstab[partition] 276*9e94795aSAndroid Build Coastguard Worker self.script.append('format("%s", "%s", %s, "%s", "%s");' % 277*9e94795aSAndroid Build Coastguard Worker (p.fs_type, common.PARTITION_TYPES[p.fs_type], 278*9e94795aSAndroid Build Coastguard Worker self._GetSlotSuffixDeviceForEntry(p), 279*9e94795aSAndroid Build Coastguard Worker p.length, p.mount_point)) 280*9e94795aSAndroid Build Coastguard Worker 281*9e94795aSAndroid Build Coastguard Worker def WipeBlockDevice(self, partition): 282*9e94795aSAndroid Build Coastguard Worker if partition not in ("/system", "/vendor"): 283*9e94795aSAndroid Build Coastguard Worker raise ValueError(("WipeBlockDevice doesn't work on %s\n") % (partition,)) 284*9e94795aSAndroid Build Coastguard Worker fstab = self.fstab 285*9e94795aSAndroid Build Coastguard Worker size = self.info.get(partition.lstrip("/") + "_size", None) 286*9e94795aSAndroid Build Coastguard Worker device = self._GetSlotSuffixDeviceForEntry(fstab[partition]) 287*9e94795aSAndroid Build Coastguard Worker 288*9e94795aSAndroid Build Coastguard Worker self.script.append('wipe_block_device(%s, %s);' % (device, size)) 289*9e94795aSAndroid Build Coastguard Worker 290*9e94795aSAndroid Build Coastguard Worker def ApplyPatch(self, srcfile, tgtfile, tgtsize, tgtsha1, *patchpairs): 291*9e94795aSAndroid Build Coastguard Worker """Apply binary patches (in *patchpairs) to the given srcfile to 292*9e94795aSAndroid Build Coastguard Worker produce tgtfile (which may be "-" to indicate overwriting the 293*9e94795aSAndroid Build Coastguard Worker source file. 294*9e94795aSAndroid Build Coastguard Worker 295*9e94795aSAndroid Build Coastguard Worker This edify function is being deprecated in favor of PatchPartition(). It 296*9e94795aSAndroid Build Coastguard Worker will try to redirect calls to PatchPartition() if possible. On unknown / 297*9e94795aSAndroid Build Coastguard Worker invalid inputs, raises an exception. 298*9e94795aSAndroid Build Coastguard Worker """ 299*9e94795aSAndroid Build Coastguard Worker tokens = srcfile.split(':') 300*9e94795aSAndroid Build Coastguard Worker assert (len(tokens) == 6 and tokens[0] == 'EMMC' and tgtfile == '-' and 301*9e94795aSAndroid Build Coastguard Worker len(patchpairs) == 2), \ 302*9e94795aSAndroid Build Coastguard Worker "Failed to handle unknown format. Use PatchPartition() instead." 303*9e94795aSAndroid Build Coastguard Worker 304*9e94795aSAndroid Build Coastguard Worker # Also validity check the args. 305*9e94795aSAndroid Build Coastguard Worker assert tokens[3] == patchpairs[0], \ 306*9e94795aSAndroid Build Coastguard Worker "Found mismatching values for source SHA-1: {} vs {}".format( 307*9e94795aSAndroid Build Coastguard Worker tokens[3], patchpairs[0]) 308*9e94795aSAndroid Build Coastguard Worker assert int(tokens[4]) == tgtsize, \ 309*9e94795aSAndroid Build Coastguard Worker "Found mismatching values for target size: {} vs {}".format( 310*9e94795aSAndroid Build Coastguard Worker tokens[4], tgtsize) 311*9e94795aSAndroid Build Coastguard Worker assert tokens[5] == tgtsha1, \ 312*9e94795aSAndroid Build Coastguard Worker "Found mismatching values for target SHA-1: {} vs {}".format( 313*9e94795aSAndroid Build Coastguard Worker tokens[5], tgtsha1) 314*9e94795aSAndroid Build Coastguard Worker 315*9e94795aSAndroid Build Coastguard Worker source = '{}:{}:{}:{}'.format(tokens[0], tokens[1], tokens[2], tokens[3]) 316*9e94795aSAndroid Build Coastguard Worker target = '{}:{}:{}:{}'.format(tokens[0], tokens[1], tokens[4], tokens[5]) 317*9e94795aSAndroid Build Coastguard Worker patch = patchpairs[1] 318*9e94795aSAndroid Build Coastguard Worker self.PatchPartition(target, source, patch) 319*9e94795aSAndroid Build Coastguard Worker 320*9e94795aSAndroid Build Coastguard Worker def PatchPartition(self, target, source, patch): 321*9e94795aSAndroid Build Coastguard Worker """ 322*9e94795aSAndroid Build Coastguard Worker Applies the patch to the source partition and writes it to target. 323*9e94795aSAndroid Build Coastguard Worker 324*9e94795aSAndroid Build Coastguard Worker Args: 325*9e94795aSAndroid Build Coastguard Worker target: the target arg to patch_partition. Must be in the form of 326*9e94795aSAndroid Build Coastguard Worker foo:bar:baz:quux 327*9e94795aSAndroid Build Coastguard Worker source: the source arg to patch_partition. Must be in the form of 328*9e94795aSAndroid Build Coastguard Worker foo:bar:baz:quux 329*9e94795aSAndroid Build Coastguard Worker patch: the patch arg to patch_partition. Must be an unquoted string. 330*9e94795aSAndroid Build Coastguard Worker """ 331*9e94795aSAndroid Build Coastguard Worker self._CheckSecondTokenNotSlotSuffixed(target, "PatchPartitionExpr") 332*9e94795aSAndroid Build Coastguard Worker self._CheckSecondTokenNotSlotSuffixed(source, "PatchPartitionExpr") 333*9e94795aSAndroid Build Coastguard Worker self.PatchPartitionExpr('"%s"' % target, '"%s"' % source, '"%s"' % patch) 334*9e94795aSAndroid Build Coastguard Worker 335*9e94795aSAndroid Build Coastguard Worker def PatchPartitionExpr(self, target_expr, source_expr, patch_expr): 336*9e94795aSAndroid Build Coastguard Worker """ 337*9e94795aSAndroid Build Coastguard Worker Applies the patch to the source partition and writes it to target. 338*9e94795aSAndroid Build Coastguard Worker 339*9e94795aSAndroid Build Coastguard Worker Args: 340*9e94795aSAndroid Build Coastguard Worker target_expr: an Edify expression that serves as the target arg to 341*9e94795aSAndroid Build Coastguard Worker patch_partition. Must be evaluated to a string in the form of 342*9e94795aSAndroid Build Coastguard Worker foo:bar:baz:quux 343*9e94795aSAndroid Build Coastguard Worker source_expr: an Edify expression that serves as the source arg to 344*9e94795aSAndroid Build Coastguard Worker patch_partition. Must be evaluated to a string in the form of 345*9e94795aSAndroid Build Coastguard Worker foo:bar:baz:quux 346*9e94795aSAndroid Build Coastguard Worker patch_expr: an Edify expression that serves as the patch arg to 347*9e94795aSAndroid Build Coastguard Worker patch_partition. Must be evaluated to a string. 348*9e94795aSAndroid Build Coastguard Worker """ 349*9e94795aSAndroid Build Coastguard Worker self.script.append(self.WordWrap(( 350*9e94795aSAndroid Build Coastguard Worker 'patch_partition({target},\0{source},\0' 351*9e94795aSAndroid Build Coastguard Worker 'package_extract_file({patch})) ||\n' 352*9e94795aSAndroid Build Coastguard Worker ' abort(concat(' 353*9e94795aSAndroid Build Coastguard Worker ' "E{code}: Failed to apply patch to ",{source}));').format( 354*9e94795aSAndroid Build Coastguard Worker target=target_expr, 355*9e94795aSAndroid Build Coastguard Worker source=source_expr, 356*9e94795aSAndroid Build Coastguard Worker patch=patch_expr, 357*9e94795aSAndroid Build Coastguard Worker code=common.ErrorCode.APPLY_PATCH_FAILURE))) 358*9e94795aSAndroid Build Coastguard Worker 359*9e94795aSAndroid Build Coastguard Worker def _GetSlotSuffixDeviceForEntry(self, entry=None): 360*9e94795aSAndroid Build Coastguard Worker """ 361*9e94795aSAndroid Build Coastguard Worker Args: 362*9e94795aSAndroid Build Coastguard Worker entry: the fstab entry of device "foo" 363*9e94795aSAndroid Build Coastguard Worker Returns: 364*9e94795aSAndroid Build Coastguard Worker An edify expression. Caller must not quote result. 365*9e94795aSAndroid Build Coastguard Worker If foo is slot suffixed, it returns 366*9e94795aSAndroid Build Coastguard Worker 'add_slot_suffix("foo")' 367*9e94795aSAndroid Build Coastguard Worker Otherwise it returns 368*9e94795aSAndroid Build Coastguard Worker '"foo"' (quoted) 369*9e94795aSAndroid Build Coastguard Worker """ 370*9e94795aSAndroid Build Coastguard Worker assert entry is not None 371*9e94795aSAndroid Build Coastguard Worker if entry.slotselect: 372*9e94795aSAndroid Build Coastguard Worker return 'add_slot_suffix("%s")' % entry.device 373*9e94795aSAndroid Build Coastguard Worker return '"%s"' % entry.device 374*9e94795aSAndroid Build Coastguard Worker 375*9e94795aSAndroid Build Coastguard Worker def _CheckSecondTokenNotSlotSuffixed(self, s, fn): 376*9e94795aSAndroid Build Coastguard Worker lst = s.split(':') 377*9e94795aSAndroid Build Coastguard Worker assert(len(lst) == 4), "{} does not contain 4 tokens".format(s) 378*9e94795aSAndroid Build Coastguard Worker if self.fstab: 379*9e94795aSAndroid Build Coastguard Worker entry = common.GetEntryForDevice(self.fstab, lst[1]) 380*9e94795aSAndroid Build Coastguard Worker if entry is not None: 381*9e94795aSAndroid Build Coastguard Worker assert not entry.slotselect, \ 382*9e94795aSAndroid Build Coastguard Worker "Use %s because %s is slot suffixed" % (fn, lst[1]) 383*9e94795aSAndroid Build Coastguard Worker 384*9e94795aSAndroid Build Coastguard Worker def WriteRawImage(self, mount_point, fn, mapfn=None): 385*9e94795aSAndroid Build Coastguard Worker """Write the given package file into the partition for the given 386*9e94795aSAndroid Build Coastguard Worker mount point.""" 387*9e94795aSAndroid Build Coastguard Worker 388*9e94795aSAndroid Build Coastguard Worker fstab = self.fstab 389*9e94795aSAndroid Build Coastguard Worker if fstab: 390*9e94795aSAndroid Build Coastguard Worker p = fstab[mount_point] 391*9e94795aSAndroid Build Coastguard Worker partition_type = common.PARTITION_TYPES[p.fs_type] 392*9e94795aSAndroid Build Coastguard Worker device = self._GetSlotSuffixDeviceForEntry(p) 393*9e94795aSAndroid Build Coastguard Worker args = {'device': device, 'fn': fn} 394*9e94795aSAndroid Build Coastguard Worker if partition_type == "EMMC": 395*9e94795aSAndroid Build Coastguard Worker if mapfn: 396*9e94795aSAndroid Build Coastguard Worker args["map"] = mapfn 397*9e94795aSAndroid Build Coastguard Worker self.script.append( 398*9e94795aSAndroid Build Coastguard Worker 'package_extract_file("%(fn)s", %(device)s, "%(map)s");' % args) 399*9e94795aSAndroid Build Coastguard Worker else: 400*9e94795aSAndroid Build Coastguard Worker self.script.append( 401*9e94795aSAndroid Build Coastguard Worker 'package_extract_file("%(fn)s", %(device)s);' % args) 402*9e94795aSAndroid Build Coastguard Worker else: 403*9e94795aSAndroid Build Coastguard Worker raise ValueError( 404*9e94795aSAndroid Build Coastguard Worker "don't know how to write \"%s\" partitions" % p.fs_type) 405*9e94795aSAndroid Build Coastguard Worker 406*9e94795aSAndroid Build Coastguard Worker def AppendExtra(self, extra): 407*9e94795aSAndroid Build Coastguard Worker """Append text verbatim to the output script.""" 408*9e94795aSAndroid Build Coastguard Worker self.script.append(extra) 409*9e94795aSAndroid Build Coastguard Worker 410*9e94795aSAndroid Build Coastguard Worker def Unmount(self, mount_point): 411*9e94795aSAndroid Build Coastguard Worker self.script.append('unmount("%s");' % mount_point) 412*9e94795aSAndroid Build Coastguard Worker self.mounts.remove(mount_point) 413*9e94795aSAndroid Build Coastguard Worker 414*9e94795aSAndroid Build Coastguard Worker def UnmountAll(self): 415*9e94795aSAndroid Build Coastguard Worker for p in sorted(self.mounts): 416*9e94795aSAndroid Build Coastguard Worker self.script.append('unmount("%s");' % (p,)) 417*9e94795aSAndroid Build Coastguard Worker self.mounts = set() 418*9e94795aSAndroid Build Coastguard Worker 419*9e94795aSAndroid Build Coastguard Worker def AddToZip(self, input_zip, output_zip, input_path=None): 420*9e94795aSAndroid Build Coastguard Worker """Write the accumulated script to the output_zip file. input_zip 421*9e94795aSAndroid Build Coastguard Worker is used as the source for the 'updater' binary needed to run 422*9e94795aSAndroid Build Coastguard Worker script. If input_path is not None, it will be used as a local 423*9e94795aSAndroid Build Coastguard Worker path for the binary instead of input_zip.""" 424*9e94795aSAndroid Build Coastguard Worker 425*9e94795aSAndroid Build Coastguard Worker self.UnmountAll() 426*9e94795aSAndroid Build Coastguard Worker 427*9e94795aSAndroid Build Coastguard Worker common.ZipWriteStr(output_zip, "META-INF/com/google/android/updater-script", 428*9e94795aSAndroid Build Coastguard Worker "\n".join(self.script) + "\n") 429*9e94795aSAndroid Build Coastguard Worker 430*9e94795aSAndroid Build Coastguard Worker if input_path is None: 431*9e94795aSAndroid Build Coastguard Worker data = input_zip.read("OTA/bin/updater") 432*9e94795aSAndroid Build Coastguard Worker else: 433*9e94795aSAndroid Build Coastguard Worker data = open(input_path, "rb").read() 434*9e94795aSAndroid Build Coastguard Worker common.ZipWriteStr(output_zip, "META-INF/com/google/android/update-binary", 435*9e94795aSAndroid Build Coastguard Worker data, perms=0o755) 436