Remove old bt-service files
[platform/core/connectivity/bluetooth-frwk.git] / bt-service / services / bt-service-battery-monitor.c
1 /*
2  * Bluetooth-frwk
3  *
4  * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:  Sudipto Bal <sudipto.bal@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *              http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <glib.h>
23 #include <gio/gio.h>
24 #include <string.h>
25 #include <dlog.h>
26 #include <time.h>
27 #include <sys/time.h>
28 #include <vconf.h>
29
30 #include <oal-event.h>
31
32 #include "bt-service-battery-monitor.h"
33 #include "bt-service-common.h"
34 #include "bt-service-event.h"
35 #include "bt-service-core-adapter.h"
36
37 /* Avoid the build error related to vconf.h's dependency */
38 #ifndef VCONFKEY_BATTERY_MONITOR_STATUS
39 #define VCONFKEY_BATTERY_MONITOR_STATUS "db/bluetooth/bmstatus"
40 #endif
41
42 /* 20 minutes */
43 #define BT_BM_SESSION_TIMEOUT 1200
44
45 static struct timeval scan_start;
46 static struct timeval connect_start;
47 static struct timeval app_scan_base;
48 static int scan_cnt = 0;
49 static int connect_cnt = 0;
50 static gboolean is_session_started = FALSE;
51 static guint session_timer = 0;
52
53 static GSList *scan_app_list = NULL;
54
55 typedef struct {
56         int type;
57         void *data;
58 } bt_service_oal_event_data_t;
59
60 _bt_battery_data_t *current_session_data = NULL;
61
62 static void __bt_bm_add_prev_time(uint32_t scan_time);
63 static int __bt_start_session_time(void);
64 static void __bt_stop_session_time(void);
65 static bool __bt_bm_session_timeout_cb(void);
66
67 uint32_t static __bt_dm_time_diff_msec(struct timeval prev, struct timeval cur)
68 {
69     return (uint32_t)((cur.tv_sec - prev.tv_sec) * 1000.0f + (cur.tv_usec - prev.tv_usec) / 1000.0f);
70 }
71
72 static void __bt_display_session_data()
73 {
74         BT_DBG("Displaying session data...");
75
76         if (current_session_data == NULL) {
77                 BT_ERR("Session in progress but data structure is not initialized");
78                 return;
79         }
80
81         BT_DBG("session_start_time = %ld", current_session_data->session_start_time);
82         BT_DBG("session_end_time = %ld", current_session_data->session_end_time);
83         BT_DBG("session_scan_time = %d", current_session_data->session_scan_time);
84         BT_DBG("session_connected_time = %d", current_session_data->session_connected_time);
85 }
86
87 /*After reading data, the function resets it*/
88 int _bt_bm_read_data(_bt_battery_data_t *data)
89 {
90         struct timeval cur_time;
91         uint32_t tx_time = 0;
92         uint32_t rx_time = 0;
93         uint32_t idle_time = 0;
94         uint32_t energy_used = 0;
95         uint32_t scan_time_per_app = 0;
96         int scan_app_cnt = 0;
97
98         BT_DBG("");
99
100         if (data == NULL) {
101                 BT_ERR("Received NULL pointer in argument, returning...");
102                 return BLUETOOTH_ERROR_NO_DATA;
103         }
104
105         if (_bt_get_energy_info(&tx_time, &rx_time,
106                                 &idle_time, &energy_used) != BLUETOOTH_ERROR_NONE) {
107                 BT_ERR("Fail to get energy info");
108                 return BLUETOOTH_ERROR_NOT_SUPPORT;
109         }
110
111         if (is_session_started == FALSE) {
112                 if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
113                         BT_ERR("Fail to start session time");
114                         return BLUETOOTH_ERROR_NOT_SUPPORT;
115                 }
116         }
117
118         if (current_session_data == NULL) {
119                 BT_ERR("Session in progress but data structure is not initialized");
120                 return BLUETOOTH_ERROR_INTERNAL;
121         }
122
123         gettimeofday(&cur_time, 0);
124
125         data->tx_time = tx_time;
126         data->rx_time = rx_time;
127         data->idle_time = idle_time;
128
129         data->session_start_time = current_session_data->session_start_time;
130         data->session_end_time = time(NULL);
131         current_session_data->session_start_time = time(NULL);
132         current_session_data->session_end_time = 0;
133
134         data->session_scan_time = current_session_data->session_scan_time;
135         if (scan_cnt) {
136                 data->session_scan_time += (uint32_t)__bt_dm_time_diff_msec(scan_start, cur_time);
137                 gettimeofday(&scan_start, 0);
138         }
139         current_session_data->session_scan_time = 0;
140
141         data->session_connected_time = current_session_data->session_connected_time;
142         if (connect_cnt) {
143                 data->session_connected_time += (uint32_t)__bt_dm_time_diff_msec(connect_start, cur_time);
144                 gettimeofday(&connect_start, 0);
145         }
146         current_session_data->session_connected_time = 0;
147
148         scan_app_cnt = g_slist_length(scan_app_list);
149
150         if (scan_app_cnt > 0) {
151                 scan_time_per_app = (uint32_t)__bt_dm_time_diff_msec(app_scan_base, cur_time) / scan_app_cnt;
152                 __bt_bm_add_prev_time(scan_time_per_app);
153         }
154
155         gettimeofday(&app_scan_base, 0);
156
157         /* Note that this is a "shallow" copy. The pointers are copied but the actual data isn't. */
158         data->atm_list = g_slist_copy(current_session_data->atm_list);
159         current_session_data->atm_list = NULL;
160
161         BT_DBG("App-wise data transaction details");
162         for (GSList *l = data->atm_list; l != NULL; l = g_slist_next(l)) {
163                 _bt_battery_app_data_t *t = (_bt_battery_app_data_t *)(l->data);
164                 BT_DBG("%ld %ld %d %d %u", (long int)(t->uid), (long int)(t->pid), t->rx_bytes, t->tx_bytes, t->time);
165         }
166
167         /* Reset the session timer */
168         if (session_timer)
169                 g_source_remove(session_timer);
170
171         session_timer = g_timeout_add_seconds(BT_BM_SESSION_TIMEOUT,
172                                 (GSourceFunc)__bt_bm_session_timeout_cb, NULL);
173
174         return BLUETOOTH_ERROR_NONE;
175 }
176
177 static GSList* is_app_present(GSList *start, uid_t uid, pid_t pid)
178 {
179         GSList *l = NULL;
180         _bt_battery_app_data_t *t;
181         BT_DBG("Checking Memory location %p", start);
182         for (l=start; l != NULL; l = g_slist_next(l)) {
183                 t = (_bt_battery_app_data_t *)(l->data);
184                 if (t->uid == uid && t->pid == pid) {
185                         BT_DBG("App details already exist");
186                         return l;
187                 }
188         }
189         return NULL;
190 }
191
192 void _bt_bm_add_transaction_details(uid_t uid, pid_t pid, unsigned int value, data_transaction_type_e type)
193 {
194         if (is_session_started == FALSE)
195                 __bt_start_session_time();
196
197         if (current_session_data == NULL) {
198                 BT_ERR("Session in progress but data structure is not initialized");
199                 return;
200         }
201         GSList *t = is_app_present(current_session_data->atm_list, uid, pid);
202         _bt_battery_app_data_t *app_data = NULL;
203
204         if (t == NULL) {
205                 BT_DBG("Match not found, adding new node...");
206                 app_data = g_malloc0(sizeof(_bt_battery_app_data_t));
207                 app_data->uid = uid;
208                 app_data->pid = pid;
209                 if (type == RX_DATA)
210                         app_data->rx_bytes = value;
211                 else if (type == TX_DATA)
212                         app_data->tx_bytes = value;
213                 else
214                         app_data->time = value;
215                 current_session_data->atm_list = g_slist_append(current_session_data->atm_list, app_data);
216         }
217         else {
218                 BT_DBG("Match found, updating existing node...");
219                 app_data = (_bt_battery_app_data_t *)(t->data);
220                 if (type == RX_DATA)
221                         app_data->rx_bytes += value;
222                 else if (type == TX_DATA)
223                         app_data->tx_bytes += value;
224                 else
225                         app_data->time += value;
226         }
227 }
228
229 static bool __bt_bm_session_timeout_cb(void)
230 {
231         BT_DBG("No data read calls during the time.");
232
233         __bt_stop_session_time();
234
235         return FALSE;
236 }
237
238
239 static int __bt_start_session_time(void)
240 {
241         int state = 0;
242
243         if (is_session_started == TRUE) {
244                 BT_ERR("Session is already started");
245                 return BLUETOOTH_ERROR_ALREADY_INITIALIZED;
246         }
247
248         if (vconf_get_bool(VCONFKEY_BATTERY_MONITOR_STATUS, &state) != 0) {
249                 BT_ERR("vconf_get_bool failed");
250                 return BLUETOOTH_ERROR_INTERNAL;
251         }
252
253         if (state == 0) {
254                 BT_ERR("Battery is not monitoring in now");
255                 return BLUETOOTH_ERROR_NOT_SUPPORT;
256         }
257
258         BT_DBG("Bt session starting...");
259         is_session_started = TRUE;
260
261         if (current_session_data == NULL)
262                 current_session_data = g_malloc0(sizeof(_bt_battery_data_t));
263
264         current_session_data->session_start_time = time(NULL);
265         current_session_data->session_end_time = 0;
266         current_session_data->session_connected_time = 0;
267         current_session_data->session_scan_time = 0;
268         current_session_data->atm_list = NULL;
269
270         /* After starting session if there is no read data call during the specific time,
271          * stop the session time to avoid the exceed of session data.
272         */
273         if (session_timer)
274                 g_source_remove(session_timer);
275
276         session_timer = g_timeout_add_seconds(BT_BM_SESSION_TIMEOUT,
277                                 (GSourceFunc)__bt_bm_session_timeout_cb, NULL);
278
279         return BLUETOOTH_ERROR_NONE;
280 }
281
282 static void __bt_stop_session_time(void)
283 {
284         if (session_timer) {
285                 g_source_remove(session_timer);
286                 session_timer = 0;
287         }
288
289         if (is_session_started == FALSE) {
290                 BT_DBG("BT session not in progress... Returning");
291                 return;
292         }
293
294         __bt_display_session_data();
295
296         BT_DBG("Bt session ending...");
297         is_session_started = FALSE;
298
299         if (current_session_data != NULL) {
300                 g_slist_free_full(current_session_data->atm_list, g_free);
301                 g_free(current_session_data);
302                 current_session_data = NULL;
303         }
304 }
305
306 /* 1 app can operate the regacy and ble scan at the same time */
307 static GSList* __is_scan_app_present(GSList *start, bt_bm_scan_type_e type, uid_t uid, pid_t pid)
308 {
309         GSList *l = NULL;
310         bt_bm_scan_info_t *t;
311
312         for (l = start; l != NULL; l = g_slist_next(l)) {
313                 t = (bt_bm_scan_info_t *)(l->data);
314
315                 /* Find the regacy scan app for Inquiry stop */
316                 if (type == SCAN_REGACY && t->type != SCAN_LE) {
317                         BT_DBG("app already exist");
318                         return l;
319                 }
320
321                 if (t->uid == uid && t->pid == pid) {
322                         BT_DBG("app already exist");
323                         return l;
324                 }
325         }
326         return NULL;
327 }
328
329 static void __bt_bm_add_prev_time(uint32_t scan_time)
330 {
331         GSList *l = NULL;
332         bt_bm_scan_info_t *t;
333
334         for (l = scan_app_list; l != NULL; l = g_slist_next(l)) {
335                 t = (bt_bm_scan_info_t *)(l->data);
336                 _bt_bm_add_transaction_details(t->uid, t->pid, scan_time, TIME_DATA);
337         }
338 }
339
340 /* 1 regacy scan is only allowed in the platform
341  * BLE scan is allowed for many apps
342 */
343 /* When a app is added, we should add and reset the time. */
344 void _bt_bm_add_scan_app(bt_bm_scan_type_e type, uid_t uid, pid_t pid)
345 {
346         bt_bm_scan_info_t *scan_info = NULL;
347         GSList *app_list = NULL;
348         int app_cnt = 0;
349         uint32_t scan_time_per_app = 0;
350
351         BT_DBG("Scan type: %d", type);
352
353         if (scan_app_list) {
354                 app_cnt = g_slist_length(scan_app_list);
355                 app_list = __is_scan_app_present(scan_app_list, SCAN_BOTH, uid, pid);
356         }
357
358         if (app_list) {
359                 /* app try to scan both Regacy and LE */
360                 scan_info = (bt_bm_scan_info_t *)(app_list->data);
361
362                 if (scan_info == NULL) {
363                         BT_ERR("Can't get the scan info");
364                         return;
365                 }
366
367                 BT_DBG("Previous type: %d", scan_info->type);
368
369                 if (scan_info->type == type) {
370                         BT_ERR("Same scan type is doing");
371                         return;
372                 }
373
374                 scan_info->type = SCAN_BOTH;
375         } else {
376                 scan_info = g_malloc0(sizeof(bt_bm_scan_info_t));
377                 scan_info->uid = uid;
378                 scan_info->pid = pid;
379                 scan_info->type = type;
380
381                 if (app_cnt > 0) {
382                         struct timeval cur_time;
383
384                         gettimeofday(&cur_time, 0);
385
386                         scan_time_per_app = (uint32_t)(__bt_dm_time_diff_msec(app_scan_base, cur_time)) / app_cnt;
387                         __bt_bm_add_prev_time(scan_time_per_app);
388
389                         /* Update the base time */
390                         gettimeofday(&app_scan_base, 0);
391                 }
392
393                 scan_app_list = g_slist_append(scan_app_list, scan_info);
394         }
395 }
396
397 /* When a app is removed, we should add and reset the time. */
398 void _bt_bm_remove_scan_app(bt_bm_scan_type_e type, uid_t uid, pid_t pid)
399 {
400         bt_bm_scan_info_t *scan_info = NULL;
401         GSList *app_list = NULL;
402         int app_cnt = 0;
403         uint32_t scan_time_per_app = 0;
404
405         BT_DBG("Scan type: %d", type);
406
407         if (scan_app_list == NULL) {
408                 BT_ERR("No scan app in list");
409                 return;
410         }
411
412         app_cnt = g_slist_length(scan_app_list);
413
414         if (app_cnt == 0) {
415                 BT_ERR("No scan app in list");
416                 return;
417         }
418
419         app_list = __is_scan_app_present(scan_app_list, type, uid, pid);
420
421         if (app_list) {
422                 struct timeval cur_time;
423
424                 scan_info = (bt_bm_scan_info_t *)(app_list->data);
425
426                 if (scan_info->type == SCAN_BOTH) {
427                         scan_info->type = (scan_info->type == SCAN_REGACY) ? SCAN_LE : SCAN_REGACY;
428                         return;
429                 }
430
431                 gettimeofday(&cur_time, 0);
432
433                 scan_time_per_app = (uint32_t)(__bt_dm_time_diff_msec(app_scan_base, cur_time)) / app_cnt;
434                 __bt_bm_add_prev_time(scan_time_per_app);
435
436                 /* Update the base time */
437                 gettimeofday(&app_scan_base, 0);
438
439                 scan_app_list = g_slist_remove(scan_app_list, scan_info);
440
441                 g_free(scan_info);
442         }
443 }
444
445 void _bt_start_scan_time()
446 {
447         if (is_session_started == FALSE) {
448                 if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
449                         BT_ERR("Fail to start session time");
450                         return;
451                 }
452         }
453
454         if (current_session_data != NULL) {
455                 if (scan_cnt == 0) {
456                         BT_DBG("Starting scan time");
457                         gettimeofday(&scan_start, 0);
458                         gettimeofday(&app_scan_base, 0);
459                 }
460                 scan_cnt++;
461         } else {
462                 BT_ERR("Data structure uninitialized");
463         }
464 }
465
466 void _bt_stop_scan_time()
467 {
468         if (is_session_started == FALSE) {
469                 if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
470                         BT_ERR("Fail to start session time");
471                         return;
472                 }
473         }
474
475         if (scan_cnt == 0 || current_session_data == NULL)
476                 BT_ERR("Error encountered, returning...");
477         else {
478                 scan_cnt--;
479                 if(scan_cnt == 0) {
480                         struct timeval cur_time;
481
482                         gettimeofday(&cur_time, 0);
483                         current_session_data->session_scan_time += (uint32_t)(__bt_dm_time_diff_msec(scan_start, cur_time));
484                         gettimeofday(&scan_start, 0);
485                         gettimeofday(&app_scan_base, 0);
486                 }
487         }
488 }
489
490 void _bt_start_connect_time()
491 {
492         if (is_session_started == FALSE) {
493                 if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
494                         BT_ERR("Fail to start session time");
495                         return;
496                 }
497         }
498
499         if (current_session_data != NULL) {
500                 if (connect_cnt == 0) {
501                         BT_DBG("Starting connect time");
502                         gettimeofday(&connect_start, 0);
503                 }
504                 connect_cnt++;
505         }
506         else {
507                 BT_ERR("Data structure uninitialized");
508         }
509 }
510
511 void _bt_stop_connect_time()
512 {
513         if (is_session_started == FALSE) {
514                 if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
515                         BT_ERR("Fail to start session time");
516                         return;
517                 }
518         }
519
520         if(connect_cnt == 0 || current_session_data == NULL) {
521                 BT_ERR("Error encountered, returning...");
522         } else {
523                 connect_cnt--;
524                 if(connect_cnt == 0) {
525                         struct timeval cur_time;
526
527                         gettimeofday(&cur_time, 0);
528                         current_session_data->session_connected_time += (uint32_t)(__bt_dm_time_diff_msec(connect_start, cur_time));
529                 }
530         }
531 }
532
533 static void __bt_notify_battery_data(void)
534 {
535         BT_DBG("+");
536         _bt_battery_data_t *data = NULL;
537         int result;
538
539         data = g_new0(_bt_battery_data_t, 1);
540         result = _bt_bm_read_data(data);
541         GVariant *out_var = NULL, *param = NULL;
542         GArray *info = NULL;
543
544         if (result != BLUETOOTH_ERROR_NONE) {
545                 BT_ERR("Battery data not collected");
546                 g_free(data);
547                 return;
548         }
549
550         bt_battery_dbus_data_t dbus_data;
551         memset(&dbus_data, 0, sizeof(bt_battery_dbus_data_t));
552         dbus_data.session_start_time = data->session_start_time;
553         dbus_data.session_end_time = data->session_end_time;
554         dbus_data.session_scan_time = data->session_scan_time;
555         dbus_data.session_connected_time = data->session_connected_time;
556         dbus_data.tx_time = data->tx_time;
557         dbus_data.rx_time = data->rx_time;
558         dbus_data.idle_time = data->idle_time;
559
560         /*Populating app data*/
561         int n = 0;
562         for (GSList *l = data->atm_list; l != NULL; l = g_slist_next(l)) {
563                 bt_battery_app_data *t = (bt_battery_app_data *)(l->data);
564                 memcpy(&dbus_data.app_data[n], t, sizeof(bt_battery_app_data));
565                 n++;
566         }
567         dbus_data.num_app = n;
568
569         info = g_array_new(FALSE, FALSE, sizeof(gchar));
570         g_array_append_vals(info, &dbus_data, sizeof(bt_battery_dbus_data_t));
571
572         out_var = g_variant_new_from_data((const GVariantType *)"ay",
573                         info->data, info->len,
574                         TRUE, NULL, NULL);
575
576         param = g_variant_new("(iv)", result, out_var);
577         _bt_send_event(BT_ADAPTER_EVENT,
578                 BLUETOOTH_EVENT_DISABLED_BATTERY_DATA,
579                 param);
580
581         g_slist_free_full(data->atm_list, g_free);
582         g_free(data);
583         g_array_free(info, TRUE);
584         BT_DBG("-");
585 }
586
587 void _bt_bm_event_handler(gpointer data)
588 {
589         bt_service_oal_event_data_t *oal_event = data;
590         int event_type = oal_event->type;
591
592         switch(event_type) {
593         case OAL_EVENT_ADAPTER_ENABLED:
594                 BT_DBG("Handling Adapter Enabled");
595                 if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE)
596                         BT_ERR("Fail to start session time");
597                 break;
598         case OAL_EVENT_ADAPTER_DISABLED:
599                 BT_DBG("Handling Adapter Disabled");
600                 if (is_session_started == TRUE) {
601                         __bt_notify_battery_data();
602                         __bt_stop_session_time();
603                 }
604                 break;
605         case OAL_EVENT_ADAPTER_INQUIRY_STARTED:
606         case OAL_EVENT_BLE_DISCOVERY_STARTED:
607                 BT_DBG("Handling Adapter Discovery Start");
608                 _bt_start_scan_time();
609                 break;
610         case OAL_EVENT_ADAPTER_INQUIRY_FINISHED:
611                 /* Remove the regacy scan app */
612                 _bt_bm_remove_scan_app(SCAN_REGACY, 0, 0);
613
614                 _bt_stop_scan_time();
615                 break;
616         case OAL_EVENT_BLE_DISCOVERY_STOPPED:
617                 BT_DBG("Handling Adapter Discovery Stop");
618                 _bt_stop_scan_time();
619                 break;
620         case OAL_EVENT_SOCKET_OUTGOING_CONNECTED:
621         case OAL_EVENT_GATTC_CONNECTION_COMPLETED:
622                 BT_DBG("Handling Connection Start");
623                 _bt_start_connect_time();
624                 break;
625         case OAL_EVENT_SOCKET_DISCONNECTED:
626         case OAL_EVENT_GATTC_DISCONNECTION_COMPLETED:
627                 BT_DBG("Handling Connection Stop");
628                 _bt_stop_connect_time();
629                 break;
630         default:
631                 break;
632         }
633 }