diff --git a/TEST_MAPPING b/TEST_MAPPING
index dc17051c0a3dfc201f133a0ecfc241e0bcb78fe7..85cd1c13a7515938559c8c5f0e4cd95a827a8f2c 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -84,6 +84,10 @@
     {
       "name" : "net_test_stack_a2dp_native",
       "host" : true
+    },
+    {
+      "name" : "net_test_btif_config_cache",
+      "host" : true
     }
   ]
 }
diff --git a/system/btif/Android.bp b/system/btif/Android.bp
index af5f88120befcca321b69353de20f3fe07fda0e3..e2af2483e88276e00ab2615306db4a34dea7bffd 100644
--- a/system/btif/Android.bp
+++ b/system/btif/Android.bp
@@ -55,6 +55,7 @@ cc_library_static {
         "src/btif_ble_scanner.cc",
         "src/btif_bqr.cc",
         "src/btif_config.cc",
+        "src/btif_config_cache.cc",
         "src/btif_config_transcode.cc",
         "src/btif_core.cc",
         "src/btif_debug.cc",
@@ -225,3 +226,29 @@ cc_test {
         misc_undefined: ["bounds"],
     },
 }
+
+// btif config cache unit tests for target
+// ========================================================
+cc_test {
+    name: "net_test_btif_config_cache",
+    defaults: ["fluoride_defaults"],
+    test_suites: ["device-tests"],
+    host_supported: true,
+    include_dirs: btifCommonIncludes,
+    srcs: [
+        "src/btif_config_cache.cc",
+        "test/btif_config_cache_test.cc",
+    ],
+    header_libs: ["libbluetooth_headers"],
+    shared_libs: [
+        "liblog",
+        "libcutils",
+    ],
+    static_libs: [
+        "libbluetooth-types",
+        "libosi",
+        "libgmock",
+        "libc++fs",
+    ],
+    cflags: ["-DBUILDCFG"],
+}
diff --git a/system/btif/include/btif_config.h b/system/btif/include/btif_config.h
index 5c7d433826830385bf8450ce4ae989c8e2f9f94d..d1678cd7e14e3f07fdc9133226ac06a29fefbaee 100644
--- a/system/btif/include/btif_config.h
+++ b/system/btif/include/btif_config.h
@@ -64,7 +64,7 @@ bool btif_config_remove(const std::string& section, const std::string& key);
 size_t btif_config_get_bin_length(const std::string& section,
                                   const std::string& key);
 
-std::list<section_t>& btif_config_sections();
+const std::list<section_t>& btif_config_sections();
 
 void btif_config_save(void);
 void btif_config_flush(void);
diff --git a/system/btif/include/btif_config_cache.h b/system/btif/include/btif_config_cache.h
new file mode 100644
index 0000000000000000000000000000000000000000..aedcd4eb4e7e44c289cd44538c45cc7221724764
--- /dev/null
+++ b/system/btif/include/btif_config_cache.h
@@ -0,0 +1,60 @@
+/*
+ *  Copyright 2020 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.
+ */
+
+#pragma once
+
+#include <map>
+#include <unordered_set>
+
+#include "common/lru.h"
+#include "osi/include/config.h"
+#include "osi/include/log.h"
+#include "raw_address.h"
+
+class BtifConfigCache {
+ public:
+  explicit BtifConfigCache(size_t capacity);
+  ~BtifConfigCache();
+
+  void Clear();
+  void Init(std::unique_ptr<config_t> source);
+  const std::list<section_t>& GetPersistentSections();
+  config_t PersistentSectionCopy();
+  bool HasSection(const std::string& section_name);
+  bool HasUnpairedSection(const std::string& section_name);
+  bool HasPersistentSection(const std::string& section_name);
+  bool HasKey(const std::string& section_name, const std::string& key);
+  bool RemoveKey(const std::string& section_name, const std::string& key);
+  void RemovePersistentSectionsWithKey(const std::string& key);
+
+  // Setters and getters
+  void SetString(std::string section_name, std::string key, std::string value);
+  std::optional<std::string> GetString(const std::string& section_name,
+                                       const std::string& key);
+  void SetInt(std::string section_name, std::string key, int value);
+  std::optional<int> GetInt(const std::string& section_name,
+                            const std::string& key);
+  void SetUint64(std::string section_name, std::string key, uint64_t value);
+  std::optional<uint64_t> GetUint64(const std::string& section_name,
+                                    const std::string& key);
+  void SetBool(std::string section_name, std::string key, bool value);
+  std::optional<bool> GetBool(const std::string& section_name,
+                              const std::string& key);
+
+ private:
+  bluetooth::common::LruCache<std::string, section_t> unpaired_devices_cache_;
+  config_t paired_devices_list_;
+};
diff --git a/system/btif/src/btif_config.cc b/system/btif/src/btif_config.cc
index b710c2ef3009e46af74c54beb0e22267a9505bd7..d95aa55a01a2ca6811fdc88f04800deca347a6ed 100644
--- a/system/btif/src/btif_config.cc
+++ b/system/btif/src/btif_config.cc
@@ -40,6 +40,7 @@
 #include "btcore/include/module.h"
 #include "btif_api.h"
 #include "btif_common.h"
+#include "btif_config_cache.h"
 #include "btif_config_transcode.h"
 #include "btif_util.h"
 #include "common/address_obfuscator.h"
@@ -56,6 +57,7 @@
 #include "raw_address.h"
 
 #define BT_CONFIG_SOURCE_TAG_NUM 1010001
+#define TEMPORARY_SECTION_CAPACITY 10000
 
 #define INFO_SECTION "Info"
 #define FILE_TIMESTAMP "TimeCreated"
@@ -89,8 +91,6 @@ static void timer_config_save_cb(void* data);
 static void btif_config_write(uint16_t event, char* p_param);
 static bool is_factory_reset(void);
 static void delete_config_files(void);
-static void btif_config_remove_unpaired(config_t* config);
-static void btif_config_remove_restricted(config_t* config);
 static std::unique_ptr<config_t> btif_config_open(const char* filename);
 
 // Key attestation
@@ -121,7 +121,6 @@ static enum ConfigSource {
   RESET
 } btif_config_source = NOT_LOADED;
 
