Merge "Use -target-feature for MTE" into main
diff --git a/ci/build_metadata b/ci/build_metadata
index 8136702..a8eb65d 100755
--- a/ci/build_metadata
+++ b/ci/build_metadata
@@ -21,5 +21,5 @@
 export TARGET_BUILD_VARIANT=eng
 
 build/soong/bin/m dist \
-    code_metadata
+    all_teams
 
diff --git a/ci/build_test_suites.py b/ci/build_test_suites.py
index 402880c..b8c4a38 100644
--- a/ci/build_test_suites.py
+++ b/ci/build_test_suites.py
@@ -20,7 +20,6 @@
 import logging
 import os
 import pathlib
-import re
 import subprocess
 import sys
 from typing import Callable
@@ -70,7 +69,7 @@
       return BuildPlan(set(self.args.extra_targets), set())
 
     build_targets = set()
-    packaging_functions = set()
+    packaging_commands_getters = []
     for target in self.args.extra_targets:
       if self._unused_target_exclusion_enabled(
           target
@@ -86,9 +85,11 @@
           target, self.build_context, self.args
       )
       build_targets.update(target_optimizer.get_build_targets())
-      packaging_functions.add(target_optimizer.package_outputs)
+      packaging_commands_getters.append(
+          target_optimizer.get_package_outputs_commands
+      )
 
-    return BuildPlan(build_targets, packaging_functions)
+    return BuildPlan(build_targets, packaging_commands_getters)
 
   def _unused_target_exclusion_enabled(self, target: str) -> bool:
     return (
@@ -100,7 +101,7 @@
 @dataclass(frozen=True)
 class BuildPlan:
   build_targets: set[str]
-  packaging_functions: set[Callable[..., None]]
+  packaging_commands_getters: list[Callable[[], list[list[str]]]]
 
 
 def build_test_suites(argv: list[str]) -> int:
@@ -182,8 +183,12 @@
   except subprocess.CalledProcessError as e:
     raise BuildFailureError(e.returncode) from e
 
-  for packaging_function in build_plan.packaging_functions:
-    packaging_function()
+  for packaging_commands_getter in build_plan.packaging_commands_getters:
+    try:
+      for packaging_command in packaging_commands_getter():
+        run_command(packaging_command)
+    except subprocess.CalledProcessError as e:
+      raise BuildFailureError(e.returncode) from e
 
 
 def get_top() -> pathlib.Path:
diff --git a/ci/build_test_suites_test.py b/ci/build_test_suites_test.py
index f3ff6f4..2afaab7 100644
--- a/ci/build_test_suites_test.py
+++ b/ci/build_test_suites_test.py
@@ -241,17 +241,17 @@
   class TestOptimizedBuildTarget(optimized_targets.OptimizedBuildTarget):
 
     def __init__(
-        self, target, build_context, args, output_targets, packaging_outputs
+        self, target, build_context, args, output_targets, packaging_commands
     ):
       super().__init__(target, build_context, args)
       self.output_targets = output_targets
-      self.packaging_outputs = packaging_outputs
+      self.packaging_commands = packaging_commands
 
     def get_build_targets_impl(self):
       return self.output_targets
 
-    def package_outputs_impl(self):
-      self.packaging_outputs.add(f'packaging {" ".join(self.output_targets)}')
+    def get_package_outputs_commands_impl(self):
+      return self.packaging_commands
 
     def get_enabled_flag(self):
       return f'{self.target}_enabled'
@@ -276,7 +276,8 @@
 
     build_plan = build_planner.create_build_plan()
 
-    self.assertEqual(len(build_plan.packaging_functions), 0)
+    for packaging_command in self.run_packaging_commands(build_plan):
+      self.assertEqual(len(packaging_command), 0)
 
   def test_build_optimization_on_optimizes_target(self):
     build_targets = {'target_1', 'target_2'}
@@ -294,20 +295,19 @@
 
   def test_build_optimization_on_packages_target(self):
     build_targets = {'target_1', 'target_2'}
-    packaging_outputs = set()
+    optimized_target_name = self.get_optimized_target_name('target_1')
+    packaging_commands = [[f'packaging {optimized_target_name}']]
     build_planner = self.create_build_planner(
         build_targets=build_targets,
         build_context=self.create_build_context(
             enabled_build_features=[{'name': self.get_target_flag('target_1')}]
         ),
-        packaging_outputs=packaging_outputs,
+        packaging_commands=packaging_commands,
     )
 
     build_plan = build_planner.create_build_plan()
-    self.run_packaging_functions(build_plan)
 
-    optimized_target_name = self.get_optimized_target_name('target_1')
-    self.assertIn(f'packaging {optimized_target_name}', packaging_outputs)
+    self.assertIn(packaging_commands, self.run_packaging_commands(build_plan))
 
   def test_individual_build_optimization_off_doesnt_optimize(self):
     build_targets = {'target_1', 'target_2'}
@@ -321,16 +321,16 @@
 
   def test_individual_build_optimization_off_doesnt_package(self):
     build_targets = {'target_1', 'target_2'}
-    packaging_outputs = set()
+    packaging_commands = [['packaging command']]
     build_planner = self.create_build_planner(
         build_targets=build_targets,
-        packaging_outputs=packaging_outputs,
+        packaging_commands=packaging_commands,
     )
 
     build_plan = build_planner.create_build_plan()
-    self.run_packaging_functions(build_plan)
 
-    self.assertFalse(packaging_outputs)
+    for packaging_command in self.run_packaging_commands(build_plan):
+      self.assertEqual(len(packaging_command), 0)
 
   def test_target_output_used_target_built(self):
     build_target = 'test_target'
@@ -408,7 +408,7 @@
       target_optimizations: dict[
           str, optimized_targets.OptimizedBuildTarget
       ] = None,
-      packaging_outputs: set[str] = set(),
+      packaging_commands: list[list[str]] = [],
   ) -> build_test_suites.BuildPlanner:
     if not build_context:
       build_context = self.create_build_context()
@@ -418,7 +418,7 @@
       target_optimizations = self.create_target_optimizations(
           build_context,
           build_targets,
-          packaging_outputs,
+          packaging_commands,
       )
     return build_test_suites.BuildPlanner(
         build_context, args, target_optimizations
@@ -450,14 +450,14 @@
       self,
       build_context: BuildContext,
       build_targets: set[str],
-      packaging_outputs: set[str] = set(),
+      packaging_commands: list[list[str]] = [],
   ):
     target_optimizations = dict()
     for target in build_targets:
       target_optimizations[target] = functools.partial(
           self.TestOptimizedBuildTarget,
           output_targets={self.get_optimized_target_name(target)},
-          packaging_outputs=packaging_outputs,
+          packaging_commands=packaging_commands,
       )
 
     return target_optimizations
@@ -468,10 +468,6 @@
   def get_optimized_target_name(self, target: str):
     return f'{target}_optimized'
 
-  def run_packaging_functions(self, build_plan: build_test_suites.BuildPlan):
-    for packaging_function in build_plan.packaging_functions:
-      packaging_function()
-
   def get_test_context(self, target: str):
     return {
         'testInfos': [
@@ -491,6 +487,12 @@
         ],
     }
 
+  def run_packaging_commands(self, build_plan: build_test_suites.BuildPlan):
+    return [
+        packaging_command_getter()
+        for packaging_command_getter in build_plan.packaging_commands_getters
+    ]
+
 
 def wait_until(
     condition_function: Callable[[], bool],
diff --git a/ci/optimized_targets.py b/ci/optimized_targets.py
index fddde17..688bdd8 100644
--- a/ci/optimized_targets.py
+++ b/ci/optimized_targets.py
@@ -16,12 +16,13 @@
 from abc import ABC
 import argparse
 import functools
-from build_context import BuildContext
 import json
 import logging
 import os
-from typing import Self
+import pathlib
+import subprocess
 
+from build_context import BuildContext
 import test_mapping_module_retriever
 
 
@@ -33,6 +34,9 @@
   build.
   """
 
+  _SOONG_UI_BASH_PATH = 'build/soong/soong_ui.bash'
+  _PREBUILT_SOONG_ZIP_PATH = 'prebuilts/build-tools/linux-x86/bin/soong_zip'
+
   def __init__(
       self,
       target: str,
@@ -52,14 +56,17 @@
     self.modules_to_build = {self.target}
     return {self.target}
 
-  def package_outputs(self):
+  def get_package_outputs_commands(self) -> list[list[str]]:
     features = self.build_context.enabled_build_features
     if self.get_enabled_flag() in features:
-      return self.package_outputs_impl()
+      return self.get_package_outputs_commands_impl()
 
-  def package_outputs_impl(self):
+    return []
+
+  def get_package_outputs_commands_impl(self) -> list[list[str]]:
     raise NotImplementedError(
-        f'package_outputs_impl not implemented in {type(self).__name__}'
+        'get_package_outputs_commands_impl not implemented in'
+        f' {type(self).__name__}'
     )
 
   def get_enabled_flag(self):
@@ -72,6 +79,88 @@
         f'get_build_targets_impl not implemented in {type(self).__name__}'
     )
 
+  def _generate_zip_options_for_items(
+      self,
+      prefix: str = '',
+      relative_root: str = '',
+      list_files: list[str] | None = None,
+      files: list[str] | None = None,
+      directories: list[str] | None = None,
+  ) -> list[str]:
+    if not list_files and not files and not directories:
+      raise RuntimeError(
+          f'No items specified to be added to zip! Prefix: {prefix}, Relative'
+          f' root: {relative_root}'
+      )
+    command_segment = []
+    # These are all soong_zip options so consult soong_zip --help for specifics.
+    if prefix:
+      command_segment.append('-P')
+      command_segment.append(prefix)
+    if relative_root:
+      command_segment.append('-C')
+      command_segment.append(relative_root)
+    if list_files:
+      for list_file in list_files:
+        command_segment.append('-l')
+        command_segment.append(list_file)
+    if files:
+      for file in files:
+        command_segment.append('-f')
+        command_segment.append(file)
+    if directories:
+      for directory in directories:
+        command_segment.append('-D')
+        command_segment.append(directory)
+
+    return command_segment
+
+  def _query_soong_vars(
+      self, src_top: pathlib.Path, soong_vars: list[str]
+  ) -> dict[str, str]:
+    process_result = subprocess.run(
+        args=[
+            f'{src_top / self._SOONG_UI_BASH_PATH}',
+            '--dumpvars-mode',
+            f'--abs-vars={" ".join(soong_vars)}',
+        ],
+        env=os.environ,
+        check=False,
+        capture_output=True,
+        text=True,
+    )
+    if not process_result.returncode == 0:
+      logging.error('soong dumpvars command failed! stderr:')
+      logging.error(process_result.stderr)
+      raise RuntimeError('Soong dumpvars failed! See log for stderr.')
+
+    if not process_result.stdout:
+      raise RuntimeError(
+          'Necessary soong variables ' + soong_vars + ' not found.'
+      )
+
+    try:
+      return {
+          line.split('=')[0]: line.split('=')[1].strip("'")
+          for line in process_result.stdout.strip().split('\n')
+      }
+    except IndexError as e:
+      raise RuntimeError(
+          'Error parsing soong dumpvars output! See output here:'
+          f' {process_result.stdout}',
+          e,
+      )
+
+  def _base_zip_command(
+      self, src_top: pathlib.Path, dist_dir: pathlib.Path, name: str
+  ) -> list[str]:
+    return [
+        f'{src_top / self._PREBUILT_SOONG_ZIP_PATH }',
+        '-d',
+        '-o',
+        f'{dist_dir / name}',
+    ]
+
 
 class NullOptimizer(OptimizedBuildTarget):
   """No-op target optimizer.
@@ -86,8 +175,8 @@
   def get_build_targets(self):
     return {self.target}
 
-  def package_outputs(self):
-    pass
+  def get_package_outputs_commands(self):
+    return []
 
 
 class ChangeInfo:
@@ -114,11 +203,10 @@
 
     return changed_files
 
+
 class GeneralTestsOptimizer(OptimizedBuildTarget):
   """general-tests optimizer
 
-  TODO(b/358215235): Implement
-
   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
@@ -126,10 +214,13 @@
   normally built.
   """
 
-  # List of modules that are always required to be in general-tests.zip.
-  _REQUIRED_MODULES = frozenset(
-      ['cts-tradefed', 'vts-tradefed', 'compatibility-host-util']
-  )
+  # List of modules that are built alongside general-tests as dependencies.
+  _REQUIRED_MODULES = frozenset([
+      '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')
@@ -173,6 +264,212 @@
 
     return modules_to_build
 
+  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'))
+
+    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(
+        self._get_zip_test_configs_zips_commands(
+            src_top,
+            dist_dir,
+            host_out,
+            product_out,
+            host_config_files,
+            target_config_files,
+        )
+    )
+
+    zip_command = self._base_zip_command(src_top, dist_dir, 'general-tests.zip')
+
+    # Add host testcases.
+    if host_paths:
+      zip_command.extend(
+          self._generate_zip_options_for_items(
+              prefix='host',
+              relative_root=f'{src_top / soong_host_out}',
+              directories=host_paths,
+          )
+      )
+
+    # Add target testcases.
+    if target_paths:
+      zip_command.extend(
+          self._generate_zip_options_for_items(
+              prefix='target',
+              relative_root=f'{src_top / product_out}',
+              directories=target_paths,
+          )
+      )
+
+    # TODO(lucafarsi): Push this logic into a general-tests-minimal build command
+    # Add necessary tools. These are also hardcoded in general-tests.mk.
+    framework_path = soong_host_out / 'framework'
+
+    zip_command.extend(
+        self._generate_zip_options_for_items(
+            prefix='host/tools',
+            relative_root=str(framework_path),
+            files=[
+                f"{framework_path / 'cts-tradefed.jar'}",
+                f"{framework_path / 'compatibility-host-util.jar'}",
+                f"{framework_path / 'vts-tradefed.jar'}",
+            ],
+        )
+    )
+
+    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,
+      dist_dir: pathlib.Path,
+      host_out: pathlib.Path,
+      product_out: pathlib.Path,
+      host_config_files: list[str],
+      target_config_files: list[str],
+  ) -> tuple[list[str], list[str]]:
+    """Generate general-tests_configs.zip and general-tests_list.zip.
+
+    general-tests_configs.zip contains all of the .config files that were
+    built and general-tests_list.zip contains a text file which lists
+    all of the .config files that are in general-tests_configs.zip.
+
+    general-tests_configs.zip is organized as follows:
+    /
+      host/
+        testcases/
+          test_1.config
+          test_2.config
+          ...
+      target/
+        testcases/
+          test_1.config
+          test_2.config
+          ...
+
+    So the process is we write out the paths to all the host config files into
+    one
+    file and all the paths to the target config files in another. We also write
+    the paths to all the config files into a third file to use for
+    general-tests_list.zip.
+
+    Args:
+      dist_dir: dist directory.
+      host_out: host out directory.
+      product_out: product out directory.
+      host_config_files: list of all host config files.
+      target_config_files: list of all target config files.
+
+    Returns:
+      The commands to generate general-tests_configs.zip and
+      general-tests_list.zip
+    """
+    with open(
+        f"{host_out / 'host_general-tests_list'}", 'w'
+    ) as host_list_file, open(
+        f"{product_out / 'target_general-tests_list'}", 'w'
+    ) as target_list_file, open(
+        f"{host_out / 'general-tests_list'}", 'w'
+    ) as list_file:
+
+      for config_file in host_config_files:
+        host_list_file.write(f'{config_file}' + '\n')
+        list_file.write('host/' + os.path.relpath(config_file, host_out) + '\n')
+
+      for config_file in target_config_files:
+        target_list_file.write(f'{config_file}' + '\n')
+        list_file.write(
+            'target/' + os.path.relpath(config_file, product_out) + '\n'
+        )
+
+    zip_commands = []
+
+    tests_config_zip_command = self._base_zip_command(
+        src_top, dist_dir, 'general-tests_configs.zip'
+    )
+    tests_config_zip_command.extend(
+        self._generate_zip_options_for_items(
+            prefix='host',
+            relative_root=str(host_out),
+            list_files=[f"{host_out / 'host_general-tests_list'}"],
+        )
+    )
+
+    tests_config_zip_command.extend(
+        self._generate_zip_options_for_items(
+            prefix='target',
+            relative_root=str(product_out),
+            list_files=[f"{product_out / 'target_general-tests_list'}"],
+        ),
+    )
+
+    zip_commands.append(tests_config_zip_command)
+
+    tests_list_zip_command = self._base_zip_command(
+        src_top, dist_dir, 'general-tests_list.zip'
+    )
+    tests_list_zip_command.extend(
+        self._generate_zip_options_for_items(
+            relative_root=str(host_out),
+            files=[f"{host_out / 'general-tests_list'}"],
+        )
+    )
+    zip_commands.append(tests_list_zip_command)
+
+    return zip_commands
+
   def get_enabled_flag(self):
     return 'general_tests_optimized'
 
diff --git a/ci/optimized_targets_test.py b/ci/optimized_targets_test.py
index 919c193..0b0c0ec 100644
--- a/ci/optimized_targets_test.py
+++ b/ci/optimized_targets_test.py
@@ -19,10 +19,12 @@
 import os
 import pathlib
 import re
+import subprocess
+import textwrap
 import unittest
 from unittest import mock
-import optimized_targets
 from build_context import BuildContext
+import optimized_targets
 from pyfakefs import fake_filesystem_unittest
 
 
@@ -43,11 +45,68 @@
 
   def _setup_working_build_env(self):
     self.change_info_file = pathlib.Path('/tmp/change_info')
+    self._write_soong_ui_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')
+    self._target_out_testcases.mkdir(parents=True)
+    self._product_out = pathlib.Path('/tmp/top/product_out')
+    self._product_out.mkdir(parents=True)
+    self._soong_host_out = pathlib.Path('/tmp/top/soong_host_out')
+    self._soong_host_out.mkdir(parents=True)
+    self._host_out = pathlib.Path('/tmp/top/host_out')
+    self._host_out.mkdir(parents=True)
+
+    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',
     })
 
