• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_sock.h"
27 #include "common/time_util.h"
28 #include "main/shim/metrics_api.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 static android::bluetooth::SocketErrorEnum toSocketErrorEnum(btsock_error_code_t error_code);
55 static uint64_t getConnectionDuration(uint64_t start_time_ms);
56 
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,uint64_t connection_start_time_ms,btsock_error_code_t error_code,btsock_data_path_t data_path)57 void btif_sock_connection_logger(const RawAddress& address, int port, int type, int state, int role,
58                                  int uid, int server_port, int64_t tx_bytes, int64_t rx_bytes,
59                                  const char* server_name, uint64_t connection_start_time_ms,
60                                  btsock_error_code_t error_code, btsock_data_path_t data_path) {
61   log::verbose("bd_addr: {}, port: {}, role: {}, state: {}, data_path: {}", address, port, role,
62                state, data_path);
63 
64   uint8_t index = logger_index++ % SOCK_LOGGER_SIZE_MAX;
65 
66   connection_logger[index] = {
67           .used = true,
68           .addr = address,
69           .state = state,
70           .role = role,
71           .channel = server_port,
72           .type = type,
73           .server_name = {'\0'},
74   };
75 
76   if (server_name != nullptr) {
77     strncpy(connection_logger[index].server_name, server_name,
78             sizeof(connection_logger[index].server_name) - 1);
79   }
80 
81   clock_gettime(CLOCK_REALTIME, &connection_logger[index].timestamp);
82   bluetooth::shim::LogMetricSocketConnectionState(
83           address, port, type, toConnectionStateEnum(state), tx_bytes, rx_bytes, uid, server_port,
84           toSocketRoleEnum(role), getConnectionDuration(connection_start_time_ms),
85           toSocketErrorEnum(error_code), data_path == BTSOCK_DATA_PATH_HARDWARE_OFFLOAD);
86 }
87 
btif_sock_dump(int fd)88 void btif_sock_dump(int fd) {
89   dprintf(fd, "\nSocket Events: \n");
90   dprintf(fd,
91           "  Time        \tAddress          \tState             \tRole"
92           "              \tChannel   \tType     \tServerName\n");
93 
94   const uint8_t head = logger_index.load() % SOCK_LOGGER_SIZE_MAX;
95 
96   uint8_t index = head;
97   do {
98     connection_logger[index].dump(fd);
99 
100     index++;
101     index %= SOCK_LOGGER_SIZE_MAX;
102   } while (index != head);
103   dprintf(fd, "\n");
104 }
105 
dump(const int fd)106 void SockConnectionEvent::dump(const int fd) {
107   if (!used) {
108     return;
109   }
110 
111   char eventtime[20];
112   char temptime[20];
113   struct tm* tstamp = localtime(&timestamp.tv_sec);
114   strftime(temptime, sizeof(temptime), "%H:%M:%S", tstamp);
115   snprintf(eventtime, sizeof(eventtime), "%s.%03ld", temptime, timestamp.tv_nsec / 1000000);
116 
117   const char* str_state;
118   switch (state) {
119     case SOCKET_CONNECTION_STATE_LISTENING:
120       str_state = "STATE_LISTENING";
121       break;
122     case SOCKET_CONNECTION_STATE_CONNECTING:
123       str_state = "STATE_CONNECTING";
124       break;
125     case SOCKET_CONNECTION_STATE_CONNECTED:
126       str_state = "STATE_CONNECTED";
127       break;
128     case SOCKET_CONNECTION_STATE_DISCONNECTING:
129       str_state = "STATE_DISCONNECTING";
130       break;
131     case SOCKET_CONNECTION_STATE_DISCONNECTED:
132       str_state = "STATE_DISCONNECTED";
133       break;
134     default:
135       str_state = "STATE_UNKNOWN";
136       break;
137   }
138 
139   const char* str_role;
140   switch (role) {
141     case SOCKET_ROLE_LISTEN:
142       str_role = "ROLE_LISTEN";
143       break;
144     case SOCKET_ROLE_CONNECTION:
145       str_role = "ROLE_CONNECTION";
146       break;
147     default:
148       str_role = "ROLE_UNKNOWN";
149       break;
150   }
151 
152   const char* str_type;
153   switch (type) {
154     case BTSOCK_RFCOMM:
155       str_type = "RFCOMM";
156       break;
157     case BTSOCK_L2CAP:
158       str_type = "L2CAP";
159       break;
160     case BTSOCK_L2CAP_LE:
161       str_type = "L2CAP_LE";
162       break;
163     case BTSOCK_SCO:
164       str_type = "SCO";
165       break;
166     default:
167       str_type = "UNKNOWN";
168       break;
169   }
170 
171   dprintf(fd, "  %s\t%s\t%s   \t%s      \t%d         \t%s\t%s\n", eventtime,
172           addr.ToRedactedStringForLogging().c_str(), str_state, str_role, channel, str_type,
173           server_name);
174 }
175 
toConnectionStateEnum(int state)176 static android::bluetooth::SocketConnectionstateEnum toConnectionStateEnum(int state) {
177   switch (state) {
178     case SOCKET_CONNECTION_STATE_LISTENING:
179       return android::bluetooth::SocketConnectionstateEnum::SOCKET_CONNECTION_STATE_LISTENING;
180       break;
181     case SOCKET_CONNECTION_STATE_CONNECTING:
182       return android::bluetooth::SocketConnectionstateEnum::SOCKET_CONNECTION_STATE_CONNECTING;
183     case SOCKET_CONNECTION_STATE_CONNECTED:
184       return android::bluetooth::SocketConnectionstateEnum::SOCKET_CONNECTION_STATE_CONNECTED;
185     case SOCKET_CONNECTION_STATE_DISCONNECTING:
186       return android::bluetooth::SocketConnectionstateEnum::SOCKET_CONNECTION_STATE_DISCONNECTING;
187     case SOCKET_CONNECTION_STATE_DISCONNECTED:
188       return android::bluetooth::SocketConnectionstateEnum::SOCKET_CONNECTION_STATE_DISCONNECTED;
189   }
190   return android::bluetooth::SocketConnectionstateEnum::SOCKET_CONNECTION_STATE_UNKNOWN;
191 }
192 
toSocketRoleEnum(int role)193 static android::bluetooth::SocketRoleEnum toSocketRoleEnum(int role) {
194   switch (role) {
195     case SOCKET_ROLE_LISTEN:
196       return android::bluetooth::SOCKET_ROLE_LISTEN;
197     case SOCKET_ROLE_CONNECTION:
198       return android::bluetooth::SOCKET_ROLE_CONNECTION;
199   }
200   return android::bluetooth::SOCKET_ROLE_UNKNOWN;
201 }
202 
toSocketErrorEnum(btsock_error_code_t error_code)203 static android::bluetooth::SocketErrorEnum toSocketErrorEnum(btsock_error_code_t error_code) {
204   switch (error_code) {
205     case BTSOCK_ERROR_NONE:
206       return android::bluetooth::SocketErrorEnum::SOCKET_ERROR_NONE;
207     case BTSOCK_ERROR_SERVER_START_FAILURE:
208       return android::bluetooth::SocketErrorEnum::SOCKET_ERROR_SERVER_START_FAILURE;
209     case BTSOCK_ERROR_CLIENT_INIT_FAILURE:
210       return android::bluetooth::SocketErrorEnum::SOCKET_ERROR_CLIENT_INIT_FAILURE;
211     case BTSOCK_ERROR_LISTEN_FAILURE:
212       return android::bluetooth::SocketErrorEnum::SOCKET_ERROR_LISTEN_FAILURE;
213     case BTSOCK_ERROR_CONNECTION_FAILURE:
214       return android::bluetooth::SocketErrorEnum::SOCKET_ERROR_CONNECTION_FAILURE;
215     case BTSOCK_ERROR_OPEN_FAILURE:
216       return android::bluetooth::SocketErrorEnum::SOCKET_ERROR_OPEN_FAILURE;
217     case BTSOCK_ERROR_OFFLOAD_SERVER_NOT_ACCEPTING:
218       return android::bluetooth::SocketErrorEnum::SOCKET_ERROR_OFFLOAD_SERVER_NOT_ACCEPTING;
219     case BTSOCK_ERROR_OFFLOAD_HAL_OPEN_FAILURE:
220       return android::bluetooth::SocketErrorEnum::SOCKET_ERROR_OFFLOAD_HAL_OPEN_FAILURE;
221     case BTSOCK_ERROR_SEND_TO_APP_FAILURE:
222       return android::bluetooth::SocketErrorEnum::SOCKET_ERROR_SEND_TO_APP_FAILURE;
223     case BTSOCK_ERROR_RECEIVE_DATA_FAILURE:
224       return android::bluetooth::SocketErrorEnum::SOCKET_ERROR_RECEIVE_DATA_FAILURE;
225     case BTSOCK_ERROR_READ_SIGNALED_FAILURE:
226       return android::bluetooth::SocketErrorEnum::SOCKET_ERROR_READ_SIGNALED_FAILURE;
227     case BTSOCK_ERROR_WRITE_SIGNALED_FAILURE:
228       return android::bluetooth::SocketErrorEnum::SOCKET_ERROR_WRITE_SIGNALED_FAILURE;
229     case BTSOCK_ERROR_SEND_SCN_FAILURE:
230       return android::bluetooth::SocketErrorEnum::SOCKET_ERROR_SEND_SCN_FAILURE;
231     case BTSOCK_ERROR_SCN_ALLOCATION_FAILURE:
232       return android::bluetooth::SocketErrorEnum::SOCKET_ERROR_SCN_ALLOCATION_FAILURE;
233     case BTSOCK_ERROR_ADD_SDP_FAILURE:
234       return android::bluetooth::SocketErrorEnum::SOCKET_ERROR_ADD_SDP_FAILURE;
235     case BTSOCK_ERROR_SDP_DISCOVERY_FAILURE:
236       return android::bluetooth::SocketErrorEnum::SOCKET_ERROR_SDP_DISCOVERY_FAILURE;
237   }
238   return android::bluetooth::SocketErrorEnum::SOCKET_ERROR_NONE;
239 }
240 
getConnectionDuration(uint64_t start_time_ms)241 static uint64_t getConnectionDuration(uint64_t start_time_ms) {
242   // start time is 0 before the connection state, use 0 for duration
243   if (start_time_ms == 0) {
244     return 0;
245   }
246   uint64_t current_time_ms = common::time_gettimeofday_us() / 1000;
247   if (current_time_ms <= start_time_ms) {
248     log::warn("Socket connection end time is not greater than start time, logging 0 ms instead");
249     return 0;
250   }
251   return current_time_ms - start_time_ms;
252 }
253