1 /*
2  * Copyright 2023 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 #include "bta/dm/bta_dm_gatt_client.h"
18 
19 #include <base/strings/stringprintf.h>
20 
21 #include <cstdint>
22 #include <string>
23 #include <vector>
24 
25 #include "bta/include/bta_gatt_api.h"
26 #include "common/strings.h"
27 #include "main/shim/dumpsys.h"
28 #include "stack/btm/btm_int_types.h"
29 #include "types/bluetooth/uuid.h"
30 #include "types/raw_address.h"
31 
32 namespace {
33 TimestampedStringCircularBuffer gatt_history_{50};
34 constexpr char kTimeFormatString[] = "%Y-%m-%d %H:%M:%S";
35 
36 constexpr unsigned MillisPerSecond = 1000;
EpochMillisToString(long long time_ms)37 std::string EpochMillisToString(long long time_ms) {
38   time_t time_sec = time_ms / MillisPerSecond;
39   struct tm tm;
40   localtime_r(&time_sec, &tm);
41   std::string s = bluetooth::common::StringFormatTime(kTimeFormatString, tm);
42   return base::StringPrintf(
43       "%s.%03u", s.c_str(),
44       static_cast<unsigned int>(time_ms % MillisPerSecond));
45 }
46 }  // namespace
47 
48 gatt_interface_t default_gatt_interface = {
49     .BTA_GATTC_CancelOpen =
__anon3962861c0202() 50         [](tGATT_IF client_if, const RawAddress& remote_bda, bool is_direct) {
51           gatt_history_.Push(base::StringPrintf(
52               "%-32s bd_addr:%s client_if:%hu is_direct:%c", "GATTC_CancelOpen",
53               ADDRESS_TO_LOGGABLE_CSTR(remote_bda), client_if,
54               (is_direct) ? 'T' : 'F'));
55           BTA_GATTC_CancelOpen(client_if, remote_bda, is_direct);
56         },
57     .BTA_GATTC_Refresh =
__anon3962861c0302() 58         [](const RawAddress& remote_bda) {
59           gatt_history_.Push(
60               base::StringPrintf("%-32s bd_addr:%s", "GATTC_Refresh",
61                                  ADDRESS_TO_LOGGABLE_CSTR(remote_bda)));
62           BTA_GATTC_Refresh(remote_bda);
63         },
64     .BTA_GATTC_GetGattDb =
65         [](uint16_t conn_id, uint16_t start_handle, uint16_t end_handle,
__anon3962861c0402() 66            btgatt_db_element_t** db, int* count) {
67           gatt_history_.Push(base::StringPrintf(
68               "%-32s conn_id:%hu start_handle:%hu end:handle:%hu",
69               "GATTC_GetGattDb", conn_id, start_handle, end_handle));
70           BTA_GATTC_GetGattDb(conn_id, start_handle, end_handle, db, count);
71         },
72     .BTA_GATTC_AppRegister =
73         [](tBTA_GATTC_CBACK* p_client_cb, BtaAppRegisterCallback cb,
__anon3962861c0502() 74            bool eatt_support) {
75           gatt_history_.Push(base::StringPrintf("%-32s eatt_support:%c",
76                                                 "GATTC_AppRegister",
77                                                 (eatt_support) ? 'T' : 'F'));
78           BTA_GATTC_AppRegister(p_client_cb, cb, eatt_support);
79         },
80     .BTA_GATTC_Close =
__anon3962861c0602() 81         [](uint16_t conn_id) {
82           gatt_history_.Push(
83               base::StringPrintf("%-32s conn_id:%hu", "GATTC_Close", conn_id));
84           BTA_GATTC_Close(conn_id);
85         },
86     .BTA_GATTC_ServiceSearchRequest =
__anon3962861c0702() 87         [](uint16_t conn_id, const bluetooth::Uuid* p_srvc_uuid) {
88           gatt_history_.Push(base::StringPrintf(
89               "%-32s conn_id:%hu", "GATTC_ServiceSearchRequest", conn_id));
90           if (p_srvc_uuid) {
91             BTA_GATTC_ServiceSearchRequest(conn_id, *p_srvc_uuid);
92           } else {
93             BTA_GATTC_ServiceSearchAllRequest(conn_id);
94           }
95         },
96     .BTA_GATTC_Open =
97         [](tGATT_IF client_if, const RawAddress& remote_bda,
__anon3962861c0802() 98            tBTM_BLE_CONN_TYPE connection_type, bool opportunistic) {
99           gatt_history_.Push(base::StringPrintf(
100               "%-32s bd_addr:%s client_if:%hu type:0x%x opportunistic:%c",
101               "GATTC_Open", ADDRESS_TO_LOGGABLE_CSTR(remote_bda), client_if,
102               connection_type, (opportunistic) ? 'T' : 'F'));
103           BTA_GATTC_Open(client_if, remote_bda, connection_type, opportunistic);
104         },
105 };
106 
107 gatt_interface_t* gatt_interface = &default_gatt_interface;
108 
get_gatt_interface()109 gatt_interface_t& get_gatt_interface() { return *gatt_interface; }
110 
gatt_history_callback(const std::string & entry)111 void gatt_history_callback(const std::string& entry) {
112   gatt_history_.Push(entry);
113 }
114 
115 #define DUMPSYS_TAG "shim::legacy::bta::dm"
DumpsysBtaDmGattClient(int fd)116 void DumpsysBtaDmGattClient(int fd) {
117   auto gatt_history = gatt_history_.Pull();
118   LOG_DUMPSYS(fd, " last %zu gatt history entries", gatt_history.size());
119   for (const auto& it : gatt_history) {
120     LOG_DUMPSYS(fd, "   %s %s", EpochMillisToString(it.timestamp).c_str(),
121                 it.entry.c_str());
122   }
123 }
124 #undef DUMPSYS_TAG
125 
set_gatt_interface(const gatt_interface_t & interface)126 void bluetooth::testing::set_gatt_interface(const gatt_interface_t& interface) {
127   *gatt_interface = interface;
128 }
129 
130 namespace bluetooth {
131 namespace legacy {
132 namespace testing {
133 
134 std::vector<bluetooth::common::TimestampedEntry<std::string>>
PullCopyOfGattHistory()135 PullCopyOfGattHistory() {
136   return gatt_history_.Pull();
137 }
138 
139 }  // namespace testing
140 }  // namespace legacy
141 }  // namespace bluetooth
142