device_iot_config: Add new iot config apis to store remote info(2/2)

device_iot_config apis are used to store remote device info
to local conf. For the remote info, please refer to
device_iot_conf_defs.h

CRs-Fixed: 2333805
Change-Id: I020ce3beb34550278fff6a5040e1294de68aaa72
diff --git a/system_bt_ext/device/Android.bp b/system_bt_ext/device/Android.bp
index 1032e5f..44babef 100644
--- a/system_bt_ext/device/Android.bp
+++ b/system_bt_ext/device/Android.bp
@@ -13,10 +13,13 @@
         "vendor/qcom/opensource/commonsys/system/bt/internal_include",
         "vendor/qcom/opensource/commonsys/system/bt/stack/include",
         "vendor/qcom/opensource/commonsys/bluetooth_ext/vhal/include",
+        "vendor/qcom/opensource/commonsys/system/bt/bta/include",
+        "vendor/qcom/opensource/commonsys/system/bt/utils/include/",
     ],
     srcs: [
         "src/interop.cc",
         "src/profile_config.cc",
+        "src/device_iot_config.cc",
     ],
     shared_libs: [
         "liblog",
@@ -25,8 +28,4 @@
         "libosi_qti",
         "libbluetooth-types",
     ],
-    cflags: [
-        "-DHAS_NO_BDROID_BUILDCFG"
-    ],
-
 }
