Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f68b50f9 authored by Tianjie Xu's avatar Tianjie Xu
Browse files

Fall back to normal split if imgdiff fails when splitting large apks

Imgdiff expects the input files to be valid zip archives. During the
split of large apks, imgdiff may fail when there's a hole in the input
file; potentially due to the blocks allocation of mke2fs. This CL solves
the issue by falling back to normal split in case of the imgdiff split
failure. The split transfers will then use bsdiff instead.

Bug: 69624507
Test: generate the incremental package for the failed targets and check the
transfers.
Change-Id: I4882452378123e60ad3434053b57f33e53ac4b82
parent 37066490
Loading
Loading
Loading
Loading
+42 −34
Original line number Diff line number Diff line
@@ -1178,9 +1178,38 @@ class BlockImageDiff(object):
  def FindTransfers(self):
    """Parse the file_map to generate all the transfers."""

    def AddSplitTransfers(tgt_name, src_name, tgt_ranges, src_ranges,
                          style, by_id):
      """Add one or multiple Transfer()s by splitting large files.
    def AddSplitTransfers(tgt_name, src_name, tgt_ranges, src_ranges, style,
                          by_id):
      """Add one or multiple Transfer()s by splitting large files."""
      pieces = 0
      while (tgt_ranges.size() > max_blocks_per_transfer and
             src_ranges.size() > max_blocks_per_transfer):
        tgt_split_name = "%s-%d" % (tgt_name, pieces)
        src_split_name = "%s-%d" % (src_name, pieces)
        tgt_first = tgt_ranges.first(max_blocks_per_transfer)
        src_first = src_ranges.first(max_blocks_per_transfer)

        Transfer(tgt_split_name, src_split_name, tgt_first, src_first,
                 self.tgt.RangeSha1(tgt_first), self.src.RangeSha1(src_first),
                 style, by_id)

        tgt_ranges = tgt_ranges.subtract(tgt_first)
        src_ranges = src_ranges.subtract(src_first)
        pieces += 1

      # Handle remaining blocks.
      if tgt_ranges.size() or src_ranges.size():
        # Must be both non-empty.
        assert tgt_ranges.size() and src_ranges.size()
        tgt_split_name = "%s-%d" % (tgt_name, pieces)
        src_split_name = "%s-%d" % (src_name, pieces)
        Transfer(tgt_split_name, src_split_name, tgt_ranges, src_ranges,
                 self.tgt.RangeSha1(tgt_ranges), self.src.RangeSha1(src_ranges),
                 style, by_id)

    def FindZipsAndAddSplitTransfers(tgt_name, src_name, tgt_ranges,
                                     src_ranges, style, by_id):
      """Find all the zip archives and add split transfers for the other files.

      For BBOTA v3, we need to stash source blocks for resumable feature.
      However, with the growth of file size and the shrink of the cache
@@ -1195,8 +1224,6 @@ class BlockImageDiff(object):
      size by 30% for volantis, and 20% for angler and bullhead."""

      assert style == "diff"
      # Possibly split large files into smaller chunks.
      pieces = 0

      # Change nothing for small files.
      if (tgt_ranges.size() <= max_blocks_per_transfer and
@@ -1214,29 +1241,7 @@ class BlockImageDiff(object):
          large_apks.append((tgt_name, src_name, tgt_ranges, src_ranges))
          return

      while (tgt_ranges.size() > max_blocks_per_transfer and
             src_ranges.size() > max_blocks_per_transfer):
        tgt_split_name = "%s-%d" % (tgt_name, pieces)
        src_split_name = "%s-%d" % (src_name, pieces)
        tgt_first = tgt_ranges.first(max_blocks_per_transfer)
        src_first = src_ranges.first(max_blocks_per_transfer)

        Transfer(tgt_split_name, src_split_name, tgt_first, src_first,
                 self.tgt.RangeSha1(tgt_first), self.src.RangeSha1(src_first),
                 style, by_id)

        tgt_ranges = tgt_ranges.subtract(tgt_first)
        src_ranges = src_ranges.subtract(src_first)
        pieces += 1

      # Handle remaining blocks.
      if tgt_ranges.size() or src_ranges.size():
        # Must be both non-empty.
        assert tgt_ranges.size() and src_ranges.size()
        tgt_split_name = "%s-%d" % (tgt_name, pieces)
        src_split_name = "%s-%d" % (src_name, pieces)
        Transfer(tgt_split_name, src_split_name, tgt_ranges, src_ranges,
                 self.tgt.RangeSha1(tgt_ranges), self.src.RangeSha1(src_ranges),
      AddSplitTransfers(tgt_name, src_name, tgt_ranges, src_ranges,
                        style, by_id)

    def AddTransfer(tgt_name, src_name, tgt_ranges, src_ranges, style, by_id,
@@ -1287,7 +1292,7 @@ class BlockImageDiff(object):
          assert tgt_changed + tgt_skipped.size() == tgt_size
          print('%10d %10d (%6.2f%%) %s' % (tgt_skipped.size(), tgt_size,
                tgt_skipped.size() * 100.0 / tgt_size, tgt_name))
          AddSplitTransfers(
          FindZipsAndAddSplitTransfers(
              "%s-skipped" % (tgt_name,),
              "%s-skipped" % (src_name,),
              tgt_skipped, src_skipped, style, by_id)
@@ -1304,7 +1309,7 @@ class BlockImageDiff(object):
            return

      # Add the transfer(s).
      AddSplitTransfers(
      FindZipsAndAddSplitTransfers(
          tgt_name, src_name, tgt_ranges, src_ranges, style, by_id)

    def ParseAndValidateSplitInfo(patch_size, tgt_ranges, src_ranges,
@@ -1403,10 +1408,13 @@ class BlockImageDiff(object):
               src_file, tgt_file, patch_file]
        p = common.Run(cmd, stdout=subprocess.PIPE)
        p.communicate()
        # TODO(xunchang) fall back to the normal split if imgdiff fails.
        if p.returncode != 0:
          raise ValueError("Failed to create patch between {} and {}".format(
              src_name, tgt_name))
          print("Failed to create patch between {} and {},"
                " falling back to bsdiff".format(src_name, tgt_name))
          with transfer_lock:
            AddSplitTransfers(tgt_name, src_name, tgt_ranges, src_ranges,
                              "diff", self.transfers)
          continue

        with open(patch_info_file) as patch_info:
          lines = patch_info.readlines()