Sort the split transfers to generate a determinate package
We split large apks and generated patches for them in parallel,
resulting in nondeterminate packages between different runs. This CL
sort the split transfers by target name first; and then add them
sequentially to the final transfer list.
Also fix a side effect where we may generate a wrong sha1 for split
ranges due to synchronization error.
Bug: 71770360
Bug: 71759418
Test: Generate the package several times, compare the log and the transfer list.
Change-Id: I2a49e22594d59ffaa98b11edc776be4e3c4c561f
diff --git a/tools/releasetools/blockimgdiff.py b/tools/releasetools/blockimgdiff.py
index 69750b2..2b2e6d9 100644
--- a/tools/releasetools/blockimgdiff.py
+++ b/tools/releasetools/blockimgdiff.py
@@ -1385,8 +1385,8 @@
assert patch_start == patch_size
return split_info_list
- def AddSplitTransferForLargeApks():
- """Create split transfers for large apk files.
+ def SplitLargeApks():
+ """Split the large apks files.
Example: Chrome.apk will be split into
src-0: Chrome.apk-0, tgt-0: Chrome.apk-0
@@ -1452,16 +1452,16 @@
split_src_name = "{}-{}".format(src_name, index)
split_tgt_name = "{}-{}".format(tgt_name, index)
- transfer_split = Transfer(split_tgt_name, split_src_name,
- split_tgt_ranges, split_src_ranges,
- self.tgt.RangeSha1(split_tgt_ranges),
- self.src.RangeSha1(split_src_ranges),
- "diff", self.transfers)
- transfer_split.patch = patch_content
+ split_large_apks.append((split_tgt_name,
+ split_src_name,
+ split_tgt_ranges,
+ split_src_ranges,
+ patch_content))
print("Finding transfers...")
large_apks = []
+ split_large_apks = []
cache_size = common.OPTIONS.cache_size
split_threshold = 0.125
max_blocks_per_transfer = int(cache_size * split_threshold /
@@ -1511,13 +1511,23 @@
AddTransfer(tgt_fn, None, tgt_ranges, empty, "new", self.transfers)
transfer_lock = threading.Lock()
- threads = [threading.Thread(target=AddSplitTransferForLargeApks)
+ threads = [threading.Thread(target=SplitLargeApks)
for _ in range(self.threads)]
for th in threads:
th.start()
while threads:
threads.pop().join()
+ # Sort the split transfers for large apks to generate a determinate package.
+ split_large_apks.sort()
+ for (tgt_name, src_name, tgt_ranges, src_ranges,
+ patch) in split_large_apks:
+ transfer_split = Transfer(tgt_name, src_name, tgt_ranges, src_ranges,
+ self.tgt.RangeSha1(tgt_ranges),
+ self.src.RangeSha1(src_ranges),
+ "diff", self.transfers)
+ transfer_split.patch = patch
+
def AbbreviateSourceNames(self):
for k in self.src.file_map.keys():
b = os.path.basename(k)