+  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',
+                }],
+            }],
+        }]
+    }
+
+    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()
 
@@ -124,36 +183,44 @@
     with self.assertRaises(json.decoder.JSONDecodeError):
       build_targets = optimizer.get_build_targets()
 
-  def _write_change_info_file(self):
-    change_info_contents = {
-        'changes': [{
-            'projectPath': '/project/path',
-            'revisions': [{
-                'fileInfos': [{
-                    'path': 'file/path/file_name',
-                }],
-            }],
-        }]
-    }
+  @mock.patch('subprocess.run')
+  def test_packaging_outputs_success(self, subprocess_run):
+    subprocess_run.return_value = self._get_soong_vars_output()
+    optimizer = self._create_general_tests_optimizer()
+    self._set_up_build_outputs(['test_mapping_module'])
 
-    with open(self.change_info_file, 'w') as f:
-      json.dump(change_info_contents, f)
+    targets = optimizer.get_build_targets()
+    package_commands = optimizer.get_package_outputs_commands()
 
-  def _write_test_mapping_file(self):
-    test_mapping_contents = {
-        'test-mapping-group': [
-            {
-                'name': 'test_mapping_module',
-            },
-        ],
-    }
+    self._verify_soong_zip_commands(package_commands, ['test_mapping_module'])
 
-    with open('/project/path/file/path/TEST_MAPPING', 'w') as f:
-      json.dump(test_mapping_contents, f)
+  @mock.patch('subprocess.run')
+  def test_get_soong_dumpvars_fails_raises(self, subprocess_run):
+    subprocess_run.return_value = self._get_soong_vars_output(return_code=-1)
+    optimizer = self._create_general_tests_optimizer()
+    self._set_up_build_outputs(['test_mapping_module'])
 
-  def _create_general_tests_optimizer(
-      self, build_context: BuildContext = None
-  ):
+    targets = optimizer.get_build_targets()
+
+    with self.assertRaisesRegex(RuntimeError, 'Soong dumpvars failed!'):
+      package_commands = optimizer.get_package_outputs_commands()
+
+  @mock.patch('subprocess.run')
+  def test_get_soong_dumpvars_bad_output_raises(self, subprocess_run):
+    subprocess_run.return_value = self._get_soong_vars_output(
+        stdout='This output is bad'
+    )
+    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()
+
+  def _create_general_tests_optimizer(self, build_context: BuildContext = None):
     if not build_context:
       build_context = self._create_build_context()
     return optimized_targets.GeneralTestsOptimizer(
@@ -170,7 +237,9 @@
     build_context_dict = {}
     build_context_dict['enabledBuildFeatures'] = [{'name': 'optimized_build'}]
     if general_tests_optimized:
-      build_context_dict['enabledBuildFeatures'].append({'name': 'general_tests_optimized'})
+      build_context_dict['enabledBuildFeatures'].append(
+          {'name': 'general_tests_optimized'}
+      )
     build_context_dict['testContext'] = test_context
     return BuildContext(build_context_dict)
 
@@ -199,6 +268,81 @@
         ],
     }
 
+  def _get_soong_vars_output(
+      self, return_code: int = 0, stdout: str = ''
+  ) -> subprocess.CompletedProcess:
+    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}'""")
+
+    return_value.stdout = stdout
+    return return_value
+
+  def _set_up_build_outputs(self, targets: list[str]):
+    for target in targets:
+      host_dir = self._host_out_testcases / target
+      host_dir.mkdir()
+      (host_dir / f'{target}.config').touch()
+      (host_dir / f'test_file').touch()
+
+      target_dir = self._target_out_testcases / target
+      target_dir.mkdir()
+      (target_dir / f'{target}.config').touch()
+      (target_dir / f'test_file').touch()
+
+  def _verify_soong_zip_commands(self, commands: list[str], targets: list[str]):
+    """Verify the structure of the zip commands.
+
+    Zip commands have to start with the soong_zip binary path, then are followed
+    by a couple of options and the name of the file being zipped. Depending on
+    which zip we are creating look for a few essential items being added in
+    those zips.
+
+    Args:
+      commands: list of command lists
+      targets: list of targets expected to be in general-tests.zip
+    """
+    for command in commands:
+      self.assertEqual(
+          '/tmp/top/prebuilts/build-tools/linux-x86/bin/soong_zip',
+          command[0],
+      )
+      self.assertEqual('-d', command[1])
+      self.assertEqual('-o', command[2])
+      match (command[3]):
+        case '/tmp/top/out/dist/general-tests_configs.zip':
+          self.assertIn(f'{self._host_out}/host_general-tests_list', command)
+          self.assertIn(
+              f'{self._product_out}/target_general-tests_list', command
+          )
+          return
+        case '/tmp/top/out/dist/general-tests_list.zip':
+          self.assertIn('-f', command)
+          self.assertIn(f'{self._host_out}/general-tests_list', command)
+          return
+        case '/tmp/top/out/dist/general-tests.zip':
+          for target in targets:
+            self.assertIn(f'{self._host_out_testcases}/{target}', command)
+            self.assertIn(f'{self._target_out_testcases}/{target}', command)
+          self.assertIn(
+              f'{self._soong_host_out}/framework/cts-tradefed.jar', command
+          )
+          self.assertIn(
+              f'{self._soong_host_out}/framework/compatibility-host-util.jar',
+              command,
+          )
+          self.assertIn(
+              f'{self._soong_host_out}/framework/vts-tradefed.jar', command
+          )
+          return
+        case _:
+          self.fail(f'malformed command: {command}')
+
 
 if __name__ == '__main__':
   # Setup logging to be silent so unit tests can pass through TF.
diff --git a/core/Makefile b/core/Makefile
index bf2d48a..49b1432 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -3511,6 +3511,8 @@
 		--output $@ --value "$(STUB_LIBRARIES)" --system "$(TARGET_OUT)"
 	$(HOST_OUT_EXECUTABLES)/conv_linker_config append --source $@ --output $@ --key requireLibs \
 		--value "$(foreach lib,$(LLNDK_MOVED_TO_APEX_LIBRARIES), $(lib).so)"
+	$(HOST_OUT_EXECUTABLES)/conv_linker_config append --source $@ --output $@ --key provideLibs \
+		--value "$(foreach lib,$(PRODUCT_EXTRA_STUB_LIBRARIES), $(lib).so)"
 
 $(call declare-1p-target,$(SYSTEM_LINKER_CONFIG),)
 $(call declare-license-deps,$(SYSTEM_LINKER_CONFIG),$(INTERNAL_SYSTEMIMAGE_FILES) $(SYSTEM_LINKER_CONFIG_SOURCE))
@@ -3588,10 +3590,10 @@
 ifeq ($(PRODUCT_SOONG_DEFINED_SYSTEM_IMAGE),)
 $(error PRODUCT_SOONG_DEFINED_SYSTEM_IMAGE must be set if USE_SOONG_DEFINED_SYSTEM_IMAGE is true)
 endif
-soong_defined_system_image := $(call intermediates-dir-for,ETC,$(PRODUCT_SOONG_DEFINED_SYSTEM_IMAGE))/$(PRODUCT_SOONG_DEFINED_SYSTEM_IMAGE)
-$(BUILT_SYSTEMIMAGE): $(INSTALLED_FILES_FILE) $(systemimage_intermediates)/file_list.txt $(soong_defined_system_image)
-$(eval $(call copy-one-file, $(soong_defined_system_image), $(BUILT_SYSTEMIMAGE)))
-soong_defined_system_image :=
+SOONG_DEFINED_SYSTEM_IMAGE_PATH := $(call intermediates-dir-for,ETC,$(PRODUCT_SOONG_DEFINED_SYSTEM_IMAGE))/$(PRODUCT_SOONG_DEFINED_SYSTEM_IMAGE)
+SOONG_DEFINED_SYSTEM_IMAGE_BASE := $(dir $(ALL_MODULES.$(PRODUCT_SOONG_DEFINED_SYSTEM_IMAGE).FILESYSTEM_FILELIST))
+$(BUILT_SYSTEMIMAGE): $(INSTALLED_FILES_FILE) $(systemimage_intermediates)/file_list.txt $(SOONG_DEFINED_SYSTEM_IMAGE_PATH)
+$(eval $(call copy-one-file, $(SOONG_DEFINED_SYSTEM_IMAGE_PATH), $(BUILT_SYSTEMIMAGE)))
 else
 $(BUILT_SYSTEMIMAGE): $(FULL_SYSTEMIMAGE_DEPS) $(INSTALLED_FILES_FILE) $(systemimage_intermediates)/file_list.txt
 	$(call build-systemimage-target,$@)
@@ -6134,6 +6136,9 @@
 $(BUILT_TARGET_FILES_DIR): zip_root := $(intermediates)/$(name)
 $(BUILT_TARGET_FILES_DIR): intermediates := $(intermediates)
 
+ifneq ($(SOONG_DEFINED_SYSTEM_IMAGE_PATH),)
+  $(BUILT_TARGET_FILES_DIR): $(SOONG_DEFINED_SYSTEM_IMAGE_PATH)
+endif
 
 # $(1): Directory to copy
 # $(2): Location to copy it to
@@ -6462,8 +6467,11 @@
 	    $(INSTALLED_RAMDISK_TARGET) \
 	    $(INSTALLED_DTBIMAGE_TARGET) \
 	    $(INSTALLED_2NDBOOTLOADER_TARGET) \
+	    $(INSTALLED_VENDOR_KERNEL_RAMDISK_TARGET) \
 	    $(BUILT_RAMDISK_16K_TARGET) \
 	    $(BUILT_KERNEL_16K_TARGET) \
+	    $(BUILT_BOOTIMAGE_16K_TARGET) \
+	    $(INSTALLED_DTBOIMAGE_16KB_TARGET) \
 	    $(BOARD_PREBUILT_DTBOIMAGE) \
 	    $(BOARD_PREBUILT_RECOVERY_DTBOIMAGE) \
 	    $(BOARD_RECOVERY_ACPIO) \
@@ -6617,8 +6625,13 @@
 endif # INSTALLED_VENDOR_BOOTIMAGE_TARGET
 ifdef BUILDING_SYSTEM_IMAGE
 	@# Contents of the system image
+ifneq ($(SOONG_DEFINED_SYSTEM_IMAGE_PATH),)
+	$(hide) $(call package_files-copy-root, \
+	    $(SOONG_DEFINED_SYSTEM_IMAGE_BASE)/root/system,$(zip_root)/SYSTEM)
+else
 	$(hide) $(call package_files-copy-root, \
 	    $(SYSTEMIMAGE_SOURCE_DIR),$(zip_root)/SYSTEM)
+endif
 else ifdef INSTALLED_BUILD_PROP_TARGET
 	@# Copy the system build.prop even if not building a system image
 	@# because add_img_to_target_files may need it to build other partition
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index 5fc8fd4..75e9f77 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -47,6 +47,8 @@
 $(call soong_config_set_bool,ANDROID,CLANG_COVERAGE,$(CLANG_COVERAGE))
 $(call soong_config_set,ANDROID,SCUDO_ALLOCATION_RING_BUFFER_SIZE,$(PRODUCT_SCUDO_ALLOCATION_RING_BUFFER_SIZE))
 
+$(call soong_config_set_bool,ANDROID,EMMA_INSTRUMENT,$(if $(filter true,$(EMMA_INSTRUMENT)),true,false))
+
 # PRODUCT_PRECOMPILED_SEPOLICY defaults to true. Explicitly check if it's "false" or not.
 $(call soong_config_set_bool,ANDROID,PRODUCT_PRECOMPILED_SEPOLICY,$(if $(filter false,$(PRODUCT_PRECOMPILED_SEPOLICY)),false,true))
 
@@ -182,3 +184,6 @@
 
 # Add target_use_pan_display flag for hardware/libhardware:gralloc.default
 $(call soong_config_set_bool,gralloc,target_use_pan_display,$(if $(filter true,$(TARGET_USE_PAN_DISPLAY)),true,false))
+
+# Add use_camera_v4l2_hal flag for hardware/libhardware/modules/camera/3_4:camera.v4l2
+$(call soong_config_set_bool,camera,use_camera_v4l2_hal,$(if $(filter true,$(USE_CAMERA_V4L2_HAL)),true,false))
diff --git a/core/main.mk b/core/main.mk
index 8d0b465..80ffec4 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -289,6 +289,9 @@
 
 $(foreach mk,$(subdir_makefiles),$(info [$(call inc_and_print,subdir_makefiles_inc)/$(subdir_makefiles_total)] including $(mk) ...)$(eval include $(mk)))
 
+# Build bootloader.img/radio.img, and unpack the partitions.
+include $(BUILD_SYSTEM)/tasks/tools/update_bootloader_radio_image.mk
+
 # For an unbundled image, we can skip blueprint_tools because unbundled image
 # aims to remove a large number framework projects from the manifest, the
 # sources or dependencies for these tools may be missing from the tree.
@@ -297,6 +300,9 @@
 checkbuild: blueprint_tests
 endif
 
+# Create necessary directories and symlinks in the root filesystem
+include system/core/rootdir/create_root_structure.mk
+
 endif # dont_bother
 
 ifndef subdir_makefiles_total
@@ -305,9 +311,6 @@
 
 $(info [$(call inc_and_print,subdir_makefiles_inc)/$(subdir_makefiles_total)] finishing legacy Make module parsing ...)
 
-# Create necessary directories and symlinks in the root filesystem
-include system/core/rootdir/create_root_structure.mk
-
 # -------------------------------------------------------------------
 # All module makefiles have been included at this point.
 # -------------------------------------------------------------------
diff --git a/core/packaging/flags.mk b/core/packaging/flags.mk
index a77956b..4693bcd 100644
--- a/core/packaging/flags.mk
+++ b/core/packaging/flags.mk
@@ -18,7 +18,7 @@
 #
 
 # TODO: Should we do all of the images in $(IMAGES_TO_BUILD)?
-_FLAG_PARTITIONS := product system system_ext vendor
+_FLAG_PARTITIONS := product system vendor
 
 
 # -----------------------------------------------------------------
@@ -28,7 +28,6 @@
 # $(1): built aconfig flags file (out)
 # $(2): installed aconfig flags file (out)
 # $(3): the partition (in)
-# $(4): input aconfig files for the partition (in)
 define generate-partition-aconfig-flag-file
 $(eval $(strip $(1)): PRIVATE_OUT := $(strip $(1)))
 $(eval $(strip $(1)): PRIVATE_IN := $(strip $(4)))
@@ -36,12 +35,14 @@
 	mkdir -p $$(dir $$(PRIVATE_OUT))
 	$$(if $$(PRIVATE_IN), \
 		$$(ACONFIG) dump --dedup --format protobuf --out $$(PRIVATE_OUT) \
-			--filter container:$$(strip $(3)) $$(addprefix --cache ,$$(PRIVATE_IN)), \
+			--filter container:$(strip $(3)) \
+			$$(addprefix --cache ,$$(PRIVATE_IN)), \
 		echo -n > $$(PRIVATE_OUT) \
 	)
 $(call copy-one-file, $(1), $(2))
 endef
 
+
 # Create a summary file of build flags for each partition
 # $(1): built aconfig flags file (out)
 # $(2): installed aconfig flags file (out)
@@ -59,16 +60,22 @@
 $(call copy-one-file, $(1), $(2))
 endef
 
-
 $(foreach partition, $(_FLAG_PARTITIONS), \
 	$(eval aconfig_flag_summaries_protobuf.$(partition) := $(PRODUCT_OUT)/$(partition)/etc/aconfig_flags.pb) \
 	$(eval $(call generate-partition-aconfig-flag-file, \
-				$(TARGET_OUT_FLAGS)/$(partition)/aconfig_flags.pb, \
-				$(aconfig_flag_summaries_protobuf.$(partition)), \
-				$(partition), \
-				$(sort $(foreach m,$(call register-names-for-partition, $(partition)), \
+			$(TARGET_OUT_FLAGS)/$(partition)/aconfig_flags.pb, \
+			$(aconfig_flag_summaries_protobuf.$(partition)), \
+			$(partition), \
+			$(sort \
+				$(foreach m, $(call register-names-for-partition, $(partition)), \
 					$(ALL_MODULES.$(m).ACONFIG_FILES) \
-				)), \
+				) \
+				$(if $(filter system, $(partition)), \
+					$(foreach m, $(call register-names-for-partition, system_ext), \
+						$(ALL_MODULES.$(m).ACONFIG_FILES) \
+					) \
+				) \
+			) \
 	)) \
 )
 
@@ -175,4 +182,3 @@
 	$(eval aconfig_storage_flag_map.$(partition):=) \
 	$(eval aconfig_storage_flag_val.$(partition):=) \
 )
-
diff --git a/core/product.mk b/core/product.mk
index 4c23e5d..b07e6e0 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -499,6 +499,10 @@
 # If set, build would generate system image from Soong-defined module.
 _product_single_value_vars += PRODUCT_SOONG_DEFINED_SYSTEM_IMAGE
 
+# List of stub libraries specific to the product that are already present in the system image and
+# should be included in the system_linker_config.
+_product_list_vars += PRODUCT_EXTRA_STUB_LIBRARIES
+
 .KATI_READONLY := _product_single_value_vars _product_list_vars
 _product_var_list :=$= $(_product_single_value_vars) $(_product_list_vars)
 
