Merge "Merge 'aosp/android16-release' into 'aosp/main-kernel'" into main-kernel
diff --git a/backported_fixes/applied_fixes/ki385124056.txtpb b/backported_fixes/applied_fixes/ki385124056.txtpb
new file mode 100644
index 0000000..e2d4545
--- /dev/null
+++ b/backported_fixes/applied_fixes/ki385124056.txtpb
@@ -0,0 +1,19 @@
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# proto-file: ../backported_fixes.proto
+# proto-message: BackportedFix
+
+known_issue: 385124056
+alias: 4
diff --git a/ci/build_test_suites b/ci/build_test_suites
index 74470a8..a63f3fc 100755
--- a/ci/build_test_suites
+++ b/ci/build_test_suites
@@ -15,5 +15,5 @@
 # limitations under the License.
 set -euo pipefail
 
-build/soong/soong_ui.bash --make-mode build_test_suites
-$(build/soong/soong_ui.bash --dumpvar-mode HOST_OUT)/bin/build_test_suites $@
+build/soong/soong_ui.bash --make-mode dist build_test_suites general-tests-files-list test_mapping || exit $?
+$(build/soong/soong_ui.bash --dumpvar-mode HOST_OUT)/bin/build_test_suites $@ || exit $?
diff --git a/ci/build_test_suites.py b/ci/build_test_suites.py
index d81248b..7636f6a 100644
--- a/ci/build_test_suites.py
+++ b/ci/build_test_suites.py
@@ -16,6 +16,7 @@
 
 import argparse
 from dataclasses import dataclass
+from collections import defaultdict
 import json
 import logging
 import os
@@ -68,6 +69,7 @@
     self.build_context = build_context
     self.args = args
     self.target_optimizations = target_optimizations
+    self.target_to_test_infos = defaultdict(list)
 
   def create_build_plan(self):
 
@@ -102,7 +104,7 @@
         continue
 
       target_optimizer = target_optimizer_getter(
-          target, self.build_context, self.args
+          target, self.build_context, self.args, self.target_to_test_infos[target]
       )
       build_targets.update(target_optimizer.get_build_targets())
       packaging_commands_getters.append(
@@ -178,6 +180,10 @@
       tf_command = self._build_tf_command(test_info)
       discovery_agent = test_discovery_agent.TestDiscoveryAgent(tradefed_args=tf_command)
       for regex in discovery_agent.discover_test_zip_regexes():
+        for target in self.args.extra_targets:
+          target_regex = r'\b(%s.*)\b' % re.escape(target)
+          if re.search(target_regex, regex):
+            self.target_to_test_infos[target].append(test_info)
         build_target_regexes.add(regex)
     return build_target_regexes
 
diff --git a/ci/build_test_suites_test.py b/ci/build_test_suites_test.py
index 190740f..e4501d3 100644
--- a/ci/build_test_suites_test.py
+++ b/ci/build_test_suites_test.py
@@ -257,9 +257,9 @@
   class TestOptimizedBuildTarget(optimized_targets.OptimizedBuildTarget):
 
     def __init__(
-        self, target, build_context, args, output_targets, packaging_commands
+        self, target, build_context, args, test_infos, output_targets, packaging_commands
     ):
-      super().__init__(target, build_context, args)
+      super().__init__(target, build_context, args, test_infos)
       self.output_targets = output_targets
       self.packaging_commands = packaging_commands
 
diff --git a/ci/metrics_agent.py b/ci/metrics_agent.py
index bc2479e..85cdcbd 100644
--- a/ci/metrics_agent.py
+++ b/ci/metrics_agent.py
@@ -92,15 +92,15 @@
       size: int,
       included_modules: set[str],
   ):
-    target_result = self.target_results.get(target_name)
+    target_result = self._target_results.get(target_name)
     artifact = (
         metrics_pb2.OptimizedBuildMetrics.TargetOptimizationResult.OutputArtifact()
     )
     artifact.name = artifact_name
     artifact.size = size
     for module in included_modules:
-      artifact.included_modules.add(module)
-    target_result.output_artifacts.add(artifact)
+      artifact.included_modules.append(module)
+    target_result.output_artifact.append(artifact)
 
   def end_reporting(self):
     for target_result in self._target_results.values():
diff --git a/ci/optimized_targets.py b/ci/optimized_targets.py
index 688bdd8..548e342 100644
--- a/ci/optimized_targets.py
+++ b/ci/optimized_targets.py
@@ -23,7 +23,9 @@
 import subprocess
 
 from build_context import BuildContext
+import metrics_agent
 import test_mapping_module_retriever
+import test_discovery_agent
 
 
 class OptimizedBuildTarget(ABC):
@@ -42,10 +44,12 @@
       target: str,
       build_context: BuildContext,
       args: argparse.Namespace,
+      test_infos,
   ):
     self.target = target
     self.build_context = build_context
     self.args = args
+    self.test_infos = test_infos
 
   def get_build_targets(self) -> set[str]:
     features = self.build_context.enabled_build_features
@@ -53,6 +57,8 @@
       self.modules_to_build = self.get_build_targets_impl()
       return self.modules_to_build
 
+    if self.target == 'general-tests':
+      self._report_info_metrics_silently('general-tests.zip')
     self.modules_to_build = {self.target}
     return {self.target}
 
@@ -161,6 +167,16 @@
         f'{dist_dir / name}',
     ]
 
+  def _report_info_metrics_silently(self, artifact_name):
+    try:
+      metrics_agent_instance = metrics_agent.MetricsAgent.instance()
+      targets = self.get_build_targets_impl()
+      metrics_agent_instance.report_optimized_target(self.target)
+      metrics_agent_instance.add_target_artifact(self.target, artifact_name, 0, targets)
+    except Exception as e:
+      logging.error(f'error while silently reporting metrics: {e}')
+
+
 
 class NullOptimizer(OptimizedBuildTarget):
   """No-op target optimizer.
@@ -191,6 +207,19 @@
 
     self._change_info_contents = change_info_contents
 
+  def get_changed_paths(self) -> set[str]:
+    changed_paths = set()
+    for change in self._change_info_contents['changes']:
+      project_path = change.get('projectPath') + '/'
+
+      for revision in change.get('revisions'):
+        for file_info in revision.get('fileInfos'):
+          file_path = file_info.get('path')
+          dir_path = os.path.dirname(file_path)
+          changed_paths.add(project_path + dir_path)
+
+    return changed_paths
+
   def find_changed_files(self) -> set[str]:
     changed_files = set()
 
@@ -207,11 +236,7 @@
 class GeneralTestsOptimizer(OptimizedBuildTarget):
   """general-tests optimizer
 
