Merge "Turn on V3 cow" into main
diff --git a/cogsetup.sh b/cogsetup.sh
index 6439af0..44538f2 100644
--- a/cogsetup.sh
+++ b/cogsetup.sh
@@ -21,18 +21,21 @@
     OUT_DIR="out"
   fi
 
-  if [[ -L "${OUT_DIR}" ]]; then
+  # getoutdir ensures paths are absolute. envsetup could be called from a
+  # directory other than the root of the source tree
+  local outdir=$(getoutdir)
+  if [[ -L "${outdir}" ]]; then
     return
   fi
-  if [ -d "${OUT_DIR}" ]; then
-    echo -e "\tOutput directory ${OUT_DIR} cannot be present in a Cog workspace."
-    echo -e "\tDelete \"${OUT_DIR}\" or create a symlink from \"${OUT_DIR}\" to a directory outside your workspace."
+  if [ -d "${outdir}" ]; then
+    echo -e "\tOutput directory ${outdir} cannot be present in a Cog workspace."
+    echo -e "\tDelete \"${outdir}\" or create a symlink from \"${outdir}\" to a directory outside your workspace."
     return 1
   fi
 
   DEFAULT_OUTPUT_DIR="${HOME}/.cog/android-build-out"
   mkdir -p ${DEFAULT_OUTPUT_DIR}
-  ln -s ${DEFAULT_OUTPUT_DIR} `pwd`/out
+  ln -s ${DEFAULT_OUTPUT_DIR} ${outdir}
 }
 
 # This function sets up the build environment to be appropriate for Cog.
@@ -63,4 +66,4 @@
   echo -e "\e[01;31mERROR:\e[0m This script must be run from a Cog workspace."
 fi
 
-_setup_cog_env
\ No newline at end of file
+_setup_cog_env
diff --git a/core/Makefile b/core/Makefile
index d4e241e..f132db3 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -465,9 +465,7 @@
 	)
 	$(if $(1),\
 	  cp $$(PRIVATE_MODULES) $$(PRIVATE_MODULE_DIR)/; \
-	  for MODULE in $$(PRIVATE_LOAD_MODULES); do \
-	    basename $$$$MODULE >> $$(PRIVATE_LOAD_FILE); \
-	  done; \
+	  if [ -n "$$(PRIVATE_LOAD_MODULES)" ]; then basename -a $$(PRIVATE_LOAD_MODULES); fi > $$(PRIVATE_LOAD_FILE); \
 	)
 	# The ln -sf + find -delete sequence is to remove any modules in
 	# PRIVATE_EXTRA_MODULES which have same basename as MODULES in PRIVATE_MODULES
@@ -2727,6 +2725,8 @@
 	$(if $(strip $(recovery_wipe)), \
 	  cp -f $(recovery_wipe) $(TARGET_RECOVERY_ROOT_OUT)/system/etc/recovery.wipe)
 	ln -sf prop.default $(TARGET_RECOVERY_ROOT_OUT)/default.prop
+	# Silence warnings in first_stage_console.
+	touch $(TARGET_RECOVERY_ROOT_OUT)/linkerconfig/ld.config.txt
 	$(BOARD_RECOVERY_IMAGE_PREPARE)
 	$(hide) touch $@
 
@@ -3395,6 +3395,14 @@
 
 FULL_SYSTEMIMAGE_DEPS += $(INTERNAL_ROOT_FILES) $(INSTALLED_FILES_FILE_ROOT)
 
+define write-file-lines
+$(1):
+	@echo Writing $$@
+	rm -f $$@
+	echo -n > $$@
+	$$(foreach f,$(2),echo "$$(f)" >> $$@$$(newline))
+endef
+
 # -----------------------------------------------------------------
 ifdef BUILDING_SYSTEM_IMAGE
 
@@ -3448,14 +3456,6 @@
 $(systemimage_intermediates)/staging_dir.stamp: $(FULL_SYSTEMIMAGE_DEPS)
 	touch $@
 
-define write-file-lines
-$(1):
-	@echo Writing $$@
-	rm -f $$@
-	echo -n > $$@
-	$$(foreach f,$(2),echo "$$(f)" >> $$@$$(newline))
-endef
-
 # $(1): output file
 define build-systemimage-target
   @echo "Target system fs image: $(1)"
@@ -5110,6 +5110,7 @@
 endif
 
 # -- Check system and system_ext manifests / matrices including fragments (excluding other framework manifests / matrices, e.g. product);
+ifdef BUILDING_SYSTEM_IMAGE
 check_vintf_system_deps := $(filter $(TARGET_OUT)/etc/vintf/% \
                                     $(TARGET_OUT_SYSTEM_EXT)/etc/vintf/%, \
                                     $(check_vintf_common_srcs))
@@ -5139,6 +5140,8 @@
 endif # check_vintf_system_deps
 check_vintf_system_deps :=
 
+endif # BUILDING_SYSTEM_IMAGE
+
 # -- Check vendor manifest / matrix including fragments (excluding other device manifests / matrices)
 check_vintf_vendor_deps := $(filter $(TARGET_OUT_VENDOR)/etc/vintf/% \
                                     $(TARGET_OUT_VENDOR)/apex/%, \
@@ -5714,6 +5717,10 @@
 	  echo "flash vbmeta_$(partition)" >> $@;)
 endif
 endif # BOARD_AVB_ENABLE
+ifneq (,$(strip $(BOARD_CUSTOMIMAGES_PARTITION_LIST)))
+	$(hide) $(foreach partition,$(BOARD_CUSTOMIMAGES_PARTITION_LIST), \
+	  echo "flash $(partition)" >> $@;)
+endif
 	$(hide) echo "reboot fastboot" >> $@
 	$(hide) echo "update-super" >> $@
 	$(hide) $(foreach partition,$(BOARD_SUPER_PARTITION_PARTITION_LIST), \
@@ -6075,7 +6082,7 @@
 # $1: root directory
 # $2: add prefix
 define fs_config
-(cd $(1); find . -type d | sed 's,$$,/,'; find . \! -type d) | cut -c 3- | sort | sed 's,^,$(2),' | $(HOST_OUT_EXECUTABLES)/fs_config -C -D $(TARGET_OUT) -S $(SELINUX_FC) -R "$(2)"
+(cd $(1); find . -type d | sed 's,$$,/,'; find . \! -type d) | cut -c 3- | sort | sed 's,^,$(2),' | $(HOST_OUT_EXECUTABLES)/fs_config -C -D $(TARGET_OUT) -R "$(2)"
 endef
 
 define filter-out-missing-vendor
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index 9f43a3e..82e8baa 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -164,6 +164,8 @@
 
 $(call add_soong_config_var_value,ANDROID,release_binder_death_recipient_weak_from_jni,$(RELEASE_BINDER_DEATH_RECIPIENT_WEAK_FROM_JNI))
 
+$(call add_soong_config_var_value,ANDROID,release_selinux_data_data_ignore,$(RELEASE_SELINUX_DATA_DATA_IGNORE))
+
 # Enable system_server optimizations by default unless explicitly set or if
 # there may be dependent runtime jars.
 # TODO(b/240588226): Remove the off-by-default exceptions after handling
diff --git a/core/art_config.mk b/core/art_config.mk
index 54bfd6b..47b4bcf 100644
--- a/core/art_config.mk
+++ b/core/art_config.mk
@@ -27,8 +27,11 @@
 # soong variables indicate whether the prebuilt is enabled:
 # - $(m)_module/source_build for art and TOGGLEABLE_PREBUILT_MODULES
 # - ANDROID/module_build_from_source for other mainline modules
+# Note that RELEASE_APEX_BOOT_JARS_PREBUILT_EXCLUDED_LIST is the list of module names
+# and library names of jars that need to be removed. We have to keep separated list per
+# release config due to possibility of different prebuilt content.
 APEX_BOOT_JARS_EXCLUDED :=
-$(foreach pair, $(PRODUCT_APEX_BOOT_JARS_FOR_SOURCE_BUILD_ONLY),\
+$(foreach pair, $(RELEASE_APEX_BOOT_JARS_PREBUILT_EXCLUDED_LIST),\
   $(eval m := $(subst com.android.,,$(call word-colon,1,$(pair)))) \
   $(if $(call soong_config_get,$(m)_module,source_build), \
     $(if $(filter true,$(call soong_config_get,$(m)_module,source_build)),, \
diff --git a/core/binary.mk b/core/binary.mk
index 6dab49c..b17ab00 100644
--- a/core/binary.mk
+++ b/core/binary.mk
@@ -481,6 +481,34 @@
     my_cflags += $(CLANG_EXTERNAL_CFLAGS)
 endif
 
+# Extra cflags for projects under hardware/ directory.
+# This should match the definition of `thirdPartyDirPrefixExceptions`
+# in build/soong/android/paths.go.
+# Get the second element of LOCAL_PATH
+ifneq ($(filter hardware/%,$(LOCAL_PATH)),)
+  my_subdir := $(word 2,$(subst /,$(space),$(LOCAL_PATH)))
+  must_compile_hardware_subdirs := \
+                  hardware/google/% \
+                  hardware/interfaces/% \
+                  hardware/libhardware/% \
+                  hardware/libhardware_legacy/% \
+                  hardware/ril/%
+  ifeq ($(filter $(must_compile_hardware_subdirs),$(my_subdir)),)
+    my_cflags += $(CLANG_EXTERNAL_CFLAGS)
+  endif
+endif
+
+# Extra cflags for projects under vendor/ directory.
+# This should match the definition of `thirdPartyDirPrefixExceptions`
+# in build/soong/android/paths.go.
+ifneq ($(filter vendor/%,$(LOCAL_PATH)),)
+  my_subdir := $(word 2,$(subst /,$(space),$(LOCAL_PATH)))
+  # Do not add the flags for any subdir that contains the string "google".
+  ifneq ($(findstring google,$(my_subdir)),)
+    my_cflags += $(CLANG_EXTERNAL_CFLAGS)
+  endif
+endif
+
 # arch-specific static libraries go first so that generic ones can depend on them
 my_static_libraries := $(LOCAL_STATIC_LIBRARIES_$($(my_prefix)$(LOCAL_2ND_ARCH_VAR_PREFIX)ARCH)) $(LOCAL_STATIC_LIBRARIES_$(my_32_64_bit_suffix)) $(my_static_libraries)
 my_whole_static_libraries := $(LOCAL_WHOLE_STATIC_LIBRARIES_$($(my_prefix)$(LOCAL_2ND_ARCH_VAR_PREFIX)ARCH)) $(LOCAL_WHOLE_STATIC_LIBRARIES_$(my_32_64_bit_suffix)) $(my_whole_static_libraries)
diff --git a/core/board_config.mk b/core/board_config.mk
index 8c23f93..77489c6 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -287,6 +287,9 @@
 
 include $(BUILD_SYSTEM)/board_config_wifi.mk
 
+# Set up soong config for "soong_config_value_variable".
+-include vendor/google/build/soong/soong_config_namespace/camera.mk
+
 # Default *_CPU_VARIANT_RUNTIME to CPU_VARIANT if unspecified.
 TARGET_CPU_VARIANT_RUNTIME := $(or $(TARGET_CPU_VARIANT_RUNTIME),$(TARGET_CPU_VARIANT))
 TARGET_2ND_CPU_VARIANT_RUNTIME := $(or $(TARGET_2ND_CPU_VARIANT_RUNTIME),$(TARGET_2ND_CPU_VARIANT))
diff --git a/core/main.mk b/core/main.mk
index 9b7382b..c1cafc0 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -284,6 +284,11 @@
     ro.product.first_api_level=$(PRODUCT_SHIPPING_API_LEVEL)
 endif
 
+ifdef PRODUCT_SHIPPING_VENDOR_API_LEVEL
+ADDITIONAL_VENDOR_PROPERTIES += \
+    ro.vendor.api_level=$(PRODUCT_SHIPPING_VENDOR_API_LEVEL)
+endif
+
 ifneq ($(TARGET_BUILD_VARIANT),user)
   ifdef PRODUCT_SET_DEBUGFS_RESTRICTIONS
     ADDITIONAL_VENDOR_PROPERTIES += \
@@ -1672,6 +1677,7 @@
     $(INSTALLED_SYSTEM_DLKMIMAGE_TARGET) \
     $(INSTALLED_SUPERIMAGE_EMPTY_TARGET) \
     $(INSTALLED_PRODUCTIMAGE_TARGET) \
+    $(INSTALLED_SYSTEM_EXTIMAGE_TARGET) \
     $(INSTALLED_SYSTEMOTHERIMAGE_TARGET) \
     $(INSTALLED_TEST_HARNESS_RAMDISK_TARGET) \
     $(INSTALLED_TEST_HARNESS_BOOTIMAGE_TARGET) \
diff --git a/core/packaging/flags.mk b/core/packaging/flags.mk
index 62ef3df..500efdd 100644
--- a/core/packaging/flags.mk
+++ b/core/packaging/flags.mk
@@ -154,9 +154,9 @@
 
 ifeq ($(RELEASE_CREATE_ACONFIG_STORAGE_FILE),true)
 $(foreach partition, $(_FLAG_PARTITIONS), \
-	$(eval aconfig_storage_package_map.$(partition) := $(PRODUCT_OUT)/$(partition)/etc/package.map) \
-	$(eval aconfig_storage_flag_map.$(partition) := $(PRODUCT_OUT)/$(partition)/etc/flag.map) \
-	$(eval aconfig_storage_flag_val.$(partition) := $(PRODUCT_OUT)/$(partition)/etc/flag.val) \
+	$(eval aconfig_storage_package_map.$(partition) := $(PRODUCT_OUT)/$(partition)/etc/aconfig/package.map) \
+	$(eval aconfig_storage_flag_map.$(partition) := $(PRODUCT_OUT)/$(partition)/etc/aconfig/flag.map) \
+	$(eval aconfig_storage_flag_val.$(partition) := $(PRODUCT_OUT)/$(partition)/etc/aconfig/flag.val) \
 	$(eval $(call generate-partition-aconfig-storage-file, \
 				$(TARGET_OUT_FLAGS)/$(partition)/package.map, \
 				$(TARGET_OUT_FLAGS)/$(partition)/flag.map, \
diff --git a/core/product.mk b/core/product.mk
index 4250253..d64dde2 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -230,6 +230,9 @@
 # The first API level this product shipped with
 _product_single_value_vars += PRODUCT_SHIPPING_API_LEVEL
 
+# The first vendor API level this product shipped with
+_product_single_value_vars += PRODUCT_SHIPPING_VENDOR_API_LEVEL
+
 _product_list_vars += VENDOR_PRODUCT_RESTRICT_VENDOR_FILES
 _product_list_vars += VENDOR_EXCEPTION_MODULES
 _product_list_vars += VENDOR_EXCEPTION_PATHS
@@ -456,6 +459,10 @@
 
 _product_list_vars += PRODUCT_BUILD_IGNORE_APEX_CONTRIBUTION_CONTENTS
 
+_product_single_value_vars += PRODUCT_HIDDEN_API_EXPORTABLE_STUBS
+
+_product_single_value_vars += PRODUCT_EXPORT_RUNTIME_APIS
+
 .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 ec0c70e..b43a952 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -400,6 +400,10 @@
 
 $(call add_json_bool, BuildFromSourceStub, $(findstring true,$(PRODUCT_BUILD_FROM_SOURCE_STUB) $(BUILD_FROM_SOURCE_STUB)))
 
+$(call add_json_bool, HiddenapiExportableStubs, $(filter true,$(PRODUCT_HIDDEN_API_EXPORTABLE_STUBS)))
+
+$(call add_json_bool, ExportRuntimeApis, $(filter true,$(PRODUCT_EXPORT_RUNTIME_APIS)))
+
 $(call json_end)
 
 $(file >$(SOONG_VARIABLES).tmp,$(json_contents))
diff --git a/core/tasks/meta-lic.mk b/core/tasks/meta-lic.mk
new file mode 100644
index 0000000..0079714
--- /dev/null
+++ b/core/tasks/meta-lic.mk
@@ -0,0 +1,23 @@
+# 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.
+
+# Declare license metadata for non-module files released with products.
+
+# Moved here from frameworks/av/media/Android.mk
+$(eval $(call declare-1p-copy-files,frameworks/av/media/libeffects,audio_effects.conf))
+$(eval $(call declare-1p-copy-files,frameworks/av/media/libeffects,audio_effects.xml))
+$(eval $(call declare-1p-copy-files,frameworks/av/media/libstagefright,))
+
+# Moved here from frameworks/av/services/Android.mk
+$(eval $(call declare-1p-copy-files,frameworks/av/services/audiopolicy,))
diff --git a/target/product/AndroidProducts.mk b/target/product/AndroidProducts.mk
index 76b1c58..07eb96d 100644
--- a/target/product/AndroidProducts.mk
+++ b/target/product/AndroidProducts.mk
@@ -67,6 +67,7 @@
     $(LOCAL_DIR)/mainline_system_x86_arm.mk \
     $(LOCAL_DIR)/ndk.mk \
     $(LOCAL_DIR)/sdk.mk \
+    $(LOCAL_DIR)/sdk_with_runtime_apis.mk \
 
 endif
 
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index 3840e1f..b8aeb38 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -17,6 +17,7 @@
 # Base modules and settings for the system partition.
 PRODUCT_PACKAGES += \
     abx \
+    aconfigd \
     adbd_system_api \
     aflags \
     am \
diff --git a/target/product/default_art_config.mk b/target/product/default_art_config.mk
index dca9baa..d13a4c4 100644
--- a/target/product/default_art_config.mk
+++ b/target/product/default_art_config.mk
@@ -104,13 +104,6 @@
         com.android.nfcservices:framework-nfc
 endif
 
-# TODO(b/308174306): Adjust this after multiple prebuilts version is supported.
-# APEX boot jars that are not in prebuilt apexes.
-# Keep the list sorted by module names and then library names.
-PRODUCT_APEX_BOOT_JARS_FOR_SOURCE_BUILD_ONLY := \
-    com.android.mediaprovider:framework-pdf \
-    com.android.mediaprovider:framework-pdf-v \
-
 # 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.
diff --git a/target/product/sdk_with_runtime_apis.mk b/target/product/sdk_with_runtime_apis.mk
new file mode 100644
index 0000000..e80b4fb
--- /dev/null
+++ b/target/product/sdk_with_runtime_apis.mk
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+$(call inherit-product, $(SRC_TARGET_DIR)/product/sdk.mk)
+
+PRODUCT_NAME := sdk_with_runtime_apis
+
+PRODUCT_HIDDEN_API_EXPORTABLE_STUBS := true
+PRODUCT_EXPORT_RUNTIME_APIS := true
\ No newline at end of file
diff --git a/tools/aconfig/Cargo.toml b/tools/aconfig/Cargo.toml
index 95f1215..7112fd4 100644
--- a/tools/aconfig/Cargo.toml
+++ b/tools/aconfig/Cargo.toml
@@ -4,6 +4,7 @@
     "aconfig",
     "aconfig_protos",
     "aconfig_storage_file",
+    "aconfig_storage_read_api",
     "aflags",
     "printflags"
 ]
diff --git a/tools/aconfig/TEST_MAPPING b/tools/aconfig/TEST_MAPPING
index e42b5d3..26d6172 100644
--- a/tools/aconfig/TEST_MAPPING
+++ b/tools/aconfig/TEST_MAPPING
@@ -20,10 +20,11 @@
       // aconfig C++ integration tests (test mode auto-generated code)
       "name": "aconfig.test.cpp.test_mode"
     },
-    {
-      // aconfig C++ integration tests (exported mode auto-generated code)
-      "name": "aconfig.test.cpp.exported_mode"
-    },
+    // TODO(327420679): Enable export mode for native flag library
+    // {
+    //   // aconfig C++ integration tests (exported mode auto-generated code)
+    //   "name": "aconfig.test.cpp.exported_mode"
+    // },
     {
       // aconfig Rust integration tests (production mode auto-generated code)
       "name": "aconfig.prod_mode.test.rust"
@@ -32,10 +33,11 @@
       // aconfig Rust integration tests (test mode auto-generated code)
       "name": "aconfig.test_mode.test.rust"
     },
-    {
-      // aconfig Rust integration tests (exported mode auto-generated code)
-      "name": "aconfig.exported_mode.test.rust"
-    },
+    // TODO(327420679): Enable export mode for native flag library
+    // {
+    //   // aconfig Rust integration tests (exported mode auto-generated code)
+    //   "name": "aconfig.exported_mode.test.rust"
+    // },
     {
       // printflags unit tests
       "name": "printflags.test"
@@ -68,12 +70,16 @@
   ],
   "postsubmit": [
     {
+      // aconfig_storage_read_api unit tests
+      "name": "aconfig_storage_read_api.test"
+    },
+    {
       // aconfig_storage read api rust integration tests
-      "name": "aconfig_storage.test.rust"
+      "name": "aconfig_storage_read_api.test.rust"
     },
     {
       // aconfig_storage read api cpp integration tests
-      "name": "aconfig_storage.test.cpp"
+      "name": "aconfig_storage_read_api.test.cpp"
     },
     {
       // aflags CLI unit tests
diff --git a/tools/aconfig/aconfig/Android.bp b/tools/aconfig/aconfig/Android.bp
index 164bfe7..2c26166 100644
--- a/tools/aconfig/aconfig/Android.bp
+++ b/tools/aconfig/aconfig/Android.bp
@@ -143,12 +143,6 @@
 }
 
 cc_aconfig_library {
-    name: "aconfig_test_cpp_library_exported_variant",
-    aconfig_declarations: "aconfig.test.flags",
-    mode: "exported",
-}
-
-cc_aconfig_library {
     name: "aconfig_test_cpp_library_force_read_only_variant",
     aconfig_declarations: "aconfig.test.flags",
     mode: "force-read-only",
@@ -184,6 +178,14 @@
     test_suites: ["general-tests"],
 }
 
+// TODO(327420679): Enable export mode for native flag library
+/*
+cc_aconfig_library {
+    name: "aconfig_test_cpp_library_exported_variant",
+    aconfig_declarations: "aconfig.test.flags",
+    mode: "exported",
+}
+
 cc_test {
     name: "aconfig.test.cpp.exported_mode",
     srcs: [
@@ -198,6 +200,7 @@
     ],
     test_suites: ["general-tests"],
 }
+*/
 
 cc_test {
     name: "aconfig.test.cpp.force_read_only_mode",
@@ -249,6 +252,8 @@
     test_suites: ["general-tests"],
 }
 
+// TODO(327420679): Enable export mode for native flag library
+/*
 rust_aconfig_library {
     name: "libaconfig_test_rust_library_with_exported_mode",
     crate_name: "aconfig_test_rust_library",
@@ -266,6 +271,7 @@
     ],
     test_suites: ["general-tests"],
 }
+*/
 
 rust_aconfig_library {
     name: "libaconfig_test_rust_library_with_force_read_only_mode",
diff --git a/tools/aconfig/aconfig/src/commands.rs b/tools/aconfig/aconfig/src/commands.rs
index 59f349b..c1df16b 100644
--- a/tools/aconfig/aconfig/src/commands.rs
+++ b/tools/aconfig/aconfig/src/commands.rs
@@ -203,6 +203,11 @@
 }
 
 pub fn create_cpp_lib(mut input: Input, codegen_mode: CodegenMode) -> Result<Vec<OutputFile>> {
+    // TODO(327420679): Enable export mode for native flag library
+    ensure!(
+        codegen_mode != CodegenMode::Exported,
+        "Exported mode for generated c/c++ flag library is disabled"
+    );
     let parsed_flags = input.try_parse_flags()?;
     let modified_parsed_flags = modify_parsed_flags_based_on_mode(parsed_flags, codegen_mode)?;
     let Some(package) = find_unique_package(&modified_parsed_flags) else {
@@ -214,6 +219,11 @@
 }
 
 pub fn create_rust_lib(mut input: Input, codegen_mode: CodegenMode) -> Result<OutputFile> {
+    // // TODO(327420679): Enable export mode for native flag library
+    ensure!(
+        codegen_mode != CodegenMode::Exported,
+        "Exported mode for generated rust flag library is disabled"
+    );
     let parsed_flags = input.try_parse_flags()?;
     let modified_parsed_flags = modify_parsed_flags_based_on_mode(parsed_flags, codegen_mode)?;
     let Some(package) = find_unique_package(&modified_parsed_flags) else {
diff --git a/tools/aconfig/aconfig_storage_file/Android.bp b/tools/aconfig/aconfig_storage_file/Android.bp
index 8922ba4..6be3c19 100644
--- a/tools/aconfig/aconfig_storage_file/Android.bp
+++ b/tools/aconfig/aconfig_storage_file/Android.bp
@@ -9,12 +9,6 @@
     srcs: ["src/lib.rs"],
     rustlibs: [
         "libanyhow",
-        "libaconfig_storage_protos",
-        "libonce_cell",
-        "libprotobuf",
-        "libtempfile",
-        "libmemmap2",
-        "libcxx",
         "libthiserror",
     ],
 }
@@ -26,91 +20,8 @@
     defaults: ["aconfig_storage_file.defaults"],
 }
 
-genrule {
-    name: "ro.package.map",
-    out: ["tests/tmp.ro.package.map"],
-    srcs: ["tests/package.map"],
-    cmd: "rm -f $(out);cp -f $(in) $(out);chmod -w $(out)",
-}
-
-genrule {
-    name: "ro.flag.map",
-    out: ["tests/tmp.ro.flag.map"],
-    srcs: ["tests/flag.map"],
-    cmd: "rm -f $(out);cp -f $(in) $(out);chmod -w $(out)",
-}
-
-genrule {
-    name: "ro.flag.val",
-    out: ["tests/tmp.ro.flag.val"],
-    srcs: ["tests/flag.val"],
-    cmd: "rm -f $(out);cp -f $(in) $(out);chmod -w $(out)",
-}
-
 rust_test_host {
     name: "aconfig_storage_file.test",
     test_suites: ["general-tests"],
     defaults: ["aconfig_storage_file.defaults"],
-    data: [
-        "tests/package.map",
-        "tests/flag.map",
-        "tests/flag.val",
-    ],
-}
-
-rust_protobuf {
-    name: "libaconfig_storage_protos",
-    protos: ["protos/aconfig_storage_metadata.proto"],
-    crate_name: "aconfig_storage_protos",
-    source_stem: "aconfig_storage_protos",
-    host_supported: true,
-}
-
-cc_library_static {
-    name: "libaconfig_storage_protos_cc",
-    proto: {
-        export_proto_headers: true,
-        type: "lite",
-    },
-    srcs: ["protos/aconfig_storage_metadata.proto"],
-    apex_available: [
-        "//apex_available:platform",
-        "//apex_available:anyapex",
-    ],
-    host_supported: true,
-}
-
-genrule {
-    name: "libcxx_aconfig_storage_bridge_code",
-    tools: ["cxxbridge"],
-    cmd: "$(location cxxbridge) $(in) > $(out)",
-    srcs: ["src/lib.rs"],
-    out: ["aconfig_storage/lib.rs.cc"],
-}
-
-genrule {
-    name: "libcxx_aconfig_storage_bridge_header",
-    tools: ["cxxbridge"],
-    cmd: "$(location cxxbridge) $(in) --header > $(out)",
-    srcs: ["src/lib.rs"],
-    out: ["aconfig_storage/lib.rs.h"],
-}
-
-rust_ffi_static {
-    name: "libaconfig_storage_cxx_bridge",
-    crate_name: "aconfig_storage_cxx_bridge",
-    host_supported: true,
-    defaults: ["aconfig_storage_file.defaults"],
-}
-
-cc_library_static {
-    name: "libaconfig_storage_cc",
-    srcs: ["aconfig_storage.cpp"],
-    generated_headers: [
-        "cxx-bridge-header",
-        "libcxx_aconfig_storage_bridge_header"
-    ],
-    generated_sources: ["libcxx_aconfig_storage_bridge_code"],
-    whole_static_libs: ["libaconfig_storage_cxx_bridge"],
-    export_include_dirs: ["include"],
 }
diff --git a/tools/aconfig/aconfig_storage_file/src/flag_table.rs b/tools/aconfig/aconfig_storage_file/src/flag_table.rs
index 108804e..e1791d1 100644
--- a/tools/aconfig/aconfig_storage_file/src/flag_table.rs
+++ b/tools/aconfig/aconfig_storage_file/src/flag_table.rs
@@ -17,10 +17,9 @@
 //! flag table module defines the flag table file format and methods for serialization
 //! and deserialization
 
-use crate::AconfigStorageError::{self, BytesParseFail, HigherStorageFileVersion};
+use crate::AconfigStorageError::{self, BytesParseFail};
 use crate::{get_bucket_index, read_str_from_bytes, read_u16_from_bytes, read_u32_from_bytes};
 use anyhow::anyhow;
-pub type FlagOffset = u16;
 
 /// Flag table header struct
 #[derive(PartialEq, Debug)]
@@ -154,44 +153,6 @@
     }
 }
 
-/// Query flag within package offset
-pub fn find_flag_offset(
-    buf: &[u8],
-    package_id: u32,
-    flag: &str,
-) -> Result<Option<FlagOffset>, AconfigStorageError> {
-    let interpreted_header = FlagTableHeader::from_bytes(buf)?;
-    if interpreted_header.version > crate::FILE_VERSION {
-        return Err(HigherStorageFileVersion(anyhow!(
-            "Cannot read storage file with a higher version of {} with lib version {}",
-            interpreted_header.version,
-            crate::FILE_VERSION
-        )));
-    }
-
-    let num_buckets = (interpreted_header.node_offset - interpreted_header.bucket_offset) / 4;
-    let bucket_index = FlagTableNode::find_bucket_index(package_id, flag, num_buckets);
-
-    let mut pos = (interpreted_header.bucket_offset + 4 * bucket_index) as usize;
-    let mut flag_node_offset = read_u32_from_bytes(buf, &mut pos)? as usize;
-    if flag_node_offset < interpreted_header.node_offset as usize
-        || flag_node_offset >= interpreted_header.file_size as usize
-    {
-        return Ok(None);
-    }
-
-    loop {
-        let interpreted_node = FlagTableNode::from_bytes(&buf[flag_node_offset..])?;
-        if interpreted_node.package_id == package_id && interpreted_node.flag_name == flag {
-            return Ok(Some(interpreted_node.flag_id));
-        }
-        match interpreted_node.next_offset {
-            Some(offset) => flag_node_offset = offset as usize,
-            None => return Ok(None),
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -270,52 +231,4 @@
         assert!(reinterpreted_table.is_ok());
         assert_eq!(&flag_table, &reinterpreted_table.unwrap());
     }
-
-    #[test]
-    // this test point locks down table query
-    fn test_flag_query() {
-        let flag_table = create_test_flag_table().as_bytes();
-        let baseline = vec![
-            (0, "enabled_ro", 1u16),
-            (0, "enabled_rw", 2u16),
-            (1, "disabled_ro", 0u16),
-            (2, "enabled_ro", 1u16),
-            (1, "enabled_fixed_ro", 1u16),
-            (1, "enabled_ro", 2u16),
-            (2, "enabled_fixed_ro", 0u16),
-            (0, "disabled_rw", 0u16),
-        ];
-        for (package_id, flag_name, expected_offset) in baseline.into_iter() {
-            let flag_offset =
-                find_flag_offset(&flag_table[..], package_id, flag_name).unwrap().unwrap();
-            assert_eq!(flag_offset, expected_offset);
-        }
-    }
-
-    #[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_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();
-        assert_eq!(flag_offset, None);
-    }
-
-    #[test]
-    // this test point locks down query error when file has a higher version
-    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 error = find_flag_offset(&flag_table[..], 0, "enabled_ro").unwrap_err();
-        assert_eq!(
-            format!("{:?}", error),
-            format!(
-                "HigherStorageFileVersion(Cannot read storage file with a higher version of {} with lib version {})",
-                crate::FILE_VERSION + 1,
-                crate::FILE_VERSION
-            )
-        );
-    }
 }
diff --git a/tools/aconfig/aconfig_storage_file/src/flag_value.rs b/tools/aconfig/aconfig_storage_file/src/flag_value.rs
index 0a6a37f..8356847 100644
--- a/tools/aconfig/aconfig_storage_file/src/flag_value.rs
+++ b/tools/aconfig/aconfig_storage_file/src/flag_value.rs
@@ -17,9 +17,8 @@
 //! flag value module defines the flag value file format and methods for serialization
 //! and deserialization
 
-use crate::AconfigStorageError::{self, HigherStorageFileVersion, InvalidStorageFileOffset};
+use crate::AconfigStorageError;
 use crate::{read_str_from_bytes, read_u32_from_bytes, read_u8_from_bytes};
-use anyhow::anyhow;
 
 /// Flag value header struct
 #[derive(PartialEq, Debug)]
@@ -87,31 +86,6 @@
     }
 }
 
-/// Query flag value
-pub fn find_boolean_flag_value(buf: &[u8], flag_offset: u32) -> Result<bool, AconfigStorageError> {
-    let interpreted_header = FlagValueHeader::from_bytes(buf)?;
-    if interpreted_header.version > crate::FILE_VERSION {
-        return Err(HigherStorageFileVersion(anyhow!(
-            "Cannot read storage file with a higher version of {} with lib version {}",
-            interpreted_header.version,
-            crate::FILE_VERSION
-        )));
-    }
-
-    let mut head = (interpreted_header.boolean_value_offset + flag_offset) as usize;
-
-    // TODO: right now, there is only boolean flags, with more flag value types added
-    // later, the end of boolean flag value section should be updated (b/322826265).
-    if head >= interpreted_header.file_size as usize {
-        return Err(InvalidStorageFileOffset(anyhow!(
-            "Flag value offset goes beyond the end of the file."
-        )));
-    }
-
-    let val = read_u8_from_bytes(buf, &mut head)?;
-    Ok(val == 1)
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -142,43 +116,4 @@
         assert!(reinterpreted_value_list.is_ok());
         assert_eq!(&flag_value_list, &reinterpreted_value_list.unwrap());
     }
-
-    #[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 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();
-            assert_eq!(flag_value, expected_value);
-        }
-    }
-
-    #[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 error = find_boolean_flag_value(&flag_value_list[..], 8).unwrap_err();
-        assert_eq!(
-            format!("{:?}", error),
-            "InvalidStorageFileOffset(Flag value offset goes beyond the end of the file.)"
-        );
-    }
-
-    #[test]
-    // this test point locks down query error when file has a higher version
-    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 error = find_boolean_flag_value(&flag_value[..], 4).unwrap_err();
-        assert_eq!(
-            format!("{:?}", error),
-            format!(
-                "HigherStorageFileVersion(Cannot read storage file with a higher version of {} with lib version {})",
-                crate::FILE_VERSION + 1,
-                crate::FILE_VERSION
-            )
-        );
-    }
 }