diff --git a/core/soong_config.mk b/core/soong_config.mk
index fddb500..1e6388a 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -236,6 +236,12 @@
 
 $(call add_json_list, TargetFSConfigGen,                 $(TARGET_FS_CONFIG_GEN))
 
+# Although USE_SOONG_DEFINED_SYSTEM_IMAGE determines whether to use the system image specified by
+# PRODUCT_SOONG_DEFINED_SYSTEM_IMAGE, PRODUCT_SOONG_DEFINED_SYSTEM_IMAGE is still used to compare
+# installed files between make and soong, regardless of the USE_SOONG_DEFINED_SYSTEM_IMAGE setting.
+$(call add_json_bool, UseSoongSystemImage,               $(filter true,$(USE_SOONG_DEFINED_SYSTEM_IMAGE)))
+$(call add_json_str,  ProductSoongDefinedSystemImage,    $(PRODUCT_SOONG_DEFINED_SYSTEM_IMAGE))
+
 $(call add_json_map, VendorVars)
 $(foreach namespace,$(sort $(SOONG_CONFIG_NAMESPACES)),\
   $(call add_json_map, $(namespace))\
diff --git a/core/tasks/sts-sdk.mk b/core/tasks/sts-sdk.mk
index b8ce5bf..4abbc29 100644
--- a/core/tasks/sts-sdk.mk
+++ b/core/tasks/sts-sdk.mk
@@ -28,8 +28,7 @@
 	rm -f $@ $(STS_SDK_ZIP)_filtered
 	$(ZIP2ZIP) -i $(STS_SDK_ZIP) -o $(STS_SDK_ZIP)_filtered \
 		-x android-sts-sdk/tools/sts-tradefed-tests.jar \
-		'android-sts-sdk/tools/*:plugin/src/main/resources/sts-tradefed-tools/' \
-		'android-sts-sdk/jdk/**/*:plugin/src/main/resources/jdk/'
+		'android-sts-sdk/tools/*:sts-sdk/src/main/resources/sts-tradefed-tools/'
 	$(MERGE_ZIPS) $@ $(STS_SDK_ZIP)_filtered $(STS_SDK_PLUGIN_SKEL)
 	rm -f $(STS_SDK_ZIP)_filtered
 
diff --git a/core/tasks/tools/update_bootloader_radio_image.mk b/core/tasks/tools/update_bootloader_radio_image.mk
new file mode 100644
index 0000000..0ebf247
--- /dev/null
+++ b/core/tasks/tools/update_bootloader_radio_image.mk
@@ -0,0 +1,17 @@
+# 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.
+
+ifeq ($(USES_DEVICE_GOOGLE_ZUMA),true)
+    -include vendor/google_devices/zuma/prebuilts/misc_bins/update_bootloader_radio_image.mk
+endif
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index d806c06..563511f 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -345,6 +345,11 @@
         com.android.webview.bootstrap
 endif
 
+ifneq (,$(RELEASE_RANGING_STACK))
+    PRODUCT_PACKAGES += \
+        com.android.ranging
+endif
+
 # VINTF data for system image
 PRODUCT_PACKAGES += \
     system_manifest.xml \
diff --git a/target/product/default_art_config.mk b/target/product/default_art_config.mk
index 1a3f2cf..668f054 100644
--- a/target/product/default_art_config.mk
+++ b/target/product/default_art_config.mk
@@ -76,6 +76,7 @@
     com.android.mediaprovider:framework-mediaprovider \
     com.android.mediaprovider:framework-pdf \
     com.android.mediaprovider:framework-pdf-v \
+    com.android.mediaprovider:framework-photopicker \
     com.android.ondevicepersonalization:framework-ondevicepersonalization \
     com.android.os.statsd:framework-statsd \
     com.android.permission:framework-permission \
@@ -113,6 +114,12 @@
 
 endif
 
+ifneq (,$(RELEASE_RANGING_STACK))
+    PRODUCT_APEX_BOOT_JARS += \
+        com.android.uwb:framework-ranging \
+    $(call soong_config_set,bootclasspath,release_ranging_stack,true)
+endif
+
 # List of system_server classpath jars delivered via apex.
 # Keep the list sorted by module names and then library names.
 # Note: For modules available in Q, DO NOT add new entries here.
@@ -168,6 +175,11 @@
 
 endif
 
+ifneq (,$(RELEASE_RANGING_STACK))
+    PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS += \
+        com.android.uwb:service-ranging
+endif
+
 # Overrides the (apex, jar) pairs above when determining the on-device location. The format is:
 # <old_apex>:<old_jar>:<new_apex>:<new_jar>
 PRODUCT_CONFIGURED_JAR_LOCATION_OVERRIDES := \
diff --git a/tools/aconfig/aconfig/Android.bp b/tools/aconfig/aconfig/Android.bp
index 68521af..5037783 100644
--- a/tools/aconfig/aconfig/Android.bp
+++ b/tools/aconfig/aconfig/Android.bp
@@ -68,6 +68,14 @@
     ],
 }
 
+aconfig_values {
+    name: "aconfig.test.flag.second_values",
+    package: "com.android.aconfig.test",
+    srcs: [
+        "tests/third.values",
+    ],
+}
+
 aconfig_value_set {
     name: "aconfig.test.flag.value_set",
     values: [
diff --git a/tools/aconfig/aconfig/src/codegen/cpp.rs b/tools/aconfig/aconfig/src/codegen/cpp.rs
index 2c569da..7a9c382 100644
--- a/tools/aconfig/aconfig/src/codegen/cpp.rs
+++ b/tools/aconfig/aconfig/src/codegen/cpp.rs
@@ -283,39 +283,23 @@
     virtual ~flag_provider_interface() = default;
 
     virtual bool disabled_ro() = 0;
-
-    virtual void disabled_ro(bool val) = 0;
-
     virtual bool disabled_rw() = 0;
-
-    virtual void disabled_rw(bool val) = 0;
-
     virtual bool disabled_rw_exported() = 0;
-
-    virtual void disabled_rw_exported(bool val) = 0;
-
     virtual bool disabled_rw_in_other_namespace() = 0;
-
-    virtual void disabled_rw_in_other_namespace(bool val) = 0;
-
     virtual bool enabled_fixed_ro() = 0;
-
-    virtual void enabled_fixed_ro(bool val) = 0;
-
     virtual bool enabled_fixed_ro_exported() = 0;
-
-    virtual void enabled_fixed_ro_exported(bool val) = 0;
-
     virtual bool enabled_ro() = 0;
-
-    virtual void enabled_ro(bool val) = 0;
-
     virtual bool enabled_ro_exported() = 0;
-
-    virtual void enabled_ro_exported(bool val) = 0;
-
     virtual bool enabled_rw() = 0;
 
+    virtual void disabled_ro(bool val) = 0;
+    virtual void disabled_rw(bool val) = 0;
+    virtual void disabled_rw_exported(bool val) = 0;
+    virtual void disabled_rw_in_other_namespace(bool val) = 0;
+    virtual void enabled_fixed_ro(bool val) = 0;
+    virtual void enabled_fixed_ro_exported(bool val) = 0;
+    virtual void enabled_ro(bool val) = 0;
+    virtual void enabled_ro_exported(bool val) = 0;
     virtual void enabled_rw(bool val) = 0;
 
     virtual void reset_flags() {}
diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs
index dbc4ab5..1ac58c1 100644
--- a/tools/aconfig/aconfig/src/codegen/java.rs
+++ b/tools/aconfig/aconfig/src/codegen/java.rs
@@ -745,10 +745,8 @@
                 boolean val;
                 try {
                     val = reader.getBooleanFlagValue(1);
-                    if (val == disabledRw) {
-                        Log.i(TAG, String.format(SUCCESS_LOG, "disabledRw"));
-                    } else {
-                        Log.i(TAG, String.format(MISMATCH_LOG, "disabledRw", val, disabledRw));
+                    if (val != disabledRw) {
+                        Log.w(TAG, String.format(MISMATCH_LOG, "disabledRw", val, disabledRw));
                     }
 
                     if (useNewStorageValueAndDiscardOld) {
@@ -756,10 +754,8 @@
                     }
 
                     val = reader.getBooleanFlagValue(2);
-                    if (val == disabledRwExported) {
-                        Log.i(TAG, String.format(SUCCESS_LOG, "disabledRwExported"));
-                    } else {
-                        Log.i(TAG, String.format(MISMATCH_LOG, "disabledRwExported", val, disabledRwExported));
+                    if (val != disabledRwExported) {
+                        Log.w(TAG, String.format(MISMATCH_LOG, "disabledRwExported", val, disabledRwExported));
                     }
 
                     if (useNewStorageValueAndDiscardOld) {
@@ -767,10 +763,8 @@
                     }
 
                     val = reader.getBooleanFlagValue(8);
-                    if (val == enabledRw) {
-                        Log.i(TAG, String.format(SUCCESS_LOG, "enabledRw"));
-                    } else {
-                        Log.i(TAG, String.format(MISMATCH_LOG, "enabledRw", val, enabledRw));
+                    if (val != enabledRw) {
+                        Log.w(TAG, String.format(MISMATCH_LOG, "enabledRw", val, enabledRw));
                     }
 
                     if (useNewStorageValueAndDiscardOld) {
@@ -804,10 +798,8 @@
                 boolean val;
                 try {
                     val = reader.getBooleanFlagValue(3);
-                    if (val == disabledRwInOtherNamespace) {
-                        Log.i(TAG, String.format(SUCCESS_LOG, "disabledRwInOtherNamespace"));
-                    } else {
-                        Log.i(TAG, String.format(MISMATCH_LOG, "disabledRwInOtherNamespace", val, disabledRwInOtherNamespace));
+                    if (val != disabledRwInOtherNamespace) {
+                        Log.w(TAG, String.format(MISMATCH_LOG, "disabledRwInOtherNamespace", val, disabledRwInOtherNamespace));
                     }
 
                     if (useNewStorageValueAndDiscardOld) {
diff --git a/tools/aconfig/aconfig/src/codegen/rust.rs b/tools/aconfig/aconfig/src/codegen/rust.rs
index 6f3f7bf..7bc34d6 100644
--- a/tools/aconfig/aconfig/src/codegen/rust.rs
+++ b/tools/aconfig/aconfig/src/codegen/rust.rs
@@ -116,10 +116,6 @@
 use std::sync::LazyLock;
 use log::{log, LevelFilter, Level};
 
-static STORAGE_MIGRATION_MARKER_FILE: &str =
-    "/metadata/aconfig_test_missions/mission_1";
-static MIGRATION_LOG_TAG: &str = "AconfigTestMission1";
-
 /// flag provider
 pub struct FlagProvider;
 
@@ -260,13 +256,13 @@
 use std::sync::LazyLock;
 use log::{log, LevelFilter, Level};
 
-static STORAGE_MIGRATION_MARKER_FILE: &str =
-    "/metadata/aconfig_test_missions/mission_1";
-static MIGRATION_LOG_TAG: &str = "AconfigTestMission1";
-
 /// flag provider
 pub struct FlagProvider;
 
+static READ_FROM_NEW_STORAGE: LazyLock<bool> = LazyLock::new(|| unsafe {
+    Path::new("/metadata/aconfig/boot/enable_only_new_storage").exists()
+});
+
 static PACKAGE_OFFSET: LazyLock<Result<Option<u32>, AconfigStorageError>> = LazyLock::new(|| unsafe {
     get_mapped_storage_file("system", StorageFileType::PackageMap)
     .and_then(|package_map| get_package_read_context(&package_map, "com.android.aconfig.test"))
@@ -279,24 +275,14 @@
 
 /// flag value cache for disabled_rw
 static CACHED_disabled_rw: LazyLock<bool> = LazyLock::new(|| {
-    let result = flags_rust::GetServerConfigurableFlag(
-        "aconfig_flags.aconfig_test",
-        "com.android.aconfig.test.disabled_rw",
-        "false") == "true";
-
-    let use_new_storage_value = flags_rust::GetServerConfigurableFlag(
-        "aconfig_flags.core_experiments_team_internal",
-        "com.android.providers.settings.use_new_storage_value",
-        "false") == "true";
-
-    if Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+    if *READ_FROM_NEW_STORAGE {
         // This will be called multiple times. Subsequent calls after the first are noops.
         logger::init(
             logger::Config::default()
-                .with_tag_on_device(MIGRATION_LOG_TAG)
+                .with_tag_on_device("aconfig_rust_codegen")
                 .with_max_level(LevelFilter::Info));
 
-        let aconfig_storage_result = FLAG_VAL_MAP
+        let flag_value_result = FLAG_VAL_MAP
             .as_ref()
             .map_err(|err| format!("failed to get flag val map: {err}"))
             .and_then(|flag_val_map| {
@@ -314,54 +300,33 @@
                     })
                 });
 
-        match aconfig_storage_result {
-            Ok(storage_result) if storage_result == result => {
-                if use_new_storage_value {
-                    return storage_result;
-                } else {
-                    return result;
-                }
-            },
-            Ok(storage_result) => {
-                log!(Level::Error, "AconfigTestMission1: error: mismatch for flag 'disabled_rw'. Legacy storage was {result}, new storage was {storage_result}");
-                if use_new_storage_value {
-                    return storage_result;
-                } else {
-                    return result;
-                }
+        match flag_value_result {
+            Ok(flag_value) => {
+                 return flag_value;
             },
             Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: {err}");
-                if use_new_storage_value {
-                    panic!("failed to read flag value: {err}");
-                }
+                log!(Level::Error, "aconfig_rust_codegen: error: {err}");
+                panic!("failed to read flag value: {err}");
             }
         }
+    } else {
+        flags_rust::GetServerConfigurableFlag(
+            "aconfig_flags.aconfig_test",
+            "com.android.aconfig.test.disabled_rw",
+            "false") == "true"
     }
-
-    result
 });
 
 /// flag value cache for disabled_rw_exported
 static CACHED_disabled_rw_exported: LazyLock<bool> = LazyLock::new(|| {
-    let result = flags_rust::GetServerConfigurableFlag(
-        "aconfig_flags.aconfig_test",
-        "com.android.aconfig.test.disabled_rw_exported",
-        "false") == "true";
-
-    let use_new_storage_value = flags_rust::GetServerConfigurableFlag(
-        "aconfig_flags.core_experiments_team_internal",
-        "com.android.providers.settings.use_new_storage_value",
-        "false") == "true";
-
-    if Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+    if *READ_FROM_NEW_STORAGE {
         // This will be called multiple times. Subsequent calls after the first are noops.
         logger::init(
             logger::Config::default()
-                .with_tag_on_device(MIGRATION_LOG_TAG)
+                .with_tag_on_device("aconfig_rust_codegen")
                 .with_max_level(LevelFilter::Info));
 
-        let aconfig_storage_result = FLAG_VAL_MAP
+        let flag_value_result = FLAG_VAL_MAP
             .as_ref()
             .map_err(|err| format!("failed to get flag val map: {err}"))
             .and_then(|flag_val_map| {
@@ -379,54 +344,33 @@
                     })
                 });
 
-        match aconfig_storage_result {
-            Ok(storage_result) if storage_result == result => {
-                if use_new_storage_value {
-                    return storage_result;
-                } else {
-                    return result;
-                }
-            },
-            Ok(storage_result) => {
-                log!(Level::Error, "AconfigTestMission1: error: mismatch for flag 'disabled_rw_exported'. Legacy storage was {result}, new storage was {storage_result}");
-                if use_new_storage_value {
-                    return storage_result;
-                } else {
-                    return result;
-                }
+        match flag_value_result {
+            Ok(flag_value) => {
+                 return flag_value;
             },
             Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: {err}");
-                if use_new_storage_value {
-                    panic!("failed to read flag value: {err}");
-                }
+                log!(Level::Error, "aconfig_rust_codegen: error: {err}");
+                panic!("failed to read flag value: {err}");
             }
         }
+    } else {
+        flags_rust::GetServerConfigurableFlag(
+            "aconfig_flags.aconfig_test",
+            "com.android.aconfig.test.disabled_rw_exported",
+            "false") == "true"
     }
-
-    result
 });
 
 /// flag value cache for disabled_rw_in_other_namespace
 static CACHED_disabled_rw_in_other_namespace: LazyLock<bool> = LazyLock::new(|| {
-    let result = flags_rust::GetServerConfigurableFlag(
-        "aconfig_flags.other_namespace",
-        "com.android.aconfig.test.disabled_rw_in_other_namespace",
-        "false") == "true";
-
-    let use_new_storage_value = flags_rust::GetServerConfigurableFlag(
-        "aconfig_flags.core_experiments_team_internal",
-        "com.android.providers.settings.use_new_storage_value",
-        "false") == "true";
-
-    if Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+    if *READ_FROM_NEW_STORAGE {
         // This will be called multiple times. Subsequent calls after the first are noops.
         logger::init(
             logger::Config::default()
-                .with_tag_on_device(MIGRATION_LOG_TAG)
+                .with_tag_on_device("aconfig_rust_codegen")
                 .with_max_level(LevelFilter::Info));
 
-        let aconfig_storage_result = FLAG_VAL_MAP
+        let flag_value_result = FLAG_VAL_MAP
             .as_ref()
             .map_err(|err| format!("failed to get flag val map: {err}"))
             .and_then(|flag_val_map| {
@@ -444,55 +388,34 @@
                     })
                 });
 
-        match aconfig_storage_result {
-            Ok(storage_result) if storage_result == result => {
-                if use_new_storage_value {
-                    return storage_result;
-                } else {
-                    return result;
-                }
-            },
-            Ok(storage_result) => {
-                log!(Level::Error, "AconfigTestMission1: error: mismatch for flag 'disabled_rw_in_other_namespace'. Legacy storage was {result}, new storage was {storage_result}");
-                if use_new_storage_value {
-                    return storage_result;
-                } else {
-                    return result;
-                }
+        match flag_value_result {
+            Ok(flag_value) => {
+                 return flag_value;
             },
             Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: {err}");
-                if use_new_storage_value {
-                    panic!("failed to read flag value: {err}");
-                }
+                log!(Level::Error, "aconfig_rust_codegen: error: {err}");
+                panic!("failed to read flag value: {err}");
             }
         }
+    } else {
+        flags_rust::GetServerConfigurableFlag(
+            "aconfig_flags.other_namespace",
+            "com.android.aconfig.test.disabled_rw_in_other_namespace",
+            "false") == "true"
     }
-
-    result
 });
 
 
 /// flag value cache for enabled_rw
 static CACHED_enabled_rw: LazyLock<bool> = LazyLock::new(|| {
-    let result = flags_rust::GetServerConfigurableFlag(
-        "aconfig_flags.aconfig_test",
-        "com.android.aconfig.test.enabled_rw",
-        "true") == "true";
-
-    let use_new_storage_value = flags_rust::GetServerConfigurableFlag(
-        "aconfig_flags.core_experiments_team_internal",
-        "com.android.providers.settings.use_new_storage_value",
-        "false") == "true";
-
-    if Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
+    if *READ_FROM_NEW_STORAGE {
         // This will be called multiple times. Subsequent calls after the first are noops.
         logger::init(
             logger::Config::default()
-                .with_tag_on_device(MIGRATION_LOG_TAG)
+                .with_tag_on_device("aconfig_rust_codegen")
                 .with_max_level(LevelFilter::Info));
 
-        let aconfig_storage_result = FLAG_VAL_MAP
+        let flag_value_result = FLAG_VAL_MAP
             .as_ref()
             .map_err(|err| format!("failed to get flag val map: {err}"))
             .and_then(|flag_val_map| {
@@ -510,32 +433,21 @@
                     })
                 });
 
-        match aconfig_storage_result {
-            Ok(storage_result) if storage_result == result => {
-                if use_new_storage_value {
-                    return storage_result;
-                } else {
-                    return result;
-                }
-            },
-            Ok(storage_result) => {
-                log!(Level::Error, "AconfigTestMission1: error: mismatch for flag 'enabled_rw'. Legacy storage was {result}, new storage was {storage_result}");
-                if use_new_storage_value {
-                    return storage_result;
-                } else {
-                    return result;
-                }
+        match flag_value_result {
+            Ok(flag_value) => {
+                 return flag_value;
             },
             Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: {err}");
-                if use_new_storage_value {
-                    panic!("failed to read flag value: {err}");
-                }
+                log!(Level::Error, "aconfig_rust_codegen: error: {err}");
+                panic!("failed to read flag value: {err}");
             }
         }
+    } else {
+        flags_rust::GetServerConfigurableFlag(
+            "aconfig_flags.aconfig_test",
+            "com.android.aconfig.test.enabled_rw",
+            "true") == "true"
     }
-
-    result
 });
 
 impl FlagProvider {
@@ -596,65 +508,7 @@
 /// query flag disabled_ro
 #[inline(always)]
 pub fn disabled_ro() -> bool {
-
-
-    let result = false;
-    if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
-        return result;
-    }
-
-    // This will be called multiple times. Subsequent calls after the first
-    // are noops.
-    logger::init(
-        logger::Config::default()
-            .with_tag_on_device(MIGRATION_LOG_TAG)
-            .with_max_level(LevelFilter::Info),
-    );
-
-    unsafe {
-        let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
-            Ok(file) => file,
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'disabled_ro': {err}");
-                return result;
-            }
-        };
-
-        let package_read_context = match get_package_read_context(&package_map, "com.android.aconfig.test") {
-            Ok(Some(context)) => context,
-            Ok(None) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'disabled_ro': did not get context");
-                return result;
-            },
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'disabled_ro': {err}");
-                return result;
-            }
-        };
-        let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
-            Ok(val_map) => val_map,
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'disabled_ro': {err}");
-                return result;
-            }
-        };
-        let value = match get_boolean_flag_value(&flag_val_map, 0 + package_read_context.boolean_start_index) {
-            Ok(val) => val,
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'disabled_ro': {err}");
-                return result;
-            }
-        };
-
-        if result != value {
-            log!(Level::Error, "AconfigTestMission1: error: flag mismatch for 'disabled_ro'. Legacy storage was {result}, new storage was {value}");
-        } else {
-            let default_value = false;
-        }
-    }
-
-    result
-
+   false
 }
 
 /// query flag disabled_rw
@@ -678,257 +532,25 @@
 /// query flag enabled_fixed_ro
 #[inline(always)]
 pub fn enabled_fixed_ro() -> bool {
-
-
-    let result = true;
-    if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
-        return result;
-    }
-
-    // This will be called multiple times. Subsequent calls after the first
-    // are noops.
-    logger::init(
-        logger::Config::default()
-            .with_tag_on_device(MIGRATION_LOG_TAG)
-            .with_max_level(LevelFilter::Info),
-    );
-
-    unsafe {
-        let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
-            Ok(file) => file,
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro': {err}");
-                return result;
-            }
-        };
-
-        let package_read_context = match get_package_read_context(&package_map, "com.android.aconfig.test") {
-            Ok(Some(context)) => context,
-            Ok(None) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro': did not get context");
-                return result;
-            },
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro': {err}");
-                return result;
-            }
-        };
-        let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
-            Ok(val_map) => val_map,
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro': {err}");
-                return result;
-            }
-        };
-        let value = match get_boolean_flag_value(&flag_val_map, 4 + package_read_context.boolean_start_index) {
-            Ok(val) => val,
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro': {err}");
-                return result;
-            }
-        };
-
-        if result != value {
-            log!(Level::Error, "AconfigTestMission1: error: flag mismatch for 'enabled_fixed_ro'. Legacy storage was {result}, new storage was {value}");
-        } else {
-            let default_value = true;
-        }
-    }
-
-    result
-
+    true
 }
 
 /// query flag enabled_fixed_ro_exported
 #[inline(always)]
 pub fn enabled_fixed_ro_exported() -> bool {
-
-
-    let result = true;
-    if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
-        return result;
-    }
-
-    // This will be called multiple times. Subsequent calls after the first
-    // are noops.
-    logger::init(
-        logger::Config::default()
-            .with_tag_on_device(MIGRATION_LOG_TAG)
-            .with_max_level(LevelFilter::Info),
-    );
-
-    unsafe {
-        let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
-            Ok(file) => file,
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro_exported': {err}");
-                return result;
-            }
-        };
-
-        let package_read_context = match get_package_read_context(&package_map, "com.android.aconfig.test") {
-            Ok(Some(context)) => context,
-            Ok(None) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro_exported': did not get context");
-                return result;
-            },
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro_exported': {err}");
-                return result;
-            }
-        };
-        let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
-            Ok(val_map) => val_map,
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro_exported': {err}");
-                return result;
-            }
-        };
-        let value = match get_boolean_flag_value(&flag_val_map, 5 + package_read_context.boolean_start_index) {
-            Ok(val) => val,
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_fixed_ro_exported': {err}");
-                return result;
-            }
-        };
-
-        if result != value {
-            log!(Level::Error, "AconfigTestMission1: error: flag mismatch for 'enabled_fixed_ro_exported'. Legacy storage was {result}, new storage was {value}");
-        } else {
-            let default_value = true;
-        }
-    }
-
-    result
-
+    true
 }
 
 /// query flag enabled_ro
 #[inline(always)]
 pub fn enabled_ro() -> bool {
-
-
-    let result = true;
-    if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
-        return result;
-    }
-
-    // This will be called multiple times. Subsequent calls after the first
-    // are noops.
-    logger::init(
-        logger::Config::default()
-            .with_tag_on_device(MIGRATION_LOG_TAG)
-            .with_max_level(LevelFilter::Info),
-    );
-
-    unsafe {
-        let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
-            Ok(file) => file,
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro': {err}");
-                return result;
-            }
-        };
-
-        let package_read_context = match get_package_read_context(&package_map, "com.android.aconfig.test") {
-            Ok(Some(context)) => context,
-            Ok(None) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro': did not get context");
-                return result;
-            },
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro': {err}");
-                return result;
-            }
-        };
-        let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
-            Ok(val_map) => val_map,
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro': {err}");
-                return result;
-            }
-        };
-        let value = match get_boolean_flag_value(&flag_val_map, 6 + package_read_context.boolean_start_index) {
-            Ok(val) => val,
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro': {err}");
-                return result;
-            }
-        };
-
-        if result != value {
-            log!(Level::Error, "AconfigTestMission1: error: flag mismatch for 'enabled_ro'. Legacy storage was {result}, new storage was {value}");
-        } else {
-            let default_value = true;
-        }
-    }
-
-    result
-
+    true
 }
 
 /// query flag enabled_ro_exported
 #[inline(always)]
 pub fn enabled_ro_exported() -> bool {
-
-
-    let result = true;
-    if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() {
-        return result;
-    }
-
-    // This will be called multiple times. Subsequent calls after the first
-    // are noops.
-    logger::init(
-        logger::Config::default()
-            .with_tag_on_device(MIGRATION_LOG_TAG)
-            .with_max_level(LevelFilter::Info),
-    );
-
-    unsafe {
-        let package_map = match get_mapped_storage_file("system", StorageFileType::PackageMap) {
-            Ok(file) => file,
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro_exported': {err}");
-                return result;
-            }
-        };
-
-        let package_read_context = match get_package_read_context(&package_map, "com.android.aconfig.test") {
-            Ok(Some(context)) => context,
-            Ok(None) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro_exported': did not get context");
-                return result;
-            },
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro_exported': {err}");
-                return result;
-            }
-        };
-        let flag_val_map = match get_mapped_storage_file("system", StorageFileType::FlagVal) {
-            Ok(val_map) => val_map,
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro_exported': {err}");
-                return result;
-            }
-        };
-        let value = match get_boolean_flag_value(&flag_val_map, 7 + package_read_context.boolean_start_index) {
-            Ok(val) => val,
-            Err(err) => {
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag 'enabled_ro_exported': {err}");
-                return result;
-            }
-        };
-
-        if result != value {
-            log!(Level::Error, "AconfigTestMission1: error: flag mismatch for 'enabled_ro_exported'. Legacy storage was {result}, new storage was {value}");
-        } else {
-            let default_value = true;
-        }
-    }
-
-    result
-
+    true
 }
 
 /// query flag enabled_rw
