/* * Copyright 2023 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_bta_dm_test" #include #include #include #include #include #include #include #include "bta/dm/bta_dm_device_search.h" #include "bta/dm/bta_dm_device_search_int.h" #include "bta/dm/bta_dm_disc.h" #include "bta/dm/bta_dm_disc_int.h" #include "bta/test/bta_test_fixtures.h" #include "bta_api_data_types.h" #include "stack/btm/neighbor_inquiry.h" #include "types/bt_transport.h" #define TEST_BT com::android::bluetooth::flags using namespace bluetooth; using ::testing::_; using ::testing::Return; namespace { const RawAddress kRawAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); } // Test hooks namespace bluetooth { namespace legacy { namespace testing { void bta_dm_disc_init_search_cb(tBTA_DM_SEARCH_CB& bta_dm_search_cb); bool bta_dm_read_remote_device_name(const RawAddress& bd_addr, tBT_TRANSPORT transport); tBTA_DM_SEARCH_CB& bta_dm_disc_search_cb(); void bta_dm_discover_next_device(); void bta_dm_sdp_find_services(tBTA_DM_SDP_STATE* state); void bta_dm_inq_cmpl(); void bta_dm_inq_cmpl_cb(void* p_result); void bta_dm_observe_cmpl_cb(void* p_result); void bta_dm_observe_results_cb(tBTM_INQ_RESULTS* p_inq, const uint8_t* p_eir, uint16_t eir_len); void bta_dm_opportunistic_observe_results_cb(tBTM_INQ_RESULTS* p_inq, const uint8_t* p_eir, uint16_t eir_len); void bta_dm_queue_search(tBTA_DM_API_SEARCH& search); void bta_dm_start_scan(uint8_t duration_sec); } // namespace testing } // namespace legacy } // namespace bluetooth class BtaInitializedTest : public BtaWithContextTest { protected: void SetUp() override { BtaWithContextTest::SetUp(); BTA_dm_init(); } void TearDown() override { BtaWithContextTest::TearDown(); } }; TEST_F(BtaInitializedTest, nop) {} TEST_F(BtaInitializedTest, DumpsysBtaDmDisc) { std::FILE* file = std::tmpfile(); DumpsysBtaDmDisc(fileno(file)); } TEST_F(BtaInitializedTest, bta_dm_ble_csis_observe) { bta_dm_ble_csis_observe(true, [](tBTA_DM_SEARCH_EVT, tBTA_DM_SEARCH*) {}); } TEST_F(BtaInitializedTest, bta_dm_ble_csis_observe__false) { bta_dm_ble_csis_observe(false, [](tBTA_DM_SEARCH_EVT, tBTA_DM_SEARCH*) {}); } TEST_F(BtaInitializedTest, bta_dm_ble_scan) { // bool start, uint8_t duration_sec constexpr bool kStartLeScan = true; constexpr bool kStopLeScan = false; const uint8_t duration_in_seconds = 5; bta_dm_ble_scan(kStartLeScan, duration_in_seconds); bta_dm_ble_scan(kStopLeScan, duration_in_seconds); } TEST_F(BtaInitializedTest, bta_dm_disc_discover_next_device) { bta_dm_disc_discover_next_device(); } TEST_F(BtaInitializedTest, bta_dm_disc_remove_device) { bta_dm_disc_remove_device(kRawAddress); } TEST_F(BtaInitializedTest, bta_dm_discover_next_device) { bluetooth::legacy::testing::bta_dm_discover_next_device(); } TEST_F(BtaInitializedTest, bta_dm_sdp_find_services) { std::unique_ptr state = std::make_unique(tBTA_DM_SDP_STATE{ .bd_addr = kRawAddress, .services_to_search = BTA_ALL_SERVICE_MASK, .services_found = 0, .service_index = 0, }); bluetooth::legacy::testing::bta_dm_sdp_find_services(state.get()); } TEST_F(BtaInitializedTest, bta_dm_inq_cmpl) { bluetooth::legacy::testing::bta_dm_inq_cmpl(); } TEST_F(BtaInitializedTest, bta_dm_inq_cmpl_cb) { tBTM_INQUIRY_CMPL complete; bluetooth::legacy::testing::bta_dm_inq_cmpl_cb(&complete); } TEST_F(BtaInitializedTest, bta_dm_observe_cmpl_cb) { tBTM_INQUIRY_CMPL complete; bluetooth::legacy::testing::bta_dm_observe_cmpl_cb(&complete); } TEST_F(BtaInitializedTest, bta_dm_observe_results_cb) { tBTM_INQ_RESULTS result; const uint8_t p_eir[] = {0x0, 0x1, 0x2, 0x3}; uint16_t eir_len = sizeof(p_eir); bluetooth::legacy::testing::bta_dm_observe_results_cb(&result, p_eir, eir_len); } TEST_F(BtaInitializedTest, bta_dm_opportunistic_observe_results_cb) { tBTM_INQ_RESULTS result; const uint8_t p_eir[] = {0x0, 0x1, 0x2, 0x3}; uint16_t eir_len = sizeof(p_eir); bluetooth::legacy::testing::bta_dm_opportunistic_observe_results_cb(&result, p_eir, eir_len); } TEST_F(BtaInitializedTest, bta_dm_queue_search) { tBTA_DM_API_SEARCH search{}; bluetooth::legacy::testing::bta_dm_queue_search(search); // Release the queued search bta_dm_disc_stop(); } TEST_F(BtaInitializedTest, bta_dm_read_remote_device_name) { EXPECT_CALL(mock_stack_rnr_interface_, BTM_ReadRemoteDeviceName(_, _, _)) .WillOnce(Return(tBTM_STATUS::BTM_CMD_STARTED)); bluetooth::legacy::testing::bta_dm_read_remote_device_name(kRawAddress, BT_TRANSPORT_BR_EDR); } TEST_F(BtaInitializedTest, bta_dm_start_scan) { const uint8_t duration_sec = 5; bluetooth::legacy::testing::bta_dm_start_scan(duration_sec); bluetooth::legacy::testing::bta_dm_start_scan(duration_sec); } TEST_F(BtaInitializedTest, bta_dm_disc_start_device_discovery) { bta_dm_disc_start_device_discovery( [](tBTA_DM_SEARCH_EVT /*event*/, tBTA_DM_SEARCH* /*p_data*/) {}); } TEST_F(BtaInitializedTest, bta_dm_disc_stop_device_discovery) { bta_dm_disc_stop_device_discovery(); } TEST_F(BtaInitializedTest, bta_dm_disc_start_service_discovery__BT_TRANSPORT_AUTO) { bta_dm_disc_start_service_discovery( {nullptr, nullptr, [](RawAddress, const std::vector&, tBTA_STATUS) {}}, kRawAddress, BT_TRANSPORT_AUTO); } // must be global, as capturing lambda can't be treated as function int service_cb_call_cnt = 0; TEST_F(BtaInitializedTest, bta_dm_disc_start_service_discovery__BT_TRANSPORT_BR_EDR) { bta_dm_disc_start(true); int sdp_call_cnt = 0; base::RepeatingCallback sdp_performer = base::BindLambdaForTesting([&](tBTA_DM_SDP_STATE* sdp_state) { sdp_call_cnt++; bta_dm_sdp_finished(sdp_state->bd_addr, BTA_SUCCESS, {}, {}); }); bta_dm_disc_override_sdp_performer_for_testing(sdp_performer); service_cb_call_cnt = 0; bta_dm_disc_start_service_discovery({nullptr, nullptr, [](RawAddress /*addr*/, const std::vector&, tBTA_STATUS) { service_cb_call_cnt++; }}, kRawAddress, BT_TRANSPORT_BR_EDR); EXPECT_EQ(sdp_call_cnt, 1); EXPECT_EQ(service_cb_call_cnt, 1); bta_dm_disc_override_sdp_performer_for_testing({}); } // must be global, as capturing lambda can't be treated as function int gatt_service_cb_call_cnt = 0; TEST_F(BtaInitializedTest, bta_dm_disc_start_service_discovery__BT_TRANSPORT_LE) { bta_dm_disc_start(true); int gatt_call_cnt = 0; base::RepeatingCallback gatt_performer = base::BindLambdaForTesting([&](const RawAddress& bd_addr) { gatt_call_cnt++; bta_dm_gatt_finished(bd_addr, BTA_SUCCESS); }); bta_dm_disc_override_gatt_performer_for_testing(gatt_performer); gatt_service_cb_call_cnt = 0; bta_dm_disc_start_service_discovery({[](RawAddress, std::vector&, bool) { gatt_service_cb_call_cnt++; }, nullptr, nullptr}, kRawAddress, BT_TRANSPORT_LE); EXPECT_EQ(gatt_call_cnt, 1); EXPECT_EQ(gatt_service_cb_call_cnt, 1); bta_dm_disc_override_gatt_performer_for_testing({}); } // must be global, as capturing lambda can't be treated as function int service_cb_both_call_cnt = 0; int gatt_service_cb_both_call_cnt = 0; /* This test exercises the usual service discovery flow when bonding to * dual-mode, CTKD capable device on LE transport. */ TEST_F_WITH_FLAGS(BtaInitializedTest, bta_dm_disc_both_transports_flag_disabled, REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(TEST_BT, bta_dm_discover_both))) { bta_dm_disc_start(true); std::promise gatt_triggered; int gatt_call_cnt = 0; base::RepeatingCallback gatt_performer = base::BindLambdaForTesting([&](const RawAddress& /*bd_addr*/) { gatt_call_cnt++; gatt_triggered.set_value(); }); bta_dm_disc_override_gatt_performer_for_testing(gatt_performer); int sdp_call_cnt = 0; base::RepeatingCallback sdp_performer = base::BindLambdaForTesting([&](tBTA_DM_SDP_STATE* /*sdp_state*/) { sdp_call_cnt++; }); bta_dm_disc_override_sdp_performer_for_testing(sdp_performer); gatt_service_cb_both_call_cnt = 0; service_cb_both_call_cnt = 0; bta_dm_disc_start_service_discovery( {[](RawAddress, std::vector&, bool) {}, nullptr, [](RawAddress /*addr*/, const std::vector&, tBTA_STATUS) { service_cb_both_call_cnt++; }}, kRawAddress, BT_TRANSPORT_BR_EDR); EXPECT_EQ(sdp_call_cnt, 1); bta_dm_disc_start_service_discovery( {[](RawAddress, std::vector&, bool) { gatt_service_cb_both_call_cnt++; }, nullptr, [](RawAddress /*addr*/, const std::vector&, tBTA_STATUS) {}}, kRawAddress, BT_TRANSPORT_LE); // GATT discovery is queued, until SDP finishes EXPECT_EQ(gatt_call_cnt, 0); bta_dm_sdp_finished(kRawAddress, BTA_SUCCESS, {}, {}); EXPECT_EQ(service_cb_both_call_cnt, 1); // SDP finished, wait until GATT is triggered. EXPECT_EQ(std::future_status::ready, gatt_triggered.get_future().wait_for(std::chrono::seconds(1))); bta_dm_gatt_finished(kRawAddress, BTA_SUCCESS); EXPECT_EQ(gatt_service_cb_both_call_cnt, 1); bta_dm_disc_override_sdp_performer_for_testing({}); bta_dm_disc_override_gatt_performer_for_testing({}); } /* This test exercises the usual service discovery flow when bonding to * dual-mode, CTKD capable device on LE transport. */ TEST_F_WITH_FLAGS(BtaInitializedTest, bta_dm_disc_both_transports_flag_enabled, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, bta_dm_discover_both))) { bta_dm_disc_start(true); int gatt_call_cnt = 0; base::RepeatingCallback gatt_performer = base::BindLambdaForTesting([&](const RawAddress& /*bd_addr*/) { gatt_call_cnt++; }); bta_dm_disc_override_gatt_performer_for_testing(gatt_performer); int sdp_call_cnt = 0; base::RepeatingCallback sdp_performer = base::BindLambdaForTesting([&](tBTA_DM_SDP_STATE* /*sdp_state*/) { sdp_call_cnt++; }); bta_dm_disc_override_sdp_performer_for_testing(sdp_performer); gatt_service_cb_both_call_cnt = 0; service_cb_both_call_cnt = 0; bta_dm_disc_start_service_discovery( {[](RawAddress, std::vector&, bool) { gatt_service_cb_both_call_cnt++; }, nullptr, [](RawAddress /*addr*/, const std::vector&, tBTA_STATUS) { service_cb_both_call_cnt++; }}, kRawAddress, BT_TRANSPORT_BR_EDR); EXPECT_EQ(sdp_call_cnt, 1); bta_dm_disc_start_service_discovery( {[](RawAddress, std::vector&, bool) { gatt_service_cb_both_call_cnt++; }, nullptr, [](RawAddress /*addr*/, const std::vector&, tBTA_STATUS) { service_cb_both_call_cnt++; }}, kRawAddress, BT_TRANSPORT_LE); // GATT discovery on same device is immediately started EXPECT_EQ(gatt_call_cnt, 1); // GATT finished first bta_dm_gatt_finished(kRawAddress, BTA_SUCCESS); EXPECT_EQ(gatt_service_cb_both_call_cnt, 1); // SDP finishes too bta_dm_sdp_finished(kRawAddress, BTA_SUCCESS, {}, {}); EXPECT_EQ(service_cb_both_call_cnt, 1); bta_dm_disc_override_sdp_performer_for_testing({}); bta_dm_disc_override_gatt_performer_for_testing({}); } TEST_F(BtaInitializedTest, init_bta_dm_search_cb__conn_id) { // Set the global search block target field to some non-reset value tBTA_DM_SEARCH_CB& search_cb = bluetooth::legacy::testing::bta_dm_disc_search_cb(); search_cb.name_discover_done = true; bluetooth::legacy::testing::bta_dm_disc_init_search_cb(search_cb); // Verify global search block field reset value is correct ASSERT_EQ(search_cb.name_discover_done, false); }