1 /*
2  * Copyright 2024 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 #define LOG_TAG "bt_btif_sock"
18 
19 #include "btif/include/btif_sock_logging.h"
20 
21 #include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h>
22 #include <time.h>
23 
24 #include <atomic>
25 
26 #include "btif/include/btif_metrics_logging.h"
27 #include "btif/include/btif_sock.h"
28 #include "os/logging/log_adapter.h"
29 #include "types/raw_address.h"
30 
31 #define SOCK_LOGGER_SIZE_MAX 16
32 
33 using namespace bluetooth;
34 
35 struct SockConnectionEvent {
36   bool used;
37   RawAddress addr;
38   int state;
39   int role;
40   int channel;
41   int type;
42   char server_name[64];
43   struct timespec timestamp;
44 
45   void dump(const int fd);
46 };
47 
48 static std::atomic<uint8_t> logger_index;
49 
50 static SockConnectionEvent connection_logger[SOCK_LOGGER_SIZE_MAX];
51 
52 static android::bluetooth::SocketConnectionstateEnum toConnectionStateEnum(int state);
53 static android::bluetooth::SocketRoleEnum toSocketRoleEnum(int role);
54 
btif_sock_connection_logger(const RawAddress & address,int port,int type,int state,int role,int uid,int server_port,int64_t tx_bytes,int64_t rx_bytes,const char * server_name)55 void btif_sock_connection_logger(const RawAddress& address, int port, int type, int state, int role,
56                                  int uid, int server_port, int64_t tx_bytes, int64_t rx_bytes,
57                                  const char* server_name) {
58   log::verbose("bd_addr: {}, port: {}, role: {}, state: {}", address, port, role, state);
59 
60   uint8_t index = logger_index++ % SOCK_LOGGER_SIZE_MAX;
61 
62   connection_logger[index] = {
63           .used = true,
64           .addr = address,
65           .state = state,
66           .role = role,
67           .channel = server_port,
68           .type = type,
69           .server_name = {'\0'},
70   };
71 
72   if (server_name != nullptr) {
73     strncpy(connection_logger[index].server_name, server_name,
74             sizeof(connection_logger[index].server_name) - 1);
75   }
76 
77   clock_gettime(CLOCK_REALTIME, &connection_logger[index].timestamp);
78   log_socket_connection_state(address, port, type, toConnectionStateEnum(state), tx_bytes, rx_bytes,
79                               uid, server_port, toSocketRoleEnum(role));
80 }
81 
btif_sock_dump(int fd)82 void btif_sock_dump(int fd) {
83   dprintf(fd, "\nSocket Events: \n");
84   dprintf(fd,
85           "  Time        \tAddress          \tState             \tRole"
86           "              \tChannel   \tType     \tServerName\n");
87 
88   const uint8_t head = logger_index.load() % SOCK_LOGGER_SIZE_MAX;
89 
90   uint8_t index = head;
91   do {
92     connection_logger[index].dump(fd);
93 
94     index++;
95     index %= SOCK_LOGGER_SIZE_MAX;
96   } while (index != head);
97   dprintf(fd, "\n");
98 }
99 
dump(const int fd)100 void SockConnectionEvent::dump(const int fd) {
101   if (!used) {
102     return;
103   }
104 
105   char eventtime[20];
106   char temptime[20];
107   struct tm* tstamp = localtime(&timestamp.tv_sec);
108   strftime(temptime, sizeof(temptime), "%H:%M:%S", tstamp);
109   snprintf(eventtime, sizeof(eventtime), "%s.%03ld", temptime, timestamp.tv_nsec / 1000000);
110 
111   const char* str_state;
112   switch (state) {
113     case SOCKET_CONNECTION_STATE_LISTENING:
114       str_state = "STATE_LISTENING";
115       break;
116     case SOCKET_CONNECTION_STATE_CONNECTING:
117       str_state = "STATE_CONNECTING";
118       break;
119     case SOCKET_CONNECTION_STATE_CONNECTED:
120       str_state = "STATE_CONNECTED";
121       break;
122     case SOCKET_CONNECTION_STATE_DISCONNECTING:
123       str_state = "STATE_DISCONNECTING";
124       break;
125     case SOCKET_CONNECTION_STATE_DISCONNECTED:
126       str_state = "STATE_DISCONNECTED";
127       break;
128     default:
129       str_state = "STATE_UNKNOWN";
130       break;
131   }
132 
133   const char* str_role;
134   switch (role) {
135     case SOCKET_ROLE_LISTEN:
136       str_role = "ROLE_LISTEN";
137       break;
138     case SOCKET_ROLE_CONNECTION:
139       str_role = "ROLE_CONNECTION";
140       break;
141     default:
142       str_role = "ROLE_UNKNOWN";
143       break;
144   }
145 
146   const char* str_type;
147   switch (type) {
148     case BTSOCK_RFCOMM:
149       str_type = "RFCOMM";
150       break;
151     case BTSOCK_L2CAP:
152       str_type = "L2CAP";
153       break;
154     case BTSOCK_L2CAP_LE:
155       str_type = "L2CAP_LE";
156       break;
157     case BTSOCK_SCO:
158       str_type = "SCO";
159       break;
160     default:
161       str_type = "UNKNOWN";
162       break;
163   }
164 
165   dprintf(fd, "  %s\t%s\t%s   \t%s      \t%d         \t%s\t%s\n", eventtime,
166           ADDRESS_TO_LOGGABLE_CSTR(addr), str_state, str_role, channel, str_type, server_name);
167 }
168 
toConnectionStateEnum(int state)169 static android::bluetooth::SocketConnectionstateEnum toConnectionStateEnum(int state) {
170   switch (state) {
171     case SOCKET_CONNECTION_STATE_LISTENING:
172       return android::bluetooth::SocketConnectionstateEnum::SOCKET_CONNECTION_STATE_LISTENING;
173       break;
174     case SOCKET_CONNECTION_STATE_CONNECTING:
175       return android::bluetooth::SocketConnectionstateEnum::SOCKET_CONNECTION_STATE_CONNECTING;
176     case SOCKET_CONNECTION_STATE_CONNECTED:
177       return android::bluetooth::SocketConnectionstateEnum::SOCKET_CONNECTION_STATE_CONNECTED;
178     case SOCKET_CONNECTION_STATE_DISCONNECTING:
179       return android::bluetooth::SocketConnectionstateEnum::SOCKET_CONNECTION_STATE_DISCONNECTING;
180     case SOCKET_CONNECTION_STATE_DISCONNECTED:
181       return android::bluetooth::SocketConnectionstateEnum::SOCKET_CONNECTION_STATE_DISCONNECTED;
182   }
183   return android::bluetooth::SocketConnectionstateEnum::SOCKET_CONNECTION_STATE_UNKNOWN;
184 }
185 
toSocketRoleEnum(int role)186 static android::bluetooth::SocketRoleEnum toSocketRoleEnum(int role) {
187   switch (role) {
188     case SOCKET_ROLE_LISTEN:
189       return android::bluetooth::SOCKET_ROLE_LISTEN;
190     case SOCKET_ROLE_CONNECTION:
191       return android::bluetooth::SOCKET_ROLE_CONNECTION;
192   }
193   return android::bluetooth::SOCKET_ROLE_UNKNOWN;
194 }
195