@@ -1203,10 +825,6 @@
 use std::sync::LazyLock;
 use log::{log, LevelFilter, Level};
 
-static STORAGE_MIGRATION_MARKER_FILE: &str =
-    "/metadata/aconfig_test_missions/mission_1";
-static MIGRATION_LOG_TAG: &str = "AconfigTestMission1";
-
 /// flag provider
 pub struct FlagProvider;
 
@@ -1275,10 +893,6 @@
 use std::sync::LazyLock;
 use log::{log, LevelFilter, Level};
 
-static STORAGE_MIGRATION_MARKER_FILE: &str =
-    "/metadata/aconfig_test_missions/mission_1";
-static MIGRATION_LOG_TAG: &str = "AconfigTestMission1";
-
 /// flag provider
 pub struct FlagProvider;
 
diff --git a/tools/aconfig/aconfig/src/commands.rs b/tools/aconfig/aconfig/src/commands.rs
index 1a14f64..b585416 100644
--- a/tools/aconfig/aconfig/src/commands.rs
+++ b/tools/aconfig/aconfig/src/commands.rs
@@ -17,7 +17,7 @@
 use anyhow::{bail, ensure, Context, Result};
 use itertools::Itertools;
 use protobuf::Message;
-use std::collections::{BTreeMap, HashMap};
+use std::collections::HashMap;
 use std::hash::Hasher;
 use std::io::Read;
 use std::path::PathBuf;
@@ -79,8 +79,18 @@
             .read_to_string(&mut contents)
             .with_context(|| format!("failed to read {}", input.source))?;
 
-        let flag_declarations = aconfig_protos::flag_declarations::try_from_text_proto(&contents)
-            .with_context(|| input.error_context())?;
+        let mut flag_declarations =
+            aconfig_protos::flag_declarations::try_from_text_proto(&contents)
+                .with_context(|| input.error_context())?;
+
+        // system_ext flags should be treated as system flags as we are combining /system_ext
+        // and /system as one container
+        // TODO: remove this logic when we start enforcing that system_ext cannot be set as
+        // container in aconfig declaration files.
+        if flag_declarations.container() == "system_ext" {
+            flag_declarations.set_container(String::from("system"));
+        }
+
         ensure!(
             package == flag_declarations.package(),
             "failed to parse {}: expected package {}, got {}",
@@ -412,25 +422,32 @@
     Ok(flag_ids)
 }
 
