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