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