Fine tune btif config mechanism to limit the number of section in bt config cache and improve the bt config clone performance

* Bt config cache will grow bigger and bigger without limitation and
cause many Bluetooth stability issues
* Do not clone the whole config cache before writing config cache
into file, clone paired devices section instead.
* Implement BtifConfigCache class to handle bt devices config add,
remove, paired, unpaired,..etc.

Bug: 143515989
Test: 1. Add BtifConfigCacheTest unit tests to test bt config cache
setup, paire with a new devices, unpaire with a devices, remove the
sections with specific key.
2. Checking the paired devices information still existed in settings
after Bluetooth disable or device reboot.
3. Checking the paired devices information still saved in btif_config
file after Bluetooth disable and device reboot.
4. Remove btif_confing files and enable Bluetooth, checking the
btif_config file can be created and included adapter information
normally.
5. Checking the paired devices information be clean in btif_config
file after device factory reset
6. keep BLE scanning, then pair with a bluetooth device, connect a
bluetooth device, disable Bluetooth, checking the function work
normally.
Tag: #stability

Change-Id: Ide1ba1b6daaf9d102ab96976cbf28e65031423d0
diff --git a/TEST_MAPPING b/TEST_MAPPING
index dc17051..85cd1c1 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 af5f881..e2af248 100644
--- a/system/btif/Android.bp
+++ b/system/btif/Android.bp
@@ -55,6 +55,7 @@
         "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 @@
         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 5c7d433..d1678cd 100644
--- a/system/btif/include/btif_config.h
+++ b/system/btif/include/btif_config.h
@@ -64,7 +64,7 @@
 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 0000000..aedcd4e
--- /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 b710c2e..d95aa55 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 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 @@
   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 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 @@
     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 @@
 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 @@
   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 @@
                                              .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 @@
 
 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 @@
     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 @@
         !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 @@
 
 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 @@
 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 @@
 
   {
     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 @@
 }
 
 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 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 @@
       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 0000000..c5562aa
--- /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 0000000..aaccf8c
--- /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 8041afc..754d9c5 100755
--- a/system/test/run_unit_tests.sh
+++ b/system/test/run_unit_tests.sh
@@ -12,6 +12,7 @@
   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