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