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