Ensure insertion order of Python dict

Add keys to the dict `partitions` in serial to have a deterministic
insertion order.
This guarantees the generated vbmeta.img is always the same on the same
input, fixing image consistency issues.

Reference:
https://android-review.googlesource.com/c/platform/build/+/2585397

Bug: 332550989
Test: Generate vbmeta several times, confirm identical result.
Change-Id: I39da5844045f497fdc89e6477a7e32ddacb70764
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index b39a82c..a2c0949 100644
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -1055,6 +1055,20 @@
     for call in add_partition_calls:
       add_partition(*call)
   else:
+    # When calling avbtool make_vbmeta_image, it uses the `partitions`
+    # dictionary to include the options for --include_descriptors_from_image.
+    # The vbmeta image is different if the order of the
+    # --include_descriptors_from_image changes. As the images are generated
+    # parallelly and entries are added on completion of image creation,
+    # this `partitions` dict might be indeterministic as the order of
+    # completion of image creation cannot be predicted.
+    # To address this issue, add keys to the dict `partitions` with null values
+    # in the order they are listed in the variable `add_partition_calls`, and
+    # then the values are updated by `add_partition` keeping the order of the
+    # items. This ensures generated vbmeta.img is the same for the same input.
+    for call in add_partition_calls:
+      if call[1]:
+        partitions[call[0]] = None
     with ThreadPoolExecutor(max_workers=len(add_partition_calls)) as executor:
       for future in [executor.submit(add_partition, *call) for call in add_partition_calls]:
         future.result()