[my-place] Refactoring: Code separation.
[platform/core/context/context-provider.git] / src / my-place / visit-detector / wifi_logger.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <sstream>
18 #include <Types.h>
19 #include <DatabaseManager.h>
20 #include "../facade/user_places_types.h"
21 #include "../utils/debug_utils.h"
22 #include "wifi_logger.h"
23
24 #define __WIFI_CREATE_TABLE_COLUMNS \
25         WIFI_COLUMN_TIMESTAMP " timestamp NOT NULL, "\
26         WIFI_COLUMN_BSSID " TEXT NOT NULL, "\
27         WIFI_COLUMN_ESSID " TEXT NOT NULL"
28
29 #define __WIFI_ERROR_LOG(error) { \
30         if (error != WIFI_ERROR_NONE) { \
31                 _E("ERROR == %s", __wifiError2Str(error)); \
32         } else { \
33                 _D("SUCCESS"); \
34         } \
35 }
36
37 int ctx::WifiLogger::__dbCreateTable()
38 {
39         ctx::DatabaseManager dbManager;
40         bool ret = dbManager.createTable(0, WIFI_TABLE_NAME, __WIFI_CREATE_TABLE_COLUMNS, NULL, NULL);
41         _D("Table Creation Request: %s", ret ? "SUCCESS" : "FAIL");
42         return ret;
43 }
44
45 int ctx::WifiLogger::__dbInsertLogs()
46 {
47         if (__logs.size() > 0) {
48                 ctx::DatabaseManager dbManager;
49                 std::stringstream query;
50                 const char* separator = " ";
51                 query << "BEGIN TRANSACTION; \
52                                 INSERT INTO " WIFI_TABLE_NAME " \
53                                 ( " WIFI_COLUMN_BSSID ", " WIFI_COLUMN_ESSID ", " WIFI_COLUMN_TIMESTAMP " ) \
54                                 VALUES";
55                 for (MacEvent mac_event : __logs) {
56                         query << separator << "( '" << mac_event.mac << "', '" << mac_event.networkName << "', '" << mac_event.timestamp << "' )";
57                         separator = ", ";
58                 }
59                 __logs.clear();
60                 query << "; \
61                                 END TRANSACTION;";
62                 bool ret = dbManager.execute(0, query.str().c_str(), NULL);
63                 _D("DB insert request: %s", ret ? "SUCCESS" : "FAIL");
64                 return ret;
65         }
66         _D("__logs vector empty -> nothing to insert");
67         return 0;
68 }
69
70 ctx::WifiLogger::WifiLogger(IWifiListener * listener, PlaceRecogMode energyMode) :
71         __timerOn(false),
72         __intervalMinutes(WIFI_LOGGER_INTERVAL_MINUTES_HIGH_ACCURACY),
73         __listener(listener),
74         __lastScanTime(time_t(0)),
75         __lasTimerCallbackTime(time_t(0)),
76         __duringVisit(false),
77         __connectedToWifiAp(false),
78         __started(false),
79         __running(false)
80 {
81         _D("CONSTRUCTOR");
82
83         __setInterval(energyMode);
84
85         if (WIFI_LOGGER_DATABASE)
86                 __dbCreateTable();
87
88         __logs = std::vector<MacEvent>();
89
90         __wifiSetDeviceStateChangedCbRequest();
91
92         if (WIFI_LOGGER_LOW_POWER_MODE)
93                 __wifiSetConnectionStateChangedCbRequest();
94
95         wifi_connection_state_e state = __wifiGetConnectionStateRequest();
96         __connectedToWifiAp = (state == WIFI_CONNECTION_STATE_CONNECTED);
97         _D("__connectedToWifiAp = %d, __duringVisit = %d IN CONSTRUCTOR",
98                                 static_cast<int>(__connectedToWifiAp),
99                                 static_cast<int>(__duringVisit));
100 }
101
102 ctx::WifiLogger::~WifiLogger()
103 {
104         _D("DESTRUCTOR");
105         stopLogging();
106 }
107
108 void ctx::WifiLogger::__wifiDeviceStateChangedCb(wifi_device_state_e state, void *userData)
109 {
110         ctx::WifiLogger* wifiLogger = (ctx::WifiLogger *)userData;
111         switch (state) {
112         case WIFI_DEVICE_STATE_DEACTIVATED:
113                 _D("WIFI setting OFF");
114                 if (wifiLogger->__started)
115                         wifiLogger->__stopLogging();
116                 break;
117         case WIFI_DEVICE_STATE_ACTIVATED:
118                 _D("WIFI setting ON");
119                 if (wifiLogger->__started)
120                         wifiLogger->__startLogging();
121                 break;
122         default:
123                 break;
124         }
125 }
126
127 void ctx::WifiLogger::__wifiConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap, void *userData)
128 {
129         ctx::WifiLogger* wifiLogger = (ctx::WifiLogger *)userData;
130         switch (state) {
131         case WIFI_CONNECTION_STATE_CONNECTED:
132                 _D("connected to AP");
133                 wifiLogger->__connectedToWifiAp = true;
134                 break;
135         default:
136                 _D("disconnected from AP -> __lastScansPool.clear()");
137                 wifiLogger->__connectedToWifiAp = false;
138                 wifiLogger->__lastScansPool.clear();
139                 break;
140         }
141         // TODO: Check if AP bssid (MAC Address) will be helpful somehow in LOW_POWER mode
142 }
143
144 bool ctx::WifiLogger::__wifiFoundApCb(wifi_ap_h ap, void *userData)
145 {
146         ctx::WifiLogger* wifiLogger = (ctx::WifiLogger *)userData;
147
148         char *bssid = NULL;
149         int ret = wifiLogger->__wifiApGetBssidRequest(ap, &bssid);
150         if (ret != WIFI_ERROR_NONE)
151                 return false;
152
153         char *essid = NULL;
154         ret = wifiLogger->__wifiApGetEssidRequest(ap, &essid);
155         if (ret != WIFI_ERROR_NONE)
156                 return false;
157
158         Mac mac;
159         try {
160                 mac = Mac(bssid);
161         } catch (std::runtime_error &e) {
162                 _E("Cannot create mac_event. Exception: %s", e.what());
163                 return false;
164         }
165
166         MacEvent log(wifiLogger->__lastScanTime, mac, std::string(essid));
167         if (wifiLogger->__listener) {
168                 wifiLogger->__listener->onWifiScan(log);
169                 if (WIFI_LOGGER_LOW_POWER_MODE
170                                 && (wifiLogger->__connectedToWifiAp || wifiLogger->__duringVisit) ) {
171                         // Add to last scans AP's set
172                         wifiLogger->__lastScansPool.insert(std::pair<std::string, std::string>(std::string(bssid), std::string(essid)));
173                 }
174         }
175         if (WIFI_LOGGER_DATABASE)
176                 wifiLogger->__logs.push_back(log);
177
178         return true;
179 }
180
181 const char* ctx::WifiLogger::__wifiError2Str(int error)
182 {
183         switch (error) {
184         case WIFI_ERROR_INVALID_PARAMETER:
185                 return "WIFI_ERROR_INVALID_PARAMETER";
186         case WIFI_ERROR_OUT_OF_MEMORY:
187                 return "WIFI_ERROR_OUT_OF_MEMORY";
188         case WIFI_ERROR_INVALID_OPERATION:
189                 return "WIFI_ERROR_INVALID_OPERATION";
190         case WIFI_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED:
191                 return "WIFI_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED";
192         case WIFI_ERROR_OPERATION_FAILED:
193                 return "WIFI_ERROR_OPERATION_FAILED";
194         case WIFI_ERROR_NO_CONNECTION:
195                 return "WIFI_ERROR_NO_CONNECTION";
196         case WIFI_ERROR_NOW_IN_PROGRESS:
197                 return "WIFI_ERROR_NOW_IN_PROGRESS";
198         case WIFI_ERROR_ALREADY_EXISTS:
199                 return "WIFI_ERROR_ALREADY_EXISTS";
200         case WIFI_ERROR_OPERATION_ABORTED:
201                 return "WIFI_ERROR_OPERATION_ABORTED";
202         case WIFI_ERROR_DHCP_FAILED:
203                 return "WIFI_ERROR_DHCP_FAILED";
204         case WIFI_ERROR_INVALID_KEY:
205                 return "WIFI_ERROR_INVALID_KEY";
206         case WIFI_ERROR_NO_REPLY:
207                 return "WIFI_ERROR_NO_REPLY";
208         case WIFI_ERROR_SECURITY_RESTRICTED:
209                 return "WIFI_ERROR_SECURITY_RESTRICTED";
210         case WIFI_ERROR_PERMISSION_DENIED:
211                 return "WIFI_ERROR_PERMISSION_DENIED";
212         default:
213                 return "unknown wifi error code";
214         }
215 }
216
217 void ctx::WifiLogger::__wifiScanFinishedCb(wifi_error_e errorCode, void *userData)
218 {
219         ctx::WifiLogger* wifiLogger = (ctx::WifiLogger *)userData;
220
221         time_t now = time(nullptr);
222 #ifdef TIZEN_ENGINEER_MODE
223         double seconds = 0;
224         if (wifiLogger->__lastScanTime > 0) {
225                 seconds = difftime(now, wifiLogger->__lastScanTime);
226         }
227         std::string timeStr = DebugUtils::humanReadableDateTime(now, "%T", 9);
228         _D("__connectedToWifiAp = %d, __duringVisit = %d, __lastScansPool.size() = %d -> scan %s (from last : %.1fs)",
229                         static_cast<int>(wifiLogger->__connectedToWifiAp),
230                         static_cast<int>(wifiLogger->__duringVisit),
231                         wifiLogger->__lastScansPool.size(),
232                         timeStr.c_str(),
233                         seconds);
234 #endif /* TIZEN_ENGINEER_MODE */
235         wifiLogger->__lastScanTime = now;
236
237         int ret = wifiLogger->__wifiForeachFoundApsRequest(userData);
238         if (ret != WIFI_ERROR_NONE)
239                 return;
240         if (WIFI_LOGGER_DATABASE)
241                 wifiLogger->__dbInsertLogs();
242 }
243
244 bool ctx::WifiLogger::__checkWifiIsActivated()
245 {
246         bool wifiActivated = true;
247         int ret = __wifiWrapper.isActivated(&wifiActivated);
248         __WIFI_ERROR_LOG(ret);
249         _D("Wi-Fi is %s", wifiActivated ? "ON" : "OFF");
250         return wifiActivated;
251 }
252
253 void ctx::WifiLogger::__wifiScanRequest()
254 {
255         int ret = __wifiWrapper.scan(__wifiScanFinishedCb, this);
256         __WIFI_ERROR_LOG(ret);
257 }
258
259 int ctx::WifiLogger::__wifiForeachFoundApsRequest(void *userData)
260 {
261         int ret = __wifiWrapper.foreachFoundAP(__wifiFoundApCb, userData);
262         __WIFI_ERROR_LOG(ret);
263         return ret;
264 }
265
266 wifi_connection_state_e ctx::WifiLogger::__wifiGetConnectionStateRequest()
267 {
268         wifi_connection_state_e connectionState;
269         int ret = __wifiWrapper.getConnectionState(&connectionState);
270         __WIFI_ERROR_LOG(ret);
271         return connectionState;
272 }
273
274 void ctx::WifiLogger::__wifiSetBackgroundScanCbRequest()
275 {
276         int ret = __wifiWrapper.setBackgroundScanCb(__wifiScanFinishedCb, this);
277         __WIFI_ERROR_LOG(ret);
278 }
279
280 void ctx::WifiLogger::__wifiSetDeviceStateChangedCbRequest()
281 {
282         int ret = __wifiWrapper.setDeviceStateChangedCb(__wifiDeviceStateChangedCb, this);
283         __WIFI_ERROR_LOG(ret);
284 }
285
286 void ctx::WifiLogger::__wifiSetConnectionStateChangedCbRequest()
287 {
288         int ret = __wifiWrapper.setConnectionStateChangedCb(__wifiConnectionStateChangedCb, this);
289         __WIFI_ERROR_LOG(ret);
290 }
291
292 int ctx::WifiLogger::__wifiApGetEssidRequest(wifi_ap_h ap, char **essid)
293 {
294         int ret = __wifiWrapper.getEssidFromAP(ap, essid);
295         __WIFI_ERROR_LOG(ret);
296         return ret;
297 }
298
299 int ctx::WifiLogger::__wifiApGetBssidRequest(wifi_ap_h ap, char **bssid)
300 {
301         int ret = __wifiWrapper.getBssidFromAP(ap, bssid);
302         __WIFI_ERROR_LOG(ret);
303         return ret;
304 }
305
306 bool ctx::WifiLogger::__checkTimerId(int id)
307 {
308         _D("id == %d, __timerId == %d", id, __timerId);
309         return id == __timerId;
310 }
311
312 /*
313  * Accepted time from last callback is >= than minimum interval
314  */
315 bool ctx::WifiLogger::__checkTimerTime(time_t now)
316 {
317         double seconds = 0;
318         if (__lasTimerCallbackTime > 0) {
319                 seconds = difftime(now, __lasTimerCallbackTime);
320                 if (seconds < WIFI_LOGGER_ACTIVE_SCANNING_MIN_INTERVAL) {
321                         _D("last == %d, now == %d, diff = %.1fs -> Incorrect timer callback", __lasTimerCallbackTime, now, seconds);
322                         return false;
323                 } else {
324                         _D("last == %d, now == %d, diff = %.1fs -> Correct timer callback", __lasTimerCallbackTime, now, seconds);
325                 }
326         } else {
327                 _D("last == %d, now == %d -> First callback", __lasTimerCallbackTime, now);
328         }
329         __lasTimerCallbackTime = now;
330         return true;
331 }
332
333 bool ctx::WifiLogger::onTimerExpired(int id)
334 {
335         time_t now = time(nullptr);
336         _D("");
337         if (__checkTimerId(id) == false) // Incorrect callback call
338                 return false;
339         if (__checkTimerTime(now) == false) // Prevention from double callback call bug
340                 return __timerOn;
341         _D("__connectedToWifiAp = %d, __duringVisit = %d, __lastScansPool.size() = %d",
342                         static_cast<int>(__connectedToWifiAp),
343                         static_cast<int>(__duringVisit),
344                         __lastScansPool.size());
345         if (WIFI_LOGGER_LOW_POWER_MODE
346                         && __duringVisit
347                         && __connectedToWifiAp
348                         && __lastScansPool.size() > 0) {
349                 _D("trying to send fake scan");
350                 if (__listener) {
351                         _D("__listener != false -> CORRECT");
352                         for (std::pair<std::string, std::string> ap : __lastScansPool) {
353                                 Mac mac(ap.first);
354                                 MacEvent scan(now, mac, ap.second);
355                                 _D("send fake scan (%s, %s)", ap.first.c_str(), ap.second.c_str());
356                                 __listener->onWifiScan(scan);
357                         }
358                 }
359         } else {
360                 __wifiScanRequest();
361         }
362         return __timerOn;
363 }
364
365 void ctx::WifiLogger::startLogging()
366 {
367         _D("");
368         __started = true;
369         __startLogging();
370 }
371
372 void ctx::WifiLogger::__startLogging()
373 {
374         _D("");
375         if (!__checkWifiIsActivated() || __running)
376                 return;
377         __running = true;
378
379         if (WIFI_LOGGER_ACTIVE_SCANNING) {
380                 __timerStart(__intervalMinutes);
381                 __wifiScanRequest();
382         }
383         if (WIFI_LOGGER_PASSIVE_SCANNING)
384                 __wifiSetBackgroundScanCbRequest();
385 }
386
387 void ctx::WifiLogger::stopLogging()
388 {
389         _D("");
390         __started = false;
391         __stopLogging();
392 }
393
394 void ctx::WifiLogger::__stopLogging()
395 {
396         _D("");
397         if (!__running)
398                 return;
399         if (WIFI_LOGGER_ACTIVE_SCANNING) {
400                 // Unset timer
401                 __timerOn = false;
402                 // Remove timer
403                 __timerManager.remove(__timerId);
404         }
405         if (WIFI_LOGGER_PASSIVE_SCANNING)
406                 __wifiWrapper.unsetBackgroundScanCb();
407         __running = false;
408 }
409
410 void ctx::WifiLogger::__timerStart(time_t minutes)
411 {
412         __timerOn = true;
413         __timerId = __timerManager.setFor(minutes, this);
414         _D("%s (minutes=%d)", __timerId >= 0 ? "SUCCESS" : "ERROR", minutes);
415 }
416
417 void ctx::WifiLogger::onVisitStart()
418 {
419         _D("");
420         __duringVisit = true;
421 }
422
423 void ctx::WifiLogger::onVisitEnd()
424 {
425         _D("__lastScansPool.clear()");
426         __duringVisit = false;
427         __lastScansPool.clear();
428 }
429
430 void ctx::WifiLogger::__setInterval(PlaceRecogMode energyMode)
431 {
432         switch (energyMode) {
433         case PLACE_RECOG_LOW_POWER_MODE:
434                 __intervalMinutes = WIFI_LOGGER_INTERVAL_MINUTES_LOW_POWER;
435                 break;
436         case PLACE_RECOG_HIGH_ACCURACY_MODE:
437                 __intervalMinutes = WIFI_LOGGER_INTERVAL_MINUTES_HIGH_ACCURACY;
438                 break;
439         default:
440                 _E("Incorrect energy mode");
441         }
442 }
443
444 void ctx::WifiLogger::__timerRestart()
445 {
446         __timerManager.remove(__timerId);
447         __timerStart(__intervalMinutes);
448 }
449
450 void ctx::WifiLogger::setMode(PlaceRecogMode energyMode)
451 {
452         _D("");
453         __setInterval(energyMode);
454         if (WIFI_LOGGER_ACTIVE_SCANNING && __timerOn)
455                 __timerRestart();
456 }