-  This optimizer reads in the list of changed files from the file located in
-  env[CHANGE_INFO] and uses this list alongside the normal TEST MAPPING logic to
-  determine what test mapping modules will run for the given changes. It then
-  builds those modules and packages them in the same way general-tests.zip is
-  normally built.
+  This optimizer uses test discovery to build a list of modules that are needed by all tests configured for the build. These modules are then build and packaged by the optimizer in the same way as they are in a normal build.
   """
 
   # List of modules that are built alongside general-tests as dependencies.
@@ -219,93 +244,105 @@
       'cts-tradefed',
       'vts-tradefed',
       'compatibility-host-util',
-      'general-tests-shared-libs',
   ])
 
   def get_build_targets_impl(self) -> set[str]:
-    change_info_file_path = os.environ.get('CHANGE_INFO')
-    if not change_info_file_path:
-      logging.info(
-          'No CHANGE_INFO env var found, general-tests optimization disabled.'
-      )
-      return {'general-tests'}
-
-    test_infos = self.build_context.test_infos
-    test_mapping_test_groups = set()
-    for test_info in test_infos:
-      is_test_mapping = test_info.is_test_mapping
-      current_test_mapping_test_groups = test_info.test_mapping_test_groups
-      uses_general_tests = test_info.build_target_used('general-tests')
-
-      if uses_general_tests and not is_test_mapping:
-        logging.info(
-            'Test uses general-tests.zip but is not test-mapping, general-tests'
-            ' optimization disabled.'
-        )
-        return {'general-tests'}
-
-      if is_test_mapping:
-        test_mapping_test_groups.update(current_test_mapping_test_groups)
-
-    change_info = ChangeInfo(change_info_file_path)
-    changed_files = change_info.find_changed_files()
-
-    test_mappings = test_mapping_module_retriever.GetTestMappings(
-        changed_files, set()
-    )
+    self._general_tests_outputs = self._get_general_tests_outputs()
+    test_modules = self._get_test_discovery_modules()
 
     modules_to_build = set(self._REQUIRED_MODULES)
-
-    modules_to_build.update(
-        test_mapping_module_retriever.FindAffectedModules(
-            test_mappings, changed_files, test_mapping_test_groups
-        )
-    )
+    self._build_outputs = []
+    for module in test_modules:
+      module_outputs = [output for output in self._general_tests_outputs if module in output]
+      if module_outputs:
+        modules_to_build.add(module)
+        self._build_outputs.extend(module_outputs)
 
     return modules_to_build
 
+  def _get_general_tests_outputs(self) -> list[str]:
+    src_top = pathlib.Path(os.environ.get('TOP', os.getcwd()))
+    soong_vars = self._query_soong_vars(
+        src_top,
+        [
+            'PRODUCT_OUT',
+        ],
+    )
+    product_out = pathlib.Path(soong_vars.get('PRODUCT_OUT'))
+    with open(f'{product_out / "general-tests_files"}') as general_tests_list_file:
+      general_tests_list = general_tests_list_file.readlines()
+    with open(f'{product_out / "general-tests_host_files"}') as general_tests_list_file:
+      self._general_tests_host_outputs = general_tests_list_file.readlines()
+    with open(f'{product_out / "general-tests_target_files"}') as general_tests_list_file:
+      self._general_tests_target_outputs = general_tests_list_file.readlines()
+    return general_tests_list
+
+
+  def _get_test_discovery_modules(self) -> set[str]:
+    change_info = ChangeInfo(os.environ.get('CHANGE_INFO'))
+    change_paths = change_info.get_changed_paths()
+    test_modules = set()
+    for test_info in self.test_infos:
+      tf_command = self._build_tf_command(test_info, change_paths)
+      discovery_agent = test_discovery_agent.TestDiscoveryAgent(tradefed_args=tf_command, test_mapping_zip_path=os.environ.get('DIST_DIR')+'/test_mappings.zip')
+      modules, dependencies = discovery_agent.discover_test_mapping_test_modules()
+      for regex in modules:
+        test_modules.add(regex)
+    return test_modules
+
+
+  def _build_tf_command(self, test_info, change_paths) -> list[str]:
+    command = [test_info.command]
+    for extra_option in test_info.extra_options:
+      if not extra_option.get('key'):
+        continue
+      arg_key = '--' + extra_option.get('key')
+      if arg_key == '--build-id':
+        command.append(arg_key)
+        command.append(os.environ.get('BUILD_NUMBER'))
+        continue
+      if extra_option.get('values'):
+        for value in extra_option.get('values'):
+          command.append(arg_key)
+          command.append(value)
+      else:
+        command.append(arg_key)
+    if test_info.is_test_mapping:
+      for change_path in change_paths:
+        command.append('--test-mapping-path')
+        command.append(change_path)
+
+    return command
+
   def get_package_outputs_commands_impl(self):
     src_top = pathlib.Path(os.environ.get('TOP', os.getcwd()))
     dist_dir = pathlib.Path(os.environ.get('DIST_DIR'))
+    tmp_dir = pathlib.Path(os.environ.get('TMPDIR'))
+    print(f'modules: {self.modules_to_build}')
 
+    host_outputs = [str(src_top) + '/' + file for file in self._general_tests_host_outputs if any('/'+module+'/' in file for module in self.modules_to_build)]
+    target_outputs = [str(src_top) + '/' + file for file in self._general_tests_target_outputs if any('/'+module+'/' in file for module in self.modules_to_build)]
+    host_config_files = [file for file in host_outputs if file.endswith('.config\n')]
+    target_config_files = [file for file in target_outputs if file.endswith('.config\n')]
+    logging.info(host_outputs)
+    logging.info(target_outputs)
+    with open(f"{tmp_dir / 'host.list'}", 'w') as host_list_file:
+      for output in host_outputs:
+        host_list_file.write(output)
+    with open(f"{tmp_dir / 'target.list'}", 'w') as target_list_file:
+      for output in target_outputs:
+        target_list_file.write(output)
     soong_vars = self._query_soong_vars(
         src_top,
         [
-            'HOST_OUT_TESTCASES',
-            'TARGET_OUT_TESTCASES',
             'PRODUCT_OUT',
             'SOONG_HOST_OUT',
             'HOST_OUT',
         ],
     )
-    host_out_testcases = pathlib.Path(soong_vars.get('HOST_OUT_TESTCASES'))
-    target_out_testcases = pathlib.Path(soong_vars.get('TARGET_OUT_TESTCASES'))
     product_out = pathlib.Path(soong_vars.get('PRODUCT_OUT'))
     soong_host_out = pathlib.Path(soong_vars.get('SOONG_HOST_OUT'))
     host_out = pathlib.Path(soong_vars.get('HOST_OUT'))
-
-    host_paths = []
-    target_paths = []
-    host_config_files = []
-    target_config_files = []
-    for module in self.modules_to_build:
-      # The required modules are handled separately, no need to package.
-      if module in self._REQUIRED_MODULES:
-        continue
-
-      host_path = host_out_testcases / module
-      if os.path.exists(host_path):
-        host_paths.append(host_path)
-        self._collect_config_files(src_top, host_path, host_config_files)
-
-      target_path = target_out_testcases / module
-      if os.path.exists(target_path):
-        target_paths.append(target_path)
-        self._collect_config_files(src_top, target_path, target_config_files)
-
-      if not os.path.exists(host_path) and not os.path.exists(target_path):
-        logging.info(f'No host or target build outputs found for {module}.')
-
     zip_commands = []
 
     zip_commands.extend(
@@ -320,24 +357,23 @@
     )
 
     zip_command = self._base_zip_command(src_top, dist_dir, 'general-tests.zip')
-
     # Add host testcases.
-    if host_paths:
+    if host_outputs:
       zip_command.extend(
           self._generate_zip_options_for_items(
               prefix='host',
-              relative_root=f'{src_top / soong_host_out}',
-              directories=host_paths,
+              relative_root=str(host_out),
+              list_files=[f"{tmp_dir / 'host.list'}"],
           )
       )
 
     # Add target testcases.
-    if target_paths:
+    if target_outputs:
       zip_command.extend(
           self._generate_zip_options_for_items(
               prefix='target',
-              relative_root=f'{src_top / product_out}',
-              directories=target_paths,
+              relative_root=str(product_out),
+              list_files=[f"{tmp_dir / 'target.list'}"],
           )
       )
 
@@ -357,20 +393,11 @@
         )
     )
 
+    zip_command.append('-sha256')
+
     zip_commands.append(zip_command)
     return zip_commands
 
-  def _collect_config_files(
-      self,
-      src_top: pathlib.Path,
-      root_dir: pathlib.Path,
-      config_files: list[str],
-  ):
-    for root, dirs, files in os.walk(src_top / root_dir):
-      for file in files:
-        if file.endswith('.config'):
-          config_files.append(root_dir / file)
-
   def _get_zip_test_configs_zips_commands(
       self,
       src_top: pathlib.Path,
diff --git a/ci/optimized_targets_test.py b/ci/optimized_targets_test.py
index 0b0c0ec..2935c83 100644
--- a/ci/optimized_targets_test.py
+++ b/ci/optimized_targets_test.py
@@ -26,6 +26,7 @@
 from build_context import BuildContext
 import optimized_targets
 from pyfakefs import fake_filesystem_unittest
+import test_discovery_agent
 
 
 class GeneralTestsOptimizerTest(fake_filesystem_unittest.TestCase):
@@ -38,14 +39,12 @@
     self.mock_os_environ = os_environ_patcher.start()
 
     self._setup_working_build_env()
-    self._write_change_info_file()
     test_mapping_dir = pathlib.Path('/project/path/file/path')
     test_mapping_dir.mkdir(parents=True)
-    self._write_test_mapping_file()
 
   def _setup_working_build_env(self):
-    self.change_info_file = pathlib.Path('/tmp/change_info')
     self._write_soong_ui_file()
+    self._write_change_info_file()
     self._host_out_testcases = pathlib.Path('/tmp/top/host_out_testcases')
     self._host_out_testcases.mkdir(parents=True)
     self._target_out_testcases = pathlib.Path('/tmp/top/target_out_testcases')
@@ -56,143 +55,147 @@
     self._soong_host_out.mkdir(parents=True)
     self._host_out = pathlib.Path('/tmp/top/host_out')
     self._host_out.mkdir(parents=True)
+    self._write_general_tests_files_outputs()
 
     self._dist_dir = pathlib.Path('/tmp/top/out/dist')
     self._dist_dir.mkdir(parents=True)
 
     self.mock_os_environ.update({
-        'CHANGE_INFO': str(self.change_info_file),
         'TOP': '/tmp/top',
         'DIST_DIR': '/tmp/top/out/dist',
+        'TMPDIR': '/tmp/',
+        'CHANGE_INFO': '/tmp/top/change_info'
     })
 
+  def _write_change_info_file(self):
+    change_info_path = pathlib.Path('/tmp/top/')
+    with open(os.path.join(change_info_path, 'change_info'), 'w') as f:
+      f.write("""
+    {
+      "changes": [
+        {
+          "projectPath": "build/ci",
+          "revisions": [
+            {
+              "revisionNumber": 1,
+              "fileInfos": [
+                {
+                  "path": "src/main/java/com/example/MyClass.java",
+                  "action": "MODIFIED"
+                },
+                {
+                  "path": "src/test/java/com/example/MyClassTest.java",
+                  "action": "ADDED"
+                }
+              ]
+            },
+            {
+              "revisionNumber": 2,
+              "fileInfos": [
+                {
+                  "path": "src/main/java/com/example/AnotherClass.java",
+                  "action": "MODIFIED"
+                }
+              ]
+            }
+          ]
+        }
+      ]
+    }
+    """)
+
   def _write_soong_ui_file(self):
     soong_path = pathlib.Path('/tmp/top/build/soong')
     soong_path.mkdir(parents=True)
     with open(os.path.join(soong_path, 'soong_ui.bash'), 'w') as f:
       f.write("""
               #/bin/bash
