1 /*
2 * Copyright 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.cc
20 *
21 * Description: Contains data structures and functions for keeping track of
22 * socket usage per app UID.
23 *
24 ******************************************************************************/
25 #include "btif_uid.h"
26
27 #include <mutex>
28
29 #include "osi/include/allocator.h"
30
31 static std::mutex set_lock;
32
33 typedef struct uid_set_node_t {
34 struct uid_set_node_t* next;
35 bt_uid_traffic_t data;
36 } uid_set_node_t;
37
38 typedef struct uid_set_t {
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 = (uid_set_t*)osi_calloc(sizeof(uid_set_t));
44 return set;
45 }
46
uid_set_destroy(uid_set_t * set)47 void uid_set_destroy(uid_set_t* set) {
48 std::unique_lock<std::mutex> guard(set_lock);
49 uid_set_node_t* node = set->head;
50 while (node) {
51 uid_set_node_t* temp = node;
52 node = node->next;
53 osi_free(temp);
54 }
55 set->head = NULL;
56 osi_free(set);
57 }
58
59 // Lock in uid_set_t must be held.
uid_set_find_or_create_node(uid_set_t * set,int32_t app_uid)60 static uid_set_node_t* uid_set_find_or_create_node(uid_set_t* set, int32_t app_uid) {
61 uid_set_node_t* node = set->head;
62 while (node && node->data.app_uid != app_uid) {
63 node = node->next;
64 }
65
66 if (!node) {
67 node = (uid_set_node_t*)osi_calloc(sizeof(uid_set_node_t));
68 node->data.app_uid = app_uid;
69 node->next = set->head;
70 set->head = node;
71 }
72 return node;
73 }
74
uid_set_add_tx(uid_set_t * set,int32_t app_uid,uint64_t bytes)75 void uid_set_add_tx(uid_set_t* set, int32_t app_uid, uint64_t bytes) {
76 if (set == nullptr || app_uid == -1 || bytes == 0) {
77 return;
78 }
79
80 std::unique_lock<std::mutex> guard(set_lock);
81 uid_set_node_t* node = uid_set_find_or_create_node(set, app_uid);
82 node->data.tx_bytes += bytes;
83 }
84
uid_set_add_rx(uid_set_t * set,int32_t app_uid,uint64_t bytes)85 void uid_set_add_rx(uid_set_t* set, int32_t app_uid, uint64_t bytes) {
86 if (set == nullptr || app_uid == -1 || bytes == 0) {
87 return;
88 }
89
90 std::unique_lock<std::mutex> guard(set_lock);
91 uid_set_node_t* node = uid_set_find_or_create_node(set, app_uid);
92 node->data.rx_bytes += bytes;
93 }
94
uid_set_read_and_clear(uid_set_t * set)95 bt_uid_traffic_t* uid_set_read_and_clear(uid_set_t* set) {
96 std::unique_lock<std::mutex> guard(set_lock);
97
98 // Find the length
99 size_t len = 0;
100 uid_set_node_t* node = set->head;
101 while (node) {
102 len++;
103 node = node->next;
104 }
105
106 // Allocate an array of elements + 1, to signify the end with app_uid set to
107 // -1.
108 bt_uid_traffic_t* result = (bt_uid_traffic_t*)osi_calloc(sizeof(bt_uid_traffic_t) * (len + 1));
109
110 bt_uid_traffic_t* data = result;
111 node = set->head;
112 while (node) {
113 // Copy the data.
114 *data = node->data;
115 data++;
116
117 // Clear the counters.
118 node->data.rx_bytes = 0;
119 node->data.tx_bytes = 0;
120 node = node->next;
121 }
122
123 // Mark the last entry
124 data->app_uid = -1;
125
126 return result;
127 }
128