Merge "releasetools: Really allow removing partitions" am: 68e2dc2086 am: 230086552b
am: a442906386

Change-Id: I5f5b2ba26c726b0258ca96d6986bee5b71fb8bff
diff --git a/tools/releasetools/blockimgdiff.py b/tools/releasetools/blockimgdiff.py
index 456f791..e5a9050 100644
--- a/tools/releasetools/blockimgdiff.py
+++ b/tools/releasetools/blockimgdiff.py
@@ -84,6 +84,7 @@
     self.extended = RangeSet()
     self.total_blocks = 0
     self.file_map = {}
+    self.hashtree_info = None
 
   def RangeSha1(self, ranges):
     return sha1().hexdigest()
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 0415894..5d310d2 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -1770,15 +1770,21 @@
     if OPTIONS.source_info_dict is None:
       is_dynamic_build = OPTIONS.info_dict.get(
           "use_dynamic_partitions") == "true"
+      is_dynamic_source = False
     else:
       is_dynamic_build = OPTIONS.source_info_dict.get(
           "use_dynamic_partitions") == "true"
+      is_dynamic_source = partition in shlex.split(
+          OPTIONS.source_info_dict.get("dynamic_partition_list", "").strip())
 
-    # For dynamic partitions builds, always check partition list in target build
-    # because new partitions may be added.
-    is_dynamic = is_dynamic_build and partition in shlex.split(
+    is_dynamic_target = partition in shlex.split(
         OPTIONS.info_dict.get("dynamic_partition_list", "").strip())
 
+    # For dynamic partitions builds, check partition list in both source
+    # and target build because new partitions may be added, and existing
+    # partitions may be removed.
+    is_dynamic = is_dynamic_build and (is_dynamic_source or is_dynamic_target)
+
     if is_dynamic:
       self.device = 'map_partition("%s")' % partition
     else:
diff --git a/tools/releasetools/test_common.py b/tools/releasetools/test_common.py
index 3619633..cfd070d 100644
--- a/tools/releasetools/test_common.py
+++ b/tools/releasetools/test_common.py
@@ -27,6 +27,7 @@
 import validate_target_files
 from rangelib import RangeSet
 
+from blockimgdiff import EmptyImage, DataImage
 
 KiB = 1024
 MiB = 1024 * KiB
@@ -1113,7 +1114,7 @@
                     "ops that remove / shrink partitions must precede ops that "
                     "grow / add partitions")
 
-  def test_inc_partitions(self):
+  def test_incremental(self):
     source_info = common.LoadDictionaryFromLines("""
 dynamic_partition_list=system vendor product product_services
 super_partition_groups=group_foo
@@ -1186,3 +1187,38 @@
                     min_idx_move_partition_in_foo,
                     "Must shrink partitions / remove partitions from group"
                     "before adding / moving partitions into group")
+
+  def test_remove_partition(self):
+    source_info = common.LoadDictionaryFromLines("""
+blockimgdiff_versions=3,4
+use_dynamic_partitions=true
+dynamic_partition_list=foo
+super_partition_groups=group_foo
+super_group_foo_group_size={group_foo_size}
+super_group_foo_partition_list=foo
+""".format(group_foo_size=4 * GiB).split("\n"))
+    target_info = common.LoadDictionaryFromLines("""
+blockimgdiff_versions=3,4
+use_dynamic_partitions=true
+super_partition_groups=group_foo
+super_group_foo_group_size={group_foo_size}
+""".format(group_foo_size=4 * GiB).split("\n"))
+
+    common.OPTIONS.info_dict = target_info
+    common.OPTIONS.target_info_dict = target_info
+    common.OPTIONS.source_info_dict = source_info
+    common.OPTIONS.cache_size = 4 * 4096
+
+    block_diffs = [common.BlockDifference("foo", EmptyImage(),
+                                          src=DataImage("source", pad=True))]
+
+    dp_diff = common.DynamicPartitionsDifference(target_info, block_diffs,
+                                                 source_info_dict=source_info)
+    with zipfile.ZipFile(self.output_path, 'w') as output_zip:
+      dp_diff.WriteScript(self.script, output_zip, write_verify_script=True)
+
+    self.assertNotIn("block_image_update", str(self.script),
+        "Removed partition should not be patched.")
+
+    lines = self.get_op_list(self.output_path)
+    self.assertEqual(lines, ["remove foo"])