make full OTAs block based

Instead of writing individual files and fixing up their metadata, make
full OTAs contain a system image and simply write it to the block
device.

This is only done for target-files that already contain the recovery
flashing information, older target-files still get a file-based full
OTA.

Bug: 12893978
Change-Id: If7586083c8f275e24fec49d260af5b5aff4a0a88
diff --git a/tools/releasetools/img_from_target_files b/tools/releasetools/img_from_target_files
new file mode 120000
index 0000000..afaf24b
--- /dev/null
+++ b/tools/releasetools/img_from_target_files
@@ -0,0 +1 @@
+img_from_target_files.py
\ No newline at end of file
diff --git a/tools/releasetools/img_from_target_files b/tools/releasetools/img_from_target_files.py
similarity index 95%
rename from tools/releasetools/img_from_target_files
rename to tools/releasetools/img_from_target_files.py
index e894c42..ab505b1 100755
--- a/tools/releasetools/img_from_target_files
+++ b/tools/releasetools/img_from_target_files.py
@@ -53,7 +53,7 @@
 OPTIONS = common.OPTIONS
 
 
-def AddSystem(output_zip):
+def AddSystem(output_zip, sparse=True):
   """Turn the contents of SYSTEM into a system image and store it in
   output_zip."""
 
@@ -84,11 +84,20 @@
                                 image_props, img.name)
   assert succ, "build system.img image failed"
 
-  img.seek(os.SEEK_SET, 0)
-  data = img.read()
-  img.close()
+  if sparse:
+    img.seek(os.SEEK_SET, 0)
+    data = img.read()
+    img.close()
+  else:
+    success, name = build_image.UnsparseImage(img.name, replace=False)
+    if not success:
+      assert False, "unsparsing system.img failed"
+    try:
+      with open(name) as f:
+        data = f.read()
+    finally:
+      os.unlink(name)
 
-  common.CheckSize(data, "system.img", OPTIONS.info_dict)
   common.ZipWriteStr(output_zip, "system.img", data)
 
 
diff --git a/tools/releasetools/ota_from_target_files b/tools/releasetools/ota_from_target_files
index 652052d..dcfbf83 100755
--- a/tools/releasetools/ota_from_target_files
+++ b/tools/releasetools/ota_from_target_files
@@ -80,6 +80,7 @@
   from sha import sha as sha1
 
 import common
+import img_from_target_files
 import edify_generator
 
 OPTIONS = common.OPTIONS
@@ -434,22 +435,29 @@
 
   device_specific.FullOTA_InstallBegin()
 
-  script.ShowProgress(0.5, 0)
+  system_progress = 0.75
 
   if OPTIONS.wipe_user_data:
+    system_progress -= 0.1
+    script.ShowProgress(0.1, 10)
     script.FormatPartition("/data")
 
   if "selinux_fc" in OPTIONS.info_dict:
     WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip)
 
-  script.FormatPartition("/system")
-  script.Mount("/system")
-  if not has_recovery_patch:
-    script.UnpackPackageDir("recovery", "/system")
-  script.UnpackPackageDir("system", "/system")
+  script.ShowProgress(system_progress, 30)
+  if has_recovery_patch:
+    img_from_target_files.AddSystem(output_zip, sparse=False)
+    script.WriteRawImage("/system", "system.img")
+  else:
+    script.FormatPartition("/system")
+    script.Mount("/system")
+    if not has_recovery_patch:
+      script.UnpackPackageDir("recovery", "/system")
+      script.UnpackPackageDir("system", "/system")
 
-  symlinks = CopySystemFiles(input_zip, output_zip)
-  script.MakeSymlinks(symlinks)
+    symlinks = CopySystemFiles(input_zip, output_zip)
+    script.MakeSymlinks(symlinks)
 
   boot_img = common.GetBootableImage("boot.img", "boot.img",
                                      OPTIONS.input_tmp, "BOOT")
@@ -462,17 +470,16 @@
     common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink,
                              recovery_img, boot_img)
 
-  Item.GetMetadata(input_zip)
-  Item.Get("system").SetPermissions(script)
+    Item.GetMetadata(input_zip)
+    Item.Get("system").SetPermissions(script)
 
   common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict)
   common.ZipWriteStr(output_zip, "boot.img", boot_img.data)
-  script.ShowProgress(0.2, 0)
 
-  script.ShowProgress(0.2, 10)
+  script.ShowProgress(0.05, 5)
   script.WriteRawImage("/boot", "boot.img")
 
-  script.ShowProgress(0.1, 0)
+  script.ShowProgress(0.2, 10)
   device_specific.FullOTA_InstallEnd()
 
   if OPTIONS.extra_script is not None: