releasetools: Support packaging for system_root_image.

For system images that contain the root directory, we need to find the
root directory at ROOT/ instead of BOOT/RAMDISK/.

Change-Id: Ica345c8b1b03475f8ac6c44fd576045fcf17c882
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 9112108..a67f044 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -202,7 +202,8 @@
   makeint("boot_size")
   makeint("fstab_version")
 
-  d["fstab"] = LoadRecoveryFSTab(read_helper, d["fstab_version"], d.get("system_root_image", False))
+  d["fstab"] = LoadRecoveryFSTab(read_helper, d["fstab_version"],
+                                 d.get("system_root_image", False))
   d["build.prop"] = LoadBuildProp(read_helper)
   return d
 
@@ -318,7 +319,8 @@
     raise ValueError("Unknown fstab_version: \"%d\"" % (fstab_version,))
 
   # / is used for the system mount point when the root directory is included in
-  # system. Other areas assume system is always at "/system" so point /system at /
+  # system. Other areas assume system is always at "/system" so point /system
+  # at /.
   if system_root_image:
     assert not d.has_key("/system") and d.has_key("/")
     d["/system"] = d["/"]
@@ -330,34 +332,46 @@
     print "%-25s = (%s) %s" % (k, type(v).__name__, v)
 
 
-def BuildBootableImage(sourcedir, fs_config_file, info_dict=None):
-  """Take a kernel, cmdline, and ramdisk directory from the input (in
-  'sourcedir'), and turn them into a boot image.  Return the image
-  data, or None if sourcedir does not appear to contains files for
-  building the requested image."""
+def _BuildBootableImage(sourcedir, fs_config_file, info_dict=None,
+                        has_ramdisk=False):
+  """Build a bootable image from the specified sourcedir.
 
-  if (not os.access(os.path.join(sourcedir, "RAMDISK"), os.F_OK) or
-      not os.access(os.path.join(sourcedir, "kernel"), os.F_OK)):
+  Take a kernel, cmdline, and optionally a ramdisk directory from the input (in
+  'sourcedir'), and turn them into a boot image.  Return the image data, or
+  None if sourcedir does not appear to contains files for building the
+  requested image."""
+
+  def make_ramdisk():
+    ramdisk_img = tempfile.NamedTemporaryFile()
+
+    if os.access(fs_config_file, os.F_OK):
+      cmd = ["mkbootfs", "-f", fs_config_file,
+             os.path.join(sourcedir, "RAMDISK")]
+    else:
+      cmd = ["mkbootfs", os.path.join(sourcedir, "RAMDISK")]
+    p1 = Run(cmd, stdout=subprocess.PIPE)
+    p2 = Run(["minigzip"], stdin=p1.stdout, stdout=ramdisk_img.file.fileno())
+
+    p2.wait()
+    p1.wait()
+    assert p1.returncode == 0, "mkbootfs of %s ramdisk failed" % (sourcedir,)
+    assert p2.returncode == 0, "minigzip of %s ramdisk failed" % (sourcedir,)
+
+    return ramdisk_img
+
+  if not os.access(os.path.join(sourcedir, "kernel"), os.F_OK):
+    return None
+
+  if has_ramdisk and not os.access(os.path.join(sourcedir, "RAMDISK"), os.F_OK):
     return None
 
   if info_dict is None:
     info_dict = OPTIONS.info_dict
 
-  ramdisk_img = tempfile.NamedTemporaryFile()
   img = tempfile.NamedTemporaryFile()
 