-              echo HOST_OUT_TESTCASES='/tmp/top/host_out_testcases'
-              echo TARGET_OUT_TESTCASES='/tmp/top/target_out_testcases'
               echo PRODUCT_OUT='/tmp/top/product_out'
               echo SOONG_HOST_OUT='/tmp/top/soong_host_out'
               echo HOST_OUT='/tmp/top/host_out'
               """)
     os.chmod(os.path.join(soong_path, 'soong_ui.bash'), 0o666)
 
-  def _write_change_info_file(self):
-    change_info_contents = {
-        'changes': [{
-            'projectPath': '/project/path',
-            'revisions': [{
-                'fileInfos': [{
-                    'path': 'file/path/file_name',
-                }],
-            }],
-        }]
-    }
+  def _write_general_tests_files_outputs(self):
+    with open(os.path.join(self._product_out, 'general-tests_files'), 'w') as f:
+      f.write("""
+              path/to/module_1/general-tests-host-file
+              path/to/module_1/general-tests-host-file.config
+              path/to/module_1/general-tests-target-file
+              path/to/module_1/general-tests-target-file.config
+              path/to/module_2/general-tests-host-file
+              path/to/module_2/general-tests-host-file.config
+              path/to/module_2/general-tests-target-file
+              path/to/module_2/general-tests-target-file.config
+              path/to/module_1/general-tests-host-file
+              path/to/module_1/general-tests-host-file.config
+              path/to/module_1/general-tests-target-file
+              path/to/module_1/general-tests-target-file.config
+              """)
+    with open(os.path.join(self._product_out, 'general-tests_host_files'), 'w') as f:
+      f.write("""
+              path/to/module_1/general-tests-host-file
+              path/to/module_1/general-tests-host-file.config
+              path/to/module_2/general-tests-host-file
+              path/to/module_2/general-tests-host-file.config
+              path/to/module_1/general-tests-host-file
+              path/to/module_1/general-tests-host-file.config
+              """)
+    with open(os.path.join(self._product_out, 'general-tests_target_files'), 'w') as f:
+      f.write("""
+              path/to/module_1/general-tests-target-file
+              path/to/module_1/general-tests-target-file.config
+              path/to/module_2/general-tests-target-file
+              path/to/module_2/general-tests-target-file.config
+              path/to/module_1/general-tests-target-file
+              path/to/module_1/general-tests-target-file.config
+              """)
 
-    with open(self.change_info_file, 'w') as f:
-      json.dump(change_info_contents, f)
-
-  def _write_test_mapping_file(self):
-    test_mapping_contents = {
-        'test-mapping-group': [
-            {
-                'name': 'test_mapping_module',
-            },
-        ],
-    }
-
-    with open('/project/path/file/path/TEST_MAPPING', 'w') as f:
-      json.dump(test_mapping_contents, f)
-
-  def test_general_tests_optimized(self):
-    optimizer = self._create_general_tests_optimizer()
-
-    build_targets = optimizer.get_build_targets()
-
-    expected_build_targets = set(
-        optimized_targets.GeneralTestsOptimizer._REQUIRED_MODULES
-    )
-    expected_build_targets.add('test_mapping_module')
-
-    self.assertSetEqual(build_targets, expected_build_targets)
-
-  def test_no_change_info_no_optimization(self):
-    del os.environ['CHANGE_INFO']
-
-    optimizer = self._create_general_tests_optimizer()
-
-    build_targets = optimizer.get_build_targets()
-
-    self.assertSetEqual(build_targets, {'general-tests'})
-
-  def test_mapping_groups_unused_module_not_built(self):
-    test_context = self._create_test_context()
-    test_context['testInfos'][0]['extraOptions'] = [
-        {
-            'key': 'additional-files-filter',
-            'values': ['general-tests.zip'],
-        },
-        {
-            'key': 'test-mapping-test-group',
-            'values': ['unused-test-mapping-group'],
-        },
-    ]
-    optimizer = self._create_general_tests_optimizer(
-        build_context=self._create_build_context(test_context=test_context)
-    )
-
-    build_targets = optimizer.get_build_targets()
-
-    expected_build_targets = set(
-        optimized_targets.GeneralTestsOptimizer._REQUIRED_MODULES
-    )
-    self.assertSetEqual(build_targets, expected_build_targets)
-
-  def test_general_tests_used_by_non_test_mapping_test_no_optimization(self):
-    test_context = self._create_test_context()
-    test_context['testInfos'][0]['extraOptions'] = [{
-        'key': 'additional-files-filter',
-        'values': ['general-tests.zip'],
-    }]
-    optimizer = self._create_general_tests_optimizer(
-        build_context=self._create_build_context(test_context=test_context)
-    )
-
-    build_targets = optimizer.get_build_targets()
-
-    self.assertSetEqual(build_targets, {'general-tests'})
-
-  def test_malformed_change_info_raises(self):
-    with open(self.change_info_file, 'w') as f:
-      f.write('not change info')
-
-    optimizer = self._create_general_tests_optimizer()
-
-    with self.assertRaises(json.decoder.JSONDecodeError):
-      build_targets = optimizer.get_build_targets()
-
-  def test_malformed_test_mapping_raises(self):
-    with open('/project/path/file/path/TEST_MAPPING', 'w') as f:
-      f.write('not test mapping')
-
-    optimizer = self._create_general_tests_optimizer()
-
-    with self.assertRaises(json.decoder.JSONDecodeError):
-      build_targets = optimizer.get_build_targets()
 
   @mock.patch('subprocess.run')
-  def test_packaging_outputs_success(self, subprocess_run):
+  @mock.patch.object(test_discovery_agent.TestDiscoveryAgent, 'discover_test_mapping_test_modules')
+  def test_general_tests_optimized(self, discover_modules, subprocess_run):
     subprocess_run.return_value = self._get_soong_vars_output()
+    discover_modules.return_value = (['module_1'], ['dependency_1'])
+
+    optimizer = self._create_general_tests_optimizer()
+
+    build_targets = optimizer.get_build_targets()
+
+    expected_build_targets = set(
+        optimized_targets.GeneralTestsOptimizer._REQUIRED_MODULES
+    )
+    expected_build_targets.add('module_1')
+
+    self.assertSetEqual(build_targets, expected_build_targets)
+
+  @mock.patch('subprocess.run')
+  @mock.patch.object(test_discovery_agent.TestDiscoveryAgent, 'discover_test_mapping_test_modules')
+  def test_module_unused_module_not_built(self, discover_modules, subprocess_run):
+    subprocess_run.return_value = self._get_soong_vars_output()
+    discover_modules.return_value = (['no_module'], ['dependency_1'])
+
+    optimizer = self._create_general_tests_optimizer()
+
+    build_targets = optimizer.get_build_targets()
+
+    expected_build_targets = set(
+        optimized_targets.GeneralTestsOptimizer._REQUIRED_MODULES
+    )
+    self.assertSetEqual(build_targets, expected_build_targets)
+
+  @mock.patch('subprocess.run')
+  @mock.patch.object(test_discovery_agent.TestDiscoveryAgent, 'discover_test_mapping_test_modules')
+  def test_packaging_outputs_success(self, discover_modules, subprocess_run):
+    subprocess_run.return_value = self._get_soong_vars_output()
+    discover_modules.return_value = (['module_1'], ['dependency_1'])
     optimizer = self._create_general_tests_optimizer()
     self._set_up_build_outputs(['test_mapping_module'])
 
     targets = optimizer.get_build_targets()
     package_commands = optimizer.get_package_outputs_commands()
 
-    self._verify_soong_zip_commands(package_commands, ['test_mapping_module'])
+    self._verify_soong_zip_commands(package_commands, ['module_1'])
 
   @mock.patch('subprocess.run')
   def test_get_soong_dumpvars_fails_raises(self, subprocess_run):
@@ -200,10 +203,8 @@
     optimizer = self._create_general_tests_optimizer()
     self._set_up_build_outputs(['test_mapping_module'])
 
-    targets = optimizer.get_build_targets()
-
     with self.assertRaisesRegex(RuntimeError, 'Soong dumpvars failed!'):
-      package_commands = optimizer.get_package_outputs_commands()
+      targets = optimizer.get_build_targets()
 
   @mock.patch('subprocess.run')
   def test_get_soong_dumpvars_bad_output_raises(self, subprocess_run):
@@ -213,18 +214,16 @@
     optimizer = self._create_general_tests_optimizer()
     self._set_up_build_outputs(['test_mapping_module'])
 
-    targets = optimizer.get_build_targets()
-
     with self.assertRaisesRegex(
         RuntimeError, 'Error parsing soong dumpvars output'
     ):
-      package_commands = optimizer.get_package_outputs_commands()
+      targets = optimizer.get_build_targets()
 
   def _create_general_tests_optimizer(self, build_context: BuildContext = None):
     if not build_context:
       build_context = self._create_build_context()
     return optimized_targets.GeneralTestsOptimizer(
-        'general-tests', build_context, None
+        'general-tests', build_context, None, build_context.test_infos
     )
 
   def _create_build_context(
@@ -274,11 +273,10 @@
     return_value = subprocess.CompletedProcess(args=[], returncode=return_code)
     if not stdout:
       stdout = textwrap.dedent(f"""\
-                               HOST_OUT_TESTCASES='{self._host_out_testcases}'
-                               TARGET_OUT_TESTCASES='{self._target_out_testcases}'
                                PRODUCT_OUT='{self._product_out}'
                                SOONG_HOST_OUT='{self._soong_host_out}'
-                               HOST_OUT='{self._host_out}'""")
+                               HOST_OUT='{self._host_out}'
+                               """)
 
     return_value.stdout = stdout
     return return_value
diff --git a/ci/test_discovery_agent.py b/ci/test_discovery_agent.py
index 008ee47..3c1caf4 100644
--- a/ci/test_discovery_agent.py
+++ b/ci/test_discovery_agent.py
@@ -30,6 +30,10 @@
 
   _TRADEFED_TEST_ZIP_REGEXES_LIST_KEY = "TestZipRegexes"
 