-static int btif_config_devices_loaded = -1;
 static char btif_config_time_created[TIME_STRING_LENGTH];
 
 static const storage_config_t interface = {
@@ -265,13 +264,16 @@ static void init_metric_id_allocator() {
 }
 
 static std::recursive_mutex config_lock;  // protects operations on |config|.
-static std::unique_ptr<config_t> config;
 static alarm_t* config_timer;
 
+// limited btif config cache capacity
+static BtifConfigCache btif_config_cache(TEMPORARY_SECTION_CAPACITY);
+
 // Module lifecycle functions
 
 static future_t* init(void) {
   std::unique_lock<std::recursive_mutex> lock(config_lock);
+  std::unique_ptr<config_t> config;
 
   if (is_factory_reset()) delete_config_files();
 
@@ -305,28 +307,29 @@ static future_t* init(void) {
     file_source = "Empty";
   }
 
-  if (!file_source.empty())
-    storage_config_get_interface()->config_set_string(
-        config.get(), INFO_SECTION, FILE_SOURCE, file_source);
+  // move persistent config data from btif_config file to btif config cache
+  btif_config_cache.Init(std::move(config));
 
-  btif_config_remove_unpaired(config.get());
+  if (!file_source.empty()) {
+    btif_config_cache.SetString(INFO_SECTION, FILE_SOURCE, file_source);
+  }
 
   // Cleanup temporary pairings if we have left guest mode
-  if (!is_restricted_mode()) btif_config_remove_restricted(config.get());
+  if (!is_restricted_mode()) {
+    btif_config_cache.RemovePersistentSectionsWithKey("Restricted");
+  }
 
   // Read or set config file creation timestamp
-  const std::string* time_str;
-  time_str = storage_config_get_interface()->config_get_string(
-      *config, INFO_SECTION, FILE_TIMESTAMP, NULL);
-  if (time_str != NULL) {
-    strlcpy(btif_config_time_created, time_str->c_str(), TIME_STRING_LENGTH);
-  } else {
+  auto time_str = btif_config_cache.GetString(INFO_SECTION, FILE_TIMESTAMP);
+  if (!time_str) {
     time_t current_time = time(NULL);
     struct tm* time_created = localtime(&current_time);
     strftime(btif_config_time_created, TIME_STRING_LENGTH, TIME_STRING_FORMAT,
              time_created);
-    storage_config_get_interface()->config_set_string(
-        config.get(), INFO_SECTION, FILE_TIMESTAMP, btif_config_time_created);
+    btif_config_cache.SetString(INFO_SECTION, FILE_TIMESTAMP,
+                                btif_config_time_created);
+  } else {
+    strlcpy(btif_config_time_created, time_str->c_str(), TIME_STRING_LENGTH);
   }
 
   // Read or set metrics 256 bit hashing salt
@@ -351,6 +354,7 @@ static future_t* init(void) {
 error:
   alarm_free(config_timer);
   config.reset();
+  btif_config_cache.Clear();
   config_timer = NULL;
   btif_config_source = NOT_LOADED;
   return future_new_immediate(FUTURE_FAIL);
@@ -383,7 +387,7 @@ static future_t* clean_up(void) {
   std::unique_lock<std::recursive_mutex> lock(config_lock);
   get_bluetooth_keystore_interface()->clear_map();
   MetricIdAllocator::GetInstance().Close();
-  config.reset();
+  btif_config_cache.Clear();
   return future_new_immediate(FUTURE_SUCCESS);
 }
 
@@ -394,98 +398,74 @@ EXPORT_SYMBOL module_t btif_config_module = {.name = BTIF_CONFIG_MODULE,
                                              .clean_up = clean_up};
 
 bool btif_config_has_section(const char* section) {
-  CHECK(config != NULL);
   CHECK(section != NULL);
 
   std::unique_lock<std::recursive_mutex> lock(config_lock);
-  return storage_config_get_interface()->config_has_section(*config, section);
+  return btif_config_cache.HasSection(section);
 }
 
 bool btif_config_exist(const std::string& section, const std::string& key) {
-  CHECK(config != NULL);
-
   std::unique_lock<std::recursive_mutex> lock(config_lock);
-  return storage_config_get_interface()->config_has_key(*config, section, key);
+  return btif_config_cache.HasKey(section, key);
 }
 
 bool btif_config_get_int(const std::string& section, const std::string& key,
                          int* value) {
-  CHECK(config != NULL);
   CHECK(value != NULL);
-
   std::unique_lock<std::recursive_mutex> lock(config_lock);
-  bool ret =
-      storage_config_get_interface()->config_has_key(*config, section, key);
-  if (ret)
-    *value = storage_config_get_interface()->config_get_int(*config, section,
-                                                            key, *value);
-
-  return ret;
+  auto ret = btif_config_cache.GetInt(section, key);
+  if (!ret) {
+    return false;
+  }
+  *value = *ret;
+  return true;
 }
 
 bool btif_config_set_int(const std::string& section, const std::string& key,
                          int value) {
-  CHECK(config != NULL);
-
   std::unique_lock<std::recursive_mutex> lock(config_lock);
-  storage_config_get_interface()->config_set_int(config.get(), section, key,
-                                                 value);
-
+  btif_config_cache.SetInt(section, key, value);
   return true;
 }
 
 bool btif_config_get_uint64(const std::string& section, const std::string& key,
                             uint64_t* value) {
-  CHECK(config != NULL);
   CHECK(value != NULL);
-
   std::unique_lock<std::recursive_mutex> lock(config_lock);
-  bool ret =
-      storage_config_get_interface()->config_has_key(*config, section, key);
-  if (ret)
-    *value = storage_config_get_interface()->config_get_uint64(*config, section,
-                                                               key, *value);
-
-  return ret;
+  auto ret = btif_config_cache.GetUint64(section, key);
+  if (!ret) {
+    return false;
+  }
+  *value = *ret;
+  return true;
 }
 
 bool btif_config_set_uint64(const std::string& section, const std::string& key,
                             uint64_t value) {
-  CHECK(config != NULL);
-
   std::unique_lock<std::recursive_mutex> lock(config_lock);
-  storage_config_get_interface()->config_set_uint64(config.get(), section, key,
-                                                    value);
-
+  btif_config_cache.SetUint64(section, key, value);
   return true;
 }
 
 bool btif_config_get_str(const std::string& section, const std::string& key,
                          char* value, int* size_bytes) {
-  CHECK(config != NULL);
   CHECK(value != NULL);
   CHECK(size_bytes != NULL);
 
   {
     std::unique_lock<std::recursive_mutex> lock(config_lock);
-    const std::string* stored_value =
-        storage_config_get_interface()->config_get_string(*config, section, key,
-                                                          NULL);
+    auto stored_value = btif_config_cache.GetString(section, key);
     if (!stored_value) return false;
     strlcpy(value, stored_value->c_str(), *size_bytes);
   }
-
   *size_bytes = strlen(value) + 1;
   return true;
 }
 
 bool btif_config_set_str(const std::string& section, const std::string& key,
                          const std::string& value) {
-  CHECK(config != NULL);
-
   std::unique_lock<std::recursive_mutex> lock(config_lock);
-  storage_config_get_interface()->config_set_string(config.get(), section, key,
-                                                    value);
+  btif_config_cache.SetString(section, key, value);
   return true;
 }
 
@@ -497,14 +477,12 @@ static bool btif_in_encrypt_key_name_list(std::string key) {
 
 bool btif_config_get_bin(const std::string& section, const std::string& key,
                          uint8_t* value, size_t* length) {
-  CHECK(config != NULL);
   CHECK(value != NULL);
   CHECK(length != NULL);
 
   std::unique_lock<std::recursive_mutex> lock(config_lock);
   const std::string* value_str;
-  const std::string* value_str_from_config =
-      config_get_string(*config, section, key, NULL);
+  auto value_str_from_config = btif_config_cache.GetString(section, key);
 
   if (!value_str_from_config) {
     VLOG(1) << __func__ << ": cannot find string for section " << section
@@ -521,7 +499,7 @@ bool btif_config_get_bin(const std::string& section, const std::string& key,
     string = get_bluetooth_keystore_interface()->get_key(section + "-" + key);
     value_str = &string;
   } else {
-    value_str = value_str_from_config;
+    value_str = &value_str_from_config.value();
   }
 
   size_t value_len = value_str->length();
@@ -546,11 +524,11 @@ bool btif_config_get_bin(const std::string& section, const std::string& key,
         !is_key_encrypted) {
       get_bluetooth_keystore_interface()->set_encrypt_key_or_remove_key(
           section + "-" + key, *value_str_from_config);
-      config_set_string(config.get(), section, key, ENCRYPTED_STR);
+      btif_config_cache.SetString(section, key, ENCRYPTED_STR);
     }
   } else {
     if (in_encrypt_key_name_list && is_key_encrypted) {
-      config_set_string(config.get(), section, key, value_str->c_str());
+      btif_config_cache.SetString(section, key, *value_str);
     }
   }
 
@@ -559,14 +537,9 @@ bool btif_config_get_bin(const std::string& section, const std::string& key,
 
 size_t btif_config_get_bin_length(const std::string& section,
                                   const std::string& key) {
-  CHECK(config != NULL);
-
   std::unique_lock<std::recursive_mutex> lock(config_lock);
-  const std::string* value_str =
-      storage_config_get_interface()->config_get_string(*config, section, key,
-                                                        NULL);
+  auto value_str = btif_config_cache.GetString(section, key);
   if (!value_str) return 0;
-
   size_t value_len = value_str->length();
   return ((value_len % 2) != 0) ? 0 : (value_len / 2);
 }
@@ -574,9 +547,6 @@ size_t btif_config_get_bin_length(const std::string& section,
 bool btif_config_set_bin(const std::string& section, const std::string& key,
                          const uint8_t* value, size_t length) {
   const char* lookup = "0123456789abcdef";
-
-  CHECK(config != NULL);
-
   if (length > 0) CHECK(value != NULL);
 
   size_t max_value = ((size_t)-1);
@@ -604,37 +574,33 @@ bool btif_config_set_bin(const std::string& section, const std::string& key,
 
   {
     std::unique_lock<std::recursive_mutex> lock(config_lock);
-    storage_config_get_interface()->config_set_string(config.get(), section,
-                                                      key, value_str);
+    btif_config_cache.SetString(section, key, value_str);
   }
 
   osi_free(str);
   return true;
 }
 
-std::list<section_t>& btif_config_sections() { return config->sections; }
+const std::list<section_t>& btif_config_sections() {
+  return btif_config_cache.GetPersistentSections();
+}
 
 bool btif_config_remove(const std::string& section, const std::string& key) {
-  CHECK(config != NULL);
-
   if (is_niap_mode() && btif_in_encrypt_key_name_list(key)) {
     get_bluetooth_keystore_interface()->set_encrypt_key_or_remove_key(
         section + "-" + key, "");
   }
   std::unique_lock<std::recursive_mutex> lock(config_lock);
-  return storage_config_get_interface()->config_remove_key(config.get(),
-                                                           section, key);
+  return btif_config_cache.RemoveKey(section, key);
 }
 
 void btif_config_save(void) {
-  CHECK(config != NULL);
   CHECK(config_timer != NULL);
 
   alarm_set(config_timer, CONFIG_SETTLE_PERIOD_MS, timer_config_save_cb, NULL);
 }
 
 void btif_config_flush(void) {
-  CHECK(config != NULL);
   CHECK(config_timer != NULL);
 
   alarm_cancel(config_timer);
@@ -642,17 +608,15 @@ void btif_config_flush(void) {
 }
 
 bool btif_config_clear(void) {
-  CHECK(config != NULL);
   CHECK(config_timer != NULL);
 
   alarm_cancel(config_timer);
 
   std::unique_lock<std::recursive_mutex> lock(config_lock);
 
-  config = storage_config_get_interface()->config_new_empty();
-
-  bool ret =
-      storage_config_get_interface()->config_save(*config, CONFIG_FILE_PATH);
+  btif_config_cache.Clear();
+  bool ret = storage_config_get_interface()->config_save(
+      btif_config_cache.PersistentSectionCopy(), CONFIG_FILE_PATH);
   btif_config_source = RESET;
 
   return ret;
@@ -667,52 +631,18 @@ static void timer_config_save_cb(UNUSED_ATTR void* data) {
 
 static void btif_config_write(UNUSED_ATTR uint16_t event,
                               UNUSED_ATTR char* p_param) {
-  CHECK(config != NULL);
   CHECK(config_timer != NULL);
 
   std::unique_lock<std::recursive_mutex> lock(config_lock);
   rename(CONFIG_FILE_PATH, CONFIG_BACKUP_PATH);
-  std::unique_ptr<config_t> config_paired =
-      storage_config_get_interface()->config_new_clone(*config);
-  btif_config_remove_unpaired(config_paired.get());
-  storage_config_get_interface()->config_save(*config_paired, CONFIG_FILE_PATH);
+  storage_config_get_interface()->config_save(
+      btif_config_cache.PersistentSectionCopy(), CONFIG_FILE_PATH);
   if (btif_is_niap_mode()) {
     get_bluetooth_keystore_interface()->set_encrypt_key_or_remove_key(
         CONFIG_FILE_PREFIX, CONFIG_FILE_HASH);
   }
 }
 
-static void btif_config_remove_unpaired(config_t* conf) {
-  CHECK(conf != NULL);
-  int paired_devices = 0;
-
-  // The paired config used to carry information about
-  // discovered devices during regular inquiry scans.
-  // We remove these now and cache them in memory instead.
-  for (auto it = conf->sections.begin(); it != conf->sections.end();) {
-    std::string& section = it->name;
-    if (RawAddress::IsValidAddress(section)) {
-      // TODO: config_has_key loop thorugh all data, maybe just make it so we
-      // loop just once ?
-      if (!config_has_key(*conf, section, "LinkKey") &&
-          !config_has_key(*conf, section, "LE_KEY_PENC") &&
-          !config_has_key(*conf, section, "LE_KEY_PID") &&
-          !config_has_key(*conf, section, "LE_KEY_PCSRK") &&
-          !config_has_key(*conf, section, "LE_KEY_LENC") &&
-          !config_has_key(*conf, section, "LE_KEY_LCSRK")) {
-        it = conf->sections.erase(it);
-        continue;
-      }
-      paired_devices++;
-    }
-    it++;
-  }
-
-  // should only happen once, at initial load time
-  if (btif_config_devices_loaded == -1)
-    btif_config_devices_loaded = paired_devices;
-}
-
 void btif_debug_config_dump(int fd) {
   dprintf(fd, "\nBluetooth Config:\n");
 
@@ -738,30 +668,15 @@ void btif_debug_config_dump(int fd) {
       break;
   }
 
-  std::string original = "Original";
-  dprintf(fd, "  Devices loaded: %d\n", btif_config_devices_loaded);
-  dprintf(fd, "  File created/tagged: %s\n", btif_config_time_created);
-  dprintf(fd, "  File source: %s\n",
-          storage_config_get_interface()
-              ->config_get_string(*config, INFO_SECTION, FILE_SOURCE, &original)
-              ->c_str());
-}
-
-static void btif_config_remove_restricted(config_t* config) {
-  CHECK(config != NULL);
-
-  for (auto it = config->sections.begin(); it != config->sections.end();) {
-    const std::string& section = it->name;
-    if (RawAddress::IsValidAddress(section) &&
-        storage_config_get_interface()->config_has_key(*config, section,
-                                                       "Restricted")) {
-      BTIF_TRACE_DEBUG("%s: Removing restricted device %s", __func__,
-                       section.c_str());
-      it = config->sections.erase(it);
-      continue;
-    }
-    it++;
+  auto file_source = btif_config_cache.GetString(INFO_SECTION, FILE_SOURCE);
+  if (!file_source) {
+    file_source.emplace("Original");
   }
+
+  dprintf(fd, "  Devices loaded: %zu\n",
+          btif_config_cache.GetPersistentSections().size());
+  dprintf(fd, "  File created/tagged: %s\n", btif_config_time_created);
+  dprintf(fd, "  File source: %s\n", file_source->c_str());
 }
 
 static bool is_factory_reset(void) {
diff --git a/system/btif/src/btif_config_cache.cc b/system/btif/src/btif_config_cache.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c5562aa8600f94d29d98d92aef6ca8e6d947a137
--- /dev/null
+++ b/system/btif/src/btif_config_cache.cc
@@ -0,0 +1,301 @@
+/*
+ *  Copyright 2020 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 <limits>
+
+#include "btif_config_cache.h"
+
+namespace {
+
+const std::unordered_set<std::string> kLinkKeyTypes = {
+    "LinkKey",      "LE_KEY_PENC", "LE_KEY_PID",
+    "LE_KEY_PCSRK", "LE_KEY_LENC", "LE_KEY_LCSRK"};
+
+const std::unordered_set<std::string> kLocalSectionNames = {"Info", "Metrics",
+                                                            "Adapter"};
+
+bool is_link_key(const std::string& key) {
+  return kLinkKeyTypes.find(key) != kLinkKeyTypes.end();
+}
+
+bool has_link_key_in_section(const section_t& section) {
+  for (const auto& entry : section.entries) {
+    if (is_link_key(entry.key)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool is_local_section_info(const std::string& section) {
+  return kLocalSectionNames.find(section) != kLocalSectionNames.end();
+}
+
+// trim new line in place, return true if newline was found
+bool trim_new_line(std::string& value) {
+  size_t newline_position = value.find_first_of('\n');
+  if (newline_position != std::string::npos) {
+    value.erase(newline_position);
+    return true;
+  }
+  return false;
+}
+
+}  // namespace
+
+BtifConfigCache::BtifConfigCache(size_t capacity)
+    : unpaired_devices_cache_(capacity, "bt_config_cache") {
+  LOG(INFO) << __func__ << ", capacity: " << capacity;
+}
+
+BtifConfigCache::~BtifConfigCache() { Clear(); }
+
+void BtifConfigCache::Clear() {
+  unpaired_devices_cache_.Clear();
+  paired_devices_list_.sections.clear();
+}
+
+void BtifConfigCache::Init(std::unique_ptr<config_t> source) {
+  // get the config persistent data from btif_config file
+  paired_devices_list_ = std::move(*source);
+  source.reset();
+}
+
+bool BtifConfigCache::HasPersistentSection(const std::string& section_name) {
+  return paired_devices_list_.Find(section_name) !=
+         paired_devices_list_.sections.end();
+}
+
+bool BtifConfigCache::HasUnpairedSection(const std::string& section_name) {
+  return unpaired_devices_cache_.HasKey(section_name);
+}
+
+bool BtifConfigCache::HasSection(const std::string& section_name) {
+  return HasUnpairedSection(section_name) || HasPersistentSection(section_name);
+}
+
+bool BtifConfigCache::HasKey(const std::string& section_name,
+                             const std::string& key) {
+  auto section_iter = paired_devices_list_.Find(section_name);
+  if (section_iter != paired_devices_list_.sections.end()) {
+    return section_iter->Has(key);
+  }
+  section_t* section = unpaired_devices_cache_.Find(section_name);
+  if (section == nullptr) {
+    return false;
+  }
+  return section->Has(key);
+}
+
+// remove sections with the restricted key
+void BtifConfigCache::RemovePersistentSectionsWithKey(const std::string& key) {
+  for (auto it = paired_devices_list_.sections.begin();
+       it != paired_devices_list_.sections.end();) {
+    if (it->Has(key)) {
+      it = paired_devices_list_.sections.erase(it);
+      continue;
+    }
+    it++;
+  }
+}
+
+/* remove a key from section, section itself is removed when empty */
+bool BtifConfigCache::RemoveKey(const std::string& section_name,
+                                const std::string& key) {
+  section_t* section = unpaired_devices_cache_.Find(section_name);
+  if (section != nullptr) {
+    auto entry_iter = section->Find(key);
+    if (entry_iter == section->entries.end()) {
+      return false;
+    }
+    section->entries.erase(entry_iter);
+    if (section->entries.empty()) {
+      unpaired_devices_cache_.Remove(section_name);
+    }
+    return true;
+  } else {
+    auto section_iter = paired_devices_list_.Find(section_name);
+    if (section_iter == paired_devices_list_.sections.end()) {
+      return false;
+    }
+    auto entry_iter = section_iter->Find(key);
+    if (entry_iter == section_iter->entries.end()) {
+      return false;
+    }
+    section_iter->entries.erase(entry_iter);
+    if (section_iter->entries.empty()) {
+      paired_devices_list_.sections.erase(section_iter);
+    } else if (!has_link_key_in_section(*section_iter)) {
+      // if no link key in section after removal, move it to unpaired section
+      auto moved_section = std::move(*section_iter);
+      paired_devices_list_.sections.erase(section_iter);
+      unpaired_devices_cache_.Put(section_name, std::move(moved_section));
+    }
+    return true;
+  }
+}
+
+/* clone persistent sections (Local Adapter sections, remote paired devices
+ * section,..) */
+config_t BtifConfigCache::PersistentSectionCopy() {
+  return paired_devices_list_;
+}
+
+const std::list<section_t>& BtifConfigCache::GetPersistentSections() {
+  return paired_devices_list_.sections;
+}
+
+void BtifConfigCache::SetString(std::string section_name, std::string key,
+                                std::string value) {
+  if (trim_new_line(section_name) || trim_new_line(key) ||
+      trim_new_line(value)) {
+    android_errorWriteLog(0x534e4554, "70808273");
+  }
+  if (section_name.empty()) {
+    LOG(FATAL) << "Empty section not allowed";
+    return;
+  }
+  if (key.empty()) {
+    LOG(FATAL) << "Empty key not allowed";
+    return;
+  }
+  if (!paired_devices_list_.Has(section_name)) {
+    // section is not in paired_device_list, handle it in unpaired devices cache
+    section_t section = {};
+    bool in_unpaired_cache = true;
+    if (!unpaired_devices_cache_.Get(section_name, &section)) {
+      // it's a new unpaired section, add it to unpaired devices cache
+      section.name = section_name;
+      in_unpaired_cache = false;
+    }
+    // set key to value and replace existing key if already exist
+    section.Set(key, value);
+
+    if (is_local_section_info(section_name) ||
+        (is_link_key(key) && RawAddress::IsValidAddress(section_name))) {
+      // remove this section that has the LinkKey from unpaired devices cache.
+      if (in_unpaired_cache) {
+        unpaired_devices_cache_.Remove(section_name);
+      }
+      // when a unpaired section got the LinkKey, move this section to the
+      // paired devices list
+      paired_devices_list_.sections.emplace_back(std::move(section));
+    } else {
+      // update to the unpaired devices cache
+      unpaired_devices_cache_.Put(section_name, section);
+    }
+  } else {
+    // already have section in paired device list, add key-value entry.
+    auto section_found = paired_devices_list_.Find(section_name);
+    if (section_found == paired_devices_list_.sections.end()) {
+      LOG(WARNING) << __func__ << " , section_found not found!";
+      return;
+    }
+    section_found->Set(key, value);
+  }
+}
+
+std::optional<std::string> BtifConfigCache::GetString(
+    const std::string& section_name, const std::string& key) {
+  // Check paired sections first
+  auto section_iter = paired_devices_list_.Find(section_name);
+  if (section_iter != paired_devices_list_.sections.end()) {
+    auto entry_iter = section_iter->Find(key);
+    if (entry_iter == section_iter->entries.end()) {
+      return std::nullopt;
+    }
+    return entry_iter->value;
+  }
+  // Check unpaired sections later
+  section_t section = {};
+  if (!unpaired_devices_cache_.Get(section_name, &section)) {
+    return std::nullopt;
+  }
+  auto entry_iter = section.Find(key);
+  if (entry_iter == section.entries.end()) {
+    return std::nullopt;
+  }
+  return entry_iter->value;
+}
+
+void BtifConfigCache::SetInt(std::string section_name, std::string key,
+                             int value) {
+  SetString(std::move(section_name), std::move(key), std::to_string(value));
+}
+
+std::optional<int> BtifConfigCache::GetInt(const std::string& section_name,
+                                           const std::string& key) {
+  auto value = GetString(section_name, key);
+  if (!value) {
+    return std::nullopt;
+  }
+  char* endptr;
+  long ret_long = strtol(value->c_str(), &endptr, 0);
+  if (*endptr != '\0') {
+    LOG(WARNING) << "Failed to parse value to long for section " << section_name
+                 << ", key " << key;
+    return std::nullopt;
+  }
+  if (ret_long >= std::numeric_limits<int>::max()) {
+    LOG(WARNING) << "Integer overflow when parsing value to int for section "
+                 << section_name << ", key " << key;
+    return std::nullopt;
+  }
+  return static_cast<int>(ret_long);
+}
+
+void BtifConfigCache::SetUint64(std::string section_name, std::string key,
+                                uint64_t value) {
+  SetString(std::move(section_name), std::move(key), std::to_string(value));
+}
+
+std::optional<uint64_t> BtifConfigCache::GetUint64(
+    const std::string& section_name, const std::string& key) {
+  auto value = GetString(section_name, key);
+  if (!value) {
+    return std::nullopt;
+  }
+  char* endptr;
+  uint64_t ret = strtoull(value->c_str(), &endptr, 0);
+  if (*endptr != '\0') {
+    LOG(WARNING) << "Failed to parse value to uint64 for section "
+                 << section_name << ", key " << key;
+    return std::nullopt;
+  }
+  return ret;
+}
+
+void BtifConfigCache::SetBool(std::string section_name, std::string key,
+                              bool value) {
+  SetString(std::move(section_name), std::move(key), value ? "true" : "false");
+}
+
+std::optional<bool> BtifConfigCache::GetBool(const std::string& section_name,
+                                             const std::string& key) {
+  auto value = GetString(section_name, key);
+  if (!value) {
+    return std::nullopt;
+  }
+  if (*value == "true") {
+    return true;
+  }
+  if (*value == "false") {
+    return false;
+  }
+  LOG(WARNING) << "Failed to parse value to boolean for section "
+               << section_name << ", key " << key;
+  return std::nullopt;
+}
diff --git a/system/btif/test/btif_config_cache_test.cc b/system/btif/test/btif_config_cache_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..aaccf8c0cbe7953e1e5fe61d418819ab916f0a83
--- /dev/null
+++ b/system/btif/test/btif_config_cache_test.cc
@@ -0,0 +1,527 @@
+/*
+ *  Copyright 2020 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 "btif/include/btif_config_cache.h"
+
+#include <filesystem>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace {
+
+const int kCapacity = 3;
+const int kTestRepeatCount = 30;
+const std::string kBtAddr1 = "11:22:33:44:55:66";
+const std::string kBtAddr2 = "AA:BB:CC:DD:EE:FF";
+const std::string kBtAddr3 = "AB:CD:EF:12:34:56";
+const std::string kBtAddr4 = "11:AA:22:BB:33:CC";
+const std::string kBtAddr5 = "11:AA:22:BB:33:CD";
+const std::string kBtLocalAddr = "12:34:56:78:90:AB";
+const std::string kBtInfo = "Info";
+const std::string kBtMetrics = "Metrics";
+const std::string kBtAdapter = "Adapter";
+const std::string kBtAddrInvalid1 = "AB:CD:EF:12:34";
+const std::string kBtAddrInvalid2 = "AB:CD:EF:12:34:56:78";
+const std::string kBtAddrInvalid3 = "ABCDEF123456";
+const std::string kBtAddrInvalid4 = "AB-CD-EF-12-34-56";
+const std::string kBtSectionInvalid1 = "Invalid Section";
+const std::filesystem::path kTestConfigFile =
+    std::filesystem::temp_directory_path() / "config_cache_test.conf";
+const char* TEST_CONFIG_FILE = kTestConfigFile.c_str();
+
+}  // namespace
+
+namespace testing {
+
+/* Test to basic btif_config_cache set up
+ * 1. when received Local device sections information, the sections can be put
+ * into btif config cache
+ * 2. the device sections and key-value will be set to Btif config cache when
+ * receiving different device sections
+ * 3. limit the capacity of unpacire devices cache to 3, test the oldest device
+ * section will be ruled out when receiveing 4 different device sections.
+ */
+TEST(BtifConfigCacheTest, test_setup_btif_config_cache) {
+  BtifConfigCache test_btif_config_cache(kCapacity);
+  // Info section
+  test_btif_config_cache.SetString(kBtInfo, "FileSource", "");
+  test_btif_config_cache.SetString(kBtInfo, "TimeCreated",
+                                   "2020-06-05 12:12:12");
+  // Metrics section
+  test_btif_config_cache.SetString(kBtMetrics, "Salt256Bit",
+                                   "92a331174d20f2bb");
+  // Adapter Section
+  test_btif_config_cache.SetString(kBtAdapter, "Address", kBtLocalAddr);
+  EXPECT_TRUE(test_btif_config_cache.HasSection(kBtAdapter));
+
+  // bt_device_1
+  test_btif_config_cache.SetString(kBtAddr1, "Name", "Headset_1");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr1, "Name"));
+
+  test_btif_config_cache.SetInt(kBtAddr1, "Property_Int", 1);
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr1, "Property_Int"));
+
+  // bt_device_2
+  test_btif_config_cache.SetString(kBtAddr2, "Name", "Headset_2");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr2, "Name"));
+
+  // bt_device_3
+  test_btif_config_cache.SetString(kBtAddr3, "Name", "Headset_3");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr3, "Name"));
+
+  // bt_device_4
+  test_btif_config_cache.SetString(kBtAddr4, "Name", "Headset_4");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr4, "Name"));
+
+  // out out the capacty of unpair devices cache, the bt_device_1 be ruled out
+  EXPECT_FALSE(test_btif_config_cache.HasSection(kBtAddr1));
+  EXPECT_TRUE(test_btif_config_cache.HasSection(kBtAddr2));
+  EXPECT_TRUE(test_btif_config_cache.HasSection(kBtAddr3));
+  EXPECT_TRUE(test_btif_config_cache.HasSection(kBtAddr4));
+}
+
+/* Test to set up btif_config_cache with invalid bt address or section name
+ * when received Invalid bt address or section, it's not allowed to put invalid
+ * section to paired devices list section
+ */
+TEST(BtifConfigCacheTest, test_set_up_config_cache_with_invalid_section) {
+  BtifConfigCache test_btif_config_cache(kCapacity);
+
+  // kBtAddrInvalid1
+  test_btif_config_cache.SetString(kBtAddrInvalid1, "Name", "Headset_1");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddrInvalid1, "Name"));
+  EXPECT_TRUE(test_btif_config_cache.HasUnpairedSection(kBtAddrInvalid1));
+  // get the LinkKey
+  test_btif_config_cache.SetString(kBtAddrInvalid1, "LinkKey",
+                                   "1122334455667788");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddrInvalid1, "LinkKey"));
+  EXPECT_TRUE(test_btif_config_cache.HasUnpairedSection(kBtAddrInvalid1));
+  EXPECT_FALSE(test_btif_config_cache.HasPersistentSection(kBtAddrInvalid1));
+
+  // kBtAddrInvalid2
+  test_btif_config_cache.SetString(kBtAddrInvalid2, "Name", "Headset_1");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddrInvalid2, "Name"));
+  EXPECT_TRUE(test_btif_config_cache.HasUnpairedSection(kBtAddrInvalid2));
+  // get the LinkKey
+  test_btif_config_cache.SetString(kBtAddrInvalid2, "LinkKey",
+                                   "1122334455667788");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddrInvalid2, "LinkKey"));
+  EXPECT_TRUE(test_btif_config_cache.HasUnpairedSection(kBtAddrInvalid2));
+  EXPECT_FALSE(test_btif_config_cache.HasPersistentSection(kBtAddrInvalid2));
+
+  // kBtAddrInvalid3
+  test_btif_config_cache.SetString(kBtAddrInvalid3, "Name", "Headset_1");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddrInvalid3, "Name"));
+  EXPECT_TRUE(test_btif_config_cache.HasUnpairedSection(kBtAddrInvalid3));
+  // get the LinkKey
+  test_btif_config_cache.SetString(kBtAddrInvalid3, "LinkKey",
+                                   "1122334455667788");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddrInvalid3, "LinkKey"));
+  EXPECT_TRUE(test_btif_config_cache.HasUnpairedSection(kBtAddrInvalid3));
+  EXPECT_FALSE(test_btif_config_cache.HasPersistentSection(kBtAddrInvalid3));
+
+  // kBtAddrInvalid4
+  test_btif_config_cache.SetString(kBtAddrInvalid4, "Name", "Headset_1");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddrInvalid4, "Name"));
+  EXPECT_TRUE(test_btif_config_cache.HasUnpairedSection(kBtAddrInvalid4));
+  // get the LinkKey
+  test_btif_config_cache.SetString(kBtAddrInvalid4, "LinkKey",
+                                   "1122334455667788");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddrInvalid4, "LinkKey"));
+  EXPECT_TRUE(test_btif_config_cache.HasUnpairedSection(kBtAddrInvalid4));
+  EXPECT_FALSE(test_btif_config_cache.HasPersistentSection(kBtAddrInvalid4));
+
+  // kBtSectionInvalid1
+  test_btif_config_cache.SetString(kBtSectionInvalid1, "Name", "Headset_1");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtSectionInvalid1, "Name"));
+  EXPECT_TRUE(test_btif_config_cache.HasUnpairedSection(kBtSectionInvalid1));
+  // get the LinkKey
+  test_btif_config_cache.SetString(kBtSectionInvalid1, "LinkKey",
+                                   "1122334455667788");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtSectionInvalid1, "LinkKey"));
+  EXPECT_TRUE(test_btif_config_cache.HasUnpairedSection(kBtSectionInvalid1));
+  EXPECT_FALSE(test_btif_config_cache.HasPersistentSection(kBtSectionInvalid1));
+}
+
+/* Stress test to set and get key values
+ * 1. stress test to set different type key value to unpaired device cache and
+ * get the different type key values in the unpaired cache section to check if
+ * we get the key-values the same with we set in unpaired device cache.
+ * 2. stress test to set different type key value to paired device section and
+ * get the different type key values in the paired cache section to check if we
+ * get the key-values the same with we set in paired device cache.
+ */
+TEST(BtifConfigCacheTest, test_get_set_key_value_test) {
+  BtifConfigCache test_btif_config_cache(kCapacity);
+  // test in unpaired cache
+  test_btif_config_cache.SetString(kBtAddr1, "Name", "Headset_1");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr1, "Name"));
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr1, "Name"),
+              Optional(StrEq("Headset_1")));
+
+  test_btif_config_cache.SetInt(kBtAddr1, "Property_Int", 65536);
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr1, "Property_Int"));
+  EXPECT_THAT(test_btif_config_cache.GetInt(kBtAddr1, "Property_Int"),
+              Optional(Eq(65536)));
+
+  test_btif_config_cache.SetUint64(kBtAddr1, "Property_64", 4294967296);
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr1, "Property_64"));
+  EXPECT_THAT(test_btif_config_cache.GetUint64(kBtAddr1, "Property_64"),
+              Optional(Eq(uint64_t(4294967296))));
+
+  test_btif_config_cache.SetBool(kBtAddr1, "Property_Bool", true);
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr1, "Property_Bool"));
+  EXPECT_THAT(test_btif_config_cache.GetBool(kBtAddr1, "Property_Bool"),
+              Optional(IsTrue()));
+
+  // empty value
+  test_btif_config_cache.SetString(kBtAddr1, "Name", "");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr1, "Name"));
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr1, "Name"),
+              Optional(StrEq("")));
+
+  // get the LinkKey
+  test_btif_config_cache.SetString(kBtAddr1, "LinkKey", "1122334455667788");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr1, "LinkKey"));
+  EXPECT_FALSE(test_btif_config_cache.HasUnpairedSection(kBtAddr1));
+  EXPECT_TRUE(test_btif_config_cache.HasPersistentSection(kBtAddr1));
+
+  // test in unpaired cache
+  test_btif_config_cache.SetString(kBtAddr1, "Name", "Headset_1");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr1, "Name"));
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr1, "Name"),
+              Optional(StrEq("Headset_1")));
+
+  test_btif_config_cache.SetInt(kBtAddr1, "Property_Int", 65536);
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr1, "Property_Int"));
+  EXPECT_THAT(test_btif_config_cache.GetInt(kBtAddr1, "Property_Int"),
+              Optional(Eq(65536)));
+
+  test_btif_config_cache.SetUint64(kBtAddr1, "Property_64", 4294967296);
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr1, "Property_64"));
+  EXPECT_THAT(test_btif_config_cache.GetUint64(kBtAddr1, "Property_64"),
+              Optional(Eq(uint64_t(4294967296))));
+
+  test_btif_config_cache.SetBool(kBtAddr1, "Property_Bool", true);
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr1, "Property_Bool"));
+  EXPECT_THAT(test_btif_config_cache.GetBool(kBtAddr1, "Property_Bool"),
+              Optional(IsTrue()));
+
+  // empty section is disallowed
+  EXPECT_DEATH({ test_btif_config_cache.SetString("", "name", "Headset_1"); },
+               "Empty section not allowed");
+  // empty key is disallowed
+  EXPECT_DEATH({ test_btif_config_cache.SetString(kBtAddr1, "", "Headset_1"); },
+               "Empty key not allowed");
+  EXPECT_FALSE(test_btif_config_cache.HasKey(kBtAddr1, ""));
+  // empty value is allowed
+  test_btif_config_cache.SetString(kBtAddr1, "Name", "");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr1, "Name"));
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr1, "Name"),
+              Optional(StrEq("")));
+}
+
+/* Test to set values in the same key
+ * Receiving the same key with different values in a section, the new incoming
+ * value will be updated but the key will not be added repeatedly. test this
+ * feature in both unpaired devic cache and paired device list cache
+ */
+TEST(BtifConfigCacheTest, test_set_values_in_the_same_key) {
+  BtifConfigCache test_btif_config_cache(kCapacity);
+  // add new a key "Name"
+  test_btif_config_cache.SetString(kBtAddr1, "Name", "Headset_1");
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr1, "Name"),
+              Optional(StrEq("Headset_1")));
+  EXPECT_TRUE(test_btif_config_cache.HasUnpairedSection(kBtAddr1));
+
+  // add the same key "Name" with different value
+  test_btif_config_cache.SetString(kBtAddr1, "Name", "Headset_1A");
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr1, "Name"),
+              Optional(StrEq("Headset_1A")));
+
+  // add the same key "Name" with different value
+  test_btif_config_cache.SetString(kBtAddr1, "Name", "Headset_2A");
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr1, "Name"),
+              Optional(StrEq("Headset_2A")));
+  EXPECT_TRUE(test_btif_config_cache.HasUnpairedSection(kBtAddr1));
+
+  // add new a key "Property_Int"
+  test_btif_config_cache.SetInt(kBtAddr1, "Property_Int", 65536);
+  EXPECT_THAT(test_btif_config_cache.GetInt(kBtAddr1, "Property_Int"),
+              Optional(Eq(65536)));
+
+  // add the same key "Property_Int" with different value
+  test_btif_config_cache.SetInt(kBtAddr1, "Property_Int", 256);
+  EXPECT_THAT(test_btif_config_cache.GetInt(kBtAddr1, "Property_Int"),
+              Optional(Eq(256)));
+
+  test_btif_config_cache.SetUint64(kBtAddr1, "Property_64", 4294967296);
+  EXPECT_THAT(test_btif_config_cache.GetUint64(kBtAddr1, "Property_64"),
+              Optional(Eq(uint64_t(4294967296))));
+
+  // get the LinkKey and set values in the same key in paired device list
+  test_btif_config_cache.SetString(kBtAddr1, "LinkKey", "1122334455667788");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr1, "LinkKey"));
+  EXPECT_FALSE(test_btif_config_cache.HasUnpairedSection(kBtAddr1));
+  EXPECT_TRUE(test_btif_config_cache.HasPersistentSection(kBtAddr1));
+
+  // add the same key "Name" with the different value
+  test_btif_config_cache.SetString(kBtAddr1, "Name", "Headset_1A");
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr1, "Name"),
+              Optional(StrEq("Headset_1A")));
+
+  // add the same key "Name" with the value different
+  test_btif_config_cache.SetString(kBtAddr1, "Name", "Headset_2A");
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr1, "Name"),
+              Optional(StrEq("Headset_2A")));
+
+  test_btif_config_cache.SetInt(kBtAddr1, "Property_Int", 64);
+  EXPECT_THAT(test_btif_config_cache.GetInt(kBtAddr1, "Property_Int"),
+              Optional(Eq(64)));
+
+  test_btif_config_cache.SetUint64(kBtAddr1, "Property_64", 65537);
+  EXPECT_THAT(test_btif_config_cache.GetUint64(kBtAddr1, "Property_64"),
+              Optional(Eq(uint64_t(65537))));
+
+  EXPECT_TRUE(test_btif_config_cache.HasPersistentSection(kBtAddr1));
+}
+
+/* Stress test to pair with device then unpair device
+ * 1. paired with device by adding a "LinKey" to device and check the device be
+ * moved into paired devices list
+ * 2. unpaired with the device by removing the "LinkKey" and check the device be
+ * moved back to unpaired devices cache
+ * 3. loop for 30 times
+ */
+TEST(BtifConfigCacheTest, test_pair_unpair_device_stress_test) {
+  BtifConfigCache test_btif_config_cache(kCapacity);
+
+  // pair with Headset_1 11:22:33:44:55:66
+  test_btif_config_cache.SetString(kBtAddr1, "Name", "Headset_1");
+  EXPECT_TRUE(test_btif_config_cache.HasUnpairedSection(kBtAddr1));
+  EXPECT_FALSE(test_btif_config_cache.HasPersistentSection(kBtAddr1));
+
+  for (int i = 0; i < kTestRepeatCount; ++i) {
+    // get the LinkKey, the device will be moved from the unpaired cache to
+    // paired cache
+    test_btif_config_cache.SetString(kBtAddr1, "LinkKey", "1122334455667788");
+    EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr1, "LinkKey"));
+    EXPECT_FALSE(test_btif_config_cache.HasUnpairedSection(kBtAddr1));
+    EXPECT_TRUE(test_btif_config_cache.HasPersistentSection(kBtAddr1));
+
+    // remove the LinkKey, the device will be moved from the paired cache to
+    // unpaired cache
+    test_btif_config_cache.RemoveKey(kBtAddr1, "LinkKey");
+    EXPECT_FALSE(test_btif_config_cache.HasKey(kBtAddr1, "LinkKey"));
+    EXPECT_TRUE(test_btif_config_cache.HasUnpairedSection(kBtAddr1));
+    EXPECT_FALSE(test_btif_config_cache.HasPersistentSection(kBtAddr1));
+  }
+}
+
+/* Stress test to pair with multi-devices and unpair with multi-devices
+ * 1. Pired with 4 devices with Link-Key type key in order, to check these 4
+ * devices are in the paired devices list cache
+ * 2. unpair with these 4 devices by removed Link-Key type key in order, to
+ * check the fisrt device was ruled-out from unpaired devices cache due to
+ * capacity limitation, and other 3 devices are be moved to unpaired device
+ * cache.
+ */
+TEST(BtifConfigCacheTest, test_multi_pair_unpair_with_devices) {
+  BtifConfigCache test_btif_config_cache(kCapacity);
+  // pair with 4 bt address devices by add different type linkkey.
+  test_btif_config_cache.SetString(kBtAddr1, "name", "kBtAddr1");
+  test_btif_config_cache.SetString(kBtAddr1, "LinkKey", "1122334455667788");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr1, "LinkKey"));
+
+  test_btif_config_cache.SetString(kBtAddr2, "name", "kBtAddr2");
+  test_btif_config_cache.SetString(kBtAddr2, "LE_KEY_PENC", "aabbccddeeff9900");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr2, "LE_KEY_PENC"));
+
+  test_btif_config_cache.SetString(kBtAddr3, "name", "kBtAddr3");
+  test_btif_config_cache.SetString(kBtAddr3, "LE_KEY_PID", "a1b2c3d4e5feeeee");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr3, "LE_KEY_PID"));
+
+  test_btif_config_cache.SetString(kBtAddr4, "LE_KEY_PCSRK",
+                                   "aaaabbbbccccdddd");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr4, "LE_KEY_PCSRK"));
+
+  test_btif_config_cache.SetString(kBtAddr5, "name", "kBtAddr5");
+  test_btif_config_cache.SetString(kBtAddr5, "LE_KEY_LENC", "jilkjlkjlkn");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr5, "LE_KEY_LENC"));
+
+  // checking these 4 devices are in paired list cache and the content are
+  // correct.
+  EXPECT_TRUE(test_btif_config_cache.HasPersistentSection(kBtAddr1));
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr1, "LinkKey"),
+              Optional(StrEq("1122334455667788")));
+  EXPECT_TRUE(test_btif_config_cache.HasPersistentSection(kBtAddr2));
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr2, "LE_KEY_PENC"),
+              Optional(StrEq("aabbccddeeff9900")));
+  EXPECT_TRUE(test_btif_config_cache.HasPersistentSection(kBtAddr3));
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr3, "LE_KEY_PID"),
+              Optional(StrEq("a1b2c3d4e5feeeee")));
+  EXPECT_TRUE(test_btif_config_cache.HasPersistentSection(kBtAddr4));
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr4, "LE_KEY_PCSRK"),
+              Optional(StrEq("aaaabbbbccccdddd")));
+  EXPECT_TRUE(test_btif_config_cache.HasPersistentSection(kBtAddr5));
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr5, "LE_KEY_LENC"),
+              Optional(StrEq("jilkjlkjlkn")));
+
+  // unpair with these 4 bt address devices by removed the linkkey.
+  // unpair kBtAddr1 11:22:33:44:55:66
+  test_btif_config_cache.RemoveKey(kBtAddr1, "LinkKey");
+  EXPECT_FALSE(test_btif_config_cache.HasKey(kBtAddr1, "LinkKey"));
+  // no empty section is moved to unpaired
+  EXPECT_FALSE(test_btif_config_cache.HasPersistentSection(kBtAddr1));
+  EXPECT_TRUE(test_btif_config_cache.HasUnpairedSection(kBtAddr1));
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr1, "name"),
+              Optional(StrEq("kBtAddr1")));
+
+  // unpair with kBtAddr2 aa:bb:cc:dd:ee:ff
+  test_btif_config_cache.RemoveKey(kBtAddr2, "LE_KEY_PENC");
+  EXPECT_FALSE(test_btif_config_cache.HasKey(kBtAddr2, "LE_KEY_PENC"));
+  EXPECT_FALSE(test_btif_config_cache.HasPersistentSection(kBtAddr2));
+  EXPECT_TRUE(test_btif_config_cache.HasUnpairedSection(kBtAddr2));
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr2, "name"),
+              Optional(StrEq("kBtAddr2")));
+
+  // unpair with kBtAddr3 AB:CD:EF:12:34:56
+  test_btif_config_cache.RemoveKey(kBtAddr3, "LE_KEY_PID");
+  EXPECT_FALSE(test_btif_config_cache.HasKey(kBtAddr3, "LE_KEY_PID"));
+  EXPECT_FALSE(test_btif_config_cache.HasPersistentSection(kBtAddr3));
+  // no empty section is moved to unpaired
+  EXPECT_TRUE(test_btif_config_cache.HasUnpairedSection(kBtAddr3));
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr3, "name"),
+              Optional(StrEq("kBtAddr3")));
+
+  // unpair with kBtAddr4 11:AA:22:BB:33:CC
+  test_btif_config_cache.RemoveKey(kBtAddr4, "LE_KEY_PCSRK");
+  EXPECT_FALSE(test_btif_config_cache.HasKey(kBtAddr4, "LE_KEY_PCSRK"));
+  EXPECT_FALSE(test_btif_config_cache.HasPersistentSection(kBtAddr4));
+  // empty section is removed
+  EXPECT_FALSE(test_btif_config_cache.HasUnpairedSection(kBtAddr4));
+
+  // unpair with kBtAddr5 11:AA:22:BB:33:CD
+  test_btif_config_cache.RemoveKey(kBtAddr5, "LE_KEY_LENC");
+  EXPECT_FALSE(test_btif_config_cache.HasKey(kBtAddr5, "LE_KEY_LENC"));
+  EXPECT_FALSE(test_btif_config_cache.HasPersistentSection(kBtAddr5));
+  // no empty section is moved to unpaired
+  EXPECT_TRUE(test_btif_config_cache.HasUnpairedSection(kBtAddr5));
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr5, "name"),
+              Optional(StrEq("kBtAddr5")));
+
+  // checking the oldest unpaired device kBtAddr1 was ruled out from cache due
+  // to capacity limitation (3) in unpaired cache.
+  EXPECT_FALSE(test_btif_config_cache.HasUnpairedSection(kBtAddr1));
+}
+
+/* Test to remove sections with the specific key
+ * paired with sections with the specific "Restricted" key and then removed the
+ * "Restricted" key, check if the sections with the specific "Restricted" key
+ * are removed.
+ */
+TEST(BtifConfigCacheTest, test_remove_sections_with_key) {
+  BtifConfigCache test_btif_config_cache(kCapacity);
+  // pair with Headset_1 (kBtAddr1), Headset_2 (kBtAddr1), Heasdet_3 (kBtAddr3)
+  // , and Headset_1 (kBtAddr1), Headset_3 (kBtAddr3) have sepcific "Restricted"
+  // key
+  test_btif_config_cache.SetString(kBtAddr1, "Name", "Headset_1");
+  test_btif_config_cache.SetString(kBtAddr1, "Restricted", "1");
+  test_btif_config_cache.SetString(kBtAddr1, "LinkKey", "1122334455667788");
+  test_btif_config_cache.SetString(kBtAddr2, "Name", "Headset_2");
+  test_btif_config_cache.SetString(kBtAddr2, "LinkKey", "aabbccddeeff9900");
+  test_btif_config_cache.SetString(kBtAddr3, "Name", "Headset_3");
+  test_btif_config_cache.SetString(kBtAddr3, "LinkKey", "a1b2c3d4e5feeeee");
+  test_btif_config_cache.SetString(kBtAddr3, "Restricted", "1");
+
+  // remove sections with "Restricted" key
+  test_btif_config_cache.RemovePersistentSectionsWithKey("Restricted");
+
+  // checking the kBtAddr1 and kBtAddr3 can not be found in config cache, only
+  // keep kBtAddr2 in config cache.
+  EXPECT_FALSE(test_btif_config_cache.HasSection(kBtAddr1));
+  EXPECT_TRUE(test_btif_config_cache.HasSection(kBtAddr2));
+  EXPECT_FALSE(test_btif_config_cache.HasSection(kBtAddr3));
+}
+
+/* Test PersistentSectionCopy and Init */
+TEST(BtifConfigCacheTest, test_PersistentSectionCopy_Init) {
+  BtifConfigCache test_btif_config_cache(kCapacity);
+  config_t config_paired = {};
+  // pair with 3 bt devices, kBtAddr1, kBtAddr2, kBtAddr3
+  test_btif_config_cache.SetString(kBtAddr1, "LinkKey", "1122334455667788");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr1, "LinkKey"));
+  EXPECT_TRUE(test_btif_config_cache.HasPersistentSection(kBtAddr1));
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr1, "LinkKey"),
+              Optional(StrEq("1122334455667788")));
+
+  test_btif_config_cache.SetString(kBtAddr2, "LE_KEY_PENC", "aabbccddeeff9900");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr2, "LE_KEY_PENC"));
+  EXPECT_TRUE(test_btif_config_cache.HasPersistentSection(kBtAddr2));
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr2, "LE_KEY_PENC"),
+              Optional(StrEq("aabbccddeeff9900")));
+
+  test_btif_config_cache.SetString(kBtAddr3, "LE_KEY_PID", "a1b2c3d4e5feeeee");
+  EXPECT_TRUE(test_btif_config_cache.HasKey(kBtAddr3, "LE_KEY_PID"));
+  EXPECT_TRUE(test_btif_config_cache.HasPersistentSection(kBtAddr3));
+  EXPECT_THAT(test_btif_config_cache.GetString(kBtAddr3, "LE_KEY_PID"),
+              Optional(StrEq("a1b2c3d4e5feeeee")));
+
+  // check GetPersistentSections
+  int num_of_paired_devices = 0;
+  for (const section_t& sec : test_btif_config_cache.GetPersistentSections()) {
+    EXPECT_TRUE(test_btif_config_cache.HasPersistentSection(sec.name));
+    num_of_paired_devices++;
+  }
+  EXPECT_EQ(num_of_paired_devices, 3);
+
+  // copy persistent sections
+  int num_of_copy_paired_devices = 0;
+  config_paired = test_btif_config_cache.PersistentSectionCopy();
+  for (const section_t& sec : config_paired.sections) {
+    EXPECT_TRUE(test_btif_config_cache.HasPersistentSection(sec.name));
+    num_of_copy_paired_devices++;
+  }
+  EXPECT_EQ(num_of_copy_paired_devices, 3);
+
+  // write persistent sections to temp test config file
+  EXPECT_TRUE(config_save(config_paired, TEST_CONFIG_FILE));
+  // get persistent sections from temp test config file
+  int num_of_save_paired_devices = 0;
+  std::unique_ptr<config_t> config_source = config_new(TEST_CONFIG_FILE);
+  for (const section_t& sec : config_paired.sections) {
+    EXPECT_TRUE(test_btif_config_cache.HasPersistentSection(sec.name));
+    num_of_save_paired_devices++;
+  }
+  EXPECT_EQ(num_of_save_paired_devices, 3);
+
+  // Clear all btif config cache sections
+  test_btif_config_cache.Clear();
+
+  // move the persistent sections to btif config paired list
+  int num_of_init_paired_devices = 0;
+  test_btif_config_cache.Init(std::move(config_source));
+  for (const section_t& sec : config_paired.sections) {
+    EXPECT_TRUE(test_btif_config_cache.HasPersistentSection(sec.name));
+    num_of_init_paired_devices++;
+  }
+  EXPECT_EQ(num_of_init_paired_devices, 3);
+
+  EXPECT_TRUE(std::filesystem::remove(kTestConfigFile));
+}
+
+}  // namespace testing
diff --git a/system/test/run_unit_tests.sh b/system/test/run_unit_tests.sh
index 8041afcf91aced40f2c5321d7ae959a94e3f3d13..754d9c57f3846cc38e2e6e14dc2b954c5a3c17a7 100755
--- a/system/test/run_unit_tests.sh
+++ b/system/test/run_unit_tests.sh
@@ -12,6 +12,7 @@ known_tests=(
   net_test_bta
   net_test_btif
   net_test_btif_profile_queue
+  net_test_btif_config_cache
   net_test_device
   net_test_hci
   net_test_stack