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