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