+  _TRADEFED_TEST_MODULES_LIST_KEY = "TestModules"
+
+  _TRADEFED_TEST_DEPENDENCIES_LIST_KEY = "TestDependencies"
+
   _TRADEFED_DISCOVERY_OUTPUT_FILE_NAME = "test_discovery_agent.txt"
 
   def __init__(
@@ -49,7 +53,7 @@
       A list of test zip regexes that TF is going to try to pull files from.
     """
     test_discovery_output_file_name = os.path.join(
-        os.environ.get('TOP'), 'out', self._TRADEFED_DISCOVERY_OUTPUT_FILE_NAME
+        os.environ.get("TOP"), "out", self._TRADEFED_DISCOVERY_OUTPUT_FILE_NAME
     )
     with open(
         test_discovery_output_file_name, mode="w+t"
@@ -89,14 +93,61 @@
         raise TestDiscoveryError("No test zip regexes returned")
       return data[self._TRADEFED_TEST_ZIP_REGEXES_LIST_KEY]
 
-  def discover_test_modules(self) -> list[str]:
-    """Discover test modules from TradeFed.
+  def discover_test_mapping_test_modules(self) -> (list[str], list[str]):
+    """Discover test mapping test modules and dependencies from TradeFed.
 
     Returns:
-      A list of test modules that TradeFed is going to execute based on the
+      A tuple that contains a list of test modules and a list of test
+      dependencies that TradeFed is going to execute based on the
       TradeFed test args.
     """
-    return []
+    test_discovery_output_file_name = os.path.join(
+        os.environ.get("TOP"), "out", self._TRADEFED_DISCOVERY_OUTPUT_FILE_NAME
+    )
+    with open(
+        test_discovery_output_file_name, mode="w+t"
+    ) as test_discovery_output_file:
+      java_args = []
+      java_args.append("prebuilts/jdk/jdk21/linux-x86/bin/java")
+      java_args.append("-cp")
+      java_args.append(
+          self.create_classpath(self.tradefed_jar_relevant_files_path)
+      )
+      java_args.append(
+          "com.android.tradefed.observatory.TestMappingDiscoveryAgent"
+      )
+      java_args.extend(self.tradefed_args)
+      env = os.environ.copy()
+      env.update({"SKIP_JAVA_QUERY": "1"})
+      env.update({"ALLOW_EMPTY_TEST_MAPPING": "1"})
+      env.update({"TF_TEST_MAPPING_ZIP_FILE": self.test_mapping_zip_path})
+      env.update({"DISCOVERY_OUTPUT_FILE": test_discovery_output_file.name})
+      logging.info(f"Calling test discovery with args: {java_args}")
+      try:
+        result = subprocess.run(args=java_args, env=env, text=True, check=True, stdout = subprocess.PIPE,
+    stderr = subprocess.PIPE)
+        logging.info(f"Test discovery agent output: {result.stdout}")
+      except subprocess.CalledProcessError as e:
+        raise TestDiscoveryError(
+            f"Failed to run test discovery, stdout: {e.stdout}, stderr:"
+            f" {e.stderr}, returncode: {e.returncode}"
+        )
+      data = json.loads(test_discovery_output_file.read())
+      logging.info(f"Test discovery result file content: {data}")
+      if (
+          self._TRADEFED_NO_POSSIBLE_TEST_DISCOVERY_KEY in data
+          and data[self._TRADEFED_NO_POSSIBLE_TEST_DISCOVERY_KEY]
+      ):
+        raise TestDiscoveryError("No possible test discovery")
+      if (
+          data[self._TRADEFED_TEST_MODULES_LIST_KEY] is None
+          or data[self._TRADEFED_TEST_MODULES_LIST_KEY] is []
+      ):
+        raise TestDiscoveryError("No test modules returned")
+      return (
+          data[self._TRADEFED_TEST_MODULES_LIST_KEY],
+          data[self._TRADEFED_TEST_DEPENDENCIES_LIST_KEY],
+      )
 
   def create_classpath(self, directory):
     """Creates a classpath string from all .jar files in the given directory.
diff --git a/core/Makefile b/core/Makefile
index 150f5bc..5620d96 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -7827,6 +7827,7 @@
 	        -I $(HOST_OUT) \
 	        -I $(TARGET_COMMON_OUT_ROOT) \
 	        -v "PLATFORM_NAME=$(PRIVATE_PLATFORM_NAME)" \
+	        -v "PLATFORM_SDK_API_VERSION=$(PLATFORM_SDK_VERSION_FULL)" \
 	        -v "OUT_DIR=$(OUT_DIR)" \
 	        -v "HOST_OUT=$(HOST_OUT)" \
 	        -v "TARGET_ARCH=$(TARGET_ARCH)" \
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index 377d6e8..59b6467 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -157,8 +157,6 @@
 
 $(call add_soong_config_var_value,ANDROID,release_libpower_no_lock_binder_txn,$(RELEASE_LIBPOWER_NO_LOCK_BINDER_TXN))
 
-$(call add_soong_config_var_value,ANDROID,release_package_libandroid_runtime_punch_holes,$(RELEASE_PACKAGE_LIBANDROID_RUNTIME_PUNCH_HOLES))
-
 $(call add_soong_config_var_value,ANDROID,release_selinux_data_data_ignore,$(RELEASE_SELINUX_DATA_DATA_IGNORE))
 ifneq (,$(filter eng userdebug,$(TARGET_BUILD_VARIANT)))
     # write appcompat system properties on userdebug and eng builds
diff --git a/core/board_config.mk b/core/board_config.mk
index 4bd473e..ca36adb 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -290,7 +290,7 @@
     $(error Valid values of $(var) are "true", "false", and "". Not "$($(var))")))
 
 include $(BUILD_SYSTEM)/board_config_wifi.mk
-include $(BUILD_SYSTEM)/board_config_wpa_supplicant.mk
+-include external/wpa_supplicant_8/board_config_wpa_supplicant.mk
 
 # Set up soong config for "soong_config_value_variable".
 -include hardware/interfaces/configstore/1.1/default/surfaceflinger.mk
diff --git a/core/board_config_wpa_supplicant.mk b/core/board_config_wpa_supplicant.mk
deleted file mode 100644
index 9ef438e..0000000
--- a/core/board_config_wpa_supplicant.mk
+++ /dev/null
@@ -1,88 +0,0 @@
-#
-# Copyright (C) 2024 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# ###############################################################
-# This file adds wpa_supplicant_8 variables into soong config namespace (`wpa_supplicant_8`)
-# ###############################################################
-
-ifdef BOARD_HOSTAPD_DRIVER
-$(call soong_config_set_bool,wpa_supplicant_8,wpa_build_hostapd,true)
-ifneq ($(BOARD_HOSTAPD_DRIVER),NL80211)
-    $(error BOARD_HOSTAPD_DRIVER set to $(BOARD_HOSTAPD_DRIVER) but current soong expected it should be NL80211 only!)
-endif
-endif
-
-ifdef BOARD_WPA_SUPPLICANT_DRIVER
-ifneq ($(BOARD_WPA_SUPPLICANT_DRIVER),NL80211)
-    $(error BOARD_WPA_SUPPLICANT_DRIVER set to $(BOARD_WPA_SUPPLICANT_DRIVER) but current soong expected it should be NL80211 only!)
-endif
-endif
-
-# This is for CONFIG_DRIVER_NL80211_BRCM, CONFIG_DRIVER_NL80211_SYNA, CONFIG_DRIVER_NL80211_QCA
-# And it is only used for a cflags setting in driver.
-$(call soong_config_set,wpa_supplicant_8,board_wlan_device,$(BOARD_WLAN_DEVICE))
-
-# Belong to CONFIG_IEEE80211AX definition
-ifeq ($(WIFI_FEATURE_HOSTAPD_11AX),true)
-$(call soong_config_set_bool,wpa_supplicant_8,hostapd_11ax,true)
-endif
-
-# Belong to CONFIG_IEEE80211BE definition
-ifeq ($(WIFI_FEATURE_HOSTAPD_11BE),true)
-$(call soong_config_set_bool,wpa_supplicant_8,hostapd_11be,true)
-endif
-
-# PLATFORM_VERSION
-$(call soong_config_set,wpa_supplicant_8,platform_version,$(PLATFORM_VERSION))
-
-# BOARD_HOSTAPD_PRIVATE_LIB
-ifeq ($(BOARD_HOSTAPD_PRIVATE_LIB),)
-$(call soong_config_set_bool,wpa_supplicant_8,hostapd_use_stub_lib,true)
-else
-$(call soong_config_set,wpa_supplicant_8,board_hostapd_private_lib,$(BOARD_HOSTAPD_PRIVATE_LIB))
-endif
-
-ifeq ($(BOARD_HOSTAPD_CONFIG_80211W_MFP_OPTIONAL),true)
-$(call soong_config_set_bool,wpa_supplicant_8,board_hostapd_config_80211w_mfp_optional,true)
-endif
-
-ifneq ($(BOARD_HOSTAPD_PRIVATE_LIB_EVENT),)
-$(call soong_config_set_bool,wpa_supplicant_8,board_hostapd_private_lib_event,true)
-endif
-
-# BOARD_WPA_SUPPLICANT_PRIVATE_LIB
-ifeq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB),)
-$(call soong_config_set_bool,wpa_supplicant_8,wpa_supplicant_use_stub_lib,true)
-else
-$(call soong_config_set,wpa_supplicant_8,board_wpa_supplicant_private_lib,$(BOARD_WPA_SUPPLICANT_PRIVATE_LIB))
-endif
-
-ifneq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB_EVENT),)
-$(call soong_config_set_bool,wpa_supplicant_8,board_wpa_supplicant_private_lib_event,true)
-endif
-
-ifeq ($(WIFI_PRIV_CMD_UPDATE_MBO_CELL_STATUS), enabled)
-$(call soong_config_set_bool,wpa_supplicant_8,wifi_priv_cmd_update_mbo_cell_status,true)
-endif
-
-ifeq ($(WIFI_HIDL_UNIFIED_SUPPLICANT_SERVICE_RC_ENTRY), true)
-$(call soong_config_set_bool,wpa_supplicant_8,wifi_hidl_unified_supplicant_service_rc_entry,true)
-endif
-
-# New added in internal main
-ifeq ($(WIFI_BRCM_OPEN_SOURCE_MULTI_AKM), enabled)
-$(call soong_config_set_bool,wpa_supplicant_8,wifi_brcm_open_source_multi_akm,true)
-endif
diff --git a/core/build_id.mk b/core/build_id.mk
index bed839f..9067611 100644
--- a/core/build_id.mk
+++ b/core/build_id.mk
@@ -18,4 +18,4 @@
 # (like "CRB01").  It must be a single word, and is
 # capitalized by convention.
 
-BUILD_ID=MAIN
+BUILD_ID=BP2A.250605.031.A2
diff --git a/core/soong_config.mk b/core/soong_config.mk
index b774648..dcfe9ff 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -38,6 +38,7 @@
 $(call add_json_str,  Platform_display_version_name,     $(PLATFORM_DISPLAY_VERSION))
 $(call add_json_str,  Platform_version_name,             $(PLATFORM_VERSION))
 $(call add_json_val,  Platform_sdk_version,              $(PLATFORM_SDK_VERSION))
+$(call add_json_val,  Platform_sdk_version_full,         $(PLATFORM_SDK_VERSION_FULL))
 $(call add_json_str,  Platform_sdk_codename,             $(PLATFORM_VERSION_CODENAME))
 $(call add_json_bool, Platform_sdk_final,                $(filter REL,$(PLATFORM_VERSION_CODENAME)))
 $(call add_json_val,  Platform_sdk_extension_version,    $(PLATFORM_SDK_EXTENSION_VERSION))
diff --git a/core/sysprop.mk b/core/sysprop.mk
index 5485a3a..4c040e4 100644
--- a/core/sysprop.mk
+++ b/core/sysprop.mk
@@ -79,7 +79,7 @@
     echo "ro.$(1).build.version.release=$(PLATFORM_VERSION_LAST_STABLE)" >> $(2);\
     echo "ro.$(1).build.version.release_or_codename=$(PLATFORM_VERSION)" >> $(2);\
     echo "ro.$(1).build.version.sdk=$(PLATFORM_SDK_VERSION)" >> $(2);\
-    echo "ro.$(1).build.version.sdk_minor=$(PLATFORM_SDK_MINOR_VERSION)" >> $(2);\
+    echo "ro.$(1).build.version.sdk_full=$(PLATFORM_SDK_VERSION_FULL)" >> $(2);\
 
 endef
 
diff --git a/core/tasks/cts-v-host.mk b/core/tasks/cts-v-host.mk
new file mode 100644
index 0000000..67cc0f2
--- /dev/null
+++ b/core/tasks/cts-v-host.mk
@@ -0,0 +1,29 @@
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# cts-v-host includes host-side interactive and multi-device CTS tests that
+# cannot be fully automated. It is part of CTS Verifier.
+ifneq ($(wildcard cts/tools/cts-v-host/README),)
+test_suite_name := cts-v-host
+test_suite_tradefed := cts-v-host-tradefed
+test_suite_readme := cts/tools/cts-v-host/README
+test_suite_tools := $(HOST_OUT_JAVA_LIBRARIES)/ats_console_deploy.jar \
+  $(HOST_OUT_JAVA_LIBRARIES)/ats_olc_server_local_mode_deploy.jar
+
+include $(BUILD_SYSTEM)/tasks/tools/compatibility.mk
+
+.PHONY: cts-v-host
+cts-v-host: $(compatibility_zip) $(compatibility_tests_list_zip)
+$(call dist-for-goals, cts-v-host, $(compatibility_zip) $(compatibility_tests_list_zip))
+endif
diff --git a/core/tasks/cts.mk b/core/tasks/cts.mk
index f5b3aa9..c7b5cad 100644
--- a/core/tasks/cts.mk
+++ b/core/tasks/cts.mk
@@ -78,14 +78,28 @@
 verifier-dir := $(cts-dir)/$(verifier-dir-name)
 verifier-zip-name := $(verifier-dir-name).zip
 verifier-zip := $(cts-dir)/$(verifier-zip-name)
+cts-v-host-zip := $(HOST_OUT)/cts-v-host/android-cts-v-host.zip
 
 cts : $(verifier-zip)
+ifeq ($(wildcard cts/tools/cts-v-host/README),)
 $(verifier-zip): PRIVATE_DIR := $(cts-dir)
 $(verifier-zip): $(SOONG_ANDROID_CTS_VERIFIER_ZIP)
 	rm -rf $(PRIVATE_DIR)
 	mkdir -p $(PRIVATE_DIR)
 	unzip -q -d $(PRIVATE_DIR) $<
 	$(copy-file-to-target)
+else
+$(verifier-zip): PRIVATE_DIR := $(cts-dir)
+$(verifier-zip): PRIVATE_verifier_dir := $(verifier-dir)
+$(verifier-zip): PRIVATE_host_zip := $(cts-v-host-zip)
+$(verifier-zip): $(SOONG_ANDROID_CTS_VERIFIER_ZIP) $(cts-v-host-zip) $(SOONG_ZIP)
+	rm -rf $(PRIVATE_DIR)
+	mkdir -p $(PRIVATE_DIR)
+	unzip -q -d $(PRIVATE_DIR) $<
+	unzip -q -d $(PRIVATE_verifier_dir) $(PRIVATE_host_zip)
+	$(SOONG_ZIP) -d -o $@ -C $(PRIVATE_DIR) -D $(PRIVATE_verifier_dir)
+endif
+$(call dist-for-goals, cts, $(verifier-zip))
 
 # For producing CTS coverage reports.
 # Run "make cts-test-coverage" in the $ANDROID_BUILD_TOP directory.
@@ -372,3 +386,4 @@
 verifier-dir :=
 verifier-zip-name :=
 verifier-zip :=
+cts-v-host-zip :=
diff --git a/core/version_util.mk b/core/version_util.mk
index ddcbda2..cc94063 100644
--- a/core/version_util.mk
+++ b/core/version_util.mk
@@ -22,6 +22,7 @@
 #     PLATFORM_VERSION
 #     PLATFORM_DISPLAY_VERSION
 #     PLATFORM_SDK_VERSION
+#     PLATFORM_SDK_VERSION_FULL
 #     PLATFORM_SDK_EXTENSION_VERSION
 #     PLATFORM_BASE_SDK_EXTENSION_VERSION
 #     PLATFORM_VERSION_CODENAME
@@ -62,11 +63,18 @@
 PLATFORM_SDK_VERSION := $(RELEASE_PLATFORM_SDK_VERSION)
 .KATI_READONLY := PLATFORM_SDK_VERSION
 
-ifdef PLATFORM_SDK_MINOR_VERSION
-  $(error Do not set PLATFORM_SDK_MINOR_VERSION directly. Use RELEASE_PLATFORM_SDK_MINOR_VERSION. value: $(PLATFORM_SDK_MINOR_VERSION))
+ifdef PLATFORM_SDK_VERSION_FULL
+  $(error Do not set PLATFORM_SDK_VERSION_FULL directly. Use RELEASE_PLATFORM_SDK_VERSION_FULL. value: $(PLATFORM_SDK_VERSION_FULL))
 endif
-PLATFORM_SDK_MINOR_VERSION := $(RELEASE_PLATFORM_SDK_MINOR_VERSION)
-.KATI_READONLY := PLATFORM_SDK_MINOR_VERSION
+ifeq ($(RELEASE_PLATFORM_SDK_VERSION_FULL),)
+  PLATFORM_SDK_VERSION_FULL := "$(PLATFORM_SDK_VERSION).0"
+else
+  ifneq ($(RELEASE_PLATFORM_SDK_VERSION),$(word 1,$(subst ., ,$(RELEASE_PLATFORM_SDK_VERSION_FULL))))
+    $(error if RELEASE_PLATFORM_SDK_VERSION_FULL ($(RELEASE_PLATFORM_SDK_VERSION_FULL)) is set, its major version must match RELEASE_PLATFORM_SDK_VERSION ($(RELEASE_PLATFORM_SDK_VERSION)))
+  endif
+  PLATFORM_SDK_VERSION_FULL := "$(RELEASE_PLATFORM_SDK_VERSION_FULL)"
+endif
+.KATI_READONLY := PLATFORM_SDK_VERSION_FULL
 
 ifdef PLATFORM_SDK_EXTENSION_VERSION
   $(error Do not set PLATFORM_SDK_EXTENSION_VERSION directly. Use RELEASE_PLATFORM_SDK_EXTENSION_VERSION. value: $(PLATFORM_SDK_EXTENSION_VERSION))
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index ab4abac..5c4ef33 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -578,3 +578,7 @@
 $(call soong_config_set, bionic, large_system_property_node, $(RELEASE_LARGE_SYSTEM_PROPERTY_NODE))
 $(call soong_config_set, Aconfig, read_from_new_storage, $(RELEASE_READ_FROM_NEW_STORAGE))
 $(call soong_config_set, SettingsLib, legacy_avatar_picker_app_enabled, $(if $(RELEASE_AVATAR_PICKER_APP),,true))
+$(call soong_config_set, appsearch, enable_isolated_storage, $(RELEASE_APPSEARCH_ENABLE_ISOLATED_STORAGE))
+
+# Enable AppSearch Isolated Storage per BUILD flag
+PRODUCT_PRODUCT_PROPERTIES += ro.appsearch.feature.enable_isolated_storage=$(RELEASE_APPSEARCH_ENABLE_ISOLATED_STORAGE)
diff --git a/target/product/build_variables.mk b/target/product/build_variables.mk
index 562e5b7..7c54258 100644
--- a/target/product/build_variables.mk
+++ b/target/product/build_variables.mk
@@ -32,8 +32,8 @@
 # Use the configured MessageQueue implementation
 $(call soong_config_set, messagequeue, release_package_messagequeue_implementation, $(RELEASE_PACKAGE_MESSAGEQUEUE_IMPLEMENTATION))
 
-# Use the configured version of WebView
-$(call soong_config_set, webview, release_package_webview_version, $(RELEASE_PACKAGE_WEBVIEW_VERSION))
-
 # Use the configured version of Cronet
 $(call soong_config_set,cronet,enable_cronet_tot,$(RELEASE_ENABLE_TOT_CRONET))
+
+# Use the configured version of WebView
+$(call soong_config_set, webview, release_package_webview_version, $(RELEASE_PACKAGE_WEBVIEW_VERSION))
diff --git a/target/product/virtual_ab_ota/vabc_features.mk b/target/product/virtual_ab_ota/vabc_features.mk
index d092699..0339ebd 100644
--- a/target/product/virtual_ab_ota/vabc_features.mk
+++ b/target/product/virtual_ab_ota/vabc_features.mk
@@ -42,6 +42,7 @@
 # device's .mk file improve performance for low mem devices.
 #
 # PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.read_ahead_size=16
+# warning: enabling o_direct on devices with low CMA could lead to failures
 # PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.o_direct.enabled=true
 # PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.merge_thread_priority=19
 # PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.worker_thread_priority=0
@@ -52,6 +53,16 @@
 # PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.verify_threshold_size=1073741824
 # PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.verify_block_size=1048576
 
+
+# Enabling this property will skip verification post OTA reboot.
+# Verification allows the device to safely roll back if any boot failures
+# are detected.  If the verification is disabled, update_verifier to will
+# try to verify using bufferred read if care_map.pb is present in
+# /metadata/ota/. This will increase the boot time and may also impact
+# memory usage as all the blocks in dynamic partitions are read into page-cache.
+# If care_map.pb isn't present, update-verifier will skip the verification.
+# PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.skip_verification =true
+
 # Enabling this property, will improve OTA install time
 # but will use an additional CPU core
 # PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.compression.threads=true
diff --git a/teams/Android.bp b/teams/Android.bp
index d5bef59..7946a3d 100644
--- a/teams/Android.bp
+++ b/teams/Android.bp
@@ -3332,6 +3332,13 @@
 }
 
 team {
+    name: "trendy_team_wear_partner_engineering",
+
+    // go/trendy/manage/engineers/5098351636676608
+    trendy_team_id: "5098351636676608",
+}
+
+team {
     name: "trendy_team_framework_android_multiuser",
 
     // go/trendy/manage/engineers/5981525732392960
diff --git a/tools/aconfig/convert_finalized_flags/extended_flags_list_35.txt b/tools/aconfig/convert_finalized_flags/extended_flags_list_35.txt
index e69de29..0b506ba 100644
--- a/tools/aconfig/convert_finalized_flags/extended_flags_list_35.txt
+++ b/tools/aconfig/convert_finalized_flags/extended_flags_list_35.txt
@@ -0,0 +1,129 @@
+android.app.admin.flags.permission_migration_for_zero_trust_api_enabled
+android.app.app_restrictions_api
+android.app.pinner_service_client_api
+android.car.feature.android_vic_vehicle_properties
+android.car.feature.area_id_config_access
+android.car.feature.batched_subscriptions
+android.car.feature.car_app_card
+android.car.feature.car_audio_dynamic_devices
+android.car.feature.car_audio_fade_manager_configuration
+android.car.feature.car_audio_min_max_activation_volume
+android.car.feature.car_audio_mute_ambiguity
+android.car.feature.car_evs_query_service_status
+android.car.feature.car_evs_stream_management
+android.car.feature.car_night_global_setting
+android.car.feature.car_property_detailed_error_codes
+android.car.feature.car_property_value_property_status
+android.car.feature.cluster_health_monitoring
+android.car.feature.display_compatibility
+android.car.feature.persist_ap_settings
+android.car.feature.projection_query_bt_profile_inhibit
+android.car.feature.serverless_remote_access
+android.car.feature.subscription_with_resolution
+android.car.feature.switch_user_ignoring_uxr
+android.car.feature.variable_update_rate
+android.companion.new_association_builder
+android.companion.virtual.flags.impulse_velocity_strategy_for_touch_navigation
+android.companion.virtual.flags.interactive_screen_mirror
+android.companion.virtual.flags.intercept_intents_before_applying_policy
+android.content.pm.get_package_storage_stats
+android.credentials.flags.settings_activity_enabled
+android.graphics.pdf.flags.enable_form_filling
+android.graphics.pdf.flags.enable_pdf_viewer
+android.hardware.devicestate.feature.flags.device_state_requester_cancel_state
+android.hardware.usb.flags.enable_is_mode_change_supported_api
+android.media.audio.focus_exclusive_with_recording
+android.media.audio.focus_freeze_test_api
+android.media.audio.ro_foreground_audio_control
+android.media.audiopolicy.audio_mix_test_api
+android.multiuser.enable_biometrics_to_unlock_private_space
+android.nfc.enable_nfc_reader_option
+android.nfc.enable_nfc_set_discovery_tech
+android.nfc.nfc_vendor_cmd
+android.os.bugreport_mode_max_value
+android.os.profiling.redaction_enabled
+android.os.profiling.telemetry_apis
+android.permission.flags.device_aware_permissions_enabled
+android.permission.flags.sensitive_notification_app_protection
+android.permission.flags.system_server_role_controller_enabled
+android.service.chooser.fix_resolver_memory_leak
+android.service.notification.redact_sensitive_notifications_big_text_style
+android.service.notification.redact_sensitive_notifications_from_untrusted_listeners
+android.view.accessibility.motion_event_observing
+android.webkit.update_service_v2
+com.android.aconfig.test.enabled_fixed_ro_exported
+com.android.aconfig.test.enabled_ro_exported
+com.android.adservices.ondevicepersonalization.flags.on_device_personalization_apis_enabled
+com.android.appsearch.flags.enable_enterprise_global_search_session
+com.android.appsearch.flags.enable_generic_document_builder_hidden_methods
+com.android.appsearch.flags.enable_generic_document_copy_constructor
+com.android.appsearch.flags.enable_get_parent_types_and_indexable_nested_properties
+com.android.appsearch.flags.enable_grouping_type_per_schema
+com.android.appsearch.flags.enable_list_filter_has_property_function
+com.android.appsearch.flags.enable_put_documents_request_add_taken_actions
+com.android.appsearch.flags.enable_safe_parcelable_2
+com.android.appsearch.flags.enable_search_spec_filter_properties
+com.android.appsearch.flags.enable_search_spec_set_search_source_log_tag
+com.android.appsearch.flags.enable_set_publicly_visible_schema
+com.android.appsearch.flags.enable_set_schema_visible_to_configs
+com.android.bluetooth.flags.a2dp_offload_codec_extensibility
+com.android.bluetooth.flags.allow_switching_hid_and_hogp
+com.android.bluetooth.flags.auto_on_feature
+com.android.bluetooth.flags.channel_sounding
+com.android.bluetooth.flags.enumerate_gatt_errors
+com.android.bluetooth.flags.get_address_type_api
+com.android.bluetooth.flags.key_missing_broadcast
+com.android.bluetooth.flags.leaudio_add_sampling_frequencies
+com.android.bluetooth.flags.leaudio_broadcast_monitor_source_sync_status
+com.android.bluetooth.flags.leaudio_broadcast_volume_control_for_connected_devices
+com.android.bluetooth.flags.leaudio_callback_on_group_stream_status
+com.android.bluetooth.flags.leaudio_multiple_vocs_instances_api
+com.android.bluetooth.flags.metadata_api_inactive_audio_device_upon_connection
+com.android.bluetooth.flags.mfi_has_uuid
+com.android.bluetooth.flags.settings_can_control_hap_preset
+com.android.bluetooth.flags.support_exclusive_manager
+com.android.bluetooth.flags.unix_file_socket_creation_failure
+com.android.healthconnect.flags.read_exercise_routes_all_enabled
+com.android.healthconnect.flags.skin_temperature
+com.android.healthconnect.flags.training_plans
+com.android.icu.icu_v_api
+com.android.ipsec.flags.dpd_disable_api
+com.android.ipsec.flags.dumpsys_api
+com.android.ipsec.flags.enabled_ike_options_api
+com.android.ipsec.flags.liveness_check_api
+com.android.libcore.hpke_v_apis
+com.android.libcore.v_apis
+com.android.media.flags.enable_cross_user_routing_in_media_router2
+com.android.media.mainline.flags.enable_pid_to_media_session_2
+com.android.nearby.flags.powered_off_finding
+com.android.net.flags.basic_background_restrictions_enabled
+com.android.net.flags.ipsec_transform_state
+com.android.net.flags.net_capability_local_network
+com.android.net.flags.nsd_subtypes_support_enabled
+com.android.net.flags.register_nsd_offload_engine_api
+com.android.net.flags.request_restricted_wifi
+com.android.net.flags.set_data_saver_via_cm
+com.android.net.flags.support_is_uid_networking_blocked
+com.android.net.flags.support_transport_satellite
+com.android.net.flags.tethering_request_with_soft_ap_config
+com.android.net.thread.flags.thread_enabled
+com.android.permission.flags.private_profile_supported
+com.android.permission.flags.private_profile_title_api
+com.android.permission.flags.wear_privacy_dashboard_enabled_read_only
+com.android.providers.contactkeys.flags.contactkeys_strip_fix
+com.android.providers.media.flags.access_media_owner_package_name_permission
+com.android.providers.media.flags.pick_ordered_images
+com.android.providers.media.flags.picker_accent_color
+com.android.providers.media.flags.picker_default_tab
+com.android.providers.media.flags.picker_recent_selection
+com.android.system.virtualmachine.flags.avf_v_test_apis
+com.android.uwb.flags.data_transfer_phase_config
+com.android.uwb.flags.hw_state
+com.android.uwb.flags.hybrid_session_support
+com.android.uwb.flags.query_timestamp_micros
+com.android.uwb.flags.reason_inband_session_stop
+com.android.wifi.flags.android_v_wifi_api
+com.android.wifi.flags.network_provider_battery_charging_status
+com.android.wifi.flags.shared_connectivity_broadcast_receiver_test_api
+com.android.window.flags.untrusted_embedding_state_sharing
+com.google.android.haptics.flags.vendor_vibration_control
diff --git a/tools/aconfig/exported_flag_check/allow_flag_list.txt b/tools/aconfig/exported_flag_check/allow_flag_list.txt
index b9c81c4..9c314c2 100644
--- a/tools/aconfig/exported_flag_check/allow_flag_list.txt
+++ b/tools/aconfig/exported_flag_check/allow_flag_list.txt
@@ -257,4 +257,144 @@
 com.android.wifi.flags.wep_disabled_in_apm
 com.android.window.flags.untrusted_embedding_state_sharing
 vendor.vibrator.hal.flags.enable_pwle_v2
-vendor.vibrator.hal.flags.remove_capo
\ No newline at end of file
+vendor.vibrator.hal.flags.remove_capo
+
+android.app.supervision.flags.enable_app_approval
+android.app.supervision.flags.enable_supervision_app_service
+android.app.supervision.flags.enable_supervision_pin_recovery_screen
+android.app.supervision.flags.enable_supervision_settings_screen
+android.app.supervision.flags.enable_web_content_filters_screen
+android.car.feature.display_compatibility_caption_bar
+android.companion.virtualdevice.flags.viewconfiguration_apis
+android.content.pm.always_load_past_certs_v4
+android.content.res.always_false
+android.content.res.use_new_aconfig_storage
+android.credentials.flags.propagate_user_context_for_intent_creation
+android.database.sqlite.concurrent_open_helper
+android.hardware.devicestate.feature.flags.device_state_configuration_flag
+android.media.audio.ringtone_user_uri_check
+android.media.soundtrigger.detection_service_paused_resumed_api
+android.media.tv.flags.tif_extension_standardization
+android.os.allow_thermal_hal_skin_forecast
+android.os.force_concurrent_message_queue
+android.permission.flags.enable_all_sqlite_appops_accesses
+android.permission.flags.grant_read_blocked_numbers_to_system_ui_intelligence
+android.permission.flags.record_all_runtime_appops_sqlite
+android.permission.flags.unknown_call_setting_blocked_logging_enabled
+android.server.wear_gesture_api
+android.view.accessibility.a11y_is_visited_api
+android.view.accessibility.request_rectangle_with_source
+android.view.contentcapture.flags.flush_after_each_frame
+com.android.adservices.flags.ad_id_cache_enabled
+com.android.adservices.flags.adservices_enablement_check_enabled
+com.android.adservices.flags.adservices_outcomereceiver_r_api_enabled
+com.android.adservices.flags.enable_adservices_api_enabled
+com.android.adservices.flags.sdksandbox_invalidate_effective_target_sdk_version_cache
+com.android.adservices.flags.sdksandbox_use_effective_target_sdk_version_for_restrictions
+com.android.appsearch.flags.enable_all_package_indexing_on_indexer_update
+com.android.appsearch.flags.enable_app_functions
+com.android.appsearch.flags.enable_app_open_events_indexer_check_prior_attempt
+com.android.appsearch.flags.enable_app_search_manage_blob_files
+com.android.appsearch.flags.enable_apps_indexer_check_prior_attempt
+com.android.appsearch.flags.enable_batch_put
+com.android.appsearch.flags.enable_calculate_time_since_last_attempted_optimize
+com.android.appsearch.flags.enable_check_contacts_indexer_delta_timestamps
+com.android.appsearch.flags.enable_check_contacts_indexer_update_job_params
+com.android.appsearch.flags.enable_four_hour_min_time_optimize_threshold
+com.android.appsearch.flags.enable_isolated_storage
+com.android.appsearch.flags.enable_marker_file_for_optimize
+com.android.appsearch.flags.enable_qualified_id_join_index_v3
+com.android.appsearch.flags.enable_recovery_proof_persistence
+com.android.appsearch.flags.enable_release_backup_schema_file_if_overlay_present
+com.android.appsearch.flags.enable_soft_index_restoration
+com.android.clockwork.flags.support_paired_device_none
+com.android.gms.flags.enable_deleted_gms
+com.android.gms.flags.enable_new_gms
+com.android.gms.flags.enable_optional_gms
+com.android.hardware.input.key_event_activity_detection
+com.android.healthfitness.flags.cloud_backup_and_restore_db
+com.android.healthfitness.flags.exercise_segment_weight
+com.android.healthfitness.flags.exercise_segment_weight_db
+com.android.healthfitness.flags.extend_export_import_telemetry
+com.android.healthfitness.flags.launch_onboarding_activity
+com.android.healthfitness.flags.personal_health_record_enable_export_import
+com.android.healthfitness.flags.phr_change_logs
+com.android.healthfitness.flags.phr_change_logs_db
+com.android.healthfitness.flags.phr_fhir_extension_validation
+com.android.healthfitness.flags.phr_fhir_resource_validator_use_weak_reference
+com.android.healthfitness.flags.phr_fhir_validation_disallow_empty_objects_arrays
+com.android.healthfitness.flags.refactor_aggregations
+com.android.healthfitness.flags.single_user_permission_intent_tracker
+com.android.healthfitness.flags.smoking
+com.android.healthfitness.flags.smoking_db
+com.android.healthfitness.flags.step_tracking_enabled
+com.android.healthfitness.flags.symptoms
+com.android.healthfitness.flags.symptoms_db
+com.android.icu.telephony_lookup_mcc_extension
+com.android.internal.telephony.flags.pass_copied_call_state_list
+com.android.internal.telephony.flags.robust_number_verification
+com.android.internal.telephony.flags.satellite_exit_p2p_session_outside_geofence
+com.android.internal.telephony.flags.starlink_data_bugfix
+com.android.media.audio.hardening_partial
+com.android.media.flags.enable_suggested_device_api
+com.android.media.flags.enable_use_of_singleton_audio_manager_route_controller
+com.android.media.projection.flags.app_content_sharing
+com.android.media.projection.flags.show_stop_dialog_post_call_end
+com.android.permission.flags.cross_user_role_ux_bugfix_enabled
+com.android.permission.flags.default_apps_recommendation_enabled
+com.android.permission.flags.fix_safety_center_touch_target
+com.android.providers.media.flags.enable_exclusion_list_for_default_folders
+com.android.providers.media.flags.enable_mime_type_fix_for_android_15
+com.android.providers.media.flags.exclude_unreliable_volumes
+com.android.providers.media.flags.revoke_access_owned_photos
+com.android.sdksandbox.flags.sandbox_activity_sdk_based_context
+com.android.sdksandbox.flags.selinux_input_selector
+com.android.sdksandbox.flags.selinux_sdk_sandbox_audit
+com.android.settings.flags.enable_remove_association_bt_unpair
+com.android.settingslib.widget.theme.flags.is_expressive_design_enabled
+com.android.window.flags.fix_hide_overlay_api
+com.android.window.flags.update_host_input_transfer_token
+com.fuchsia.bluetooth.flags.a2dp_lhdc_api
+com.fuchsia.bluetooth.flags.aics_api
+com.fuchsia.bluetooth.flags.allow_switching_hid_and_hogp
+com.fuchsia.bluetooth.flags.bt_offload_socket_api
+com.fuchsia.bluetooth.flags.bt_socket_api_l2cap_cid
+com.fuchsia.bluetooth.flags.channel_sounding
+com.fuchsia.bluetooth.flags.channel_sounding_25q2_apis
+com.fuchsia.bluetooth.flags.directed_advertising_api
+com.fuchsia.bluetooth.flags.encryption_change_broadcast
+com.fuchsia.bluetooth.flags.hci_vendor_specific_extension
+com.fuchsia.bluetooth.flags.identity_address_type_api
+com.fuchsia.bluetooth.flags.key_missing_public
+com.fuchsia.bluetooth.flags.leaudio_add_opus_codec_type
+com.fuchsia.bluetooth.flags.leaudio_broadcast_api_get_local_metadata
+com.fuchsia.bluetooth.flags.leaudio_broadcast_api_manage_primary_group
+com.fuchsia.bluetooth.flags.leaudio_broadcast_monitor_source_sync_status
+com.fuchsia.bluetooth.flags.leaudio_broadcast_volume_control_for_connected_devices
+com.fuchsia.bluetooth.flags.leaudio_mono_location_errata_api
+com.fuchsia.bluetooth.flags.leaudio_multiple_vocs_instances_api
+com.fuchsia.bluetooth.flags.metadata_api_inactive_audio_device_upon_connection
+com.fuchsia.bluetooth.flags.metadata_api_microphone_for_call_enabled
+com.fuchsia.bluetooth.flags.settings_can_control_hap_preset
+com.fuchsia.bluetooth.flags.socket_settings_api
+com.fuchsia.bluetooth.flags.support_bluetooth_quality_report_v6
+com.fuchsia.bluetooth.flags.support_exclusive_manager
+com.fuchsia.bluetooth.flags.support_metadata_device_types_apis
+com.fuchsia.bluetooth.flags.support_remote_device_metadata
+com.fuchsia.bluetooth.flags.unix_file_socket_creation_failure
+com.google.android.clockwork.pele.flags.koru_feature_cached_views
+com.google.android.clockwork.pele.flags.koru_origami
+com.google.android.device.pixel.watch.flags.pdms_flag_1
+com.google.android.haptics.flags.vendor_vibration_control
+com.google.clockwork.flags.prevent_ime_startup
+vendor.gc2.flags.mse_report
+vendor.google.plat_security.flags.enable_service
+vendor.google.plat_security.flags.enable_trusty_service
+vendor.google.wireless_charger.service.flags.enable_service
+
+android.hardware.biometrics.move_fm_api_to_bm
+android.hardware.serial.flags.enable_serial_api
+com.android.providers.media.flags.enable_local_media_provider_capabilities
+com.android.providers.media.flags.enable_photopicker_datescrubber
+com.android.system.virtualmachine.flags.terminal_storage_balloon
+com.android.tradeinmode.flags.trade_in_mode_2025q4
diff --git a/tools/aconfig/exported_flag_check/allow_package_list.txt b/tools/aconfig/exported_flag_check/allow_package_list.txt
index e69de29..e76472b 100644
--- a/tools/aconfig/exported_flag_check/allow_package_list.txt
+++ b/tools/aconfig/exported_flag_check/allow_package_list.txt
@@ -0,0 +1,2 @@
+com.google.wear.sdk
+com.google.wear.services.infra.flags
diff --git a/tools/finalization/OWNERS b/tools/finalization/OWNERS
index b00b774..4df0094 100644
--- a/tools/finalization/OWNERS
+++ b/tools/finalization/OWNERS
@@ -1,7 +1,5 @@
 include platform/build/soong:/OWNERS
-amhk@google.com
-gurpreetgs@google.com
-michaelwr@google.com
+include platform/frameworks/base:/SDK_OWNERS
 patb@google.com
 smoreland@google.com
 zyy@google.com
diff --git a/tools/finalization/build-step-0.sh b/tools/finalization/build-step-0.sh
index 8826b35..bc41a19 100755
--- a/tools/finalization/build-step-0.sh
+++ b/tools/finalization/build-step-0.sh
@@ -25,8 +25,8 @@
     fi;
 
     if [ "$need_vintf_finalize" = true ] ; then        # VINTF finalization
-        source $top/build/make/tools/finalization/finalize-vintf-resources.sh
+        source $top/build/make/tools/finalization/finalize-vintf-resources.sh $@
     fi;
 }
 
-finalize_main_step0
+finalize_main_step0 $@
diff --git a/tools/finalization/finalize-vintf-resources.sh b/tools/finalization/finalize-vintf-resources.sh
index 45efc10..9660e3f 100755
--- a/tools/finalization/finalize-vintf-resources.sh
+++ b/tools/finalization/finalize-vintf-resources.sh
@@ -3,6 +3,21 @@
 set -ex
 
 function finalize_vintf_resources() {
+    if [ $# -gt 1 ]; then
+        echo "No argument or '--steps_for_build_test_only' is allowed"
+        exit 1
+    fi
+    if [ $# -eq 1 ]; then
+        if [ "$1" == "--steps_for_build_test_only" ]; then
+            echo "This is only to verify building a target."
+            echo "Skip LLNDK ABI dump and VINTF check."
+            local build_test_only=true
+        else
+            echo "Unknown argument $1"
+            exit 1
+        fi
+    fi
+
     local top="$(dirname "$0")"/../../../..
     source $top/build/make/tools/finalization/environment.sh
     # environment needed to build dependencies and run scripts
@@ -26,37 +41,30 @@
     # system/sepolicy
     "$top/system/sepolicy/tools/finalize-vintf-resources.sh" "$top" "$FINAL_BOARD_API_LEVEL"
 
-    create_new_compat_matrix_and_kernel_configs
-
-    # pre-finalization build target (trunk)
     local aidl_m="$top/build/soong/soong_ui.bash --make-mode"
     AIDL_TRANSITIVE_FREEZE=true $aidl_m aidl-freeze-api create_reference_dumps
 
-    # Generate LLNDK ABI dumps
-    # This command depends on ANDROID_BUILD_TOP
-    "$ANDROID_HOST_OUT/bin/create_reference_dumps" -release "$TARGET_RELEASE" --build-variant "$TARGET_BUILD_VARIANT" --lib-variant LLNDK
+    finalize_compat_matrix $build_test_only
+
+    if ! [ "$build_test_only" = "true" ]; then
+        # Generate LLNDK ABI dumps
+        # This command depends on ANDROID_BUILD_TOP
+        "$ANDROID_HOST_OUT/bin/create_reference_dumps" -release "$TARGET_RELEASE" --build-variant "$TARGET_BUILD_VARIANT" --lib-variant LLNDK
+    fi
 }
 
-function create_new_compat_matrix_and_kernel_configs() {
-    # The compatibility matrix versions are bumped during vFRC
-    # These will change every time we have a new vFRC
+function finalize_compat_matrix() {
+    local build_test_only=$1
     local CURRENT_COMPATIBILITY_MATRIX_LEVEL="$FINAL_BOARD_API_LEVEL"
-    local NEXT_COMPATIBILITY_MATRIX_LEVEL="$FINAL_NEXT_BOARD_API_LEVEL"
-    # The kernel configs need the letter of the Android release
-    local CURRENT_RELEASE_LETTER="$FINAL_CORRESPONDING_VERSION_LETTER"
-    local NEXT_RELEASE_LETTER="$FINAL_NEXT_CORRESPONDING_VERSION_LETTER"
 
+    "$top/prebuilts/build-tools/path/linux-x86/python3" "$top/hardware/interfaces/compatibility_matrices/finalize.py" "$CURRENT_COMPATIBILITY_MATRIX_LEVEL"
 
-    # build the targets required before touching the Android.bp/Android.mk files
-    local build_cmd="$top/build/soong/soong_ui.bash --make-mode"
-    $build_cmd bpmodify
-
-    "$top/prebuilts/build-tools/path/linux-x86/python3" "$top/hardware/interfaces/compatibility_matrices/bump.py" "$CURRENT_COMPATIBILITY_MATRIX_LEVEL" "$NEXT_COMPATIBILITY_MATRIX_LEVEL" "$CURRENT_RELEASE_LETTER" "$NEXT_RELEASE_LETTER" "$FINAL_CORRESPONDING_PLATFORM_VERSION"
-
-    # Freeze the current framework manifest file. This relies on the
-    # aosp_cf_x86_64-trunk_staging build target to get the right manifest
-    # fragments installed.
-    "$top/system/libhidl/vintfdata/freeze.sh" "$CURRENT_COMPATIBILITY_MATRIX_LEVEL"
+    if ! [ "$build_test_only" = "true" ]; then
+        # Freeze the current framework manifest file. This relies on the
+        # interfaces already being frozen because we are building with fina_0 which
+        # inherits from `next` where RELEASE_AIDL_USE_UNFROZEN=false
+        "$top/system/libhidl/vintfdata/freeze.sh" "$CURRENT_COMPATIBILITY_MATRIX_LEVEL"
+    fi
 }
 
 function freeze_framework_manifest() {
@@ -65,5 +73,5 @@
 }
 
 
-finalize_vintf_resources
+finalize_vintf_resources $@
 
diff --git a/tools/releasetools/check_partition_sizes.py b/tools/releasetools/check_partition_sizes.py
index 738d77d..b469d46 100644
--- a/tools/releasetools/check_partition_sizes.py
+++ b/tools/releasetools/check_partition_sizes.py
@@ -58,6 +58,9 @@
                   *format_args)
     else:
       msg = "{} is greater than {}:\n{} == {} > {} == {}".format(*format_args)
+      if "SOONG_RUSTC_INCREMENTAL" in os.environ:
+        msg = ("If setting \"SOONG_RUSTC_INCREMENTAL\" try building without it. "
+               + msg)
       if level == logging.ERROR:
         raise RuntimeError(msg)
       else: