1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /************************************************************************************
18 *
19 * Filename: btif_uid.c
20 *
21 * Description: Contains data structures and functions for keeping track of
22 * socket usage per app UID.
23 *
24 ***********************************************************************************/
25 #define LOG_TAG "bt_uid_set"
26 #include "bt_common.h"
27 #include "btif_uid.h"
28
29 #include <log/log.h>
30 #include <pthread.h>
31
32 typedef struct uid_set_node_t {
33 struct uid_set_node_t* next;
34 bt_uid_traffic_t data;
35 } uid_set_node_t;
36
37 typedef struct uid_set_t {
38 pthread_mutex_t lock;
39 uid_set_node_t* head;
40 } uid_set_t;
41
uid_set_create(void)42 uid_set_t* uid_set_create(void) {
43 uid_set_t* set = osi_calloc(sizeof(uid_set_t));
44 pthread_mutex_init(&set->lock, NULL);
45 return set;
46 }
47
uid_set_destroy(uid_set_t * set)48 void uid_set_destroy(uid_set_t* set) {
49 pthread_mutex_lock(&set->lock);
50 uid_set_node_t* node = set->head;
51 while (node) {
52 uid_set_node_t* temp = node;
53 node = node->next;
54 osi_free(temp);
55 }
56 set->head = NULL;
57 pthread_mutex_unlock(&set->lock);
58 pthread_mutex_destroy(&set->lock);
59 osi_free(set);
60 }
61
62 // Lock in uid_set_t must be held.
uid_set_find_or_create_node(uid_set_t * set,int32_t app_uid)63 static uid_set_node_t* uid_set_find_or_create_node(uid_set_t* set, int32_t app_uid) {
64 uid_set_node_t* node = set->head;
65 while (node && node->data.app_uid != app_uid) {
66 node = node->next;
67 }
68
69 if (!node) {
70 node = osi_calloc(sizeof(uid_set_node_t));
71 node->data.app_uid = app_uid;
72 node->next = set->head;
73 set->head = node;
74 }
75 return node;
76 }
77
uid_set_add_tx(uid_set_t * set,int32_t app_uid,uint64_t bytes)78 void uid_set_add_tx(uid_set_t* set, int32_t app_uid, uint64_t bytes) {
79 if (app_uid == -1 || bytes == 0) {
80 return;
81 }
82
83 pthread_mutex_lock(&set->lock);
84 uid_set_node_t* node = uid_set_find_or_create_node(set, app_uid);
85 node->data.tx_bytes += bytes;
86 pthread_mutex_unlock(&set->lock);
87 }
88
uid_set_add_rx(uid_set_t * set,int32_t app_uid,uint64_t bytes)89 void uid_set_add_rx(uid_set_t* set, int32_t app_uid, uint64_t bytes) {
90 if (app_uid == -1 || bytes == 0) {
91 return;
92 }
93
94 pthread_mutex_lock(&set->lock);
95 uid_set_node_t* node = uid_set_find_or_create_node(set, app_uid);
96 node->data.rx_bytes += bytes;
97 pthread_mutex_unlock(&set->lock);
98 }
99
uid_set_read_and_clear(uid_set_t * set)100 bt_uid_traffic_t* uid_set_read_and_clear(uid_set_t* set) {
101 pthread_mutex_lock(&set->lock);
102
103 // Find the length
104 size_t len = 0;
105 uid_set_node_t* node = set->head;
106 while (node) {
107 len++;
108 node = node->next;
109 }
110
111 // Allocate an array of elements + 1, to signify the end with app_uid set to -1.
112 bt_uid_traffic_t* result = osi_calloc(sizeof(bt_uid_traffic_t) * (len + 1));
113
114 bt_uid_traffic_t* data = result;
115 node = set->head;
116 while (node) {
117 // Copy the data.
118 *data = node->data;
119 data++;
120
121 // Clear the counters.
122 node->data.rx_bytes = 0;
123 node->data.tx_bytes = 0;
124 node = node->next;
125 }
126
127 // Mark the last entry
128 data->app_uid = -1;
129
130 pthread_mutex_unlock(&set->lock);
131
132 return result;
133 }
134