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