Merge "Use vFRC version as-is for ToT sepolicy version" into main
diff --git a/core/base_rules.mk b/core/base_rules.mk
index 07e1afb..b8aa5fe 100644
--- a/core/base_rules.mk
+++ b/core/base_rules.mk
@@ -806,7 +806,7 @@
   ifneq (,$(test_config))
     $(foreach suite, $(LOCAL_COMPATIBILITY_SUITE), \
       $(eval my_compat_dist_config_$(suite) += $(foreach dir, $(call compatibility_suite_dirs,$(suite)), \
-        $(test_config):$(dir)/$(LOCAL_MODULE).config)))
+        $(test_config):$(dir)/$(LOCAL_MODULE).config$(LOCAL_TEST_CONFIG_SUFFIX))))
   endif
 
   ifneq (,$(LOCAL_EXTRA_FULL_TEST_CONFIGS))
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index 0136784..5481d50 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -291,6 +291,7 @@
 LOCAL_SYSTEM_SHARED_LIBRARIES:=none
 LOCAL_TARGET_REQUIRED_MODULES:=
 LOCAL_TEST_CONFIG:=
+LOCAL_TEST_CONFIG_SUFFIX:=
 LOCAL_TEST_DATA:=
 LOCAL_TEST_DATA_BINS:=
 LOCAL_TEST_MAINLINE_MODULES:=
diff --git a/core/python_binary_host_mobly_test_config_template.xml b/core/python_binary_host_mobly_test_config_template.xml
index a6576cd..a986df2 100644
--- a/core/python_binary_host_mobly_test_config_template.xml
+++ b/core/python_binary_host_mobly_test_config_template.xml
@@ -13,13 +13,9 @@
 <configuration description="Config for {MODULE} mobly test">
     {EXTRA_CONFIGS}
 
-    <device name="device1"></device>
-    <device name="device2"></device>
+    <device name="AndroidRealDevice"></device>
+    <device name="AndroidRealDevice"></device>
 
-    <test class="com.android.tradefed.testtype.mobly.MoblyBinaryHostTest">
-      <!-- The mobly-par-file-name should match the module name -->
-      <option name="mobly-par-file-name" value="{MODULE}" />
-      <!-- Timeout limit in milliseconds for all test cases of the python binary -->
-      <option name="mobly-test-timeout" value="300000" />
-    </test>
+    <option name="mobly_pkg" key="file" value="{MODULE}" />
+    <test class="MoblyAospPackageTest" />
 </configuration>
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index 7d2b3ba..5f5f510 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -126,6 +126,7 @@
     ip \
     iptables \
     javax.obex \
+    kcmdlinectrl \
     keystore2 \
     credstore \
     ld.mc \
diff --git a/tools/aconfig/TEST_MAPPING b/tools/aconfig/TEST_MAPPING
index 650c8c0..398da06 100644
--- a/tools/aconfig/TEST_MAPPING
+++ b/tools/aconfig/TEST_MAPPING
@@ -1,25 +1,6 @@
 {
   "presubmit": [
     {
-      // Ensure changes on aconfig auto generated library is compatible with
-      // test testing filtering logic. Breakage on this test means all tests
-      // that using the flag annotations to do filtering will get affected.
-      "name": "FlagAnnotationTests",
-      "options": [
-        {
-          "include-filter": "android.cts.flags.tests.FlagAnnotationTest"
-        }
-      ]
-    },
-    {
-      // Ensure changes on aconfig auto generated library is compatible with
-      // test testing filtering logic. Breakage on this test means all tests
-      // that using the flag macros to do filtering will get affected.
-      "name": "FlagMacrosTests"
-    }
-  ],
-  "postsubmit": [
-    {
       // aconfig unit tests
       "name": "aconfig.test"
     },
@@ -66,6 +47,23 @@
     {
       // aconfig_storage_file unit tests
       "name": "aconfig_storage_file.test"
+    },
+    {
+      // Ensure changes on aconfig auto generated library is compatible with
+      // test testing filtering logic. Breakage on this test means all tests
+      // that using the flag annotations to do filtering will get affected.
+      "name": "FlagAnnotationTests",
+      "options": [
+        {
+          "include-filter": "android.cts.flags.tests.FlagAnnotationTest"
+        }
+      ]
+    },
+    {
+      // Ensure changes on aconfig auto generated library is compatible with
+      // test testing filtering logic. Breakage on this test means all tests
+      // that using the flag macros to do filtering will get affected.
+      "name": "FlagMacrosTests"
     }
   ]
 }
diff --git a/tools/releasetools/merge/merge_meta.py b/tools/releasetools/merge/merge_meta.py
index 198c973..76582c0 100644
--- a/tools/releasetools/merge/merge_meta.py
+++ b/tools/releasetools/merge/merge_meta.py
@@ -53,23 +53,31 @@
 MODULE_KEY_PATTERN = re.compile(r'name="(.+)\.(apex|apk)"')
 
 
