1 /******************************************************************************
2 *
3 * Copyright 2015 Google Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #include "btif/include/btif_debug_conn.h"
20
21 #include <time.h>
22
23 #include "common/time_util.h"
24 #include "types/raw_address.h"
25
26 #define NUM_CONNECTION_EVENTS 16
27 #define TEMP_BUFFER_SIZE 30
28
29 typedef struct conn_event_t {
30 uint64_t ts;
31 btif_debug_conn_state_t state;
32 RawAddress bda;
33 tGATT_DISCONN_REASON disconnect_reason;
34 } conn_event_t;
35
36 static conn_event_t connection_events[NUM_CONNECTION_EVENTS];
37 static uint8_t current_event = 0;
38
format_ts(const uint64_t ts,char * buffer,int len)39 static char* format_ts(const uint64_t ts, char* buffer, int len) {
40 const uint64_t ms = ts / 1000;
41 const time_t secs = ms / 1000;
42 struct tm* ptm = localtime(&secs);
43
44 char tempbuff[20];
45 strftime(tempbuff, sizeof(tempbuff), "%m-%d %H:%M:%S", ptm);
46 snprintf(buffer, len, "%s.%03u", tempbuff, (uint16_t)(ms % 1000));
47
48 return buffer;
49 }
50
format_state(const btif_debug_conn_state_t state)51 static const char* format_state(const btif_debug_conn_state_t state) {
52 switch (state) {
53 case BTIF_DEBUG_CONNECTED:
54 return "CONNECTED ";
55 case BTIF_DEBUG_DISCONNECTED:
56 return "DISCONNECTED";
57 }
58 return "UNKNOWN";
59 }
60
next_event()61 static void next_event() {
62 ++current_event;
63 if (current_event == NUM_CONNECTION_EVENTS) {
64 current_event = 0;
65 }
66 }
67
btif_debug_conn_state(const RawAddress & bda,const btif_debug_conn_state_t state,const tGATT_DISCONN_REASON disconnect_reason)68 void btif_debug_conn_state(const RawAddress& bda, const btif_debug_conn_state_t state,
69 const tGATT_DISCONN_REASON disconnect_reason) {
70 next_event();
71
72 conn_event_t* evt = &connection_events[current_event];
73 evt->ts = bluetooth::common::time_gettimeofday_us();
74 evt->state = state;
75 evt->disconnect_reason = disconnect_reason;
76 evt->bda = bda;
77 }
78
btif_debug_conn_dump(int fd)79 void btif_debug_conn_dump(int fd) {
80 const uint8_t current_event_local = current_event; // Cache to avoid threading issues
81 uint8_t dump_event = current_event_local;
82 char ts_buffer[TEMP_BUFFER_SIZE] = {0};
83
84 dprintf(fd, "\nConnection Events:\n");
85 if (connection_events[dump_event].ts == 0) {
86 dprintf(fd, " None\n");
87 }
88
89 while (connection_events[dump_event].ts) {
90 conn_event_t* evt = &connection_events[dump_event];
91 dprintf(fd, " %s %s %s", format_ts(evt->ts, ts_buffer, sizeof(ts_buffer)),
92 format_state(evt->state), evt->bda.ToRedactedStringForLogging().c_str());
93 if (evt->state == BTIF_DEBUG_DISCONNECTED) {
94 dprintf(fd, " reason=%d", evt->disconnect_reason);
95 }
96 dprintf(fd, "\n");
97
98 // Go to previous event; wrap if needed
99 if (dump_event > 0) {
100 --dump_event;
101 } else {
102 dump_event = NUM_CONNECTION_EVENTS - 1;
103 }
104
105 // Check if we dumped all events
106 if (dump_event == current_event_local) {
107 break;
108 }
109 }
110 }
111