Fix crashes with lots of discovered LE devices

When loads of devices are discovered a config file which is too large
can be written out, which causes the BT daemon to crash on startup.

This limits the number of config entries for unpaired devices which
are initialized, and prevents a large number from being saved to the
filesystem.

Bug: 26071376
Change-Id: I4a74094f57a82b17f94e99a819974b8bc8082184
(cherry picked from commit d77f1999ecece56c1cbb333f4ddc26f0b5bac2c5)
diff --git a/btif/src/btif_config.c b/btif/src/btif_config.c
index 19482ef..dfd308e 100644
--- a/btif/src/btif_config.c
+++ b/btif/src/btif_config.c
@@ -42,7 +42,9 @@
 static const char *LEGACY_CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.xml";
 static const period_ms_t CONFIG_SETTLE_PERIOD_MS = 3000;
 
-static void timer_config_save(void *data);
+static void timer_config_save_cb(void *data);
+static void btif_config_write(void);
+static void btif_config_devcache_cleanup(void);
 
 // TODO(zachoverflow): Move these two functions out, because they are too specific for this file
 // {grumpy-cat/no, monty-python/you-make-me-sad}
@@ -107,6 +109,8 @@
       unlink(LEGACY_CONFIG_FILE_PATH);
   }
 
+  btif_config_devcache_cleanup();
+
   // TODO(sharvil): use a non-wake alarm for this once we have
   // API support for it. There's no need to wake the system to
   // write back to disk.
@@ -346,7 +350,7 @@
   assert(alarm_timer != NULL);
   assert(config != NULL);
 
-  alarm_set(alarm_timer, CONFIG_SETTLE_PERIOD_MS, timer_config_save, NULL);
+  alarm_set(alarm_timer, CONFIG_SETTLE_PERIOD_MS, timer_config_save_cb, NULL);
 }
 
 void btif_config_flush(void) {
@@ -355,9 +359,7 @@
 
   alarm_cancel(alarm_timer);
 
-  pthread_mutex_lock(&lock);
-  config_save(config, CONFIG_FILE_PATH);
-  pthread_mutex_unlock(&lock);
+  btif_config_write();
 }
 
 int btif_config_clear(void){
@@ -380,45 +382,51 @@
   return ret;
 }
 
-static void timer_config_save(UNUSED_ATTR void *data) {
+static void timer_config_save_cb(UNUSED_ATTR void *data) {
+  btif_config_write();
+}
+
+static void btif_config_write(void) {
   assert(config != NULL);
   assert(alarm_timer != NULL);
 
-  // Garbage collection process: the config file accumulates
-  // cached information about remote devices during regular
-  // inquiry scans. We remove some of these junk entries
-  // so the file doesn't grow indefinitely. We have to take care
-  // to make sure we don't remove information about bonded
-  // devices (hence the check for link keys).
-  static const size_t CACHE_MAX = 256;
-  const char *keys[CACHE_MAX];
-  size_t num_keys = 0;
-  size_t total_candidates = 0;
+  btif_config_devcache_cleanup();
 
   pthread_mutex_lock(&lock);
-  for (const config_section_node_t *snode = config_section_begin(config); snode != config_section_end(config); snode = config_section_next(snode)) {
-    const char *section = config_section_name(snode);
-    if (!string_is_bdaddr(section))
-      continue;
-
-    if (config_has_key(config, section, "LinkKey") ||
-        config_has_key(config, section, "LE_KEY_PENC") ||
-        config_has_key(config, section, "LE_KEY_PID") ||
-        config_has_key(config, section, "LE_KEY_PCSRK") ||
-        config_has_key(config, section, "LE_KEY_LENC") ||
-        config_has_key(config, section, "LE_KEY_LCSRK"))
-      continue;
-
-    if (num_keys < CACHE_MAX)
-      keys[num_keys++] = section;
-
-    ++total_candidates;
-  }
-
-  if (total_candidates > CACHE_MAX * 2)
-    while (num_keys > 0)
-      config_remove_section(config, keys[--num_keys]);
-
   config_save(config, CONFIG_FILE_PATH);
   pthread_mutex_unlock(&lock);
 }
+
+static void btif_config_devcache_cleanup(void) {
+  assert(config != NULL);
+
+  // The config accumulates cached information about remote
+  // devices during regular inquiry scans. We remove some of these
+  // so the cache doesn't grow indefinitely.
+  // We don't remove information about bonded devices (which have link keys).
+  static const size_t ADDRS_MAX = 512;
+  size_t total_addrs = 0;
+
+  pthread_mutex_lock(&lock);
+  const config_section_node_t *snode = config_section_begin(config);
+  while (snode != config_section_end(config)) {
+    const char *section = config_section_name(snode);
+    if (string_is_bdaddr(section)) {
+      ++total_addrs;
+
+      if ((total_addrs > ADDRS_MAX) &&
+          !config_has_key(config, section, "LinkKey") &&
+          !config_has_key(config, section, "LE_KEY_PENC") &&
+          !config_has_key(config, section, "LE_KEY_PID") &&
+          !config_has_key(config, section, "LE_KEY_PCSRK") &&
+          !config_has_key(config, section, "LE_KEY_LENC") &&
+          !config_has_key(config, section, "LE_KEY_LCSRK")) {
+        snode = config_section_next(snode);
+        config_remove_section(config, section);
+        continue;
+      }
+    }
+    snode = config_section_next(snode);
+  }
+  pthread_mutex_unlock(&lock);
+}