Merge "Configure AILabs team" into main
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index badcf30..758d404 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -141,9 +141,12 @@
 $(call add_soong_config_var_value,ANDROID,release_avf_enable_vendor_modules,$(RELEASE_AVF_ENABLE_VENDOR_MODULES))
 $(call add_soong_config_var_value,ANDROID,release_avf_enable_virt_cpufreq,$(RELEASE_AVF_ENABLE_VIRT_CPUFREQ))
 $(call add_soong_config_var_value,ANDROID,release_avf_microdroid_kernel_version,$(RELEASE_AVF_MICRODROID_KERNEL_VERSION))
+$(call add_soong_config_var_value,ANDROID,release_avf_support_custom_vm_with_paravirtualized_devices,$(RELEASE_AVF_SUPPORT_CUSTOM_VM_WITH_PARAVIRTUALIZED_DEVICES))
 
 $(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_package_libandroid_runtime_punch_holes,$(RELEASE_PACKAGE_LIBANDROID_RUNTIME_PUNCH_HOLES))
+
 $(call add_soong_config_var_value,ANDROID,release_selinux_data_data_ignore,$(RELEASE_SELINUX_DATA_DATA_IGNORE))
 
 # Enable system_server optimizations by default unless explicitly set or if
diff --git a/core/tasks/module-info.mk b/core/tasks/module-info.mk
index 8546828..aa695eb 100644
--- a/core/tasks/module-info.mk
+++ b/core/tasks/module-info.mk
@@ -39,7 +39,7 @@
 			$(call write-optional-json-list, "srcjars", $(sort $(ALL_MODULES.$(m).SRCJARS))) \
 			$(call write-optional-json-list, "classes_jar", $(sort $(ALL_MODULES.$(m).CLASSES_JAR))) \
 			$(call write-optional-json-list, "test_mainline_modules", $(sort $(ALL_MODULES.$(m).TEST_MAINLINE_MODULES))) \
-			$(call write-optional-json-bool, $(ALL_MODULES.$(m).IS_UNIT_TEST)) \
+			$(call write-optional-json-bool, "is_unit_test", $(ALL_MODULES.$(m).IS_UNIT_TEST)) \
 			$(call write-optional-json-list, "test_options_tags", $(sort $(ALL_MODULES.$(m).TEST_OPTIONS_TAGS))) \
 			$(call write-optional-json-list, "data", $(sort $(ALL_MODULES.$(m).TEST_DATA))) \
 			$(call write-optional-json-list, "runtime_dependencies", $(sort $(ALL_MODULES.$(m).LOCAL_RUNTIME_LIBRARIES))) \
diff --git a/tools/aconfig/aconfig_storage_file/src/lib.rs b/tools/aconfig/aconfig_storage_file/src/lib.rs
index e2be66d..070a3cf 100644
--- a/tools/aconfig/aconfig_storage_file/src/lib.rs
+++ b/tools/aconfig/aconfig_storage_file/src/lib.rs
@@ -51,7 +51,9 @@
 pub use crate::flag_value::{FlagValueHeader, FlagValueList};
 pub use crate::package_table::{PackageTable, PackageTableHeader, PackageTableNode};
 
-use crate::AconfigStorageError::{BytesParseFail, HashTableSizeLimit, InvalidStoredFlagType};
+use crate::AconfigStorageError::{
+    BytesParseFail, HashTableSizeLimit, InvalidFlagValueType, InvalidStoredFlagType,
+};
 
 /// Storage file version
 pub const FILE_VERSION: u32 = 1;
@@ -103,7 +105,7 @@
 }
 
 /// Flag type enum as stored by storage file
-/// ONLY APPEND, NEVER REMOVE FOR BACKWARD COMPATOBILITY. THE MAX IS U16.
+/// ONLY APPEND, NEVER REMOVE FOR BACKWARD COMPATIBILITY. THE MAX IS U16.
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum StoredFlagType {
     ReadWriteBoolean = 0,
@@ -124,6 +126,36 @@
     }
 }
 
+/// Flag value type enum, one FlagValueType maps to many StoredFlagType
+/// ONLY APPEND, NEVER REMOVE FOR BACKWARD COMPATIBILITY. THE MAX IS U16
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum FlagValueType {
+    Boolean = 0,
+}
+
+impl TryFrom<StoredFlagType> for FlagValueType {
+    type Error = AconfigStorageError;
+
+    fn try_from(value: StoredFlagType) -> Result<Self, Self::Error> {
+        match value {
+            StoredFlagType::ReadWriteBoolean => Ok(Self::Boolean),
+            StoredFlagType::ReadOnlyBoolean => Ok(Self::Boolean),
+            StoredFlagType::FixedReadOnlyBoolean => Ok(Self::Boolean),
+        }
+    }
+}
+
+impl TryFrom<u16> for FlagValueType {
+    type Error = AconfigStorageError;
+
+    fn try_from(value: u16) -> Result<Self, Self::Error> {
+        match value {
+            x if x == Self::Boolean as u16 => Ok(Self::Boolean),
+            _ => Err(InvalidFlagValueType(anyhow!("Invalid flag value type"))),
+        }
+    }
+}
+
 /// Storage query api error
 #[non_exhaustive]
 #[derive(thiserror::Error, Debug)]
