Merge "Full ota v3 compatibilty check" into main
diff --git a/ci/build_test_suites.py b/ci/build_test_suites.py
index 23e896d..1d5b377 100644
--- a/ci/build_test_suites.py
+++ b/ci/build_test_suites.py
@@ -57,7 +57,6 @@
   argparser.add_argument(
       '--with_dexpreopt_boot_img_and_system_server_only', action='store_true'
   )
-  argparser.add_argument('--dist_dir')
   argparser.add_argument('--change_info', nargs='?')
 
   return argparser.parse_args()
@@ -92,16 +91,17 @@
 
   run_command(build_command, print_output=True)
 
-  zip_build_outputs(modules_to_build, args.dist_dir, args.target_release)
+  zip_build_outputs(modules_to_build, args.target_release)
 
 
-def base_build_command(args: argparse.Namespace, extra_targets: set[str]) -> list:
+def base_build_command(
+    args: argparse.Namespace, extra_targets: set[str]
+) -> list:
   build_command = []
   build_command.append('time')
   build_command.append('./build/soong/soong_ui.bash')
   build_command.append('--make-mode')
   build_command.append('dist')
-  build_command.append('DIST_DIR=' + args.dist_dir)
   build_command.append('TARGET_PRODUCT=' + args.target_product)
   build_command.append('TARGET_RELEASE=' + args.target_release)
   if args.with_dexpreopt_boot_img_and_system_server_only:
@@ -220,7 +220,7 @@
 
 
 def zip_build_outputs(
-    modules_to_build: set[str], dist_dir: str, target_release: str
+    modules_to_build: set[str], target_release: str
 ):
   src_top = os.environ.get('TOP', os.getcwd())
 
@@ -236,6 +236,7 @@
   product_out = pathlib.Path(get_soong_var('PRODUCT_OUT', target_release))
   soong_host_out = pathlib.Path(get_soong_var('SOONG_HOST_OUT', target_release))
   host_out = pathlib.Path(get_soong_var('HOST_OUT', target_release))
+  dist_dir = pathlib.Path(get_soong_var('DIST_DIR', target_release))
 
   # Call the class to package the outputs.
   # TODO(lucafarsi): Move this code into a replaceable class.
