blob: f8247ee1968f387cb3516f581905bc69bca20f9c [file] [log] [blame]
Doug Zongkerc494d7c2009-06-18 08:43:44 -07001# Copyright (C) 2009 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
Doug Zongkerc494d7c2009-06-18 08:43:44 -070015import re
16
17import common
18
19class EdifyGenerator(object):
20 """Class to generate scripts in the 'edify' recovery script language
21 used from donut onwards."""
22
Tao Bao34b47bf2015-06-22 19:17:41 -070023 def __init__(self, version, info, fstab=None):
Doug Zongkerc494d7c2009-06-18 08:43:44 -070024 self.script = []
25 self.mounts = set()
Tao Baod8d14be2016-02-04 14:26:02 -080026 self._required_cache = 0
Doug Zongkerc494d7c2009-06-18 08:43:44 -070027 self.version = version
Doug Zongkerb4c7d322010-07-01 15:30:11 -070028 self.info = info
Tao Bao34b47bf2015-06-22 19:17:41 -070029 if fstab is None:
30 self.fstab = self.info.get("fstab", None)
31 else:
32 self.fstab = fstab
Doug Zongkerc494d7c2009-06-18 08:43:44 -070033
Tao Baod8d14be2016-02-04 14:26:02 -080034 @property
35 def required_cache(self):
36 """Return the minimum cache size to apply the update."""
37 return self._required_cache
38
Doug Zongkerc494d7c2009-06-18 08:43:44 -070039 @staticmethod
Dan Albert8b72aef2015-03-23 19:13:21 -070040 def WordWrap(cmd, linelen=80):
Doug Zongkerc494d7c2009-06-18 08:43:44 -070041 """'cmd' should be a function call with null characters after each
42 parameter (eg, "somefun(foo,\0bar,\0baz)"). This function wraps cmd
43 to a given line length, replacing nulls with spaces and/or newlines
44 to format it nicely."""
45 indent = cmd.index("(")+1
46 out = []
47 first = True
48 x = re.compile("^(.{,%d})\0" % (linelen-indent,))
49 while True:
50 if not first:
51 out.append(" " * indent)
52 first = False
53 m = x.search(cmd)
54 if not m:
55 parts = cmd.split("\0", 1)
56 out.append(parts[0]+"\n")
57 if len(parts) == 1:
58 break
59 else:
60 cmd = parts[1]
61 continue
62 out.append(m.group(1)+"\n")
63 cmd = cmd[m.end():]
64
65 return "".join(out).replace("\0", " ").rstrip("\n")
66
67 def AppendScript(self, other):
68 """Append the contents of another script (which should be created
69 with temporary=True) to this one."""
70 self.script.extend(other.script)
71
Tao Bao481bab82017-12-21 11:23:09 -080072 def AssertOemProperty(self, name, values, oem_no_mount):
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -080073 """Assert that a property on the OEM paritition matches allowed values."""
Michael Runge6e836112014-04-15 17:40:21 -070074 if not name:
75 raise ValueError("must specify an OEM property")
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -080076 if not values:
Michael Runge6e836112014-04-15 17:40:21 -070077 raise ValueError("must specify the OEM value")
Tao Bao481bab82017-12-21 11:23:09 -080078
79 if oem_no_mount:
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -080080 get_prop_command = 'getprop("%s")' % name
Tao Bao8608cde2016-02-25 19:49:55 -080081 else:
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -080082 get_prop_command = 'file_getprop("/oem/oem.prop", "%s")' % name
83
84 cmd = ''
85 for value in values:
86 cmd += '%s == "%s" || ' % (get_prop_command, value)
87 cmd += (
88 'abort("E{code}: This package expects the value \\"{values}\\" for '
89 '\\"{name}\\"; this has value \\"" + '
90 '{get_prop_command} + "\\".");').format(
Abhishek Nigam1dfca462023-11-08 02:21:39 +000091 code=common.ErrorCode.OEM_PROP_MISMATCH,
Alain Vongsouvanh7f804ba2017-02-16 13:06:55 -080092 get_prop_command=get_prop_command, name=name,
93 values='\\" or \\"'.join(values))
Michael Runge6e836112014-04-15 17:40:21 -070094 self.script.append(cmd)
95
Doug Zongkerc494d7c2009-06-18 08:43:44 -070096 def AssertSomeFingerprint(self, *fp):
Doug Zongkeraf845252014-05-09 08:29:05 -070097 """Assert that the current recovery build fingerprint is one of *fp."""
Doug Zongkerc494d7c2009-06-18 08:43:44 -070098 if not fp:
99 raise ValueError("must specify some fingerprints")
Dan Albert8b72aef2015-03-23 19:13:21 -0700100 cmd = (' ||\n '.join([('getprop("ro.build.fingerprint") == "%s"') % i
101 for i in fp]) +
Tianjie Xu209db462016-05-24 17:34:52 -0700102 ' ||\n abort("E%d: Package expects build fingerprint of %s; '
103 'this device has " + getprop("ro.build.fingerprint") + ".");') % (
Abhishek Nigam1dfca462023-11-08 02:21:39 +0000104 common.ErrorCode.FINGERPRINT_MISMATCH, " or ".join(fp))
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700105 self.script.append(cmd)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700106
Michael Runge6e836112014-04-15 17:40:21 -0700107 def AssertSomeThumbprint(self, *fp):
Doug Zongkeraf845252014-05-09 08:29:05 -0700108 """Assert that the current recovery build thumbprint is one of *fp."""
Geremy Condra36bd3652014-02-06 19:45:10 -0800109 if not fp:
Michael Runge6e836112014-04-15 17:40:21 -0700110 raise ValueError("must specify some thumbprints")
Dan Albert8b72aef2015-03-23 19:13:21 -0700111 cmd = (' ||\n '.join([('getprop("ro.build.thumbprint") == "%s"') % i
112 for i in fp]) +
Tianjie Xu209db462016-05-24 17:34:52 -0700113 ' ||\n abort("E%d: Package expects build thumbprint of %s; this '
Dan Albert8b72aef2015-03-23 19:13:21 -0700114 'device has " + getprop("ro.build.thumbprint") + ".");') % (
Abhishek Nigam1dfca462023-11-08 02:21:39 +0000115 common.ErrorCode.THUMBPRINT_MISMATCH, " or ".join(fp))
Geremy Condra36bd3652014-02-06 19:45:10 -0800116 self.script.append(cmd)
117
Tao Bao3e30d972016-03-15 13:20:19 -0700118 def AssertFingerprintOrThumbprint(self, fp, tp):
119 """Assert that the current recovery build fingerprint is fp, or thumbprint
120 is tp."""
121 cmd = ('getprop("ro.build.fingerprint") == "{fp}" ||\n'
122 ' getprop("ro.build.thumbprint") == "{tp}" ||\n'
123 ' abort("Package expects build fingerprint of {fp} or '
124 'thumbprint of {tp}; this device has a fingerprint of " '
Tao Baod2d01e52017-06-05 12:25:46 -0700125 '+ getprop("ro.build.fingerprint") + " and a thumbprint of " '
Tao Bao3e30d972016-03-15 13:20:19 -0700126 '+ getprop("ro.build.thumbprint") + ".");').format(fp=fp, tp=tp)
127 self.script.append(cmd)
128
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700129 def AssertOlderBuild(self, timestamp, timestamp_text):
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700130 """Assert that the build on the device is older (or the same as)
131 the given timestamp."""
Doug Zongker0d92f1f2013-06-03 12:07:12 -0700132 self.script.append(
133 ('(!less_than_int(%s, getprop("ro.build.date.utc"))) || '
Tianjie Xu209db462016-05-24 17:34:52 -0700134 'abort("E%d: Can\'t install this package (%s) over newer '
Tao Bao76def242017-11-21 09:25:31 -0800135 'build (" + getprop("ro.build.date") + ").");') % (
Abhishek Nigam1dfca462023-11-08 02:21:39 +0000136 timestamp, common.ErrorCode.OLDER_BUILD, timestamp_text))
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700137
138 def AssertDevice(self, device):
139 """Assert that the device identifier is the given string."""
Steve Kondik21231df2010-04-21 11:39:48 -0400140 cmd = ('assert(' +
141 ' || \0'.join(['getprop("ro.product.device") == "%s" || getprop("ro.build.product") == "%s"'
142 % (i, i) for i in device.split(",")]) +
143 ' || abort("E%d: This package is for device: %s; ' +
144 'this device is " + getprop("ro.product.device") + ".");' +
145 ');') % (common.ErrorCode.DEVICE_MISMATCH, device)
146 self.script.append(self.WordWrap(cmd))
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700147
148 def AssertSomeBootloader(self, *bootloaders):
149 """Asert that the bootloader version is one of *bootloaders."""
150 cmd = ("assert(" +
151 " ||\0".join(['getprop("ro.bootloader") == "%s"' % (b,)
152 for b in bootloaders]) +
153 ");")
Dan Albert8b72aef2015-03-23 19:13:21 -0700154 self.script.append(self.WordWrap(cmd))
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700155
156 def ShowProgress(self, frac, dur):
157 """Update the progress bar, advancing it over 'frac' over the next
Doug Zongker881dd402009-09-20 14:03:55 -0700158 'dur' seconds. 'dur' may be zero to advance it via SetProgress
159 commands instead of by time."""
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700160 self.script.append("show_progress(%f, %d);" % (frac, int(dur)))
161
Doug Zongker881dd402009-09-20 14:03:55 -0700162 def SetProgress(self, frac):
163 """Set the position of the progress bar within the chunk defined
164 by the most recent ShowProgress call. 'frac' should be in
165 [0,1]."""
166 self.script.append("set_progress(%f);" % (frac,))
167
Tao Bao51216552018-08-26 11:53:15 -0700168 def PatchCheck(self, filename, *sha1): # pylint: disable=unused-argument
169 """Checks that the given partition has the desired checksum.
170
171 The call to this function is being deprecated in favor of
172 PatchPartitionCheck(). It will try to parse and handle the old format,
173 unless the format is unknown.
174 """
175 tokens = filename.split(':')
176 assert len(tokens) == 6 and tokens[0] == 'EMMC', \
177 "Failed to handle unknown format. Use PatchPartitionCheck() instead."
178 source = '{}:{}:{}:{}'.format(tokens[0], tokens[1], tokens[2], tokens[3])
179 target = '{}:{}:{}:{}'.format(tokens[0], tokens[1], tokens[4], tokens[5])
180 self.PatchPartitionCheck(target, source)
181
182 def PatchPartitionCheck(self, target, source):
183 """Checks whether updater can patch the given partitions.
184
185 It checks the checksums of the given partitions. If none of them matches the
186 expected checksum, updater will additionally look for a backup on /cache.
187 """
Yifan Hongbdb32012020-05-07 12:38:53 -0700188 self._CheckSecondTokenNotSlotSuffixed(target, "PatchPartitionExprCheck")
189 self._CheckSecondTokenNotSlotSuffixed(source, "PatchPartitionExprCheck")
190 self.PatchPartitionExprCheck('"%s"' % target, '"%s"' % source)
191
192 def PatchPartitionExprCheck(self, target_expr, source_expr):
193 """Checks whether updater can patch the given partitions.
194
195 It checks the checksums of the given partitions. If none of them matches the
196 expected checksum, updater will additionally look for a backup on /cache.
197
198 Args:
199 target_expr: an Edify expression that serves as the target arg to
200 patch_partition. Must be evaluated to a string in the form of
201 foo:bar:baz:quux
202 source_expr: an Edify expression that serves as the source arg to
203 patch_partition. Must be evaluated to a string in the form of
204 foo:bar:baz:quux
205 """
Tao Bao51216552018-08-26 11:53:15 -0700206 self.script.append(self.WordWrap((
Yifan Hongbdb32012020-05-07 12:38:53 -0700207 'patch_partition_check({target},\0{source}) ||\n abort('
208 'concat("E{code}: \\"",{target},"\\" or \\"",{source},"\\" has '
209 'unexpected contents."));').format(
210 target=target_expr,
211 source=source_expr,
Abhishek Nigam1dfca462023-11-08 02:21:39 +0000212 code=common.ErrorCode.BAD_PATCH_FILE)))
Doug Zongkerc8d446b2010-02-22 15:41:53 -0800213
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700214 def CacheFreeSpaceCheck(self, amount):
215 """Check that there's at least 'amount' space that can be made
216 available on /cache."""
Tao Baod8d14be2016-02-04 14:26:02 -0800217 self._required_cache = max(self._required_cache, amount)
Tianjie Xu209db462016-05-24 17:34:52 -0700218 self.script.append(('apply_patch_space(%d) || abort("E%d: Not enough free '
219 'space on /cache to apply patches.");') % (
220 amount,
Abhishek Nigam1dfca462023-11-08 02:21:39 +0000221 common.ErrorCode.INSUFFICIENT_CACHE_SPACE))
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700222
Michael Runge7cd99ba2014-10-22 17:21:48 -0700223 def Mount(self, mount_point, mount_options_by_format=""):
224 """Mount the partition with the given mount_point.
225 mount_options_by_format:
226 [fs_type=option[,option]...[|fs_type=option[,option]...]...]
227 where option is optname[=optvalue]
228 E.g. ext4=barrier=1,nodelalloc,errors=panic|f2fs=errors=recover
229 """
Tao Bao34b47bf2015-06-22 19:17:41 -0700230 fstab = self.fstab
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700231 if fstab:
232 p = fstab[mount_point]
Michael Runge7cd99ba2014-10-22 17:21:48 -0700233 mount_dict = {}
234 if mount_options_by_format is not None:
235 for option in mount_options_by_format.split("|"):
236 if "=" in option:
237 key, value = option.split("=", 1)
238 mount_dict[key] = value
Tao Baodf06e962015-06-10 12:32:41 -0700239 mount_flags = mount_dict.get(p.fs_type, "")
240 if p.context is not None:
241 mount_flags = p.context + ("," + mount_flags if mount_flags else "")
Yifan Hongbdb32012020-05-07 12:38:53 -0700242 self.script.append('mount("%s", "%s", %s, "%s", "%s");' % (
Abhishek Nigamb148ac22023-11-08 02:19:31 +0000243 p.fs_type, common.PARTITION_TYPES[p.fs_type],
Yifan Hongbdb32012020-05-07 12:38:53 -0700244 self._GetSlotSuffixDeviceForEntry(p),
Tao Baodf06e962015-06-10 12:32:41 -0700245 p.mount_point, mount_flags))
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700246 self.mounts.add(p.mount_point)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700247
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700248 def Comment(self, comment):
249 """Write a comment into the update script."""
250 self.script.append("")
251 for i in comment.split("\n"):
252 self.script.append("# " + i)
253 self.script.append("")
254
255 def Print(self, message):
256 """Log a message to the screen (if the logs are visible)."""
257 self.script.append('ui_print("%s");' % (message,))
258
Michael Runge3e286642014-11-21 00:46:03 -0800259 def TunePartition(self, partition, *options):
Tao Bao34b47bf2015-06-22 19:17:41 -0700260 fstab = self.fstab
Michael Runge3e286642014-11-21 00:46:03 -0800261 if fstab:
262 p = fstab[partition]
Dan Albert8b72aef2015-03-23 19:13:21 -0700263 if p.fs_type not in ("ext2", "ext3", "ext4"):
Michael Runge3e286642014-11-21 00:46:03 -0800264 raise ValueError("Partition %s cannot be tuned\n" % (partition,))
Dan Albert8b72aef2015-03-23 19:13:21 -0700265 self.script.append(
266 'tune2fs(' + "".join(['"%s", ' % (i,) for i in options]) +
Yifan Hongbdb32012020-05-07 12:38:53 -0700267 '%s) || abort("E%d: Failed to tune partition %s");' % (
268 self._GetSlotSuffixDeviceForEntry(p),
Abhishek Nigam1dfca462023-11-08 02:21:39 +0000269 common.ErrorCode.TUNE_PARTITION_FAILURE, partition))
Michael Runge3e286642014-11-21 00:46:03 -0800270
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700271 def FormatPartition(self, partition):
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700272 """Format the given partition, specified by its mount point (eg,
273 "/system")."""
274
Tao Bao34b47bf2015-06-22 19:17:41 -0700275 fstab = self.fstab
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700276 if fstab:
277 p = fstab[partition]
Yifan Hongbdb32012020-05-07 12:38:53 -0700278 self.script.append('format("%s", "%s", %s, "%s", "%s");' %
Abhishek Nigamb148ac22023-11-08 02:19:31 +0000279 (p.fs_type, common.PARTITION_TYPES[p.fs_type],
Yifan Hongbdb32012020-05-07 12:38:53 -0700280 self._GetSlotSuffixDeviceForEntry(p),
281 p.length, p.mount_point))
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700282
Doug Zongker5fad2032014-02-24 08:13:45 -0800283 def WipeBlockDevice(self, partition):
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700284 if partition not in ("/system", "/vendor"):
285 raise ValueError(("WipeBlockDevice doesn't work on %s\n") % (partition,))
Tao Bao34b47bf2015-06-22 19:17:41 -0700286 fstab = self.fstab
Doug Zongkerc8b4e842014-06-16 15:16:31 -0700287 size = self.info.get(partition.lstrip("/") + "_size", None)
Yifan Hongbdb32012020-05-07 12:38:53 -0700288 device = self._GetSlotSuffixDeviceForEntry(fstab[partition])
Doug Zongker5fad2032014-02-24 08:13:45 -0800289
Yifan Hongbdb32012020-05-07 12:38:53 -0700290 self.script.append('wipe_block_device(%s, %s);' % (device, size))
Doug Zongker5fad2032014-02-24 08:13:45 -0800291
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700292 def ApplyPatch(self, srcfile, tgtfile, tgtsize, tgtsha1, *patchpairs):
293 """Apply binary patches (in *patchpairs) to the given srcfile to
294 produce tgtfile (which may be "-" to indicate overwriting the
Tao Bao51216552018-08-26 11:53:15 -0700295 source file.
296
297 This edify function is being deprecated in favor of PatchPartition(). It
298 will try to redirect calls to PatchPartition() if possible. On unknown /
299 invalid inputs, raises an exception.
300 """
301 tokens = srcfile.split(':')
302 assert (len(tokens) == 6 and tokens[0] == 'EMMC' and tgtfile == '-' and
303 len(patchpairs) == 2), \
304 "Failed to handle unknown format. Use PatchPartition() instead."
305
Kelvin Zhangc693d952020-07-22 19:21:22 -0400306 # Also validity check the args.
Tao Bao51216552018-08-26 11:53:15 -0700307 assert tokens[3] == patchpairs[0], \
308 "Found mismatching values for source SHA-1: {} vs {}".format(
309 tokens[3], patchpairs[0])
310 assert int(tokens[4]) == tgtsize, \
311 "Found mismatching values for target size: {} vs {}".format(
312 tokens[4], tgtsize)
313 assert tokens[5] == tgtsha1, \
314 "Found mismatching values for target SHA-1: {} vs {}".format(
315 tokens[5], tgtsha1)
316
317 source = '{}:{}:{}:{}'.format(tokens[0], tokens[1], tokens[2], tokens[3])
318 target = '{}:{}:{}:{}'.format(tokens[0], tokens[1], tokens[4], tokens[5])
319 patch = patchpairs[1]
320 self.PatchPartition(target, source, patch)
321
322 def PatchPartition(self, target, source, patch):
Yifan Hongbdb32012020-05-07 12:38:53 -0700323 """
324 Applies the patch to the source partition and writes it to target.
325
326 Args:
327 target: the target arg to patch_partition. Must be in the form of
328 foo:bar:baz:quux
329 source: the source arg to patch_partition. Must be in the form of
330 foo:bar:baz:quux
331 patch: the patch arg to patch_partition. Must be an unquoted string.
332 """
333 self._CheckSecondTokenNotSlotSuffixed(target, "PatchPartitionExpr")
334 self._CheckSecondTokenNotSlotSuffixed(source, "PatchPartitionExpr")
335 self.PatchPartitionExpr('"%s"' % target, '"%s"' % source, '"%s"' % patch)
336
337 def PatchPartitionExpr(self, target_expr, source_expr, patch_expr):
338 """
339 Applies the patch to the source partition and writes it to target.
340
341 Args:
342 target_expr: an Edify expression that serves as the target arg to
343 patch_partition. Must be evaluated to a string in the form of
344 foo:bar:baz:quux
345 source_expr: an Edify expression that serves as the source arg to
346 patch_partition. Must be evaluated to a string in the form of
347 foo:bar:baz:quux
348 patch_expr: an Edify expression that serves as the patch arg to
349 patch_partition. Must be evaluated to a string.
350 """
Tao Bao51216552018-08-26 11:53:15 -0700351 self.script.append(self.WordWrap((
Yifan Hongbdb32012020-05-07 12:38:53 -0700352 'patch_partition({target},\0{source},\0'
353 'package_extract_file({patch})) ||\n'
354 ' abort(concat('
355 ' "E{code}: Failed to apply patch to ",{source}));').format(
356 target=target_expr,
357 source=source_expr,
358 patch=patch_expr,
Abhishek Nigam1dfca462023-11-08 02:21:39 +0000359 code=common.ErrorCode.APPLY_PATCH_FAILURE)))
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700360
Yifan Hongbdb32012020-05-07 12:38:53 -0700361 def _GetSlotSuffixDeviceForEntry(self, entry=None):
362 """
363 Args:
364 entry: the fstab entry of device "foo"
365 Returns:
366 An edify expression. Caller must not quote result.
367 If foo is slot suffixed, it returns
368 'add_slot_suffix("foo")'
369 Otherwise it returns
370 '"foo"' (quoted)
371 """
372 assert entry is not None
373 if entry.slotselect:
374 return 'add_slot_suffix("%s")' % entry.device
375 return '"%s"' % entry.device
376
377 def _CheckSecondTokenNotSlotSuffixed(self, s, fn):
378 lst = s.split(':')
P.Adarsh Reddy1ed2d662020-07-01 00:30:59 +0530379 assert(len(lst) == 4), "{} does not contain 4 tokens".format(s)
Yifan Hongbdb32012020-05-07 12:38:53 -0700380 if self.fstab:
P.Adarsh Reddy1ed2d662020-07-01 00:30:59 +0530381 entry = common.GetEntryForDevice(self.fstab, lst[1])
Yifan Hongbdb32012020-05-07 12:38:53 -0700382 if entry is not None:
383 assert not entry.slotselect, \
P.Adarsh Reddy1ed2d662020-07-01 00:30:59 +0530384 "Use %s because %s is slot suffixed" % (fn, lst[1])
Yifan Hongbdb32012020-05-07 12:38:53 -0700385
Doug Zongker5fad2032014-02-24 08:13:45 -0800386 def WriteRawImage(self, mount_point, fn, mapfn=None):
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700387 """Write the given package file into the partition for the given
388 mount point."""
Doug Zongkerb4c7d322010-07-01 15:30:11 -0700389
Tao Bao34b47bf2015-06-22 19:17:41 -0700390 fstab = self.fstab
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700391 if fstab:
392 p = fstab[mount_point]
Abhishek Nigamb148ac22023-11-08 02:19:31 +0000393 partition_type = common.PARTITION_TYPES[p.fs_type]
Yifan Hongbdb32012020-05-07 12:38:53 -0700394 device = self._GetSlotSuffixDeviceForEntry(p)
395 args = {'device': device, 'fn': fn}
Elliott Hughes305b0882016-06-15 17:04:54 -0700396 if partition_type == "EMMC":
Doug Zongker5fad2032014-02-24 08:13:45 -0800397 if mapfn:
398 args["map"] = mapfn
399 self.script.append(
Yifan Hongbdb32012020-05-07 12:38:53 -0700400 'package_extract_file("%(fn)s", %(device)s, "%(map)s");' % args)
Doug Zongker5fad2032014-02-24 08:13:45 -0800401 else:
402 self.script.append(
Yifan Hongbdb32012020-05-07 12:38:53 -0700403 'package_extract_file("%(fn)s", %(device)s);' % args)
Doug Zongker9ce0fb62010-09-20 18:04:41 -0700404 else:
Dan Albert8b72aef2015-03-23 19:13:21 -0700405 raise ValueError(
406 "don't know how to write \"%s\" partitions" % p.fs_type)
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700407
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700408 def AppendExtra(self, extra):
409 """Append text verbatim to the output script."""
410 self.script.append(extra)
411
Michael Runge63f01de2014-10-28 19:24:19 -0700412 def Unmount(self, mount_point):
Dan Albert8b72aef2015-03-23 19:13:21 -0700413 self.script.append('unmount("%s");' % mount_point)
414 self.mounts.remove(mount_point)
Michael Runge63f01de2014-10-28 19:24:19 -0700415
Doug Zongker14833602010-02-02 13:12:04 -0800416 def UnmountAll(self):
417 for p in sorted(self.mounts):
418 self.script.append('unmount("%s");' % (p,))
419 self.mounts = set()
420
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700421 def AddToZip(self, input_zip, output_zip, input_path=None):
422 """Write the accumulated script to the output_zip file. input_zip
423 is used as the source for the 'updater' binary needed to run
424 script. If input_path is not None, it will be used as a local
425 path for the binary instead of input_zip."""
426
Doug Zongker14833602010-02-02 13:12:04 -0800427 self.UnmountAll()
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700428
429 common.ZipWriteStr(output_zip, "META-INF/com/google/android/updater-script",
430 "\n".join(self.script) + "\n")
431
432 if input_path is None:
433 data = input_zip.read("OTA/bin/updater")
434 else:
Doug Zongker25568482014-03-03 10:21:27 -0800435 data = open(input_path, "rb").read()
Doug Zongkerc494d7c2009-06-18 08:43:44 -0700436 common.ZipWriteStr(output_zip, "META-INF/com/google/android/update-binary",
Dan Albert8b72aef2015-03-23 19:13:21 -0700437 data, perms=0o755)