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 <stdio.h>
22 #include <string.h>
23 #include <time.h>
24
25 #include "common/time_util.h"
26 #include "types/raw_address.h"
27
28 #define NUM_CONNECTION_EVENTS 16
29 #define TEMP_BUFFER_SIZE 30
30
31 typedef struct conn_event_t {
32 uint64_t ts;
33 btif_debug_conn_state_t state;
34 RawAddress bda;
35 tGATT_DISCONN_REASON disconnect_reason;
36 } conn_event_t;
37
38 static conn_event_t connection_events[NUM_CONNECTION_EVENTS];
39 static uint8_t current_event = 0;
40
format_ts(const uint64_t ts,char * buffer,int len)41 static char* format_ts(const uint64_t ts, char* buffer, int len) {
42 const uint64_t ms = ts / 1000;
43 const time_t secs = ms / 1000;
44 struct tm* ptm = localtime(&secs);
45
46 char tempbuff[20];
47 strftime(tempbuff, sizeof(tempbuff), "%m-%d %H:%M:%S", ptm);
48 snprintf(buffer, len, "%s.%03u", tempbuff, (uint16_t)(ms % 1000));
49
50 return buffer;
51 }
52
format_state(const btif_debug_conn_state_t state)53 static const char* format_state(const btif_debug_conn_state_t state) {
54 switch (state) {
55 case BTIF_DEBUG_CONNECTED:
56 return "CONNECTED ";
57 case BTIF_DEBUG_DISCONNECTED:
58 return "DISCONNECTED";
59 }
60 return "UNKNOWN";
61 }
62
next_event()63 static void next_event() {
64 ++current_event;
65 if (current_event == NUM_CONNECTION_EVENTS) current_event = 0;
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,
69 const btif_debug_conn_state_t state,
70 const tGATT_DISCONN_REASON disconnect_reason) {
71 next_event();
72
73 conn_event_t* evt = &connection_events[current_event];
74 evt->ts = bluetooth::common::time_gettimeofday_us();
75 evt->state = state;
76 evt->disconnect_reason = disconnect_reason;
77 evt->bda = bda;
78 }
79
btif_debug_conn_dump(int fd)80 void btif_debug_conn_dump(int fd) {
81 const uint8_t current_event_local =
82 current_event; // Cache to avoid threading issues
83 uint8_t dump_event = current_event_local;
84 char ts_buffer[TEMP_BUFFER_SIZE] = {0};
85
86 dprintf(fd, "\nConnection Events:\n");
87 if (connection_events[dump_event].ts == 0) dprintf(fd, " None\n");
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.ToString().c_str());
93 if (evt->state == BTIF_DEBUG_DISCONNECTED)
94 dprintf(fd, " reason=%d", evt->disconnect_reason);
95 dprintf(fd, "\n");
96
97 // Go to previous event; wrap if needed
98 if (dump_event > 0)
99 --dump_event;
100 else
101 dump_event = NUM_CONNECTION_EVENTS - 1;
102
103 // Check if we dumped all events
104 if (dump_event == current_event_local) break;
105 }
106 }
107