@@ -163,6 +195,9 @@
 
     #[error("invalid stored flag type")]
     InvalidStoredFlagType(#[source] anyhow::Error),
+
+    #[error("invalid flag value type")]
+    InvalidFlagValueType(#[source] anyhow::Error),
 }
 
 /// Get the right hash table size given number of entries in the table. Use a
diff --git a/tools/aconfig/aconfig_storage_read_api/include/aconfig_storage/aconfig_storage_read_api.hpp b/tools/aconfig/aconfig_storage_read_api/include/aconfig_storage/aconfig_storage_read_api.hpp
index 521ff15..4555207 100644
--- a/tools/aconfig/aconfig_storage_read_api/include/aconfig_storage/aconfig_storage_read_api.hpp
+++ b/tools/aconfig/aconfig_storage_read_api/include/aconfig_storage/aconfig_storage_read_api.hpp
@@ -6,7 +6,8 @@
 
 namespace aconfig_storage {
 
-/// Storage file type enum
+/// Storage file type enum, to be consistent with the one defined in
+/// aconfig_storage_file/src/lib.rs
 enum StorageFileType {
   package_map,
   flag_map,
@@ -14,6 +15,29 @@
   flag_info
 };
 
+/// Flag type enum, to be consistent with the one defined in
+/// aconfig_storage_file/src/lib.rs
+enum StoredFlagType {
+  ReadWriteBoolean = 0,
+  ReadOnlyBoolean = 1,
+  FixedReadOnlyBoolean = 2,
+};
+
+/// Flag value type enum, to be consistent with the one defined in
+/// aconfig_storage_file/src/lib.rs
+enum FlagValueType {
+  Boolean = 0,
+};
+
+/// Flag info enum, to be consistent with the one defined in
+/// aconfig_storage_file/src/flag_info.rs
+enum FlagInfoBit {
+  IsSticky = 1<<0,
+  IsReadWrite = 1<<1,
+  HasOverride = 1<<2,
+};
+
+
 /// Mapped storage file
 struct MappedStorageFile {
   void* file_ptr;
@@ -27,13 +51,6 @@
   uint32_t boolean_start_index;
 };
 
-/// Flag type enum, to be consistent with the one defined in aconfig_storage_file/src/lib.rs
-enum StoredFlagType {
-  ReadWriteBoolean = 0,
-  ReadOnlyBoolean = 1,
-  FixedReadOnlyBoolean = 2,
-};
-
 /// Flag read context query result
 struct FlagReadContext {
   bool flag_exists;
@@ -91,13 +108,6 @@
     MappedStorageFile const& file,
     uint32_t index);
 
-/// Flag info enum, to be consistent with the one defined in aconfig_storage_file/src/lib.rs
-enum FlagInfoBit {
-  IsSticky = 1<<0,
-  IsReadWrite = 1<<1,
-  HasOverride = 1<<2,
-};
-
 /// Get boolean flag attribute
 /// \input file: mapped storage file
 /// \input index: the boolean flag index in the file
diff --git a/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs b/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs
index 9cc90ee..3786443 100644
--- a/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs
+++ b/tools/aconfig/aconfig_storage_read_api/src/mapped_file.rs
@@ -29,7 +29,7 @@
 };
 
 /// Find where storage files are stored for a particular container
-fn find_container_storage_location(
+pub fn find_container_storage_location(
     location_pb_file: &str,
     container: &str,
 ) -> Result<ProtoStorageFileInfo, AconfigStorageError> {
diff --git a/tools/aconfig/aconfig_storage_write_api/Android.bp b/tools/aconfig/aconfig_storage_write_api/Android.bp
index 0f15b9c..4dbdbbf 100644
--- a/tools/aconfig/aconfig_storage_write_api/Android.bp
+++ b/tools/aconfig/aconfig_storage_write_api/Android.bp
@@ -14,6 +14,7 @@
         "libcxx",
         "libthiserror",
         "libaconfig_storage_file",
+        "libaconfig_storage_read_api",
     ],
 }
 
@@ -30,6 +31,7 @@
     defaults: ["aconfig_storage_write_api.defaults"],
     data: [
         "tests/flag.val",
+        "tests/flag.info",
     ],
     rustlibs: [
         "libaconfig_storage_read_api",
@@ -68,12 +70,13 @@
     srcs: ["aconfig_storage_write_api.cpp"],
     generated_headers: [
         "cxx-bridge-header",
-        "libcxx_aconfig_storage_write_api_bridge_header"
+        "libcxx_aconfig_storage_write_api_bridge_header",
     ],
     generated_sources: ["libcxx_aconfig_storage_write_api_bridge_code"],
     whole_static_libs: ["libaconfig_storage_write_api_cxx_bridge"],
     export_include_dirs: ["include"],
     static_libs: [
+        "libaconfig_storage_read_api_cc",
         "libaconfig_storage_protos_cc",
         "libprotobuf-cpp-lite",
         "libbase",
diff --git a/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp b/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp
index ea88f05..01785e1 100644
--- a/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp
+++ b/tools/aconfig/aconfig_storage_write_api/aconfig_storage_write_api.cpp
@@ -38,7 +38,8 @@
 /// Get storage file path
 static Result<std::string> find_storage_file(
     std::string const& pb_file,
-    std::string const& container) {
+    std::string const& container,
+    StorageFileType file_type) {
   auto records_pb = read_storage_records_pb(pb_file);
   if (!records_pb.ok()) {
     return Error() << "Unable to read storage records from " << pb_file
@@ -47,15 +48,26 @@
 
   for (auto& entry : records_pb->files()) {
     if (entry.container() == container) {
-        return entry.flag_val();
+      switch(file_type) {
+        case StorageFileType::package_map:
+          return entry.package_map();
+        case StorageFileType::flag_map:
+          return entry.flag_map();
+        case StorageFileType::flag_val:
+          return entry.flag_val();
+        case StorageFileType::flag_info:
+          return entry.flag_info();
+        default:
+          return Error() << "Invalid file type " << file_type;
+      }
     }
   }
 
-  return Error() << "Unable to find storage files for container " << container;;
+  return Error() << "Unable to find storage files for container " << container;
 }
 
 /// Map a storage file
-static Result<MappedFlagValueFile> map_storage_file(std::string const& file) {
+static Result<MutableMappedStorageFile> map_storage_file(std::string const& file) {
   struct stat file_stat;
   if (stat(file.c_str(), &file_stat) < 0) {
     return ErrnoError() << "stat failed";
@@ -78,7 +90,7 @@
     return ErrnoError() << "mmap failed";
   }
 
-  auto mapped_file = MappedFlagValueFile();
+  auto mapped_file = MutableMappedStorageFile();
   mapped_file.file_ptr = map_result;
   mapped_file.file_size = file_size;
 
@@ -87,34 +99,37 @@
 
 namespace private_internal_api {
 
-/// Get mapped file implementation.
-Result<MappedFlagValueFile> get_mapped_flag_value_file_impl(
+/// Get mutable mapped file implementation.
+Result<MutableMappedStorageFile> get_mutable_mapped_file_impl(
     std::string const& pb_file,
-    std::string const& container) {
-  auto file_result = find_storage_file(pb_file, container);
+    std::string const& container,
+    StorageFileType file_type) {
+  if (file_type != StorageFileType::flag_val &&
+      file_type != StorageFileType::flag_info) {
+    return Error() << "Cannot create mutable mapped file for this file type";
+  }
+
+  auto file_result = find_storage_file(pb_file, container, file_type);
   if (!file_result.ok()) {
     return Error() << file_result.error();
   }
-  auto mapped_result = map_storage_file(*file_result);
-  if (!mapped_result.ok()) {
-    return Error() << "failed to map " << *file_result << ": "
-                   << mapped_result.error();
-  }
-  return *mapped_result;
+
+  return map_storage_file(*file_result);
 }
 
 } // namespace private internal api
 
-/// Get mapped writeable flag value file
-Result<MappedFlagValueFile> get_mapped_flag_value_file(
-    std::string const& container) {
-  return private_internal_api::get_mapped_flag_value_file_impl(
-      kPersistStorageRecordsPb, container);
+/// Get mutable mapped file
+Result<MutableMappedStorageFile> get_mutable_mapped_file(
+    std::string const& container,
+    StorageFileType file_type) {
+  return private_internal_api::get_mutable_mapped_file_impl(
+      kPersistStorageRecordsPb, container, file_type);
 }
 
 /// Set boolean flag value
 Result<void> set_boolean_flag_value(
-    const MappedFlagValueFile& file,
+    const MutableMappedStorageFile& file,
     uint32_t offset,
     bool value) {
   auto content = rust::Slice<uint8_t>(
@@ -126,6 +141,38 @@
   return {};
 }
 
+/// Set if flag is sticky
+Result<void> set_flag_is_sticky(
+    const MutableMappedStorageFile& file,
+    FlagValueType value_type,
+    uint32_t offset,
+    bool value) {
+  auto content = rust::Slice<uint8_t>(
+      static_cast<uint8_t*>(file.file_ptr), file.file_size);
+  auto update_cxx = update_flag_is_sticky_cxx(
+      content, static_cast<uint16_t>(value_type), offset, value);
+  if (!update_cxx.update_success) {
+    return Error() << std::string(update_cxx.error_message.c_str());
+  }
+  return {};
+}
+
+/// Set if flag has override
+Result<void> set_flag_has_override(
+    const MutableMappedStorageFile& file,
+    FlagValueType value_type,
+    uint32_t offset,
+    bool value) {
+  auto content = rust::Slice<uint8_t>(
+      static_cast<uint8_t*>(file.file_ptr), file.file_size);
+  auto update_cxx = update_flag_has_override_cxx(
+      content, static_cast<uint16_t>(value_type), offset, value);
+  if (!update_cxx.update_success) {
+    return Error() << std::string(update_cxx.error_message.c_str());
+  }
+  return {};
+}
+
 Result<void> create_flag_info(
     std::string const& package_map,
     std::string const& flag_map,
diff --git a/tools/aconfig/aconfig_storage_write_api/include/aconfig_storage/aconfig_storage_write_api.hpp b/tools/aconfig/aconfig_storage_write_api/include/aconfig_storage/aconfig_storage_write_api.hpp
index b652510..8699b88 100644
--- a/tools/aconfig/aconfig_storage_write_api/include/aconfig_storage/aconfig_storage_write_api.hpp
+++ b/tools/aconfig/aconfig_storage_write_api/include/aconfig_storage/aconfig_storage_write_api.hpp
@@ -4,13 +4,14 @@
 #include <string>
 
 #include <android-base/result.h>
+#include <aconfig_storage/aconfig_storage_read_api.hpp>
 
 using namespace android::base;
 
 namespace aconfig_storage {
 
 /// Mapped flag value file
-struct MappedFlagValueFile{
+struct MutableMappedStorageFile{
   void* file_ptr;
   size_t file_size;
 };
@@ -18,19 +19,35 @@
 /// DO NOT USE APIS IN THE FOLLOWING NAMESPACE DIRECTLY
 namespace private_internal_api {
 
-Result<MappedFlagValueFile> get_mapped_flag_value_file_impl(
+Result<MutableMappedStorageFile> get_mutable_mapped_file_impl(
     std::string const& pb_file,
-    std::string const& container);
+    std::string const& container,
+    StorageFileType file_type);
 
 } // namespace private_internal_api
 
-/// Get mapped writeable flag value file
-Result<MappedFlagValueFile> get_mapped_flag_value_file(
-    std::string const& container);
+/// Get mapped writeable storage file
+Result<MutableMappedStorageFile> get_mutable_mapped_file(
+    std::string const& container,
+    StorageFileType file_type);
 
 /// Set boolean flag value
 Result<void> set_boolean_flag_value(
-    const MappedFlagValueFile& file,
+    const MutableMappedStorageFile& file,
+    uint32_t offset,
+    bool value);
+
+/// Set if flag is sticky
+Result<void> set_flag_is_sticky(
+    const MutableMappedStorageFile& file,
+    FlagValueType value_type,
+    uint32_t offset,
+    bool value);
+
+/// Set if flag has override
+Result<void> set_flag_has_override(
+    const MutableMappedStorageFile& file,
+    FlagValueType value_type,
     uint32_t offset,
     bool value);
 
diff --git a/tools/aconfig/aconfig_storage_write_api/src/flag_info_update.rs b/tools/aconfig/aconfig_storage_write_api/src/flag_info_update.rs
new file mode 100644
index 0000000..56e1253
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_write_api/src/flag_info_update.rs
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! flag info update module defines the flag info file write to mapped bytes
+
+use aconfig_storage_file::{
+    read_u8_from_bytes, AconfigStorageError, FlagInfoBit, FlagInfoHeader, FlagValueType,
+    FILE_VERSION,
+};
+use anyhow::anyhow;
+
+fn get_flag_info_offset(
+    buf: &mut [u8],
+    flag_type: FlagValueType,
+    flag_index: u32,
+) -> Result<usize, AconfigStorageError> {
+    let interpreted_header = FlagInfoHeader::from_bytes(buf)?;
+    if interpreted_header.version > FILE_VERSION {
+        return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
+            "Cannot write to storage file with a higher version of {} with lib version {}",
+            interpreted_header.version,
+            FILE_VERSION
+        )));
+    }
+
+    // get byte offset to the flag info
+    let head = match flag_type {
+        FlagValueType::Boolean => (interpreted_header.boolean_flag_offset + flag_index) as usize,
+    };
+
+    if head >= interpreted_header.file_size as usize {
+        return Err(AconfigStorageError::InvalidStorageFileOffset(anyhow!(
+            "Flag value offset goes beyond the end of the file."
+        )));
+    }
+
+    Ok(head)
+}
+
+fn get_flag_attribute_and_offset(
+    buf: &mut [u8],
+    flag_type: FlagValueType,
+    flag_index: u32,
+) -> Result<(u8, usize), AconfigStorageError> {
+    let head = get_flag_info_offset(buf, flag_type, flag_index)?;
+    let mut pos = head;
+    let attribute = read_u8_from_bytes(buf, &mut pos)?;
+    Ok((attribute, head))
+}
+
+/// Set if flag is sticky
+pub fn update_flag_is_sticky(
+    buf: &mut [u8],
+    flag_type: FlagValueType,
+    flag_index: u32,
+    value: bool,
+) -> Result<(), AconfigStorageError> {
+    let (attribute, head) = get_flag_attribute_and_offset(buf, flag_type, flag_index)?;
+    let is_sticky = (attribute & (FlagInfoBit::IsSticky as u8)) != 0;
+    if is_sticky != value {
+        buf[head] = (attribute ^ FlagInfoBit::IsSticky as u8).to_le_bytes()[0];
+    }
+    Ok(())
+}
+
+/// Set if flag has override
+pub fn update_flag_has_override(
+    buf: &mut [u8],
+    flag_type: FlagValueType,
+    flag_index: u32,
+    value: bool,
+) -> Result<(), AconfigStorageError> {
+    let (attribute, head) = get_flag_attribute_and_offset(buf, flag_type, flag_index)?;
+    let has_override = (attribute & (FlagInfoBit::HasOverride as u8)) != 0;
+    if has_override != value {
+        buf[head] = (attribute ^ FlagInfoBit::HasOverride as u8).to_le_bytes()[0];
+    }
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use aconfig_storage_file::test_utils::create_test_flag_info_list;
+    use aconfig_storage_read_api::flag_info_query::find_boolean_flag_attribute;
+
+    #[test]
+    // this test point locks down is sticky update
+    fn test_update_flag_is_sticky() {
+        let flag_info_list = create_test_flag_info_list();
+        let mut buf = flag_info_list.into_bytes();
+        for i in 0..flag_info_list.header.num_flags {
+            update_flag_is_sticky(&mut buf, FlagValueType::Boolean, i, true).unwrap();
+            let attribute = find_boolean_flag_attribute(&buf, i).unwrap();
+            assert!((attribute & (FlagInfoBit::IsSticky as u8)) != 0);
+            update_flag_is_sticky(&mut buf, FlagValueType::Boolean, i, false).unwrap();
+            let attribute = find_boolean_flag_attribute(&buf, i).unwrap();
+            assert!((attribute & (FlagInfoBit::IsSticky as u8)) == 0);
+        }
+    }
+
+    #[test]
+    // this test point locks down has override update
+    fn test_update_flag_has_override() {
+        let flag_info_list = create_test_flag_info_list();
+        let mut buf = flag_info_list.into_bytes();
+        for i in 0..flag_info_list.header.num_flags {
+            update_flag_has_override(&mut buf, FlagValueType::Boolean, i, true).unwrap();
+            let attribute = find_boolean_flag_attribute(&buf, i).unwrap();
+            assert!((attribute & (FlagInfoBit::HasOverride as u8)) != 0);
+            update_flag_has_override(&mut buf, FlagValueType::Boolean, i, false).unwrap();
+            let attribute = find_boolean_flag_attribute(&buf, i).unwrap();
+            assert!((attribute & (FlagInfoBit::HasOverride as u8)) == 0);
+        }
+    }
+}
diff --git a/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs b/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs
index 9b20563..0938715 100644
--- a/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs
+++ b/tools/aconfig/aconfig_storage_write_api/src/flag_value_update.rs
@@ -49,20 +49,7 @@
 #[cfg(test)]
 mod tests {
     use super::*;
-    use aconfig_storage_file::{FlagValueList, StorageFileType};
-
-    pub fn create_test_flag_value_list() -> FlagValueList {
-        let header = FlagValueHeader {
-            version: FILE_VERSION,
-            container: String::from("system"),
-            file_type: StorageFileType::FlagVal as u8,
-            file_size: 35,
-            num_flags: 8,
-            boolean_value_offset: 27,
-        };
-        let booleans: Vec<bool> = vec![false; 8];
-        FlagValueList { header, booleans }
-    }
+    use aconfig_storage_file::test_utils::create_test_flag_value_list;
 
     #[test]
     // this test point locks down flag value update
diff --git a/tools/aconfig/aconfig_storage_write_api/src/lib.rs b/tools/aconfig/aconfig_storage_write_api/src/lib.rs
index 4dcba38..ee08d16 100644
--- a/tools/aconfig/aconfig_storage_write_api/src/lib.rs
+++ b/tools/aconfig/aconfig_storage_write_api/src/lib.rs
@@ -17,6 +17,7 @@
 //! `aconfig_storage_write_api` is a crate that defines write apis to update flag value
 //! in storage file. It provides one api to interface with storage files.
 
+pub mod flag_info_update;
 pub mod flag_value_update;
 pub mod mapped_file;
 
@@ -24,8 +25,8 @@
 mod test_utils;
 
 use aconfig_storage_file::{
-    AconfigStorageError, FlagInfoHeader, FlagInfoList, FlagInfoNode, FlagTable, PackageTable,
-    StorageFileType, StoredFlagType, FILE_VERSION,
+    AconfigStorageError, FlagInfoHeader, FlagInfoList, FlagInfoNode, FlagTable, FlagValueType,
+    PackageTable, StorageFileType, StoredFlagType, FILE_VERSION,
 };
 
 use anyhow::anyhow;
@@ -36,10 +37,11 @@
 /// Storage file location pb file
 pub const STORAGE_LOCATION_FILE: &str = "/metadata/aconfig/persistent_storage_file_records.pb";
 
-/// Get mmaped flag value file given the container name
+/// Get read write mapped storage files.
 ///
 /// \input container: the flag package container
-/// \return a result of mapped file
+/// \input file_type: storage file type enum
+/// \return a result of read write mapped file
 ///
 ///
 /// # Safety
@@ -48,8 +50,11 @@
 /// file not thru this memory mapped file or there are concurrent writes to this
 /// memory mapped file. Ensure all writes to the underlying file are thru this memory
 /// mapped file and there are no concurrent writes.
-pub unsafe fn get_mapped_flag_value_file(container: &str) -> Result<MmapMut, AconfigStorageError> {
-    unsafe { crate::mapped_file::get_mapped_file(STORAGE_LOCATION_FILE, container) }
+pub unsafe fn get_mapped_storage_file(
+    container: &str,
+    file_type: StorageFileType,
+) -> Result<MmapMut, AconfigStorageError> {
+    unsafe { crate::mapped_file::get_mapped_file(STORAGE_LOCATION_FILE, container, file_type) }
 }
 
 /// Set boolean flag value thru mapped file and flush the change to file
@@ -70,6 +75,44 @@
     })
 }
 
+/// Set if flag is sticky thru mapped file and flush the change to file
+///
+/// \input mapped_file: the mapped flag info file
+/// \input index: flag index
+/// \input value: updated flag sticky value
+/// \return a result of ()
+///
+pub fn set_flag_is_sticky(
+    file: &mut MmapMut,
+    flag_type: FlagValueType,
+    index: u32,
+    value: bool,
+) -> Result<(), AconfigStorageError> {
+    crate::flag_info_update::update_flag_is_sticky(file, flag_type, index, value)?;
+    file.flush().map_err(|errmsg| {
+        AconfigStorageError::MapFlushFail(anyhow!("fail to flush storage file: {}", errmsg))
+    })
+}
+
+/// Set if flag has override thru mapped file and flush the change to file
+///
+/// \input mapped_file: the mapped flag info file
+/// \input index: flag index
+/// \input value: updated flag has override value
+/// \return a result of ()
+///
+pub fn set_flag_has_override(
+    file: &mut MmapMut,
+    flag_type: FlagValueType,
+    index: u32,
+    value: bool,
+) -> Result<(), AconfigStorageError> {
+    crate::flag_info_update::update_flag_has_override(file, flag_type, index, value)?;
+    file.flush().map_err(|errmsg| {
+        AconfigStorageError::MapFlushFail(anyhow!("fail to flush storage file: {}", errmsg))
+    })
+}
+
 /// Read in storage file as bytes
 fn read_file_to_bytes(file_path: &str) -> Result<Vec<u8>, AconfigStorageError> {
     let mut file = File::open(file_path).map_err(|errmsg| {
@@ -163,6 +206,18 @@
         pub error_message: String,
     }
 
+    // Flag is sticky update return for cc interlop
+    pub struct FlagIsStickyUpdateCXX {
+        pub update_success: bool,
+        pub error_message: String,
+    }
+
+    // Flag has override update return for cc interlop
+    pub struct FlagHasOverrideUpdateCXX {
+        pub update_success: bool,
+        pub error_message: String,
+    }
+
     // Flag info file creation return for cc interlop
     pub struct FlagInfoCreationCXX {
         pub success: bool,
@@ -177,6 +232,20 @@
             value: bool,
         ) -> BooleanFlagValueUpdateCXX;
 
+        pub fn update_flag_is_sticky_cxx(
+            file: &mut [u8],
+            flag_type: u16,
+            offset: u32,
+            value: bool,
+        ) -> FlagIsStickyUpdateCXX;
+
+        pub fn update_flag_has_override_cxx(
+            file: &mut [u8],
+            flag_type: u16,
+            offset: u32,
+            value: bool,
+        ) -> FlagHasOverrideUpdateCXX;
+
         pub fn create_flag_info_cxx(
             package_map: &str,
             flag_map: &str,
@@ -201,6 +270,58 @@
     }
 }
 
+pub(crate) fn update_flag_is_sticky_cxx(
+    file: &mut [u8],
+    flag_type: u16,
+    offset: u32,
+    value: bool,
+) -> ffi::FlagIsStickyUpdateCXX {
+    match FlagValueType::try_from(flag_type) {
+        Ok(value_type) => {
+            match crate::flag_info_update::update_flag_is_sticky(file, value_type, offset, value) {
+                Ok(()) => ffi::FlagIsStickyUpdateCXX {
+                    update_success: true,
+                    error_message: String::from("")
+                },
+                Err(errmsg) => ffi::FlagIsStickyUpdateCXX {
+                    update_success: false,
+                    error_message: format!("{:?}", errmsg),
+                },
+            }
+        }
+        Err(errmsg) => ffi::FlagIsStickyUpdateCXX {
+            update_success: false,
+            error_message: format!("{:?}", errmsg),
+        }
+    }
+}
+
+pub(crate) fn update_flag_has_override_cxx(
+    file: &mut [u8],
+    flag_type: u16,
+    offset: u32,
+    value: bool,
+) -> ffi::FlagHasOverrideUpdateCXX {
+    match FlagValueType::try_from(flag_type) {
+        Ok(value_type) => {
+            match crate::flag_info_update::update_flag_has_override(file, value_type, offset, value) {
+                Ok(()) => ffi::FlagHasOverrideUpdateCXX {
+                    update_success: true,
+                    error_message: String::from("")
+                },
+                Err(errmsg) => ffi::FlagHasOverrideUpdateCXX {
+                    update_success: false,
+                    error_message: format!("{:?}", errmsg),
+                },
+            }
+        }
+        Err(errmsg) => ffi::FlagHasOverrideUpdateCXX {
+            update_success: false,
+            error_message: format!("{:?}", errmsg),
+        }
+    }
+}
+
 /// Create flag info file cc interlop
 pub(crate) fn create_flag_info_cxx(
     package_map: &str,
@@ -224,6 +345,8 @@
         create_test_flag_info_list, create_test_flag_table, create_test_package_table,
         write_bytes_to_temp_file,
     };
+    use aconfig_storage_file::FlagInfoBit;
+    use aconfig_storage_read_api::flag_info_query::find_boolean_flag_attribute;
     use aconfig_storage_read_api::flag_value_query::find_boolean_flag_value;
     use std::fs::File;
     use std::io::Read;
@@ -248,6 +371,7 @@
     package_map: "some_package.map"
     flag_map: "some_flag.map"
     flag_val: "{}"
+    flag_info: "some_flag.info"
     timestamp: 12345
 }}
 "#,
@@ -260,7 +384,12 @@
         // The safety here is guaranteed as only this single threaded test process will
         // write to this file
         unsafe {
-            let mut file = crate::mapped_file::get_mapped_file(&record_pb_path, "system").unwrap();
+            let mut file = crate::mapped_file::get_mapped_file(
+                &record_pb_path,
+                "system",
+                StorageFileType::FlagVal,
+            )
+            .unwrap();
             for i in 0..8 {
                 set_boolean_flag_value(&mut file, i, true).unwrap();
                 let value = get_boolean_flag_value_at_offset(&flag_value_path, i);
@@ -273,6 +402,97 @@
         }
     }
 
+    fn get_flag_attribute_at_offset(file: &str, offset: u32) -> u8 {
+        let mut f = File::open(&file).unwrap();
+        let mut bytes = Vec::new();
+        f.read_to_end(&mut bytes).unwrap();
+        find_boolean_flag_attribute(&bytes, offset).unwrap()
+    }
+
+    #[test]
+    fn test_set_flag_is_sticky() {
+        let flag_info_file = copy_to_temp_file("./tests/flag.info", false).unwrap();
+        let flag_info_path = flag_info_file.path().display().to_string();
+        let text_proto = format!(
+            r#"
+    files {{
+        version: 0
+        container: "system"
+        package_map: "some_package.map"
+        flag_map: "some_flag.map"
+        flag_val: "some_flag.val"
+        flag_info: "{}"
+        timestamp: 12345
+    }}
+    "#,
+            flag_info_path
+        );
+        let record_pb_file = write_proto_to_temp_file(&text_proto).unwrap();
+        let record_pb_path = record_pb_file.path().display().to_string();
+
+        // SAFETY:
+        // The safety here is guaranteed as only this single threaded test process will
+        // write to this file
+        unsafe {
+            let mut file = crate::mapped_file::get_mapped_file(
+                &record_pb_path,
+                "system",
+                StorageFileType::FlagInfo,
+            )
+            .unwrap();
+            for i in 0..8 {
+                set_flag_is_sticky(&mut file, FlagValueType::Boolean, i, true).unwrap();
+                let attribute = get_flag_attribute_at_offset(&flag_info_path, i);
+                assert!((attribute & (FlagInfoBit::IsSticky as u8)) != 0);
+                set_flag_is_sticky(&mut file, FlagValueType::Boolean, i, false).unwrap();
+                let attribute = get_flag_attribute_at_offset(&flag_info_path, i);
+                assert!((attribute & (FlagInfoBit::IsSticky as u8)) == 0);
+            }
+        }
+    }
+
+    #[test]
+    fn test_set_flag_has_override() {
+        let flag_info_file = copy_to_temp_file("./tests/flag.info", false).unwrap();
+        let flag_info_path = flag_info_file.path().display().to_string();
+        let text_proto = format!(
+            r#"
+    files {{
+        version: 0
+        container: "system"
+        package_map: "some_package.map"
+        flag_map: "some_flag.map"
+        flag_val: "some_flag.val"
+        flag_info: "{}"
+        timestamp: 12345
+    }}
+    "#,
+            flag_info_path
+        );
+        let record_pb_file = write_proto_to_temp_file(&text_proto).unwrap();
+        let record_pb_path = record_pb_file.path().display().to_string();
+
+        // SAFETY:
+        // The safety here is guaranteed as only this single threaded test process will
+        // write to this file
+        unsafe {
+            let mut file = crate::mapped_file::get_mapped_file(
+                &record_pb_path,
+                "system",
+                StorageFileType::FlagInfo,
+            )
+            .unwrap();
+            for i in 0..8 {
+                set_flag_has_override(&mut file, FlagValueType::Boolean, i, true).unwrap();
+                let attribute = get_flag_attribute_at_offset(&flag_info_path, i);
+                assert!((attribute & (FlagInfoBit::HasOverride as u8)) != 0);
+                set_flag_has_override(&mut file, FlagValueType::Boolean, i, false).unwrap();
+                let attribute = get_flag_attribute_at_offset(&flag_info_path, i);
+                assert!((attribute & (FlagInfoBit::HasOverride as u8)) == 0);
+            }
+        }
+    }
+
     fn create_empty_temp_file() -> Result<NamedTempFile, AconfigStorageError> {
         let file = NamedTempFile::new().map_err(|_| {
             AconfigStorageError::FileCreationFail(anyhow!("Failed to create temp file"))
diff --git a/tools/aconfig/aconfig_storage_write_api/src/mapped_file.rs b/tools/aconfig/aconfig_storage_write_api/src/mapped_file.rs
index 4c98be4..ea9ac19 100644
--- a/tools/aconfig/aconfig_storage_write_api/src/mapped_file.rs
+++ b/tools/aconfig/aconfig_storage_write_api/src/mapped_file.rs
@@ -14,43 +14,41 @@
  * limitations under the License.
  */
 
-use std::fs::{self, File, OpenOptions};
-use std::io::{BufReader, Read};
-
 use anyhow::anyhow;
 use memmap2::MmapMut;
+use std::fs::{self, OpenOptions};
+use std::io::Read;
 
-use aconfig_storage_file::protos::{storage_record_pb::try_from_binary_proto, ProtoStorageFiles};
-use aconfig_storage_file::AconfigStorageError::{
-    self, FileReadFail, MapFileFail, ProtobufParseFail, StorageFileNotFound,
-};
+use aconfig_storage_file::AconfigStorageError::{self, FileReadFail, MapFileFail};
+use aconfig_storage_file::StorageFileType;
+use aconfig_storage_read_api::mapped_file::find_container_storage_location;
 
-/// Find where persistent storage value file is for a particular container
-fn find_persist_flag_value_file(
-    location_pb_file: &str,
-    container: &str,
-) -> Result<String, AconfigStorageError> {
-    let file = File::open(location_pb_file).map_err(|errmsg| {
-        FileReadFail(anyhow!("Failed to open file {}: {}", location_pb_file, errmsg))
-    })?;
-    let mut reader = BufReader::new(file);
-    let mut bytes = Vec::new();
-    reader.read_to_end(&mut bytes).map_err(|errmsg| {
-        FileReadFail(anyhow!("Failed to read file {}: {}", location_pb_file, errmsg))
-    })?;
-    let storage_locations: ProtoStorageFiles = try_from_binary_proto(&bytes).map_err(|errmsg| {
-        ProtobufParseFail(anyhow!(
-            "Failed to parse storage location pb file {}: {}",
-            location_pb_file,
-            errmsg
-        ))
-    })?;
-    for location_info in storage_locations.files.iter() {
-        if location_info.container() == container {
-            return Ok(location_info.flag_val().to_string());
-        }
+/// Get the mutable memory mapping of a storage file
+///
+/// # Safety
+///
+/// The memory mapped file may have undefined behavior if there are writes to this
+/// file not thru this memory mapped file or there are concurrent writes to this
+/// memory mapped file. Ensure all writes to the underlying file are thru this memory
+/// mapped file and there are no concurrent writes.
+unsafe fn map_file(file_path: &str) -> Result<MmapMut, AconfigStorageError> {
+    // make sure file has read write permission
+    let perms = fs::metadata(file_path).unwrap().permissions();
+    if perms.readonly() {
+        return Err(MapFileFail(anyhow!("fail to map non read write storage file {}", file_path)));
     }
-    Err(StorageFileNotFound(anyhow!("Persistent flag value file does not exist for {}", container)))
+
+    let file =
+        OpenOptions::new().read(true).write(true).open(file_path).map_err(|errmsg| {
+            FileReadFail(anyhow!("Failed to open file {}: {}", file_path, errmsg))
+        })?;
+
+    unsafe {
+        let mapped_file = MmapMut::map_mut(&file).map_err(|errmsg| {
+            MapFileFail(anyhow!("fail to map storage file {}: {}", file_path, errmsg))
+        })?;
+        Ok(mapped_file)
+    }
 }
 
 /// Get a mapped storage file given the container and file type
@@ -64,24 +62,16 @@
 pub unsafe fn get_mapped_file(
     location_pb_file: &str,
     container: &str,
+    file_type: StorageFileType,
 ) -> Result<MmapMut, AconfigStorageError> {
-    let file_path = find_persist_flag_value_file(location_pb_file, container)?;
-
-    // make sure file has read write permission
-    let perms = fs::metadata(&file_path).unwrap().permissions();
-    if perms.readonly() {
-        return Err(MapFileFail(anyhow!("fail to map non read write storage file {}", file_path)));
-    }
-
-    let file =
-        OpenOptions::new().read(true).write(true).open(&file_path).map_err(|errmsg| {
-            FileReadFail(anyhow!("Failed to open file {}: {}", file_path, errmsg))
-        })?;
-
-    unsafe {
-        MmapMut::map_mut(&file).map_err(|errmsg| {
-            MapFileFail(anyhow!("fail to map storage file {}: {}", file_path, errmsg))
-        })
+    let files_location = find_container_storage_location(location_pb_file, container)?;
+    match file_type {
+        StorageFileType::FlagVal => unsafe { map_file(files_location.flag_val()) },
+        StorageFileType::FlagInfo => unsafe { map_file(files_location.flag_info()) },
+        _ => Err(MapFileFail(anyhow!(
+            "Cannot map file type {:?} as writeable memory mapped files.",
+            file_type
+        ))),
     }
 }
 
@@ -92,41 +82,9 @@
     use aconfig_storage_file::protos::storage_record_pb::write_proto_to_temp_file;
 
     #[test]
-    fn test_find_persist_flag_value_file_location() {
-        let text_proto = r#"
-files {
-    version: 0
-    container: "system"
-    package_map: "/system/etc/package.map"
-    flag_map: "/system/etc/flag.map"
-    flag_val: "/metadata/aconfig/system.val"
-    timestamp: 12345
-}
-files {
-    version: 1
-    container: "product"
-    package_map: "/product/etc/package.map"
-    flag_map: "/product/etc/flag.map"
-    flag_val: "/metadata/aconfig/product.val"
-    timestamp: 54321
-}
-"#;
-        let file = write_proto_to_temp_file(&text_proto).unwrap();
-        let file_full_path = file.path().display().to_string();
-        let flag_value_file = find_persist_flag_value_file(&file_full_path, "system").unwrap();
-        assert_eq!(flag_value_file, "/metadata/aconfig/system.val");
-        let flag_value_file = find_persist_flag_value_file(&file_full_path, "product").unwrap();
-        assert_eq!(flag_value_file, "/metadata/aconfig/product.val");
-        let err = find_persist_flag_value_file(&file_full_path, "vendor").unwrap_err();
-        assert_eq!(
-            format!("{:?}", err),
-            "StorageFileNotFound(Persistent flag value file does not exist for vendor)"
-        );
-    }
-
-    #[test]
     fn test_mapped_file_contents() {
-        let mut rw_file = copy_to_temp_file("./tests/flag.val", false).unwrap();
+        let mut rw_val_file = copy_to_temp_file("./tests/flag.val", false).unwrap();
+        let mut rw_info_file = copy_to_temp_file("./tests/flag.info", false).unwrap();
         let text_proto = format!(
             r#"
 files {{
@@ -135,21 +93,37 @@
     package_map: "some_package.map"
     flag_map: "some_flag.map"
     flag_val: "{}"
+    flag_info: "{}"
     timestamp: 12345
 }}
 "#,
-            rw_file.path().display().to_string()
+            rw_val_file.path().display().to_string(),
+            rw_info_file.path().display().to_string()
         );
         let storage_record_file = write_proto_to_temp_file(&text_proto).unwrap();
         let storage_record_file_path = storage_record_file.path().display().to_string();
 
         let mut content = Vec::new();
-        rw_file.read_to_end(&mut content).unwrap();
+        rw_val_file.read_to_end(&mut content).unwrap();
 
         // SAFETY:
         // The safety here is guaranteed here as no writes happens to this temp file
         unsafe {
-            let mmaped_file = get_mapped_file(&storage_record_file_path, "system").unwrap();
+            let mmaped_file =
+                get_mapped_file(&storage_record_file_path, "system", StorageFileType::FlagVal)
+                    .unwrap();
+            assert_eq!(mmaped_file[..], content[..]);
+        }
+
+        let mut content = Vec::new();
+        rw_info_file.read_to_end(&mut content).unwrap();
+
+        // SAFETY:
+        // The safety here is guaranteed here as no writes happens to this temp file
+        unsafe {
+            let mmaped_file =
+                get_mapped_file(&storage_record_file_path, "system", StorageFileType::FlagInfo)
+                    .unwrap();
             assert_eq!(mmaped_file[..], content[..]);
         }
     }
@@ -165,6 +139,7 @@
     package_map: "some_package.map"
     flag_map: "some_flag.map"
     flag_val: "{}"
+    flag_info: "some_flag.info"
     timestamp: 12345
 }}
 "#,
@@ -176,7 +151,9 @@
         // SAFETY:
         // The safety here is guaranteed here as no writes happens to this temp file
         unsafe {
-            let error = get_mapped_file(&storage_record_file_path, "system").unwrap_err();
+            let error =
+                get_mapped_file(&storage_record_file_path, "system", StorageFileType::FlagVal)
+                    .unwrap_err();
             assert_eq!(
                 format!("{:?}", error),
                 format!(
@@ -186,4 +163,49 @@
             );
         }
     }
+
+    #[test]
+    fn test_mapped_not_supported_file() {
+        let text_proto = format!(
+            r#"
+files {{
+    version: 0
+    container: "system"
+    package_map: "some_package.map"
+    flag_map: "some_flag.map"
+    flag_val: "some_flag.val"
+    flag_info: "some_flag.info"
+    timestamp: 12345
+}}
+"#,
+        );
+        let storage_record_file = write_proto_to_temp_file(&text_proto).unwrap();
+        let storage_record_file_path = storage_record_file.path().display().to_string();
+
+        // SAFETY:
+        // The safety here is guaranteed here as no writes happens to this temp file
+        unsafe {
+            let error =
+                get_mapped_file(&storage_record_file_path, "system", StorageFileType::PackageMap)
+                    .unwrap_err();
+            assert_eq!(
+                format!("{:?}", error),
+                format!(
+                    "MapFileFail(Cannot map file type {:?} as writeable memory mapped files.)",
+                    StorageFileType::PackageMap
+                )
+            );
+
+            let error =
+                get_mapped_file(&storage_record_file_path, "system", StorageFileType::FlagMap)
+                    .unwrap_err();
+            assert_eq!(
+                format!("{:?}", error),
+                format!(
+                    "MapFileFail(Cannot map file type {:?} as writeable memory mapped files.)",
+                    StorageFileType::FlagMap
+                )
+            );
+        }
+    }
 }
diff --git a/tools/aconfig/aconfig_storage_write_api/tests/Android.bp b/tools/aconfig/aconfig_storage_write_api/tests/Android.bp
index 5b23dbc..85568e0 100644
--- a/tools/aconfig/aconfig_storage_write_api/tests/Android.bp
+++ b/tools/aconfig/aconfig_storage_write_api/tests/Android.bp
@@ -1,8 +1,7 @@
-
 rust_test {
     name: "aconfig_storage_write_api.test.rust",
     srcs: [
-        "storage_write_api_test.rs"
+        "storage_write_api_test.rs",
     ],
     rustlibs: [
         "libanyhow",
@@ -14,6 +13,7 @@
     ],
     data: [
         "flag.val",
+        "flag.info",
     ],
     test_suites: ["general-tests"],
 }
@@ -34,6 +34,7 @@
     ],
     data: [
         "flag.val",
+        "flag.info",
     ],
     test_suites: [
         "device-tests",
diff --git a/tools/aconfig/aconfig_storage_write_api/tests/flag.info b/tools/aconfig/aconfig_storage_write_api/tests/flag.info
new file mode 100644
index 0000000..820d839
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_write_api/tests/flag.info
Binary files differ
diff --git a/tools/aconfig/aconfig_storage_write_api/tests/storage_write_api_test.cpp b/tools/aconfig/aconfig_storage_write_api/tests/storage_write_api_test.cpp
index 00b737c..77664e4 100644
--- a/tools/aconfig/aconfig_storage_write_api/tests/storage_write_api_test.cpp
+++ b/tools/aconfig/aconfig_storage_write_api/tests/storage_write_api_test.cpp
@@ -50,7 +50,8 @@
     return temp_file;
   }
 
-  Result<std::string> write_storage_location_pb_file(std::string const& flag_val) {
+  Result<std::string> write_storage_location_pb_file(std::string const& flag_val,
+                                                     std::string const& flag_info) {
     auto temp_file = std::tmpnam(nullptr);
     auto proto = storage_files();
     auto* info = proto.add_files();
@@ -59,6 +60,7 @@
     info->set_package_map("some_package.map");
     info->set_flag_map("some_flag.map");
     info->set_flag_val(flag_val);
+    info->set_flag_info(flag_info);
     info->set_timestamp(12345);
 
     auto content = std::string();
@@ -72,22 +74,25 @@
   void SetUp() override {
     auto const test_dir = android::base::GetExecutableDirectory();
     flag_val = *copy_to_rw_temp_file(test_dir + "/flag.val");
-    storage_record_pb = *write_storage_location_pb_file(flag_val);
+    flag_info = *copy_to_rw_temp_file(test_dir + "/flag.info");
+    storage_record_pb = *write_storage_location_pb_file(flag_val, flag_info);
   }
 
   void TearDown() override {
     std::remove(flag_val.c_str());
+    std::remove(flag_info.c_str());
     std::remove(storage_record_pb.c_str());
   }
 
   std::string flag_val;
+  std::string flag_info;
   std::string storage_record_pb;
 };
 
 /// Negative test to lock down the error when mapping none exist storage files
 TEST_F(AconfigStorageTest, test_none_exist_storage_file_mapping) {
-  auto mapped_file_result = private_api::get_mapped_flag_value_file_impl(
-      storage_record_pb, "vendor");
+  auto mapped_file_result = private_api::get_mutable_mapped_file_impl(
+      storage_record_pb, "vendor", api::StorageFileType::flag_val);
   ASSERT_FALSE(mapped_file_result.ok());
   ASSERT_EQ(mapped_file_result.error().message(),
             "Unable to find storage files for container vendor");
@@ -96,17 +101,34 @@
 /// Negative test to lock down the error when mapping a non writeable storage file
 TEST_F(AconfigStorageTest, test_non_writable_storage_file_mapping) {
   ASSERT_TRUE(chmod(flag_val.c_str(), S_IRUSR | S_IRGRP | S_IROTH) != -1);
-  auto mapped_file_result = private_api::get_mapped_flag_value_file_impl(
-      storage_record_pb, "mockup");
+  auto mapped_file_result = private_api::get_mutable_mapped_file_impl(
+      storage_record_pb, "mockup", api::StorageFileType::flag_val);
   ASSERT_FALSE(mapped_file_result.ok());
   auto it = mapped_file_result.error().message().find("cannot map nonwriteable file");
   ASSERT_TRUE(it != std::string::npos) << mapped_file_result.error().message();
 }
 
+/// Negative test to lock down the error when mapping a file type that cannot be modified
+TEST_F(AconfigStorageTest, test_invalid_storage_file_type_mapping) {
+  auto mapped_file_result = private_api::get_mutable_mapped_file_impl(
+      storage_record_pb, "mockup", api::StorageFileType::package_map);
+  ASSERT_FALSE(mapped_file_result.ok());
+  auto it = mapped_file_result.error().message().find(
+      "Cannot create mutable mapped file for this file type");
+  ASSERT_TRUE(it != std::string::npos) << mapped_file_result.error().message();
+
+  mapped_file_result = private_api::get_mutable_mapped_file_impl(
+      storage_record_pb, "mockup", api::StorageFileType::flag_map);
+  ASSERT_FALSE(mapped_file_result.ok());
+  it = mapped_file_result.error().message().find(
+      "Cannot create mutable mapped file for this file type");
+  ASSERT_TRUE(it != std::string::npos) << mapped_file_result.error().message();
+}
+
 /// Test to lock down storage flag value update api
 TEST_F(AconfigStorageTest, test_boolean_flag_value_update) {
-  auto mapped_file_result = private_api::get_mapped_flag_value_file_impl(
-      storage_record_pb, "mockup");
+  auto mapped_file_result = private_api::get_mutable_mapped_file_impl(
+      storage_record_pb, "mockup", api::StorageFileType::flag_val);
   ASSERT_TRUE(mapped_file_result.ok());
   auto mapped_file = *mapped_file_result;
 
@@ -124,8 +146,8 @@
 
 /// Negative test to lock down the error when querying flag value out of range
 TEST_F(AconfigStorageTest, test_invalid_boolean_flag_value_update) {
-  auto mapped_file_result = private_api::get_mapped_flag_value_file_impl(
-      storage_record_pb, "mockup");
+  auto mapped_file_result = private_api::get_mutable_mapped_file_impl(
+      storage_record_pb, "mockup", api::StorageFileType::flag_val);
   ASSERT_TRUE(mapped_file_result.ok());
   auto mapped_file = *mapped_file_result;
   auto update_result = api::set_boolean_flag_value(mapped_file, 8, true);
@@ -133,3 +155,61 @@
   ASSERT_EQ(update_result.error().message(),
             std::string("InvalidStorageFileOffset(Flag value offset goes beyond the end of the file.)"));
 }
+
+/// Test to lock down storage flag stickiness update api
+TEST_F(AconfigStorageTest, test_flag_is_sticky_update) {
+  auto mapped_file_result = private_api::get_mutable_mapped_file_impl(
+      storage_record_pb, "mockup", api::StorageFileType::flag_info);
+  ASSERT_TRUE(mapped_file_result.ok());
+  auto mapped_file = *mapped_file_result;
+
+  for (int offset = 0; offset < 8; ++offset) {
+    auto update_result = api::set_flag_is_sticky(
+        mapped_file, api::FlagValueType::Boolean, offset, true);
+    ASSERT_TRUE(update_result.ok());
+    auto ro_mapped_file = api::MappedStorageFile();
+    ro_mapped_file.file_ptr = mapped_file.file_ptr;
+    ro_mapped_file.file_size = mapped_file.file_size;
+    auto attribute = api::get_boolean_flag_attribute(ro_mapped_file, offset);
+    ASSERT_TRUE(attribute.ok());
+    ASSERT_TRUE(*attribute & api::FlagInfoBit::IsSticky);
+
+    update_result = api::set_flag_is_sticky(
+        mapped_file, api::FlagValueType::Boolean, offset, false);
+    ASSERT_TRUE(update_result.ok());
+    ro_mapped_file.file_ptr = mapped_file.file_ptr;
+    ro_mapped_file.file_size = mapped_file.file_size;
+    attribute = api::get_boolean_flag_attribute(ro_mapped_file, offset);
+    ASSERT_TRUE(attribute.ok());
+    ASSERT_FALSE(*attribute & api::FlagInfoBit::IsSticky);
+  }
+}
+
+/// Test to lock down storage flag has override update api
+TEST_F(AconfigStorageTest, test_flag_has_override_update) {
+  auto mapped_file_result = private_api::get_mutable_mapped_file_impl(
+      storage_record_pb, "mockup", api::StorageFileType::flag_info);
+  ASSERT_TRUE(mapped_file_result.ok());
+  auto mapped_file = *mapped_file_result;
+
+  for (int offset = 0; offset < 8; ++offset) {
+    auto update_result = api::set_flag_has_override(
+        mapped_file, api::FlagValueType::Boolean, offset, true);
+    ASSERT_TRUE(update_result.ok());
+    auto ro_mapped_file = api::MappedStorageFile();
+    ro_mapped_file.file_ptr = mapped_file.file_ptr;
+    ro_mapped_file.file_size = mapped_file.file_size;
+    auto attribute = api::get_boolean_flag_attribute(ro_mapped_file, offset);
+    ASSERT_TRUE(attribute.ok());
+    ASSERT_TRUE(*attribute & api::FlagInfoBit::HasOverride);
+
+    update_result = api::set_flag_has_override(
+        mapped_file, api::FlagValueType::Boolean, offset, false);
+    ASSERT_TRUE(update_result.ok());
+    ro_mapped_file.file_ptr = mapped_file.file_ptr;
+    ro_mapped_file.file_size = mapped_file.file_size;
+    attribute = api::get_boolean_flag_attribute(ro_mapped_file, offset);
+    ASSERT_TRUE(attribute.ok());
+    ASSERT_FALSE(*attribute & api::FlagInfoBit::HasOverride);
+  }
+}
diff --git a/tools/aconfig/aconfig_storage_write_api/tests/storage_write_api_test.rs b/tools/aconfig/aconfig_storage_write_api/tests/storage_write_api_test.rs
index 4bda54c..f6a9b280 100644
--- a/tools/aconfig/aconfig_storage_write_api/tests/storage_write_api_test.rs
+++ b/tools/aconfig/aconfig_storage_write_api/tests/storage_write_api_test.rs
@@ -1,8 +1,13 @@
 #[cfg(not(feature = "cargo"))]
 mod aconfig_storage_write_api_test {
     use aconfig_storage_file::protos::ProtoStorageFiles;
+    use aconfig_storage_file::{FlagInfoBit, FlagValueType, StorageFileType};
+    use aconfig_storage_read_api::flag_info_query::find_boolean_flag_attribute;
     use aconfig_storage_read_api::flag_value_query::find_boolean_flag_value;
-    use aconfig_storage_write_api::{mapped_file::get_mapped_file, set_boolean_flag_value};
+    use aconfig_storage_write_api::{
+        mapped_file::get_mapped_file, set_boolean_flag_value, set_flag_has_override,
+        set_flag_is_sticky,
+    };
 
     use protobuf::Message;
     use std::fs::{self, File};
@@ -10,7 +15,7 @@
     use tempfile::NamedTempFile;
 
     /// Write storage location record pb to a temp file
-    fn write_storage_record_file(flag_val: &str) -> NamedTempFile {
+    fn write_storage_record_file(flag_val: &str, flag_info: &str) -> NamedTempFile {
         let text_proto = format!(
             r#"
 files {{
@@ -19,10 +24,11 @@
     package_map: "some_package_map"
     flag_map: "some_flag_map"
     flag_val: "{}"
+    flag_info: "{}"
     timestamp: 12345
 }}
 "#,
-            flag_val
+            flag_val, flag_info
         );
         let storage_files: ProtoStorageFiles =
             protobuf::text_format::parse_from_str(&text_proto).unwrap();
@@ -48,18 +54,30 @@
         find_boolean_flag_value(&bytes, offset).unwrap()
     }
 
+    /// Get flag attribute at offset
+    fn get_flag_attribute_at_offset(file: &str, offset: u32) -> u8 {
+        let mut f = File::open(file).unwrap();
+        let mut bytes = Vec::new();
+        f.read_to_end(&mut bytes).unwrap();
+        find_boolean_flag_attribute(&bytes, offset).unwrap()
+    }
+
     #[test]
     /// Test to lock down flag value update api
     fn test_boolean_flag_value_update() {
         let flag_value_file = copy_to_temp_rw_file("./flag.val");
+        let flag_info_file = copy_to_temp_rw_file("./flag.info");
         let flag_value_path = flag_value_file.path().display().to_string();
-        let record_pb_file = write_storage_record_file(&flag_value_path);
+        let flag_info_path = flag_info_file.path().display().to_string();
+        let record_pb_file = write_storage_record_file(&flag_value_path, &flag_info_path);
         let record_pb_path = record_pb_file.path().display().to_string();
 
         // SAFETY:
         // The safety here is ensured as only this single threaded test process will
         // write to this file
-        let mut file = unsafe { get_mapped_file(&record_pb_path, "mockup").unwrap() };
+        let mut file = unsafe {
+            get_mapped_file(&record_pb_path, "mockup", StorageFileType::FlagVal).unwrap()
+        };
         for i in 0..8 {
             set_boolean_flag_value(&mut file, i, true).unwrap();
             let value = get_boolean_flag_value_at_offset(&flag_value_path, i);
@@ -70,4 +88,56 @@
             assert!(!value);
         }
     }
+
+    #[test]
+    /// Test to lock down flag is sticky update api
+    fn test_set_flag_is_sticky() {
+        let flag_value_file = copy_to_temp_rw_file("./flag.val");
+        let flag_info_file = copy_to_temp_rw_file("./flag.info");
+        let flag_value_path = flag_value_file.path().display().to_string();
+        let flag_info_path = flag_info_file.path().display().to_string();
+        let record_pb_file = write_storage_record_file(&flag_value_path, &flag_info_path);
+        let record_pb_path = record_pb_file.path().display().to_string();
+
+        // SAFETY:
+        // The safety here is ensured as only this single threaded test process will
+        // write to this file
+        let mut file = unsafe {
+            get_mapped_file(&record_pb_path, "mockup", StorageFileType::FlagInfo).unwrap()
+        };
+        for i in 0..8 {
+            set_flag_is_sticky(&mut file, FlagValueType::Boolean, i, true).unwrap();
+            let attribute = get_flag_attribute_at_offset(&flag_info_path, i);
+            assert!((attribute & (FlagInfoBit::IsSticky as u8)) != 0);
+            set_flag_is_sticky(&mut file, FlagValueType::Boolean, i, false).unwrap();
+            let attribute = get_flag_attribute_at_offset(&flag_info_path, i);
+            assert!((attribute & (FlagInfoBit::IsSticky as u8)) == 0);
+        }
+    }
+
+    #[test]
+    /// Test to lock down flag is sticky update api
+    fn test_set_flag_has_override() {
+        let flag_value_file = copy_to_temp_rw_file("./flag.val");
+        let flag_info_file = copy_to_temp_rw_file("./flag.info");
+        let flag_value_path = flag_value_file.path().display().to_string();
+        let flag_info_path = flag_info_file.path().display().to_string();
+        let record_pb_file = write_storage_record_file(&flag_value_path, &flag_info_path);
+        let record_pb_path = record_pb_file.path().display().to_string();
+
+        // SAFETY:
+        // The safety here is ensured as only this single threaded test process will
+        // write to this file
+        let mut file = unsafe {
+            get_mapped_file(&record_pb_path, "mockup", StorageFileType::FlagInfo).unwrap()
+        };
+        for i in 0..8 {
+            set_flag_has_override(&mut file, FlagValueType::Boolean, i, true).unwrap();
+            let attribute = get_flag_attribute_at_offset(&flag_info_path, i);
+            assert!((attribute & (FlagInfoBit::HasOverride as u8)) != 0);
+            set_flag_has_override(&mut file, FlagValueType::Boolean, i, false).unwrap();
+            let attribute = get_flag_attribute_at_offset(&flag_info_path, i);
+            assert!((attribute & (FlagInfoBit::HasOverride as u8)) == 0);
+        }
+    }
 }