diff --git a/tools/aconfig/aconfig_storage_file/src/lib.rs b/tools/aconfig/aconfig_storage_file/src/lib.rs
index 84e0e90..e06e149 100644
--- a/tools/aconfig/aconfig_storage_file/src/lib.rs
+++ b/tools/aconfig/aconfig_storage_file/src/lib.rs
@@ -34,21 +34,15 @@
 
 pub mod flag_table;
 pub mod flag_value;
-pub mod mapped_file;
 pub mod package_table;
-pub mod protos;
-
-#[cfg(test)]
-mod test_utils;
 
 use anyhow::anyhow;
 use std::collections::hash_map::DefaultHasher;
 use std::hash::{Hash, Hasher};
 
-pub use crate::flag_table::{FlagOffset, FlagTable, FlagTableHeader, FlagTableNode};
+pub use crate::flag_table::{FlagTable, FlagTableHeader, FlagTableNode};
 pub use crate::flag_value::{FlagValueHeader, FlagValueList};
-pub use crate::package_table::{PackageOffset, PackageTable, PackageTableHeader, PackageTableNode};
-pub use crate::protos::ProtoStorageFiles;
+pub use crate::package_table::{PackageTable, PackageTableHeader, PackageTableNode};
 
 use crate::AconfigStorageError::{BytesParseFail, HashTableSizeLimit};
 
@@ -62,9 +56,6 @@
     402653189, 805306457, 1610612741,
 ];
 
-/// Storage file location pb file
-pub const STORAGE_LOCATION_FILE: &str = "/metadata/aconfig/storage_files.pb";
-
 /// Storage file type enum
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub enum StorageFileSelection {
@@ -104,7 +95,7 @@
 }
 
 /// Read and parse bytes as u8