-def MergeUpdateEngineConfig(input_metadir1, input_metadir2, merged_meta_dir):
-  UPDATE_ENGINE_CONFIG_NAME = "update_engine_config.txt"
-  config1_path = os.path.join(
-      input_metadir1, UPDATE_ENGINE_CONFIG_NAME)
-  config2_path = os.path.join(
-      input_metadir2, UPDATE_ENGINE_CONFIG_NAME)
-  config1 = ParseUpdateEngineConfig(config1_path)
-  config2 = ParseUpdateEngineConfig(config2_path)
-  # Copy older config to merged target files for maximum compatibility
-  # update_engine in system partition is from system side, but
-  # update_engine_sideload in recovery is from vendor side.
-  if config1 < config2:
-    shutil.copy(config1_path, os.path.join(
-        merged_meta_dir, UPDATE_ENGINE_CONFIG_NAME))
+def MergeUpdateEngineConfig(framework_meta_dir, vendor_meta_dir,
+                            merged_meta_dir):
+  """Merges META/update_engine_config.txt.
+
+  The output is the configuration for maximum compatibility.
+  """
+  _CONFIG_NAME = 'update_engine_config.txt'
+  framework_config_path = os.path.join(framework_meta_dir, _CONFIG_NAME)
+  vendor_config_path = os.path.join(vendor_meta_dir, _CONFIG_NAME)
+  merged_config_path = os.path.join(merged_meta_dir, _CONFIG_NAME)
+
+  if os.path.exists(framework_config_path):
+    framework_config = ParseUpdateEngineConfig(framework_config_path)
+    vendor_config = ParseUpdateEngineConfig(vendor_config_path)
+    # Copy older config to merged target files for maximum compatibility
+    # update_engine in system partition is from system side, but
+    # update_engine_sideload in recovery is from vendor side.
+    if framework_config < vendor_config:
+      shutil.copy(framework_config_path, merged_config_path)
+    else:
+      shutil.copy(vendor_config_path, merged_config_path)
   else:
-    shutil.copy(config2_path, os.path.join(
-        merged_meta_dir, UPDATE_ENGINE_CONFIG_NAME))
+    if not OPTIONS.allow_partial_ab:
+      raise FileNotFoundError(framework_config_path)
+    shutil.copy(vendor_config_path, merged_config_path)
 
 
 def MergeMetaFiles(temp_dir, merged_dir, framework_partitions):
@@ -125,8 +133,7 @@
 
   if OPTIONS.merged_misc_info.get('ab_update') == 'true':
     MergeUpdateEngineConfig(
-        framework_meta_dir,
-        vendor_meta_dir, merged_meta_dir)
+        framework_meta_dir, vendor_meta_dir, merged_meta_dir)
 
   # Write the now-finalized OPTIONS.merged_misc_info.
   merge_utils.WriteSortedData(
@@ -140,16 +147,24 @@
 
   The output contains the union of the partition names.
   """
-  with open(os.path.join(framework_meta_dir, 'ab_partitions.txt')) as f:
-    # Filter out some partitions here to support the case that the
-    # ab_partitions.txt of framework-target-files has non-framework partitions.
-    # This case happens when we use a complete merged target files package as
-    # the framework-target-files.
-    framework_ab_partitions = [
-        partition
-        for partition in f.read().splitlines()
-        if partition in framework_partitions
-    ]
+  framework_ab_partitions = []
+  framework_ab_config = os.path.join(framework_meta_dir, 'ab_partitions.txt')
+  if os.path.exists(framework_ab_config):
+    with open(framework_ab_config) as f:
+      # Filter out some partitions here to support the case that the
+      # ab_partitions.txt of framework-target-files has non-framework
+      # partitions. This case happens when we use a complete merged target
+      # files package as the framework-target-files.
+      framework_ab_partitions.extend([
+          partition
+          for partition in f.read().splitlines()
+          if partition in framework_partitions
+      ])
+  else:
+    if not OPTIONS.allow_partial_ab:
+      raise FileNotFoundError(framework_ab_config)
+    logger.info('Use partial AB because framework ab_partitions.txt does not '
+                'exist.')
 
   with open(os.path.join(vendor_meta_dir, 'ab_partitions.txt')) as f:
     vendor_ab_partitions = f.read().splitlines()
diff --git a/tools/releasetools/merge/merge_target_files.py b/tools/releasetools/merge/merge_target_files.py
index 4619246..fdba927 100755
--- a/tools/releasetools/merge/merge_target_files.py
+++ b/tools/releasetools/merge/merge_target_files.py
@@ -98,6 +98,10 @@
       If provided, resolve the conflict AVB rollback index location when
       necessary.
 
+  --allow-partial-ab
+      If provided, allow merging non-AB framework target files with AB vendor
+      target files, which means that only the vendor has AB partitions.
+
   The following only apply when using the VSDK to perform dexopt on vendor apps:
 
   --framework-dexpreopt-config
@@ -154,6 +158,7 @@
 OPTIONS.rebuild_sepolicy = False
 OPTIONS.keep_tmp = False
 OPTIONS.avb_resolve_rollback_index_location_conflict = False
+OPTIONS.allow_partial_ab = False
 OPTIONS.framework_dexpreopt_config = None
 OPTIONS.framework_dexpreopt_tools = None
 OPTIONS.vendor_dexpreopt_config = None
@@ -576,6 +581,8 @@
       OPTIONS.keep_tmp = True
     elif o == '--avb-resolve-rollback-index-location-conflict':
       OPTIONS.avb_resolve_rollback_index_location_conflict = True
+    elif o == '--allow-partial-ab':
+      OPTIONS.allow_partial_ab = True
     elif o == '--framework-dexpreopt-config':
       OPTIONS.framework_dexpreopt_config = a
     elif o == '--framework-dexpreopt-tools':
@@ -617,6 +624,7 @@
           'rebuild-sepolicy',
           'keep-tmp',
           'avb-resolve-rollback-index-location-conflict',
+          'allow-partial-ab',
       ],
       extra_option_handler=option_handler)