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