support for ext4/EMMC in target_files and OTA generation

Move the image sizes into a more generic key-value file.  Make them
optional.  Add additional key/value pairs describing what kind of
filesystem the device uses.  Pass new fs-type-related arguments in
edify scripts when mounting and reformatting partitions.

Don't include all the init.*.rc files from the regular system in
recovery -- they aren't needed, and break recovery on some devices.

Change-Id: Ic1c651f754ed00ba1cffe8cf56c43f7f3b0ebfd7
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 46cef11..2a81133 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -58,9 +58,35 @@
   return subprocess.Popen(args, **kwargs)
 
 
-def LoadMaxSizes():
+def LoadInfoDict():
+  """Read and parse the META/misc_info.txt key/value pairs from the
+  input target files and return a dict."""
+
+  d = {}
+  try:
+    for line in open(os.path.join(OPTIONS.input_tmp, "META", "misc_info.txt")):
+      line = line.strip()
+      if not line or line.startswith("#"): continue
+      k, v = line.split("=", 1)
+      d[k] = v
+  except IOError, e:
+    if e.errno == errno.ENOENT:
+      # ok if misc_info.txt file doesn't exist
+      pass
+    else:
+      raise
+
+  if "fs_type" not in d: info["fs_type"] = "yaffs2"
+  if "partition_type" not in d: info["partition_type"] = "MTD"
+
+  return d
+
+
+def LoadMaxSizes(info):
   """Load the maximum allowable images sizes from the input
-  target_files size."""
+  target_files.  Uses the imagesizes.txt file if it's available
+  (pre-honeycomb target_files), or the more general info dict (which
+  must be passed in) if not."""
   OPTIONS.max_image_size = {}
   try:
     for line in open(os.path.join(OPTIONS.input_tmp, "META", "imagesizes.txt")):
@@ -71,7 +97,15 @@
       OPTIONS.max_image_size[image + ".img"] = size
   except IOError, e:
     if e.errno == errno.ENOENT:
-      pass
+      def copy(x, y):
+        if x in info: OPTIONS.max_image_size[x+".img"] = int(info[x+y])
+      copy("blocksize", "")
+      copy("boot", "_size")
+      copy("recovery", "_size")
+      copy("system", "_size")
+      copy("userdata", "_size")
+    else:
+      raise
 
 
 def LoadMkyaffs2ExtraFlags():
diff --git a/tools/releasetools/edify_generator.py b/tools/releasetools/edify_generator.py
index 68b0850..3334b43 100644
--- a/tools/releasetools/edify_generator.py
+++ b/tools/releasetools/edify_generator.py
@@ -21,10 +21,11 @@
   """Class to generate scripts in the 'edify' recovery script language
   used from donut onwards."""
 
-  def __init__(self, version):
+  def __init__(self, version, info):
     self.script = []
     self.mounts = set()
     self.version = version
+    self.info = info
 
   def MakeTemporary(self):
     """Make a temporary script object whose commands can latter be
@@ -130,12 +131,15 @@
     available on /cache."""
     self.script.append("assert(apply_patch_space(%d));" % (amount,))
 
-  def Mount(self, kind, what, path):
+  def Mount(self, what, mount_point):
     """Mount the given 'what' at the given path.  'what' should be a
