#include <string.h>
#include <dlog.h>
#include <time.h>
-
+#include <sys/time.h>
+#include <vconf.h>
#include <oal-event.h>
#include "bt-service-battery-monitor.h"
#include "bt-service-common.h"
+#include "bt-service-event.h"
+#include "bt-service-core-adapter.h"
+
+/* Avoid the build error related to vconf.h's dependency */
+#ifndef VCONFKEY_BATTERY_MONITOR_STATUS
+#define VCONFKEY_BATTERY_MONITOR_STATUS "db/bluetooth/bmstatus"
+#endif
+
+/* 20 minutes */
+#define BT_BM_SESSION_TIMEOUT 1200
-static time_t scan_start = 0;
-static time_t connect_start = 0;
+static struct timeval scan_start;
+static struct timeval connect_start;
+static struct timeval app_scan_base;
static int scan_cnt = 0;
static int connect_cnt = 0;
static gboolean is_session_started = FALSE;
+static guint session_timer = 0;
+
+static GSList *scan_app_list = NULL;
typedef struct {
int type;
_bt_battery_data_t *current_session_data = NULL;
+static void __bt_bm_add_prev_time(uint32_t scan_time);
+static int __bt_start_session_time(void);
+static void __bt_stop_session_time(void);
+static bool __bt_bm_session_timeout_cb(void);
+
+uint32_t static __bt_dm_time_diff_msec(struct timeval prev, struct timeval cur)
+{
+ return (uint32_t)((cur.tv_sec - prev.tv_sec) * 1000.0f + (cur.tv_usec - prev.tv_usec) / 1000.0f);
+}
+
static void __bt_display_session_data()
{
BT_DBG("Displaying session data...");
+
+ if (current_session_data == NULL) {
+ BT_ERR("Session in progress but data structure is not initialized");
+ return;
+ }
+
BT_DBG("session_start_time = %ld", current_session_data->session_start_time);
BT_DBG("session_end_time = %ld", current_session_data->session_end_time);
BT_DBG("session_scan_time = %d", current_session_data->session_scan_time);
/*After reading data, the function resets it*/
int _bt_bm_read_data(_bt_battery_data_t *data)
{
+ struct timeval cur_time;
+ uint32_t tx_time = 0;
+ uint32_t rx_time = 0;
+ uint32_t idle_time = 0;
+ uint32_t energy_used = 0;
+ uint16_t scan_time_per_app = 0;
+ int scan_app_cnt = 0;
+
BT_DBG("");
if (data == NULL) {
return BLUETOOTH_ERROR_NO_DATA;
}
+ if (_bt_get_energy_info(&tx_time, &rx_time,
+ &idle_time, &energy_used) != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("Fail to get energy info");
+ return BLUETOOTH_ERROR_NOT_SUPPORT;
+ }
+
+ if (is_session_started == FALSE) {
+ if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("Fail to start session time");
+ return BLUETOOTH_ERROR_NOT_SUPPORT;
+ }
+ }
+
+ if (current_session_data == NULL) {
+ BT_ERR("Session in progress but data structure is not initialized");
+ return BLUETOOTH_ERROR_INTERNAL;
+ }
+
+ gettimeofday(&cur_time, 0);
+
+ data->tx_time = tx_time;
+ data->rx_time = rx_time;
+ data->idle_time = idle_time;
+
data->session_start_time = current_session_data->session_start_time;
data->session_end_time = time(NULL);
current_session_data->session_start_time = time(NULL);
data->session_scan_time = current_session_data->session_scan_time;
if (scan_cnt) {
- data->session_scan_time += (uint16_t) (time(NULL) - scan_start);
- scan_start = time(NULL);
+ data->session_scan_time += (uint16_t)__bt_dm_time_diff_msec(scan_start, cur_time);
+ gettimeofday(&scan_start, 0);
}
+ current_session_data->session_scan_time = 0;
data->session_connected_time = current_session_data->session_connected_time;
if (connect_cnt) {
- data->session_connected_time += (uint16_t) (time(NULL) - connect_start);
- connect_start = time(NULL);
+ data->session_connected_time += (uint16_t)__bt_dm_time_diff_msec(connect_start, cur_time);
+ gettimeofday(&connect_start, 0);
}
+ current_session_data->session_connected_time = 0;
- data->atm_list = current_session_data->atm_list;
- if (data->atm_list == NULL) {
- BT_DBG("No data transaction in this session");
- return BLUETOOTH_ERROR_NONE;
+ scan_app_cnt = g_slist_length(scan_app_list);
+
+ if (scan_app_cnt > 0) {
+ scan_time_per_app = (uint32_t)__bt_dm_time_diff_msec(app_scan_base, cur_time) / scan_app_cnt;
+ __bt_bm_add_prev_time(scan_time_per_app);
}
+ gettimeofday(&app_scan_base, 0);
+
+ /* Note that this is a "shallow" copy. The pointers are copied but the actual data isn't. */
+ data->atm_list = g_slist_copy(current_session_data->atm_list);
+ current_session_data->atm_list = NULL;
+
BT_DBG("App-wise data transaction details");
for (GSList *l = data->atm_list; l != NULL; l = g_slist_next(l)) {
_bt_battery_app_data_t *t = (_bt_battery_app_data_t *)(l->data);
- BT_DBG("%ld %ld %d %d", (long int)(t->uid), (long int)(t->pid), t->rx_bytes, t->tx_bytes);
+ BT_DBG("%ld %ld %d %d %u", (long int)(t->uid), (long int)(t->pid), t->rx_bytes, t->tx_bytes, t->time);
}
- current_session_data->atm_list = NULL;
+ /* Reset the session timer */
+ if (session_timer)
+ g_source_remove(session_timer);
+
+ session_timer = g_timeout_add_seconds(BT_BM_SESSION_TIMEOUT,
+ (GSourceFunc)__bt_bm_session_timeout_cb, NULL);
+
return BLUETOOTH_ERROR_NONE;
}
return NULL;
}
-void _bt_bm_add_transaction_details(uid_t uid, pid_t pid, int size, data_transaction_type_e type)
+void _bt_bm_add_transaction_details(uid_t uid, pid_t pid, int value, data_transaction_type_e type)
{
+ if (is_session_started == FALSE)
+ __bt_start_session_time();
+
if (current_session_data == NULL) {
- BT_ERR("Session in progress but data structure is not initialized"); //error handling
+ BT_ERR("Session in progress but data structure is not initialized");
return;
}
GSList *t = is_app_present(current_session_data->atm_list, uid, pid);
app_data->uid = uid;
app_data->pid = pid;
if (type == RX_DATA)
- app_data->rx_bytes = size;
+ app_data->rx_bytes = value;
+ else if (type == TX_DATA)
+ app_data->tx_bytes = value;
else
- app_data->tx_bytes = size;
+ app_data->time = value;
current_session_data->atm_list = g_slist_append(current_session_data->atm_list, app_data);
}
else {
BT_INFO("Match found, updating existing node...");
app_data = (_bt_battery_app_data_t *)(t->data);
if (type == RX_DATA)
- app_data->rx_bytes += size;
+ app_data->rx_bytes += value;
+ else if (type == TX_DATA)
+ app_data->tx_bytes += value;
else
- app_data->tx_bytes += size;
+ app_data->time += value;
}
}
-void _bt_start_session_time()
+static bool __bt_bm_session_timeout_cb(void)
{
- if (is_session_started == FALSE) {
- BT_DBG("Bt session starting...");
- is_session_started = TRUE;
- current_session_data = g_malloc0(sizeof(_bt_battery_data_t));
- current_session_data->session_start_time = time(NULL);
- current_session_data->session_end_time = 0;
- current_session_data->session_connected_time = 0;
- current_session_data->session_scan_time = 0;
- current_session_data->atm_list = NULL;
- } else {
- if (current_session_data == NULL)
- BT_ERR("Session in progress but data structure is not initialized"); //error handling
- else
- BT_DBG("Bt session already in progress... Returning");
+ BT_INFO("No data read calls during the time.");
+
+ __bt_stop_session_time();
+
+ return FALSE;
+}
+
+
+static int __bt_start_session_time(void)
+{
+ int state = 0;
+
+ if (is_session_started == TRUE) {
+ BT_ERR("Session is already started");
+ return BLUETOOTH_ERROR_ALREADY_INITIALIZED;
+ }
+
+ if (vconf_get_bool(VCONFKEY_BATTERY_MONITOR_STATUS, &state) != 0) {
+ BT_ERR("vconf_get_bool failed");
+ return BLUETOOTH_ERROR_INTERNAL;
}
+
+ if (state == 0) {
+ BT_ERR("Battery is not monitoring in now");
+ return BLUETOOTH_ERROR_NOT_SUPPORT;
+ }
+
+ BT_DBG("Bt session starting...");
+ is_session_started = TRUE;
+
+ if (current_session_data == NULL)
+ current_session_data = g_malloc0(sizeof(_bt_battery_data_t));
+
+ current_session_data->session_start_time = time(NULL);
+ current_session_data->session_end_time = 0;
+ current_session_data->session_connected_time = 0;
+ current_session_data->session_scan_time = 0;
+ current_session_data->atm_list = NULL;
+
+ /* After starting session if there is no read data call during the specific time,
+ * stop the session time to avoid the exceed of session data.
+ */
+ if (session_timer)
+ g_source_remove(session_timer);
+
+ session_timer = g_timeout_add_seconds(BT_BM_SESSION_TIMEOUT,
+ (GSourceFunc)__bt_bm_session_timeout_cb, NULL);
+
+ return BLUETOOTH_ERROR_NONE;
}
-void _bt_stop_session_time()
+static void __bt_stop_session_time(void)
{
+ if (session_timer) {
+ g_source_remove(session_timer);
+ session_timer = 0;
+ }
+
if (is_session_started == FALSE) {
- BT_DBG("BT session not in progress... Returning"); //error handling
+ BT_DBG("BT session not in progress... Returning");
return;
}
+
+ __bt_display_session_data();
+
BT_DBG("Bt session ending...");
is_session_started = FALSE;
- current_session_data->session_end_time = time(NULL);
- __bt_display_session_data();
+
+ if (current_session_data != NULL) {
+ g_slist_free_full(current_session_data->atm_list, g_free);
+ g_free(current_session_data);
+ current_session_data = NULL;
+ }
+}
+
+/* 1 app can operate the regacy and ble scan at the same time */
+static GSList* __is_scan_app_present(GSList *start, bt_bm_scan_type_e type, uid_t uid, pid_t pid)
+{
+ GSList *l = NULL;
+ bt_bm_scan_info_t *t;
+
+ for (l = start; l != NULL; l = g_slist_next(l)) {
+ t = (bt_bm_scan_info_t *)(l->data);
+
+ /* Find the regacy scan app for Inquiry stop */
+ if (type == SCAN_REGACY && t->type != SCAN_LE) {
+ BT_INFO("app already exist");
+ return l;
+ }
+
+ if (t->uid == uid && t->pid == pid) {
+ BT_INFO("app already exist");
+ return l;
+ }
+ }
+ return NULL;
+}
+
+static void __bt_bm_add_prev_time(uint32_t scan_time)
+{
+ GSList *l = NULL;
+ bt_bm_scan_info_t *t;
+
+ for (l = scan_app_list; l != NULL; l = g_slist_next(l)) {
+ t = (bt_bm_scan_info_t *)(l->data);
+ _bt_bm_add_transaction_details(t->uid, t->pid, scan_time, TIME_DATA);
+ }
+}
+
+/* 1 regacy scan is only allowed in the platform
+ * BLE scan is allowed for many apps
+*/
+/* When a app is added, we should add and reset the time. */
+void _bt_bm_add_scan_app(bt_bm_scan_type_e type, uid_t uid, pid_t pid)
+{
+ bt_bm_scan_info_t *scan_info = NULL;
+ GSList *app_list = NULL;
+ int app_cnt = 0;
+ uint32_t scan_time_per_app = 0;
+
+ BT_DBG("Scan type: %d", type);
+
+ if (scan_app_list) {
+ app_cnt = g_slist_length(scan_app_list);
+ app_list = __is_scan_app_present(scan_app_list, SCAN_BOTH, uid, pid);
+ }
+
+ if (app_list) {
+ /* app try to scan both Regacy and LE */
+ scan_info = (bt_bm_scan_info_t *)(app_list->data);
+
+ if (scan_info == NULL) {
+ BT_ERR("Can't get the scan info");
+ return;
+ }
+
+ BT_DBG("Previous type: %d", scan_info->type);
+
+ if (scan_info->type == type) {
+ BT_ERR("Same scan type is doing");
+ return;
+ }
+
+ scan_info->type = SCAN_BOTH;
+ } else {
+ scan_info = g_malloc0(sizeof(bt_bm_scan_info_t));
+ scan_info->uid = uid;
+ scan_info->pid = pid;
+ scan_info->type = type;
+
+ if (app_cnt > 0) {
+ struct timeval cur_time;
+
+ gettimeofday(&cur_time, 0);
+
+ scan_time_per_app = (uint32_t)(__bt_dm_time_diff_msec(app_scan_base, cur_time)) / app_cnt;
+ __bt_bm_add_prev_time(scan_time_per_app);
+
+ /* Update the base time */
+ gettimeofday(&app_scan_base, 0);
+ }
+
+ scan_app_list = g_slist_append(scan_app_list, scan_info);
+ }
+}
+
+/* When a app is removed, we should add and reset the time. */
+void _bt_bm_remove_scan_app(bt_bm_scan_type_e type, uid_t uid, pid_t pid)
+{
+ bt_bm_scan_info_t *scan_info = NULL;
+ GSList *app_list = NULL;
+ int app_cnt = 0;
+ uint32_t scan_time_per_app = 0;
+
+ BT_DBG("Scan type: %d", type);
+
+ if (scan_app_list == NULL) {
+ BT_ERR("No scan app in list");
+ return;
+ }
+
+ app_cnt = g_slist_length(scan_app_list);
+
+ if (app_cnt == 0) {
+ BT_ERR("No scan app in list");
+ return;
+ }
+
+ app_list = __is_scan_app_present(scan_app_list, type, uid, pid);
+
+ if (app_list) {
+ struct timeval cur_time;
+
+ scan_info = (bt_bm_scan_info_t *)(app_list->data);
+
+ if (scan_info->type == SCAN_BOTH) {
+ scan_info->type = (scan_info->type == SCAN_REGACY) ? SCAN_LE : SCAN_REGACY;
+ return;
+ }
+
+ gettimeofday(&cur_time, 0);
+
+ scan_time_per_app = (uint32_t)(__bt_dm_time_diff_msec(app_scan_base, cur_time)) / app_cnt;
+ __bt_bm_add_prev_time(scan_time_per_app);
+
+ /* Update the base time */
+ gettimeofday(&app_scan_base, 0);
+
+ scan_app_list = g_slist_remove(scan_app_list, scan_info);
+
+ g_free(scan_info);
+ }
}
void _bt_start_scan_time()
{
+ if (is_session_started == FALSE) {
+ if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("Fail to start session time");
+ return;
+ }
+ }
+
if (current_session_data != NULL) {
if (scan_cnt == 0) {
BT_DBG("Starting scan time");
- scan_start = time(NULL);
+ gettimeofday(&scan_start, 0);
+ gettimeofday(&app_scan_base, 0);
}
scan_cnt++;
} else {
- BT_ERR("Data structure uninitialized"); //error handling
+ BT_ERR("Data structure uninitialized");
}
}
void _bt_stop_scan_time()
{
+ if (is_session_started == FALSE) {
+ if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("Fail to start session time");
+ return;
+ }
+ }
+
if (scan_cnt == 0 || current_session_data == NULL)
- BT_ERR("Error encountered, returning..."); //error handling
+ BT_ERR("Error encountered, returning...");
else {
scan_cnt--;
if(scan_cnt == 0) {
- time_t temp = time(NULL);
- current_session_data->session_scan_time += (uint16_t) (temp - scan_start);
+ struct timeval cur_time;
+
+ gettimeofday(&cur_time, 0);
+ current_session_data->session_scan_time += (uint16_t)(__bt_dm_time_diff_msec(scan_start, cur_time));
+ gettimeofday(&scan_start, 0);
+ gettimeofday(&app_scan_base, 0);
}
}
}
void _bt_start_connect_time()
{
+ if (is_session_started == FALSE) {
+ if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("Fail to start session time");
+ return;
+ }
+ }
+
if (current_session_data != NULL) {
if (connect_cnt == 0) {
BT_DBG("Starting connect time");
- connect_start = time(NULL);
+ gettimeofday(&connect_start, 0);
}
connect_cnt++;
}
else {
- BT_ERR("Data structure uninitialized"); //error handling
+ BT_ERR("Data structure uninitialized");
}
}
void _bt_stop_connect_time()
{
- if(connect_cnt == 0 || current_session_data == NULL) {
- BT_ERR("Error encountered, returning..."); //error handling
+ if (is_session_started == FALSE) {
+ if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("Fail to start session time");
+ return;
+ }
}
- else {
+
+ if(connect_cnt == 0 || current_session_data == NULL) {
+ BT_ERR("Error encountered, returning...");
+ } else {
connect_cnt--;
if(connect_cnt == 0) {
- time_t temp = time(NULL);
- current_session_data->session_connected_time += (uint16_t) (temp - connect_start);
+ struct timeval cur_time;
+
+ gettimeofday(&cur_time, 0);
+ current_session_data->session_connected_time += (uint16_t)(__bt_dm_time_diff_msec(connect_start, cur_time));
}
}
}
+static void __bt_notify_battery_data(void)
+{
+ BT_INFO("+");
+ _bt_battery_data_t *data = NULL;
+ int result;
+
+ data = g_new0(_bt_battery_data_t, 1);
+ result = _bt_bm_read_data(data);
+ GVariant *out_var = NULL, *param = NULL;
+ GArray *info = NULL;
+
+ if (result != BLUETOOTH_ERROR_NONE) {
+ BT_ERR("Battery data not collected");
+ g_free(data);
+ return;
+ }
+
+ bt_battery_dbus_data_t dbus_data;
+ memset(&dbus_data, 0, sizeof(bt_battery_dbus_data_t));
+ dbus_data.session_start_time = data->session_start_time;
+ dbus_data.session_end_time = data->session_end_time;
+ dbus_data.session_scan_time = data->session_scan_time;
+ dbus_data.session_connected_time = data->session_connected_time;
+ dbus_data.tx_time = data->tx_time;
+ dbus_data.rx_time = data->rx_time;
+ dbus_data.idle_time = data->idle_time;
+
+ /*Populating app data*/
+ int n = 0;
+ for (GSList *l = data->atm_list; l != NULL; l = g_slist_next(l)) {
+ bt_battery_app_data *t = (bt_battery_app_data *)(l->data);
+ memcpy(&dbus_data.app_data[n], t, sizeof(bt_battery_app_data));
+ n++;
+ }
+ dbus_data.num_app = n;
+
+ info = g_array_new(FALSE, FALSE, sizeof(gchar));
+ g_array_append_vals(info, &dbus_data, sizeof(bt_battery_dbus_data_t));
+
+ out_var = g_variant_new_from_data((const GVariantType *)"ay",
+ info->data, info->len,
+ TRUE, NULL, NULL);
+
+ param = g_variant_new("(iv)", result, out_var);
+ _bt_send_event(BT_ADAPTER_EVENT,
+ BLUETOOTH_EVENT_DISABLED_BATTERY_DATA,
+ param);
+
+ g_slist_free_full(data->atm_list, g_free);
+ g_free(data);
+ g_array_free(info, TRUE);
+ BT_INFO("-");
+}
+
void _bt_bm_event_handler(gpointer data)
{
bt_service_oal_event_data_t *oal_event = data;
switch(event_type) {
case OAL_EVENT_ADAPTER_ENABLED:
BT_DBG("Handling Adapter Enabled");
- _bt_start_session_time();
+ if (__bt_start_session_time() != BLUETOOTH_ERROR_NONE)
+ BT_ERR("Fail to start session time");
break;
case OAL_EVENT_ADAPTER_DISABLED:
BT_DBG("Handling Adapter Disabled");
- _bt_stop_session_time();
+ if (is_session_started == TRUE) {
+ __bt_notify_battery_data();
+ __bt_stop_session_time();
+ }
break;
case OAL_EVENT_ADAPTER_INQUIRY_STARTED:
case OAL_EVENT_BLE_DISCOVERY_STARTED:
_bt_start_scan_time();
break;
case OAL_EVENT_ADAPTER_INQUIRY_FINISHED:
+ /* Remove the regacy scan app */
+ _bt_bm_remove_scan_app(SCAN_REGACY, 0, 0);
+
+ _bt_stop_scan_time();
+ break;
case OAL_EVENT_BLE_DISCOVERY_STOPPED:
BT_DBG("Handling Adapter Discovery Stop");
_bt_stop_scan_time();