Performs basic APEX validation in the merged target files package.

Uses apex_utils.GetApexInfoFromTargetFiles to find and parse APEX files
in the target files partition dirs. Raises an error on failure to parse
or duplicate package names.

Bug: 177225446
Test: releasetools_test
Test: Create a merged build that provides the VNDK APEX on both vendor
      and system. Observe failure.
Change-Id: I1356e263b7b32d6063129e079f3ba7ab4ff132a7
diff --git a/tools/releasetools/merge_target_files.py b/tools/releasetools/merge_target_files.py
index 17d3030..5e6c42d 100755
--- a/tools/releasetools/merge_target_files.py
+++ b/tools/releasetools/merge_target_files.py
@@ -96,6 +96,7 @@
 from xml.etree import ElementTree
 
 import add_img_to_target_files
+import apex_utils
 import build_image
 import build_super_image
 import check_target_files_vintf
@@ -739,6 +740,35 @@
   return cmd
 
 
+def validate_merged_apex_info(output_target_files_dir, partitions):
+  """Validates the APEX files in the merged target files directory.
+
+  Checks the APEX files in all possible preinstalled APEX directories.
+  Depends on the <partition>/apex/* APEX files within partitions.
+
+  Args:
+    output_target_files_dir: Output directory containing merged partition directories.
+    partitions: A list of all the partitions in the output directory.
+
+  Raises:
+    RuntimeError: if apex_utils fails to parse any APEX file.
+    ExternalError: if the same APEX package is provided by multiple partitions.
+  """
+  apex_packages = set()
+
+  apex_partitions = ('system', 'system_ext', 'product', 'vendor')
+  for partition in filter(lambda p: p in apex_partitions, partitions):
+    apex_info = apex_utils.GetApexInfoFromTargetFiles(
+        output_target_files_dir, partition, compressed_only=False)
+    partition_apex_packages = set([info.package_name for info in apex_info])
+    duplicates = apex_packages.intersection(partition_apex_packages)
+    if duplicates:
+      raise ExternalError(
+          'Duplicate APEX packages found in multiple partitions: %s' %
+          ' '.join(duplicates))
+    apex_packages.update(partition_apex_packages)
+
+
 def generate_care_map(partitions, output_target_files_dir):
   """Generates a merged META/care_map.pb file in the output target files dir.
 
@@ -1116,6 +1146,9 @@
   common.RunAndCheckOutput(split_sepolicy_cmd)
   # TODO(b/178864050): Run tests on the combined.policy file.
 
+  # Run validation checks on the pre-installed APEX files.
+  validate_merged_apex_info(output_target_files_temp_dir, partition_map.keys())
+
   generate_images(output_target_files_temp_dir, rebuild_recovery)
 
   generate_super_empty_image(output_target_files_temp_dir, output_super_empty)