-#[allow(dead_code)] // TODO: b/316357686 - Use fingerprint in codegen to
-                    // protect hardcoded offset reads.
-pub fn compute_flag_offsets_fingerprint(flags_map: &HashMap<String, u16>) -> Result<u64> {
+// Creates a fingerprint of the flag names. Sorts the vector.
+pub fn compute_flags_fingerprint(flag_names: &mut Vec<String>) -> Result<u64> {
+    flag_names.sort();
+
     let mut hasher = SipHasher13::new();
-
-    // Need to sort to ensure the data is added to the hasher in the same order
-    // each run.
-    let sorted_map: BTreeMap<&String, &u16> = flags_map.iter().collect();
-
-    for (flag, offset) in sorted_map {
-        // See https://docs.rs/siphasher/latest/siphasher/#note for use of write
-        // over write_i16. Similarly, use to_be_bytes rather than to_ne_bytes to
-        // ensure consistency.
+    for flag in flag_names {
         hasher.write(flag.as_bytes());
-        hasher.write(&offset.to_be_bytes());
     }
     Ok(hasher.finish())
 }
 
+#[allow(dead_code)] // TODO: b/316357686 - Use fingerprint in codegen to
+                    // protect hardcoded offset reads.
+fn compute_fingerprint_from_parsed_flags(flags: ProtoParsedFlags) -> Result<u64> {
+    let separated_flags: Vec<ProtoParsedFlag> = flags.parsed_flag.into_iter().collect::<Vec<_>>();
+
+    // All flags must belong to the same package as the fingerprint is per-package.
+    let Some(_package) = find_unique_package(&separated_flags) else {
+        bail!("No parsed flags, or the parsed flags use different packages.");
+    };
+
+    let mut flag_names =
+        separated_flags.into_iter().map(|flag| flag.name.unwrap()).collect::<Vec<_>>();
+    compute_flags_fingerprint(&mut flag_names)
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -439,16 +456,47 @@
     #[test]
     fn test_offset_fingerprint() {
         let parsed_flags = crate::test::parse_test_flags();
-        let package = find_unique_package(&parsed_flags.parsed_flag).unwrap().to_string();
-        let flag_ids = assign_flag_ids(&package, parsed_flags.parsed_flag.iter()).unwrap();
-        let expected_fingerprint = 10709892481002252132u64;
+        let expected_fingerprint: u64 = 5801144784618221668;
 
-        let hash_result = compute_flag_offsets_fingerprint(&flag_ids);
+        let hash_result = compute_fingerprint_from_parsed_flags(parsed_flags);
 
         assert_eq!(hash_result.unwrap(), expected_fingerprint);
     }
 
     #[test]
+    fn test_offset_fingerprint_matches_from_package() {
+        let parsed_flags: ProtoParsedFlags = crate::test::parse_test_flags();
+
+        // All test flags are in the same package, so fingerprint from all of them.
+        let result_from_parsed_flags = compute_fingerprint_from_parsed_flags(parsed_flags.clone());
+
+        let mut flag_names_vec = parsed_flags
+            .parsed_flag
+            .clone()
+            .into_iter()
+            .map(|flag| flag.name.unwrap())
+            .map(String::from)
+            .collect::<Vec<_>>();
+        let result_from_names = compute_flags_fingerprint(&mut flag_names_vec);
+
+        // Assert the same hash is generated for each case.
+        assert_eq!(result_from_parsed_flags.unwrap(), result_from_names.unwrap());
+    }
+
+    #[test]
+    fn test_offset_fingerprint_different_packages_does_not_match() {
+        // Parse flags from two packages.
+        let parsed_flags: ProtoParsedFlags = crate::test::parse_test_flags();
+        let second_parsed_flags = crate::test::parse_second_package_flags();
+
+        let result_from_parsed_flags = compute_fingerprint_from_parsed_flags(parsed_flags).unwrap();
+        let second_result = compute_fingerprint_from_parsed_flags(second_parsed_flags).unwrap();
+
+        // Different flags should have a different fingerprint.
+        assert_ne!(result_from_parsed_flags, second_result);
+    }
+
+    #[test]
     fn test_parse_flags() {
         let parsed_flags = crate::test::parse_test_flags(); // calls parse_flags
         aconfig_protos::parsed_flags::verify_fields(&parsed_flags).unwrap();
diff --git a/tools/aconfig/aconfig/src/storage/mod.rs b/tools/aconfig/aconfig/src/storage/mod.rs
index 73339f2..efce24e 100644
--- a/tools/aconfig/aconfig/src/storage/mod.rs
+++ b/tools/aconfig/aconfig/src/storage/mod.rs
@@ -25,12 +25,14 @@
     flag_table::create_flag_table, flag_value::create_flag_value,
     package_table::create_package_table,
 };
-use aconfig_protos::{ProtoParsedFlag, ProtoParsedFlags};
+use aconfig_protos::ProtoParsedFlag;
+use aconfig_protos::ProtoParsedFlags;
 use aconfig_storage_file::StorageFileType;
 
 pub struct FlagPackage<'a> {
     pub package_name: &'a str,
     pub package_id: u32,
+    pub fingerprint: u64,
     pub flag_names: HashSet<&'a str>,
     pub boolean_flags: Vec<&'a ProtoParsedFlag>,
     // The index of the first boolean flag in this aconfig package among all boolean
@@ -43,6 +45,7 @@
         FlagPackage {
             package_name,
             package_id,
+            fingerprint: 0,
             flag_names: HashSet::new(),
             boolean_flags: vec![],
             boolean_start_index: 0,
@@ -78,6 +81,8 @@
     for p in packages.iter_mut() {
         p.boolean_start_index = boolean_start_index;
         boolean_start_index += p.boolean_flags.len() as u32;
+
+        // TODO: b/316357686 - Calculate fingerprint and add to package.
     }
 
     packages
@@ -115,6 +120,8 @@
     use super::*;
     use crate::Input;
 
+    use aconfig_protos::ProtoParsedFlags;
+
     pub fn parse_all_test_flags() -> Vec<ProtoParsedFlags> {
         let aconfig_files = [
             (
diff --git a/tools/aconfig/aconfig/src/storage/package_table.rs b/tools/aconfig/aconfig/src/storage/package_table.rs
index c53602f..33bb077 100644
--- a/tools/aconfig/aconfig/src/storage/package_table.rs
+++ b/tools/aconfig/aconfig/src/storage/package_table.rs
@@ -48,6 +48,7 @@
         let node = PackageTableNode {
             package_name: String::from(package.package_name),
             package_id: package.package_id,
+            fingerprint: package.fingerprint,
             boolean_start_index: package.boolean_start_index,
             next_offset: None,
         };
diff --git a/tools/aconfig/aconfig/src/test.rs b/tools/aconfig/aconfig/src/test.rs
index 7409cda..a19b372 100644
--- a/tools/aconfig/aconfig/src/test.rs
+++ b/tools/aconfig/aconfig/src/test.rs
@@ -295,6 +295,24 @@
         aconfig_protos::parsed_flags::try_from_binary_proto(&bytes).unwrap()
     }
 
+    pub fn parse_second_package_flags() -> ProtoParsedFlags {
+        let bytes = crate::commands::parse_flags(
+            "com.android.aconfig.second_test",
+            Some("system"),
+            vec![Input {
+                source: "tests/test_second_package.aconfig".to_string(),
+                reader: Box::new(include_bytes!("../tests/test_second_package.aconfig").as_slice()),
+            }],
+            vec![Input {
+                source: "tests/third.values".to_string(),
+                reader: Box::new(include_bytes!("../tests/third.values").as_slice()),
+            }],
+            crate::commands::DEFAULT_FLAG_PERMISSION,
+        )
+        .unwrap();
+        aconfig_protos::parsed_flags::try_from_binary_proto(&bytes).unwrap()
+    }
+
     pub fn first_significant_code_diff(a: &str, b: &str) -> Option<String> {
         let a = a.lines().map(|line| line.trim_start()).filter(|line| !line.is_empty());
         let b = b.lines().map(|line| line.trim_start()).filter(|line| !line.is_empty());
diff --git a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
index 9970b1f..bc01aa4 100644
--- a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
+++ b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
@@ -90,10 +90,8 @@
 {{ -if flag.is_read_write }}
 
                 val = reader.getBooleanFlagValue({flag.flag_offset});
-                if (val == {flag.method_name}) \{
-                    Log.i(TAG, String.format(SUCCESS_LOG, "{flag.method_name}"));
-                } else \{
-                    Log.i(TAG, String.format(MISMATCH_LOG, "{flag.method_name}", val, {flag.method_name}));
+                if (val != {flag.method_name}) \{
+                    Log.w(TAG, String.format(MISMATCH_LOG, "{flag.method_name}", val, {flag.method_name}));
                 }
 
                 if (useNewStorageValueAndDiscardOld) \{
diff --git a/tools/aconfig/aconfig/templates/cpp_exported_header.template b/tools/aconfig/aconfig/templates/cpp_exported_header.template
index 0f7853e..4643c97 100644
--- a/tools/aconfig/aconfig/templates/cpp_exported_header.template
+++ b/tools/aconfig/aconfig/templates/cpp_exported_header.template
@@ -27,12 +27,13 @@
     {{ -for item in class_elements}}
     virtual bool {item.flag_name}() = 0;
 
-    {{ -if is_test_mode }}
-    virtual void {item.flag_name}(bool val) = 0;
-    {{ -endif }}
     {{ -endfor }}
 
     {{ -if is_test_mode }}
+    {{ -for item in class_elements}}
+    virtual void {item.flag_name}(bool val) = 0;
+    {{ -endfor }}
+
     virtual void reset_flags() \{}
     {{ -endif }}
 };
diff --git a/tools/aconfig/aconfig/templates/cpp_source_file.template b/tools/aconfig/aconfig/templates/cpp_source_file.template
index b6012e7..623034a 100644
--- a/tools/aconfig/aconfig/templates/cpp_source_file.template
+++ b/tools/aconfig/aconfig/templates/cpp_source_file.template
@@ -6,7 +6,7 @@
 #include "aconfig_storage/aconfig_storage_read_api.hpp"
 #include <android/log.h>
 #define LOG_TAG "aconfig_cpp_codegen"
-#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
 {{ -endif }}
 {{ endif }}
 
@@ -76,13 +76,14 @@
             : boolean_start_index_()
             {{ -endif }}
             , flag_value_file_(nullptr)
-            , read_from_new_storage_(false)
-            , use_new_storage_value(false) \{
+            , read_from_new_storage_(false) \{
 
             struct stat buffer;
-            if (stat("/metadata/aconfig_test_missions/mission_1", &buffer) == 0) \{
+            if (stat("/metadata/aconfig/boot/enable_only_new_storage", &buffer) == 0) \{
                read_from_new_storage_ = true;
-            } else \{
+            }
+
+            if (!read_from_new_storage_) \{
                return;
             }
 
@@ -90,15 +91,13 @@
                  "{container}",
                  aconfig_storage::StorageFileType::package_map);
             if (!package_map_file.ok()) \{
-                ALOGI("error: failed to get package map file: %s", package_map_file.error().c_str());
-                return;
+                ALOGE("error: failed to get package map file: %s", package_map_file.error().c_str());
             }
 
             auto context = aconfig_storage::get_package_read_context(
                 **package_map_file, "{package}");
             if (!context.ok()) \{
-                ALOGI("error: failed to get package read context: %s", context.error().c_str());
-                return;
+                ALOGE("error: failed to get package read context: %s", context.error().c_str());
             }
 
             // cache package boolean flag start index
@@ -111,18 +110,13 @@
                 "{container}",
                 aconfig_storage::StorageFileType::flag_val);
             if (!flag_value_file.ok()) \{
-                ALOGI("error: failed to get flag value file: %s", flag_value_file.error().c_str());
-                return;
+                ALOGE("error: failed to get flag value file: %s", flag_value_file.error().c_str());
             }
 
             // cache flag value file
             flag_value_file_ = std::unique_ptr<aconfig_storage::MappedStorageFile>(
                 *flag_value_file);
 
-            use_new_storage_value = server_configurable_flags::GetServerConfigurableFlag(
-                "aconfig_flags.core_experiments_team_internal",
-                "com.android.providers.settings.use_new_storage_value",
-                "false") == "true";
         }
         {{ -endif }}
         {{ -endif }}
@@ -131,44 +125,30 @@
         virtual bool {item.flag_name}() override \{
             {{ -if item.readwrite }}
             if (cache_[{item.readwrite_idx}] == -1) \{
+            {{ if allow_instrumentation- }}
+                if (read_from_new_storage_) \{
+                    auto value = aconfig_storage::get_boolean_flag_value(
+                        *flag_value_file_,
+                        boolean_start_index_ + {item.flag_offset});
+
+                    if (!value.ok()) \{
+                        ALOGE("error: failed to read flag value: %s", value.error().c_str());
+                    }
+
+                    cache_[{item.readwrite_idx}] = *value;
+                } else \{
+                    cache_[{item.readwrite_idx}] = server_configurable_flags::GetServerConfigurableFlag(
+                        "aconfig_flags.{item.device_config_namespace}",
+                        "{item.device_config_flag}",
+                        "{item.default_value}") == "true";
+                }
+            {{ -else- }}
                 cache_[{item.readwrite_idx}] = server_configurable_flags::GetServerConfigurableFlag(
                     "aconfig_flags.{item.device_config_namespace}",
                     "{item.device_config_flag}",
                     "{item.default_value}") == "true";
-            }
-
-
-            {{ if allow_instrumentation- }}
-            if (read_from_new_storage_) \{
-                if (!flag_value_file_) \{
-                    ALOGI("error: failed to get flag {item.flag_name}: flag value file is null");
-                    return cache_[{item.readwrite_idx}];
-                }
-
-                auto value = aconfig_storage::get_boolean_flag_value(
-                    *flag_value_file_,
-                    boolean_start_index_ + {item.flag_offset});
-
-                if (!value.ok()) \{
-                    ALOGI("error: failed to read flag value: %s", value.error().c_str());
-                    return cache_[{item.readwrite_idx}];
-                }
-
-                bool expected_value = cache_[{item.readwrite_idx}];
-                if (*value != expected_value) \{
-                    ALOGI("error: {item.flag_name} value mismatch, new storage value is %s, old storage value is %s",
-                    *value ? "true" : "false", expected_value ? "true" : "false");
-                }
-
-                if (use_new_storage_value) \{
-                    return *value;
-                } else \{
-                    return expected_value;
-                }
-            }
             {{ -endif }}
-
-
+            }
             return cache_[{item.readwrite_idx}];
             {{ -else }}
             {{ -if item.is_fixed_read_only }}
@@ -189,7 +169,6 @@
         std::unique_ptr<aconfig_storage::MappedStorageFile> flag_value_file_;
 
         bool read_from_new_storage_;
-        bool use_new_storage_value;
     {{ -endif }}
     {{ -endif }}
 
diff --git a/tools/aconfig/aconfig/templates/rust.template b/tools/aconfig/aconfig/templates/rust.template
index ea1c600..c2f162f 100644
--- a/tools/aconfig/aconfig/templates/rust.template
+++ b/tools/aconfig/aconfig/templates/rust.template
@@ -5,15 +5,15 @@
 use std::sync::LazyLock;
 use log::\{log, LevelFilter, Level};
 
-static STORAGE_MIGRATION_MARKER_FILE: &str =
-    "/metadata/aconfig_test_missions/mission_1";
-static MIGRATION_LOG_TAG: &str = "AconfigTestMission1";
-
 /// flag provider
 pub struct FlagProvider;
 
 {{ if has_readwrite- }}
 {{ if allow_instrumentation }}
+static READ_FROM_NEW_STORAGE: LazyLock<bool> = LazyLock::new(|| unsafe \{
+    Path::new("/metadata/aconfig/boot/enable_only_new_storage").exists()
+});
+
 static PACKAGE_OFFSET: LazyLock<Result<Option<u32>, AconfigStorageError>> = LazyLock::new(|| unsafe \{
     get_mapped_storage_file("{container}", StorageFileType::PackageMap)
     .and_then(|package_map| get_package_read_context(&package_map, "{package}"))
@@ -30,24 +30,15 @@
 /// flag value cache for {flag.name}
 {{ if allow_instrumentation }}
 static CACHED_{flag.name}: LazyLock<bool> = LazyLock::new(|| \{
-    let result = flags_rust::GetServerConfigurableFlag(
-        "aconfig_flags.{flag.device_config_namespace}",
-        "{flag.device_config_flag}",
-        "{flag.default_value}") == "true";
 
-    let use_new_storage_value = flags_rust::GetServerConfigurableFlag(
-        "aconfig_flags.core_experiments_team_internal",
-        "com.android.providers.settings.use_new_storage_value",
-        "false") == "true";
-
-    if Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() \{
+    if *READ_FROM_NEW_STORAGE \{
         // This will be called multiple times. Subsequent calls after the first are noops.
         logger::init(
             logger::Config::default()
-                .with_tag_on_device(MIGRATION_LOG_TAG)
+                .with_tag_on_device("aconfig_rust_codegen")
                 .with_max_level(LevelFilter::Info));
 
-        let aconfig_storage_result = FLAG_VAL_MAP
+        let flag_value_result = FLAG_VAL_MAP
             .as_ref()
             .map_err(|err| format!("failed to get flag val map: \{err}"))
             .and_then(|flag_val_map| \{
@@ -65,33 +56,23 @@
                     })
                 });
 
-        match aconfig_storage_result \{
-            Ok(storage_result) if storage_result == result => \{
-                if use_new_storage_value \{
-                    return storage_result;
-                } else \{
-                    return result;
-                }
-            },
-            Ok(storage_result) => \{
-                log!(Level::Error, "AconfigTestMission1: error: mismatch for flag '{flag.name}'. Legacy storage was \{result}, new storage was \{storage_result}");
-                if use_new_storage_value \{
-                    return storage_result;
-                } else \{
-                    return result;
-                }
+        match flag_value_result \{
+            Ok(flag_value) => \{
+                return flag_value;
             },
             Err(err) => \{
-                log!(Level::Error, "AconfigTestMission1: error: \{err}");
-                if use_new_storage_value \{
-                    panic!("failed to read flag value: \{err}");
-                }
+                log!(Level::Error, "aconfig_rust_codegen: error: \{err}");
+                panic!("failed to read flag value: \{err}");
             }
         }
+    } else \{
+        flags_rust::GetServerConfigurableFlag(
+            "aconfig_flags.{flag.device_config_namespace}",
+            "{flag.device_config_flag}",
+            "{flag.default_value}") == "true"
     }
 
-    result
-    });
+});
 {{ else }}
 static CACHED_{flag.name}: LazyLock<bool> = LazyLock::new(|| flags_rust::GetServerConfigurableFlag(
     "aconfig_flags.{flag.device_config_namespace}",
@@ -123,72 +104,11 @@
 {{ for flag in template_flags }}
 /// query flag {flag.name}
 #[inline(always)]
-{{ -if flag.readwrite }}
 pub fn {flag.name}() -> bool \{
+{{ -if flag.readwrite }}
     PROVIDER.{flag.name}()
 {{ -else }}
-pub fn {flag.name}() -> bool \{
-    {{ if not allow_instrumentation }}
     {flag.default_value}
-    {{ else }}
-
-    let result = {flag.default_value};
-    if !Path::new(STORAGE_MIGRATION_MARKER_FILE).exists() \{
-        return result;
-    }
-
-    // This will be called multiple times. Subsequent calls after the first
-    // are noops.
-    logger::init(
-        logger::Config::default()
-            .with_tag_on_device(MIGRATION_LOG_TAG)
-            .with_max_level(LevelFilter::Info),
-    );
-
-    unsafe \{
-        let package_map = match get_mapped_storage_file("{flag.container}", StorageFileType::PackageMap) \{
-            Ok(file) => file,
-            Err(err) => \{
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag '{flag.name}': \{err}");
-                return result;
-            }
-        };
-
-        let package_read_context = match get_package_read_context(&package_map, "{package}") \{
-            Ok(Some(context)) => context,
-            Ok(None) => \{
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag '{flag.name}': did not get context");
-                return result;
-            },
-            Err(err) => \{
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag '{flag.name}': \{err}");
-                return result;
-            }
-        };
-        let flag_val_map = match get_mapped_storage_file("{flag.container}", StorageFileType::FlagVal) \{
-            Ok(val_map) => val_map,
-            Err(err) => \{
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag '{flag.name}': \{err}");
-                return result;
-            }
-        };
-        let value = match get_boolean_flag_value(&flag_val_map, {flag.flag_offset} + package_read_context.boolean_start_index) \{
-            Ok(val) => val,
-            Err(err) => \{
-                log!(Level::Error, "AconfigTestMission1: error: failed to read flag '{flag.name}': \{err}");
-                return result;
-            }
-        };
-
-        if result != value \{
-            log!(Level::Error, "AconfigTestMission1: error: flag mismatch for '{flag.name}'. Legacy storage was \{result}, new storage was \{value}");
-        } else \{
-            let default_value = {flag.default_value};
-        }
-    }
-
-    result
-    {{ endif }}
 {{ -endif }}
 }
 {{ endfor }}
diff --git a/tools/aconfig/aconfig/tests/test.aconfig b/tools/aconfig/aconfig/tests/test.aconfig
index c11508a..a818b23 100644
--- a/tools/aconfig/aconfig/tests/test.aconfig
+++ b/tools/aconfig/aconfig/tests/test.aconfig
@@ -86,4 +86,4 @@
     bug: "111"
     is_fixed_read_only: true
     is_exported: true
-}
\ No newline at end of file
+}
diff --git a/tools/aconfig/aconfig/tests/test_second_package.aconfig b/tools/aconfig/aconfig/tests/test_second_package.aconfig
new file mode 100644
index 0000000..a8740b8
--- /dev/null
+++ b/tools/aconfig/aconfig/tests/test_second_package.aconfig
@@ -0,0 +1,12 @@
+package: "com.android.aconfig.second_test"
+container: "system"
+
+flag {
+    name: "testing_flag"
+    namespace: "another_namespace"
+    description: "This is a flag for testing."
+    bug: "123"
+    metadata {
+        purpose: PURPOSE_UNSPECIFIED
+    }
+}
diff --git a/tools/aconfig/aconfig/tests/third.values b/tools/aconfig/aconfig/tests/third.values
new file mode 100644
index 0000000..675832a
--- /dev/null
+++ b/tools/aconfig/aconfig/tests/third.values
@@ -0,0 +1,6 @@
+flag_value {
+    package: "com.android.aconfig.second_test"
+    name: "testing_flag"
+    state: DISABLED
+    permission: READ_WRITE
+}
diff --git a/tools/aconfig/aconfig_device_paths/Android.bp b/tools/aconfig/aconfig_device_paths/Android.bp
index 95cecf4..932dfbf 100644
--- a/tools/aconfig/aconfig_device_paths/Android.bp
+++ b/tools/aconfig/aconfig_device_paths/Android.bp
@@ -51,4 +51,8 @@
     static_libs: [
         "libaconfig_java_proto_nano",
     ],
+    sdk_version: "core_platform",
+    apex_available: [
+        "//apex_available:platform",
+    ],
 }
diff --git a/tools/aconfig/aconfig_device_paths/src/DeviceProtosTemplate.java b/tools/aconfig/aconfig_device_paths/src/DeviceProtosTemplate.java
index 58c58de..4d41199 100644
--- a/tools/aconfig/aconfig_device_paths/src/DeviceProtosTemplate.java
+++ b/tools/aconfig/aconfig_device_paths/src/DeviceProtosTemplate.java
@@ -29,7 +29,7 @@
  * @hide
  */
 public class DeviceProtos {
-    static final String[] PATHS = {
+	public static final String[] PATHS = {
         TEMPLATE
     };
 
@@ -50,10 +50,11 @@
         ArrayList<parsed_flag> result = new ArrayList();
 
         for (String path : parsedFlagsProtoPaths()) {
-            FileInputStream inputStream = new FileInputStream(path);
-            parsed_flags parsedFlags = parsed_flags.parseFrom(inputStream.readAllBytes());
-            for (parsed_flag flag : parsedFlags.parsedFlag) {
-                result.add(flag);
+            try (FileInputStream inputStream = new FileInputStream(path)) {
+                parsed_flags parsedFlags = parsed_flags.parseFrom(inputStream.readAllBytes());
+                for (parsed_flag flag : parsedFlags.parsedFlag) {
+                    result.add(flag);
+                }
             }
         }
 
@@ -64,7 +65,7 @@
      * Returns the list of all on-device aconfig protos paths.
      * @hide
      */
-    private static List<String> parsedFlagsProtoPaths() {
+    public static List<String> parsedFlagsProtoPaths() {
         ArrayList<String> paths = new ArrayList(Arrays.asList(PATHS));
 
         File apexDirectory = new File(APEX_DIR);
diff --git a/tools/aconfig/aconfig_flags/Android.bp b/tools/aconfig/aconfig_flags/Android.bp
new file mode 100644
index 0000000..e327ced
--- /dev/null
+++ b/tools/aconfig/aconfig_flags/Android.bp
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+rust_library {
+    name: "libaconfig_flags",
+    crate_name: "aconfig_flags",
+    srcs: [
+        "src/lib.rs",
+    ],
+    rustlibs: [
+        "libaconfig_flags_rust",
+    ],
+    host_supported: true,
+}
+
+aconfig_declarations {
+    name: "aconfig_flags",
+    package: "com.android.aconfig.flags",
+    container: "system",
+    srcs: ["flags.aconfig"],
+}
+
+rust_aconfig_library {
+    name: "libaconfig_flags_rust",
+    crate_name: "aconfig_flags_rust",
+    aconfig_declarations: "aconfig_flags",
+    host_supported: true,
+}
+
+cc_aconfig_library {
+    name: "libaconfig_flags_cc",
+    aconfig_declarations: "aconfig_flags",
+}
diff --git a/tools/aconfig/aconfig_flags/Cargo.toml b/tools/aconfig/aconfig_flags/Cargo.toml
new file mode 100644
index 0000000..6eb9f14
--- /dev/null
+++ b/tools/aconfig/aconfig_flags/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "aconfig_flags"
+version = "0.1.0"
+edition = "2021"
+
+[features]
+default = ["cargo"]
+cargo = []
+
+[dependencies]
\ No newline at end of file
diff --git a/tools/aconfig/aconfig_flags/flags.aconfig b/tools/aconfig/aconfig_flags/flags.aconfig
new file mode 100644
index 0000000..db8b1b7
--- /dev/null
+++ b/tools/aconfig/aconfig_flags/flags.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.aconfig.flags"
+container: "system"
+
+flag {
+  name: "enable_only_new_storage"
+  namespace: "core_experiments_team_internal"
+  bug: "312235596"
+  description: "When enabled, aconfig flags are read from the new aconfig storage only."
+}
diff --git a/tools/aconfig/aconfig_flags/src/lib.rs b/tools/aconfig/aconfig_flags/src/lib.rs
new file mode 100644
index 0000000..a607efb
--- /dev/null
+++ b/tools/aconfig/aconfig_flags/src/lib.rs
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+//! `aconfig_flags` is a crate for reading aconfig flags from Rust
+// When building with the Android tool-chain
+//
+//   - the flag functions will read from aconfig_flags_inner
+//   - the feature "cargo" will be disabled
+//
+// When building with cargo
+//
+//   - the flag functions will all return some trivial value, like true
+//   - the feature "cargo" will be enabled
+//
+// This module hides these differences from the rest of aconfig.
+
+/// Module used when building with the Android tool-chain
+#[cfg(not(feature = "cargo"))]
+pub mod auto_generated {
+    /// Returns the value for the enable_only_new_storage flag.
+    pub fn enable_only_new_storage() -> bool {
+        aconfig_flags_rust::enable_only_new_storage()
+    }
+}
+
+/// Module used when building with cargo
+#[cfg(feature = "cargo")]
+pub mod auto_generated {
+    /// Returns a placeholder value for the enable_only_new_storage flag.
+    pub fn enable_only_new_storage() -> bool {
+        // Used only to enable typechecking and testing with cargo
+        true
+    }
+}
diff --git a/tools/aconfig/aconfig_storage_file/Android.bp b/tools/aconfig/aconfig_storage_file/Android.bp
index 40b4464..e875c7b 100644
--- a/tools/aconfig/aconfig_storage_file/Android.bp
+++ b/tools/aconfig/aconfig_storage_file/Android.bp
@@ -14,6 +14,7 @@
         "libclap",
         "libcxx",
         "libaconfig_storage_protos",
+        "libserde",
     ],
 }
 
@@ -36,7 +37,10 @@
     name: "aconfig-storage",
     defaults: ["aconfig_storage_file.defaults"],
     srcs: ["src/main.rs"],
-    rustlibs: ["libaconfig_storage_file"],
+    rustlibs: [
+        "libaconfig_storage_file",
+        "libserde_json",
+    ],
 }
 
 rust_test_host {
diff --git a/tools/aconfig/aconfig_storage_file/Cargo.toml b/tools/aconfig/aconfig_storage_file/Cargo.toml
index 192dfad..a405578 100644
--- a/tools/aconfig/aconfig_storage_file/Cargo.toml
+++ b/tools/aconfig/aconfig_storage_file/Cargo.toml
@@ -14,6 +14,8 @@
 thiserror = "1.0.56"
 clap = { version = "4.1.8", features = ["derive"] }
 cxx = "1.0"
+serde = { version = "1.0.152", features = ["derive"] }
+serde_json = "1.0.93"
 
 [[bin]]
 name = "aconfig-storage"
diff --git a/tools/aconfig/aconfig_storage_file/src/flag_info.rs b/tools/aconfig/aconfig_storage_file/src/flag_info.rs
index beac38d..a49756d 100644
--- a/tools/aconfig/aconfig_storage_file/src/flag_info.rs
+++ b/tools/aconfig/aconfig_storage_file/src/flag_info.rs
@@ -20,10 +20,11 @@
 use crate::{read_str_from_bytes, read_u32_from_bytes, read_u8_from_bytes};
 use crate::{AconfigStorageError, StorageFileType};
 use anyhow::anyhow;
+use serde::{Deserialize, Serialize};
 use std::fmt;
 
 /// Flag info header struct
-#[derive(PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize)]
 pub struct FlagInfoHeader {
     pub version: u32,
     pub container: String,
@@ -89,7 +90,7 @@
 }
 
 /// bit field for flag info
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
 pub enum FlagInfoBit {
     HasServerOverride = 1 << 0,
     IsReadWrite = 1 << 1,
@@ -97,7 +98,7 @@
 }
 
 /// Flag info node struct
-#[derive(PartialEq, Clone)]
+#[derive(PartialEq, Clone, Serialize, Deserialize)]
 pub struct FlagInfoNode {
     pub attributes: u8,
 }
@@ -138,7 +139,7 @@
 }
 
 /// Flag info list struct
-#[derive(PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize)]
 pub struct FlagInfoList {
     pub header: FlagInfoHeader,
     pub nodes: Vec<FlagInfoNode>,
@@ -226,7 +227,7 @@
         let bytes = &flag_info_list.into_bytes();
         let mut head = 0;
         let version = read_u32_from_bytes(bytes, &mut head).unwrap();
-        assert_eq!(version, 1);
+        assert_eq!(version, 2);
     }
 
     #[test]
diff --git a/tools/aconfig/aconfig_storage_file/src/flag_table.rs b/tools/aconfig/aconfig_storage_file/src/flag_table.rs
index 660edac..be82c63 100644
--- a/tools/aconfig/aconfig_storage_file/src/flag_table.rs
+++ b/tools/aconfig/aconfig_storage_file/src/flag_table.rs
@@ -23,10 +23,11 @@
 };
 use crate::{AconfigStorageError, StorageFileType, StoredFlagType};
 use anyhow::anyhow;
+use serde::{Deserialize, Serialize};
 use std::fmt;
 
 /// Flag table header struct
-#[derive(PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize)]
 pub struct FlagTableHeader {
     pub version: u32,
     pub container: String,
@@ -95,7 +96,7 @@
 }
 
 /// Flag table node struct
-#[derive(PartialEq, Clone)]
+#[derive(PartialEq, Clone, Serialize, Deserialize)]
 pub struct FlagTableNode {
     pub package_id: u32,
     pub flag_name: String,
@@ -154,7 +155,7 @@
     }
 }
 
-#[derive(PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize)]
 pub struct FlagTable {
     pub header: FlagTableHeader,
     pub buckets: Vec<Option<u32>>,
@@ -252,7 +253,7 @@
         let bytes = &flag_table.into_bytes();
         let mut head = 0;
         let version = read_u32_from_bytes(bytes, &mut head).unwrap();
-        assert_eq!(version, 1);
+        assert_eq!(version, 2);
     }
 
     #[test]
diff --git a/tools/aconfig/aconfig_storage_file/src/flag_value.rs b/tools/aconfig/aconfig_storage_file/src/flag_value.rs
index 506924b..c4cf294 100644
--- a/tools/aconfig/aconfig_storage_file/src/flag_value.rs
+++ b/tools/aconfig/aconfig_storage_file/src/flag_value.rs
@@ -20,10 +20,11 @@
 use crate::{read_str_from_bytes, read_u32_from_bytes, read_u8_from_bytes};
 use crate::{AconfigStorageError, StorageFileType};
 use anyhow::anyhow;
+use serde::{Deserialize, Serialize};
 use std::fmt;
 
 /// Flag value header struct
-#[derive(PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize)]
 pub struct FlagValueHeader {
     pub version: u32,
     pub container: String,
@@ -89,7 +90,7 @@
 }
 
 /// Flag value list struct
-#[derive(PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize)]
 pub struct FlagValueList {
     pub header: FlagValueHeader,
     pub booleans: Vec<bool>,
@@ -158,7 +159,7 @@
         let bytes = &flag_value_list.into_bytes();
         let mut head = 0;
         let version = read_u32_from_bytes(bytes, &mut head).unwrap();
-        assert_eq!(version, 1);
+        assert_eq!(version, 2);
     }
 
     #[test]
diff --git a/tools/aconfig/aconfig_storage_file/src/lib.rs b/tools/aconfig/aconfig_storage_file/src/lib.rs
index b6367ff..19d0e51 100644
--- a/tools/aconfig/aconfig_storage_file/src/lib.rs
+++ b/tools/aconfig/aconfig_storage_file/src/lib.rs
@@ -41,6 +41,7 @@
 pub mod test_utils;
 
 use anyhow::anyhow;
+use serde::{Deserialize, Serialize};
 use std::cmp::Ordering;
 use std::fs::File;
 use std::hash::Hasher;
@@ -57,7 +58,7 @@
 };
 
 /// Storage file version
-pub const FILE_VERSION: u32 = 1;
+pub const FILE_VERSION: u32 = 2;
 
 /// Good hash table prime number
 pub(crate) const HASH_PRIMES: [u32; 29] = [
@@ -107,7 +108,7 @@
 
 /// Flag type enum as stored by storage file
 /// ONLY APPEND, NEVER REMOVE FOR BACKWARD COMPATIBILITY. THE MAX IS U16.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
 pub enum StoredFlagType {
     ReadWriteBoolean = 0,
     ReadOnlyBoolean = 1,
@@ -253,6 +254,16 @@
     Ok(val)
 }
 
+// Read and parse bytes as u64
+pub fn read_u64_from_bytes(buf: &[u8], head: &mut usize) -> Result<u64, AconfigStorageError> {
+    let val =
+        u64::from_le_bytes(buf[*head..*head + 8].try_into().map_err(|errmsg| {
+            BytesParseFail(anyhow!("fail to parse u64 from bytes: {}", errmsg))
+        })?);
+    *head += 8;
+    Ok(val)
+}
+
 /// Read and parse bytes as string
 pub(crate) fn read_str_from_bytes(
     buf: &[u8],
diff --git a/tools/aconfig/aconfig_storage_file/src/main.rs b/tools/aconfig/aconfig_storage_file/src/main.rs
index 8b9e38d..a9cfd19 100644
--- a/tools/aconfig/aconfig_storage_file/src/main.rs
+++ b/tools/aconfig/aconfig_storage_file/src/main.rs
@@ -20,9 +20,29 @@
     list_flags, list_flags_with_info, read_file_to_bytes, AconfigStorageError, FlagInfoList,
     FlagTable, FlagValueList, PackageTable, StorageFileType,
 };
-
 use clap::{builder::ArgAction, Arg, Command};
+use serde::Serialize;
+use serde_json;
+use std::fmt;
+use std::fs;
+use std::fs::File;
+use std::io::Write;
 
+/**
+ * Usage Examples
+ *
+ * Print file:
+ * $ aconfig-storage print --file=path/to/flag.map --type=flag_map
+ *
+ * List flags:
+ * $ aconfig-storage list --flag-map=path/to/flag.map \
+ * --flag-val=path/to/flag.val --package-map=path/to/package.map
+ *
+ * Write binary file for testing:
+ * $ aconfig-storage print --file=path/to/flag.map --type=flag_map --format=json > flag_map.json
+ * $ vim flag_map.json // Manually make updates
+ * $ aconfig-storage write-bytes --input-file=flag_map.json --output-file=path/to/flag.map --type=flag_map
+ */
 fn cli() -> Command {
     Command::new("aconfig-storage")
         .subcommand_required(true)
@@ -34,7 +54,8 @@
                         .long("type")
                         .required(true)
                         .value_parser(|s: &str| StorageFileType::try_from(s)),
-                ),
+                )
+                .arg(Arg::new("format").long("format").required(false).action(ArgAction::Set)),
         )
         .subcommand(
             Command::new("list")
@@ -50,41 +71,75 @@
                     Arg::new("flag-info").long("flag-info").required(false).action(ArgAction::Set),
                 ),
         )
+        .subcommand(
+            Command::new("write-bytes")
+                // Where to write the output bytes. Suggest to use the StorageFileType names (e.g. flag.map).
+                .arg(
+                    Arg::new("output-file")
+                        .long("output-file")
+                        .required(true)
+                        .action(ArgAction::Set),
+                )
+                // Input file should be json.
+                .arg(
+                    Arg::new("input-file").long("input-file").required(true).action(ArgAction::Set),
+                )
+                .arg(
+                    Arg::new("type")
+                        .long("type")
+                        .required(true)
+                        .value_parser(|s: &str| StorageFileType::try_from(s)),
+                ),
+        )
 }
 
 fn print_storage_file(
     file_path: &str,
     file_type: &StorageFileType,
+    as_json: bool,
 ) -> Result<(), AconfigStorageError> {
     let bytes = read_file_to_bytes(file_path)?;
     match file_type {
         StorageFileType::PackageMap => {
             let package_table = PackageTable::from_bytes(&bytes)?;
-            println!("{:?}", package_table);
+            println!("{}", to_print_format(package_table, as_json));
         }
         StorageFileType::FlagMap => {
             let flag_table = FlagTable::from_bytes(&bytes)?;
-            println!("{:?}", flag_table);
+            println!("{}", to_print_format(flag_table, as_json));
         }
         StorageFileType::FlagVal => {
             let flag_value = FlagValueList::from_bytes(&bytes)?;
-            println!("{:?}", flag_value);
+            println!("{}", to_print_format(flag_value, as_json));
         }
         StorageFileType::FlagInfo => {
             let flag_info = FlagInfoList::from_bytes(&bytes)?;
-            println!("{:?}", flag_info);
+            println!("{}", to_print_format(flag_info, as_json));
         }
     }
     Ok(())
 }
 
+fn to_print_format<T>(file_contents: T, as_json: bool) -> String
+where
+    T: Serialize + fmt::Debug,
+{
+    if as_json {
+        serde_json::to_string(&file_contents).unwrap()
+    } else {
+        format!("{:?}", file_contents)
+    }
+}
+
 fn main() -> Result<(), AconfigStorageError> {
     let matches = cli().get_matches();
     match matches.subcommand() {
         Some(("print", sub_matches)) => {
             let file_path = sub_matches.get_one::<String>("file").unwrap();
             let file_type = sub_matches.get_one::<StorageFileType>("type").unwrap();
-            print_storage_file(file_path, file_type)?
+            let format = sub_matches.get_one::<String>("format");
+            let as_json: bool = format == Some(&"json".to_string());
+            print_storage_file(file_path, file_type, as_json)?
         }
         Some(("list", sub_matches)) => {
             let package_map = sub_matches.get_one::<String>("package-map").unwrap();
@@ -96,10 +151,10 @@
                     let flags = list_flags_with_info(package_map, flag_map, flag_val, info_file)?;
                     for flag in flags.iter() {
                         println!(
-                            "{} {} {} {:?} IsReadWrite: {}, HasServerOverride: {}, HasLocalOverride: {}",
-                            flag.package_name, flag.flag_name, flag.flag_value, flag.value_type,
-                            flag.is_readwrite, flag.has_server_override, flag.has_local_override,
-                        );
+                          "{} {} {} {:?} IsReadWrite: {}, HasServerOverride: {}, HasLocalOverride: {}",
+                          flag.package_name, flag.flag_name, flag.flag_value, flag.value_type,
+                          flag.is_readwrite, flag.has_server_override, flag.has_local_override,
+                      );
                     }
                 }
                 None => {
@@ -113,6 +168,40 @@
                 }
             }
         }
+        // Converts JSON of the file into raw bytes (as is used on-device).
+        // Intended to generate/easily update these files for testing.
+        Some(("write-bytes", sub_matches)) => {
+            let input_file_path = sub_matches.get_one::<String>("input-file").unwrap();
+            let input_json = fs::read_to_string(input_file_path).unwrap();
+
+            let file_type = sub_matches.get_one::<StorageFileType>("type").unwrap();
+            let output_bytes: Vec<u8>;
+            match file_type {
+                StorageFileType::FlagVal => {
+                    let list: FlagValueList = serde_json::from_str(&input_json).unwrap();
+                    output_bytes = list.into_bytes();
+                }
+                StorageFileType::FlagInfo => {
+                    let list: FlagInfoList = serde_json::from_str(&input_json).unwrap();
+                    output_bytes = list.into_bytes();
+                }
+                StorageFileType::FlagMap => {
+                    let table: FlagTable = serde_json::from_str(&input_json).unwrap();
+                    output_bytes = table.into_bytes();
+                }
+                StorageFileType::PackageMap => {
+                    let table: PackageTable = serde_json::from_str(&input_json).unwrap();
+                    output_bytes = table.into_bytes();
+                }
+            }
+
+            let output_file_path = sub_matches.get_one::<String>("output-file").unwrap();
+            let file = File::create(output_file_path);
+            if file.is_err() {
+                panic!("can't make file");
+            }
+            let _ = file.unwrap().write_all(&output_bytes);
+        }
         _ => unreachable!(),
     }
     Ok(())
diff --git a/tools/aconfig/aconfig_storage_file/src/package_table.rs b/tools/aconfig/aconfig_storage_file/src/package_table.rs
index 007f86e..350f072 100644
--- a/tools/aconfig/aconfig_storage_file/src/package_table.rs
+++ b/tools/aconfig/aconfig_storage_file/src/package_table.rs
@@ -17,13 +17,17 @@
 //! package table module defines the package table file format and methods for serialization
 //! and deserialization
 
-use crate::{get_bucket_index, read_str_from_bytes, read_u32_from_bytes, read_u8_from_bytes};
+use crate::{
+    get_bucket_index, read_str_from_bytes, read_u32_from_bytes, read_u64_from_bytes,
+    read_u8_from_bytes,
+};
 use crate::{AconfigStorageError, StorageFileType};
 use anyhow::anyhow;
+use serde::{Deserialize, Serialize};
 use std::fmt;
 
 /// Package table header struct
-#[derive(PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize)]
 pub struct PackageTableHeader {
     pub version: u32,
     pub container: String,
@@ -92,10 +96,11 @@
 }
 
 /// Package table node struct
-#[derive(PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize)]
 pub struct PackageTableNode {
     pub package_name: String,
     pub package_id: u32,
+    pub fingerprint: u64,
     // The index of the first boolean flag in this aconfig package among all boolean
     // flags in this container.
     pub boolean_start_index: u32,
@@ -107,8 +112,12 @@
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         writeln!(
             f,
-            "Package: {}, Id: {}, Boolean flag start index: {}, Next: {:?}",
-            self.package_name, self.package_id, self.boolean_start_index, self.next_offset
+            "Package: {}, Id: {}, Fingerprint: {}, Boolean flag start index: {}, Next: {:?}",
+            self.package_name,
+            self.package_id,
+            self.fingerprint,
+            self.boolean_start_index,
+            self.next_offset
         )?;
         Ok(())
     }
@@ -122,6 +131,7 @@
         result.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes());
         result.extend_from_slice(name_bytes);
         result.extend_from_slice(&self.package_id.to_le_bytes());
+        result.extend_from_slice(&self.fingerprint.to_le_bytes());
         result.extend_from_slice(&self.boolean_start_index.to_le_bytes());
         result.extend_from_slice(&self.next_offset.unwrap_or(0).to_le_bytes());
         result
@@ -133,6 +143,7 @@
         let node = Self {
             package_name: read_str_from_bytes(bytes, &mut head)?,
             package_id: read_u32_from_bytes(bytes, &mut head)?,
+            fingerprint: read_u64_from_bytes(bytes, &mut head)?,
             boolean_start_index: read_u32_from_bytes(bytes, &mut head)?,
             next_offset: match read_u32_from_bytes(bytes, &mut head)? {
                 0 => None,
@@ -151,7 +162,7 @@
 }
 
 /// Package table struct
-#[derive(PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize)]
 pub struct PackageTable {
     pub header: PackageTableHeader,
     pub buckets: Vec<Option<u32>>,
@@ -250,7 +261,7 @@
         let bytes = &package_table.into_bytes();
         let mut head = 0;
         let version = read_u32_from_bytes(bytes, &mut head).unwrap();
-        assert_eq!(version, 1);
+        assert_eq!(version, 2);
     }
 
     #[test]
diff --git a/tools/aconfig/aconfig_storage_file/src/test_utils.rs b/tools/aconfig/aconfig_storage_file/src/test_utils.rs
index 106666c..11e2dc6 100644
--- a/tools/aconfig/aconfig_storage_file/src/test_utils.rs
+++ b/tools/aconfig/aconfig_storage_file/src/test_utils.rs
@@ -26,30 +26,33 @@
 
 pub fn create_test_package_table() -> PackageTable {
     let header = PackageTableHeader {
-        version: 1,
+        version: 2,
         container: String::from("mockup"),
         file_type: StorageFileType::PackageMap as u8,
-        file_size: 209,
+        file_size: 233,
         num_packages: 3,
         bucket_offset: 31,
         node_offset: 59,
     };
-    let buckets: Vec<Option<u32>> = vec![Some(59), None, None, Some(109), None, None, None];
+    let buckets: Vec<Option<u32>> = vec![Some(59), None, None, Some(117), None, None, None];
     let first_node = PackageTableNode {
         package_name: String::from("com.android.aconfig.storage.test_2"),
         package_id: 1,
+        fingerprint: 0,
         boolean_start_index: 3,
         next_offset: None,
     };
     let second_node = PackageTableNode {
         package_name: String::from("com.android.aconfig.storage.test_1"),
         package_id: 0,
+        fingerprint: 0,
         boolean_start_index: 0,
-        next_offset: Some(159),
+        next_offset: Some(175),
     };
     let third_node = PackageTableNode {
         package_name: String::from("com.android.aconfig.storage.test_4"),
         package_id: 2,
+        fingerprint: 0,
         boolean_start_index: 6,
         next_offset: None,
     };
@@ -78,7 +81,7 @@
 
 pub fn create_test_flag_table() -> FlagTable {
     let header = FlagTableHeader {
-        version: 1,
+        version: 2,
         container: String::from("mockup"),
         file_type: StorageFileType::FlagMap as u8,
         file_size: 321,
@@ -120,7 +123,7 @@
 
 pub fn create_test_flag_value_list() -> FlagValueList {
     let header = FlagValueHeader {
-        version: 1,
+        version: 2,
         container: String::from("mockup"),
         file_type: StorageFileType::FlagVal as u8,
         file_size: 35,
@@ -133,7 +136,7 @@
 
 pub fn create_test_flag_info_list() -> FlagInfoList {
     let header = FlagInfoHeader {
-        version: 1,
+        version: 2,
         container: String::from("mockup"),
         file_type: StorageFileType::FlagInfo as u8,
         file_size: 35,
diff --git a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/ByteBufferReader.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/ByteBufferReader.java
index 4bea083..44a82ee 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/ByteBufferReader.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/ByteBufferReader.java
@@ -37,6 +37,10 @@
         return Short.toUnsignedInt(mByteBuffer.getShort());
     }
 
+    public long readLong() {
+        return mByteBuffer.getLong();
+    }
+
     public int readInt() {
         return this.mByteBuffer.getInt();
     }
diff --git a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/PackageTable.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/PackageTable.java
index 773b882..f1288f5 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/PackageTable.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/PackageTable.java
@@ -118,6 +118,7 @@
 
         private String mPackageName;
         private int mPackageId;
+        private long mFingerprint;
         private int mBooleanStartIndex;
         private int mNextOffset;
 
@@ -125,6 +126,7 @@
             Node node = new Node();
             node.mPackageName = reader.readString();
             node.mPackageId = reader.readInt();
+            node.mFingerprint = reader.readLong();
             node.mBooleanStartIndex = reader.readInt();
             node.mNextOffset = reader.readInt();
             node.mNextOffset = node.mNextOffset == 0 ? -1 : node.mNextOffset;
@@ -150,6 +152,7 @@
             return Objects.equals(mPackageName, other.mPackageName)
                     && mPackageId == other.mPackageId
                     && mBooleanStartIndex == other.mBooleanStartIndex
+                    && mFingerprint == other.mFingerprint
                     && mNextOffset == other.mNextOffset;
         }
 
@@ -165,6 +168,10 @@
             return mBooleanStartIndex;
         }
 
+        public long getFingerprint() {
+            return mFingerprint;
+        }
+
         public int getNextOffset() {
             return mNextOffset;
         }
diff --git a/tools/aconfig/aconfig_storage_file/tests/flag.info b/tools/aconfig/aconfig_storage_file/tests/flag.info
index 6223edf..9db7fde 100644
--- a/tools/aconfig/aconfig_storage_file/tests/flag.info
+++ b/tools/aconfig/aconfig_storage_file/tests/flag.info
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_file/tests/flag.map b/tools/aconfig/aconfig_storage_file/tests/flag.map
index e868f53..cf4685c 100644
--- a/tools/aconfig/aconfig_storage_file/tests/flag.map
+++ b/tools/aconfig/aconfig_storage_file/tests/flag.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_file/tests/flag.val b/tools/aconfig/aconfig_storage_file/tests/flag.val
index ed203d4..37d4750 100644
--- a/tools/aconfig/aconfig_storage_file/tests/flag.val
+++ b/tools/aconfig/aconfig_storage_file/tests/flag.val
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_file/tests/package.map b/tools/aconfig/aconfig_storage_file/tests/package.map
index 6c46a03..358010c 100644
--- a/tools/aconfig/aconfig_storage_file/tests/package.map
+++ b/tools/aconfig/aconfig_storage_file/tests/package.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_file/tests/srcs/FlagTableTest.java b/tools/aconfig/aconfig_storage_file/tests/srcs/FlagTableTest.java
index fd40d4c..e3b02cd 100644
--- a/tools/aconfig/aconfig_storage_file/tests/srcs/FlagTableTest.java
+++ b/tools/aconfig/aconfig_storage_file/tests/srcs/FlagTableTest.java
@@ -33,7 +33,7 @@
     public void testFlagTable_rightHeader() throws Exception {
         FlagTable flagTable = FlagTable.fromBytes(TestDataUtils.getTestFlagMapByteBuffer());
         FlagTable.Header header = flagTable.getHeader();
-        assertEquals(1, header.getVersion());
+        assertEquals(2, header.getVersion());
         assertEquals("mockup", header.getContainer());
         assertEquals(FileType.FLAG_MAP, header.getFileType());
         assertEquals(321, header.getFileSize());
diff --git a/tools/aconfig/aconfig_storage_file/tests/srcs/FlagValueListTest.java b/tools/aconfig/aconfig_storage_file/tests/srcs/FlagValueListTest.java
index 1b0de63..ebc231c 100644
--- a/tools/aconfig/aconfig_storage_file/tests/srcs/FlagValueListTest.java
+++ b/tools/aconfig/aconfig_storage_file/tests/srcs/FlagValueListTest.java
@@ -36,7 +36,7 @@
         FlagValueList flagValueList =
                 FlagValueList.fromBytes(TestDataUtils.getTestFlagValByteBuffer());
         FlagValueList.Header header = flagValueList.getHeader();
-        assertEquals(1, header.getVersion());
+        assertEquals(2, header.getVersion());
         assertEquals("mockup", header.getContainer());
         assertEquals(FileType.FLAG_VAL, header.getFileType());
         assertEquals(35, header.getFileSize());
diff --git a/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java b/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
index e7e19d8..6d56cee 100644
--- a/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
+++ b/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
@@ -20,7 +20,6 @@
 
 import android.aconfig.storage.FileType;
 import android.aconfig.storage.PackageTable;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -28,42 +27,40 @@
 @RunWith(JUnit4.class)
 public class PackageTableTest {
 
-    @Test
-    public void testPackageTable_rightHeader() throws Exception {
-        PackageTable packageTable =
-                PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer());
-        PackageTable.Header header = packageTable.getHeader();
-        assertEquals(1, header.getVersion());
-        assertEquals("mockup", header.getContainer());
-        assertEquals(FileType.PACKAGE_MAP, header.getFileType());
-        assertEquals(209, header.getFileSize());
-        assertEquals(3, header.getNumPackages());
-        assertEquals(31, header.getBucketOffset());
-        assertEquals(59, header.getNodeOffset());
-    }
+  @Test
+  public void testPackageTable_rightHeader() throws Exception {
+    PackageTable packageTable = PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer());
+    PackageTable.Header header = packageTable.getHeader();
+    assertEquals(2, header.getVersion());
+    assertEquals("mockup", header.getContainer());
+    assertEquals(FileType.PACKAGE_MAP, header.getFileType());
+    assertEquals(209, header.getFileSize());
+    assertEquals(3, header.getNumPackages());
+    assertEquals(31, header.getBucketOffset());
+    assertEquals(59, header.getNodeOffset());
+  }
 
-    @Test
-    public void testPackageTable_rightNode() throws Exception {
-        PackageTable packageTable =
-                PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer());
+  @Test
+  public void testPackageTable_rightNode() throws Exception {
+    PackageTable packageTable = PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer());
 
-        PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
-        PackageTable.Node node2 = packageTable.get("com.android.aconfig.storage.test_2");
-        PackageTable.Node node4 = packageTable.get("com.android.aconfig.storage.test_4");
+    PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
+    PackageTable.Node node2 = packageTable.get("com.android.aconfig.storage.test_2");
+    PackageTable.Node node4 = packageTable.get("com.android.aconfig.storage.test_4");
 
-        assertEquals("com.android.aconfig.storage.test_1", node1.getPackageName());
-        assertEquals("com.android.aconfig.storage.test_2", node2.getPackageName());
-        assertEquals("com.android.aconfig.storage.test_4", node4.getPackageName());
+    assertEquals("com.android.aconfig.storage.test_1", node1.getPackageName());
+    assertEquals("com.android.aconfig.storage.test_2", node2.getPackageName());
+    assertEquals("com.android.aconfig.storage.test_4", node4.getPackageName());
 
-        assertEquals(0, node1.getPackageId());
-        assertEquals(1, node2.getPackageId());
-        assertEquals(2, node4.getPackageId());
+    assertEquals(0, node1.getPackageId());
+    assertEquals(1, node2.getPackageId());
+    assertEquals(2, node4.getPackageId());
 
-        assertEquals(0, node1.getBooleanStartIndex());
-        assertEquals(3, node2.getBooleanStartIndex());
-        assertEquals(6, node4.getBooleanStartIndex());
+    assertEquals(0, node1.getBooleanStartIndex());
+    assertEquals(3, node2.getBooleanStartIndex());
+    assertEquals(6, node4.getBooleanStartIndex());
 
-        assertEquals(159, node1.getNextOffset());
+        assertEquals(175, node1.getNextOffset());
         assertEquals(-1, node2.getNextOffset());
         assertEquals(-1, node4.getNextOffset());
     }
diff --git a/tools/aconfig/aconfig_storage_read_api/src/lib.rs b/tools/aconfig/aconfig_storage_read_api/src/lib.rs
index d76cf3f..59aa749 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/lib.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/lib.rs
@@ -507,9 +507,9 @@
     #[test]
     // this test point locks down flag storage file version number query api
     fn test_storage_version_query() {
-        assert_eq!(get_storage_file_version("./tests/package.map").unwrap(), 1);
-        assert_eq!(get_storage_file_version("./tests/flag.map").unwrap(), 1);
-        assert_eq!(get_storage_file_version("./tests/flag.val").unwrap(), 1);
-        assert_eq!(get_storage_file_version("./tests/flag.info").unwrap(), 1);
+        assert_eq!(get_storage_file_version("./tests/package.map").unwrap(), 2);
+        assert_eq!(get_storage_file_version("./tests/flag.map").unwrap(), 2);
+        assert_eq!(get_storage_file_version("./tests/flag.val").unwrap(), 2);
+        assert_eq!(get_storage_file_version("./tests/flag.info").unwrap(), 2);
     }
 }
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/flag.info b/tools/aconfig/aconfig_storage_read_api/tests/flag.info
index 6223edf..9db7fde 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/flag.info
+++ b/tools/aconfig/aconfig_storage_read_api/tests/flag.info
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/flag.map b/tools/aconfig/aconfig_storage_read_api/tests/flag.map
index e868f53..cf4685c 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/flag.map
+++ b/tools/aconfig/aconfig_storage_read_api/tests/flag.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/flag.val b/tools/aconfig/aconfig_storage_read_api/tests/flag.val
index ed203d4..37d4750 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/flag.val
+++ b/tools/aconfig/aconfig_storage_read_api/tests/flag.val
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/package.map b/tools/aconfig/aconfig_storage_read_api/tests/package.map
index 6c46a03..358010c 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/package.map
+++ b/tools/aconfig/aconfig_storage_read_api/tests/package.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp
index 6d29045..58460d1 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp
+++ b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp
@@ -80,16 +80,16 @@
 TEST_F(AconfigStorageTest, test_storage_version_query) {
   auto version = api::get_storage_file_version(package_map);
   ASSERT_TRUE(version.ok());
-  ASSERT_EQ(*version, 1);
+  ASSERT_EQ(*version, 2);
   version = api::get_storage_file_version(flag_map);
   ASSERT_TRUE(version.ok());
-  ASSERT_EQ(*version, 1);
+  ASSERT_EQ(*version, 2);
   version = api::get_storage_file_version(flag_val);
   ASSERT_TRUE(version.ok());
-  ASSERT_EQ(*version, 1);
+  ASSERT_EQ(*version, 2);
   version = api::get_storage_file_version(flag_info);
   ASSERT_TRUE(version.ok());
-  ASSERT_EQ(*version, 1);
+  ASSERT_EQ(*version, 2);
 }
 
 /// Negative test to lock down the error when mapping none exist storage files
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs
index afc44d4..bd1b584 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs
+++ b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs
@@ -200,9 +200,9 @@
 
     #[test]
     fn test_storage_version_query() {
-        assert_eq!(get_storage_file_version("./package.map").unwrap(), 1);
-        assert_eq!(get_storage_file_version("./flag.map").unwrap(), 1);
-        assert_eq!(get_storage_file_version("./flag.val").unwrap(), 1);
-        assert_eq!(get_storage_file_version("./flag.info").unwrap(), 1);
+        assert_eq!(get_storage_file_version("./package.map").unwrap(), 2);
+        assert_eq!(get_storage_file_version("./flag.map").unwrap(), 2);
+        assert_eq!(get_storage_file_version("./flag.val").unwrap(), 2);
+        assert_eq!(get_storage_file_version("./flag.info").unwrap(), 2);
     }
 }
diff --git a/tools/aconfig/aflags/Android.bp b/tools/aconfig/aflags/Android.bp
index c48585a..2040cc6 100644
--- a/tools/aconfig/aflags/Android.bp
+++ b/tools/aconfig/aflags/Android.bp
@@ -10,6 +10,7 @@
     srcs: ["src/main.rs"],
     rustlibs: [
         "libaconfig_device_paths",
+        "libaconfig_flags",
         "libaconfig_protos",
         "libaconfigd_protos",
         "libaconfig_storage_read_api",
@@ -24,6 +25,7 @@
 
 rust_binary {
     name: "aflags",
+    host_supported: true,
     defaults: ["aflags.defaults"],
 }
 
diff --git a/tools/aconfig/aflags/Cargo.toml b/tools/aconfig/aflags/Cargo.toml
index 7dc3436..7efce6d 100644
--- a/tools/aconfig/aflags/Cargo.toml
+++ b/tools/aconfig/aflags/Cargo.toml
@@ -15,3 +15,4 @@
 aconfig_storage_read_api = { version = "0.1.0", path = "../aconfig_storage_read_api" }
 clap = {version = "4.5.2" }
 aconfig_device_paths = { version = "0.1.0", path = "../aconfig_device_paths" }
+aconfig_flags = { version = "0.1.0", path = "../aconfig_flags" }
\ No newline at end of file
diff --git a/tools/aconfig/aflags/src/aconfig_storage_source.rs b/tools/aconfig/aflags/src/aconfig_storage_source.rs
index b2fd3c9..68edf7d 100644
--- a/tools/aconfig/aflags/src/aconfig_storage_source.rs
+++ b/tools/aconfig/aflags/src/aconfig_storage_source.rs
@@ -1,3 +1,4 @@
+use crate::load_protos;
 use crate::{Flag, FlagSource};
 use crate::{FlagPermission, FlagValue, ValuePickedFrom};
 use aconfigd_protos::{
@@ -9,13 +10,18 @@
 use anyhow::Result;
 use protobuf::Message;
 use protobuf::SpecialFields;
+use std::collections::HashMap;
 use std::io::{Read, Write};
 use std::net::Shutdown;
 use std::os::unix::net::UnixStream;
 
 pub struct AconfigStorageSource {}
 
-fn convert(msg: ProtoFlagQueryReturnMessage) -> Result<Flag> {
+fn load_flag_to_container() -> Result<HashMap<String, String>> {
+    Ok(load_protos::load()?.into_iter().map(|p| (p.qualified_name(), p.container)).collect())
+}
+
+fn convert(msg: ProtoFlagQueryReturnMessage, containers: &HashMap<String, String>) -> Result<Flag> {
     let (value, value_picked_from) = match (
         &msg.boot_flag_value,
         msg.default_flag_value,
@@ -55,15 +61,21 @@
         None => return Err(anyhow!("missing permission")),
     };
 
+    let name = msg.flag_name.ok_or(anyhow!("missing flag name"))?;
+    let package = msg.package_name.ok_or(anyhow!("missing package name"))?;
+    let qualified_name = format!("{package}.{name}");
     Ok(Flag {
-        name: msg.flag_name.ok_or(anyhow!("missing flag name"))?,
-        package: msg.package_name.ok_or(anyhow!("missing package name"))?,
+        name,
+        package,
         value,
         permission,
         value_picked_from,
         staged_value,
-        container: "-".to_string(),
-
+        container: containers
+            .get(&qualified_name)
+            .cloned()
+            .unwrap_or_else(|| "<no container>".to_string())
+            .to_string(),
         // TODO: remove once DeviceConfig is not in the CLI.
         namespace: "-".to_string(),
     })
@@ -114,9 +126,13 @@
 
 impl FlagSource for AconfigStorageSource {
     fn list_flags() -> Result<Vec<Flag>> {
+        let containers = load_flag_to_container()?;
         read_from_socket()
             .map(|query_messages| {
-                query_messages.iter().map(|message| convert(message.clone())).collect::<Vec<_>>()
+                query_messages
+                    .iter()
+                    .map(|message| convert(message.clone(), &containers))
+                    .collect::<Vec<_>>()
             })?
             .into_iter()
             .collect()
diff --git a/tools/aconfig/aflags/src/main.rs b/tools/aconfig/aflags/src/main.rs
index d8912a9..07b7243 100644
--- a/tools/aconfig/aflags/src/main.rs
+++ b/tools/aconfig/aflags/src/main.rs
@@ -116,9 +116,10 @@
     }
 
     fn display_staged_value(&self) -> String {
-        match self.staged_value {
-            Some(v) => format!("(->{})", v),
-            None => "-".to_string(),
+        match (&self.permission, self.staged_value) {
+            (FlagPermission::ReadOnly, _) => "-".to_string(),
+            (FlagPermission::ReadWrite, None) => "-".to_string(),
+            (FlagPermission::ReadWrite, Some(v)) => format!("(->{})", v),
         }
     }
 }
@@ -164,10 +165,6 @@
 enum Command {
     /// List all aconfig flags on this device.
     List {
-        /// Read from the new flag storage.
-        #[clap(long)]
-        use_new_storage: bool,
-
         /// Optionally filter by container name.
         #[clap(short = 'c', long = "container")]
         container: Option<String>,
@@ -184,6 +181,9 @@
         /// <package>.<flag_name>
         qualified_name: String,
     },
+
+    /// Display which flag storage backs aconfig flags.
+    WhichBacking,
 }
 
 struct PaddingInfo {
@@ -282,21 +282,31 @@
     Ok(result)
 }
 
+fn display_which_backing() -> String {
+    if aconfig_flags::auto_generated::enable_only_new_storage() {
+        "aconfig_storage".to_string()
+    } else {
+        "device_config".to_string()
+    }
+}
+
 fn main() -> Result<()> {
     ensure!(nix::unistd::Uid::current().is_root(), "must be root");
 
     let cli = Cli::parse();
     let output = match cli.command {
-        Command::List { use_new_storage: true, container } => {
-            list(FlagSourceType::AconfigStorage, container)
-                .map_err(|err| anyhow!("storage may not be enabled: {err}"))
-                .map(Some)
-        }
-        Command::List { use_new_storage: false, container } => {
-            list(FlagSourceType::DeviceConfig, container).map(Some)
+        Command::List { container } => {
+            if aconfig_flags::auto_generated::enable_only_new_storage() {
+                list(FlagSourceType::AconfigStorage, container)
+                    .map_err(|err| anyhow!("storage may not be enabled: {err}"))
+                    .map(Some)
+            } else {
+                list(FlagSourceType::DeviceConfig, container).map(Some)
+            }
         }
         Command::Enable { qualified_name } => set_flag(&qualified_name, "true").map(|_| None),
         Command::Disable { qualified_name } => set_flag(&qualified_name, "false").map(|_| None),
+        Command::WhichBacking => Ok(Some(display_which_backing())),
     };
     match output {
         Ok(Some(text)) => println!("{text}"),
diff --git a/tools/aconfig/fake_device_config/src/android/util/Log.java b/tools/aconfig/fake_device_config/src/android/util/Log.java
index 3e7fd0f..79de680 100644
--- a/tools/aconfig/fake_device_config/src/android/util/Log.java
+++ b/tools/aconfig/fake_device_config/src/android/util/Log.java
@@ -5,6 +5,10 @@
         return 0;
     }
 
+    public static int w(String tag, String msg) {
+        return 0;
+    }
+
     public static int e(String tag, String msg) {
         return 0;
     }
diff --git a/tools/edit_monitor/Android.bp b/tools/edit_monitor/Android.bp
new file mode 100644
index 0000000..80437c0
--- /dev/null
+++ b/tools/edit_monitor/Android.bp
@@ -0,0 +1,21 @@
+// Copyright 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.
+
+// Set of error prone rules to ensure code quality
+// PackageLocation check requires the androidCompatible=false otherwise it does not do anything.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+    default_team: "trendy_team_adte",
+}
diff --git a/tools/edit_monitor/OWNERS b/tools/edit_monitor/OWNERS
new file mode 100644
index 0000000..8f0f364
--- /dev/null
+++ b/tools/edit_monitor/OWNERS
@@ -0,0 +1 @@
+include platform/tools/asuite:/OWNERS_ADTE_TEAM
\ No newline at end of file
diff --git a/tools/filelistdiff/allowlist b/tools/filelistdiff/allowlist
index c4a464d..120045e 100644
--- a/tools/filelistdiff/allowlist
+++ b/tools/filelistdiff/allowlist
@@ -43,7 +43,9 @@
 etc/aconfig/package.map
 etc/bpf/uprobestats/BitmapAllocation.o
 etc/bpf/uprobestats/GenericInstrumentation.o
+etc/bpf/uprobestats/ProcessManagement.o
 etc/init/UprobeStats.rc
 lib/libuprobestats_client.so
 lib64/libuprobestats_client.so
-priv-app/DeviceDiagnostics/DeviceDiagnostics.apk
\ No newline at end of file
+priv-app/DeviceDiagnostics/DeviceDiagnostics.apk
+
diff --git a/tools/releasetools/ota_from_raw_img.py b/tools/releasetools/ota_from_raw_img.py
index 03b44f1..3b9374a 100644
--- a/tools/releasetools/ota_from_raw_img.py
+++ b/tools/releasetools/ota_from_raw_img.py
@@ -105,9 +105,6 @@
 
     if args.package_key:
       logger.info("Signing payload...")
-      # TODO: remove OPTIONS when no longer used as fallback in payload_signer
-      common.OPTIONS.payload_signer_args = None
-      common.OPTIONS.payload_signer_maximum_signature_size = None
       signer = PayloadSigner(args.package_key, args.private_key_suffix,
                              key_passwords[args.package_key],
                              payload_signer=args.payload_signer,
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 985cd56..6446e1f 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -264,6 +264,10 @@
 
   --compression_factor
       Specify the maximum block size to be compressed at once during OTA. supported options: 4k, 8k, 16k, 32k, 64k, 128k, 256k
+
+  --full_ota_partitions
+      Specify list of partitions should be updated in full OTA fashion, even if
+      an incremental OTA is about to be generated
 """
 
 from __future__ import print_function
@@ -283,7 +287,7 @@
 import ota_utils
 import payload_signer
 from ota_utils import (VABC_COMPRESSION_PARAM_SUPPORT, FinalizeMetadata, GetPackageMetadata,
-                       PayloadGenerator, SECURITY_PATCH_LEVEL_PROP_NAME, ExtractTargetFiles, CopyTargetFilesDir)
+                       PayloadGenerator, SECURITY_PATCH_LEVEL_PROP_NAME, ExtractTargetFiles, CopyTargetFilesDir, TARGET_FILES_IMAGES_SUBDIR)
 from common import DoesInputFileContain, IsSparseImage
 import target_files_diff
 from non_ab_ota import GenerateNonAbOtaPackage
@@ -337,6 +341,7 @@
 OPTIONS.max_threads = None
 OPTIONS.vabc_cow_version = None
 OPTIONS.compression_factor = None
+OPTIONS.full_ota_partitions = None
 
 
 POSTINSTALL_CONFIG = 'META/postinstall_config.txt'
@@ -892,6 +897,14 @@
 
   if source_file is not None:
     source_file = ExtractTargetFiles(source_file)
+    if OPTIONS.full_ota_partitions:
+      for partition in OPTIONS.full_ota_partitions:
+        for subdir in TARGET_FILES_IMAGES_SUBDIR:
+          image_path = os.path.join(source_file, subdir, partition + ".img")
+          if os.path.exists(image_path):
+            logger.info(
+                "Ignoring source image %s for partition %s because it is configured to use full OTA", image_path, partition)
+            os.remove(image_path)
     assert "ab_partitions" in OPTIONS.source_info_dict, \
         "META/ab_partitions.txt is required for ab_update."
     assert "ab_partitions" in OPTIONS.target_info_dict, \
@@ -1193,7 +1206,7 @@
 
 def main(argv):
 
-  def option_handler(o, a):
+  def option_handler(o, a: str):
     if o in ("-i", "--incremental_from"):
       OPTIONS.incremental_source = a
     elif o == "--full_radio":
@@ -1320,6 +1333,9 @@
       else:
         raise ValueError("Cannot parse value %r for option %r - only "
                          "integers are allowed." % (a, o))
+    elif o == "--full_ota_partitions":
+      OPTIONS.full_ota_partitions = set(
+          a.strip().strip("\"").strip("'").split(","))
     else:
       return False
     return True
@@ -1370,6 +1386,7 @@
                                  "max_threads=",
                                  "vabc_cow_version=",
                                  "compression_factor=",
+                                 "full_ota_partitions=",
                              ], extra_option_handler=[option_handler, payload_signer.signer_options])
   common.InitLogging()
 
diff --git a/tools/releasetools/sign_target_files_apks.py b/tools/releasetools/sign_target_files_apks.py
index a72342f..4ad97e0 100755
--- a/tools/releasetools/sign_target_files_apks.py
+++ b/tools/releasetools/sign_target_files_apks.py
@@ -184,6 +184,7 @@
 import shutil
 import stat
 import sys
+import shlex
 import tempfile
 import zipfile
 from xml.etree import ElementTree
@@ -582,6 +583,24 @@
         filename.endswith("/prop.default")
 
 
+def GetOtaSigningArgs():
+  args = []
+  if OPTIONS.package_key:
+    args.extend(["--package_key", OPTIONS.package_key])
+  if OPTIONS.payload_signer:
+    args.extend(["--payload_signer=" + OPTIONS.payload_signer])
+  if OPTIONS.payload_signer_args:
+    args.extend(["--payload_signer_args=" + shlex.join(OPTIONS.payload_signer_args)])
+  if OPTIONS.search_path:
+    args.extend(["--search_path", OPTIONS.search_path])
+  if OPTIONS.payload_signer_maximum_signature_size:
+    args.extend(["--payload_signer_maximum_signature_size",
+                OPTIONS.payload_signer_maximum_signature_size])
+  if OPTIONS.private_key_suffix:
+    args.extend(["--private_key_suffix", OPTIONS.private_key_suffix])
+  return args
+
+
 def RegenerateKernelPartitions(input_tf_zip: zipfile.ZipFile, output_tf_zip: zipfile.ZipFile, misc_info):
   """Re-generate boot and dtbo partitions using new signing configuration"""
   files_to_unzip = [
@@ -648,9 +667,9 @@
       if os.path.exists(signed_16k_dtbo_image):
         signed_dtbo_image += ":" + signed_16k_dtbo_image
 
-
-  args = ["ota_from_raw_img", "--package_key", OPTIONS.package_key,
+  args = ["ota_from_raw_img",
           "--max_timestamp", timestamp, "--output", input_ota.name]
+  args.extend(GetOtaSigningArgs())
   if "dtbo" in partitions:
     args.extend(["--partition_name", "boot,dtbo",
                 signed_boot_image, signed_dtbo_image])