-pub(crate) fn read_u8_from_bytes(buf: &[u8], head: &mut usize) -> Result<u8, AconfigStorageError> {
+pub fn read_u8_from_bytes(buf: &[u8], head: &mut usize) -> Result<u8, AconfigStorageError> {
     let val =
         u8::from_le_bytes(buf[*head..*head + 1].try_into().map_err(|errmsg| {
             BytesParseFail(anyhow!("fail to parse u8 from bytes: {}", errmsg))
@@ -127,10 +118,7 @@
 }
 
 /// Read and parse bytes as u32
-pub(crate) fn read_u32_from_bytes(
-    buf: &[u8],
-    head: &mut usize,
-) -> Result<u32, AconfigStorageError> {
+pub fn read_u32_from_bytes(buf: &[u8], head: &mut usize) -> Result<u32, AconfigStorageError> {
     let val =
         u32::from_le_bytes(buf[*head..*head + 4].try_into().map_err(|errmsg| {
             BytesParseFail(anyhow!("fail to parse u32 from bytes: {}", errmsg))
@@ -179,392 +167,3 @@
     #[error("invalid storage file byte offset")]
     InvalidStorageFileOffset(#[source] anyhow::Error),
 }
-
-/// Get package start offset implementation
-pub fn get_package_offset_impl(
-    pb_file: &str,
-    container: &str,
-    package: &str,
-) -> Result<Option<PackageOffset>, AconfigStorageError> {
-    let mapped_file =
-        crate::mapped_file::get_mapped_file(pb_file, container, StorageFileSelection::PackageMap)?;
-    crate::package_table::find_package_offset(&mapped_file, package)
-}
-
-/// Get flag offset implementation
-pub fn get_flag_offset_impl(
-    pb_file: &str,
-    container: &str,
-    package_id: u32,
-    flag: &str,
-) -> Result<Option<FlagOffset>, AconfigStorageError> {
-    let mapped_file =
-        crate::mapped_file::get_mapped_file(pb_file, container, StorageFileSelection::FlagMap)?;
-    crate::flag_table::find_flag_offset(&mapped_file, package_id, flag)
-}
-
-/// Get boolean flag value implementation
-pub fn get_boolean_flag_value_impl(
-    pb_file: &str,
-    container: &str,
-    offset: u32,
-) -> Result<bool, AconfigStorageError> {
-    let mapped_file =
-        crate::mapped_file::get_mapped_file(pb_file, container, StorageFileSelection::FlagVal)?;
-    crate::flag_value::find_boolean_flag_value(&mapped_file, offset)
-}
-
-/// Get package start offset for flags given the container and package name.
-///
-/// This function would map the corresponding package map file if has not been mapped yet,
-/// and then look for the target package in this mapped file.
-///
-/// If a package is found, it returns Ok(Some(PackageOffset))
-/// If a package is not found, it returns Ok(None)
-/// If errors out such as no such package map file is found, it returns an Err(errmsg)
-pub fn get_package_offset(
-    container: &str,
-    package: &str,
-) -> Result<Option<PackageOffset>, AconfigStorageError> {
-    get_package_offset_impl(STORAGE_LOCATION_FILE, container, package)
-}
-
-/// Get flag offset within a package given the container name, package id and flag name.
-///
-/// This function would map the corresponding flag map file if has not been mapped yet,
-/// and then look for the target flag in this mapped file.
-///
-/// If a flag is found, it returns Ok(Some(u16))
-/// If a flag is not found, it returns Ok(None)
-/// If errors out such as no such flag map file is found, it returns an Err(errmsg)
-pub fn get_flag_offset(
-    container: &str,
-    package_id: u32,
-    flag: &str,
-) -> Result<Option<FlagOffset>, AconfigStorageError> {
-    get_flag_offset_impl(STORAGE_LOCATION_FILE, container, package_id, flag)
-}
-
-/// Get the boolean flag value given the container name and flag global offset
-///
-/// This function would map the corresponding flag value file if has not been mapped yet,
-/// and then look for the target flag value at the specified offset.
-///
-/// If flag value file is successfully mapped and the provide offset is valid, it returns
-/// the boolean flag value, otherwise it returns the error message.
-pub fn get_boolean_flag_value(container: &str, offset: u32) -> Result<bool, AconfigStorageError> {
-    get_boolean_flag_value_impl(STORAGE_LOCATION_FILE, container, offset)
-}
-
-#[cxx::bridge]
-mod ffi {
-    // Package table query return for cc interlop
-    pub struct PackageOffsetQueryCXX {
-        pub query_success: bool,
-        pub error_message: String,
-        pub package_exists: bool,
-        pub package_id: u32,
-        pub boolean_offset: u32,
-    }
-
-    // Flag table query return for cc interlop
-    pub struct FlagOffsetQueryCXX {
-        pub query_success: bool,
-        pub error_message: String,
-        pub flag_exists: bool,
-        pub flag_offset: u16,
-    }
-
-    // Flag value query return for cc interlop
-    pub struct BooleanFlagValueQueryCXX {
-        pub query_success: bool,
-        pub error_message: String,
-        pub flag_value: bool,
-    }
-
-    // Rust export to c++
-    extern "Rust" {
-        pub fn get_package_offset_cxx_impl(
-            pb_file: &str,
-            container: &str,
-            package: &str,
-        ) -> PackageOffsetQueryCXX;
-
-        pub fn get_flag_offset_cxx_impl(
-            pb_file: &str,
-            container: &str,
-            package_id: u32,
-            flag: &str,
-        ) -> FlagOffsetQueryCXX;
-
-        pub fn get_boolean_flag_value_cxx_impl(
-            pb_file: &str,
-            container: &str,
-            offset: u32,
-        ) -> BooleanFlagValueQueryCXX;
-
-        pub fn get_package_offset_cxx(container: &str, package: &str) -> PackageOffsetQueryCXX;
-
-        pub fn get_flag_offset_cxx(
-            container: &str,
-            package_id: u32,
-            flag: &str,
-        ) -> FlagOffsetQueryCXX;
-
-        pub fn get_boolean_flag_value_cxx(container: &str, offset: u32)
-            -> BooleanFlagValueQueryCXX;
-    }
-}
-
-/// Get package start offset impl cc interlop
-pub fn get_package_offset_cxx_impl(
-    pb_file: &str,
-    container: &str,
-    package: &str,
-) -> ffi::PackageOffsetQueryCXX {
-    ffi::PackageOffsetQueryCXX::new(get_package_offset_impl(pb_file, container, package))
-}
-
-/// Get flag start offset impl cc interlop
-pub fn get_flag_offset_cxx_impl(
-    pb_file: &str,
-    container: &str,
-    package_id: u32,
-    flag: &str,
-) -> ffi::FlagOffsetQueryCXX {
-    ffi::FlagOffsetQueryCXX::new(get_flag_offset_impl(pb_file, container, package_id, flag))
-}
-
-/// Get boolean flag value impl cc interlop
-pub fn get_boolean_flag_value_cxx_impl(
-    pb_file: &str,
-    container: &str,
-    offset: u32,
-) -> ffi::BooleanFlagValueQueryCXX {
-    ffi::BooleanFlagValueQueryCXX::new(get_boolean_flag_value_impl(pb_file, container, offset))
-}
-
-/// Get package start offset cc interlop
-pub fn get_package_offset_cxx(container: &str, package: &str) -> ffi::PackageOffsetQueryCXX {
-    ffi::PackageOffsetQueryCXX::new(get_package_offset(container, package))
-}
-
-/// Get flag start offset cc interlop
-pub fn get_flag_offset_cxx(
-    container: &str,
-    package_id: u32,
-    flag: &str,
-) -> ffi::FlagOffsetQueryCXX {
-    ffi::FlagOffsetQueryCXX::new(get_flag_offset(container, package_id, flag))
-}
-
-/// Get boolean flag value cc interlop
-pub fn get_boolean_flag_value_cxx(container: &str, offset: u32) -> ffi::BooleanFlagValueQueryCXX {
-    ffi::BooleanFlagValueQueryCXX::new(get_boolean_flag_value(container, offset))
-}
-
-impl ffi::PackageOffsetQueryCXX {
-    pub(crate) fn new(offset_result: Result<Option<PackageOffset>, AconfigStorageError>) -> Self {
-        match offset_result {
-            Ok(offset_opt) => match offset_opt {
-                Some(offset) => Self {
-                    query_success: true,
-                    error_message: String::from(""),
-                    package_exists: true,
-                    package_id: offset.package_id,
-                    boolean_offset: offset.boolean_offset,
-                },
-                None => Self {
-                    query_success: true,
-                    error_message: String::from(""),
-                    package_exists: false,
-                    package_id: 0,
-                    boolean_offset: 0,
-                },
-            },
-            Err(errmsg) => Self {
-                query_success: false,
-                error_message: format!("{:?}", errmsg),
-                package_exists: false,
-                package_id: 0,
-                boolean_offset: 0,
-            },
-        }
-    }
-}
-
-impl ffi::FlagOffsetQueryCXX {
-    pub(crate) fn new(offset_result: Result<Option<FlagOffset>, AconfigStorageError>) -> Self {
-        match offset_result {
-            Ok(offset_opt) => match offset_opt {
-                Some(offset) => Self {
-                    query_success: true,
-                    error_message: String::from(""),
-                    flag_exists: true,
-                    flag_offset: offset,
-                },
-                None => Self {
-                    query_success: true,
-                    error_message: String::from(""),
-                    flag_exists: false,
-                    flag_offset: 0,
-                },
-            },
-            Err(errmsg) => Self {
-                query_success: false,
-                error_message: format!("{:?}", errmsg),
-                flag_exists: false,
-                flag_offset: 0,
-            },
-        }
-    }
-}
-
-impl ffi::BooleanFlagValueQueryCXX {
-    pub(crate) fn new(value_result: Result<bool, AconfigStorageError>) -> Self {
-        match value_result {
-            Ok(value) => {
-                Self { query_success: true, error_message: String::from(""), flag_value: value }
-            }
-            Err(errmsg) => Self {
-                query_success: false,
-                error_message: format!("{:?}", errmsg),
-                flag_value: false,
-            },
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::test_utils::{write_storage_text_to_temp_file, TestStorageFileSet};
-
-    fn create_test_storage_files(read_only: bool) -> TestStorageFileSet {
-        TestStorageFileSet::new(
-            "./tests/package.map",
-            "./tests/flag.map",
-            "./tests/flag.val",
-            read_only,
-        )
-        .unwrap()
-    }
-
-    #[test]
-    // this test point locks down flag package offset query
-    fn test_package_offset_query() {
-        let ro_files = create_test_storage_files(true);
-        let text_proto = format!(
-            r#"
-files {{
-    version: 0
-    container: "system"
-    package_map: "{}"
-    flag_map: "{}"
-    flag_val: "{}"
-    timestamp: 12345
-}}
-"#,
-            ro_files.package_map.name, ro_files.flag_map.name, ro_files.flag_val.name
-        );
-
-        let file = write_storage_text_to_temp_file(&text_proto).unwrap();
-        let file_full_path = file.path().display().to_string();
-        let package_offset = get_package_offset_impl(
-            &file_full_path,
-            "system",
-            "com.android.aconfig.storage.test_1",
-        )
-        .unwrap()
-        .unwrap();
-        let expected_package_offset = PackageOffset { package_id: 0, boolean_offset: 0 };
-        assert_eq!(package_offset, expected_package_offset);
-
-        let package_offset = get_package_offset_impl(
-            &file_full_path,
-            "system",
-            "com.android.aconfig.storage.test_2",
-        )
-        .unwrap()
-        .unwrap();
-        let expected_package_offset = PackageOffset { package_id: 1, boolean_offset: 3 };
-        assert_eq!(package_offset, expected_package_offset);
-
-        let package_offset = get_package_offset_impl(
-            &file_full_path,
-            "system",
-            "com.android.aconfig.storage.test_4",
-        )
-        .unwrap()
-        .unwrap();
-        let expected_package_offset = PackageOffset { package_id: 2, boolean_offset: 6 };
-        assert_eq!(package_offset, expected_package_offset);
-    }
-
-    #[test]
-    // this test point locks down flag offset query
-    fn test_flag_offset_query() {
-        let ro_files = create_test_storage_files(true);
-        let text_proto = format!(
-            r#"
-files {{
-    version: 0
-    container: "system"
-    package_map: "{}"
-    flag_map: "{}"
-    flag_val: "{}"
-    timestamp: 12345
-}}
-"#,
-            ro_files.package_map.name, ro_files.flag_map.name, ro_files.flag_val.name
-        );
-
-        let file = write_storage_text_to_temp_file(&text_proto).unwrap();
-        let file_full_path = file.path().display().to_string();
-        let baseline = vec![
-            (0, "enabled_ro", 1u16),
-            (0, "enabled_rw", 2u16),
-            (1, "disabled_ro", 0u16),
-            (2, "enabled_ro", 1u16),
-            (1, "enabled_fixed_ro", 1u16),
-            (1, "enabled_ro", 2u16),
-            (2, "enabled_fixed_ro", 0u16),
-            (0, "disabled_rw", 0u16),
-        ];
-        for (package_id, flag_name, expected_offset) in baseline.into_iter() {
-            let flag_offset =
-                get_flag_offset_impl(&file_full_path, "system", package_id, flag_name)
-                    .unwrap()
-                    .unwrap();
-            assert_eq!(flag_offset, expected_offset);
-        }
-    }
-
-    #[test]
-    // this test point locks down flag offset query
-    fn test_flag_value_query() {
-        let ro_files = create_test_storage_files(true);
-        let text_proto = format!(
-            r#"
-files {{
-    version: 0
-    container: "system"
-    package_map: "{}"
-    flag_map: "{}"
-    flag_val: "{}"
-    timestamp: 12345
-}}
-"#,
-            ro_files.package_map.name, ro_files.flag_map.name, ro_files.flag_val.name
-        );
-
-        let file = write_storage_text_to_temp_file(&text_proto).unwrap();
-        let file_full_path = file.path().display().to_string();
-        let baseline: Vec<bool> = vec![false; 8];
-        for (offset, expected_value) in baseline.into_iter().enumerate() {
-            let flag_value =
-                get_boolean_flag_value_impl(&file_full_path, "system", offset as u32).unwrap();
-            assert_eq!(flag_value, expected_value);
-        }
-    }
-}
diff --git a/tools/aconfig/aconfig_storage_file/src/package_table.rs b/tools/aconfig/aconfig_storage_file/src/package_table.rs
index 7308d7b..28310a8 100644
--- a/tools/aconfig/aconfig_storage_file/src/package_table.rs
+++ b/tools/aconfig/aconfig_storage_file/src/package_table.rs
@@ -17,7 +17,7 @@
 //! package table module defines the package table file format and methods for serialization
 //! and deserialization
 
-use crate::AconfigStorageError::{self, BytesParseFail, HigherStorageFileVersion};
+use crate::AconfigStorageError::{self, BytesParseFail};
 use crate::{get_bucket_index, read_str_from_bytes, read_u32_from_bytes};
 use anyhow::anyhow;
 
@@ -153,53 +153,6 @@
     }
 }
 
-/// Package table query return
-#[derive(PartialEq, Debug)]
-pub struct PackageOffset {
-    pub package_id: u32,
-    pub boolean_offset: u32,
-}
-
-/// Query package id and start offset
-pub fn find_package_offset(
-    buf: &[u8],
-    package: &str,
-) -> Result<Option<PackageOffset>, AconfigStorageError> {
-    let interpreted_header = PackageTableHeader::from_bytes(buf)?;
-    if interpreted_header.version > crate::FILE_VERSION {
-        return Err(HigherStorageFileVersion(anyhow!(
-            "Cannot read storage file with a higher version of {} with lib version {}",
-            interpreted_header.version,
-            crate::FILE_VERSION
-        )));
-    }
-
-    let num_buckets = (interpreted_header.node_offset - interpreted_header.bucket_offset) / 4;
-    let bucket_index = PackageTableNode::find_bucket_index(package, num_buckets);
-
-    let mut pos = (interpreted_header.bucket_offset + 4 * bucket_index) as usize;
-    let mut package_node_offset = read_u32_from_bytes(buf, &mut pos)? as usize;
-    if package_node_offset < interpreted_header.node_offset as usize
-        || package_node_offset >= interpreted_header.file_size as usize
-    {
-        return Ok(None);
-    }
-
-    loop {
-        let interpreted_node = PackageTableNode::from_bytes(&buf[package_node_offset..])?;
-        if interpreted_node.package_name == package {
-            return Ok(Some(PackageOffset {
-                package_id: interpreted_node.package_id,
-                boolean_offset: interpreted_node.boolean_offset,
-            }));
-        }
-        match interpreted_node.next_offset {
-            Some(offset) => package_node_offset = offset as usize,
-            None => return Ok(None),
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -255,60 +208,4 @@
         assert!(reinterpreted_table.is_ok());
         assert_eq!(&package_table, &reinterpreted_table.unwrap());
     }
-
-    #[test]
-    // this test point locks down table query
-    fn test_package_query() {
-        let package_table = create_test_package_table().as_bytes();
-        let package_offset =
-            find_package_offset(&package_table[..], "com.android.aconfig.storage.test_1")
-                .unwrap()
-                .unwrap();
-        let expected_package_offset = PackageOffset { package_id: 0, boolean_offset: 0 };
-        assert_eq!(package_offset, expected_package_offset);
-        let package_offset =
-            find_package_offset(&package_table[..], "com.android.aconfig.storage.test_2")
-                .unwrap()
-                .unwrap();
-        let expected_package_offset = PackageOffset { package_id: 1, boolean_offset: 3 };
-        assert_eq!(package_offset, expected_package_offset);
-        let package_offset =
-            find_package_offset(&package_table[..], "com.android.aconfig.storage.test_4")
-                .unwrap()
-                .unwrap();
-        let expected_package_offset = PackageOffset { package_id: 2, boolean_offset: 6 };
-        assert_eq!(package_offset, expected_package_offset);
-    }
-
-    #[test]
-    // 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_offset =
-            find_package_offset(&package_table[..], "com.android.aconfig.storage.test_3").unwrap();
-        assert_eq!(package_offset, None);
-        // this will land at the end of a linked list
-        let package_offset =
-            find_package_offset(&package_table[..], "com.android.aconfig.storage.test_5").unwrap();
-        assert_eq!(package_offset, None);
-    }
-
-    #[test]
-    // this test point locks down query error when file has a higher version
-    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 error = find_package_offset(&package_table[..], "com.android.aconfig.storage.test_1")
-            .unwrap_err();
-        assert_eq!(
-            format!("{:?}", error),
-            format!(
-                "HigherStorageFileVersion(Cannot read storage file with a higher version of {} with lib version {})",
-                crate::FILE_VERSION + 1,
-                crate::FILE_VERSION
-            )
-        );
-    }
 }
diff --git a/tools/aconfig/aconfig_storage_read_api/Android.bp b/tools/aconfig/aconfig_storage_read_api/Android.bp
new file mode 100644
index 0000000..43697b3
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/Android.bp
@@ -0,0 +1,121 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_defaults {
+    name: "aconfig_storage_read_api.defaults",
+    edition: "2021",
+    lints: "none",
+    srcs: ["src/lib.rs"],
+    rustlibs: [
+        "libanyhow",
+        "libaconfig_storage_protos",
+        "libonce_cell",
+        "libprotobuf",
+        "libtempfile",
+        "libmemmap2",
+        "libcxx",
+        "libthiserror",
+        "libaconfig_storage_file",
+    ],
+}
+
+rust_library {
+    name: "libaconfig_storage_read_api",
+    crate_name: "aconfig_storage_read_api",
+    host_supported: true,
+    defaults: ["aconfig_storage_read_api.defaults"],
+}
+
+rust_test_host {
+    name: "aconfig_storage_read_api.test",
+    test_suites: ["general-tests"],
+    defaults: ["aconfig_storage_read_api.defaults"],
+    data: [
+        "tests/package.map",
+        "tests/flag.map",
+        "tests/flag.val",
+    ],
+}
+
+rust_protobuf {
+    name: "libaconfig_storage_protos",
+    protos: ["protos/aconfig_storage_metadata.proto"],
+    crate_name: "aconfig_storage_protos",
+    source_stem: "aconfig_storage_protos",
+    host_supported: true,
+}
+
+cc_library_static {
+    name: "libaconfig_storage_protos_cc",
+    proto: {
+        export_proto_headers: true,
+        type: "lite",
+    },
+    srcs: ["protos/aconfig_storage_metadata.proto"],
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+    host_supported: true,
+}
+
+genrule {
+    name: "ro.package.map",
+    out: ["tests/tmp.ro.package.map"],
+    srcs: ["tests/package.map"],
+    cmd: "rm -f $(out);cp -f $(in) $(out);chmod -w $(out)",
+}
+
+genrule {
+    name: "ro.flag.map",
+    out: ["tests/tmp.ro.flag.map"],
+    srcs: ["tests/flag.map"],
+    cmd: "rm -f $(out);cp -f $(in) $(out);chmod -w $(out)",
+}
+
+genrule {
+    name: "ro.flag.val",
+    out: ["tests/tmp.ro.flag.val"],
+    srcs: ["tests/flag.val"],
+    cmd: "rm -f $(out);cp -f $(in) $(out);chmod -w $(out)",
+}
+
+// cxx source codegen from rust api
+genrule {
+    name: "libcxx_aconfig_storage_read_api_bridge_code",
+    tools: ["cxxbridge"],
+    cmd: "$(location cxxbridge) $(in) > $(out)",
+    srcs: ["src/lib.rs"],
+    out: ["aconfig_storage/lib.rs.cc"],
+}
+
+// cxx header codegen from rust api
+genrule {
+    name: "libcxx_aconfig_storage_read_api_bridge_header",
+    tools: ["cxxbridge"],
+    cmd: "$(location cxxbridge) $(in) --header > $(out)",
+    srcs: ["src/lib.rs"],
+    out: ["aconfig_storage/lib.rs.h"],
+}
+
+// a static cc lib based on generated code
+rust_ffi_static {
+    name: "libaconfig_storage_read_api_cxx_bridge",
+    crate_name: "aconfig_storage_read_api_cxx_bridge",
+    host_supported: true,
+    defaults: ["aconfig_storage_read_api.defaults"],
+}
+
+// flag read api cc interface
+cc_library_static {
+    name: "libaconfig_storage_read_api_cc",
+    srcs: ["aconfig_storage_read_api.cpp"],
+    generated_headers: [
+        "cxx-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"],
+    export_include_dirs: ["include"],
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/Cargo.toml b/tools/aconfig/aconfig_storage_read_api/Cargo.toml
new file mode 100644
index 0000000..4c65d40
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/Cargo.toml
@@ -0,0 +1,22 @@
+[package]
+name = "aconfig_storage_read_api"
+version = "0.1.0"
+edition = "2021"
+
+[features]
+default = ["cargo"]
+cargo = []
+
+[dependencies]
+anyhow = "1.0.69"
+memmap2 = "0.8.0"
+protobuf = "3.2.0"
+once_cell = "1.19.0"
+tempfile = "3.9.0"
+cxx = "1.0"
+thiserror = "1.0.56"
+aconfig_storage_file = { path = "../aconfig_storage_file" }
+
+[build-dependencies]
+protobuf-codegen = "3.2.0"
+cxx-build = "1.0"
diff --git a/tools/aconfig/aconfig_storage_file/aconfig_storage.cpp b/tools/aconfig/aconfig_storage_read_api/aconfig_storage_read_api.cpp
similarity index 97%
rename from tools/aconfig/aconfig_storage_file/aconfig_storage.cpp
rename to tools/aconfig/aconfig_storage_read_api/aconfig_storage_read_api.cpp
index ac64093..7cf8e38 100644
--- a/tools/aconfig/aconfig_storage_file/aconfig_storage.cpp
+++ b/tools/aconfig/aconfig_storage_read_api/aconfig_storage_read_api.cpp
@@ -1,4 +1,4 @@
-#include "aconfig_storage/aconfig_storage.hpp"
+#include "aconfig_storage/aconfig_storage_read_api.hpp"
 
 #include "rust/cxx.h"
 #include "aconfig_storage/lib.rs.h"
diff --git a/tools/aconfig/aconfig_storage_file/build.rs b/tools/aconfig/aconfig_storage_read_api/build.rs
similarity index 100%
rename from tools/aconfig/aconfig_storage_file/build.rs
rename to tools/aconfig/aconfig_storage_read_api/build.rs
diff --git a/tools/aconfig/aconfig_storage_file/include/aconfig_storage/aconfig_storage.hpp b/tools/aconfig/aconfig_storage_read_api/include/aconfig_storage/aconfig_storage_read_api.hpp
similarity index 100%
rename from tools/aconfig/aconfig_storage_file/include/aconfig_storage/aconfig_storage.hpp
rename to tools/aconfig/aconfig_storage_read_api/include/aconfig_storage/aconfig_storage_read_api.hpp
diff --git a/tools/aconfig/aconfig_storage_file/protos/aconfig_storage_metadata.proto b/tools/aconfig/aconfig_storage_read_api/protos/aconfig_storage_metadata.proto
similarity index 100%
rename from tools/aconfig/aconfig_storage_file/protos/aconfig_storage_metadata.proto
rename to tools/aconfig/aconfig_storage_read_api/protos/aconfig_storage_metadata.proto
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
new file mode 100644
index 0000000..cc05557
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/src/flag_table_query.rs
@@ -0,0 +1,175 @@
+/*
+ * 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 table query module defines the flag table file read from mapped bytes
+
+use crate::{AconfigStorageError, FILE_VERSION};
+use aconfig_storage_file::{
+    flag_table::FlagTableHeader, flag_table::FlagTableNode, read_u32_from_bytes,
+};
+use anyhow::anyhow;
+
+pub type FlagOffset = u16;
+
+/// Query flag within package offset
+pub fn find_flag_offset(
+    buf: &[u8],
+    package_id: u32,
+    flag: &str,
+) -> Result<Option<FlagOffset>, AconfigStorageError> {
+    let interpreted_header = FlagTableHeader::from_bytes(buf)?;
+    if interpreted_header.version > crate::FILE_VERSION {
+        return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
+            "Cannot read storage file with a higher version of {} with lib version {}",
+            interpreted_header.version,
+            FILE_VERSION
+        )));
+    }
+
+    let num_buckets = (interpreted_header.node_offset - interpreted_header.bucket_offset) / 4;
+    let bucket_index = FlagTableNode::find_bucket_index(package_id, flag, num_buckets);
+
+    let mut pos = (interpreted_header.bucket_offset + 4 * bucket_index) as usize;
+    let mut flag_node_offset = read_u32_from_bytes(buf, &mut pos)? as usize;
+    if flag_node_offset < interpreted_header.node_offset as usize
+        || flag_node_offset >= interpreted_header.file_size as usize
+    {
+        return Ok(None);
+    }
+
+    loop {
+        let interpreted_node = FlagTableNode::from_bytes(&buf[flag_node_offset..])?;
+        if interpreted_node.package_id == package_id && interpreted_node.flag_name == flag {
+            return Ok(Some(interpreted_node.flag_id));
+        }
+        match interpreted_node.next_offset {
+            Some(offset) => flag_node_offset = offset as usize,
+            None => return Ok(None),
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use aconfig_storage_file::FlagTable;
+
+    // create test baseline, syntactic sugar
+    fn new_expected_node(
+        package_id: u32,
+        flag_name: &str,
+        flag_type: u16,
+        flag_id: u16,
+        next_offset: Option<u32>,
+    ) -> FlagTableNode {
+        FlagTableNode {
+            package_id,
+            flag_name: flag_name.to_string(),
+            flag_type,
+            flag_id,
+            next_offset,
+        }
+    }
+
+    pub fn create_test_flag_table() -> FlagTable {
+        let header = FlagTableHeader {
+            version: crate::FILE_VERSION,
+            container: String::from("system"),
+            file_size: 320,
+            num_flags: 8,
+            bucket_offset: 30,
+            node_offset: 98,
+        };
+        let buckets: Vec<Option<u32>> = vec![
+            Some(98),
+            Some(124),
+            None,
+            None,
+            None,
+            Some(177),
+            None,
+            Some(203),
+            None,
+            Some(261),
+            None,
+            None,
+            None,
+            None,
+            None,
+            Some(293),
+            None,
+        ];
+        let nodes = vec![
+            new_expected_node(0, "enabled_ro", 1, 1, None),
+            new_expected_node(0, "enabled_rw", 1, 2, Some(150)),
+            new_expected_node(1, "disabled_ro", 1, 0, None),
+            new_expected_node(2, "enabled_ro", 1, 1, None),
+            new_expected_node(1, "enabled_fixed_ro", 1, 1, Some(235)),
+            new_expected_node(1, "enabled_ro", 1, 2, None),
+            new_expected_node(2, "enabled_fixed_ro", 1, 0, None),
+            new_expected_node(0, "disabled_rw", 1, 0, None),
+        ];
+        FlagTable { header, buckets, nodes }
+    }
+
+    #[test]
+    // this test point locks down table query
+    fn test_flag_query() {
+        let flag_table = create_test_flag_table().as_bytes();
+        let baseline = vec![
+            (0, "enabled_ro", 1u16),
+            (0, "enabled_rw", 2u16),
+            (1, "disabled_ro", 0u16),
+            (2, "enabled_ro", 1u16),
+            (1, "enabled_fixed_ro", 1u16),
+            (1, "enabled_ro", 2u16),
+            (2, "enabled_fixed_ro", 0u16),
+            (0, "disabled_rw", 0u16),
+        ];
+        for (package_id, flag_name, expected_offset) in baseline.into_iter() {
+            let flag_offset =
+                find_flag_offset(&flag_table[..], package_id, flag_name).unwrap().unwrap();
+            assert_eq!(flag_offset, expected_offset);
+        }
+    }
+
+    #[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_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();
+        assert_eq!(flag_offset, None);
+    }
+
+    #[test]
+    // this test point locks down query error when file has a higher version
+    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 error = find_flag_offset(&flag_table[..], 0, "enabled_ro").unwrap_err();
+        assert_eq!(
+            format!("{:?}", error),
+            format!(
+                "HigherStorageFileVersion(Cannot read storage file with a higher version of {} with lib version {})",
+                crate::FILE_VERSION + 1,
+                crate::FILE_VERSION
+            )
+        );
+    }
+}
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
new file mode 100644
index 0000000..6ff6b05
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/src/flag_value_query.rs
@@ -0,0 +1,103 @@
+/*
+ * 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 value query module defines the flag value file read from mapped bytes
+
+use crate::{AconfigStorageError, FILE_VERSION};
+use aconfig_storage_file::{flag_value::FlagValueHeader, read_u8_from_bytes};
+use anyhow::anyhow;
+
+/// Query flag value
+pub fn find_boolean_flag_value(buf: &[u8], flag_offset: u32) -> Result<bool, AconfigStorageError> {
+    let interpreted_header = FlagValueHeader::from_bytes(buf)?;
+    if interpreted_header.version > crate::FILE_VERSION {
+        return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
+            "Cannot read storage file with a higher version of {} with lib version {}",
+            interpreted_header.version,
+            FILE_VERSION
+        )));
+    }
+
+    let mut head = (interpreted_header.boolean_value_offset + flag_offset) as usize;
+
+    // TODO: right now, there is only boolean flags, with more flag value types added
+    // later, the end of boolean flag value section should be updated (b/322826265).
+    if head >= interpreted_header.file_size as usize {
+        return Err(AconfigStorageError::InvalidStorageFileOffset(anyhow!(
+            "Flag value offset goes beyond the end of the file."
+        )));
+    }
+
+    let val = read_u8_from_bytes(buf, &mut head)?;
+    Ok(val == 1)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use aconfig_storage_file::FlagValueList;
+
+    pub fn create_test_flag_value_list() -> FlagValueList {
+        let header = FlagValueHeader {
+            version: crate::FILE_VERSION,
+            container: String::from("system"),
+            file_size: 34,
+            num_flags: 8,
+            boolean_value_offset: 26,
+        };
+        let booleans: Vec<bool> = vec![false, true, false, false, true, true, false, true];
+        FlagValueList { header, booleans }
+    }
+
+    #[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 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();
+            assert_eq!(flag_value, expected_value);
+        }
+    }
+
+    #[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 error = find_boolean_flag_value(&flag_value_list[..], 8).unwrap_err();
+        assert_eq!(
+            format!("{:?}", error),
+            "InvalidStorageFileOffset(Flag value offset goes beyond the end of the file.)"
+        );
+    }
+
+    #[test]
+    // this test point locks down query error when file has a higher version
+    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 error = find_boolean_flag_value(&flag_value[..], 4).unwrap_err();
+        assert_eq!(
+            format!("{:?}", error),
+            format!(
+                "HigherStorageFileVersion(Cannot read storage file with a higher version of {} with lib version {})",
+                crate::FILE_VERSION + 1,
+                crate::FILE_VERSION
+            )
+        );
+    }
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/src/lib.rs b/tools/aconfig/aconfig_storage_read_api/src/lib.rs
new file mode 100644
index 0000000..996256b
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/src/lib.rs
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2023 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_storage_read_api` is a crate that defines read apis to read flags from storage
+//! files. It provides three apis to
+//! interface with storage files:
+//!
+//! 1, function to get package flag value start offset
+//! pub fn get_package_offset(container: &str, package: &str) -> `Result<Option<PackageOffset>>>`
+//!
+//! 2, function to get flag offset within a specific package
+//! pub fn get_flag_offset(container: &str, package_id: u32, flag: &str) -> `Result<Option<u16>>>`
+//!
+//! 3, function to get the actual flag value given the global offset (combined package and
+//! flag offset).
+//! pub fn get_boolean_flag_value(container: &str, offset: u32) -> `Result<bool>`
+//!
+//! Note these are low level apis that are expected to be only used in auto generated flag
+//! 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_table_query;
+pub mod flag_value_query;
+pub mod mapped_file;
+pub mod package_table_query;
+pub mod protos;
+
+#[cfg(test)]
+mod test_utils;
+
+pub use crate::protos::ProtoStorageFiles;
+pub use aconfig_storage_file::{AconfigStorageError, StorageFileSelection, FILE_VERSION};
+pub use flag_table_query::FlagOffset;
+pub use package_table_query::PackageOffset;
+
+use flag_table_query::find_flag_offset;
+use flag_value_query::find_boolean_flag_value;
+use mapped_file::get_mapped_file;
+use package_table_query::find_package_offset;
+
+/// Storage file location pb file
+pub const STORAGE_LOCATION_FILE: &str = "/metadata/aconfig/available_storage_file_records.pb";
+
+/// Get package start offset implementation
+pub fn get_package_offset_impl(
+    pb_file: &str,
+    container: &str,
+    package: &str,
+) -> Result<Option<PackageOffset>, AconfigStorageError> {
+    let mapped_file = get_mapped_file(pb_file, container, StorageFileSelection::PackageMap)?;
+    find_package_offset(&mapped_file, package)
+}
+
+/// Get flag offset implementation
+pub fn get_flag_offset_impl(
+    pb_file: &str,
+    container: &str,
+    package_id: u32,
+    flag: &str,
+) -> Result<Option<FlagOffset>, AconfigStorageError> {
+    let mapped_file = get_mapped_file(pb_file, container, StorageFileSelection::FlagMap)?;
+    find_flag_offset(&mapped_file, package_id, flag)
+}
+
+/// Get boolean flag value implementation
+pub fn get_boolean_flag_value_impl(
+    pb_file: &str,
+    container: &str,
+    offset: u32,
+) -> Result<bool, AconfigStorageError> {
+    let mapped_file = get_mapped_file(pb_file, container, StorageFileSelection::FlagVal)?;
+    find_boolean_flag_value(&mapped_file, offset)
+}
+
+/// Get package start offset for flags given the container and package name.
+///
+/// This function would map the corresponding package map file if has not been mapped yet,
+/// and then look for the target package in this mapped file.
+///
+/// If a package is found, it returns Ok(Some(PackageOffset))
+/// If a package is not found, it returns Ok(None)
+/// If errors out such as no such package map file is found, it returns an Err(errmsg)
+pub fn get_package_offset(
+    container: &str,
+    package: &str,
+) -> Result<Option<PackageOffset>, AconfigStorageError> {
+    get_package_offset_impl(STORAGE_LOCATION_FILE, container, package)
+}
+
+/// Get flag offset within a package given the container name, package id and flag name.
+///
+/// This function would map the corresponding flag map file if has not been mapped yet,
+/// and then look for the target flag in this mapped file.
+///
+/// If a flag is found, it returns Ok(Some(u16))
+/// If a flag is not found, it returns Ok(None)
+/// If errors out such as no such flag map file is found, it returns an Err(errmsg)
+pub fn get_flag_offset(
+    container: &str,
+    package_id: u32,
+    flag: &str,
+) -> Result<Option<FlagOffset>, AconfigStorageError> {
+    get_flag_offset_impl(STORAGE_LOCATION_FILE, container, package_id, flag)
+}
+
+/// Get the boolean flag value given the container name and flag global offset
+///
+/// This function would map the corresponding flag value file if has not been mapped yet,
+/// and then look for the target flag value at the specified offset.
+///
+/// If flag value file is successfully mapped and the provide offset is valid, it returns
+/// the boolean flag value, otherwise it returns the error message.
+pub fn get_boolean_flag_value(container: &str, offset: u32) -> Result<bool, AconfigStorageError> {
+    get_boolean_flag_value_impl(STORAGE_LOCATION_FILE, container, offset)
+}
+
+#[cxx::bridge]
+mod ffi {
+    // Package table query return for cc interlop
+    pub struct PackageOffsetQueryCXX {
+        pub query_success: bool,
+        pub error_message: String,
+        pub package_exists: bool,
+        pub package_id: u32,
+        pub boolean_offset: u32,
+    }
+
+    // Flag table query return for cc interlop
+    pub struct FlagOffsetQueryCXX {
+        pub query_success: bool,
+        pub error_message: String,
+        pub flag_exists: bool,
+        pub flag_offset: u16,
+    }
+
+    // Flag value query return for cc interlop
+    pub struct BooleanFlagValueQueryCXX {
+        pub query_success: bool,
+        pub error_message: String,
+        pub flag_value: bool,
+    }
+
+    // Rust export to c++
+    extern "Rust" {
+        pub fn get_package_offset_cxx_impl(
+            pb_file: &str,
+            container: &str,
+            package: &str,
+        ) -> PackageOffsetQueryCXX;
+
+        pub fn get_flag_offset_cxx_impl(
+            pb_file: &str,
+            container: &str,
+            package_id: u32,
+            flag: &str,
+        ) -> FlagOffsetQueryCXX;
+
+        pub fn get_boolean_flag_value_cxx_impl(
+            pb_file: &str,
+            container: &str,
+            offset: u32,
+        ) -> BooleanFlagValueQueryCXX;
+
+        pub fn get_package_offset_cxx(container: &str, package: &str) -> PackageOffsetQueryCXX;
+
+        pub fn get_flag_offset_cxx(
+            container: &str,
+            package_id: u32,
+            flag: &str,
+        ) -> FlagOffsetQueryCXX;
+
+        pub fn get_boolean_flag_value_cxx(container: &str, offset: u32)
+            -> BooleanFlagValueQueryCXX;
+    }
+}
+
+/// Get package start offset impl cc interlop
+pub fn get_package_offset_cxx_impl(
+    pb_file: &str,
+    container: &str,
+    package: &str,
+) -> ffi::PackageOffsetQueryCXX {
+    ffi::PackageOffsetQueryCXX::new(get_package_offset_impl(pb_file, container, package))
+}
+
+/// Get flag start offset impl cc interlop
+pub fn get_flag_offset_cxx_impl(
+    pb_file: &str,
+    container: &str,
+    package_id: u32,
+    flag: &str,
+) -> ffi::FlagOffsetQueryCXX {
+    ffi::FlagOffsetQueryCXX::new(get_flag_offset_impl(pb_file, container, package_id, flag))
+}
+
+/// Get boolean flag value impl cc interlop
+pub fn get_boolean_flag_value_cxx_impl(
+    pb_file: &str,
+    container: &str,
+    offset: u32,
+) -> ffi::BooleanFlagValueQueryCXX {
+    ffi::BooleanFlagValueQueryCXX::new(get_boolean_flag_value_impl(pb_file, container, offset))
+}
+
+/// Get package start offset cc interlop
+pub fn get_package_offset_cxx(container: &str, package: &str) -> ffi::PackageOffsetQueryCXX {
+    ffi::PackageOffsetQueryCXX::new(get_package_offset(container, package))
+}
+
+/// Get flag start offset cc interlop
+pub fn get_flag_offset_cxx(
+    container: &str,
+    package_id: u32,
+    flag: &str,
+) -> ffi::FlagOffsetQueryCXX {
+    ffi::FlagOffsetQueryCXX::new(get_flag_offset(container, package_id, flag))
+}
+
+/// Get boolean flag value cc interlop
+pub fn get_boolean_flag_value_cxx(container: &str, offset: u32) -> ffi::BooleanFlagValueQueryCXX {
+    ffi::BooleanFlagValueQueryCXX::new(get_boolean_flag_value(container, offset))
+}
+
+impl ffi::PackageOffsetQueryCXX {
+    pub(crate) fn new(offset_result: Result<Option<PackageOffset>, AconfigStorageError>) -> Self {
+        match offset_result {
+            Ok(offset_opt) => match offset_opt {
+                Some(offset) => Self {
+                    query_success: true,
+                    error_message: String::from(""),
+                    package_exists: true,
+                    package_id: offset.package_id,
+                    boolean_offset: offset.boolean_offset,
+                },
+                None => Self {
+                    query_success: true,
+                    error_message: String::from(""),
+                    package_exists: false,
+                    package_id: 0,
+                    boolean_offset: 0,
+                },
+            },
+            Err(errmsg) => Self {
+                query_success: false,
+                error_message: format!("{:?}", errmsg),
+                package_exists: false,
+                package_id: 0,
+                boolean_offset: 0,
+            },
+        }
+    }
+}
+
+impl ffi::FlagOffsetQueryCXX {
+    pub(crate) fn new(offset_result: Result<Option<FlagOffset>, AconfigStorageError>) -> Self {
+        match offset_result {
+            Ok(offset_opt) => match offset_opt {
+                Some(offset) => Self {
+                    query_success: true,
+                    error_message: String::from(""),
+                    flag_exists: true,
+                    flag_offset: offset,
+                },
+                None => Self {
+                    query_success: true,
+                    error_message: String::from(""),
+                    flag_exists: false,
+                    flag_offset: 0,
+                },
+            },
+            Err(errmsg) => Self {
+                query_success: false,
+                error_message: format!("{:?}", errmsg),
+                flag_exists: false,
+                flag_offset: 0,
+            },
+        }
+    }
+}
+
+impl ffi::BooleanFlagValueQueryCXX {
+    pub(crate) fn new(value_result: Result<bool, AconfigStorageError>) -> Self {
+        match value_result {
+            Ok(value) => {
+                Self { query_success: true, error_message: String::from(""), flag_value: value }
+            }
+            Err(errmsg) => Self {
+                query_success: false,
+                error_message: format!("{:?}", errmsg),
+                flag_value: false,
+            },
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::test_utils::{write_storage_text_to_temp_file, TestStorageFileSet};
+
+    fn create_test_storage_files(read_only: bool) -> TestStorageFileSet {
+        TestStorageFileSet::new(
+            "./tests/package.map",
+            "./tests/flag.map",
+            "./tests/flag.val",
+            read_only,
+        )
+        .unwrap()
+    }
+
+    #[test]
+    // this test point locks down flag package offset query
+    fn test_package_offset_query() {
+        let ro_files = create_test_storage_files(true);
+        let text_proto = format!(
+            r#"
+files {{
+    version: 0
+    container: "system"
+    package_map: "{}"
+    flag_map: "{}"
+    flag_val: "{}"
+    timestamp: 12345
+}}
+"#,
+            ro_files.package_map.name, ro_files.flag_map.name, ro_files.flag_val.name
+        );
+
+        let file = write_storage_text_to_temp_file(&text_proto).unwrap();
+        let file_full_path = file.path().display().to_string();
+        let package_offset = get_package_offset_impl(
+            &file_full_path,
+            "system",
+            "com.android.aconfig.storage.test_1",
+        )
+        .unwrap()
+        .unwrap();
+        let expected_package_offset = PackageOffset { package_id: 0, boolean_offset: 0 };
+        assert_eq!(package_offset, expected_package_offset);
+
+        let package_offset = get_package_offset_impl(
+            &file_full_path,
+            "system",
+            "com.android.aconfig.storage.test_2",
+        )
+        .unwrap()
+        .unwrap();
+        let expected_package_offset = PackageOffset { package_id: 1, boolean_offset: 3 };
+        assert_eq!(package_offset, expected_package_offset);
+
+        let package_offset = get_package_offset_impl(
+            &file_full_path,
+            "system",
+            "com.android.aconfig.storage.test_4",
+        )
+        .unwrap()
+        .unwrap();
+        let expected_package_offset = PackageOffset { package_id: 2, boolean_offset: 6 };
+        assert_eq!(package_offset, expected_package_offset);
+    }
+
+    #[test]
+    // this test point locks down flag offset query
+    fn test_flag_offset_query() {
+        let ro_files = create_test_storage_files(true);
+        let text_proto = format!(
+            r#"
+files {{
+    version: 0
+    container: "system"
+    package_map: "{}"
+    flag_map: "{}"
+    flag_val: "{}"
+    timestamp: 12345
+}}
+"#,
+            ro_files.package_map.name, ro_files.flag_map.name, ro_files.flag_val.name
+        );
+
+        let file = write_storage_text_to_temp_file(&text_proto).unwrap();
+        let file_full_path = file.path().display().to_string();
+        let baseline = vec![
+            (0, "enabled_ro", 1u16),
+            (0, "enabled_rw", 2u16),
+            (1, "disabled_ro", 0u16),
+            (2, "enabled_ro", 1u16),
+            (1, "enabled_fixed_ro", 1u16),
+            (1, "enabled_ro", 2u16),
+            (2, "enabled_fixed_ro", 0u16),
+            (0, "disabled_rw", 0u16),
+        ];
+        for (package_id, flag_name, expected_offset) in baseline.into_iter() {
+            let flag_offset =
+                get_flag_offset_impl(&file_full_path, "system", package_id, flag_name)
+                    .unwrap()
+                    .unwrap();
+            assert_eq!(flag_offset, expected_offset);
+        }
+    }
+
+    #[test]
+    // this test point locks down flag offset query
+    fn test_flag_value_query() {
+        let ro_files = create_test_storage_files(true);
+        let text_proto = format!(
+            r#"
+files {{
+    version: 0
+    container: "system"
+    package_map: "{}"
+    flag_map: "{}"
+    flag_val: "{}"
+    timestamp: 12345
+}}
+"#,
+            ro_files.package_map.name, ro_files.flag_map.name, ro_files.flag_val.name
+        );
+
+        let file = write_storage_text_to_temp_file(&text_proto).unwrap();
+        let file_full_path = file.path().display().to_string();
+        let baseline: Vec<bool> = vec![false; 8];
+        for (offset, expected_value) in baseline.into_iter().enumerate() {
+            let flag_value =
+                get_boolean_flag_value_impl(&file_full_path, "system", offset as u32).unwrap();
+            assert_eq!(flag_value, expected_value);
+        }
+    }
+}
diff --git a/tools/aconfig/aconfig_storage_file/src/mapped_file.rs b/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs
similarity index 100%
rename from tools/aconfig/aconfig_storage_file/src/mapped_file.rs
rename to tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs
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
new file mode 100644
index 0000000..6d2ed5f7
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/src/package_table_query.rs
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+//! package table query module defines the package table file read from mapped bytes
+
+use crate::{AconfigStorageError, FILE_VERSION};
+use aconfig_storage_file::{
+    package_table::PackageTableHeader, package_table::PackageTableNode, read_u32_from_bytes,
+};
+use anyhow::anyhow;
+
+/// Package table query return
+#[derive(PartialEq, Debug)]
+pub struct PackageOffset {
+    pub package_id: u32,
+    pub boolean_offset: u32,
+}
+
+/// Query package id and start offset
+pub fn find_package_offset(
+    buf: &[u8],
+    package: &str,
+) -> Result<Option<PackageOffset>, AconfigStorageError> {
+    let interpreted_header = PackageTableHeader::from_bytes(buf)?;
+    if interpreted_header.version > FILE_VERSION {
+        return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
+            "Cannot read storage file with a higher version of {} with lib version {}",
+            interpreted_header.version,
+            FILE_VERSION
+        )));
+    }
+
+    let num_buckets = (interpreted_header.node_offset - interpreted_header.bucket_offset) / 4;
+    let bucket_index = PackageTableNode::find_bucket_index(package, num_buckets);
+
+    let mut pos = (interpreted_header.bucket_offset + 4 * bucket_index) as usize;
+    let mut package_node_offset = read_u32_from_bytes(buf, &mut pos)? as usize;
+    if package_node_offset < interpreted_header.node_offset as usize
+        || package_node_offset >= interpreted_header.file_size as usize
+    {
+        return Ok(None);
+    }
+
+    loop {
+        let interpreted_node = PackageTableNode::from_bytes(&buf[package_node_offset..])?;
+        if interpreted_node.package_name == package {
+            return Ok(Some(PackageOffset {
+                package_id: interpreted_node.package_id,
+                boolean_offset: interpreted_node.boolean_offset,
+            }));
+        }
+        match interpreted_node.next_offset {
+            Some(offset) => package_node_offset = offset as usize,
+            None => return Ok(None),
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use aconfig_storage_file::PackageTable;
+
+    pub fn create_test_package_table() -> PackageTable {
+        let header = PackageTableHeader {
+            version: crate::FILE_VERSION,
+            container: String::from("system"),
+            file_size: 208,
+            num_packages: 3,
+            bucket_offset: 30,
+            node_offset: 58,
+        };
+        let buckets: Vec<Option<u32>> = vec![Some(58), None, None, Some(108), None, None, None];
+        let first_node = PackageTableNode {
+            package_name: String::from("com.android.aconfig.storage.test_2"),
+            package_id: 1,
+            boolean_offset: 3,
+            next_offset: None,
+        };
+        let second_node = PackageTableNode {
+            package_name: String::from("com.android.aconfig.storage.test_1"),
+            package_id: 0,
+            boolean_offset: 0,
+            next_offset: Some(158),
+        };
+        let third_node = PackageTableNode {
+            package_name: String::from("com.android.aconfig.storage.test_4"),
+            package_id: 2,
+            boolean_offset: 6,
+            next_offset: None,
+        };
+        let nodes = vec![first_node, second_node, third_node];
+        PackageTable { header, buckets, nodes }
+    }
+
+    #[test]
+    // this test point locks down table query
+    fn test_package_query() {
+        let package_table = create_test_package_table().as_bytes();
+        let package_offset =
+            find_package_offset(&package_table[..], "com.android.aconfig.storage.test_1")
+                .unwrap()
+                .unwrap();
+        let expected_package_offset = PackageOffset { package_id: 0, boolean_offset: 0 };
+        assert_eq!(package_offset, expected_package_offset);
+        let package_offset =
+            find_package_offset(&package_table[..], "com.android.aconfig.storage.test_2")
+                .unwrap()
+                .unwrap();
+        let expected_package_offset = PackageOffset { package_id: 1, boolean_offset: 3 };
+        assert_eq!(package_offset, expected_package_offset);
+        let package_offset =
+            find_package_offset(&package_table[..], "com.android.aconfig.storage.test_4")
+                .unwrap()
+                .unwrap();
+        let expected_package_offset = PackageOffset { package_id: 2, boolean_offset: 6 };
+        assert_eq!(package_offset, expected_package_offset);
+    }
+
+    #[test]
+    // 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_offset =
+            find_package_offset(&package_table[..], "com.android.aconfig.storage.test_3").unwrap();
+        assert_eq!(package_offset, None);
+        // this will land at the end of a linked list
+        let package_offset =
+            find_package_offset(&package_table[..], "com.android.aconfig.storage.test_5").unwrap();
+        assert_eq!(package_offset, None);
+    }
+
+    #[test]
+    // this test point locks down query error when file has a higher version
+    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 error = find_package_offset(&package_table[..], "com.android.aconfig.storage.test_1")
+            .unwrap_err();
+        assert_eq!(
+            format!("{:?}", error),
+            format!(
+                "HigherStorageFileVersion(Cannot read storage file with a higher version of {} with lib version {})",
+                crate::FILE_VERSION + 1,
+                crate::FILE_VERSION
+            )
+        );
+    }
+}
diff --git a/tools/aconfig/aconfig_storage_file/src/protos.rs b/tools/aconfig/aconfig_storage_read_api/src/protos.rs
similarity index 100%
rename from tools/aconfig/aconfig_storage_file/src/protos.rs
rename to tools/aconfig/aconfig_storage_read_api/src/protos.rs
diff --git a/tools/aconfig/aconfig_storage_file/src/test_utils.rs b/tools/aconfig/aconfig_storage_read_api/src/test_utils.rs
similarity index 100%
rename from tools/aconfig/aconfig_storage_file/src/test_utils.rs
rename to tools/aconfig/aconfig_storage_read_api/src/test_utils.rs
diff --git a/tools/aconfig/aconfig_storage_file/tests/Android.bp b/tools/aconfig/aconfig_storage_read_api/tests/Android.bp
similarity index 71%
rename from tools/aconfig/aconfig_storage_file/tests/Android.bp
rename to tools/aconfig/aconfig_storage_read_api/tests/Android.bp
index b951273..0bfc7bf 100644
--- a/tools/aconfig/aconfig_storage_file/tests/Android.bp
+++ b/tools/aconfig/aconfig_storage_read_api/tests/Android.bp
@@ -1,11 +1,11 @@
 rust_test {
-    name: "aconfig_storage.test.rust",
+    name: "aconfig_storage_read_api.test.rust",
     srcs: [
-        "storage_lib_rust_test.rs"
+        "storage_read_api_test.rs"
     ],
     rustlibs: [
         "libanyhow",
-        "libaconfig_storage_file",
+        "libaconfig_storage_read_api",
         "libprotobuf",
         "libtempfile",
     ],
@@ -18,15 +18,15 @@
 }
 
 cc_test {
-    name: "aconfig_storage.test.cpp",
+    name: "aconfig_storage_read_api.test.cpp",
     srcs: [
-        "storage_lib_cc_test.cpp",
+        "storage_read_api_test.cpp",
     ],
     static_libs: [
         "libgmock",
         "libaconfig_storage_protos_cc",
         "libprotobuf-cpp-lite",
-        "libaconfig_storage_cc",
+        "libaconfig_storage_read_api_cc",
         "libbase",
         "liblog",
     ],
diff --git a/tools/aconfig/aconfig_storage_file/tests/flag.map b/tools/aconfig/aconfig_storage_read_api/tests/flag.map
similarity index 100%
rename from tools/aconfig/aconfig_storage_file/tests/flag.map
rename to tools/aconfig/aconfig_storage_read_api/tests/flag.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_file/tests/flag.val b/tools/aconfig/aconfig_storage_read_api/tests/flag.val
similarity index 100%
rename from tools/aconfig/aconfig_storage_file/tests/flag.val
rename to tools/aconfig/aconfig_storage_read_api/tests/flag.val
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_file/tests/package.map b/tools/aconfig/aconfig_storage_read_api/tests/package.map
similarity index 100%
rename from tools/aconfig/aconfig_storage_file/tests/package.map
rename to tools/aconfig/aconfig_storage_read_api/tests/package.map
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_file/tests/storage_lib_cc_test.cpp b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp
similarity index 98%
rename from tools/aconfig/aconfig_storage_file/tests/storage_lib_cc_test.cpp
rename to tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp
index 7d5ba0a..b605646 100644
--- a/tools/aconfig/aconfig_storage_file/tests/storage_lib_cc_test.cpp
+++ b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.cpp
@@ -17,7 +17,7 @@
 #include <string>
 #include <vector>
 
-#include "aconfig_storage/aconfig_storage.hpp"
+#include "aconfig_storage/aconfig_storage_read_api.hpp"
 #include <gtest/gtest.h>
 #include <protos/aconfig_storage_metadata.pb.h>
 #include <android-base/file.h>
diff --git a/tools/aconfig/aconfig_storage_file/tests/storage_lib_rust_test.rs b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs
similarity index 98%
rename from tools/aconfig/aconfig_storage_file/tests/storage_lib_rust_test.rs
rename to tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs
index 9916915..9b23ec4 100644
--- a/tools/aconfig/aconfig_storage_file/tests/storage_lib_rust_test.rs
+++ b/tools/aconfig/aconfig_storage_read_api/tests/storage_read_api_test.rs
@@ -1,6 +1,6 @@
 #[cfg(not(feature = "cargo"))]
 mod aconfig_storage_rust_test {
-    use aconfig_storage_file::{
+    use aconfig_storage_read_api::{
         get_boolean_flag_value_impl, get_flag_offset_impl, get_package_offset_impl, PackageOffset,
         ProtoStorageFiles,
     };
diff --git a/tools/aconfig/aflags/src/device_config_source.rs b/tools/aconfig/aflags/src/device_config_source.rs
index 12a62cf..1cea6ed 100644
--- a/tools/aconfig/aflags/src/device_config_source.rs
+++ b/tools/aconfig/aflags/src/device_config_source.rs
@@ -64,7 +64,7 @@
 fn read_pb_files() -> Result<Vec<Flag>> {
     let mut flags: BTreeMap<String, Flag> = BTreeMap::new();
     for partition in ["system", "system_ext", "product", "vendor"] {
-        let path = format!("/{}/etc/aconfig_flags.pb", partition);
+        let path = format!("/{partition}/etc/aconfig_flags.pb");
         let Ok(bytes) = fs::read(&path) else {
             eprintln!("warning: failed to read {}", path);
             continue;
@@ -98,11 +98,13 @@
     Ok(flags)
 }
 
-fn read_device_config_output(command: &str) -> Result<String> {
-    let output = Command::new("/system/bin/device_config").arg(command).output()?;
+fn read_device_config_output(command: &[&str]) -> Result<String> {
+    let output = Command::new("/system/bin/device_config").args(command).output()?;
     if !output.status.success() {
         let reason = match output.status.code() {
-            Some(code) => format!("exit code {}", code),
+            Some(code) => {
+                format!("exit code {}, output was {}", code, str::from_utf8(&output.stdout)?)
+            }
             None => "terminated by signal".to_string(),
         };
         bail!("failed to execute device_config: {}", reason);
@@ -111,7 +113,7 @@
 }
 
 fn read_device_config_flags() -> Result<HashMap<String, String>> {
-    let list_output = read_device_config_output("list")?;
+    let list_output = read_device_config_output(&["list"])?;
     parse_device_config(&list_output)
 }
 
@@ -145,6 +147,10 @@
         let flags = reconcile(&pb_flags, dc_flags);
         Ok(flags)
     }
+
+    fn override_flag(namespace: &str, qualified_name: &str, value: &str) -> Result<()> {
+        read_device_config_output(&["put", namespace, qualified_name, value]).map(|_| ())
+    }
 }
 
 #[cfg(test)]
diff --git a/tools/aconfig/aflags/src/main.rs b/tools/aconfig/aflags/src/main.rs
index 1e2a7a0..ef0195f 100644
--- a/tools/aconfig/aflags/src/main.rs
+++ b/tools/aconfig/aflags/src/main.rs
@@ -16,7 +16,7 @@
 
 //! `aflags` is a device binary to read and write aconfig flags.
 
-use anyhow::Result;
+use anyhow::{anyhow, Result};
 use clap::Parser;
 
 mod device_config_source;
@@ -63,8 +63,15 @@
     value_picked_from: ValuePickedFrom,
 }
 
+impl Flag {
+    fn qualified_name(&self) -> String {
+        format!("{}.{}", self.package, self.name)
+    }
+}
+
 trait FlagSource {
     fn list_flags() -> Result<Vec<Flag>>;
+    fn override_flag(namespace: &str, qualified_name: &str, value: &str) -> Result<()>;
 }
 
 const ABOUT_TEXT: &str = "Tool for reading and writing flags.
@@ -94,6 +101,18 @@
 enum Command {
     /// List all aconfig flags on this device.
     List,
+
+    /// Enable an aconfig flag on this device, on the next boot.
+    Enable {
+        /// <package>.<flag_name>
+        qualified_name: String,
+    },
+
+    /// Disable an aconfig flag on this device, on the next boot.
+    Disable {
+        /// <package>.<flag_name>
+        qualified_name: String,
+    },
 }
 
 struct PaddingInfo {
@@ -125,6 +144,23 @@
     format!("{pkg:p0$}{name:p1$}{val:p2$}{value_picked_from:p3$}{perm:p4$}{container}\n")
 }
 
+fn set_flag(qualified_name: &str, value: &str) -> Result<()> {
+    let flags_binding = DeviceConfigSource::list_flags()?;
+    let flag = flags_binding.iter().find(|f| f.qualified_name() == qualified_name).ok_or(
+        anyhow!("no aconfig flag '{qualified_name}'. Does the flag have an .aconfig definition?"),
+    )?;
+
+    if let FlagPermission::ReadOnly = flag.permission {
+        return Err(anyhow!(
+            "could not write flag '{qualified_name}', it is read-only for the current release configuration.",
+        ));
+    }
+
+    DeviceConfigSource::override_flag(&flag.namespace, qualified_name, value)?;
+
+    Ok(())
+}
+
 fn list() -> Result<String> {
     let flags = DeviceConfigSource::list_flags()?;
     let padding_info = PaddingInfo {
@@ -154,10 +190,13 @@
 fn main() {
     let cli = Cli::parse();
     let output = match cli.command {
-        Command::List => list(),
+        Command::List => list().map(Some),
+        Command::Enable { qualified_name } => set_flag(&qualified_name, "true").map(|_| None),
+        Command::Disable { qualified_name } => set_flag(&qualified_name, "false").map(|_| None),
     };
     match output {
-        Ok(text) => println!("{text}"),
-        Err(msg) => println!("Error: {}", msg),
+        Ok(Some(text)) => println!("{text}"),
+        Ok(None) => (),
+        Err(message) => println!("Error: {message}"),
     }
 }
diff --git a/tools/aconfig/printflags/src/main.rs b/tools/aconfig/printflags/src/main.rs
index a0c9ee8..7838b51 100644
--- a/tools/aconfig/printflags/src/main.rs
+++ b/tools/aconfig/printflags/src/main.rs
@@ -67,9 +67,23 @@
     let device_config_flags = parse_device_config(dc_stdout);
 
     // read aconfig_flags.pb files
+    let apex_pattern = Regex::new(r"^/apex/[^@]+\.[^@]+$").unwrap();
+    let mut mount_points = vec![
+        "system".to_string(),
+        "system_ext".to_string(),
+        "product".to_string(),
+        "vendor".to_string(),
+    ];
+    for apex in fs::read_dir("/apex")? {
+        let path_name = apex?.path().display().to_string();
+        if let Some(canonical_path) = apex_pattern.captures(&path_name) {
+            mount_points.push(canonical_path.get(0).unwrap().as_str().to_owned());
+        }
+    }
+
     let mut flags: BTreeMap<String, Vec<String>> = BTreeMap::new();
-    for partition in ["system", "system_ext", "product", "vendor"] {
-        let path = format!("/{}/etc/aconfig_flags.pb", partition);
+    for mount_point in mount_points {
+        let path = format!("/{}/etc/aconfig_flags.pb", mount_point);
         let Ok(bytes) = fs::read(&path) else {
             eprintln!("warning: failed to read {}", path);
             continue;
@@ -80,7 +94,7 @@
             })?;
         for flag in parsed_flags.parsed_flag {
             let key = format!("{}/{}.{}", flag.namespace(), flag.package(), flag.name());
-            let value = format!("{:?} + {:?} ({})", flag.permission(), flag.state(), partition);
+            let value = format!("{:?} + {:?} ({})", flag.permission(), flag.state(), mount_point);
             flags.entry(key).or_default().push(value);
         }
     }
diff --git a/tools/fs_config/Android.bp b/tools/fs_config/Android.bp
index 55fdca4..bd9543a 100644
--- a/tools/fs_config/Android.bp
+++ b/tools/fs_config/Android.bp
@@ -35,7 +35,6 @@
     srcs: ["fs_config.c"],
     shared_libs: [
         "libcutils",
-        "libselinux",
     ],
     cflags: ["-Werror"],
 }
diff --git a/tools/fs_config/fs_config.c b/tools/fs_config/fs_config.c
index 2a75add..80bd3c1 100644
--- a/tools/fs_config/fs_config.c
+++ b/tools/fs_config/fs_config.c
@@ -22,9 +22,6 @@
 #include <string.h>
 #include <inttypes.h>
 
-#include <selinux/selinux.h>
-#include <selinux/label.h>
-
 #include "private/android_filesystem_config.h"
 #include "private/fs_config.h"
 
@@ -35,8 +32,8 @@
 //
 // After the first 4 columns, optional key=value pairs are emitted
 // for each file.  Currently, the following keys are supported:
-// * -S: selabel=[selinux_label]
-// * -C: capabilities=[hex capabilities value]
+//
+//   -C: capabilities=[hex capabilities value]
 //
 // Example input:
 //
@@ -48,45 +45,24 @@
 //      system/etc/dbus.conf 1002 1002 440
 //      data/app 1000 1000 771
 //
-//   or if, for example, -S is used:
-//
-//      system/etc/dbus.conf 1002 1002 440 selabel=u:object_r:system_file:s0
-//      data/app 1000 1000 771 selabel=u:object_r:apk_data_file:s0
-//
 // Note that the output will omit the trailing slash from
 // directories.
 
-static struct selabel_handle* get_sehnd(const char* context_file) {
-  struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, context_file } };
-  struct selabel_handle* sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
-
-  if (!sehnd) {
-    perror("error running selabel_open");
-    exit(EXIT_FAILURE);
-  }
-  return sehnd;
-}
-
 static void usage() {
-  fprintf(stderr, "Usage: fs_config [-D product_out_path] [-S context_file] [-R root] [-C]\n");
+  fprintf(stderr, "Usage: fs_config [-D product_out_path] [-R root] [-C]\n");
 }
 
 int main(int argc, char** argv) {
   char buffer[1024];
-  const char* context_file = NULL;
   const char* product_out_path = NULL;
   char* root_path = NULL;
-  struct selabel_handle* sehnd = NULL;
   int print_capabilities = 0;
   int opt;
-  while((opt = getopt(argc, argv, "CS:R:D:")) != -1) {
+  while((opt = getopt(argc, argv, "CR:D:")) != -1) {
     switch(opt) {
     case 'C':
       print_capabilities = 1;
       break;
-    case 'S':
-      context_file = optarg;
-      break;
     case 'R':
       root_path = optarg;
       break;
@@ -99,10 +75,6 @@
     }
   }
 
-  if (context_file != NULL) {
-    sehnd = get_sehnd(context_file);
-  }
-
   if (root_path != NULL) {
     size_t root_len = strlen(root_path);
     /* Trim any trailing slashes from the root path. */
@@ -141,33 +113,6 @@
     }
     printf("%s %d %d %o", buffer, uid, gid, mode);
 
-    if (sehnd != NULL) {
-      size_t buffer_strlen = strnlen(buffer, sizeof(buffer));
-      if (buffer_strlen >= sizeof(buffer)) {
-        fprintf(stderr, "non null terminated buffer, aborting\n");
-        exit(EXIT_FAILURE);
-      }
-      size_t full_name_size = buffer_strlen + 2;
-      char* full_name = (char*) malloc(full_name_size);
-      if (full_name == NULL) {
-        perror("malloc");
-        exit(EXIT_FAILURE);
-      }
-
-      full_name[0] = '/';
-      strncpy(full_name + 1, buffer, full_name_size - 1);
-      full_name[full_name_size - 1] = '\0';
-
-      char* secontext;
-      if (selabel_lookup(sehnd, &secontext, full_name, ( mode | (is_dir ? S_IFDIR : S_IFREG)))) {
-        secontext = strdup("u:object_r:unlabeled:s0");
-      }
-
-      printf(" selabel=%s", secontext);
-      free(full_name);
-      freecon(secontext);
-    }
-
     if (print_capabilities) {
       printf(" capabilities=0x%" PRIx64, capabilities);
     }
diff --git a/tools/ide_query/cc_analyzer/Android.bp b/tools/ide_query/cc_analyzer/Android.bp
new file mode 100644
index 0000000..3cbbb05
--- /dev/null
+++ b/tools/ide_query/cc_analyzer/Android.bp
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_defaults {
+    name: "ide_query_cc_analyzer_defaults",
+    compile_multilib: "64",
+    defaults: [
+        "llvm-build-host-tools-defaults",
+    ],
+    cflags: [
+        // LLVM Sources do have unused parameters :(
+        "-Wno-unused-parameter",
+    ],
+    target: {
+        host: {
+            cppflags: [
+                "-fno-rtti",
+            ],
+        },
+    },
+}
+
+cc_library_host_static {
+    name: "builtin_headers",
+    srcs: ["builtin_headers.cc"],
+    generated_headers: ["clang_builtin_headers_resources"],
+    defaults: ["ide_query_cc_analyzer_defaults"],
+}
+
+cc_library_host_static {
+    name: "include_scanner",
+    srcs: ["include_scanner.cc"],
+    shared_libs: ["libclang-cpp_host"],
+    static_libs: ["builtin_headers"],
+    defaults: ["ide_query_cc_analyzer_defaults"],
+}
+
+cc_library_host_static {
+    name: "analyzer",
+    srcs: ["analyzer.cc"],
+    shared_libs: ["libclang-cpp_host"],
+    static_libs: [
+        "include_scanner",
+        "ide_query_proto",
+    ],
+    defaults: ["ide_query_cc_analyzer_defaults"],
+}
+
+cc_binary_host {
+    name: "ide_query_cc_analyzer",
+    defaults: ["ide_query_cc_analyzer_defaults"],
+    srcs: ["main.cc"],
+    shared_libs: [
+        "libclang-cpp_host",
+        "libprotobuf-cpp-full",
+    ],
+    static_libs: [
+        "ide_query_proto",
+        "builtin_headers",
+        "include_scanner",
+        "analyzer",
+    ],
+}
diff --git a/tools/ide_query/cc_analyzer/analyzer.cc b/tools/ide_query/cc_analyzer/analyzer.cc
new file mode 100644
index 0000000..8cc07e8
--- /dev/null
+++ b/tools/ide_query/cc_analyzer/analyzer.cc
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+#include "analyzer.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/JSONCompilationDatabase.h"
+#include "ide_query.pb.h"
+#include "include_scanner.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/VirtualFileSystem.h"
+
+namespace tools::ide_query::cc_analyzer {
+namespace {
+llvm::Expected<std::unique_ptr<clang::tooling::CompilationDatabase>> LoadCompDB(
+    llvm::StringRef comp_db_path) {
+  std::string err;
+  std::unique_ptr<clang::tooling::CompilationDatabase> db =
+      clang::tooling::JSONCompilationDatabase::loadFromFile(
+          comp_db_path, err, clang::tooling::JSONCommandLineSyntax::AutoDetect);
+  if (!db) {
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "Failed to load CDB: " + err);
+  }
+  // Provide some heuristic support for missing files.
+  return inferMissingCompileCommands(std::move(db));
+}
+}  // namespace
+
+::ide_query::DepsResponse GetDeps(::ide_query::RepoState state) {
+  ::ide_query::DepsResponse results;
+  auto db = LoadCompDB(state.comp_db_path());
+  if (!db) {
+    results.mutable_status()->set_code(::ide_query::Status::FAILURE);
+    results.mutable_status()->set_message(llvm::toString(db.takeError()));
+    return results;
+  }
+  for (llvm::StringRef active_file : state.active_file_path()) {
+    auto& result = *results.add_deps();
+
+    llvm::SmallString<256> abs_file(state.repo_dir());
+    llvm::sys::path::append(abs_file, active_file);
+    auto cmds = db->get()->getCompileCommands(active_file);
+    if (cmds.empty()) {
+      result.mutable_status()->set_code(::ide_query::Status::FAILURE);
+      result.mutable_status()->set_message(
+          llvm::Twine("Can't find compile flags for file: ", abs_file).str());
+      continue;
+    }
+    result.set_source_file(active_file.str());
+    llvm::StringRef file = cmds[0].Filename;
+    if (llvm::StringRef actual_file(cmds[0].Heuristic);
+        actual_file.consume_front("inferred from ")) {
+      file = actual_file;
+    }
+    // TODO: Query ninja graph to figure out a minimal set of targets to build.
+    result.add_build_target(file.str() + "^");
+  }
+  return results;
+}
+
+::ide_query::IdeAnalysis GetBuildInputs(::ide_query::RepoState state) {
+  auto db = LoadCompDB(state.comp_db_path());
+  ::ide_query::IdeAnalysis results;
+  if (!db) {
+    results.mutable_status()->set_code(::ide_query::Status::FAILURE);
+    results.mutable_status()->set_message(llvm::toString(db.takeError()));
+    return results;
+  }
+  std::string repo_dir = state.repo_dir();
+  if (!repo_dir.empty() && repo_dir.back() == '/') repo_dir.pop_back();
+
+  llvm::SmallString<256> genfile_root_abs(repo_dir);
+  llvm::sys::path::append(genfile_root_abs, state.out_dir());
+  if (genfile_root_abs.empty() || genfile_root_abs.back() != '/') {
+    genfile_root_abs.push_back('/');
+  }
+
+  results.set_build_artifact_root(state.out_dir());
+  for (llvm::StringRef active_file : state.active_file_path()) {
+    auto& result = *results.add_sources();
+    result.set_path(active_file.str());
+
+    llvm::SmallString<256> abs_file(repo_dir);
+    llvm::sys::path::append(abs_file, active_file);
+    auto cmds = db->get()->getCompileCommands(abs_file);
+    if (cmds.empty()) {
+      result.mutable_status()->set_code(::ide_query::Status::FAILURE);
+      result.mutable_status()->set_message(
+          llvm::Twine("Can't find compile flags for file: ", abs_file).str());
+      continue;
+    }
+    const auto& cmd = cmds.front();
+    llvm::StringRef working_dir = cmd.Directory;
+    if (!working_dir.consume_front(repo_dir)) {
+      result.mutable_status()->set_code(::ide_query::Status::FAILURE);
+      result.mutable_status()->set_message("Command working dir " +
+                                           working_dir.str() +
+                                           "outside repository " + repo_dir);
+      continue;
+    }
+    working_dir = working_dir.ltrim('/');
+    result.set_working_dir(working_dir.str());
+    for (auto& arg : cmd.CommandLine) result.add_compiler_arguments(arg);
+
+    auto includes =
+        ScanIncludes(cmds.front(), llvm::vfs::createPhysicalFileSystem());
+    if (!includes) {
+      result.mutable_status()->set_code(::ide_query::Status::FAILURE);
+      result.mutable_status()->set_message(
+          llvm::toString(includes.takeError()));
+      continue;
+    }
+
+    for (auto& [req_input, contents] : *includes) {
+      llvm::StringRef req_input_ref(req_input);
+      // We're only interested in generated files.
+      if (!req_input_ref.consume_front(genfile_root_abs)) continue;
+      auto& genfile = *result.add_generated();
+      genfile.set_path(req_input_ref.str());
+      genfile.set_contents(std::move(contents));
+    }
+  }
+  return results;
+}
+}  // namespace tools::ide_query::cc_analyzer
diff --git a/tools/ide_query/cc_analyzer/analyzer.h b/tools/ide_query/cc_analyzer/analyzer.h
new file mode 100644
index 0000000..3133795
--- /dev/null
+++ b/tools/ide_query/cc_analyzer/analyzer.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef _TOOLS_IDE_QUERY_CC_ANALYZER_ANALYZER_H_
+#define _TOOLS_IDE_QUERY_CC_ANALYZER_ANALYZER_H_
+
+#include "ide_query.pb.h"
+
+namespace tools::ide_query::cc_analyzer {
+
+// Scans the build graph and returns target names from the build graph to
+// generate all the dependencies for the active files.
+::ide_query::DepsResponse GetDeps(::ide_query::RepoState state);
+
+// Scans the sources and returns all the source files required for analyzing the
+// active files.
+::ide_query::IdeAnalysis GetBuildInputs(::ide_query::RepoState state);
+
+}  // namespace tools::ide_query::cc_analyzer
+
+#endif
diff --git a/tools/ide_query/cc_analyzer/builtin_headers.cc b/tools/ide_query/cc_analyzer/builtin_headers.cc
new file mode 100644
index 0000000..6d44ce7
--- /dev/null
+++ b/tools/ide_query/cc_analyzer/builtin_headers.cc
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+#include "builtin_headers.h"
+
+#include <cstddef>
+
+#include "clang_builtin_headers_resources.inc"
+
+const struct FileToc *builtin_headers_create() { return kPackedFiles; }
+size_t builtin_headers_size() {
+  return sizeof(kPackedFiles) / sizeof(FileToc) - 1;
+}
diff --git a/tools/ide_query/cc_analyzer/builtin_headers.h b/tools/ide_query/cc_analyzer/builtin_headers.h
new file mode 100644
index 0000000..eda722f
--- /dev/null
+++ b/tools/ide_query/cc_analyzer/builtin_headers.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _TOOLS_IDE_QUERY_CC_ANALYZER_BUILTIN_HEADERS_H_
+#define _TOOLS_IDE_QUERY_CC_ANALYZER_BUILTIN_HEADERS_H_
+
+#include <cstddef>
+
+struct FileToc {
+  const char *name;
+  const char *data;
+};
+
+const struct FileToc *builtin_headers_create();
+size_t builtin_headers_size();
+
+#endif
diff --git a/tools/ide_query/cc_analyzer/include_scanner.cc b/tools/ide_query/cc_analyzer/include_scanner.cc
new file mode 100644
index 0000000..8916a3e
--- /dev/null
+++ b/tools/ide_query/cc_analyzer/include_scanner.cc
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+#include "include_scanner.h"
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include "builtin_headers.h"
+#include "clang/Basic/FileEntry.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/Module.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Tooling/ArgumentsAdjusters.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/VirtualFileSystem.h"
+
+namespace tools::ide_query::cc_analyzer {
+namespace {
+std::string CleanPath(llvm::StringRef path) {
+  // both ./ and ../ has `./` in them.
+  if (!path.contains("./")) return path.str();
+  llvm::SmallString<256> clean_path(path);
+  llvm::sys::path::remove_dots(clean_path, /*remove_dot_dot=*/true);
+  return clean_path.str().str();
+}
+
+// Returns the absolute path to file_name, treating it as relative to cwd if it
+// isn't already absolute.
+std::string GetAbsolutePath(llvm::StringRef cwd, llvm::StringRef file_name) {
+  if (llvm::sys::path::is_absolute(file_name)) return CleanPath(file_name);
+  llvm::SmallString<256> abs_path(cwd);
+  llvm::sys::path::append(abs_path, file_name);
+  llvm::sys::path::remove_dots(abs_path, /*remove_dot_dot=*/true);
+  return abs_path.str().str();
+}
+
+class IncludeRecordingPP : public clang::PPCallbacks {
+ public:
+  explicit IncludeRecordingPP(
+      std::unordered_map<std::string, std::string> &abs_paths, std::string cwd,
+      const clang::SourceManager &sm)
+      : abs_paths_(abs_paths), cwd_(std::move(cwd)), sm_(sm) {}
+
+  void LexedFileChanged(clang::FileID FID, LexedFileChangeReason Reason,
+                        clang::SrcMgr::CharacteristicKind FileType,
+                        clang::FileID PrevFID,
+                        clang::SourceLocation Loc) override {
+    auto file_entry = sm_.getFileEntryRefForID(FID);
+    if (!file_entry) return;
+    auto abs_path = GetAbsolutePath(cwd_, file_entry->getName());
+    auto [it, inserted] = abs_paths_.try_emplace(abs_path);
+    if (inserted) it->second = sm_.getBufferData(FID);
+  }
+
+  std::unordered_map<std::string, std::string> &abs_paths_;
+  const std::string cwd_;
+  const clang::SourceManager &sm_;
+};
+
+class IncludeScanningAction final : public clang::PreprocessOnlyAction {
+ public:
+  explicit IncludeScanningAction(
+      std::unordered_map<std::string, std::string> &abs_paths)
+      : abs_paths_(abs_paths) {}
+  bool BeginSourceFileAction(clang::CompilerInstance &ci) override {
+    std::string cwd;
+    auto cwd_or_err = ci.getVirtualFileSystem().getCurrentWorkingDirectory();
+    if (!cwd_or_err || cwd_or_err.get().empty()) return false;
+    cwd = cwd_or_err.get();
+    ci.getPreprocessor().addPPCallbacks(std::make_unique<IncludeRecordingPP>(
+        abs_paths_, std::move(cwd), ci.getSourceManager()));
+    return true;
+  }
+
+ private:
+  std::unordered_map<std::string, std::string> &abs_paths_;
+};
+
+llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayBuiltinHeaders(
+    std::vector<std::string> &argv,
+    llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> base) {
+  static constexpr llvm::StringLiteral kResourceDir = "/resources";
+  llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> overlay(
+      new llvm::vfs::OverlayFileSystem(std::move(base)));
+  llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> builtin_headers(
+      new llvm::vfs::InMemoryFileSystem);
+
+  llvm::SmallString<256> file_path;
+  for (const auto &builtin_header :
+       llvm::ArrayRef(builtin_headers_create(), builtin_headers_size())) {
+    file_path.clear();
+    llvm::sys::path::append(file_path, kResourceDir, "include",
+                            builtin_header.name);
+    builtin_headers->addFile(
+        file_path,
+        /*ModificationTime=*/0,
+        llvm::MemoryBuffer::getMemBuffer(builtin_header.data));
+  }
+  overlay->pushOverlay(std::move(builtin_headers));
+  argv.insert(llvm::find(argv, "--"),
+              llvm::Twine("-resource-dir=", kResourceDir).str());
+  return overlay;
+}
+
+}  // namespace
+
+llvm::Expected<std::vector<std::pair<std::string, std::string>>> ScanIncludes(
+    const clang::tooling::CompileCommand &cmd,
+    llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs) {
+  if (fs->setCurrentWorkingDirectory(cmd.Directory)) {
+    return llvm::createStringError(
+        llvm::inconvertibleErrorCode(),
+        "Failed to set working directory to: " + cmd.Directory);
+  }
+
+  auto main_file = fs->getBufferForFile(cmd.Filename);
+  if (!main_file) {
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "Main file doesn't exist: " + cmd.Filename);
+  }
+  std::unordered_map<std::string, std::string> abs_paths;
+  abs_paths.try_emplace(GetAbsolutePath(cmd.Directory, cmd.Filename),
+                        main_file.get()->getBuffer().str());
+
+  std::vector<std::string> argv = cmd.CommandLine;
+  fs = OverlayBuiltinHeaders(argv, std::move(fs));
+
+  llvm::IntrusiveRefCntPtr<clang::FileManager> files(
+      new clang::FileManager(/*FileSystemOpts=*/{}, std::move(fs)));
+  clang::tooling::ToolInvocation tool(
+      argv, std::make_unique<IncludeScanningAction>(abs_paths), files.get());
+  if (!tool.run()) {
+    return llvm::createStringError(
+        llvm::inconvertibleErrorCode(),
+        "Failed to scan includes for: " + cmd.Filename);
+  }
+
+  std::vector<std::pair<std::string, std::string>> result;
+  result.reserve(abs_paths.size());
+  for (auto &entry : abs_paths) {
+    result.emplace_back(entry.first, std::move(entry.second));
+  }
+  return result;
+}
+}  // namespace tools::ide_query::cc_analyzer
diff --git a/tools/ide_query/cc_analyzer/include_scanner.h b/tools/ide_query/cc_analyzer/include_scanner.h
new file mode 100644
index 0000000..e814e72
--- /dev/null
+++ b/tools/ide_query/cc_analyzer/include_scanner.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+#ifndef _TOOLS_IDE_QUERY_CC_ANALYZER_INCLUDE_SCANNER_H_
+#define _TOOLS_IDE_QUERY_CC_ANALYZER_INCLUDE_SCANNER_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "clang/Tooling/CompilationDatabase.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/VirtualFileSystem.h"
+
+namespace tools::ide_query::cc_analyzer {
+
+// Returns absolute paths and contents for all the includes necessary for
+// compiling source file in command.
+llvm::Expected<std::vector<std::pair<std::string, std::string>>> ScanIncludes(
+    const clang::tooling::CompileCommand &cmd,
+    llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs);
+
+}  // namespace tools::ide_query::cc_analyzer
+
+#endif
diff --git a/tools/ide_query/cc_analyzer/main.cc b/tools/ide_query/cc_analyzer/main.cc
new file mode 100644
index 0000000..8e00c63
--- /dev/null
+++ b/tools/ide_query/cc_analyzer/main.cc
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+// Driver for c++ extractor. Operates in two modes:
+// - DEPS, scans build graph for active files and reports targets that need to
+// be build for analyzing that file.
+// - INPUTS, scans the source code for active files and returns all the sources
+// required for analyzing that file.
+//
+// Uses stdin/stdout to take in requests and provide responses.
+#include <unistd.h>
+
+#include <memory>
+#include <utility>
+
+#include "analyzer.h"
+#include "google/protobuf/message.h"
+#include "ide_query.pb.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace {
+enum class OpMode {
+  DEPS = 0,
+  INPUTS = 1,
+};
+llvm::cl::opt<OpMode> mode{
+    "mode",
+    llvm::cl::values(clEnumValN(OpMode::DEPS, "deps",
+                                "Figure out targets that need to be build"),
+                     clEnumValN(OpMode::INPUTS, "inputs",
+                                "Figure out generated files used")),
+    llvm::cl::desc("Print the list of headers to insert and remove"),
+};
+
+ide_query::IdeAnalysis ReturnError(llvm::StringRef message) {
+  ide_query::IdeAnalysis result;
+  result.mutable_status()->set_code(ide_query::Status::FAILURE);
+  result.mutable_status()->set_message(message.str());
+  return result;
+}
+
+}  // namespace
+
+int main(int argc, char* argv[]) {
+  llvm::InitializeAllTargetInfos();
+  llvm::cl::ParseCommandLineOptions(argc, argv);
+
+  ide_query::RepoState state;
+  if (!state.ParseFromFileDescriptor(STDIN_FILENO)) {
+    llvm::errs() << "Failed to parse input!\n";
+    return 1;
+  }
+
+  std::unique_ptr<google::protobuf::Message> result;
+  switch (mode) {
+    case OpMode::DEPS: {
+      result = std::make_unique<ide_query::DepsResponse>(
+          tools::ide_query::cc_analyzer::GetDeps(std::move(state)));
+      break;
+    }
+    case OpMode::INPUTS: {
+      result = std::make_unique<ide_query::IdeAnalysis>(
+          tools::ide_query::cc_analyzer::GetBuildInputs(std::move(state)));
+      break;
+    }
+    default:
+      llvm::errs() << "Unknown operation mode!\n";
+      return 1;
+  }
+  if (!result->SerializeToFileDescriptor(STDOUT_FILENO)) {
+    llvm::errs() << "Failed to serialize result!\n";
+    return 1;
+  }
+
+  return 0;
+}
diff --git a/tools/ide_query/ide_query.go b/tools/ide_query/ide_query.go
index c1c4da0..9645a02 100644
--- a/tools/ide_query/ide_query.go
+++ b/tools/ide_query/ide_query.go
@@ -1,8 +1,25 @@
+/*
+ * 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.
+ */
+
 // Binary ide_query generates and analyzes build artifacts.
 // The produced result can be consumed by IDEs to provide language features.
 package main
 
 import (
+	"bytes"
 	"container/list"
 	"context"
 	"encoding/json"
@@ -21,9 +38,13 @@
 
 // Env contains information about the current environment.
 type Env struct {
-	LunchTarget LunchTarget
-	RepoDir     string
-	OutDir      string
+	LunchTarget    LunchTarget
+	RepoDir        string
+	OutDir         string
+	ClangToolsRoot string
+
+	CcFiles   []string
+	JavaFiles []string
 }
 
 // LunchTarget is a parsed Android lunch target.
@@ -64,6 +85,7 @@
 	var env Env
 	env.OutDir = os.Getenv("OUT_DIR")
 	env.RepoDir = os.Getenv("ANDROID_BUILD_TOP")
+	env.ClangToolsRoot = os.Getenv("PREBUILTS_CLANG_TOOLS_ROOT")
 	flag.Var(&env.LunchTarget, "lunch_target", "The lunch target to query")
 	flag.Parse()
 	files := flag.Args()
@@ -73,64 +95,169 @@
 		return
 	}
 
-	var javaFiles []string
 	for _, f := range files {
 		switch {
 		case strings.HasSuffix(f, ".java") || strings.HasSuffix(f, ".kt"):
-			javaFiles = append(javaFiles, f)
+			env.JavaFiles = append(env.JavaFiles, f)
+		case strings.HasSuffix(f, ".cc") || strings.HasSuffix(f, ".cpp") || strings.HasSuffix(f, ".h"):
+			env.CcFiles = append(env.CcFiles, f)
 		default:
 			log.Printf("File %q is supported - will be skipped.", f)
 		}
 	}
 
 	ctx := context.Background()
-	javaDepsPath := path.Join(env.RepoDir, env.OutDir, "soong/module_bp_java_deps.json")
-	// TODO(michaelmerg): Figure out if module_bp_java_deps.json is outdated.
+	// TODO(michaelmerg): Figure out if module_bp_java_deps.json and compile_commands.json is outdated.
 	runMake(ctx, env, "nothing")
 
-	javaModules, err := loadJavaModules(javaDepsPath)
+	javaModules, javaFileToModuleMap, err := loadJavaModules(&env)
 	if err != nil {
-		log.Fatalf("Failed to load java modules: %v", err)
+		log.Printf("Failed to load java modules: %v", err)
+	}
+	toMake := getJavaTargets(javaFileToModuleMap)
+
+	ccTargets, status := getCCTargets(ctx, &env)
+	if status != nil && status.Code != pb.Status_OK {
+		log.Fatalf("Failed to query cc targets: %v", *status.Message)
+	}
+	toMake = append(toMake, ccTargets...)
+	fmt.Printf("Running make for modules: %v\n", strings.Join(toMake, ", "))
+	if err := runMake(ctx, env, toMake...); err != nil {
+		log.Printf("Building deps failed: %v", err)
 	}
 
-	fileToModule := make(map[string]*javaModule) // file path -> module
-	for _, f := range javaFiles {
-		for _, m := range javaModules {
-			if !slices.Contains(m.Srcs, f) {
-				continue
-			}
-			if fileToModule[f] != nil {
-				// TODO(michaelmerg): Handle the case where a file is covered by multiple modules.
-				log.Printf("File %q found in module %q but is already covered by module %q", f, m.Name, fileToModule[f].Name)
-				continue
-			}
-			fileToModule[f] = m
+	res := getJavaInputs(&env, javaModules, javaFileToModuleMap)
+	ccAnalysis := getCCInputs(ctx, &env)
+	proto.Merge(res, ccAnalysis)
+
+	res.BuildArtifactRoot = env.OutDir
+	data, err := proto.Marshal(res)
+	if err != nil {
+		log.Fatalf("Failed to marshal result proto: %v", err)
+	}
+
+	err = os.WriteFile(path.Join(env.RepoDir, env.OutDir, "ide_query.pb"), data, 0644)
+	if err != nil {
+		log.Fatalf("Failed to write result proto: %v", err)
+	}
+
+	for _, s := range res.Sources {
+		fmt.Printf("%s: %v (Deps: %d, Generated: %d)\n", s.GetPath(), s.GetStatus(), len(s.GetDeps()), len(s.GetGenerated()))
+	}
+}
+
+func repoState(env *Env) *pb.RepoState {
+	const compDbPath = "soong/development/ide/compdb/compile_commands.json"
+	return &pb.RepoState{
+		RepoDir:        env.RepoDir,
+		ActiveFilePath: env.CcFiles,
+		OutDir:         env.OutDir,
+		CompDbPath:     path.Join(env.OutDir, compDbPath),
+	}
+}
+
+func runCCanalyzer(ctx context.Context, env *Env, mode string, in []byte) ([]byte, error) {
+	ccAnalyzerPath := path.Join(env.ClangToolsRoot, "bin/ide_query_cc_analyzer")
+	outBuffer := new(bytes.Buffer)
+
+	inBuffer := new(bytes.Buffer)
+	inBuffer.Write(in)
+
+	cmd := exec.CommandContext(ctx, ccAnalyzerPath, "--mode="+mode)
+	cmd.Dir = env.RepoDir
+
+	cmd.Stdin = inBuffer
+	cmd.Stdout = outBuffer
+	cmd.Stderr = os.Stderr
+
+	err := cmd.Run()
+
+	return outBuffer.Bytes(), err
+}
+
+// Execute cc_analyzer and get all the targets that needs to be build for analyzing files.
+func getCCTargets(ctx context.Context, env *Env) ([]string, *pb.Status) {
+	state := repoState(env)
+	bytes, err := proto.Marshal(state)
+	if err != nil {
+		log.Fatalln("Failed to serialize state:", err)
+	}
+
+	resp := new(pb.DepsResponse)
+	result, err := runCCanalyzer(ctx, env, "deps", bytes)
+	if marshal_err := proto.Unmarshal(result, resp); marshal_err != nil {
+		return nil, &pb.Status{
+			Code:    pb.Status_FAILURE,
+			Message: proto.String("Malformed response from cc_analyzer: " + marshal_err.Error()),
 		}
 	}
 
-	var toMake []string
-	for _, m := range fileToModule {
-		toMake = append(toMake, m.Name)
+	var targets []string
+	if resp.Status != nil && resp.Status.Code != pb.Status_OK {
+		return targets, resp.Status
 	}
-	fmt.Printf("Running make for modules: %v\n", strings.Join(toMake, ", "))
-	if err := runMake(ctx, env, toMake...); err != nil {
-		log.Fatalf("Failed to run make: %v", err)
+	for _, deps := range resp.Deps {
+		targets = append(targets, deps.BuildTarget...)
 	}
 
+	status := &pb.Status{Code: pb.Status_OK}
+	if err != nil {
+		status = &pb.Status{
+			Code:    pb.Status_FAILURE,
+			Message: proto.String(err.Error()),
+		}
+	}
+	return targets, status
+}
+
+func getCCInputs(ctx context.Context, env *Env) *pb.IdeAnalysis {
+	state := repoState(env)
+	bytes, err := proto.Marshal(state)
+	if err != nil {
+		log.Fatalln("Failed to serialize state:", err)
+	}
+
+	resp := new(pb.IdeAnalysis)
+	result, err := runCCanalyzer(ctx, env, "inputs", bytes)
+	if marshal_err := proto.Unmarshal(result, resp); marshal_err != nil {
+		resp.Status = &pb.Status{
+			Code:    pb.Status_FAILURE,
+			Message: proto.String("Malformed response from cc_analyzer: " + marshal_err.Error()),
+		}
+		return resp
+	}
+
+	if err != nil && (resp.Status == nil || resp.Status.Code == pb.Status_OK) {
+		resp.Status = &pb.Status{
+			Code:    pb.Status_FAILURE,
+			Message: proto.String(err.Error()),
+		}
+	}
+	return resp
+}
+
+func getJavaTargets(javaFileToModuleMap map[string]*javaModule) []string {
+	var targets []string
+	for _, m := range javaFileToModuleMap {
+		targets = append(targets, m.Name)
+	}
+	return targets
+}
+
+func getJavaInputs(env *Env, javaModules map[string]*javaModule, javaFileToModuleMap map[string]*javaModule) *pb.IdeAnalysis {
 	var sources []*pb.SourceFile
 	type depsAndGenerated struct {
 		Deps      []string
 		Generated []*pb.GeneratedFile
 	}
 	moduleToDeps := make(map[string]*depsAndGenerated)
-	for _, f := range files {
+	for _, f := range env.JavaFiles {
 		file := &pb.SourceFile{
-			Path:       f,
-			WorkingDir: env.RepoDir,
+			Path: f,
 		}
 		sources = append(sources, file)
 
-		m := fileToModule[f]
+		m := javaFileToModuleMap[f]
 		if m == nil {
 			file.Status = &pb.Status{
 				Code:    pb.Status_FAILURE,
@@ -167,24 +294,8 @@
 		file.Generated = generated
 		file.Deps = deps
 	}
-
-	res := &pb.IdeAnalysis{
-		BuildArtifactRoot: env.OutDir,
-		Sources:           sources,
-		Status:            &pb.Status{Code: pb.Status_OK},
-	}
-	data, err := proto.Marshal(res)
-	if err != nil {
-		log.Fatalf("Failed to marshal result proto: %v", err)
-	}
-
-	err = os.WriteFile(path.Join(env.OutDir, "ide_query.pb"), data, 0644)
-	if err != nil {
-		log.Fatalf("Failed to write result proto: %v", err)
-	}
-
-	for _, s := range sources {
-		fmt.Printf("%s: %v (Deps: %d, Generated: %d)\n", s.GetPath(), s.GetStatus(), len(s.GetDeps()), len(s.GetGenerated()))
+	return &pb.IdeAnalysis{
+		Sources: sources,
 	}
 }
 
@@ -214,26 +325,40 @@
 	SrcJars []string `json:"srcjars,omitempty"`
 }
 
-func loadJavaModules(path string) (map[string]*javaModule, error) {
-	data, err := os.ReadFile(path)
+func loadJavaModules(env *Env) (map[string]*javaModule, map[string]*javaModule, error) {
+	javaDepsPath := path.Join(env.RepoDir, env.OutDir, "soong/module_bp_java_deps.json")
+	data, err := os.ReadFile(javaDepsPath)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	var ret map[string]*javaModule // module name -> module
-	if err = json.Unmarshal(data, &ret); err != nil {
-		return nil, err
+	var moduleMapping map[string]*javaModule // module name -> module
+	if err = json.Unmarshal(data, &moduleMapping); err != nil {
+		return nil, nil, err
 	}
 
-	for name, module := range ret {
+	javaModules := make(map[string]*javaModule)
+	javaFileToModuleMap := make(map[string]*javaModule)
+	for name, module := range moduleMapping {
 		if strings.HasSuffix(name, "-jarjar") || strings.HasSuffix(name, ".impl") {
-			delete(ret, name)
 			continue
 		}
-
 		module.Name = name
+		javaModules[name] = module
+		for _, src := range module.Srcs {
+			if !slices.Contains(env.JavaFiles, src) {
+				// We are only interested in active files.
+				continue
+			}
+			if javaFileToModuleMap[src] != nil {
+				// TODO(michaelmerg): Handle the case where a file is covered by multiple modules.
+				log.Printf("File %q found in module %q but is already covered by module %q", src, module.Name, javaFileToModuleMap[src].Name)
+				continue
+			}
+			javaFileToModuleMap[src] = module
+		}
 	}
-	return ret, nil
+	return javaModules, javaFileToModuleMap, nil
 }
 
 func transitiveDeps(m *javaModule, modules map[string]*javaModule) []string {
diff --git a/tools/ide_query/ide_query.sh b/tools/ide_query/ide_query.sh
index 663c4dc..2df48d0 100755
--- a/tools/ide_query/ide_query.sh
+++ b/tools/ide_query/ide_query.sh
@@ -1,5 +1,19 @@
 #!/bin/bash -e
 
+# 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.
+
 cd $(dirname $BASH_SOURCE)
 source $(pwd)/../../shell_utils.sh
 require_top
@@ -7,6 +21,17 @@
 # Ensure cogsetup (out/ will be symlink outside the repo)
 . ${TOP}/build/make/cogsetup.sh
 
+case $(uname -s) in
+    Linux)
+      export PREBUILTS_CLANG_TOOLS_ROOT="${TOP}/prebuilts/clang-tools/linux-x86/"
+      PREBUILTS_GO_ROOT="${TOP}/prebuilts/go/linux-x86/"
+      ;;
+    *)
+      echo "Only supported for linux hosts" >&2
+      exit 1
+      ;;
+esac
+
 export ANDROID_BUILD_TOP=$TOP
 export OUT_DIR=${OUT_DIR}
-exec "${TOP}/prebuilts/go/linux-x86/bin/go" "run" "ide_query" "$@"
+exec "${PREBUILTS_GO_ROOT}/bin/go" "run" "ide_query" "$@"
diff --git a/tools/ide_query/ide_query_proto/Android.bp b/tools/ide_query/ide_query_proto/Android.bp
new file mode 100644
index 0000000..70f15cd
--- /dev/null
+++ b/tools/ide_query/ide_query_proto/Android.bp
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_host_static {
+    name: "ide_query_proto",
+    srcs: [
+        "ide_query.proto",
+    ],
+    proto: {
+        export_proto_headers: true,
+        type: "full",
+        canonical_path_from_root: false,
+    },
+    compile_multilib: "64",
+    shared_libs: ["libprotobuf-cpp-full"],
+}
diff --git a/tools/ide_query/ide_query_proto/ide_query.pb.go b/tools/ide_query/ide_query_proto/ide_query.pb.go
index 30571cc..f3a016d 100644
--- a/tools/ide_query/ide_query_proto/ide_query.pb.go
+++ b/tools/ide_query/ide_query_proto/ide_query.pb.go
@@ -1,6 +1,6 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.30.0
+// 	protoc-gen-go v1.25.0-devel
 // 	protoc        v3.21.12
 // source: ide_query.proto
 
@@ -72,7 +72,7 @@
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	Code Status_Code `protobuf:"varint,1,opt,name=code,proto3,enum=cider.build.companion.Status_Code" json:"code,omitempty"`
+	Code Status_Code `protobuf:"varint,1,opt,name=code,proto3,enum=ide_query.Status_Code" json:"code,omitempty"`
 	// Details about the status, might be displayed to user.
 	Message *string `protobuf:"bytes,2,opt,name=message,proto3,oneof" json:"message,omitempty"`
 }
@@ -123,6 +123,142 @@
 	return ""
 }
 
+// Represents an Android checkout on user's workstation.
+type RepoState struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Absolute path for the checkout in the workstation.
+	// e.g. /home/user/work/android/
+	RepoDir string `protobuf:"bytes,1,opt,name=repo_dir,json=repoDir,proto3" json:"repo_dir,omitempty"`
+	// Relative to repo_dir.
+	ActiveFilePath []string `protobuf:"bytes,2,rep,name=active_file_path,json=activeFilePath,proto3" json:"active_file_path,omitempty"`
+	// Repository relative path to output directory in workstation.
+	OutDir string `protobuf:"bytes,3,opt,name=out_dir,json=outDir,proto3" json:"out_dir,omitempty"`
+	// Repository relative path to compile_commands.json in workstation.
+	CompDbPath string `protobuf:"bytes,4,opt,name=comp_db_path,json=compDbPath,proto3" json:"comp_db_path,omitempty"`
+}
+
+func (x *RepoState) Reset() {
+	*x = RepoState{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_ide_query_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *RepoState) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RepoState) ProtoMessage() {}
+
+func (x *RepoState) ProtoReflect() protoreflect.Message {
+	mi := &file_ide_query_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use RepoState.ProtoReflect.Descriptor instead.
+func (*RepoState) Descriptor() ([]byte, []int) {
+	return file_ide_query_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *RepoState) GetRepoDir() string {
+	if x != nil {
+		return x.RepoDir
+	}
+	return ""
+}
+
+func (x *RepoState) GetActiveFilePath() []string {
+	if x != nil {
+		return x.ActiveFilePath
+	}
+	return nil
+}
+
+func (x *RepoState) GetOutDir() string {
+	if x != nil {
+		return x.OutDir
+	}
+	return ""
+}
+
+func (x *RepoState) GetCompDbPath() string {
+	if x != nil {
+		return x.CompDbPath
+	}
+	return ""
+}
+
+// Provides all the targets that are pre-requisities for running language
+// services on active_file_paths.
+type DepsResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Deps   []*DepsResponse_Deps `protobuf:"bytes,1,rep,name=deps,proto3" json:"deps,omitempty"`
+	Status *Status              `protobuf:"bytes,2,opt,name=status,proto3,oneof" json:"status,omitempty"`
+}
+
+func (x *DepsResponse) Reset() {
+	*x = DepsResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_ide_query_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DepsResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DepsResponse) ProtoMessage() {}
+
+func (x *DepsResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_ide_query_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use DepsResponse.ProtoReflect.Descriptor instead.
+func (*DepsResponse) Descriptor() ([]byte, []int) {
+	return file_ide_query_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *DepsResponse) GetDeps() []*DepsResponse_Deps {
+	if x != nil {
+		return x.Deps
+	}
+	return nil
+}
+
+func (x *DepsResponse) GetStatus() *Status {
+	if x != nil {
+		return x.Status
+	}
+	return nil
+}
+
+// Returns all the information necessary for providing language services for the
+// active files.
 type GeneratedFile struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -130,8 +266,7 @@
 
 	// Path to the file relative to IdeAnalysis.build_artifact_root.
 	Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
-	//	The text of the generated file, if not provided contents will be read
-	//
+	// The text of the generated file, if not provided contents will be read
 	// from the path above in user's workstation.
 	Contents []byte `protobuf:"bytes,2,opt,name=contents,proto3,oneof" json:"contents,omitempty"`
 }
@@ -139,7 +274,7 @@
 func (x *GeneratedFile) Reset() {
 	*x = GeneratedFile{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_ide_query_proto_msgTypes[1]
+		mi := &file_ide_query_proto_msgTypes[3]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -152,7 +287,7 @@
 func (*GeneratedFile) ProtoMessage() {}
 
 func (x *GeneratedFile) ProtoReflect() protoreflect.Message {
-	mi := &file_ide_query_proto_msgTypes[1]
+	mi := &file_ide_query_proto_msgTypes[3]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -165,7 +300,7 @@
 
 // Deprecated: Use GeneratedFile.ProtoReflect.Descriptor instead.
 func (*GeneratedFile) Descriptor() ([]byte, []int) {
-	return file_ide_query_proto_rawDescGZIP(), []int{1}
+	return file_ide_query_proto_rawDescGZIP(), []int{3}
 }
 
 func (x *GeneratedFile) GetPath() string {
@@ -187,11 +322,11 @@
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	// Repo root relative path to the source file in the tree.
+	// Path to the source file relative to repository root.
 	Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
 	// Working directory used by the build system. All the relative
 	// paths in compiler_arguments should be relative to this path.
-	// Relative to workspace root.
+	// Relative to repository root.
 	WorkingDir string `protobuf:"bytes,2,opt,name=working_dir,json=workingDir,proto3" json:"working_dir,omitempty"`
 	// Compiler arguments to compile the source file. If multiple variants
 	// of the module being compiled are possible, the query script will choose
@@ -200,12 +335,12 @@
 	// Any generated files that are used in compiling the file.
 	Generated []*GeneratedFile `protobuf:"bytes,4,rep,name=generated,proto3" json:"generated,omitempty"`
 	// Paths to all of the sources, like build files, code generators,
-	// proto files etc. that were used  during analysis. Used to figure
+	// proto files etc. that were used during analysis. Used to figure
 	// out when a set of build artifacts are stale and the query tool
 	// must be re-run.
-	// Relative to workspace root.
+	// Relative to repository root.
 	Deps []string `protobuf:"bytes,5,rep,name=deps,proto3" json:"deps,omitempty"`
-	// Represensts analysis status for this particular file. e.g. not part
+	// Represents analysis status for this particular file. e.g. not part
 	// of the build graph.
 	Status *Status `protobuf:"bytes,6,opt,name=status,proto3,oneof" json:"status,omitempty"`
 }
@@ -213,7 +348,7 @@
 func (x *SourceFile) Reset() {
 	*x = SourceFile{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_ide_query_proto_msgTypes[2]
+		mi := &file_ide_query_proto_msgTypes[4]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -226,7 +361,7 @@
 func (*SourceFile) ProtoMessage() {}
 
 func (x *SourceFile) ProtoReflect() protoreflect.Message {
-	mi := &file_ide_query_proto_msgTypes[2]
+	mi := &file_ide_query_proto_msgTypes[4]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -239,7 +374,7 @@
 
 // Deprecated: Use SourceFile.ProtoReflect.Descriptor instead.
 func (*SourceFile) Descriptor() ([]byte, []int) {
-	return file_ide_query_proto_rawDescGZIP(), []int{2}
+	return file_ide_query_proto_rawDescGZIP(), []int{4}
 }
 
 func (x *SourceFile) GetPath() string {
@@ -289,21 +424,20 @@
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	// Path relative to workspace root, containing all the artifacts
+	// Path relative to repository root, containing all the artifacts
 	// generated by the build system. GeneratedFile.path are always
 	// relative to this directory.
 	BuildArtifactRoot string        `protobuf:"bytes,1,opt,name=build_artifact_root,json=buildArtifactRoot,proto3" json:"build_artifact_root,omitempty"`
 	Sources           []*SourceFile `protobuf:"bytes,2,rep,name=sources,proto3" json:"sources,omitempty"`
 	// Status representing overall analysis.
-	// Should fail only when no analysis can be performed, e.g. workspace
-	// isn't setup.
+	// Should fail only when no analysis can be performed.
 	Status *Status `protobuf:"bytes,3,opt,name=status,proto3,oneof" json:"status,omitempty"`
 }
 
 func (x *IdeAnalysis) Reset() {
 	*x = IdeAnalysis{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_ide_query_proto_msgTypes[3]
+		mi := &file_ide_query_proto_msgTypes[5]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -316,7 +450,7 @@
 func (*IdeAnalysis) ProtoMessage() {}
 
 func (x *IdeAnalysis) ProtoReflect() protoreflect.Message {
-	mi := &file_ide_query_proto_msgTypes[3]
+	mi := &file_ide_query_proto_msgTypes[5]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -329,7 +463,7 @@
 
 // Deprecated: Use IdeAnalysis.ProtoReflect.Descriptor instead.
 func (*IdeAnalysis) Descriptor() ([]byte, []int) {
-	return file_ide_query_proto_rawDescGZIP(), []int{3}
+	return file_ide_query_proto_rawDescGZIP(), []int{5}
 }
 
 func (x *IdeAnalysis) GetBuildArtifactRoot() string {
@@ -353,58 +487,144 @@
 	return nil
 }
 
+// Build dependencies of a source file for providing language services.
+type DepsResponse_Deps struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Relative to repo_dir.
+	SourceFile string `protobuf:"bytes,1,opt,name=source_file,json=sourceFile,proto3" json:"source_file,omitempty"`
+	// Build target to execute for generating dep.
+	BuildTarget []string `protobuf:"bytes,2,rep,name=build_target,json=buildTarget,proto3" json:"build_target,omitempty"`
+	Status      *Status  `protobuf:"bytes,3,opt,name=status,proto3,oneof" json:"status,omitempty"`
+}
+
+func (x *DepsResponse_Deps) Reset() {
+	*x = DepsResponse_Deps{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_ide_query_proto_msgTypes[6]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *DepsResponse_Deps) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DepsResponse_Deps) ProtoMessage() {}
+
+func (x *DepsResponse_Deps) ProtoReflect() protoreflect.Message {
+	mi := &file_ide_query_proto_msgTypes[6]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use DepsResponse_Deps.ProtoReflect.Descriptor instead.
+func (*DepsResponse_Deps) Descriptor() ([]byte, []int) {
+	return file_ide_query_proto_rawDescGZIP(), []int{2, 0}
+}
+
+func (x *DepsResponse_Deps) GetSourceFile() string {
+	if x != nil {
+		return x.SourceFile
+	}
+	return ""
+}
+
+func (x *DepsResponse_Deps) GetBuildTarget() []string {
+	if x != nil {
+		return x.BuildTarget
+	}
+	return nil
+}
+
+func (x *DepsResponse_Deps) GetStatus() *Status {
+	if x != nil {
+		return x.Status
+	}
+	return nil
+}
+
 var File_ide_query_proto protoreflect.FileDescriptor
 
 var file_ide_query_proto_rawDesc = []byte{
 	0x0a, 0x0f, 0x69, 0x64, 0x65, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74,
-	0x6f, 0x12, 0x15, 0x63, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2e, 0x63,
-	0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x69, 0x6f, 0x6e, 0x22, 0x88, 0x01, 0x0a, 0x06, 0x53, 0x74, 0x61,
-	0x74, 0x75, 0x73, 0x12, 0x36, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x0e, 0x32, 0x22, 0x2e, 0x63, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2e,
-	0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
-	0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x07, 0x6d,
-	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x07,
-	0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x88, 0x01, 0x01, 0x22, 0x1b, 0x0a, 0x04, 0x43, 0x6f,
-	0x64, 0x65, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x46, 0x41,
-	0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x6d, 0x65, 0x73, 0x73,
-	0x61, 0x67, 0x65, 0x22, 0x51, 0x0a, 0x0d, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64,
-	0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74,
-	0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x08, 0x63, 0x6f,
-	0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x63, 0x6f,
-	0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x8f, 0x02, 0x0a, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63,
-	0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x6f, 0x72,
-	0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
-	0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x72, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x6f,
-	0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x5f, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73,
-	0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72,
-	0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x42, 0x0a, 0x09, 0x67, 0x65, 0x6e,
-	0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63,
-	0x69, 0x64, 0x65, 0x72, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x61,
-	0x6e, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x46, 0x69,
-	0x6c, 0x65, 0x52, 0x09, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x12, 0x12, 0x0a,
-	0x04, 0x64, 0x65, 0x70, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x70,
-	0x73, 0x12, 0x3a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28,
-	0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2e,
-	0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
-	0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a,
-	0x07, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xc1, 0x01, 0x0a, 0x0b, 0x49, 0x64, 0x65,
-	0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x62, 0x75, 0x69, 0x6c,
-	0x64, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x41, 0x72, 0x74, 0x69,
-	0x66, 0x61, 0x63, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x3b, 0x0a, 0x07, 0x73, 0x6f, 0x75, 0x72,
-	0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x69, 0x64, 0x65,
-	0x72, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x69, 0x6f,
-	0x6e, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x07, 0x73, 0x6f,
-	0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18,
-	0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x62, 0x75,
-	0x69, 0x6c, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x74,
-	0x61, 0x74, 0x75, 0x73, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x88, 0x01,
-	0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x1b, 0x5a, 0x19,
-	0x69, 0x64, 0x65, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2f, 0x69, 0x64, 0x65, 0x5f, 0x71, 0x75,
-	0x65, 0x72, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x33,
+	0x6f, 0x12, 0x09, 0x69, 0x64, 0x65, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x7c, 0x0a, 0x06,
+	0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2a, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x69, 0x64, 0x65, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79,
+	0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f,
+	0x64, 0x65, 0x12, 0x1d, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x88, 0x01,
+	0x01, 0x22, 0x1b, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10,
+	0x00, 0x12, 0x0b, 0x0a, 0x07, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x01, 0x42, 0x0a,
+	0x0a, 0x08, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x8b, 0x01, 0x0a, 0x09, 0x52,
+	0x65, 0x70, 0x6f, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x65, 0x70, 0x6f,
+	0x5f, 0x64, 0x69, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x70, 0x6f,
+	0x44, 0x69, 0x72, 0x12, 0x28, 0x0a, 0x10, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x66, 0x69,
+	0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x61,
+	0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x17, 0x0a,
+	0x07, 0x6f, 0x75, 0x74, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
+	0x6f, 0x75, 0x74, 0x44, 0x69, 0x72, 0x12, 0x20, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x70, 0x5f, 0x64,
+	0x62, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f,
+	0x6d, 0x70, 0x44, 0x62, 0x50, 0x61, 0x74, 0x68, 0x22, 0x83, 0x02, 0x0a, 0x0c, 0x44, 0x65, 0x70,
+	0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x04, 0x64, 0x65, 0x70,
+	0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x69, 0x64, 0x65, 0x5f, 0x71, 0x75,
+	0x65, 0x72, 0x79, 0x2e, 0x44, 0x65, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x2e, 0x44, 0x65, 0x70, 0x73, 0x52, 0x04, 0x64, 0x65, 0x70, 0x73, 0x12, 0x2e, 0x0a, 0x06, 0x73,
+	0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x69, 0x64,
+	0x65, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x48, 0x00,
+	0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x88, 0x01, 0x01, 0x1a, 0x85, 0x01, 0x0a, 0x04,
+	0x44, 0x65, 0x70, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x66,
+	0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63,
+	0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x74,
+	0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x62, 0x75, 0x69,
+	0x6c, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x2e, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74,
+	0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x69, 0x64, 0x65, 0x5f, 0x71,
+	0x75, 0x65, 0x72, 0x79, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x48, 0x00, 0x52, 0x06, 0x73,
+	0x74, 0x61, 0x74, 0x75, 0x73, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x74, 0x61,
+	0x74, 0x75, 0x73, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x51,
+	0x0a, 0x0d, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12,
+	0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70,
+	0x61, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
+	0x73, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
+	0x73, 0x22, 0xf7, 0x01, 0x0a, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65,
+	0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
+	0x70, 0x61, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x5f,
+	0x64, 0x69, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x69,
+	0x6e, 0x67, 0x44, 0x69, 0x72, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65,
+	0x72, 0x5f, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
+	0x09, 0x52, 0x11, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x41, 0x72, 0x67, 0x75, 0x6d,
+	0x65, 0x6e, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x09, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65,
+	0x64, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x69, 0x64, 0x65, 0x5f, 0x71, 0x75,
+	0x65, 0x72, 0x79, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6c,
+	0x65, 0x52, 0x09, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04,
+	0x64, 0x65, 0x70, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x70, 0x73,
+	0x12, 0x2e, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x11, 0x2e, 0x69, 0x64, 0x65, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x53, 0x74, 0x61,
+	0x74, 0x75, 0x73, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x88, 0x01, 0x01,
+	0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xa9, 0x01, 0x0a, 0x0b,
+	0x49, 0x64, 0x65, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x62,
+	0x75, 0x69, 0x6c, 0x64, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x72, 0x6f,
+	0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x41,
+	0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x2f, 0x0a, 0x07, 0x73,
+	0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x69,
+	0x64, 0x65, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46,
+	0x69, 0x6c, 0x65, 0x52, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x06,
+	0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x69,
+	0x64, 0x65, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x48,
+	0x00, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07,
+	0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x1b, 0x5a, 0x19, 0x69, 0x64, 0x65, 0x5f, 0x71,
+	0x75, 0x65, 0x72, 0x79, 0x2f, 0x69, 0x64, 0x65, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -420,25 +640,31 @@
 }
 
 var file_ide_query_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
-var file_ide_query_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
+var file_ide_query_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
 var file_ide_query_proto_goTypes = []interface{}{
-	(Status_Code)(0),      // 0: cider.build.companion.Status.Code
-	(*Status)(nil),        // 1: cider.build.companion.Status
-	(*GeneratedFile)(nil), // 2: cider.build.companion.GeneratedFile
-	(*SourceFile)(nil),    // 3: cider.build.companion.SourceFile
-	(*IdeAnalysis)(nil),   // 4: cider.build.companion.IdeAnalysis
+	(Status_Code)(0),          // 0: ide_query.Status.Code
+	(*Status)(nil),            // 1: ide_query.Status
+	(*RepoState)(nil),         // 2: ide_query.RepoState
+	(*DepsResponse)(nil),      // 3: ide_query.DepsResponse
+	(*GeneratedFile)(nil),     // 4: ide_query.GeneratedFile
+	(*SourceFile)(nil),        // 5: ide_query.SourceFile
+	(*IdeAnalysis)(nil),       // 6: ide_query.IdeAnalysis
+	(*DepsResponse_Deps)(nil), // 7: ide_query.DepsResponse.Deps
 }
 var file_ide_query_proto_depIdxs = []int32{
-	0, // 0: cider.build.companion.Status.code:type_name -> cider.build.companion.Status.Code
-	2, // 1: cider.build.companion.SourceFile.generated:type_name -> cider.build.companion.GeneratedFile
-	1, // 2: cider.build.companion.SourceFile.status:type_name -> cider.build.companion.Status
-	3, // 3: cider.build.companion.IdeAnalysis.sources:type_name -> cider.build.companion.SourceFile
-	1, // 4: cider.build.companion.IdeAnalysis.status:type_name -> cider.build.companion.Status
-	5, // [5:5] is the sub-list for method output_type
-	5, // [5:5] is the sub-list for method input_type
-	5, // [5:5] is the sub-list for extension type_name
-	5, // [5:5] is the sub-list for extension extendee
-	0, // [0:5] is the sub-list for field type_name
+	0, // 0: ide_query.Status.code:type_name -> ide_query.Status.Code
+	7, // 1: ide_query.DepsResponse.deps:type_name -> ide_query.DepsResponse.Deps
+	1, // 2: ide_query.DepsResponse.status:type_name -> ide_query.Status
+	4, // 3: ide_query.SourceFile.generated:type_name -> ide_query.GeneratedFile
+	1, // 4: ide_query.SourceFile.status:type_name -> ide_query.Status
+	5, // 5: ide_query.IdeAnalysis.sources:type_name -> ide_query.SourceFile
+	1, // 6: ide_query.IdeAnalysis.status:type_name -> ide_query.Status
+	1, // 7: ide_query.DepsResponse.Deps.status:type_name -> ide_query.Status
+	8, // [8:8] is the sub-list for method output_type
+	8, // [8:8] is the sub-list for method input_type
+	8, // [8:8] is the sub-list for extension type_name
+	8, // [8:8] is the sub-list for extension extendee
+	0, // [0:8] is the sub-list for field type_name
 }
 
 func init() { file_ide_query_proto_init() }
@@ -460,7 +686,7 @@
 			}
 		}
 		file_ide_query_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*GeneratedFile); i {
+			switch v := v.(*RepoState); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -472,7 +698,7 @@
 			}
 		}
 		file_ide_query_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*SourceFile); i {
+			switch v := v.(*DepsResponse); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -484,6 +710,30 @@
 			}
 		}
 		file_ide_query_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GeneratedFile); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_ide_query_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SourceFile); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_ide_query_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*IdeAnalysis); i {
 			case 0:
 				return &v.state
@@ -495,18 +745,32 @@
 				return nil
 			}
 		}
+		file_ide_query_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DepsResponse_Deps); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
 	}
 	file_ide_query_proto_msgTypes[0].OneofWrappers = []interface{}{}
-	file_ide_query_proto_msgTypes[1].OneofWrappers = []interface{}{}
 	file_ide_query_proto_msgTypes[2].OneofWrappers = []interface{}{}
 	file_ide_query_proto_msgTypes[3].OneofWrappers = []interface{}{}
+	file_ide_query_proto_msgTypes[4].OneofWrappers = []interface{}{}
+	file_ide_query_proto_msgTypes[5].OneofWrappers = []interface{}{}
+	file_ide_query_proto_msgTypes[6].OneofWrappers = []interface{}{}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_ide_query_proto_rawDesc,
 			NumEnums:      1,
-			NumMessages:   4,
+			NumMessages:   7,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
diff --git a/tools/ide_query/ide_query_proto/ide_query.proto b/tools/ide_query/ide_query_proto/ide_query.proto
index 63eea39..3d7a8e7 100644
--- a/tools/ide_query/ide_query_proto/ide_query.proto
+++ b/tools/ide_query/ide_query_proto/ide_query.proto
@@ -1,3 +1,18 @@
+/*
+ * 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.
+ */
 syntax = "proto3";
 
 package ide_query;
@@ -14,6 +29,36 @@
   optional string message = 2;
 }
 
+// Represents an Android checkout on user's workstation.
+message RepoState {
+  // Absolute path for the checkout in the workstation.
+  // e.g. /home/user/work/android/
+  string repo_dir = 1;
+  // Relative to repo_dir.
+  repeated string active_file_path = 2;
+  // Repository relative path to output directory in workstation.
+  string out_dir = 3;
+  // Repository relative path to compile_commands.json in workstation.
+  string comp_db_path = 4;
+}
+
+// Provides all the targets that are pre-requisities for running language
+// services on active_file_paths.
+message DepsResponse {
+  // Build dependencies of a source file for providing language services.
+  message Deps {
+    // Relative to repo_dir.
+    string source_file = 1;
+    // Build target to execute for generating dep.
+    repeated string build_target = 2;
+    optional Status status = 3;
+  }
+  repeated Deps deps = 1;
+  optional Status status = 2;
+}
+
+// Returns all the information necessary for providing language services for the
+// active files.
 message GeneratedFile {
   // Path to the file relative to IdeAnalysis.build_artifact_root.
   string path = 1;
diff --git a/tools/releasetools/sign_target_files_apks.py b/tools/releasetools/sign_target_files_apks.py
index bf69dec..52d95d8 100755
--- a/tools/releasetools/sign_target_files_apks.py
+++ b/tools/releasetools/sign_target_files_apks.py
@@ -795,6 +795,16 @@
         # Copy it verbatim if we allow the file to exist.
         common.ZipWriteStr(output_tf_zip, out_info, data)
 
+    # Sign microdroid_vendor.img.
+    elif filename == "VENDOR/etc/avf/microdroid/microdroid_vendor.img":
+      vendor_key = OPTIONS.avb_keys.get("vendor")
+      vendor_algorithm = OPTIONS.avb_algorithms.get("vendor")
+      with tempfile.NamedTemporaryFile() as image:
+        image.write(data)
+        image.flush()
+        ReplaceKeyInAvbHashtreeFooter(image, vendor_key, vendor_algorithm,
+            misc_info)
+        common.ZipWrite(output_tf_zip, image.name, filename)
     # A non-APK file; copy it verbatim.
     else:
       common.ZipWriteStr(output_tf_zip, out_info, data)
@@ -812,6 +822,106 @@
   # Write back misc_info with the latest values.
   ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
 
+def ReplaceKeyInAvbHashtreeFooter(image, new_key, new_algorithm, misc_info):
+  # Get avb information about the image by parsing avbtool info_image.
+  def GetAvbInfo(avbtool, image_name):
+    # Get information with raw string by `avbtool info_image`.
+    info_raw = common.RunAndCheckOutput([
+      avbtool, 'info_image',
+      '--image', image_name
+    ])
+
+    # line_matcher is for parsing each output line of `avbtool info_image`.
+    # example string input: "      Hash Algorithm:        sha1"
+    # example matched input: ("      ", "Hash Algorithm", "sha1")
+    line_matcher = re.compile(r'^(\s*)([^:]+):\s*(.*)$')
+    # prop_matcher is for parsing value part of 'Prop' in `avbtool info_image`.
+    # example string input: "example_prop_key -> 'example_prop_value'"
+    # example matched output: ("example_prop_key", "example_prop_value")
+    prop_matcher = re.compile(r"(.+)\s->\s'(.+)'")
+    info = {}
+    indent_stack = [[-1, info]]
+    for line_info_raw in info_raw.split('\n'):
+      # Parse the line
+      line_info_parsed = line_matcher.match(line_info_raw)
+      if not line_info_parsed:
+        continue
+      indent = len(line_info_parsed.group(1))
+      key = line_info_parsed.group(2).strip()
+      value = line_info_parsed.group(3).strip()
+
+      # Pop indentation stack
+      while indent <= indent_stack[-1][0]:
+        del indent_stack[-1]
+
+      # Insert information into 'info'.
+      cur_info = indent_stack[-1][1]
+      if value == "":
+        if key == "Descriptors":
+          empty_list = []
+          cur_info[key] = empty_list
+          indent_stack.append([indent, empty_list])
+        else:
+          empty_dict = {}
+          cur_info.append({key:empty_dict})
+          indent_stack.append([indent, empty_dict])
+      elif key == "Prop":
+        prop_parsed = prop_matcher.match(value)
+        if not prop_parsed:
+          raise ValueError(
+              "Failed to parse prop while getting avb information.")
+        cur_info.append({key:{prop_parsed.group(1):prop_parsed.group(2)}})
+      else:
+        cur_info[key] = value
+
+    return info
+
+  # Get hashtree descriptor from info
+  def GetAvbHashtreeDescriptor(avb_info):
+    hashtree_descriptors = tuple(filter(lambda x: "Hashtree descriptor" in x,
+        info.get('Descriptors')))
+    if len(hashtree_descriptors) != 1:
+      raise ValueError("The number of hashtree descriptor is not 1.")
+    return hashtree_descriptors[0]["Hashtree descriptor"]
+
+  # Get avb info
+  avbtool = misc_info['avb_avbtool']
+  info = GetAvbInfo(avbtool, image.name)
+  hashtree_descriptor = GetAvbHashtreeDescriptor(info)
+
+  # Generate command
+  cmd = [avbtool, 'add_hashtree_footer',
+    '--key', new_key,
+    '--algorithm', new_algorithm,
+    '--partition_name', hashtree_descriptor.get("Partition Name"),
+    '--partition_size', info.get("Image size").removesuffix(" bytes"),
+    '--hash_algorithm', hashtree_descriptor.get("Hash Algorithm"),
+    '--salt', hashtree_descriptor.get("Salt"),
+    '--do_not_generate_fec',
+    '--image', image.name
+  ]
+
+  # Append properties into command
+  props = map(lambda x: x.get("Prop"), filter(lambda x: "Prop" in x,
+      info.get('Descriptors')))
+  for prop_wrapped in props:
+    prop = tuple(prop_wrapped.items())
+    if len(prop) != 1:
+      raise ValueError("The number of property is not 1.")
+    cmd.append('--prop')
+    cmd.append(prop[0][0] + ':' + prop[0][1])
+
+  # Replace Hashtree Footer with new key
+  common.RunAndCheckOutput(cmd)
+
+  # Check root digest is not changed
+  new_info = GetAvbInfo(avbtool, image.name)
+  new_hashtree_descriptor = GetAvbHashtreeDescriptor(info)
+  root_digest = hashtree_descriptor.get("Root Digest")
+  new_root_digest = new_hashtree_descriptor.get("Root Digest")
+  assert root_digest == new_root_digest, \
+      ("Root digest in hashtree descriptor shouldn't be changed. Old: {}, New: "
+       "{}").format(root_digest, new_root_digest)
 
 def ReplaceCerts(data):
   """Replaces all the occurences of X.509 certs with the new ones.