diff --git a/core/board_config.mk b/core/board_config.mk
index 25e0643..633303f 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -973,15 +973,6 @@
   $(if $(wildcard $(vndk_path)/*/Android.bp),,$(error VNDK version $(1) not found))
 endef
 
-ifeq ($(KEEP_VNDK),true)
-ifeq ($(BOARD_VNDK_VERSION),$(PLATFORM_VNDK_VERSION))
-  $(error BOARD_VNDK_VERSION is equal to PLATFORM_VNDK_VERSION; use BOARD_VNDK_VERSION := current)
-endif
-ifneq ($(BOARD_VNDK_VERSION),current)
-  $(call check_vndk_version,$(BOARD_VNDK_VERSION))
-endif
-endif
-
 TARGET_VENDOR_TEST_SUFFIX := /vendor
 
 ifeq (,$(TARGET_BUILD_UNBUNDLED))
@@ -1001,7 +992,7 @@
 # BOARD_API_LEVEL for vendor API surface
 ifdef RELEASE_BOARD_API_LEVEL
   ifdef BOARD_API_LEVEL
-    $(error BOARD_API_LEVEL must not set manully. The build system automatically sets this value.)
+    $(error BOARD_API_LEVEL must not be set manually. The build system automatically sets this value.)
   endif
   BOARD_API_LEVEL := $(RELEASE_BOARD_API_LEVEL)
   .KATI_READONLY := BOARD_API_LEVEL
diff --git a/core/config.mk b/core/config.mk
index c5df45c..daefa70 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -419,16 +419,10 @@
 endif
 .KATI_READONLY := TARGET_MAX_PAGE_SIZE_SUPPORTED
 
-# Boolean variable determining if AOSP is page size agnostic. This means
-# that AOSP can use a kernel configured with 4k/16k/64k PAGE SIZES.
+# Boolean variable determining if AOSP relies on bionic's PAGE_SIZE macro.
 TARGET_NO_BIONIC_PAGE_SIZE_MACRO := false
 ifdef PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO
   TARGET_NO_BIONIC_PAGE_SIZE_MACRO := $(PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO)
-  ifeq ($(TARGET_NO_BIONIC_PAGE_SIZE_MACRO),true)
-      ifeq (,$(filter 16384 65536,$(TARGET_MAX_PAGE_SIZE_SUPPORTED)))
-          $(error TARGET_MAX_PAGE_SIZE_SUPPORTED has to be either 16384 or 65536 to support page size agnostic)
-      endif
-  endif
 endif
 .KATI_READONLY := TARGET_NO_BIONIC_PAGE_SIZE_MACRO
 
diff --git a/core/envsetup.mk b/core/envsetup.mk
index 30a6c06..7f9cbad 100644
--- a/core/envsetup.mk
+++ b/core/envsetup.mk
@@ -789,6 +789,7 @@
 TARGET_OUT_ODM_APPS := $(target_out_odm_app_base)/app
 TARGET_OUT_ODM_APPS_PRIVILEGED := $(target_out_odm_app_base)/priv-app
 TARGET_OUT_ODM_ETC := $(TARGET_OUT_ODM)/etc
+TARGET_OUT_ODM_FAKE := $(PRODUCT_OUT)/odm_fake_packages
 .KATI_READONLY := \
   TARGET_OUT_ODM \
   TARGET_OUT_ODM_EXECUTABLES \
@@ -798,7 +799,8 @@
   TARGET_OUT_ODM_JAVA_LIBRARIES \
   TARGET_OUT_ODM_APPS \
   TARGET_OUT_ODM_APPS_PRIVILEGED \
-  TARGET_OUT_ODM_ETC
+  TARGET_OUT_ODM_ETC \
+  TARGET_OUT_ODM_FAKE
 
 $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_ODM_EXECUTABLES := $(TARGET_OUT_ODM_EXECUTABLES)
 $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_ODM_SHARED_LIBRARIES := $(target_out_odm_shared_libraries_base)/lib
@@ -936,13 +938,15 @@
 TARGET_OUT_PRODUCT_APPS := $(target_out_product_app_base)/app
 TARGET_OUT_PRODUCT_APPS_PRIVILEGED := $(target_out_product_app_base)/priv-app
 TARGET_OUT_PRODUCT_ETC := $(TARGET_OUT_PRODUCT)/etc
+TARGET_OUT_PRODUCT_FAKE := $(TARGET_OUT_PRODUCT)/product_fake_packages
 .KATI_READONLY := \
   TARGET_OUT_PRODUCT_EXECUTABLES \
   TARGET_OUT_PRODUCT_SHARED_LIBRARIES \
   TARGET_OUT_PRODUCT_JAVA_LIBRARIES \
   TARGET_OUT_PRODUCT_APPS \
   TARGET_OUT_PRODUCT_APPS_PRIVILEGED \
-  TARGET_OUT_PRODUCT_ETC
+  TARGET_OUT_PRODUCT_ETC \
+  TARGET_OUT_PRODUCT_FAKE
 
 $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_PRODUCT_EXECUTABLES := $(TARGET_OUT_PRODUCT_EXECUTABLES)
 $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_PRODUCT_SHARED_LIBRARIES := $(target_out_product_shared_libraries_base)/lib
@@ -979,13 +983,15 @@
 TARGET_OUT_SYSTEM_EXT_APPS_PRIVILEGED := $(target_out_system_ext_app_base)/priv-app
 TARGET_OUT_SYSTEM_EXT_ETC := $(TARGET_OUT_SYSTEM_EXT)/etc
 TARGET_OUT_SYSTEM_EXT_EXECUTABLES := $(TARGET_OUT_SYSTEM_EXT)/bin
+TARGET_OUT_SYSTEM_EXT_FAKE := $(PRODUCT_OUT)/system_ext_fake_packages
 .KATI_READONLY := \
   TARGET_OUT_SYSTEM_EXT_EXECUTABLES \
   TARGET_OUT_SYSTEM_EXT_SHARED_LIBRARIES \
   TARGET_OUT_SYSTEM_EXT_JAVA_LIBRARIES \
   TARGET_OUT_SYSTEM_EXT_APPS \
   TARGET_OUT_SYSTEM_EXT_APPS_PRIVILEGED \
-  TARGET_OUT_SYSTEM_EXT_ETC
+  TARGET_OUT_SYSTEM_EXT_ETC \
+  TARGET_OUT_SYSTEM_EXT_FAKE
 
 $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_SYSTEM_EXT_EXECUTABLES := $(TARGET_OUT_SYSTEM_EXT_EXECUTABLES)
 $(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_SYSTEM_EXT_SHARED_LIBRARIES := $(target_out_system_ext_shared_libraries_base)/lib
diff --git a/core/main.mk b/core/main.mk
index c1cafc0..bc8adde 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -221,20 +221,6 @@
 # mount system_other partition.
 ADDITIONAL_SYSTEM_PROPERTIES += ro.postinstall.fstab.prefix=/system
 
-# -----------------------------------------------------------------
-# ADDITIONAL_VENDOR_PROPERTIES will be installed in vendor/build.prop if
-# property_overrides_split_enabled is true. Otherwise it will be installed in
-# /system/build.prop
-ifeq ($(KEEP_VNDK),true)
-ifdef BOARD_VNDK_VERSION
-  ifeq ($(BOARD_VNDK_VERSION),current)
-    ADDITIONAL_VENDOR_PROPERTIES := ro.vndk.version=$(PLATFORM_VNDK_VERSION)
-  else
-    ADDITIONAL_VENDOR_PROPERTIES := ro.vndk.version=$(BOARD_VNDK_VERSION)
-  endif
-endif
-endif
-
 # Add cpu properties for bionic and ART.
 ADDITIONAL_VENDOR_PROPERTIES += ro.bionic.arch=$(TARGET_ARCH)
 ADDITIONAL_VENDOR_PROPERTIES += ro.bionic.cpu_variant=$(TARGET_CPU_VARIANT_RUNTIME)
@@ -346,18 +332,6 @@
     ro.build.ab_update=$(AB_OTA_UPDATER)
 endif
 
-# Set ro.product.vndk.version to PLATFORM_VNDK_VERSION only if
-# KEEP_VNDK is true, PRODUCT_PRODUCT_VNDK_VERSION is current and
-# PLATFORM_VNDK_VERSION is less than or equal to 35.
-# ro.product.vndk.version must be removed for the other future builds.
-ifeq ($(KEEP_VNDK)|$(PRODUCT_PRODUCT_VNDK_VERSION),true|current)
-ifeq ($(call math_is_number,$(PLATFORM_VNDK_VERSION)),true)
-ifeq ($(call math_lt_or_eq,$(PLATFORM_VNDK_VERSION),35),true)
-ADDITIONAL_PRODUCT_PROPERTIES += ro.product.vndk.version=$(PLATFORM_VNDK_VERSION)
-endif
-endif
-endif
-
 ADDITIONAL_PRODUCT_PROPERTIES += ro.build.characteristics=$(TARGET_AAPT_CHARACTERISTICS)
 
 ifeq ($(AB_OTA_UPDATER),true)
@@ -1859,12 +1833,12 @@
     $(INSTALLED_FILES_JSON_SYSTEMOTHER) \
     $(INSTALLED_FILES_FILE_RECOVERY) \
     $(INSTALLED_FILES_JSON_RECOVERY) \
-    $(INSTALLED_BUILD_PROP_TARGET):build.prop \
-    $(INSTALLED_VENDOR_BUILD_PROP_TARGET):build.prop-vendor \
-    $(INSTALLED_PRODUCT_BUILD_PROP_TARGET):build.prop-product \
-    $(INSTALLED_ODM_BUILD_PROP_TARGET):build.prop-odm \
-    $(INSTALLED_SYSTEM_EXT_BUILD_PROP_TARGET):build.prop-system_ext \
-    $(INSTALLED_RAMDISK_BUILD_PROP_TARGET):build.prop-ramdisk \
+    $(if $(BUILDING_SYSTEM_IMAGE), $(INSTALLED_BUILD_PROP_TARGET):build.prop) \
+    $(if $(BUILDING_VENDOR_IMAGE), $(INSTALLED_VENDOR_BUILD_PROP_TARGET):build.prop-vendor) \
+    $(if $(BUILDING_PRODUCT_IMAGE), $(INSTALLED_PRODUCT_BUILD_PROP_TARGET):build.prop-product) \
+    $(if $(BUILDING_ODM_IMAGE), $(INSTALLED_ODM_BUILD_PROP_TARGET):build.prop-odm) \
+    $(if $(BUILDING_SYSTEM_EXT_IMAGE), $(INSTALLED_SYSTEM_EXT_BUILD_PROP_TARGET):build.prop-system_ext) \
+    $(if $(BUILDING_RAMDISK_IMAGE), $(INSTALLED_RAMDISK_BUILD_PROP_TARGET):build.prop-ramdisk) \
     $(INSTALLED_ANDROID_INFO_TXT_TARGET) \
     $(INSTALLED_MISC_INFO_TARGET) \
     $(INSTALLED_RAMDISK_TARGET) \
diff --git a/core/product.mk b/core/product.mk
index d64dde2..01b5ead 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -33,8 +33,7 @@
 # 4096, 16384 and 65536.
 _product_single_value_vars += PRODUCT_MAX_PAGE_SIZE_SUPPORTED
 
-# Indicates that AOSP can use a kernel configured with 4k/16k/64k page sizes.
-# The possible values are true or false.
+# Boolean variable determining if AOSP relies on bionic's PAGE_SIZE macro.
 _product_single_value_vars += PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO
 
 # The resource configuration options to use for this product.
diff --git a/core/release_config.mk b/core/release_config.mk
index a7b5b3f..3e51af5 100644
--- a/core/release_config.mk
+++ b/core/release_config.mk
@@ -41,8 +41,7 @@
 # which has OWNERS control.  If it isn't let others define their own.
 # TODO: Remove wildcard for build/release one when all branch manifests
 # have updated.
-config_map_files := $(wildcard build/trunk_release/release_config_map.mk) \
-    $(wildcard build/release/release_config_map.mk) \
+config_map_files := $(wildcard build/release/release_config_map.mk) \
     $(wildcard vendor/google_shared/build/release/release_config_map.mk) \
     $(if $(wildcard vendor/google/release/release_config_map.mk), \
         vendor/google/release/release_config_map.mk, \
diff --git a/core/release_config.scl b/core/release_config.scl
index 728fc1b..c5815df 100644
--- a/core/release_config.scl
+++ b/core/release_config.scl
@@ -179,18 +179,23 @@
     validate(all_flags, _all_flags_schema)
     validate(all_values, _all_values_schema)
 
+    # Final values.
+    values = {}
     # Validate flags
     flag_names = []
     flags_dict = {}
     for flag in all_flags:
-        if flag["name"] in flag_names:
-            if equal_flag_declaration(flag, flags_dict[flag["name"]]):
+        name = flag["name"]
+        if name in flag_names:
+            if equal_flag_declaration(flag, flags_dict[name]):
                 continue
             else:
-                fail(flag["declared_in"] + ": Duplicate declaration of flag " + flag["name"] +
-                     " (declared first in " + flags_dict[flag["name"]]["declared_in"] + ")")
-        flag_names.append(flag["name"])
-        flags_dict[flag["name"]] = flag
+                fail(flag["declared_in"] + ": Duplicate declaration of flag " + name +
+                     " (declared first in " + flags_dict[name]["declared_in"] + ")")
+        flag_names.append(name)
+        flags_dict[name] = flag
+        # Set the flag value to the default value.
+        values[name] = {"name": name, "value": _format_value(flag["default"]), "set_in": flag["declared_in"]}
 
     # Record which flags go on which partition
     partitions = {}
@@ -206,7 +211,6 @@
 
     # Generate final values.
     # Only declared flags may have a value.
-    values = {}
     for value in all_values:
         name = value["name"]
         if name not in flag_names:
@@ -227,19 +231,13 @@
     for partition, names in partitions.items():
         result["_ALL_RELEASE_FLAGS.PARTITIONS." + partition] = names
     for flag in all_flags:
-        if flag["name"] in values:
-            val = values[flag["name"]]["value"]
-            set_in = values[flag["name"]]["set_in"]
-        else:
-            val = flag["default"]
-            set_in = flag["declared_in"]
-        val = _format_value(val)
+        val = _format_value(values[flag["name"]]["value"])
         result[flag["name"]] = val
         result["_ALL_RELEASE_FLAGS." + flag["name"] + ".PARTITIONS"] = flag["partitions"]
         result["_ALL_RELEASE_FLAGS." + flag["name"] + ".DEFAULT"] = _format_value(flag["default"])
         result["_ALL_RELEASE_FLAGS." + flag["name"] + ".VALUE"] = val
         result["_ALL_RELEASE_FLAGS." + flag["name"] + ".DECLARED_IN"] = flag["declared_in"]
-        result["_ALL_RELEASE_FLAGS." + flag["name"] + ".SET_IN"] = set_in
+        result["_ALL_RELEASE_FLAGS." + flag["name"] + ".SET_IN"] = values[flag["name"]]["set_in"]
         result["_ALL_RELEASE_FLAGS." + flag["name"] + ".ORIGIN"] = flag["origin"]
 
     return result
diff --git a/core/soong_cc_rust_prebuilt.mk b/core/soong_cc_rust_prebuilt.mk
index 943ed30..a1c6478 100644
--- a/core/soong_cc_rust_prebuilt.mk
+++ b/core/soong_cc_rust_prebuilt.mk
@@ -38,14 +38,6 @@
   endif
 endif
 
-# Don't install modules of current VNDK when it is told so
-ifeq ($(TARGET_SKIP_CURRENT_VNDK),true)
-  ifeq ($(LOCAL_SOONG_VNDK_VERSION),$(PLATFORM_VNDK_VERSION))
-    LOCAL_UNINSTALLABLE_MODULE := true
-  endif
-endif
-
-
 # Use the Soong output as the checkbuild target instead of LOCAL_BUILT_MODULE
 # to avoid checkbuilds making an extra copy of every module.
 LOCAL_CHECKED_MODULE := $(LOCAL_PREBUILT_MODULE_FILE)
diff --git a/core/tasks/tools/vts_package_utils.mk b/core/tasks/tools/vts_package_utils.mk
index 06161f0..1a819f2 100644
--- a/core/tasks/tools/vts_package_utils.mk
+++ b/core/tasks/tools/vts_package_utils.mk
@@ -21,7 +21,7 @@
 $(foreach m,$(1),\
   $(eval _built_files := $(strip $(ALL_MODULES.$(m).BUILT_INSTALLED)\
   $(ALL_MODULES.$(m)$(TARGET_2ND_ARCH_MODULE_SUFFIX).BUILT_INSTALLED)))\
-  $(foreach i, $(_built_files),\
+  $(foreach i, $(sort $(_built_files)),\
     $(eval bui_ins := $(subst :,$(space),$(i)))\
     $(eval ins := $(word 2,$(bui_ins)))\
     $(if $(filter $(TARGET_OUT_ROOT)/%,$(ins)),\
diff --git a/core/tasks/vndk.mk b/core/tasks/vndk.mk
deleted file mode 100644
index ebe9bd4..0000000
--- a/core/tasks/vndk.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (C) 2017 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.
-
-current_makefile := $(lastword $(MAKEFILE_LIST))
-
-# BOARD_VNDK_VERSION must be set to 'current' in order to generate a VNDK snapshot.
-ifeq ($(BOARD_VNDK_VERSION),current)
-
-# PLATFORM_VNDK_VERSION must be set.
-ifneq (,$(PLATFORM_VNDK_VERSION))
-
-.PHONY: vndk
-vndk: $(SOONG_VNDK_SNAPSHOT_ZIP)
-
-$(call dist-for-goals, vndk, $(SOONG_VNDK_SNAPSHOT_ZIP))
-
-else # PLATFORM_VNDK_VERSION is NOT set
-error_msg := "CANNOT generate VNDK snapshot. PLATFORM_VNDK_VERSION must be set."
-endif # PLATFORM_VNDK_VERSION
-
-else # BOARD_VNDK_VERSION is NOT set to 'current'
-error_msg := "CANNOT generate VNDK snapshot. BOARD_VNDK_VERSION must be set to 'current'."
-endif # BOARD_VNDK_VERSION
-
-ifneq (,$(error_msg))
-
-.PHONY: vndk
-vndk: PRIVATE_MAKEFILE := $(current_makefile)
-vndk:
-	$(call echo-error,$(PRIVATE_MAKEFILE),$(error_msg))
-	exit 1
-
-endif
diff --git a/core/version_util.mk b/core/version_util.mk
index 6cda0fc..610cdaf 100644
--- a/core/version_util.mk
+++ b/core/version_util.mk
@@ -28,7 +28,6 @@
 #     BUILD_ID
 #     BUILD_NUMBER
 #     PLATFORM_SECURITY_PATCH
-#     PLATFORM_VNDK_VERSION
 #     PLATFORM_SYSTEMSDK_VERSIONS
 #     PLATFORM_VERSION_LAST_STABLE
 #     PLATFORM_VERSION_KNOWN_CODENAMES
@@ -151,24 +150,6 @@
 endif
 .KATI_READONLY := DEFAULT_APP_TARGET_SDK
 
-ifeq ($(KEEP_VNDK),true)
-  ifndef PLATFORM_VNDK_VERSION
-    # This is the definition of the VNDK version for the current VNDK libraries.
-    # With trunk stable, VNDK will not be frozen but deprecated.
-    # This version will be removed with the VNDK deprecation.
-    ifeq (REL,$(PLATFORM_VERSION_CODENAME))
-      ifdef RELEASE_PLATFORM_VNDK_VERSION
-        PLATFORM_VNDK_VERSION := $(RELEASE_PLATFORM_VNDK_VERSION)
-      else
-        PLATFORM_VNDK_VERSION := $(PLATFORM_SDK_VERSION)
-      endif
-    else
-      PLATFORM_VNDK_VERSION := $(PLATFORM_VERSION_CODENAME)
-    endif
-  endif
-  .KATI_READONLY := PLATFORM_VNDK_VERSION
-endif
-
 ifndef PLATFORM_SYSTEMSDK_MIN_VERSION
   # This is the oldest version of system SDK that the platform supports. Contrary
   # to the public SDK where platform essentially supports all previous SDK versions,
diff --git a/target/product/gsi/Android.mk b/target/product/gsi/Android.mk
index c8ace36..3bb65ac 100644
--- a/target/product/gsi/Android.mk
+++ b/target/product/gsi/Android.mk
@@ -5,23 +5,6 @@
 INTERNAL_VNDK_LIB_LIST := $(SOONG_VNDK_LIBRARIES_FILE)
 
 #####################################################################
-# This is the up-to-date list of vndk libs.
-LATEST_VNDK_LIB_LIST := $(LOCAL_PATH)/current.txt
-ifeq ($(KEEP_VNDK),true)
-UNFROZEN_VNDK := true
-ifeq (REL,$(PLATFORM_VERSION_CODENAME))
-    # Use frozen vndk lib list only if "34 >= PLATFORM_VNDK_VERSION"
-    ifeq ($(call math_gt_or_eq,34,$(PLATFORM_VNDK_VERSION)),true)
-        LATEST_VNDK_LIB_LIST := $(LOCAL_PATH)/$(PLATFORM_VNDK_VERSION).txt
-        ifeq ($(wildcard $(LATEST_VNDK_LIB_LIST)),)
-            $(error $(LATEST_VNDK_LIB_LIST) file not found. Please copy "$(LOCAL_PATH)/current.txt" to "$(LATEST_VNDK_LIB_LIST)" and commit a CL for release branch)
-        endif
-        UNFROZEN_VNDK :=
-    endif
-endif
-endif
-
-#####################################################################
 # Check the generate list against the latest list stored in the
 # source tree
 .PHONY: check-vndk-list
@@ -159,11 +142,7 @@
 $(notdir $(call filter-abi-dump-paths,$(1),$(2)))
 endef
 
-ifdef RELEASE_BOARD_API_LEVEL
-    VNDK_ABI_DUMP_DIR := prebuilts/abi-dumps/vndk/$(RELEASE_BOARD_API_LEVEL)
-else
-    VNDK_ABI_DUMP_DIR := prebuilts/abi-dumps/vndk/$(PLATFORM_VNDK_VERSION)
-endif
+
 ifeq (REL,$(PLATFORM_VERSION_CODENAME))
     NDK_ABI_DUMP_DIR := prebuilts/abi-dumps/ndk/$(PLATFORM_SDK_VERSION)
     PLATFORM_ABI_DUMP_DIR := prebuilts/abi-dumps/platform/$(PLATFORM_SDK_VERSION)
@@ -171,7 +150,6 @@
     NDK_ABI_DUMP_DIR := prebuilts/abi-dumps/ndk/current
     PLATFORM_ABI_DUMP_DIR := prebuilts/abi-dumps/platform/current
 endif
-VNDK_ABI_DUMPS := $(call find-abi-dump-paths,$(VNDK_ABI_DUMP_DIR))
 NDK_ABI_DUMPS := $(call find-abi-dump-paths,$(NDK_ABI_DUMP_DIR))
 PLATFORM_ABI_DUMPS := $(call find-abi-dump-paths,$(PLATFORM_ABI_DUMP_DIR))
 
diff --git a/teams/Android.bp b/teams/Android.bp
index bae8e80..8f83e71 100644
--- a/teams/Android.bp
+++ b/teams/Android.bp
@@ -4364,3 +4364,10 @@
   // go/trendy/manage/engineers/4943966050844672
   trendy_team_id: "4943966050844672",
 }
+
+team {
+  name: "trendy_team_android_platform_performance_testing",
+
+  // go/trendy/manage/engineers/5810097836621824
+  trendy_team_id: "5810097836621824",
+}
diff --git a/tools/aconfig/TEST_MAPPING b/tools/aconfig/TEST_MAPPING
index 0ea8fea..7651dba 100644
--- a/tools/aconfig/TEST_MAPPING
+++ b/tools/aconfig/TEST_MAPPING
@@ -20,7 +20,7 @@
       // aconfig C++ integration tests (test mode auto-generated code)
       "name": "aconfig.test.cpp.test_mode"
     },
-    // TODO(327420679): Enable export mode for native flag library
+    // TODO(b/327420679): Enable export mode for native flag library
     // {
     //   // aconfig C++ integration tests (exported mode auto-generated code)
     //   "name": "aconfig.test.cpp.exported_mode"
@@ -33,7 +33,7 @@
       // aconfig Rust integration tests (test mode auto-generated code)
       "name": "aconfig.test_mode.test.rust"
     },
-    // TODO(327420679): Enable export mode for native flag library
+    // TODO(b/327420679): Enable export mode for native flag library
     // {
     //   // aconfig Rust integration tests (exported mode auto-generated code)
     //   "name": "aconfig.exported_mode.test.rust"
diff --git a/tools/aconfig/aconfig/src/commands.rs b/tools/aconfig/aconfig/src/commands.rs
index 98dde44..7736ce7 100644
--- a/tools/aconfig/aconfig/src/commands.rs
+++ b/tools/aconfig/aconfig/src/commands.rs
@@ -317,9 +317,7 @@
 }
 
 fn find_unique_package(parsed_flags: &[ProtoParsedFlag]) -> Option<&str> {
-    let Some(package) = parsed_flags.first().map(|pf| pf.package()) else {
-        return None;
-    };
+    let package = parsed_flags.first().map(|pf| pf.package())?;
     if parsed_flags.iter().any(|pf| pf.package() != package) {
         return None;
     }
@@ -327,9 +325,7 @@
 }
 
 fn find_unique_container(parsed_flags: &ProtoParsedFlags) -> Option<&str> {
-    let Some(container) = parsed_flags.parsed_flag.first().map(|pf| pf.container()) else {
-        return None;
-    };
+    let container = parsed_flags.parsed_flag.first().map(|pf| pf.container())?;
     if parsed_flags.parsed_flag.iter().any(|pf| pf.container() != container) {
         return None;
     }
diff --git a/tools/aconfig/aconfig/src/storage/flag_table.rs b/tools/aconfig/aconfig/src/storage/flag_table.rs
index b861c1f..401379b 100644
--- a/tools/aconfig/aconfig/src/storage/flag_table.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_table.rs
@@ -17,7 +17,7 @@
 use crate::commands::assign_flag_ids;
 use crate::storage::FlagPackage;
 use aconfig_storage_file::{
-    get_table_size, FlagTable, FlagTableHeader, FlagTableNode, FILE_VERSION, StorageFileType
+    get_table_size, FlagTable, FlagTableHeader, FlagTableNode, StorageFileType, FILE_VERSION,
 };
 use anyhow::{anyhow, Result};
 
@@ -95,10 +95,10 @@
         .concat();
 
     // initialize all header fields
-    header.bucket_offset = header.as_bytes().len() as u32;
+    header.bucket_offset = header.into_bytes().len() as u32;
     header.node_offset = header.bucket_offset + num_buckets * 4;
     header.file_size = header.node_offset
-        + node_wrappers.iter().map(|x| x.node.as_bytes().len()).sum::<usize>() as u32;
+        + node_wrappers.iter().map(|x| x.node.into_bytes().len()).sum::<usize>() as u32;
 
     // sort nodes by bucket index for efficiency
     node_wrappers.sort_by(|a, b| a.bucket_index.cmp(&b.bucket_index));
@@ -116,7 +116,7 @@
         if buckets[node_bucket_idx as usize].is_none() {
             buckets[node_bucket_idx as usize] = Some(offset);
         }
-        offset += node_wrappers[i].node.as_bytes().len() as u32;
+        offset += node_wrappers[i].node.into_bytes().len() as u32;
 
         if let Some(index) = next_node_bucket_idx {
             if index == node_bucket_idx {
diff --git a/tools/aconfig/aconfig/src/storage/flag_value.rs b/tools/aconfig/aconfig/src/storage/flag_value.rs
index e40bbc1..c5cf215 100644
--- a/tools/aconfig/aconfig/src/storage/flag_value.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_value.rs
@@ -17,7 +17,7 @@
 use crate::commands::assign_flag_ids;
 use crate::storage::FlagPackage;
 use aconfig_protos::ProtoFlagState;
-use aconfig_storage_file::{FlagValueHeader, FlagValueList, FILE_VERSION, StorageFileType};
+use aconfig_storage_file::{FlagValueHeader, FlagValueList, StorageFileType, FILE_VERSION};
 use anyhow::{anyhow, Result};
 
 fn new_header(container: &str, num_flags: u32) -> FlagValueHeader {
@@ -53,7 +53,7 @@
     }
 
     // initialize all header fields
-    list.header.boolean_value_offset = list.header.as_bytes().len() as u32;
+    list.header.boolean_value_offset = list.header.into_bytes().len() as u32;
     list.header.file_size = list.header.boolean_value_offset + num_flags;
 
     Ok(list)
diff --git a/tools/aconfig/aconfig/src/storage/mod.rs b/tools/aconfig/aconfig/src/storage/mod.rs
index c818d79..11f1a43 100644
--- a/tools/aconfig/aconfig/src/storage/mod.rs
+++ b/tools/aconfig/aconfig/src/storage/mod.rs
@@ -18,7 +18,7 @@
 pub mod flag_value;
 pub mod package_table;
 
-use anyhow::Result;
+use anyhow::{anyhow, Result};
 use std::collections::{HashMap, HashSet};
 
 use crate::storage::{
@@ -97,16 +97,17 @@
     match file {
         StorageFileType::PackageMap => {
             let package_table = create_package_table(container, &packages)?;
-            Ok(package_table.as_bytes())
+            Ok(package_table.into_bytes())
         }
         StorageFileType::FlagMap => {
             let flag_table = create_flag_table(container, &packages)?;
-            Ok(flag_table.as_bytes())
+            Ok(flag_table.into_bytes())
         }
         StorageFileType::FlagVal => {
             let flag_value = create_flag_value(container, &packages)?;
-            Ok(flag_value.as_bytes())
+            Ok(flag_value.into_bytes())
         }
+        _ => Err(anyhow!("aconfig does not support the creation of this storage file type")),
     }
 }
 
diff --git a/tools/aconfig/aconfig/src/storage/package_table.rs b/tools/aconfig/aconfig/src/storage/package_table.rs
index bc2da4d..4e3d987 100644
--- a/tools/aconfig/aconfig/src/storage/package_table.rs
+++ b/tools/aconfig/aconfig/src/storage/package_table.rs
@@ -17,7 +17,8 @@
 use anyhow::Result;
 
 use aconfig_storage_file::{
-    get_table_size, PackageTable, PackageTableHeader, PackageTableNode, FILE_VERSION, StorageFileType
+    get_table_size, PackageTable, PackageTableHeader, PackageTableNode, StorageFileType,
+    FILE_VERSION,
 };
 
 use crate::storage::FlagPackage;
@@ -65,10 +66,10 @@
         packages.iter().map(|pkg| PackageTableNodeWrapper::new(pkg, num_buckets)).collect();
 
     // initialize all header fields
-    header.bucket_offset = header.as_bytes().len() as u32;
+    header.bucket_offset = header.into_bytes().len() as u32;
     header.node_offset = header.bucket_offset + num_buckets * 4;
     header.file_size = header.node_offset
-        + node_wrappers.iter().map(|x| x.node.as_bytes().len()).sum::<usize>() as u32;
+        + node_wrappers.iter().map(|x| x.node.into_bytes().len()).sum::<usize>() as u32;
 
     // sort node_wrappers by bucket index for efficiency
     node_wrappers.sort_by(|a, b| a.bucket_index.cmp(&b.bucket_index));
@@ -86,7 +87,7 @@
         if buckets[node_bucket_idx as usize].is_none() {
             buckets[node_bucket_idx as usize] = Some(offset);
         }
-        offset += node_wrappers[i].node.as_bytes().len() as u32;
+        offset += node_wrappers[i].node.into_bytes().len() as u32;
 
         if let Some(index) = next_node_bucket_idx {
             if index == node_bucket_idx {
diff --git a/tools/aconfig/aconfig_storage_file/Android.bp b/tools/aconfig/aconfig_storage_file/Android.bp
index 2a606bf..b590312 100644
--- a/tools/aconfig/aconfig_storage_file/Android.bp
+++ b/tools/aconfig/aconfig_storage_file/Android.bp
@@ -22,6 +22,11 @@
     host_supported: true,
     defaults: ["aconfig_storage_file.defaults"],
     srcs: ["src/lib.rs"],
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+    min_sdk_version: "29",
 }
 
 rust_binary_host {
@@ -44,6 +49,11 @@
     crate_name: "aconfig_storage_protos",
     source_stem: "aconfig_storage_protos",
     host_supported: true,
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+    min_sdk_version: "29",
 }
 
 cc_library_static {
diff --git a/tools/aconfig/aconfig_storage_file/src/flag_info.rs b/tools/aconfig/aconfig_storage_file/src/flag_info.rs
new file mode 100644
index 0000000..c67e70e
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_file/src/flag_info.rs
@@ -0,0 +1,238 @@
+/*
+ * 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.
+ */
+
+//! flag info module defines the flag info file format and methods for serialization
+//! and deserialization
+
+use crate::{read_str_from_bytes, read_u32_from_bytes, read_u8_from_bytes};
+use crate::{AconfigStorageError, StorageFileType};
+use anyhow::anyhow;
+use std::fmt;
+
+/// Flag info header struct
+#[derive(PartialEq)]
+pub struct FlagInfoHeader {
+    pub version: u32,
+    pub container: String,
+    pub file_type: u8,
+    pub file_size: u32,
+    pub num_flags: u32,
+    pub boolean_flag_offset: u32,
+}
+
+/// Implement debug print trait for header
+impl fmt::Debug for FlagInfoHeader {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        writeln!(
+            f,
+            "Version: {}, Container: {}, File Type: {:?}, File Size: {}",
+            self.version,
+            self.container,
+            StorageFileType::try_from(self.file_type),
+            self.file_size
+        )?;
+        writeln!(
+            f,
+            "Num of Flags: {}, Boolean Flag Offset:{}",
+            self.num_flags, self.boolean_flag_offset
+        )?;
+        Ok(())
+    }
+}
+
+impl FlagInfoHeader {
+    /// Serialize to bytes
+    pub fn into_bytes(&self) -> Vec<u8> {
+        let mut result = Vec::new();
+        result.extend_from_slice(&self.version.to_le_bytes());
+        let container_bytes = self.container.as_bytes();
+        result.extend_from_slice(&(container_bytes.len() as u32).to_le_bytes());
+        result.extend_from_slice(container_bytes);
+        result.extend_from_slice(&self.file_type.to_le_bytes());
+        result.extend_from_slice(&self.file_size.to_le_bytes());
+        result.extend_from_slice(&self.num_flags.to_le_bytes());
+        result.extend_from_slice(&self.boolean_flag_offset.to_le_bytes());
+        result
+    }
+
+    /// Deserialize from bytes
+    pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
+        let mut head = 0;
+        let list = Self {
+            version: read_u32_from_bytes(bytes, &mut head)?,
+            container: read_str_from_bytes(bytes, &mut head)?,
+            file_type: read_u8_from_bytes(bytes, &mut head)?,
+            file_size: read_u32_from_bytes(bytes, &mut head)?,
+            num_flags: read_u32_from_bytes(bytes, &mut head)?,
+            boolean_flag_offset: read_u32_from_bytes(bytes, &mut head)?,
+        };
+        if list.file_type != StorageFileType::FlagInfo as u8 {
+            return Err(AconfigStorageError::BytesParseFail(anyhow!(
+                "binary file is not a flag info file"
+            )));
+        }
+        Ok(list)
+    }
+}
+
+/// bit field for flag info
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum FlagInfoBit {
+    IsSticky = 0,
+    IsReadWrite = 1,
+    HasOverride = 2,
+}
+
+/// Flag info node struct
+#[derive(PartialEq, Clone)]
+pub struct FlagInfoNode {
+    pub attributes: u8,
+}
+
+/// Implement debug print trait for node
+impl fmt::Debug for FlagInfoNode {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        writeln!(
+            f,
+            "sticky: {}, readwrite: {}, override: {}",
+            self.attributes & (FlagInfoBit::IsSticky as u8),
+            self.attributes & (FlagInfoBit::IsReadWrite as u8),
+            self.attributes & (FlagInfoBit::HasOverride as u8),
+        )?;
+        Ok(())
+    }
+}
+
+impl FlagInfoNode {
+    /// Serialize to bytes
+    pub fn into_bytes(&self) -> Vec<u8> {
+        let mut result = Vec::new();
+        result.extend_from_slice(&self.attributes.to_le_bytes());
+        result
+    }
+
+    /// Deserialize from bytes
+    pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
+        let mut head = 0;
+        let node = Self { attributes: read_u8_from_bytes(bytes, &mut head)? };
+        Ok(node)
+    }
+}
+
+/// Flag info list struct
+#[derive(PartialEq)]
+pub struct FlagInfoList {
+    pub header: FlagInfoHeader,
+    pub nodes: Vec<FlagInfoNode>,
+}
+
+/// Implement debug print trait for flag info list
+impl fmt::Debug for FlagInfoList {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        writeln!(f, "Header:")?;
+        write!(f, "{:?}", self.header)?;
+        writeln!(f, "Nodes:")?;
+        for node in self.nodes.iter() {
+            write!(f, "{:?}", node)?;
+        }
+        Ok(())
+    }
+}
+
+impl FlagInfoList {
+    /// Serialize to bytes
+    pub fn into_bytes(&self) -> Vec<u8> {
+        [
+            self.header.into_bytes(),
+            self.nodes.iter().map(|v| v.into_bytes()).collect::<Vec<_>>().concat(),
+        ]
+        .concat()
+    }
+
+    /// Deserialize from bytes
+    pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
+        let header = FlagInfoHeader::from_bytes(bytes)?;
+        let num_flags = header.num_flags;
+        let mut head = header.into_bytes().len();
+        let nodes = (0..num_flags)
+            .map(|_| {
+                let node = FlagInfoNode::from_bytes(&bytes[head..])?;
+                head += node.into_bytes().len();
+                Ok(node)
+            })
+            .collect::<Result<Vec<_>, AconfigStorageError>>()
+            .map_err(|errmsg| {
+                AconfigStorageError::BytesParseFail(anyhow!(
+                    "fail to parse flag info list: {}",
+                    errmsg
+                ))
+            })?;
+        let list = Self { header, nodes };
+        Ok(list)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::test_utils::create_test_flag_info_list;
+
+    #[test]
+    // this test point locks down the value list serialization
+    fn test_serialization() {
+        let flag_info_list = create_test_flag_info_list();
+
+        let header: &FlagInfoHeader = &flag_info_list.header;
+        let reinterpreted_header = FlagInfoHeader::from_bytes(&header.into_bytes());
+        assert!(reinterpreted_header.is_ok());
+        assert_eq!(header, &reinterpreted_header.unwrap());
+
+        let nodes: &Vec<FlagInfoNode> = &flag_info_list.nodes;
+        for node in nodes.iter() {
+            let reinterpreted_node = FlagInfoNode::from_bytes(&node.into_bytes()).unwrap();
+            assert_eq!(node, &reinterpreted_node);
+        }
+
+        let flag_info_bytes = flag_info_list.into_bytes();
+        let reinterpreted_info_list = FlagInfoList::from_bytes(&flag_info_bytes);
+        assert!(reinterpreted_info_list.is_ok());
+        assert_eq!(&flag_info_list, &reinterpreted_info_list.unwrap());
+        assert_eq!(flag_info_bytes.len() as u32, header.file_size);
+    }
+
+    #[test]
+    // this test point locks down that version number should be at the top of serialized
+    // bytes
+    fn test_version_number() {
+        let flag_info_list = create_test_flag_info_list();
+        let bytes = &flag_info_list.into_bytes();
+        let mut head = 0;
+        let version = read_u32_from_bytes(bytes, &mut head).unwrap();
+        assert_eq!(version, 1234)
+    }
+
+    #[test]
+    // this test point locks down file type check
+    fn test_file_type_check() {
+        let mut flag_info_list = create_test_flag_info_list();
+        flag_info_list.header.file_type = 123u8;
+        let error = FlagInfoList::from_bytes(&flag_info_list.into_bytes()).unwrap_err();
+        assert_eq!(
+            format!("{:?}", error),
+            format!("BytesParseFail(binary file is not a flag info file)")
+        );
+    }
+}
diff --git a/tools/aconfig/aconfig_storage_file/src/flag_table.rs b/tools/aconfig/aconfig_storage_file/src/flag_table.rs
index f9b3158..2e2b857 100644
--- a/tools/aconfig/aconfig_storage_file/src/flag_table.rs
+++ b/tools/aconfig/aconfig_storage_file/src/flag_table.rs
@@ -59,7 +59,7 @@
 
 impl FlagTableHeader {
     /// Serialize to bytes
-    pub fn as_bytes(&self) -> Vec<u8> {
+    pub fn into_bytes(&self) -> Vec<u8> {
         let mut result = Vec::new();
         result.extend_from_slice(&self.version.to_le_bytes());
         let container_bytes = self.container.as_bytes();
@@ -118,7 +118,7 @@
 
 impl FlagTableNode {
     /// Serialize to bytes
-    pub fn as_bytes(&self) -> Vec<u8> {
+    pub fn into_bytes(&self) -> Vec<u8> {
         let mut result = Vec::new();
         result.extend_from_slice(&self.package_id.to_le_bytes());
         let name_bytes = self.flag_name.as_bytes();
@@ -178,11 +178,11 @@
 /// Flag table struct
 impl FlagTable {
     /// Serialize to bytes
-    pub fn as_bytes(&self) -> Vec<u8> {
+    pub fn into_bytes(&self) -> Vec<u8> {
         [
-            self.header.as_bytes(),
+            self.header.into_bytes(),
             self.buckets.iter().map(|v| v.unwrap_or(0).to_le_bytes()).collect::<Vec<_>>().concat(),
-            self.nodes.iter().map(|v| v.as_bytes()).collect::<Vec<_>>().concat(),
+            self.nodes.iter().map(|v| v.into_bytes()).collect::<Vec<_>>().concat(),
         ]
         .concat()
     }
@@ -192,7 +192,7 @@
         let header = FlagTableHeader::from_bytes(bytes)?;
         let num_flags = header.num_flags;
         let num_buckets = crate::get_table_size(num_flags)?;
-        let mut head = header.as_bytes().len();
+        let mut head = header.into_bytes().len();
         let buckets = (0..num_buckets)
             .map(|_| match read_u32_from_bytes(bytes, &mut head).unwrap() {
                 0 => None,
@@ -202,7 +202,7 @@
         let nodes = (0..num_flags)
             .map(|_| {
                 let node = FlagTableNode::from_bytes(&bytes[head..])?;
-                head += node.as_bytes().len();
+                head += node.into_bytes().len();
                 Ok(node)
             })
             .collect::<Result<Vec<_>, AconfigStorageError>>()
@@ -226,17 +226,17 @@
         let flag_table = create_test_flag_table();
 
         let header: &FlagTableHeader = &flag_table.header;
-        let reinterpreted_header = FlagTableHeader::from_bytes(&header.as_bytes());
+        let reinterpreted_header = FlagTableHeader::from_bytes(&header.into_bytes());
         assert!(reinterpreted_header.is_ok());
         assert_eq!(header, &reinterpreted_header.unwrap());
 
         let nodes: &Vec<FlagTableNode> = &flag_table.nodes;
         for node in nodes.iter() {
-            let reinterpreted_node = FlagTableNode::from_bytes(&node.as_bytes()).unwrap();
+            let reinterpreted_node = FlagTableNode::from_bytes(&node.into_bytes()).unwrap();
             assert_eq!(node, &reinterpreted_node);
         }
 
-        let flag_table_bytes = flag_table.as_bytes();
+        let flag_table_bytes = flag_table.into_bytes();
         let reinterpreted_table = FlagTable::from_bytes(&flag_table_bytes);
         assert!(reinterpreted_table.is_ok());
         assert_eq!(&flag_table, &reinterpreted_table.unwrap());
@@ -248,7 +248,7 @@
     // bytes
     fn test_version_number() {
         let flag_table = create_test_flag_table();
-        let bytes = &flag_table.as_bytes();
+        let bytes = &flag_table.into_bytes();
         let mut head = 0;
         let version = read_u32_from_bytes(bytes, &mut head).unwrap();
         assert_eq!(version, 1234)
@@ -259,7 +259,7 @@
     fn test_file_type_check() {
         let mut flag_table = create_test_flag_table();
         flag_table.header.file_type = 123u8;
-        let error = FlagTable::from_bytes(&flag_table.as_bytes()).unwrap_err();
+        let error = FlagTable::from_bytes(&flag_table.into_bytes()).unwrap_err();
         assert_eq!(
             format!("{:?}", error),
             format!("BytesParseFail(binary file is not a flag map)")
diff --git a/tools/aconfig/aconfig_storage_file/src/flag_value.rs b/tools/aconfig/aconfig_storage_file/src/flag_value.rs
index c9d09a1..40ccb34 100644
--- a/tools/aconfig/aconfig_storage_file/src/flag_value.rs
+++ b/tools/aconfig/aconfig_storage_file/src/flag_value.rs
@@ -55,7 +55,7 @@
 
 impl FlagValueHeader {
     /// Serialize to bytes
-    pub fn as_bytes(&self) -> Vec<u8> {
+    pub fn into_bytes(&self) -> Vec<u8> {
         let mut result = Vec::new();
         result.extend_from_slice(&self.version.to_le_bytes());
         let container_bytes = self.container.as_bytes();
@@ -108,9 +108,9 @@
 
 impl FlagValueList {
     /// Serialize to bytes
-    pub fn as_bytes(&self) -> Vec<u8> {
+    pub fn into_bytes(&self) -> Vec<u8> {
         [
-            self.header.as_bytes(),
+            self.header.into_bytes(),
             self.booleans.iter().map(|&v| u8::from(v).to_le_bytes()).collect::<Vec<_>>().concat(),
         ]
         .concat()
@@ -120,7 +120,7 @@
     pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
         let header = FlagValueHeader::from_bytes(bytes)?;
         let num_flags = header.num_flags;
-        let mut head = header.as_bytes().len();
+        let mut head = header.into_bytes().len();
         let booleans =
             (0..num_flags).map(|_| read_u8_from_bytes(bytes, &mut head).unwrap() == 1).collect();
         let list = Self { header, booleans };
@@ -139,11 +139,11 @@
         let flag_value_list = create_test_flag_value_list();
 
         let header: &FlagValueHeader = &flag_value_list.header;
-        let reinterpreted_header = FlagValueHeader::from_bytes(&header.as_bytes());
+        let reinterpreted_header = FlagValueHeader::from_bytes(&header.into_bytes());
         assert!(reinterpreted_header.is_ok());
         assert_eq!(header, &reinterpreted_header.unwrap());
 
-        let flag_value_bytes = flag_value_list.as_bytes();
+        let flag_value_bytes = flag_value_list.into_bytes();
         let reinterpreted_value_list = FlagValueList::from_bytes(&flag_value_bytes);
         assert!(reinterpreted_value_list.is_ok());
         assert_eq!(&flag_value_list, &reinterpreted_value_list.unwrap());
@@ -155,7 +155,7 @@
     // bytes
     fn test_version_number() {
         let flag_value_list = create_test_flag_value_list();
-        let bytes = &flag_value_list.as_bytes();
+        let bytes = &flag_value_list.into_bytes();
         let mut head = 0;
         let version = read_u32_from_bytes(bytes, &mut head).unwrap();
         assert_eq!(version, 1234)
@@ -166,7 +166,7 @@
     fn test_file_type_check() {
         let mut flag_value_list = create_test_flag_value_list();
         flag_value_list.header.file_type = 123u8;
-        let error = FlagValueList::from_bytes(&flag_value_list.as_bytes()).unwrap_err();
+        let error = FlagValueList::from_bytes(&flag_value_list.into_bytes()).unwrap_err();
         assert_eq!(
             format!("{:?}", error),
             format!("BytesParseFail(binary file is not a flag value file)")
diff --git a/tools/aconfig/aconfig_storage_file/src/lib.rs b/tools/aconfig/aconfig_storage_file/src/lib.rs
index 24b16a1..e7fda8a 100644
--- a/tools/aconfig/aconfig_storage_file/src/lib.rs
+++ b/tools/aconfig/aconfig_storage_file/src/lib.rs
@@ -32,6 +32,7 @@
 //! apis. DO NOT DIRECTLY USE THESE APIS IN YOUR SOURCE CODE. For auto generated flag apis
 //! please refer to the g3doc go/android-flags
 
+pub mod flag_info;
 pub mod flag_table;
 pub mod flag_value;
 pub mod package_table;
@@ -46,6 +47,7 @@
 use std::hash::{Hash, Hasher};
 use std::io::Read;
 
+pub use crate::flag_info::{FlagInfoHeader, FlagInfoList, FlagInfoNode};
 pub use crate::flag_table::{FlagTable, FlagTableHeader, FlagTableNode};
 pub use crate::flag_value::{FlagValueHeader, FlagValueList};
 pub use crate::package_table::{PackageTable, PackageTableHeader, PackageTableNode};
@@ -68,6 +70,7 @@
     PackageMap = 0,
     FlagMap = 1,
     FlagVal = 2,
+    FlagInfo = 3,
 }
 
 impl TryFrom<&str> for StorageFileType {
@@ -78,6 +81,7 @@
             "package_map" => Ok(Self::PackageMap),
             "flag_map" => Ok(Self::FlagMap),
             "flag_val" => Ok(Self::FlagVal),
+            "flag_info" => Ok(Self::FlagInfo),
             _ => Err(anyhow!(
                 "Invalid storage file type, valid types are package_map|flag_map|flag_val"
             )),
@@ -93,6 +97,7 @@
             x if x == Self::PackageMap as u8 => Ok(Self::PackageMap),
             x if x == Self::FlagMap as u8 => Ok(Self::FlagMap),
             x if x == Self::FlagVal as u8 => Ok(Self::FlagVal),
+            x if x == Self::FlagInfo as u8 => Ok(Self::FlagInfo),
             _ => Err(anyhow!("Invalid storage file type")),
         }
     }
@@ -219,7 +224,7 @@
     package_map: &str,
     flag_map: &str,
     flag_val: &str,
-) -> Result<Vec<(String, bool)>, AconfigStorageError> {
+) -> Result<Vec<(String, String, bool)>, AconfigStorageError> {
     let package_table = PackageTable::from_bytes(&read_file_to_bytes(package_map)?)?;
     let flag_table = FlagTable::from_bytes(&read_file_to_bytes(flag_map)?)?;
     let flag_value_list = FlagValueList::from_bytes(&read_file_to_bytes(flag_val)?)?;
@@ -232,10 +237,9 @@
     let mut flags = Vec::new();
     for node in flag_table.nodes.iter() {
         let (package_name, package_offset) = package_info[node.package_id as usize];
-        let full_flag_name = String::from(package_name) + "/" + &node.flag_name;
         let flag_offset = package_offset + node.flag_id as u32;
         let flag_value = flag_value_list.booleans[flag_offset as usize];
-        flags.push((full_flag_name, flag_value));
+        flags.push((String::from(package_name), node.flag_name.clone(), flag_value));
     }
 
     flags.sort_by(|v1, v2| v1.0.cmp(&v2.0));
@@ -254,10 +258,10 @@
     // this test point locks down the flag list api
     fn test_list_flag() {
         let package_table =
-            write_bytes_to_temp_file(&create_test_package_table().as_bytes()).unwrap();
-        let flag_table = write_bytes_to_temp_file(&create_test_flag_table().as_bytes()).unwrap();
+            write_bytes_to_temp_file(&create_test_package_table().into_bytes()).unwrap();
+        let flag_table = write_bytes_to_temp_file(&create_test_flag_table().into_bytes()).unwrap();
         let flag_value_list =
-            write_bytes_to_temp_file(&create_test_flag_value_list().as_bytes()).unwrap();
+            write_bytes_to_temp_file(&create_test_flag_value_list().into_bytes()).unwrap();
 
         let package_table_path = package_table.path().display().to_string();
         let flag_table_path = flag_table.path().display().to_string();
@@ -266,14 +270,30 @@
         let flags =
             list_flags(&package_table_path, &flag_table_path, &flag_value_list_path).unwrap();
         let expected = [
-            (String::from("com.android.aconfig.storage.test_1/disabled_rw"), false),
-            (String::from("com.android.aconfig.storage.test_1/enabled_ro"), true),
-            (String::from("com.android.aconfig.storage.test_1/enabled_rw"), false),
-            (String::from("com.android.aconfig.storage.test_2/disabled_ro"), false),
-            (String::from("com.android.aconfig.storage.test_2/enabled_fixed_ro"), true),
-            (String::from("com.android.aconfig.storage.test_2/enabled_ro"), true),
-            (String::from("com.android.aconfig.storage.test_4/enabled_fixed_ro"), false),
-            (String::from("com.android.aconfig.storage.test_4/enabled_ro"), true),
+            (String::from("com.android.aconfig.storage.test_1"), String::from("enabled_ro"), true),
+            (String::from("com.android.aconfig.storage.test_1"), String::from("enabled_rw"), false),
+            (
+                String::from("com.android.aconfig.storage.test_1"),
+                String::from("disabled_rw"),
+                false,
+            ),
+            (
+                String::from("com.android.aconfig.storage.test_2"),
+                String::from("disabled_ro"),
+                false,
+            ),
+            (
+                String::from("com.android.aconfig.storage.test_2"),
+                String::from("enabled_fixed_ro"),
+                true,
+            ),
+            (String::from("com.android.aconfig.storage.test_2"), String::from("enabled_ro"), true),
+            (String::from("com.android.aconfig.storage.test_4"), String::from("enabled_ro"), true),
+            (
+                String::from("com.android.aconfig.storage.test_4"),
+                String::from("enabled_fixed_ro"),
+                false,
+            ),
         ];
         assert_eq!(flags, expected);
     }
diff --git a/tools/aconfig/aconfig_storage_file/src/main.rs b/tools/aconfig/aconfig_storage_file/src/main.rs
index 293d018..12e0024 100644
--- a/tools/aconfig/aconfig_storage_file/src/main.rs
+++ b/tools/aconfig/aconfig_storage_file/src/main.rs
@@ -17,8 +17,8 @@
 //! `aconfig-storage` is a debugging tool to parse storage files
 
 use aconfig_storage_file::{
-    list_flags, read_file_to_bytes, AconfigStorageError, FlagTable, FlagValueList, PackageTable,
-    StorageFileType,
+    list_flags, read_file_to_bytes, AconfigStorageError, FlagInfoList, FlagTable, FlagValueList,
+    PackageTable, StorageFileType,
 };
 
 use clap::{builder::ArgAction, Arg, Command};
@@ -67,6 +67,10 @@
             let flag_value = FlagValueList::from_bytes(&bytes)?;
             println!("{:?}", flag_value);
         }
+        StorageFileType::FlagInfo => {
+            let flag_info = FlagInfoList::from_bytes(&bytes)?;
+            println!("{:?}", flag_info);
+        }
     }
     Ok(())
 }
diff --git a/tools/aconfig/aconfig_storage_file/src/package_table.rs b/tools/aconfig/aconfig_storage_file/src/package_table.rs
index 7cb60eb..e377115 100644
--- a/tools/aconfig/aconfig_storage_file/src/package_table.rs
+++ b/tools/aconfig/aconfig_storage_file/src/package_table.rs
@@ -56,7 +56,7 @@
 
 impl PackageTableHeader {
     /// Serialize to bytes
-    pub fn as_bytes(&self) -> Vec<u8> {
+    pub fn into_bytes(&self) -> Vec<u8> {
         let mut result = Vec::new();
         result.extend_from_slice(&self.version.to_le_bytes());
         let container_bytes = self.container.as_bytes();
@@ -116,7 +116,7 @@
 
 impl PackageTableNode {
     /// Serialize to bytes
-    pub fn as_bytes(&self) -> Vec<u8> {
+    pub fn into_bytes(&self) -> Vec<u8> {
         let mut result = Vec::new();
         let name_bytes = self.package_name.as_bytes();
         result.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes());
@@ -175,11 +175,11 @@
 
 impl PackageTable {
     /// Serialize to bytes
-    pub fn as_bytes(&self) -> Vec<u8> {
+    pub fn into_bytes(&self) -> Vec<u8> {
         [
-            self.header.as_bytes(),
+            self.header.into_bytes(),
             self.buckets.iter().map(|v| v.unwrap_or(0).to_le_bytes()).collect::<Vec<_>>().concat(),
-            self.nodes.iter().map(|v| v.as_bytes()).collect::<Vec<_>>().concat(),
+            self.nodes.iter().map(|v| v.into_bytes()).collect::<Vec<_>>().concat(),
         ]
         .concat()
     }
@@ -189,7 +189,7 @@
         let header = PackageTableHeader::from_bytes(bytes)?;
         let num_packages = header.num_packages;
         let num_buckets = crate::get_table_size(num_packages)?;
-        let mut head = header.as_bytes().len();
+        let mut head = header.into_bytes().len();
         let buckets = (0..num_buckets)
             .map(|_| match read_u32_from_bytes(bytes, &mut head).unwrap() {
                 0 => None,
@@ -199,7 +199,7 @@
         let nodes = (0..num_packages)
             .map(|_| {
                 let node = PackageTableNode::from_bytes(&bytes[head..])?;
-                head += node.as_bytes().len();
+                head += node.into_bytes().len();
                 Ok(node)
             })
             .collect::<Result<Vec<_>, AconfigStorageError>>()
@@ -225,17 +225,17 @@
     fn test_serialization() {
         let package_table = create_test_package_table();
         let header: &PackageTableHeader = &package_table.header;
-        let reinterpreted_header = PackageTableHeader::from_bytes(&header.as_bytes());
+        let reinterpreted_header = PackageTableHeader::from_bytes(&header.into_bytes());
         assert!(reinterpreted_header.is_ok());
         assert_eq!(header, &reinterpreted_header.unwrap());
 
         let nodes: &Vec<PackageTableNode> = &package_table.nodes;
         for node in nodes.iter() {
-            let reinterpreted_node = PackageTableNode::from_bytes(&node.as_bytes()).unwrap();
+            let reinterpreted_node = PackageTableNode::from_bytes(&node.into_bytes()).unwrap();
             assert_eq!(node, &reinterpreted_node);
         }
 
-        let package_table_bytes = package_table.as_bytes();
+        let package_table_bytes = package_table.into_bytes();
         let reinterpreted_table = PackageTable::from_bytes(&package_table_bytes);
         assert!(reinterpreted_table.is_ok());
         assert_eq!(&package_table, &reinterpreted_table.unwrap());
@@ -247,7 +247,7 @@
     // bytes
     fn test_version_number() {
         let package_table = create_test_package_table();
-        let bytes = &package_table.as_bytes();
+        let bytes = &package_table.into_bytes();
         let mut head = 0;
         let version = read_u32_from_bytes(bytes, &mut head).unwrap();
         assert_eq!(version, 1234)
@@ -258,7 +258,7 @@
     fn test_file_type_check() {
         let mut package_table = create_test_package_table();
         package_table.header.file_type = 123u8;
-        let error = PackageTable::from_bytes(&package_table.as_bytes()).unwrap_err();
+        let error = PackageTable::from_bytes(&package_table.into_bytes()).unwrap_err();
         assert_eq!(
             format!("{:?}", error),
             format!("BytesParseFail(binary file is not a package map)")
diff --git a/tools/aconfig/aconfig_storage_file/src/test_utils.rs b/tools/aconfig/aconfig_storage_file/src/test_utils.rs
index 586bb4c..4641829 100644
--- a/tools/aconfig/aconfig_storage_file/src/test_utils.rs
+++ b/tools/aconfig/aconfig_storage_file/src/test_utils.rs
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+use crate::flag_info::{FlagInfoHeader, FlagInfoList, FlagInfoNode};
 use crate::flag_table::{FlagTable, FlagTableHeader, FlagTableNode};
 use crate::flag_value::{FlagValueHeader, FlagValueList};
 use crate::package_table::{PackageTable, PackageTableHeader, PackageTableNode};
@@ -124,6 +125,19 @@
     FlagValueList { header, booleans }
 }
 
+pub(crate) fn create_test_flag_info_list() -> FlagInfoList {
+    let header = FlagInfoHeader {
+        version: 1234,
+        container: String::from("system"),
+        file_type: StorageFileType::FlagInfo as u8,
+        file_size: 35,
+        num_flags: 8,
+        boolean_flag_offset: 27,
+    };
+    let nodes: Vec<FlagInfoNode> = vec![FlagInfoNode { attributes: 0 }; 8];
+    FlagInfoList { header, nodes }
+}
+
 pub(crate) fn write_bytes_to_temp_file(bytes: &[u8]) -> Result<NamedTempFile, AconfigStorageError> {
     let mut file = NamedTempFile::new().map_err(|_| {
         AconfigStorageError::FileCreationFail(anyhow!("Failed to create temp file"))
diff --git a/tools/aconfig/aconfig_storage_read_api/Android.bp b/tools/aconfig/aconfig_storage_read_api/Android.bp
index 5006161..b252e9d 100644
--- a/tools/aconfig/aconfig_storage_read_api/Android.bp
+++ b/tools/aconfig/aconfig_storage_read_api/Android.bp
@@ -23,6 +23,11 @@
     crate_name: "aconfig_storage_read_api",
     host_supported: true,
     defaults: ["aconfig_storage_read_api.defaults"],
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+    min_sdk_version: "29",
 }
 
 rust_test_host {
@@ -68,7 +73,7 @@
     srcs: ["aconfig_storage_read_api.cpp"],
     generated_headers: [
         "cxx-bridge-header",
-        "libcxx_aconfig_storage_read_api_bridge_header"
+        "libcxx_aconfig_storage_read_api_bridge_header",
     ],
     generated_sources: ["libcxx_aconfig_storage_read_api_bridge_code"],
     whole_static_libs: ["libaconfig_storage_read_api_cxx_bridge"],
diff --git a/tools/aconfig/aconfig_storage_read_api/aconfig_storage_read_api.cpp b/tools/aconfig/aconfig_storage_read_api/aconfig_storage_read_api.cpp
index ea756b3..2213831 100644
--- a/tools/aconfig/aconfig_storage_read_api/aconfig_storage_read_api.cpp
+++ b/tools/aconfig/aconfig_storage_read_api/aconfig_storage_read_api.cpp
@@ -67,18 +67,18 @@
 static Result<MappedStorageFile> map_storage_file(std::string const& file) {
   int fd = open(file.c_str(), O_CLOEXEC | O_NOFOLLOW | O_RDONLY);
   if (fd == -1) {
-    return Error() << "failed to open " << file;
+    return ErrnoError() << "failed to open " << file;
   };
 
   struct stat fd_stat;
   if (fstat(fd, &fd_stat) < 0) {
-    return Error() << "fstat failed";
+    return ErrnoError() << "fstat failed";
   }
   size_t file_size = fd_stat.st_size;
 
   void* const map_result = mmap(nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0);
   if (map_result == MAP_FAILED) {
-    return Error() << "mmap failed";
+    return ErrnoError() << "mmap failed";
   }
 
   auto mapped_file = MappedStorageFile();
diff --git a/tools/aconfig/aconfig_storage_read_api/src/flag_table_query.rs b/tools/aconfig/aconfig_storage_read_api/src/flag_table_query.rs
index 43977ee..4c19646 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/flag_table_query.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/flag_table_query.rs
@@ -129,7 +129,7 @@
     #[test]
     // this test point locks down table query
     fn test_flag_query() {
-        let flag_table = create_test_flag_table().as_bytes();
+        let flag_table = create_test_flag_table().into_bytes();
         let baseline = vec![
             (0, "enabled_ro", 1u16),
             (0, "enabled_rw", 2u16),
@@ -150,7 +150,7 @@
     #[test]
     // this test point locks down table query of a non exist flag
     fn test_not_existed_flag_query() {
-        let flag_table = create_test_flag_table().as_bytes();
+        let flag_table = create_test_flag_table().into_bytes();
         let flag_offset = find_flag_offset(&flag_table[..], 1, "disabled_fixed_ro").unwrap();
         assert_eq!(flag_offset, None);
         let flag_offset = find_flag_offset(&flag_table[..], 2, "disabled_rw").unwrap();
@@ -162,7 +162,7 @@
     fn test_higher_version_storage_file() {
         let mut table = create_test_flag_table();
         table.header.version = crate::FILE_VERSION + 1;
-        let flag_table = table.as_bytes();
+        let flag_table = table.into_bytes();
         let error = find_flag_offset(&flag_table[..], 0, "enabled_ro").unwrap_err();
         assert_eq!(
             format!("{:?}", error),
diff --git a/tools/aconfig/aconfig_storage_read_api/src/flag_value_query.rs b/tools/aconfig/aconfig_storage_read_api/src/flag_value_query.rs
index 88d2397..964cd69 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/flag_value_query.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/flag_value_query.rs
@@ -66,7 +66,7 @@
     #[test]
     // this test point locks down flag value query
     fn test_flag_value_query() {
-        let flag_value_list = create_test_flag_value_list().as_bytes();
+        let flag_value_list = create_test_flag_value_list().into_bytes();
         let baseline: Vec<bool> = vec![false, true, false, false, true, true, false, true];
         for (offset, expected_value) in baseline.into_iter().enumerate() {
             let flag_value = find_boolean_flag_value(&flag_value_list[..], offset as u32).unwrap();
@@ -77,7 +77,7 @@
     #[test]
     // this test point locks down query beyond the end of boolean section
     fn test_boolean_out_of_range() {
-        let flag_value_list = create_test_flag_value_list().as_bytes();
+        let flag_value_list = create_test_flag_value_list().into_bytes();
         let error = find_boolean_flag_value(&flag_value_list[..], 8).unwrap_err();
         assert_eq!(
             format!("{:?}", error),
@@ -90,7 +90,7 @@
     fn test_higher_version_storage_file() {
         let mut value_list = create_test_flag_value_list();
         value_list.header.version = crate::FILE_VERSION + 1;
-        let flag_value = value_list.as_bytes();
+        let flag_value = value_list.into_bytes();
         let error = find_boolean_flag_value(&flag_value[..], 4).unwrap_err();
         assert_eq!(
             format!("{:?}", error),
diff --git a/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs b/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs
index 86c6a1b..51354db 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs
@@ -91,6 +91,9 @@
         StorageFileType::PackageMap => unsafe { map_file(files_location.package_map()) },
         StorageFileType::FlagMap => unsafe { map_file(files_location.flag_map()) },
         StorageFileType::FlagVal => unsafe { map_file(files_location.flag_val()) },
+        StorageFileType::FlagInfo => {
+            Err(MapFileFail(anyhow!("TODO: add support for flag info file")))
+        }
     }
 }
 
diff --git a/tools/aconfig/aconfig_storage_read_api/src/package_table_query.rs b/tools/aconfig/aconfig_storage_read_api/src/package_table_query.rs
index 3587e10..190de99 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/package_table_query.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/package_table_query.rs
@@ -110,7 +110,7 @@
     #[test]
     // this test point locks down table query
     fn test_package_query() {
-        let package_table = create_test_package_table().as_bytes();
+        let package_table = create_test_package_table().into_bytes();
         let package_offset =
             find_package_offset(&package_table[..], "com.android.aconfig.storage.test_1")
                 .unwrap()
@@ -135,7 +135,7 @@
     // this test point locks down table query of a non exist package
     fn test_not_existed_package_query() {
         // this will land at an empty bucket
-        let package_table = create_test_package_table().as_bytes();
+        let package_table = create_test_package_table().into_bytes();
         let package_offset =
             find_package_offset(&package_table[..], "com.android.aconfig.storage.test_3").unwrap();
         assert_eq!(package_offset, None);
@@ -150,7 +150,7 @@
     fn test_higher_version_storage_file() {
         let mut table = create_test_package_table();
         table.header.version = crate::FILE_VERSION + 1;
-        let package_table = table.as_bytes();
+        let package_table = table.into_bytes();
         let error = find_package_offset(&package_table[..], "com.android.aconfig.storage.test_1")
             .unwrap_err();
         assert_eq!(
diff --git a/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp b/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp
index 391b305..e863c0e 100644
--- a/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp
+++ b/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp
@@ -58,24 +58,24 @@
 static Result<MappedFlagValueFile> map_storage_file(std::string const& file) {
   struct stat file_stat;
   if (stat(file.c_str(), &file_stat) < 0) {
-    return Error() << "fstat failed";
+    return ErrnoError() << "stat failed";
   }
 
   if ((file_stat.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0) {
-    return Error() << "cannot map nonwriteable file";
+    return ErrnoError() << "cannot map nonwriteable file";
   }
 
   size_t file_size = file_stat.st_size;
 
   const int fd = open(file.c_str(), O_RDWR | O_NOFOLLOW | O_CLOEXEC);
   if (fd == -1) {
-    return Error() << "failed to open " << file;
+    return ErrnoError() << "failed to open " << file;
   };
 
   void* const map_result =
       mmap(nullptr, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
   if (map_result == MAP_FAILED) {
-    return Error() << "mmap failed";
+    return ErrnoError() << "mmap failed";
   }
 
   auto mapped_file = MappedFlagValueFile();
@@ -95,7 +95,12 @@
   if (!file_result.ok()) {
     return Error() << file_result.error();
   }
-  return map_storage_file(*file_result);
+  auto mapped_result = map_storage_file(*file_result);
+  if (!mapped_result.ok()) {
+    return Error() << "failed to map " << *file_result << ": "
+                   << mapped_result.error();
+  }
+  return *mapped_result;
 }
 
 } // namespace private internal api
diff --git a/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs b/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs
index c2375dd..4cb7939 100644
--- a/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs
+++ b/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs
@@ -71,7 +71,7 @@
     fn test_boolean_flag_value_update() {
         let flag_value_list = create_test_flag_value_list();
         let value_offset = flag_value_list.header.boolean_value_offset;
-        let mut content = flag_value_list.as_bytes();
+        let mut content = flag_value_list.into_bytes();
         let true_byte = u8::from(true).to_le_bytes()[0];
         let false_byte = u8::from(false).to_le_bytes()[0];
 
@@ -87,7 +87,7 @@
     #[test]
     // this test point locks down update beyond the end of boolean section
     fn test_boolean_out_of_range() {
-        let mut flag_value_list = create_test_flag_value_list().as_bytes();
+        let mut flag_value_list = create_test_flag_value_list().into_bytes();
         let error = update_boolean_flag_value(&mut flag_value_list[..], 8, true).unwrap_err();
         assert_eq!(
             format!("{:?}", error),
@@ -100,7 +100,7 @@
     fn test_higher_version_storage_file() {
         let mut value_list = create_test_flag_value_list();
         value_list.header.version = FILE_VERSION + 1;
-        let mut flag_value = value_list.as_bytes();
+        let mut flag_value = value_list.into_bytes();
         let error = update_boolean_flag_value(&mut flag_value[..], 4, true).unwrap_err();
         assert_eq!(
             format!("{:?}", error),
diff --git a/tools/aconfig/aflags/Android.bp b/tools/aconfig/aflags/Android.bp
index b36aa34..4920a6f 100644
--- a/tools/aconfig/aflags/Android.bp
+++ b/tools/aconfig/aflags/Android.bp
@@ -10,6 +10,8 @@
     srcs: ["src/main.rs"],
     rustlibs: [
         "libaconfig_protos",
+        "libaconfig_storage_read_api",
+        "libaconfig_storage_file",
         "libanyhow",
         "libclap",
         "libnix",
diff --git a/tools/aconfig/aflags/Cargo.toml b/tools/aconfig/aflags/Cargo.toml
index 6a08da6..cce7f9d 100644
--- a/tools/aconfig/aflags/Cargo.toml
+++ b/tools/aconfig/aflags/Cargo.toml
@@ -6,8 +6,10 @@
 [dependencies]
 anyhow = "1.0.69"
 paste = "1.0.11"
-clap = { version = "4", features = ["derive"] }
 protobuf = "3.2.0"
 regex = "1.10.3"
 aconfig_protos = { path = "../aconfig_protos" }
 nix = { version = "0.28.0", features = ["user"] }
+aconfig_storage_file = { version = "0.1.0", path = "../aconfig_storage_file" }
+aconfig_storage_read_api = { version = "0.1.0", path = "../aconfig_storage_read_api" }
+clap = {version = "4.5.2" }
diff --git a/tools/aconfig/aflags/src/aconfig_storage_source.rs b/tools/aconfig/aflags/src/aconfig_storage_source.rs
new file mode 100644
index 0000000..1d73688
--- /dev/null
+++ b/tools/aconfig/aflags/src/aconfig_storage_source.rs
@@ -0,0 +1,56 @@
+use crate::{Flag, FlagPermission, FlagSource, FlagValue, ValuePickedFrom};
+use anyhow::{anyhow, Result};
+
+use std::fs::File;
+use std::io::Read;
+
+pub struct AconfigStorageSource {}
+
+use aconfig_storage_file::protos::ProtoStorageFiles;
+
+static STORAGE_INFO_FILE_PATH: &str = "/metadata/aconfig/persistent_storage_file_records.pb";
+
+impl FlagSource for AconfigStorageSource {
+    fn list_flags() -> Result<Vec<Flag>> {
+        let mut result = Vec::new();
+
+        let mut file = File::open(STORAGE_INFO_FILE_PATH)?;
+        let mut bytes = Vec::new();
+        file.read_to_end(&mut bytes)?;
+        let storage_file_info: ProtoStorageFiles = protobuf::Message::parse_from_bytes(&bytes)?;
+
+        for file_info in storage_file_info.files {
+            let package_map =
+                file_info.package_map.ok_or(anyhow!("storage file is missing package map"))?;
+            let flag_map = file_info.flag_map.ok_or(anyhow!("storage file is missing flag map"))?;
+            let flag_val = file_info.flag_val.ok_or(anyhow!("storage file is missing flag val"))?;
+            let container =
+                file_info.container.ok_or(anyhow!("storage file is missing container"))?;
+
+            for (package, name, val) in
+                aconfig_storage_file::list_flags(&package_map, &flag_map, &flag_val)?
+            {
+                result.push(Flag {
+                    name: name.to_string(),
+                    package: package.to_string(),
+                    value: FlagValue::try_from(val.to_string().as_str())?,
+                    container: container.to_string(),
+
+                    // TODO(b/324436145): delete namespace field once DeviceConfig isn't in CLI.
+                    namespace: "-".to_string(),
+
+                    // TODO(b/324436145): Populate with real values once API is available.
+                    staged_value: None,
+                    permission: FlagPermission::ReadOnly,
+                    value_picked_from: ValuePickedFrom::Default,
+                });
+            }
+        }
+
+        Ok(result)
+    }
+
+    fn override_flag(_namespace: &str, _qualified_name: &str, _value: &str) -> Result<()> {
+        todo!()
+    }
+}
diff --git a/tools/aconfig/aflags/src/main.rs b/tools/aconfig/aflags/src/main.rs
index 808ffa0..1c453c5 100644
--- a/tools/aconfig/aflags/src/main.rs
+++ b/tools/aconfig/aflags/src/main.rs
@@ -22,6 +22,9 @@
 mod device_config_source;
 use device_config_source::DeviceConfigSource;
 
+mod aconfig_storage_source;
+use aconfig_storage_source::AconfigStorageSource;
+
 #[derive(Clone, PartialEq, Debug)]
 enum FlagPermission {
     ReadOnly,
@@ -109,6 +112,11 @@
     fn override_flag(namespace: &str, qualified_name: &str, value: &str) -> Result<()>;
 }
 
+enum FlagSourceType {
+    DeviceConfig,
+    AconfigStorage,
+}
+
 const ABOUT_TEXT: &str = "Tool for reading and writing flags.
 
 Rows in the table from the `list` command follow this format:
@@ -139,7 +147,11 @@
 #[derive(Parser, Debug)]
 enum Command {
     /// List all aconfig flags on this device.
-    List,
+    List {
+        /// Read from the new flag storage.
+        #[clap(long)]
+        use_new_storage: bool,
+    },
 
     /// Enable an aconfig flag on this device, on the next boot.
     Enable {
@@ -201,8 +213,11 @@
     Ok(())
 }
 
-fn list() -> Result<String> {
-    let flags = DeviceConfigSource::list_flags()?;
+fn list(source_type: FlagSourceType) -> Result<String> {
+    let flags = match source_type {
+        FlagSourceType::DeviceConfig => DeviceConfigSource::list_flags()?,
+        FlagSourceType::AconfigStorage => AconfigStorageSource::list_flags()?,
+    };
     let padding_info = PaddingInfo {
         longest_flag_col: flags.iter().map(|f| f.qualified_name().len()).max().unwrap_or(0),
         longest_val_col: flags.iter().map(|f| f.value.to_string().len()).max().unwrap_or(0),
@@ -234,7 +249,8 @@
 fn main() {
     let cli = Cli::parse();
     let output = match cli.command {
-        Command::List => list().map(Some),
+        Command::List { use_new_storage: true } => list(FlagSourceType::AconfigStorage).map(Some),
+        Command::List { use_new_storage: false } => list(FlagSourceType::DeviceConfig).map(Some),
         Command::Enable { qualified_name } => set_flag(&qualified_name, "true").map(|_| None),
         Command::Disable { qualified_name } => set_flag(&qualified_name, "false").map(|_| None),
     };