1 /******************************************************************************
2  *
3  *  Copyright (C) 2014 Google, Inc.
4  *  Copyright (C) 2018 The Linux Foundation
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at:
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  *
18  ******************************************************************************/
19 
20 #define LOG_TAG "device_iot_config"
21 #include "device_iot_config_int.h"
22 
23 #include <bluetooth/log.h>
24 #include <com_android_bluetooth_flags.h>
25 #include <string.h>
26 #include <time.h>
27 #include <unistd.h>
28 
29 #include <mutex>
30 #include <string>
31 
32 #include "btcore/include/module.h"
33 #include "btif/include/btif_common.h"
34 #include "device/include/device_iot_config.h"
35 #include "osi/include/alarm.h"
36 #include "osi/include/config.h"
37 #include "osi/include/future.h"
38 #include "osi/include/properties.h"
39 #include "types/raw_address.h"
40 
41 extern enum ConfigSource device_iot_config_source;
42 
43 extern int device_iot_config_devices_loaded;
44 extern char device_iot_config_time_created[TIME_STRING_LENGTH];
45 
46 extern std::mutex config_lock;  // protects operations on |config|.
47 extern std::unique_ptr<config_t> config;
48 extern alarm_t* config_timer;
49 
50 using namespace bluetooth;
51 
cleanup()52 static void cleanup() {
53   alarm_free(config_timer);
54   config_timer = NULL;
55   config.reset();
56   config = NULL;
57   device_iot_config_source = NOT_LOADED;
58 }
59 
60 // Module lifecycle functions
device_iot_config_module_init(void)61 future_t* device_iot_config_module_init(void) {
62   log::info("");
63 
64   std::unique_lock<std::mutex> lock(config_lock);
65 
66   config_timer = NULL;
67   config = NULL;
68 
69   if (device_iot_config_is_factory_reset()) {
70     device_iot_config_delete_files();
71   }
72 
73   config = config_new(IOT_CONFIG_FILE_PATH);
74   device_iot_config_source = ORIGINAL;
75   if (!config) {
76     log::warn("Unable to load config file: {}; using backup.", IOT_CONFIG_FILE_PATH);
77     config = config_new(IOT_CONFIG_BACKUP_PATH);
78     device_iot_config_source = BACKUP;
79   }
80 
81   if (!config) {
82     log::error("Unable to load bak file; creating empty config.");
83     config = config_new_empty();
84     device_iot_config_source = NEW_FILE;
85   }
86 
87   if (!config) {
88     log::error("Unable to allocate a config object.");
89     cleanup();
90     return future_new_immediate(FUTURE_FAIL);
91   }
92 
93   int version;
94   if (device_iot_config_source == NEW_FILE) {
95     version = DEVICE_IOT_INFO_CURRENT_VERSION;
96     config_set_int(config.get(), INFO_SECTION, VERSION_KEY, version);
97   } else {
98     version = config_get_int(*config, INFO_SECTION, VERSION_KEY, -1);
99     if (version == -1) {
100       version = DEVICE_IOT_INFO_FIRST_VERSION;
101       config_set_int(config.get(), INFO_SECTION, VERSION_KEY, version);
102     }
103   }
104 
105   if (version != DEVICE_IOT_INFO_CURRENT_VERSION) {
106     log::info("Version in file is {}, CURRENT_VERSION is {}", version,
107               DEVICE_IOT_INFO_CURRENT_VERSION);
108     remove(IOT_CONFIG_FILE_PATH);
109     remove(IOT_CONFIG_BACKUP_PATH);
110     config.reset();
111     config = config_new_empty();
112     if (!config) {
113       log::error("Unable to allocate a config object.");
114       cleanup();
115       return future_new_immediate(FUTURE_FAIL);
116     }
117     config_set_int(config.get(), INFO_SECTION, VERSION_KEY, DEVICE_IOT_INFO_CURRENT_VERSION);
118     device_iot_config_source = NEW_FILE;
119   }
120 
121   device_iot_config_devices_loaded = device_iot_config_get_device_num(*config);
122   log::info("Devices loaded {}", device_iot_config_devices_loaded);
123 
124   // Read or set config file creation timestamp
125   const std::string* time_str =
126           config_get_string(*config, INFO_SECTION, FILE_CREATED_TIMESTAMP, NULL);
127   if (time_str != NULL) {
128     strncpy(device_iot_config_time_created, time_str->c_str(), TIME_STRING_LENGTH);
129   } else {
130     // Read or set config file creation timestamp
131     time_t current_time = time(NULL);
132     struct tm* time_created = localtime(&current_time);
133     if (time_created) {
134       strftime(device_iot_config_time_created, TIME_STRING_LENGTH, TIME_STRING_FORMAT,
135                time_created);
136       config_set_string(config.get(), INFO_SECTION, FILE_CREATED_TIMESTAMP,
137                         std::string(device_iot_config_time_created));
138     }
139   }
140 
141   // TODO: use a non-wake alarm for this once we have
142   // API support for it. There's no need to wake the system to
143   // write back to disk.
144   config_timer = alarm_new("btif.iot.config");
145   if (!config_timer) {
146     log::error("Unable to create alarm.");
147     cleanup();
148     return future_new_immediate(FUTURE_FAIL);
149   }
150 
151   return future_new_immediate(FUTURE_SUCCESS);
152 }
153 
device_iot_config_module_start_up(void)154 future_t* device_iot_config_module_start_up(void) {
155   log::info("");
156   return future_new_immediate(FUTURE_SUCCESS);
157 }
158 
device_iot_config_module_shut_down(void)159 future_t* device_iot_config_module_shut_down(void) {
160   log::info("");
161   device_iot_config_flush();
162   return future_new_immediate(FUTURE_SUCCESS);
163 }
164 
device_iot_config_module_clean_up(void)165 future_t* device_iot_config_module_clean_up(void) {
166   log::info("");
167   if (config_timer != NULL && alarm_is_scheduled(config_timer)) {
168     device_iot_config_flush();
169   }
170 
171   alarm_free(config_timer);
172   config_timer = NULL;
173 
174   std::unique_lock<std::mutex> lock(config_lock);
175   config.reset();
176   config = NULL;
177   return future_new_immediate(FUTURE_SUCCESS);
178 }
179 
180 EXPORT_SYMBOL module_t device_iot_config_module = {.name = DEVICE_IOT_CONFIG_MODULE,
181                                                    .init = device_iot_config_module_init,
182                                                    .start_up = device_iot_config_module_start_up,
183                                                    .shut_down = device_iot_config_module_shut_down,
184                                                    .clean_up = device_iot_config_module_clean_up};
185 
device_iot_config_write(uint16_t event,UNUSED_ATTR char * p_param)186 void device_iot_config_write(uint16_t event, UNUSED_ATTR char* p_param) {
187   if (!com::android::bluetooth::flags::device_iot_config_logging()) {
188     return;
189   }
190 
191   log::assert_that(config != NULL, "assert failed: config != NULL");
192   log::assert_that(config_timer != NULL, "assert failed: config_timer != NULL");
193 
194   log::info("evt={}", event);
195   std::unique_lock<std::mutex> lock(config_lock);
196   if (event == IOT_CONFIG_SAVE_TIMER_FIRED_EVT) {
197     device_iot_config_set_modified_time();
198   }
199 
200   rename(IOT_CONFIG_FILE_PATH, IOT_CONFIG_BACKUP_PATH);
201   device_iot_config_restrict_device_num(*config);
202   device_iot_config_sections_sort_by_entry_key(*config, device_iot_config_compare_key);
203   config_save(*config, IOT_CONFIG_FILE_PATH);
204 }
205 
device_iot_config_sections_sort_by_entry_key(config_t & config,compare_func comp)206 void device_iot_config_sections_sort_by_entry_key(config_t& config, compare_func comp) {
207   for (auto& entry : config.sections) {
208     entry.entries.sort(comp);
209   }
210 }
211 
device_iot_config_has_key_value(const std::string & section,const std::string & key,const std::string & value_str)212 bool device_iot_config_has_key_value(const std::string& section, const std::string& key,
213                                      const std::string& value_str) {
214   log::assert_that(config != NULL, "assert failed: config != NULL");
215 
216   const std::string* stored_value = config_get_string(*config, section, key, NULL);
217 
218   if (!stored_value || value_str.compare(*stored_value) != 0) {
219     return false;
220   }
221 
222   return true;
223 }
224 
device_iot_config_save_async(void)225 void device_iot_config_save_async(void) {
226   if (!com::android::bluetooth::flags::device_iot_config_logging()) {
227     return;
228   }
229 
230   log::assert_that(config != NULL, "assert failed: config != NULL");
231   log::assert_that(config_timer != NULL, "assert failed: config_timer != NULL");
232 
233   log::verbose("");
234   alarm_set(config_timer, CONFIG_SETTLE_PERIOD_MS, device_iot_config_timer_save_cb, NULL);
235 }
236 
device_iot_config_get_device_num(const config_t & conf)237 int device_iot_config_get_device_num(const config_t& conf) {
238   if (!com::android::bluetooth::flags::device_iot_config_logging()) {
239     return 0;
240   }
241 
242   int devices = 0;
243 
244   for (const auto& entry : conf.sections) {
245     if (RawAddress::IsValidAddress(entry.name)) {
246       devices++;
247     }
248   }
249   return devices;
250 }
251 
device_iot_config_restrict_device_num(config_t & config)252 void device_iot_config_restrict_device_num(config_t& config) {
253   int curr_num = device_iot_config_get_device_num(config);
254   int removed_devices = 0;
255   int need_remove_devices_num;
256 
257   if (curr_num <= DEVICES_MAX_NUM_IN_IOT_INFO_FILE) {
258     return;
259   }
260 
261   need_remove_devices_num = curr_num - DEVICES_MAX_NUM_IN_IOT_INFO_FILE + DEVICES_NUM_MARGIN;
262   log::info("curr_num={}, need_remove_num={}", curr_num, need_remove_devices_num);
263 
264   std::list<section_t>::iterator i = config.sections.begin();
265   while (i != config.sections.end()) {
266     if (!RawAddress::IsValidAddress(i->name)) {
267       ++i;
268       continue;
269     }
270 
271     i = config.sections.erase(i);
272     if (++removed_devices >= need_remove_devices_num) {
273       break;
274     }
275   }
276 }
277 
device_iot_config_compare_key(const entry_t & first,const entry_t & second)278 bool device_iot_config_compare_key(const entry_t& first, const entry_t& second) {
279   bool first_is_profile_key = strncasecmp(first.key.c_str(), "Profile", 7) == 0;
280   bool second_is_profile_key = strncasecmp(second.key.c_str(), "Profile", 7) == 0;
281   if (!first_is_profile_key && !second_is_profile_key) {
282     return true;
283   } else if (first_is_profile_key && second_is_profile_key) {
284     return strcasecmp(first.key.c_str(), second.key.c_str()) <= 0;
285   } else {
286     return !first_is_profile_key;
287   }
288 }
289 
device_iot_config_timer_save_cb(void *)290 void device_iot_config_timer_save_cb(void* /* data */) {
291   // Moving file I/O to btif context instead of timer callback because
292   // it usually takes a lot of time to be completed, introducing
293   // delays during A2DP playback causing blips or choppiness.
294   log::verbose("");
295   btif_transfer_context(device_iot_config_write, IOT_CONFIG_SAVE_TIMER_FIRED_EVT, NULL, 0, NULL);
296 }
297 
device_iot_config_set_modified_time()298 void device_iot_config_set_modified_time() {
299   time_t current_time = time(NULL);
300   struct tm* time_modified = localtime(&current_time);
301   char device_iot_config_time_modified[TIME_STRING_LENGTH];
302   if (time_modified) {
303     strftime(device_iot_config_time_modified, TIME_STRING_LENGTH, TIME_STRING_FORMAT,
304              time_modified);
305     config_set_string(config.get(), INFO_SECTION, FILE_MODIFIED_TIMESTAMP,
306                       device_iot_config_time_modified);
307   }
308 }
309 
device_iot_config_is_factory_reset(void)310 bool device_iot_config_is_factory_reset(void) {
311   return osi_property_get_bool(PROPERTY_FACTORY_RESET, false);
312 }
313 
device_iot_config_delete_files(void)314 void device_iot_config_delete_files(void) {
315   remove(IOT_CONFIG_FILE_PATH);
316   remove(IOT_CONFIG_BACKUP_PATH);
317 }
318