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 <mutex>
26 
27 #include "bt_common.h"
28 #include "btif_uid.h"
29 
30 static std::mutex set_lock;
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   uid_set_node_t* head;
39 } uid_set_t;
40 
uid_set_create(void)41 uid_set_t* uid_set_create(void) {
42   uid_set_t* set = (uid_set_t*)osi_calloc(sizeof(uid_set_t));
43   return set;
44 }
45 
uid_set_destroy(uid_set_t * set)46 void uid_set_destroy(uid_set_t* set) {
47   std::unique_lock<std::mutex> guard(set_lock);
48   uid_set_node_t* node = set->head;
49   while (node) {
50     uid_set_node_t* temp = node;
51     node = node->next;
52     osi_free(temp);
53   }
54   set->head = NULL;
55   osi_free(set);
56 }
57 
58 // Lock in uid_set_t must be held.
uid_set_find_or_create_node(uid_set_t * set,int32_t app_uid)59 static uid_set_node_t* uid_set_find_or_create_node(uid_set_t* set,
60                                                    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 (app_uid == -1 || bytes == 0) return;
77 
78   std::unique_lock<std::mutex> guard(set_lock);
79   uid_set_node_t* node = uid_set_find_or_create_node(set, app_uid);
80   node->data.tx_bytes += bytes;
81 }
82 
uid_set_add_rx(uid_set_t * set,int32_t app_uid,uint64_t bytes)83 void uid_set_add_rx(uid_set_t* set, int32_t app_uid, uint64_t bytes) {
84   if (app_uid == -1 || bytes == 0) return;
85 
86   std::unique_lock<std::mutex> guard(set_lock);
87   uid_set_node_t* node = uid_set_find_or_create_node(set, app_uid);
88   node->data.rx_bytes += bytes;
89 }
90 
uid_set_read_and_clear(uid_set_t * set)91 bt_uid_traffic_t* uid_set_read_and_clear(uid_set_t* set) {
92   std::unique_lock<std::mutex> guard(set_lock);
93 
94   // Find the length
95   size_t len = 0;
96   uid_set_node_t* node = set->head;
97   while (node) {
98     len++;
99     node = node->next;
100   }
101 
102   // Allocate an array of elements + 1, to signify the end with app_uid set to
103   // -1.
104   bt_uid_traffic_t* result =
105       (bt_uid_traffic_t*)osi_calloc(sizeof(bt_uid_traffic_t) * (len + 1));
106 
107   bt_uid_traffic_t* data = result;
108   node = set->head;
109   while (node) {
110     // Copy the data.
111     *data = node->data;
112     data++;
113 
114     // Clear the counters.
115     node->data.rx_bytes = 0;
116     node->data.tx_bytes = 0;
117     node = node->next;
118   }
119 
120   // Mark the last entry
121   data->app_uid = -1;
122 
123   return result;
124 }
125