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