-  if os.access(fs_config_file, os.F_OK):
-    cmd = ["mkbootfs", "-f", fs_config_file, os.path.join(sourcedir, "RAMDISK")]
-  else:
-    cmd = ["mkbootfs", os.path.join(sourcedir, "RAMDISK")]
-  p1 = Run(cmd, stdout=subprocess.PIPE)
-  p2 = Run(["minigzip"],
-           stdin=p1.stdout, stdout=ramdisk_img.file.fileno())
-
-  p2.wait()
-  p1.wait()
-  assert p1.returncode == 0, "mkbootfs of %s ramdisk failed" % (sourcedir,)
-  assert p2.returncode == 0, "minigzip of %s ramdisk failed" % (sourcedir,)
+  if has_ramdisk:
+    ramdisk_img = make_ramdisk()
 
   # use MKBOOTIMG from environ, or "mkbootimg" if empty or not set
   mkbootimg = os.getenv('MKBOOTIMG') or "mkbootimg"
@@ -388,14 +402,15 @@
   if args and args.strip():
     cmd.extend(shlex.split(args))
 
+  if has_ramdisk:
+    cmd.extend(["--ramdisk", ramdisk_img.name])
+
   img_unsigned = None
   if info_dict.get("vboot", None):
     img_unsigned = tempfile.NamedTemporaryFile()
-    cmd.extend(["--ramdisk", ramdisk_img.name,
-                "--output", img_unsigned.name])
+    cmd.extend(["--output", img_unsigned.name])
   else:
-    cmd.extend(["--ramdisk", ramdisk_img.name,
-                "--output", img.name])
+    cmd.extend(["--output", img.name])
 
   p = Run(cmd, stdout=subprocess.PIPE)
   p.communicate()
@@ -430,7 +445,8 @@
   img.seek(os.SEEK_SET, 0)
   data = img.read()
 
-  ramdisk_img.close()
+  if has_ramdisk:
+    ramdisk_img.close()
   img.close()
 
   return data
@@ -438,11 +454,11 @@
 
 def GetBootableImage(name, prebuilt_name, unpack_dir, tree_subdir,
                      info_dict=None):
-  """Return a File object (with name 'name') with the desired bootable
-  image.  Look for it in 'unpack_dir'/BOOTABLE_IMAGES under the name
-  'prebuilt_name', otherwise look for it under 'unpack_dir'/IMAGES,
-  otherwise construct it from the source files in
-  'unpack_dir'/'tree_subdir'."""
+  """Return a File object with the desired bootable image.
+
+  Look for it in 'unpack_dir'/BOOTABLE_IMAGES under the name 'prebuilt_name',
+  otherwise look for it under 'unpack_dir'/IMAGES, otherwise construct it from
+  the source files in 'unpack_dir'/'tree_subdir'."""
 
   prebuilt_path = os.path.join(unpack_dir, "BOOTABLE_IMAGES", prebuilt_name)
   if os.path.exists(prebuilt_path):
@@ -455,10 +471,18 @@
     return File.FromLocalFile(name, prebuilt_path)
 
   print "building image from target_files %s..." % (tree_subdir,)
+
+  if info_dict is None:
+    info_dict = OPTIONS.info_dict
+
+  # With system_root_image == "true", we don't pack ramdisk into the boot image.
+  has_ramdisk = (info_dict.get("system_root_image", None) != "true" or
+                 prebuilt_name != "boot.img")
+
   fs_config = "META/" + tree_subdir.lower() + "_filesystem_config.txt"
-  data = BuildBootableImage(os.path.join(unpack_dir, tree_subdir),
-                            os.path.join(unpack_dir, fs_config),
-                            info_dict)
+  data = _BuildBootableImage(os.path.join(unpack_dir, tree_subdir),
+                             os.path.join(unpack_dir, fs_config),
+                             info_dict, has_ramdisk)
   if data:
     return File(name, data)
   return None
@@ -1401,6 +1425,7 @@
     info_dict = OPTIONS.info_dict
 
   full_recovery_image = info_dict.get("full_recovery_image", None) == "true"
+  system_root_image = info_dict.get("system_root_image", None) == "true"
 
   if full_recovery_image:
     output_sink("etc/recovery.img", recovery_img.data)
@@ -1458,7 +1483,10 @@
   # target-files expects it to be, and put it there.
   sh_location = "etc/install-recovery.sh"
   found = False