-    partition name if kind is "MTD", or a block device if kind is
-    "vfat".  No other values of 'kind' are supported."""
-    self.script.append('mount("%s", "%s", "%s");' % (kind, what, path))
-    self.mounts.add(path)
+    partition name for an MTD partition, or a block device for
+    anything else."""
+    what = self.info.get("partition_path", "") + what
+    self.script.append('mount("%s", "%s", "%s", "%s");' %
+                       (self.info["fs_type"], self.info["partition_type"],
+                        what, mount_point))
+    self.mounts.add(mount_point)
 
   def UnpackPackageDir(self, src, dst):
     """Unpack a given directory from the OTA package into the given
@@ -154,8 +158,11 @@
     self.script.append('ui_print("%s");' % (message,))
 
   def FormatPartition(self, partition):
-    """Format the given MTD partition."""
-    self.script.append('format("MTD", "%s");' % (partition,))
+    """Format the given partition."""
+    partition = self.info.get("partition_path", "") + partition
+    self.script.append('format("%s", "%s", "%s");' %
+                       (self.info["fs_type"], self.info["partition_type"],
+                        partition))
 
   def DeleteFiles(self, file_list):
     """Delete all files in file_list."""
@@ -190,12 +197,23 @@
           'write_firmware_image("PACKAGE:%s", "%s");' % (fn, kind))
 
   def WriteRawImage(self, partition, fn):
-    """Write the given package file into the given MTD partition."""
-    self.script.append(
-        ('assert(package_extract_file("%(fn)s", "/tmp/%(partition)s.img"),\n'
-         '       write_raw_image("/tmp/%(partition)s.img", "%(partition)s"),\n'
-         '       delete("/tmp/%(partition)s.img"));')
-        % {'partition': partition, 'fn': fn})
+    """Write the given package file into the given partition."""
+
+    if self.info["partition_type"] == "MTD":
+      self.script.append(
+          ('assert(package_extract_file("%(fn)s", "/tmp/%(partition)s.img"),\n'
+           '       write_raw_image("/tmp/%(partition)s.img", "%(partition)s"),\n'
+           '       delete("/tmp/%(partition)s.img"));')
+          % {'partition': partition, 'fn': fn})
+    elif self.info["partition_type"] == "EMMC":
+      self.script.append(
+          ('package_extract_file("%(fn)s", "%(dir)s%(partition)s");')
+          % {'partition': partition, 'fn': fn,
+             'dir': self.info.get("partition_path", ""),
+             })
+    else:
+      raise ValueError("don't know how to write \"%s\" partitions" %
+                       (self.info["partition_type"],))
 
   def SetPermissions(self, fn, uid, gid, mode):
     """Set file ownership and permissions."""
diff --git a/tools/releasetools/img_from_target_files b/tools/releasetools/img_from_target_files
index 07eb648..46ac754 100755
--- a/tools/releasetools/img_from_target_files
+++ b/tools/releasetools/img_from_target_files
@@ -171,7 +171,8 @@
 
   OPTIONS.input_tmp = common.UnzipTemp(args[0])
 
-  common.LoadMaxSizes()
+  info = common.LoadInfoDict()
+  common.LoadMaxSizes(info)
   if not OPTIONS.max_image_size:
     print
     print "  WARNING:  Failed to load max image sizes; will not enforce"
diff --git a/tools/releasetools/ota_from_target_files b/tools/releasetools/ota_from_target_files
index ad7e0e4..02f2508 100755
--- a/tools/releasetools/ota_from_target_files
+++ b/tools/releasetools/ota_from_target_files
@@ -334,11 +334,11 @@
   return Item.Get("system/etc/install-recovery.sh", dir=False)
 
 
-def WriteFullOTAPackage(input_zip, output_zip):
+def WriteFullOTAPackage(input_zip, output_zip, info):
   # TODO: how to determine this?  We don't know what version it will
   # be installed on top of.  For now, we expect the API just won't
   # change very often.
-  script = edify_generator.EdifyGenerator(3)
+  script = edify_generator.EdifyGenerator(3, info)
 
   metadata = {"post-build": GetBuildProp("ro.build.fingerprint", input_zip),
               "pre-device": GetBuildProp("ro.product.device", input_zip),
@@ -366,7 +366,7 @@
     script.FormatPartition("userdata")
 
   script.FormatPartition("system")
-  script.Mount("MTD", "system", "/system")
+  script.Mount("system", "/system")
   script.UnpackPackageDir("recovery", "/system")
   script.UnpackPackageDir("system", "/system")
 
@@ -448,14 +448,14 @@
       return 0
 
 
-def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
+def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip, info):
   source_version = GetRecoveryAPIVersion(source_zip)
   target_version = GetRecoveryAPIVersion(target_zip)
 
   if source_version == 0:
     print ("WARNING: generating edify script for a source that "
            "can't install it.")
-  script = edify_generator.EdifyGenerator(source_version)
+  script = edify_generator.EdifyGenerator(source_version, info)
 
   metadata = {"pre-device": GetBuildProp("ro.product.device", source_zip),
               "post-timestamp": GetBuildProp("ro.build.date.utc", target_zip),
@@ -516,7 +516,7 @@
   metadata["pre-build"] = source_fp
   metadata["post-build"] = target_fp
 
-  script.Mount("MTD", "system", "/system")
+  script.Mount("system", "/system")
   script.AssertSomeFingerprint(source_fp, target_fp)
 
   source_boot = common.File("/tmp/boot.img",
@@ -755,7 +755,8 @@
       else:
         raise
 
-  common.LoadMaxSizes()
+  info = common.LoadInfoDict()
+  common.LoadMaxSizes(info)
   if not OPTIONS.max_image_size:
     print
     print "  WARNING:  Failed to load max image sizes; will not enforce"
@@ -773,12 +774,12 @@
                                  compression=zipfile.ZIP_DEFLATED)
 
   if OPTIONS.incremental_source is None:
-    WriteFullOTAPackage(input_zip, output_zip)
+    WriteFullOTAPackage(input_zip, output_zip, info)
   else:
     print "unzipping source target-files..."
     OPTIONS.source_tmp = common.UnzipTemp(OPTIONS.incremental_source)
     source_zip = zipfile.ZipFile(OPTIONS.incremental_source, "r")
-    WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)
+    WriteIncrementalOTAPackage(input_zip, source_zip, output_zip, info)
 
   output_zip.close()
   if OPTIONS.package_key: