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.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
30typedef struct uid_set_node_t {
31  struct uid_set_node_t* next;
32  bt_uid_traffic_t data;
33} uid_set_node_t;
34
35typedef struct uid_set_t {
36  std::mutex lock;
37  uid_set_node_t* head;
38} uid_set_t;
39
40uid_set_t* uid_set_create(void) {
41  uid_set_t* set = (uid_set_t*)osi_calloc(sizeof(uid_set_t));
42  return set;
43}
44
45void uid_set_destroy(uid_set_t* set) {
46  std::unique_lock<std::mutex> lock(set->lock);
47  uid_set_node_t* node = set->head;
48  while (node) {
49    uid_set_node_t* temp = node;
50    node = node->next;
51    osi_free(temp);
52  }
53  set->head = NULL;
54  osi_free(set);
55}
56
57// Lock in uid_set_t must be held.
58static uid_set_node_t* uid_set_find_or_create_node(uid_set_t* set,
59                                                   int32_t app_uid) {
60  uid_set_node_t* node = set->head;
61  while (node && node->data.app_uid != app_uid) {
62    node = node->next;
63  }
64
65  if (!node) {
66    node = (uid_set_node_t*)osi_calloc(sizeof(uid_set_node_t));
67    node->data.app_uid = app_uid;
68    node->next = set->head;
69    set->head = node;
70  }
71  return node;
72}
73
74void uid_set_add_tx(uid_set_t* set, int32_t app_uid, uint64_t bytes) {
75  if (app_uid == -1 || bytes == 0) return;
76
77  std::unique_lock<std::mutex> lock(set->lock);
78  uid_set_node_t* node = uid_set_find_or_create_node(set, app_uid);
79  node->data.tx_bytes += bytes;
80}
81
82void uid_set_add_rx(uid_set_t* set, int32_t app_uid, uint64_t bytes) {
83  if (app_uid == -1 || bytes == 0) return;
84
85  std::unique_lock<std::mutex> lock(set->lock);
86  uid_set_node_t* node = uid_set_find_or_create_node(set, app_uid);
87  node->data.rx_bytes += bytes;
88}
89
90bt_uid_traffic_t* uid_set_read_and_clear(uid_set_t* set) {
91  std::unique_lock<std::mutex> lock(set->lock);
92
93  // Find the length
94  size_t len = 0;
95  uid_set_node_t* node = set->head;
96  while (node) {
97    len++;
98    node = node->next;
99  }
100
101  // Allocate an array of elements + 1, to signify the end with app_uid set to
102  // -1.
103  bt_uid_traffic_t* result =
104      (bt_uid_traffic_t*)osi_calloc(sizeof(bt_uid_traffic_t) * (len + 1));
105
106  bt_uid_traffic_t* data = result;
107  node = set->head;
108  while (node) {
109    // Copy the data.
110    *data = node->data;
111    data++;
112
113    // Clear the counters.
114    node->data.rx_bytes = 0;
115    node->data.tx_bytes = 0;
116    node = node->next;
117  }
118
119  // Mark the last entry
120  data->app_uid = -1;
121
122  return result;
123}
124