-  init_rc_dir = os.path.join(input_dir, "BOOT", "RAMDISK")
+  if system_root_image:
+    init_rc_dir = os.path.join(input_dir, "ROOT")
+  else:
+    init_rc_dir = os.path.join(input_dir, "BOOT", "RAMDISK")
   init_rc_files = os.listdir(init_rc_dir)
   for init_rc_file in init_rc_files:
     if (not init_rc_file.startswith('init.') or
diff --git a/tools/releasetools/img_from_target_files.py b/tools/releasetools/img_from_target_files.py
index 608aad1..ce5808f 100755
--- a/tools/releasetools/img_from_target_files.py
+++ b/tools/releasetools/img_from_target_files.py
@@ -101,6 +101,7 @@
           "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
       if boot_image:
         boot_image.AddToZip(output_zip)
+
       recovery_image = common.GetBootableImage(
           "recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
       if recovery_image:
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 69987ab..03b7e05 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -617,8 +617,8 @@
     symlinks = CopyPartitionFiles(system_items, input_zip, output_zip)
     script.MakeSymlinks(symlinks)
 
-  boot_img = common.GetBootableImage("boot.img", "boot.img",
-                                     OPTIONS.input_tmp, "BOOT")
+  boot_img = common.GetBootableImage(
+      "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
 
   if not block_based:
     def output_sink(fn, data):
diff --git a/tools/releasetools/sign_target_files_apks.py b/tools/releasetools/sign_target_files_apks.py
index 962d3dd..e98eb8f 100755
--- a/tools/releasetools/sign_target_files_apks.py
+++ b/tools/releasetools/sign_target_files_apks.py
@@ -180,15 +180,17 @@
         OPTIONS.replace_verity_private_key):
       ReplaceVerityPrivateKey(input_tf_zip, output_tf_zip, misc_info,
                               OPTIONS.replace_verity_private_key[1])
-    elif (info.filename == "BOOT/RAMDISK/verity_key" and
+    elif (info.filename in ("BOOT/RAMDISK/verity_key",
+                            "BOOT/verity_key") and
           OPTIONS.replace_verity_public_key):
-      new_data = ReplaceVerityPublicKey(output_tf_zip,
+      new_data = ReplaceVerityPublicKey(output_tf_zip, info.filename,
                                         OPTIONS.replace_verity_public_key[1])
       write_to_temp(info.filename, info.external_attr, new_data)
     # Copy BOOT/, RECOVERY/, META/, ROOT/ to rebuild recovery patch.
     elif (info.filename.startswith("BOOT/") or
           info.filename.startswith("RECOVERY/") or
           info.filename.startswith("META/") or
+          info.filename.startswith("ROOT/") or
           info.filename == "SYSTEM/etc/recovery-resource.dat"):
       write_to_temp(info.filename, info.external_attr, data)
 
@@ -229,7 +231,8 @@
           info.filename == "META/misc_info.txt"):
       pass
     elif (OPTIONS.replace_verity_public_key and
-          info.filename == "BOOT/RAMDISK/verity_key"):
+          info.filename in ("BOOT/RAMDISK/verity_key",
+                            "BOOT/verity_key")):
       pass
     else:
       # a non-APK file; copy it verbatim
@@ -397,11 +400,11 @@
 
   return new_recovery_keys
 
-def ReplaceVerityPublicKey(targetfile_zip, key_path):
+def ReplaceVerityPublicKey(targetfile_zip, filename, key_path):
   print "Replacing verity public key with %s" % key_path
   with open(key_path) as f:
     data = f.read()
-  common.ZipWriteStr(targetfile_zip, "BOOT/RAMDISK/verity_key", data)
+  common.ZipWriteStr(targetfile_zip, filename, data)
   return data
 
 def ReplaceVerityPrivateKey(targetfile_input_zip, targetfile_output_zip,