Adds image-specific selinux_fc props to allow different file_contexts.

This enables mixed builds to use the file_contexts.bin from the system
build when regenerating images that come from system target files, and
similarly for file_contexts.bin from the other build when regenerating
images from other target files.

In monolithic (non-mixed) builds all image-specific selinux_fc props
point to the same file_contexts.

Bug: 132108151
Test: Built and booted mixed build devices.
Change-Id: Id51ed6d96ea6337879f1ab21d47c93c67bc25312
diff --git a/tools/releasetools/merge_target_files.py b/tools/releasetools/merge_target_files.py
index 2a722c5..e8c3cf7 100755
--- a/tools/releasetools/merge_target_files.py
+++ b/tools/releasetools/merge_target_files.py
@@ -160,7 +160,6 @@
 
 default_other_item_list = [
     'META/boot_filesystem_config.txt',
-    'META/file_contexts.bin',
     'META/otakeys.txt',
     'META/releasetools.py',
     'META/vendor_filesystem_config.txt',
@@ -501,6 +500,18 @@
         list_suffix='_partition_list')
     merged_info_dict.update(merged_dynamic_partitions_dict)
 
+  # Replace <image>_selinux_fc values with system or other file_contexts.bin
+  # depending on which dictionary the key came from.
+  # Only the file basename is required because all selinux_fc properties are
+  # replaced with the full path to the file under META/ when misc_info.txt is
+  # loaded from target files for repacking. See common.py LoadInfoDict().
+  for key in merged_info_dict:
+    if key.endswith('_selinux_fc'):
+      merged_info_dict[key] = 'other_file_contexts.bin'
+  for key in system_info_dict:
+    if key.endswith('_selinux_fc'):
+      merged_info_dict[key] = 'system_file_contexts.bin'
+
   output_misc_info_txt = os.path.join(output_target_files_temp_dir, 'META',
                                       'misc_info.txt')
   write_sorted_data(data=merged_info_dict, path=output_misc_info_txt)
@@ -605,6 +616,28 @@
   write_sorted_data(data=other_dict.values(), path=output_file)
 
 
+def copy_file_contexts(system_target_files_dir, other_target_files_dir,
+                       output_target_files_dir):
+  """Creates named copies of each build's file_contexts.bin in output META/."""
+  system_fc_path = os.path.join(system_target_files_dir, 'META', 'system_file_contexts.bin')
+  if not os.path.exists(system_fc_path):
+    system_fc_path = os.path.join(system_target_files_dir, 'META', 'file_contexts.bin')
+    if not os.path.exists(system_fc_path):
+      raise ValueError('Missing system file_contexts.bin.')
+  shutil.copyfile(
+      system_fc_path,
+      os.path.join(output_target_files_dir, 'META', 'system_file_contexts.bin'))
+
+  other_fc_path = os.path.join(other_target_files_dir, 'META', 'other_file_contexts.bin')
+  if not os.path.exists(other_fc_path):
+    other_fc_path = os.path.join(other_target_files_dir, 'META', 'file_contexts.bin')
+    if not os.path.exists(other_fc_path):
+      raise ValueError('Missing other file_contexts.bin.')
+  shutil.copyfile(
+      other_fc_path,
+      os.path.join(output_target_files_dir, 'META', 'other_file_contexts.bin'))
+
+
 def process_special_cases(system_target_files_temp_dir,
                           other_target_files_temp_dir,
                           output_target_files_temp_dir, system_misc_info_keys,
@@ -638,6 +671,11 @@
     append_recovery_to_filesystem_config(
         output_target_files_temp_dir=output_target_files_temp_dir)
 
+  copy_file_contexts(
+      system_target_files_dir=system_target_files_temp_dir,
+      other_target_files_dir=other_target_files_temp_dir,
+      output_target_files_dir=output_target_files_temp_dir)
+
   process_misc_info_txt(
       system_target_files_temp_dir=system_target_files_temp_dir,
       other_target_files_temp_dir=other_target_files_temp_dir,