1 /*
2 * Copyright 2020 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_headless_mode"
18
19 #include "test/headless/connect/connect.h"
20
21 #include <bluetooth/log.h>
22 #include <inttypes.h>
23
24 #include <chrono>
25 #include <cstdint>
26 #include <string>
27
28 #include "btif/include/stack_manager_t.h"
29 #include "main/shim/acl_api.h"
30 #include "stack/include/acl_api.h"
31 #include "stack/include/hci_error_code.h"
32 #include "test/headless/get_options.h"
33 #include "test/headless/headless.h"
34 #include "test/headless/interface.h"
35 #include "test/headless/messenger.h"
36 #include "types/raw_address.h"
37
38 using namespace bluetooth::test;
39 using namespace bluetooth;
40 using namespace std::chrono_literals;
41
42 const stack_manager_t* stack_manager_get_interface();
43
44 namespace {
45
46 bool f_simulate_stack_crash = false;
47
do_connect(unsigned int num_loops,const RawAddress & bd_addr,std::list<std::string> options)48 int do_connect([[maybe_unused]] unsigned int num_loops,
49 [[maybe_unused]] const RawAddress& bd_addr,
50 [[maybe_unused]] std::list<std::string> options) {
51 int disconnect_wait_time{0};
52
53 if (options.size() != 0) {
54 std::string opt = options.front();
55 options.pop_front();
56 auto v = bluetooth::test::headless::GetOpt::Split(opt);
57 if (v.size() == 2) {
58 if (v[0] == "wait") disconnect_wait_time = std::stoi(v[1]);
59 }
60 }
61 log::assert_that(disconnect_wait_time >= 0, "Time cannot go backwards");
62
63 headless::messenger::Context context{
64 .stop_watch = Stopwatch("Connect_timeout"),
65 .timeout = 3s,
66 .check_point = {},
67 .callbacks = {Callback::AclStateChanged},
68 };
69
70 LOG_CONSOLE("Creating connection to:%s", bd_addr.ToString().c_str());
71 log::info("Creating classic connection to {}", bd_addr.ToString());
72 bluetooth::shim::ACL_CreateClassicConnection(bd_addr);
73
74 std::shared_ptr<callback_params_t> acl{nullptr};
75 while (context.stop_watch.LapMs() < 10000) {
76 // If we have received callback results within this timeframe...
77 if (headless::messenger::await_callback(context)) {
78 while (!context.callback_ready_q.empty()) {
79 std::shared_ptr<callback_params_t> p = context.callback_ready_q.front();
80 context.callback_ready_q.pop_front();
81 switch (p->CallbackType()) {
82 case Callback::AclStateChanged: {
83 acl = p;
84 } break;
85 default:
86 LOG_CONSOLE("WARN Received callback for unasked:%s",
87 p->Name().c_str());
88 break;
89 }
90 }
91 }
92 if (acl != nullptr) break;
93 }
94
95 if (acl != nullptr) {
96 LOG_CONSOLE("Acl state changed:%s", acl->ToString().c_str());
97 }
98
99 uint64_t connect = std::chrono::duration_cast<std::chrono::milliseconds>(
100 std::chrono::system_clock::now().time_since_epoch())
101 .count();
102
103 if (f_simulate_stack_crash) {
104 LOG_CONSOLE("Just crushing stack");
105 log::info("Just crushing stack");
106 bluetoothInterface.disable();
107 }
108 std::shared_ptr<callback_params_t> acl2{nullptr};
109
110 if (disconnect_wait_time == 0) {
111 LOG_CONSOLE("Waiting to disconnect from supervision timeout\n");
112 while (context.stop_watch.LapMs() < 10000) {
113 // If we have received callback results within this timeframe...
114 if (headless::messenger::await_callback(context)) {
115 while (!context.callback_ready_q.empty()) {
116 std::shared_ptr<callback_params_t> p =
117 context.callback_ready_q.front();
118 context.callback_ready_q.pop_front();
119 switch (p->CallbackType()) {
120 case Callback::AclStateChanged: {
121 acl2 = p;
122 } break;
123 default:
124 LOG_CONSOLE("WARN Received callback for unasked:%s",
125 p->Name().c_str());
126 break;
127 }
128 }
129 }
130 if (acl2 != nullptr) break;
131 }
132 uint64_t disconnect =
133 std::chrono::duration_cast<std::chrono::milliseconds>(
134 std::chrono::system_clock::now().time_since_epoch())
135 .count();
136
137 LOG_CONSOLE("Disconnected after:%" PRId64 "ms from:%s acl:%s",
138 disconnect - connect, bd_addr.ToString().c_str(),
139 acl->ToString().c_str());
140 }
141
142 acl_disconnect_from_handle(
143 ((acl_state_changed_params_t*)(acl2.get()))->acl_handle, HCI_SUCCESS,
144 "BT headless disconnect");
145
146 sleep(3);
147
148 return 0;
149 }
150
151 } // namespace
152
Run()153 int bluetooth::test::headless::Connect::Run() {
154 return RunOnHeadlessStack<int>([this]() {
155 return do_connect(options_.loop_, options_.device_.front(),
156 options_.non_options_);
157 });
158 }
159