PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/build/tools/releasetools/edify_generator.py

https://gitlab.com/brian0218/rk3066_r-box_android4.2.2_sdk
Python | 280 lines | 264 code | 3 blank | 13 comment | 0 complexity | d9c17a928e33d7818636500c3921af44 MD5 | raw file
  1. # 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. import os
  15. import re
  16. import common
  17. class EdifyGenerator(object):
  18. """Class to generate scripts in the 'edify' recovery script language
  19. used from donut onwards."""
  20. def __init__(self, version, info):
  21. self.script = []
  22. self.mounts = set()
  23. self.version = version
  24. self.info = info
  25. def MakeTemporary(self):
  26. """Make a temporary script object whose commands can latter be
  27. appended to the parent script with AppendScript(). Used when the
  28. caller wants to generate script commands out-of-order."""
  29. x = EdifyGenerator(self.version, self.info)
  30. x.mounts = self.mounts
  31. return x
  32. @staticmethod
  33. def _WordWrap(cmd, linelen=80):
  34. """'cmd' should be a function call with null characters after each
  35. parameter (eg, "somefun(foo,\0bar,\0baz)"). This function wraps cmd
  36. to a given line length, replacing nulls with spaces and/or newlines
  37. to format it nicely."""
  38. indent = cmd.index("(")+1
  39. out = []
  40. first = True
  41. x = re.compile("^(.{,%d})\0" % (linelen-indent,))
  42. while True:
  43. if not first:
  44. out.append(" " * indent)
  45. first = False
  46. m = x.search(cmd)
  47. if not m:
  48. parts = cmd.split("\0", 1)
  49. out.append(parts[0]+"\n")
  50. if len(parts) == 1:
  51. break
  52. else:
  53. cmd = parts[1]
  54. continue
  55. out.append(m.group(1)+"\n")
  56. cmd = cmd[m.end():]
  57. return "".join(out).replace("\0", " ").rstrip("\n")
  58. def AppendScript(self, other):
  59. """Append the contents of another script (which should be created
  60. with temporary=True) to this one."""
  61. self.script.extend(other.script)
  62. def AssertSomeFingerprint(self, *fp):
  63. """Assert that the current system build fingerprint is one of *fp."""
  64. if not fp:
  65. raise ValueError("must specify some fingerprints")
  66. cmd = ('assert(' +
  67. ' ||\0'.join([('file_getprop("/system/build.prop", '
  68. '"ro.build.fingerprint") == "%s"')
  69. % i for i in fp]) +
  70. ');')
  71. self.script.append(self._WordWrap(cmd))
  72. def AssertOlderBuild(self, timestamp):
  73. """Assert that the build on the device is older (or the same as)
  74. the given timestamp."""
  75. self.script.append(('assert(!less_than_int(%s, '
  76. 'getprop("ro.build.date.utc")));') % (timestamp,))
  77. def AssertDevice(self, device):
  78. """Assert that the device identifier is the given string."""
  79. cmd = ('assert(getprop("ro.product.device") == "%s" ||\0'
  80. 'getprop("ro.build.product") == "%s");' % (device, device))
  81. self.script.append(self._WordWrap(cmd))
  82. def AssertSomeBootloader(self, *bootloaders):
  83. """Asert that the bootloader version is one of *bootloaders."""
  84. cmd = ("assert(" +
  85. " ||\0".join(['getprop("ro.bootloader") == "%s"' % (b,)
  86. for b in bootloaders]) +
  87. ");")
  88. self.script.append(self._WordWrap(cmd))
  89. def ShowProgress(self, frac, dur):
  90. """Update the progress bar, advancing it over 'frac' over the next
  91. 'dur' seconds. 'dur' may be zero to advance it via SetProgress
  92. commands instead of by time."""
  93. self.script.append("show_progress(%f, %d);" % (frac, int(dur)))
  94. def SetProgress(self, frac):
  95. """Set the position of the progress bar within the chunk defined
  96. by the most recent ShowProgress call. 'frac' should be in
  97. [0,1]."""
  98. self.script.append("set_progress(%f);" % (frac,))
  99. def PatchCheck(self, filename, *sha1):
  100. """Check that the given file (or MTD reference) has one of the
  101. given *sha1 hashes, checking the version saved in cache if the
  102. file does not match."""
  103. self.script.append('assert(apply_patch_check("%s"' % (filename,) +
  104. "".join([', "%s"' % (i,) for i in sha1]) +
  105. '));')
  106. def FileCheck(self, filename, *sha1):
  107. """Check that the given file (or MTD reference) has one of the
  108. given *sha1 hashes."""
  109. self.script.append('assert(sha1_check(read_file("%s")' % (filename,) +
  110. "".join([', "%s"' % (i,) for i in sha1]) +
  111. '));')
  112. def CacheFreeSpaceCheck(self, amount):
  113. """Check that there's at least 'amount' space that can be made
  114. available on /cache."""
  115. self.script.append("assert(apply_patch_space(%d));" % (amount,))
  116. def Mount(self, mount_point):
  117. """Mount the partition with the given mount_point."""
  118. fstab = self.info.get("fstab", None)
  119. if fstab:
  120. p = fstab[mount_point]
  121. self.script.append('mount("%s", "%s", "%s", "%s");' %
  122. (p.fs_type, common.PARTITION_TYPES[p.fs_type],
  123. p.device, p.mount_point))
  124. self.mounts.add(p.mount_point)
  125. def UnpackPackageDir(self, src, dst):
  126. """Unpack a given directory from the OTA package into the given
  127. destination directory."""
  128. self.script.append('package_extract_dir("%s", "%s");' % (src, dst))
  129. def Comment(self, comment):
  130. """Write a comment into the update script."""
  131. self.script.append("")
  132. for i in comment.split("\n"):
  133. self.script.append("# " + i)
  134. self.script.append("")
  135. def Print(self, message):
  136. """Log a message to the screen (if the logs are visible)."""
  137. self.script.append('ui_print("%s");' % (message,))
  138. def FormatPartition(self, partition):
  139. """Format the given partition, specified by its mount point (eg,
  140. "/system")."""
  141. reserve_size = 0
  142. fstab = self.info.get("fstab", None)
  143. if fstab:
  144. p = fstab[partition]
  145. self.script.append('format("%s", "%s", "%s", "%s", "%s");' %
  146. (p.fs_type, common.PARTITION_TYPES[p.fs_type],
  147. p.device, p.length, p.mount_point))
  148. def DeleteFiles(self, file_list):
  149. """Delete all files in file_list."""
  150. if not file_list: return
  151. cmd = "delete(" + ",\0".join(['"%s"' % (i,) for i in file_list]) + ");"
  152. self.script.append(self._WordWrap(cmd))
  153. def ApplyPatch(self, srcfile, tgtfile, tgtsize, tgtsha1, *patchpairs):
  154. """Apply binary patches (in *patchpairs) to the given srcfile to
  155. produce tgtfile (which may be "-" to indicate overwriting the
  156. source file."""
  157. if len(patchpairs) % 2 != 0 or len(patchpairs) == 0:
  158. raise ValueError("bad patches given to ApplyPatch")
  159. cmd = ['apply_patch("%s",\0"%s",\0%s,\0%d'
  160. % (srcfile, tgtfile, tgtsha1, tgtsize)]
  161. for i in range(0, len(patchpairs), 2):
  162. cmd.append(',\0%s, package_extract_file("%s")' % patchpairs[i:i+2])
  163. cmd.append(');')
  164. cmd = "".join(cmd)
  165. self.script.append(self._WordWrap(cmd))
  166. def WriteRawImage(self, mount_point, fn):
  167. """Write the given package file into the partition for the given
  168. mount point."""
  169. fstab = self.info["fstab"]
  170. if fstab:
  171. p = fstab[mount_point]
  172. partition_type = common.PARTITION_TYPES[p.fs_type]
  173. args = {'device': p.device, 'fn': fn}
  174. if partition_type == "MTD":
  175. self.script.append(
  176. 'write_raw_image(package_extract_file("%(fn)s"), "%(device)s");'
  177. % args)
  178. elif partition_type == "EMMC":
  179. self.script.append(
  180. 'package_extract_file("%(fn)s", "%(device)s");' % args)
  181. else:
  182. raise ValueError("don't know how to write \"%s\" partitions" % (p.fs_type,))
  183. def WriteRawParameterImage(self, mount_point, fn):
  184. """Write the given package file into the partition for the given
  185. mount point."""
  186. fstab = self.info["fstab"]
  187. if fstab:
  188. p = fstab[mount_point]
  189. partition_type = common.PARTITION_TYPES[p.fs_type]
  190. args = {'device': p.device, 'fn': fn}
  191. if partition_type == "MTD":
  192. self.script.append(
  193. 'write_raw_parameter_image(package_extract_file("%(fn)s"), "%(device)s");'
  194. % args)
  195. elif partition_type == "EMMC":
  196. self.script.append(
  197. 'write_raw_parameter_image(package_extract_file("%(fn)s"), "%(device)s");'
  198. % args)
  199. else:
  200. raise ValueError("don't know how to write \"%s\" partitions" % (p.fs_type,))
  201. def ClearMiscCommand(self):
  202. """clear misc command"""
  203. self.script.append('clear_misc_command();')
  204. def SetPermissions(self, fn, uid, gid, mode):
  205. """Set file ownership and permissions."""
  206. self.script.append('set_perm(%d, %d, 0%o, "%s");' % (uid, gid, mode, fn))
  207. def SetPermissionsRecursive(self, fn, uid, gid, dmode, fmode):
  208. """Recursively set path ownership and permissions."""
  209. self.script.append('set_perm_recursive(%d, %d, 0%o, 0%o, "%s");'
  210. % (uid, gid, dmode, fmode, fn))
  211. def MakeSymlinks(self, symlink_list):
  212. """Create symlinks, given a list of (dest, link) pairs."""
  213. by_dest = {}
  214. for d, l in symlink_list:
  215. by_dest.setdefault(d, []).append(l)
  216. for dest, links in sorted(by_dest.iteritems()):
  217. cmd = ('symlink("%s", ' % (dest,) +
  218. ",\0".join(['"' + i + '"' for i in sorted(links)]) + ");")
  219. self.script.append(self._WordWrap(cmd))
  220. def AppendExtra(self, extra):
  221. """Append text verbatim to the output script."""
  222. self.script.append(extra)
  223. def UnmountAll(self):
  224. for p in sorted(self.mounts):
  225. self.script.append('unmount("%s");' % (p,))
  226. self.mounts = set()
  227. def AddToZip(self, input_zip, output_zip, input_path=None):
  228. """Write the accumulated script to the output_zip file. input_zip
  229. is used as the source for the 'updater' binary needed to run
  230. script. If input_path is not None, it will be used as a local
  231. path for the binary instead of input_zip."""
  232. self.UnmountAll()
  233. common.ZipWriteStr(output_zip, "META-INF/com/google/android/updater-script",
  234. "\n".join(self.script) + "\n")
  235. if input_path is None:
  236. data = input_zip.read("OTA/bin/updater")
  237. else:
  238. data = open(os.path.join(input_path, "updater")).read()
  239. common.ZipWriteStr(output_zip, "META-INF/com/google/android/update-binary",
  240. data, perms=0755)