releasetools: Only verify the blocks to be touched.

For incremental BBOTAs, we used to verify the integrity of all the
blocks in the source partition. In order to reduce the time cost under
recovery, this CL changes to only verify the blocks that will be touched
in the given OTA package (BBOTA >= 3 only). This is a trade-off between
performance and reliability.

Bug: 27813356
Change-Id: I3975ae6f461f0f7e58d24f1df7df46a449d2988b
diff --git a/tools/releasetools/blockimgdiff.py b/tools/releasetools/blockimgdiff.py
index 625dca2..d49112f 100644
--- a/tools/releasetools/blockimgdiff.py
+++ b/tools/releasetools/blockimgdiff.py
@@ -272,6 +272,8 @@
     self.src_basenames = {}
     self.src_numpatterns = {}
     self._max_stashed_size = 0
+    self.touched_src_ranges = RangeSet()
+    self.touched_src_sha1 = None
 
     assert version in (1, 2, 3, 4)
 
@@ -373,6 +375,7 @@
           else:
             stashes[sh] = 1
             stashed_blocks += sr.size()
+            self.touched_src_ranges = self.touched_src_ranges.union(sr)
             out.append("stash %s %s\n" % (sh, sr.to_string_raw()))
 
       if stashed_blocks > max_stashed_blocks:
@@ -479,6 +482,9 @@
               if temp_stash_usage > max_stashed_blocks:
                 max_stashed_blocks = temp_stash_usage
 
+            self.touched_src_ranges = self.touched_src_ranges.union(
+                xf.src_ranges)
+
             out.append("%s %s %s %s\n" % (
                 xf.style,
                 self.HashBlocks(self.tgt, xf.tgt_ranges),
@@ -502,6 +508,9 @@
             if temp_stash_usage > max_stashed_blocks:
               max_stashed_blocks = temp_stash_usage
 
+          self.touched_src_ranges = self.touched_src_ranges.union(
+              xf.src_ranges)
+
           out.append("%s %d %d %s %s %s %s\n" % (
               xf.style,
               xf.patch_start, xf.patch_len,
@@ -537,6 +546,10 @@
                    self.tgt.blocksize, max_allowed, cache_size,
                    stash_threshold)
 
+    if self.version >= 3:
+      self.touched_src_sha1 = self.HashBlocks(
+          self.src, self.touched_src_ranges)
+
     # Zero out extended blocks as a workaround for bug 20881595.
     if self.tgt.extended:
       out.append("zero %s\n" % (self.tgt.extended.to_string_raw(),))
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 98e3d04..a07643e 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -1314,6 +1314,8 @@
     self.path = os.path.join(tmpdir, partition)
     b.Compute(self.path)
     self._required_cache = b.max_stashed_size
+    self.touched_src_ranges = b.touched_src_ranges
+    self.touched_src_sha1 = b.touched_src_sha1
 
     if src is None:
       _, self.device = GetTypeAndDevice("/" + partition, OPTIONS.info_dict)
@@ -1357,26 +1359,31 @@
                        self.device))
     script.AppendExtra("")
 
-  def WriteVerifyScript(self, script):
+  def WriteVerifyScript(self, script, touched_blocks_only=False):
     partition = self.partition
     if not self.src:
       script.Print("Image %s will be patched unconditionally." % (partition,))
     else:
-      ranges = self.src.care_map.subtract(self.src.clobbered_blocks)
+      if touched_blocks_only and self.version >= 3:
+        ranges = self.touched_src_ranges
+        expected_sha1 = self.touched_src_sha1
+      else:
+        ranges = self.src.care_map.subtract(self.src.clobbered_blocks)
+        expected_sha1 = self.src.TotalSha1()
       ranges_str = ranges.to_string_raw()
       if self.version >= 4:
         script.AppendExtra(('if (range_sha1("%s", "%s") == "%s" || '
                             'block_image_verify("%s", '
                             'package_extract_file("%s.transfer.list"), '
                             '"%s.new.dat", "%s.patch.dat")) then') % (
-                            self.device, ranges_str, self.src.TotalSha1(),
+                            self.device, ranges_str, expected_sha1,
                             self.device, partition, partition, partition))
       elif self.version == 3:
         script.AppendExtra(('if (range_sha1("%s", "%s") == "%s" || '
                             'block_image_verify("%s", '
                             'package_extract_file("%s.transfer.list"), '
                             '"%s.new.dat", "%s.patch.dat")) then') % (
-                            self.device, ranges_str, self.src.TotalSha1(),
+                            self.device, ranges_str, expected_sha1,
                             self.device, partition, partition, partition))
       else:
         script.AppendExtra('if range_sha1("%s", "%s") == "%s" then' % (
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 4d0d8a5..861c485 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -996,9 +996,9 @@
 """ % bcb_dev)
 
   # Verify the existing partitions.
-  system_diff.WriteVerifyScript(script)
+  system_diff.WriteVerifyScript(script, touched_blocks_only=True)
   if vendor_diff:
-    vendor_diff.WriteVerifyScript(script)
+    vendor_diff.WriteVerifyScript(script, touched_blocks_only=True)
 
   script.Comment("---- start making changes here ----")