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