diff --git a/system_bt_ext/device/include/device_iot_conf_defs.h b/system_bt_ext/device/include/device_iot_conf_defs.h
new file mode 100644
index 0000000..12907a0
--- /dev/null
+++ b/system_bt_ext/device/include/device_iot_conf_defs.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#pragma once
+
+#define IOT_CONF_KEY_SECTION_ADAPTER                    "Adapter"
+#define IOT_CONF_KEY_ADDRESS                            "Address"
+#define IOT_CONF_KEY_BT_ONOFF_COUNT                     "BTOnOffCount"
+
+#define IOT_CONF_KEY_REMOTE_NAME                        "Name"
+#define IOT_CONF_KEY_DEVCLASS                           "DevClass"
+#define IOT_CONF_KEY_DEVTYPE                            "DevType"
+#define IOT_CONF_KEY_ADDRTYPE                           "AddrType"
+#define IOT_CONF_KEY_MANUFACTURER                       "Manufacturer"
+#define IOT_CONF_KEY_LMPVER                             "LmpVer"
+#define IOT_CONF_KEY_LMPSUBVER                          "LmpSubVer"
+#define IOT_CONF_KEY_PAIRTYPE                           "PairType"
+#define IOT_CONF_KEY_LE_PAIRTYPE                        "LE_PairType"
+#define IOT_CONF_KEY_RT_SUPP_FEATURES                   "RemoteSupportedFeatures"
+#define IOT_CONF_KEY_RT_EXT_FEATURES                    "RemoteExtendedFeatures"
+#define IOT_CONF_KEY_LE_RT_FEATURES                     "LE_RemoteSupportedFeatures"
+#define IOT_CONF_KEY_RECORDED                           "Recorded"
+
+#define IOT_CONF_KEY_GAP_CONN_COUNT                     "ProfileGap_ConnectCount"
+#define IOT_CONF_KEY_GAP_CONN_FAIL_COUNT                "ProfileGap_ConnectFailCount"
+#define IOT_CONF_KEY_GAP_DISC_COUNT                     "ProfileGap_DiscCount"
+#define IOT_CONF_KEY_GAP_DISC_AUTHFAIL_COUNT            "ProfileGap_DiscAuthFailCount"
+#define IOT_CONF_KEY_GAP_DISC_CONNTIMEOUT_COUNT         "ProfileGap_DiscConnTimeoutCount"
+#define IOT_CONF_KEY_A2DP_ROLE                          "ProfileA2dp_Role"
+#define IOT_CONF_KEY_A2DP_VERSION                       "ProfileA2dp_Version"
+#define IOT_CONF_KEY_A2DP_CODECTYPE                     "ProfileA2dp_CodecType"
+#define IOT_CONF_KEY_A2DP_CONN_COUNT                    "ProfileA2dp_ConnectCount"
+#define IOT_CONF_KEY_A2DP_CONN_FAIL_COUNT               "ProfileA2dp_ConnectFailCount"
+#define IOT_CONF_KEY_HFP_ROLE                           "ProfileHfp_Role"
+#define IOT_CONF_KEY_HFP_VERSION                        "ProfileHfp_Version"
+#define IOT_CONF_KEY_HFP_CODECTYPE                      "ProfileHfp_CodecType"
+#define IOT_CONF_KEY_HFP_SLC_CONN_COUNT                 "ProfileHfp_SlcConnectCount"
+#define IOT_CONF_KEY_HFP_SLC_CONN_FAIL_COUNT            "ProfileHfp_SlcConnectFailCount"
+#define IOT_CONF_KEY_HFP_SCO_CONN_COUNT                 "ProfileHfp_ScoConnectCount"
+#define IOT_CONF_KEY_HFP_SCO_CONN_FAIL_COUNT            "ProfileHfp_ScoConnectFailCount"
+#define IOT_CONF_KEY_HFP_FEATURES                       "ProfileHfp_Features"
+#define IOT_CONF_KEY_AVRCP_CTRL_VERSION                 "ProfileAvrcp_ControllerVersion"
+#define IOT_CONF_KEY_AVRCP_TG_VERSION                   "ProfileAvrcp_TargetVersion"
+#define IOT_CONF_KEY_AVRCP_CONN_COUNT                   "ProfileAvrcp_ConnectCount"
+#define IOT_CONF_KEY_AVRCP_CONN_FAIL_COUNT              "ProfileAvrcp_ConnectFailCount"
+#define IOT_CONF_KEY_AVRCP_FEATURES                     "ProfileAvrcp_Features"
+#define IOT_CONF_KEY_HID_ROLE                           "ProfileHid_Role"
+#define IOT_CONF_KEY_HID_VERSION                        "ProfileHid_Version"
+#define IOT_CONF_KEY_HID_CONN_COUNT                     "ProfileHid_ConnectCount"
+#define IOT_CONF_KEY_HID_CONN_FAIL_COUNT                "ProfileHid_ConnectFailCount"
+#define IOT_CONF_KEY_PBAP_ROLE                          "ProfilePbap_Role"
+#define IOT_CONF_KEY_PBAP_VERSION                       "ProfilePbap_Version"
+#define IOT_CONF_KEY_PBAP_CONN_COUNT                    "ProfilePbap_ConnectCount"
+#define IOT_CONF_KEY_PBAP_CONN_FAIL_COUNT               "ProfilePbap_ConnectFailCount"
+#define IOT_CONF_KEY_MAP_ROLE                           "ProfileMap_Role"
+#define IOT_CONF_KEY_MAP_VERSION                        "ProfileMap_Version"
+#define IOT_CONF_KEY_MAP_CONN_COUNT                     "ProfileMap_ConnectCount"
+#define IOT_CONF_KEY_MAP_CONN_FAIL_COUNT                "ProfileMap_ConnectFailCount"
+
+#define IOT_CONF_VAL_PAIR_TYPE_LEGACY                   0
+#define IOT_CONF_VAL_PAIR_TYPE_SSP                      1
+#define IOT_CONF_VAL_LE_PAIRTYPE_LEGACY                 0
+#define IOT_CONF_VAL_LE_PAIRTYPE_SECURE                 1
+#define IOT_CONF_VAL_RECORDED_DEFAULT                   0
+
+#define IOT_CONF_VAL_A2DP_ROLE_SINK                     0
+#define IOT_CONF_VAL_A2DP_ROLE_SOURCE                   1
+#define IOT_CONF_VAL_A2DP_CODECTYPE_SBC                 0x01
+#define IOT_CONF_VAL_A2DP_CODECTYPE_APTX                0x02
+#define IOT_CONF_VAL_A2DP_CODECTYPE_APTXHD              0x04
+#define IOT_CONF_VAL_A2DP_CODECTYPE_AAC                 0x08
+#define IOT_CONF_VAL_A2DP_CODECTYPE_LDAC                0x10
+#define IOT_CONF_VAL_A2DP_CODECTYPE_APTXADAPTIVE        0x20
+#define IOT_CONF_VAL_A2DP_CODECTYPE_APTXTWS             0x40
+
+#define IOT_CONF_VAL_HFP_ROLE_CLIENT                    0
+#define IOT_CONF_VAL_HFP_ROLE_AG                        1
+#define IOT_CONF_VAL_HFP_CODECTYPE_CVSD                 0x01
+#define IOT_CONF_VAL_HFP_CODECTYPE_CVSDMSBC             0x02
+
+#define IOT_CONF_VAL_HID_ROLE_HOST                      0
+#define IOT_CONF_VAL_HID_ROLE_DEVICE                    1
+
+#define IOT_CONF_VAL_PBAP_ROLE_CLIENT                   0
+#define IOT_CONF_VAL_PBAP_ROLE_SERVER                   1
+
+#define IOT_CONF_VAL_MAP_ROLE_CLIENT                    0
+#define IOT_CONF_VAL_MAP_ROLE_SERVER                    1
+
+#define IOT_CONF_BYTE_NUM_1                             1
+#define IOT_CONF_BYTE_NUM_2                             2
+#define IOT_CONF_BYTE_NUM_3                             3
+#define IOT_CONF_BYTE_NUM_4                             4
+
diff --git a/system_bt_ext/device/include/device_iot_config.h b/system_bt_ext/device/include/device_iot_config.h
new file mode 100644
index 0000000..a4ed0fb
--- /dev/null
+++ b/system_bt_ext/device/include/device_iot_config.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ *  Copyright (C) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  Not a Contribution
+ *****************************************************************************/
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  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 "bt_target.h"
+#if (BT_IOT_LOGGING_ENABLED == TRUE)
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "bt_types.h"
+#include "device_iot_conf_defs.h"
+#include "raw_address.h"
+
+static const char DEVICE_IOT_CONFIG_MODULE[] = "device_iot_config_module";
+
+typedef struct device_iot_config_section_iter_t device_iot_config_section_iter_t;
+
+bool device_iot_config_has_section(const char* section);
+bool device_iot_config_exist(const char* section, const char* key);
+bool device_iot_config_get_int(const char* section, const char* key, int* value);
+bool device_iot_config_addr_get_int(const RawAddress& peer_addr, const char* key, int* value);
+bool device_iot_config_set_int(const char* section, const char* key, int value);
+bool device_iot_config_addr_set_int(const RawAddress& peer_addr, const char* key, int value);
+bool device_iot_config_int_add_one(const char* section, const char* key);
+bool device_iot_config_addr_int_add_one(const RawAddress& peer_addr, const char* key);
+
+bool device_iot_config_get_hex(const char* section, const char* key, int* value);
+bool device_iot_config_addr_get_hex(const RawAddress& peer_addr, const char* key, int* value);
+bool device_iot_config_set_hex(const char* section, const char* key, int value, int byte_num);
+bool device_iot_config_addr_set_hex(const RawAddress& peer_addr, const char* key, int value, int byte_num);
+bool device_iot_config_addr_set_hex_if_greater(const RawAddress& peer_addr, const char* key, int value, int byte_num);
+bool device_iot_config_get_str(const char* section, const char* key, char* value, int* size_bytes);
+bool device_iot_config_set_str(const char* section, const char* key, const char* value);
+bool device_iot_config_addr_set_str(const RawAddress& peer_addr, const char* key, const char* value);
+bool device_iot_config_get_bin(const char* section, const char* key, uint8_t* value, size_t* length);
+bool device_iot_config_set_bin(const char* section, const char* key, const uint8_t* value, size_t length);
+bool device_iot_config_addr_set_bin(const RawAddress& peer_addr, const char* key, const uint8_t* value, size_t length);
+bool device_iot_config_remove(const char* section, const char* key);
+
+size_t device_iot_config_get_bin_length(const char* section, const char* key);
+
+const device_iot_config_section_iter_t* device_iot_config_section_begin(void);
+const device_iot_config_section_iter_t* device_iot_config_section_end(void);
+const device_iot_config_section_iter_t* device_iot_config_section_next(const device_iot_config_section_iter_t* section);
+const char* device_iot_config_section_name(const device_iot_config_section_iter_t* section);
+
+void device_iot_config_flush(void);
+bool device_iot_config_clear(void);
+
+void device_debug_iot_config_dump(int fd);
+
+#endif
diff --git a/system_bt_ext/device/src/device_iot_config.cc b/system_bt_ext/device/src/device_iot_config.cc
new file mode 100644
index 0000000..b5b3d18
--- /dev/null
+++ b/system_bt_ext/device/src/device_iot_config.cc
@@ -0,0 +1,822 @@
+/******************************************************************************
+ *  Copyright (C) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  Not a Contribution
+ *****************************************************************************/
+/******************************************************************************
+ *
+ *  Copyright (C) 2014 Google, Inc.
+ *
+ *  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 "bt_target.h"
+#if (BT_IOT_LOGGING_ENABLED == TRUE)
+
+#define LOG_TAG "device_iot_config"
+//#undef LOG_NDEBUG
+//#define LOG_NDEBUG 0
+#include "device_iot_config.h"
+
+#include <base/logging.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <string>
+#include <mutex>
+
+#include "bt_types.h"
+#include "btcore/include/module.h"
+#include "btif/include/btif_api.h"
+#include "btif/include/btif_util.h"
+#include "osi/include/alarm.h"
+#include "osi/include/allocator.h"
+#include "osi/include/compat.h"
+#include "osi/include/config.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#include "osi/include/properties.h"
+
+#define BT_IOT_CONFIG_SOURCE_TAG_NUM 1010003
+
+#define INFO_SECTION "Info"
+#define VERSION_KEY "Version"
+#define FILE_CREATED_TIMESTAMP "TimeCreated"
+#define FILE_MODIFIED_TIMESTAMP "TimeModified"
+#define TIME_STRING_LENGTH sizeof("YYYY-MM-DD HH:MM:SS")
+static const char* TIME_STRING_FORMAT = "%Y-%m-%d %H:%M:%S";
+
+#ifndef DEVICES_MAX_NUM_IN_IOT_INFO_FILE
+#define DEVICES_MAX_NUM_IN_IOT_INFO_FILE  40
+#endif
+#define DEVICES_NUM_MARGIN 5
+
+#if (DEVICES_MAX_NUM_IN_IOT_INFO_FILE < DEVICES_NUM_MARGIN)
+#undef DEVICES_MAX_NUM_IN_IOT_INFO_FILE
+#define DEVICES_MAX_NUM_IN_IOT_INFO_FILE DEVICES_NUM_MARGIN
+#endif
+
+#define DEVICE_IOT_INFO_CURRENT_VERSION 1
+#define DEVICE_IOT_INFO_FIRST_VERSION 1
+
+#define IOT_CONFIG_FLUSH_EVT            0
+#define IOT_CONFIG_SAVE_TIMER_FIRED_EVT 1
+
+#if defined(OS_GENERIC)
+static const char* IOT_CONFIG_FILE_PATH = "bt_remote_dev_info.conf";
+static const char* IOT_CONFIG_BACKUP_PATH = "bt_remote_dev_info.bak";
+#else  // !defined(OS_GENERIC)
+static const char* IOT_CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_remote_dev_info.conf";
+static const char* IOT_CONFIG_BACKUP_PATH = "/data/misc/bluedroid/bt_remote_dev_info.bak";
+#endif  // defined(OS_GENERIC)
+static const period_ms_t CONFIG_SETTLE_PERIOD_MS = 12000;
+
+static void timer_iot_config_save_cb(void* data);
+static void device_iot_config_write(uint16_t event, char* p_param);
+static config_t* device_iot_config_open(const char* filename);
+static int device_iot_config_get_device_num(config_t* config);
+static void device_iot_config_save(void);
+static bool is_factory_reset(void);
+static void delete_iot_config_files(void);
+
+static enum ConfigSource {
+  NOT_LOADED,
+  ORIGINAL,
+  BACKUP,
+  NEW_FILE,
+  RESET
+} device_iot_config_source = NOT_LOADED;
+
+static int device_iot_config_devices_loaded = -1;
+static char device_iot_config_time_created[TIME_STRING_LENGTH];
+
+static std::mutex config_lock;  // protects operations on |config|.
+static config_t* config;
+static alarm_t* config_timer;
+static bool iot_logging_enabled = false;
+
+#define CHECK_LOGGING_ENABLED(return_value) do { if (!iot_logging_enabled) return (return_value); } while(0)
+
+// Module lifecycle functions
+static future_t* init(void) {
+  char enabled[PROPERTY_VALUE_MAX] = {0};
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  osi_property_get("persist.vendor.service.bt.iot.enablelogging", enabled, "false");
+  iot_logging_enabled = strncmp(enabled, "true", 4) == 0;
+
+  if (!iot_logging_enabled) {
+    delete_iot_config_files();
+    return future_new_immediate(FUTURE_SUCCESS);
+  }
+
+  LOG_INFO(LOG_TAG, "%s", __func__);
+
+  if (is_factory_reset())
+    delete_iot_config_files();
+
+  config = device_iot_config_open(IOT_CONFIG_FILE_PATH);
+  device_iot_config_source = ORIGINAL;
+  if (!config) {
+    LOG_WARN(LOG_TAG, "%s unable to load config file: %s; using backup.",
+          __func__, IOT_CONFIG_FILE_PATH);
+    config = device_iot_config_open(IOT_CONFIG_BACKUP_PATH);
+    device_iot_config_source = BACKUP;
+  }
+
+  if (!config) {
+    LOG_ERROR(LOG_TAG, "%s unable to load bak file; creating empty config.", __func__);
+    config = config_new_empty();
+    device_iot_config_source = NEW_FILE;
+  }
+
+  if (!config) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate a config object.", __func__);
+    goto error;
+  }
+
+  int version;
+  if (device_iot_config_source == NEW_FILE) {
+    version = DEVICE_IOT_INFO_CURRENT_VERSION;
+    config_set_int(config, INFO_SECTION, VERSION_KEY, DEVICE_IOT_INFO_CURRENT_VERSION);
+  } else {
+    version = config_get_int(config, INFO_SECTION, VERSION_KEY, -1);
+    if (version == -1) {
+      version = DEVICE_IOT_INFO_FIRST_VERSION;
+      config_set_int(config, INFO_SECTION, VERSION_KEY, DEVICE_IOT_INFO_FIRST_VERSION);
+    }
+  }
+
+  if (version != DEVICE_IOT_INFO_CURRENT_VERSION) {
+    LOG_INFO(LOG_TAG, "%s: version in file is %d, CURRENT_VERSION is %d ", __func__,
+        version, DEVICE_IOT_INFO_CURRENT_VERSION);
+    remove(IOT_CONFIG_FILE_PATH);
+    remove(IOT_CONFIG_BACKUP_PATH);
+    config_free(config);
+    config = config_new_empty();
+    if (!config) {
+      LOG_ERROR(LOG_TAG, "%s unable to allocate a config object.", __func__);
+      goto error;
+    }
+    config_set_int(config, INFO_SECTION, VERSION_KEY, DEVICE_IOT_INFO_CURRENT_VERSION);
+    device_iot_config_source = NEW_FILE;
+  }
+
+  device_iot_config_devices_loaded = device_iot_config_get_device_num(config);
+
+  // Read or set config file creation timestamp
+  const char* time_str;
+  time_str = config_get_string(config, INFO_SECTION, FILE_CREATED_TIMESTAMP, NULL);
+  if (time_str != NULL) {
+    strlcpy(device_iot_config_time_created, time_str, TIME_STRING_LENGTH);
+  } else {
+    time_t current_time = time(NULL);
+    struct tm* time_created = localtime(&current_time);
+    if (time_created) {
+      strftime(device_iot_config_time_created, TIME_STRING_LENGTH,
+              TIME_STRING_FORMAT, time_created);
+      config_set_string(config, INFO_SECTION, FILE_CREATED_TIMESTAMP,
+              device_iot_config_time_created);
+    }
+  }
+
+  // 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.
+  config_timer = alarm_new("btif.iot.config");
+  if (!config_timer) {
+    LOG_ERROR(LOG_TAG, "%s unable to create alarm.", __func__);
+    goto error;
+  }
+
+  LOG_EVENT_INT(BT_IOT_CONFIG_SOURCE_TAG_NUM, device_iot_config_source);
+
+  return future_new_immediate(FUTURE_SUCCESS);
+
+error:
+  alarm_free(config_timer);
+  config_free(config);
+  config_timer = NULL;
+  config = NULL;
+  device_iot_config_source = NOT_LOADED;
+  return future_new_immediate(FUTURE_FAIL);
+}
+
+static config_t* device_iot_config_open(const char* filename) {
+  config_t* config = config_new(filename);
+  if (!config)
+    return NULL;
+
+  return config;
+}
+
+static future_t* start_up(void) {
+  CHECK_LOGGING_ENABLED(future_new_immediate(FUTURE_SUCCESS));
+
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  device_iot_config_int_add_one(IOT_CONF_KEY_SECTION_ADAPTER, IOT_CONF_KEY_BT_ONOFF_COUNT);
+  return future_new_immediate(FUTURE_SUCCESS);
+}
+
+static future_t* shut_down(void) {
+  CHECK_LOGGING_ENABLED(future_new_immediate(FUTURE_SUCCESS));
+
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  device_iot_config_flush();
+  return future_new_immediate(FUTURE_SUCCESS);
+}
+
+static future_t* clean_up(void) {
+  CHECK_LOGGING_ENABLED(future_new_immediate(FUTURE_SUCCESS));
+
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  if (config_timer != NULL && alarm_is_scheduled(config_timer))
+    device_iot_config_flush();
+
+  alarm_free(config_timer);
+  config_timer = NULL;
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  config_free(config);
+  config = NULL;
+  return future_new_immediate(FUTURE_SUCCESS);
+}
+
+EXPORT_SYMBOL module_t device_iot_config_module = {
+  .name = DEVICE_IOT_CONFIG_MODULE,
+  .init = init,
+  .start_up = start_up,
+  .shut_down = shut_down,
+  .clean_up = clean_up
+};
+
+bool device_iot_config_has_section(const char* section) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  return config_has_section(config, section);
+}
+
+bool device_iot_config_exist(const char* section, const char* key) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  return config_has_key(config, section, key);
+}
+
+static bool device_iot_config_has_key_value(const char* section, const char* key, const char* value_str) {
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+  CHECK(value_str != NULL);
+
+  const char* stored_value = config_get_string(config, section, key, NULL);
+
+  if (!stored_value || strcmp(value_str, stored_value) != 0)
+    return false;
+
+  return true;
+}
+
+bool device_iot_config_get_int(const char* section, const char* key, int* value) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+  CHECK(value != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  bool ret = config_has_key(config, section, key);
+  if (ret)
+    *value = config_get_int(config, section, key, *value);
+
+  return ret;
+}
+
+bool device_iot_config_addr_get_int(const RawAddress& peer_addr, const char* key, int* value) {
+  CHECK_LOGGING_ENABLED(false);
+
+  std::string addrstr = peer_addr.ToString();
+  const char* bdstr = addrstr.c_str();
+  return device_iot_config_get_int(bdstr, key, value);
+}
+
+bool device_iot_config_set_int(const char* section, const char* key, int value) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+
+  LOG_VERBOSE(LOG_TAG, "%s: sec=%s, key=%s, val=%d", __func__, section, key, value);
+  std::unique_lock<std::mutex> lock(config_lock);
+  char value_str[32] = {0};
+  snprintf(value_str, sizeof(value_str), "%d", value);
+  if (device_iot_config_has_key_value(section, key, value_str))
+    return true;
+
+  config_set_string(config, section, key, value_str);
+  device_iot_config_save();
+
+  return true;
+}
+
+bool device_iot_config_addr_set_int(const RawAddress& peer_addr, const char* key, int value) {
+  CHECK_LOGGING_ENABLED(false);
+
+  std::string addrstr = peer_addr.ToString();
+  const char* bdstr = addrstr.c_str();
+  return device_iot_config_set_int(bdstr, key, value);
+}
+
+bool device_iot_config_int_add_one(const char* section, const char* key) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+
+  LOG_VERBOSE(LOG_TAG, "%s: sec=%s, key=%s", __func__, section, key);
+  int result = 0;
+  std::unique_lock<std::mutex> lock(config_lock);
+  result = config_get_int(config, section, key, result);
+  result += 1;
+  config_set_int(config, section, key, result);
+  device_iot_config_save();
+
+  return true;
+}
+
+bool device_iot_config_addr_int_add_one(const RawAddress& peer_addr, const char* key) {
+  CHECK_LOGGING_ENABLED(false);
+
+  std::string addrstr = peer_addr.ToString();
+  const char* bdstr = addrstr.c_str();
+  return device_iot_config_int_add_one(bdstr, key);
+}
+
+bool device_iot_config_get_hex(const char* section, const char* key, int* value) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+  CHECK(value != NULL);
+
+  int sscanf_ret, result = 0;
+  std::unique_lock<std::mutex> lock(config_lock);
+  const char* stored_value = config_get_string(config, section, key, NULL);
+  if (!stored_value)
+    return false;
+
+  sscanf_ret = sscanf(stored_value, "%x", &result);
+  if (sscanf_ret != 1)
+    return false;
+
+  *value = result;
+  return true;
+}
+
+bool device_iot_config_addr_get_hex(const RawAddress& peer_addr, const char* key, int* value) {
+  CHECK_LOGGING_ENABLED(false);
+
+  std::string addrstr = peer_addr.ToString();
+  const char* bdstr = addrstr.c_str();
+  return device_iot_config_get_hex(bdstr, key, value);
+}
+
+bool device_iot_config_set_hex(const char* section, const char* key, int value, int byte_num) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+
+  LOG_VERBOSE(LOG_TAG, "%s: sec=%s, key=%s, val=0x%x", __func__, section, key, value);
+  char value_str[32] = { 0 };
+  if (byte_num == 1)
+    snprintf(value_str, sizeof(value_str), "%02x", value);
+  else if (byte_num == 2)
+    snprintf(value_str, sizeof(value_str), "%04x", value);
+  else if (byte_num == 3)
+    snprintf(value_str, sizeof(value_str), "%06x", value);
+  else if (byte_num == 4)
+    snprintf(value_str, sizeof(value_str), "%08x", value);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  if (device_iot_config_has_key_value(section, key, value_str))
+    return true;
+
+  config_set_string(config, section, key, value_str);
+  device_iot_config_save();
+
+  return true;
+}
+
+bool device_iot_config_addr_set_hex(const RawAddress& peer_addr,
+          const char* key, int value, int byte_num) {
+  CHECK_LOGGING_ENABLED(false);
+
+  std::string addrstr = peer_addr.ToString();
+  const char* bdstr = addrstr.c_str();
+  return device_iot_config_set_hex(bdstr, key, value, byte_num);
+}
+
+bool device_iot_config_addr_set_hex_if_greater(const RawAddress& peer_addr,
+    const char* key, int value, int byte_num) {
+  CHECK_LOGGING_ENABLED(false);
+
+  int stored_value = 0;
+  bool ret = device_iot_config_addr_get_hex(peer_addr, key, &stored_value);
+  if (ret && stored_value >= value)
+    return true;
+
+  return device_iot_config_addr_set_hex(peer_addr, key, value, byte_num);
+}
+
+bool device_iot_config_get_str(const char* section, const char* key, char* value, int* size_bytes) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+  CHECK(value != NULL);
+  CHECK(size_bytes != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  const char* stored_value = config_get_string(config, section, key, NULL);
+
+  if (!stored_value)
+    return false;
+
+  strlcpy(value, stored_value, *size_bytes);
+  *size_bytes = strlen(value) + 1;
+
+  return true;
+}
+
+bool device_iot_config_set_str(const char* section, const char* key, const char* value) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+  CHECK(value != NULL);
+
+  LOG_VERBOSE(LOG_TAG, "%s: sec=%s, key=%s, val=%s", __func__, section, key, value);
+  std::unique_lock<std::mutex> lock(config_lock);
+  if (device_iot_config_has_key_value(section, key, value))
+    return true;
+
+  config_set_string(config, section, key, value);
+  device_iot_config_save();
+
+  return true;
+}
+
+bool device_iot_config_addr_set_str(const RawAddress& peer_addr,
+          const char* key, const char* value) {
+  CHECK_LOGGING_ENABLED(false);
+
+  std::string addrstr = peer_addr.ToString();
+  const char* bdstr = addrstr.c_str();
+  return device_iot_config_set_str(bdstr, key, value);
+}
+
+bool device_iot_config_get_bin(const char* section, const char* key,
+          uint8_t* value, size_t* length) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+  CHECK(value != NULL);
+  CHECK(length != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  const char* value_str = config_get_string(config, section, key, NULL);
+
+  if (!value_str)
+    return false;
+
+  size_t value_len = strlen(value_str);
+  if ((value_len % 2) != 0 || *length < (value_len / 2))
+    return false;
+
+  for (size_t i = 0; i < value_len; ++i)
+    if (!isxdigit(value_str[i]))
+      return false;
+
+  for (*length = 0; *value_str; value_str += 2, *length += 1)
+    sscanf(value_str, "%02hhx", &value[*length]);
+
+  return true;
+}
+
+size_t device_iot_config_get_bin_length(const char* section, const char* key) {
+  CHECK_LOGGING_ENABLED(0);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  const char* value_str = config_get_string(config, section, key, NULL);
+
+  if (!value_str)
+    return 0;
+
+  size_t value_len = strlen(value_str);
+  return ((value_len % 2) != 0) ? 0 : (value_len / 2);
+}
+
+bool device_iot_config_set_bin(const char* section, const char* key,
+          const uint8_t* value, size_t length) {
+  CHECK_LOGGING_ENABLED(false);
+
+  const char* lookup = "0123456789abcdef";
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+
+  LOG_VERBOSE(LOG_TAG, "%s: key = %s", __func__, key);
+  if (length > 0)
+    CHECK(value != NULL);
+
+  char* str = (char* )osi_calloc(length * 2 + 1);
+  if (str == NULL) {
+    LOG_ERROR(LOG_TAG, "%s unable to allocate a str.", __func__);
+    return false;
+  }
+
+  for (size_t i = 0; i < length; ++i) {
+    str[(i * 2) + 0] = lookup[(value[i] >> 4) & 0x0F];
+    str[(i * 2) + 1] = lookup[value[i] & 0x0F];
+  }
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  if (device_iot_config_has_key_value(section, key, str))
+    return true;
+
+  config_set_string(config, section, key, str);
+  device_iot_config_save();
+
+  osi_free(str);
+  return true;
+}
+
+bool device_iot_config_addr_set_bin(const RawAddress& peer_addr,
+          const char* key, const uint8_t* value, size_t length) {
+  CHECK_LOGGING_ENABLED(false);
+
+  std::string addrstr = peer_addr.ToString();
+  const char* bdstr = addrstr.c_str();
+  return device_iot_config_set_bin(bdstr, key, value, length);
+}
+
+const device_iot_config_section_iter_t* device_iot_config_section_begin(void) {
+  CHECK_LOGGING_ENABLED(NULL);
+
+  CHECK(config != NULL);
+  return (const device_iot_config_section_iter_t* )config_section_begin(config);
+}
+
+const device_iot_config_section_iter_t* device_iot_config_section_end(void) {
+  CHECK_LOGGING_ENABLED(NULL);
+
+  CHECK(config != NULL);
+  return (const device_iot_config_section_iter_t* )config_section_end(config);
+}
+
+const device_iot_config_section_iter_t* device_iot_config_section_next(const
+          device_iot_config_section_iter_t* section) {
+  CHECK_LOGGING_ENABLED(NULL);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  return (const device_iot_config_section_iter_t* )config_section_next((const
+          config_section_node_t* )section);
+}
+
+const char* device_iot_config_section_name(const device_iot_config_section_iter_t* section) {
+  CHECK_LOGGING_ENABLED(NULL);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  return config_section_name((const config_section_node_t* )section);
+}
+
+bool device_iot_config_remove(const char* section, const char* key) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(section != NULL);
+  CHECK(key != NULL);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  return config_remove_key(config, section, key);
+}
+
+static void device_iot_config_save(void) {
+  CHECK_LOGGING_ENABLED((void)0);
+
+  CHECK(config != NULL);
+  CHECK(config_timer != NULL);
+
+  LOG_VERBOSE(LOG_TAG, "%s", __func__);
+  alarm_set(config_timer, CONFIG_SETTLE_PERIOD_MS, timer_iot_config_save_cb, NULL);
+}
+
+void device_iot_config_flush(void) {
+  CHECK_LOGGING_ENABLED((void)0);
+
+  CHECK(config != NULL);
+  CHECK(config_timer != NULL);
+
+  int event = alarm_is_scheduled(config_timer) ? IOT_CONFIG_SAVE_TIMER_FIRED_EVT :
+          IOT_CONFIG_FLUSH_EVT;
+  LOG_VERBOSE(LOG_TAG, "%s: evt=%d", __func__, event);
+  alarm_cancel(config_timer);
+  device_iot_config_write(event, NULL);
+}
+
+bool device_iot_config_clear(void) {
+  CHECK_LOGGING_ENABLED(false);
+
+  CHECK(config != NULL);
+  CHECK(config_timer != NULL);
+
+  LOG_INFO(LOG_TAG, "%s", __func__);
+  alarm_cancel(config_timer);
+
+  std::unique_lock<std::mutex> lock(config_lock);
+  config_free(config);
+
+  config = config_new_empty();
+  if (config == NULL) {
+    return false;
+  }
+
+  bool ret = config_save(config, IOT_CONFIG_FILE_PATH);
+  device_iot_config_source = RESET;
+  return ret;
+}
+
+static void timer_iot_config_save_cb(UNUSED_ATTR void* data) {
+  // Moving file I/O to btif context instead of timer callback because
+  // it usually takes a lot of time to be completed, introducing
+  // delays during A2DP playback causing blips or choppiness.
+  LOG_VERBOSE(LOG_TAG, "%s", __func__);
+  btif_transfer_context(device_iot_config_write, IOT_CONFIG_SAVE_TIMER_FIRED_EVT, NULL, 0, NULL);
+}
+
+static void set_modified_time() {
+  time_t current_time = time(NULL);
+  struct tm* time_modified = localtime(&current_time);
+  char device_iot_config_time_modified[TIME_STRING_LENGTH];
+  if (time_modified) {
+    strftime(device_iot_config_time_modified, TIME_STRING_LENGTH,
+            TIME_STRING_FORMAT, time_modified);
+    config_set_string(config, INFO_SECTION, FILE_MODIFIED_TIMESTAMP,
+            device_iot_config_time_modified);
+  }
+}
+
+static void restrict_device_num() {
+  CHECK(config != NULL);
+
+  int curr_num = device_iot_config_get_device_num(config);
+  int removed_devices = 0;
+  int need_remove_devices_num;
+
+  if (curr_num <= DEVICES_MAX_NUM_IN_IOT_INFO_FILE) {
+    return;
+  }
+
+  need_remove_devices_num = curr_num - DEVICES_MAX_NUM_IN_IOT_INFO_FILE + DEVICES_NUM_MARGIN;
+  LOG_INFO(LOG_TAG, "%s: curr_num=%d, need_remove_num=%d", __func__,
+     curr_num, need_remove_devices_num);
+
+  const config_section_node_t* snode = config_section_begin(config);
+  while (snode != config_section_end(config)) {
+    const char* section = config_section_name(snode);
+    if (RawAddress::IsValidAddress(section)) {
+      snode = config_section_next(snode);
+      config_remove_section(config, section);
+      if (++removed_devices >= need_remove_devices_num) {
+        break;
+      }
+    } else {
+      snode = config_section_next(snode);
+    }
+  }
+}
+
+static int compare_key(const char* first, const char* second) {
+  bool first_is_profile_key = strncasecmp(first, "Profile", 7) == 0;
+  bool second_is_profile_key = strncasecmp(second, "Profile", 7) == 0;
+  if (!first_is_profile_key && !second_is_profile_key) {
+    return 0;
+  } else if (first_is_profile_key && second_is_profile_key) {
+    return strcasecmp(first, second);
+  } else {
+    return first_is_profile_key ? 1 : -1;
+  }
+}
+
+static void device_iot_config_write(uint16_t event, UNUSED_ATTR char* p_param) {
+  CHECK_LOGGING_ENABLED((void)0);
+
+  CHECK(config != NULL);
+  CHECK(config_timer != NULL);
+
+  LOG_INFO(LOG_TAG, "%s: evt=%d", __func__, event);
+  std::unique_lock<std::mutex> lock(config_lock);
+  if (event == IOT_CONFIG_SAVE_TIMER_FIRED_EVT)
+    set_modified_time();
+
+  rename(IOT_CONFIG_FILE_PATH, IOT_CONFIG_BACKUP_PATH);
+  restrict_device_num();
+  config_sections_sort_by_entry_key(config, compare_key);
+  config_save(config, IOT_CONFIG_FILE_PATH);
+}
+
+static int device_iot_config_get_device_num(config_t* conf) {
+  CHECK_LOGGING_ENABLED(0);
+
+  CHECK(conf != NULL);
+  int devices = 0;
+
+  const config_section_node_t* snode = config_section_begin(conf);
+  while (snode != config_section_end(conf)) {
+    const char* section = config_section_name(snode);
+    if (RawAddress::IsValidAddress(section)) {
+      devices++;
+    }
+    snode = config_section_next(snode);
+  }
+  return devices;
+}
+
+void device_debug_iot_config_dump(int fd) {
+  CHECK_LOGGING_ENABLED((void)0);
+
+  dprintf(fd, "\nBluetooth Iot Config:\n");
+
+  dprintf(fd, "  Config Source: ");
+  switch(device_iot_config_source) {
+    case NOT_LOADED:
+      dprintf(fd, "Not loaded\n");
+      break;
+    case ORIGINAL:
+      dprintf(fd, "Original file\n");
+      break;
+    case BACKUP:
+      dprintf(fd, "Backup file\n");
+      break;
+    case NEW_FILE:
+      dprintf(fd, "New file\n");
+      break;
+    case RESET:
+      dprintf(fd, "Reset file\n");
+      break;
+  }
+
+  dprintf(fd, "  Devices loaded: %d\n", device_iot_config_devices_loaded);
+  dprintf(fd, "  File created/tagged: %s\n", device_iot_config_time_created);
+}
+
+static bool is_factory_reset(void) {
+  char factory_reset[PROPERTY_VALUE_MAX] = {0};
+  osi_property_get("persist.bluetooth.factoryreset", factory_reset, "false");
+  return strncmp(factory_reset, "true", 4) == 0;
+}
+
+static void delete_iot_config_files(void) {
+  remove(IOT_CONFIG_FILE_PATH);
+  remove(IOT_CONFIG_BACKUP_PATH);
+}
+
+#endif