1 /******************************************************************************
2 *
3 * Copyright (C) 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 <stdio.h>
20 #include <string.h>
21 #include <time.h>
22
23 #include "btif/include/btif_debug_conn.h"
24 #include "osi/include/time.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) current_event = 0;
64 }
65
btif_debug_conn_state(const RawAddress & bda,const btif_debug_conn_state_t state,const tGATT_DISCONN_REASON disconnect_reason)66 void btif_debug_conn_state(const RawAddress& bda,
67 const btif_debug_conn_state_t state,
68 const tGATT_DISCONN_REASON disconnect_reason) {
69 next_event();
70
71 conn_event_t* evt = &connection_events[current_event];
72 evt->ts = time_gettimeofday_us();
73 evt->state = state;
74 evt->disconnect_reason = disconnect_reason;
75 evt->bda = bda;
76 }
77
btif_debug_conn_dump(int fd)78 void btif_debug_conn_dump(int fd) {
79 const uint8_t current_event_local =
80 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) dprintf(fd, " None\n");
86
87 while (connection_events[dump_event].ts) {
88 conn_event_t* evt = &connection_events[dump_event];
89 dprintf(fd, " %s %s %s", format_ts(evt->ts, ts_buffer, sizeof(ts_buffer)),
90 format_state(evt->state), evt->bda.ToString().c_str());
91 if (evt->state == BTIF_DEBUG_DISCONNECTED)
92 dprintf(fd, " reason=%d", evt->disconnect_reason);
93 dprintf(fd, "\n");
94
95 // Go to previous event; wrap if needed
96 if (dump_event > 0)
97 --dump_event;
98 else
99 dump_event = NUM_CONNECTION_EVENTS - 1;
100
101 // Check if we dumped all events
102 if (dump_event == current_event_local) break;
103 }
104 }
105