/* * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "bt_headless_mode" #include "test/headless/connect/connect.h" #include #include #include #include #include #include "btif/include/stack_manager_t.h" #include "main/shim/acl_api.h" #include "stack/include/acl_api.h" #include "stack/include/hci_error_code.h" #include "test/headless/get_options.h" #include "test/headless/headless.h" #include "test/headless/interface.h" #include "test/headless/messenger.h" #include "types/raw_address.h" using namespace bluetooth::test; using namespace bluetooth; using namespace std::chrono_literals; const stack_manager_t* stack_manager_get_interface(); namespace { bool f_simulate_stack_crash = false; int do_connect([[maybe_unused]] unsigned int num_loops, [[maybe_unused]] const RawAddress& bd_addr, [[maybe_unused]] std::list options) { int disconnect_wait_time{0}; if (options.size() != 0) { std::string opt = options.front(); options.pop_front(); auto v = bluetooth::test::headless::GetOpt::Split(opt); if (v.size() == 2) { if (v[0] == "wait") disconnect_wait_time = std::stoi(v[1]); } } log::assert_that(disconnect_wait_time >= 0, "Time cannot go backwards"); headless::messenger::Context context{ .stop_watch = Stopwatch("Connect_timeout"), .timeout = 3s, .check_point = {}, .callbacks = {Callback::AclStateChanged}, }; LOG_CONSOLE("Creating connection to:%s", bd_addr.ToString().c_str()); log::info("Creating classic connection to {}", bd_addr.ToString()); bluetooth::shim::ACL_CreateClassicConnection(bd_addr); std::shared_ptr acl{nullptr}; while (context.stop_watch.LapMs() < 10000) { // If we have received callback results within this timeframe... if (headless::messenger::await_callback(context)) { while (!context.callback_ready_q.empty()) { std::shared_ptr p = context.callback_ready_q.front(); context.callback_ready_q.pop_front(); switch (p->CallbackType()) { case Callback::AclStateChanged: { acl = p; } break; default: LOG_CONSOLE("WARN Received callback for unasked:%s", p->Name().c_str()); break; } } } if (acl != nullptr) break; } if (acl != nullptr) { LOG_CONSOLE("Acl state changed:%s", acl->ToString().c_str()); } uint64_t connect = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()) .count(); if (f_simulate_stack_crash) { LOG_CONSOLE("Just crushing stack"); log::info("Just crushing stack"); bluetoothInterface.disable(); } std::shared_ptr acl2{nullptr}; if (disconnect_wait_time == 0) { LOG_CONSOLE("Waiting to disconnect from supervision timeout\n"); while (context.stop_watch.LapMs() < 10000) { // If we have received callback results within this timeframe... if (headless::messenger::await_callback(context)) { while (!context.callback_ready_q.empty()) { std::shared_ptr p = context.callback_ready_q.front(); context.callback_ready_q.pop_front(); switch (p->CallbackType()) { case Callback::AclStateChanged: { acl2 = p; } break; default: LOG_CONSOLE("WARN Received callback for unasked:%s", p->Name().c_str()); break; } } } if (acl2 != nullptr) break; } uint64_t disconnect = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()) .count(); LOG_CONSOLE("Disconnected after:%" PRId64 "ms from:%s acl:%s", disconnect - connect, bd_addr.ToString().c_str(), acl->ToString().c_str()); } acl_disconnect_from_handle( ((acl_state_changed_params_t*)(acl2.get()))->acl_handle, HCI_SUCCESS, "BT headless disconnect"); sleep(3); return 0; } } // namespace int bluetooth::test::headless::Connect::Run() { return RunOnHeadlessStack([this]() { return do_connect(options_.loop_, options_.device_.front(), options_.non_options_); }); }