| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /************************************************************************************ |
| * |
| * Filename: btif_uid.c |
| * |
| * Description: Contains data structures and functions for keeping track of |
| * socket usage per app UID. |
| * |
| ***********************************************************************************/ |
| #define LOG_TAG "bt_uid_set" |
| #include "bt_common.h" |
| #include "btif_uid.h" |
| |
| #include <log/log.h> |
| #include <pthread.h> |
| |
| typedef struct uid_set_node_t { |
| struct uid_set_node_t* next; |
| bt_uid_traffic_t data; |
| } uid_set_node_t; |
| |
| typedef struct uid_set_t { |
| pthread_mutex_t lock; |
| uid_set_node_t* head; |
| } uid_set_t; |
| |
| uid_set_t* uid_set_create(void) { |
| uid_set_t* set = (uid_set_t*)osi_calloc(sizeof(uid_set_t)); |
| pthread_mutex_init(&set->lock, NULL); |
| return set; |
| } |
| |
| void uid_set_destroy(uid_set_t* set) { |
| pthread_mutex_lock(&set->lock); |
| uid_set_node_t* node = set->head; |
| while (node) { |
| uid_set_node_t* temp = node; |
| node = node->next; |
| osi_free(temp); |
| } |
| set->head = NULL; |
| pthread_mutex_unlock(&set->lock); |
| pthread_mutex_destroy(&set->lock); |
| osi_free(set); |
| } |
| |
| // Lock in uid_set_t must be held. |
| static uid_set_node_t* uid_set_find_or_create_node(uid_set_t* set, int32_t app_uid) { |
| uid_set_node_t* node = set->head; |
| while (node && node->data.app_uid != app_uid) { |
| node = node->next; |
| } |
| |
| if (!node) { |
| node = (uid_set_node_t*)osi_calloc(sizeof(uid_set_node_t)); |
| node->data.app_uid = app_uid; |
| node->next = set->head; |
| set->head = node; |
| } |
| return node; |
| } |
| |
| void uid_set_add_tx(uid_set_t* set, int32_t app_uid, uint64_t bytes) { |
| if (app_uid == -1 || bytes == 0) { |
| return; |
| } |
| |
| pthread_mutex_lock(&set->lock); |
| uid_set_node_t* node = uid_set_find_or_create_node(set, app_uid); |
| node->data.tx_bytes += bytes; |
| pthread_mutex_unlock(&set->lock); |
| } |
| |
| void uid_set_add_rx(uid_set_t* set, int32_t app_uid, uint64_t bytes) { |
| if (app_uid == -1 || bytes == 0) { |
| return; |
| } |
| |
| pthread_mutex_lock(&set->lock); |
| uid_set_node_t* node = uid_set_find_or_create_node(set, app_uid); |
| node->data.rx_bytes += bytes; |
| pthread_mutex_unlock(&set->lock); |
| } |
| |
| bt_uid_traffic_t* uid_set_read_and_clear(uid_set_t* set) { |
| pthread_mutex_lock(&set->lock); |
| |
| // Find the length |
| size_t len = 0; |
| uid_set_node_t* node = set->head; |
| while (node) { |
| len++; |
| node = node->next; |
| } |
| |
| // Allocate an array of elements + 1, to signify the end with app_uid set to -1. |
| bt_uid_traffic_t* result = (bt_uid_traffic_t*)osi_calloc(sizeof(bt_uid_traffic_t) * (len + 1)); |
| |
| bt_uid_traffic_t* data = result; |
| node = set->head; |
| while (node) { |
| // Copy the data. |
| *data = node->data; |
| data++; |
| |
| // Clear the counters. |
| node->data.rx_bytes = 0; |
| node->data.tx_bytes = 0; |
| node = node->next; |
| } |
| |
| // Mark the last entry |
| data->app_uid = -1; |
| |
| pthread_mutex_unlock(&set->lock); |
| |
| return result; |
| } |