diff options
| author | 2025-03-13 18:47:02 +0000 | |
|---|---|---|
| committer | 2025-03-14 15:30:14 -0700 | |
| commit | e9d0c64bc947a38d6d51958359ccd38b67855cd6 (patch) | |
| tree | 2f13fedc8e83e32eda1743960e85d9b8164da56e | |
| parent | 96641c762aa6160a7598dc0c41ba1e0aac3cab17 (diff) | |
Fixes bugs about the procedure enabled.
1. scheule procedure enable command for failure retry
2. clear the procedure data only when the session is stopped.
3. work around a controller problem - got DISABLE complete for ENABLE
command
Flag: EXEMPT critical bug fixes, flag was in nextfood
Bug: 403547016
Test: atest --host bluetooth_test_gd_unit
Change-Id: Ie63cba5673e847a9d1b607c855003db77c96d075
| -rw-r--r-- | system/gd/Android.bp | 3 | ||||
| -rw-r--r-- | system/gd/hci/distance_measurement_manager.cc | 108 | ||||
| -rw-r--r-- | system/gd/hci/distance_measurement_manager_test.cc | 179 |
3 files changed, 244 insertions, 46 deletions
diff --git a/system/gd/Android.bp b/system/gd/Android.bp index 26f31f0b8e..6d708f1370 100644 --- a/system/gd/Android.bp +++ b/system/gd/Android.bp @@ -414,6 +414,9 @@ cc_test { "storage/mutation_test.cc", "storage/storage_module_test.cc", ], + cflags: [ + "-DUSE_FAKE_TIMERS", + ], static_libs: [ "bluetooth_flags_c_lib_for_test", "libbase", diff --git a/system/gd/hci/distance_measurement_manager.cc b/system/gd/hci/distance_measurement_manager.cc index 6bdfde00b9..6e57f2c9d5 100644 --- a/system/gd/hci/distance_measurement_manager.cc +++ b/system/gd/hci/distance_measurement_manager.cc @@ -441,6 +441,8 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { it->second.measurement_ongoing = true; it->second.waiting_for_start_callback = true; it->second.local_hci_role = local_hci_role; + it->second.retry_counter_for_create_config = 0; + it->second.retry_counter_for_cs_enable = 0; return true; } @@ -845,6 +847,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { static void reset_tracker_on_stopped(CsTracker& cs_tracker) { cs_tracker.measurement_ongoing = false; cs_tracker.state = CsTrackerState::STOPPED; + cs_tracker.procedure_data_list.clear(); } void handle_cs_setup_failure(uint16_t connection_handle, DistanceMeasurementErrorCode errorCode) { @@ -906,7 +909,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { if (cs_requester_trackers_.find(connection_handle) != cs_requester_trackers_.end()) { reset_tracker_on_stopped(cs_requester_trackers_[connection_handle]); } - } else if (status_view.GetStatus() != ErrorCode::SUCCESS) { + } else if (enable == Enable::ENABLED && status_view.GetStatus() != ErrorCode::SUCCESS) { if (cs_requester_trackers_.count(connection_handle) == 0) { log::error("Error code {} for connection_handle {}. No request tracker found.", ErrorCodeText(status), connection_handle); @@ -919,6 +922,14 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { if (cs_requester_trackers_[connection_handle].retry_counter_for_cs_enable++ >= kMaxRetryCounterForCsEnable) { handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR); + } else { + cs_requester_trackers_[connection_handle].procedure_schedule_guard_alarm->Cancel(); + log::info("schedule next procedure enable after {} ms", + cs_requester_trackers_[connection_handle].interval_ms); + cs_requester_trackers_[connection_handle].procedure_schedule_guard_alarm->Schedule( + common::Bind(&impl::send_le_cs_procedure_enable, common::Unretained(this), + connection_handle, Enable::ENABLED), + std::chrono::milliseconds(cs_requester_trackers_[connection_handle].interval_ms)); } } } @@ -1237,25 +1248,8 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { void on_cs_procedure_enable_complete(LeCsProcedureEnableCompleteView event_view) { log::assert_that(event_view.IsValid(), "assert failed: event_view.IsValid()"); uint16_t connection_handle = event_view.GetConnectionHandle(); - log::debug("on cs procedure enabled complete"); - if (event_view.GetStatus() != ErrorCode::SUCCESS) { - std::string error_code = ErrorCodeText(event_view.GetStatus()); - if (cs_requester_trackers_.count(connection_handle) == 0) { - log::warn( - "Received LeCsProcedureEnableCompleteView with error code {}, No request tracker " - "found", - error_code); - handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR); - return; - } - log::warn("Received LeCsProcedureEnableCompleteView with error code {}. Retry counter {}", - error_code, cs_requester_trackers_[connection_handle].retry_counter_for_cs_enable); - if (cs_requester_trackers_[connection_handle].retry_counter_for_cs_enable++ >= - kMaxRetryCounterForCsEnable) { - handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR); - } - return; - } + log::debug("Procedure enabled, {}", event_view.ToString()); + uint8_t config_id = event_view.GetConfigId(); CsTracker* live_tracker = nullptr; @@ -1272,7 +1266,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { live_tracker = get_live_tracker(connection_handle, config_id, valid_requester_states, valid_responder_states); if (live_tracker == nullptr) { - log::error("no tracker is available for {}", connection_handle); + log::error("enable - no tracker is available for {}", connection_handle); return; } if (live_tracker->used_config_id != config_id) { @@ -1280,7 +1274,22 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { live_tracker->used_config_id); return; } - log::debug("Procedure enabled, {}", event_view.ToString()); + + if (live_tracker->local_start && event_view.GetStatus() != ErrorCode::SUCCESS) { + log::warn("Received LeCsProcedureEnableCompleteView with error code {}. Retry counter {}", + ErrorCodeText(event_view.GetStatus()), live_tracker->retry_counter_for_cs_enable); + if (live_tracker->retry_counter_for_cs_enable++ >= kMaxRetryCounterForCsEnable) { + handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR); + } else { + live_tracker->procedure_schedule_guard_alarm->Cancel(); + log::info("schedule next procedure enable after {} ms", live_tracker->interval_ms); + live_tracker->procedure_schedule_guard_alarm->Schedule( + common::Bind(&impl::send_le_cs_procedure_enable, common::Unretained(this), + connection_handle, Enable::ENABLED), + std::chrono::milliseconds(live_tracker->interval_ms)); + } + return; + } live_tracker->state = CsTrackerState::STARTED; live_tracker->selected_tx_power = event_view.GetSelectedTxPower(); live_tracker->n_procedure_count = event_view.GetProcedureCount(); @@ -1297,38 +1306,45 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback { if (live_tracker->n_procedure_count >= 1) { live_tracker->procedure_schedule_guard_alarm->Cancel(); log::info("schedule next procedure enable after {} ms", schedule_interval); - cs_requester_trackers_[connection_handle].procedure_schedule_guard_alarm->Schedule( + live_tracker->procedure_schedule_guard_alarm->Schedule( common::Bind(&impl::send_le_cs_procedure_enable, common::Unretained(this), connection_handle, Enable::ENABLED), std::chrono::milliseconds(schedule_interval)); } - } - if (live_tracker->local_start && live_tracker->waiting_for_start_callback) { - live_tracker->waiting_for_start_callback = false; - distance_measurement_callbacks_->OnDistanceMeasurementStarted(live_tracker->address, - METHOD_CS); - } - if (live_tracker->local_start && is_hal_v2()) { - // reset the procedure sequence - live_tracker->procedure_sequence_after_enable = -1; - ranging_hal_->UpdateProcedureEnableConfig(connection_handle, event_view); + if (live_tracker->waiting_for_start_callback) { + live_tracker->waiting_for_start_callback = false; + distance_measurement_callbacks_->OnDistanceMeasurementStarted(live_tracker->address, + METHOD_CS); + } + if (is_hal_v2()) { + // reset the procedure sequence + live_tracker->procedure_sequence_after_enable = -1; + ranging_hal_->UpdateProcedureEnableConfig(connection_handle, event_view); + } } } else if (event_view.GetState() == Enable::DISABLED) { - uint8_t valid_requester_states = static_cast<uint8_t>(CsTrackerState::STARTED); - uint8_t valid_responder_states = static_cast<uint8_t>(CsTrackerState::STARTED); - live_tracker = get_live_tracker(connection_handle, config_id, valid_requester_states, - valid_responder_states); - if (live_tracker == nullptr) { - log::error("no tracker is available for {}", connection_handle); - return; + if (event_view.GetStatus() == ErrorCode::SUCCESS) { + // local or remote host requested it. + uint8_t valid_requester_states = static_cast<uint8_t>(CsTrackerState::STARTED); + uint8_t valid_responder_states = static_cast<uint8_t>(CsTrackerState::STARTED); + live_tracker = get_live_tracker(connection_handle, config_id, valid_requester_states, + valid_responder_states); + if (live_tracker == nullptr) { + log::error("disable - no tracker is available for {}", connection_handle); + return; + } + reset_tracker_on_stopped(*live_tracker); + } else { + // work around, controller may send 'DISABLE' complete with error for 'ENABLE' command + auto req_it = cs_requester_trackers_.find(connection_handle); + if (req_it != cs_requester_trackers_.end() && + req_it->second.state == CsTrackerState::WAIT_FOR_PROCEDURE_ENABLED && + config_id == req_it->second.used_config_id) { + log::warn("expect ENABLE complete, bug got DISABLE complete."); + handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR); + } } - reset_tracker_on_stopped(*live_tracker); - } - // reset the procedure data list. - std::vector<CsProcedureData>& data_list = live_tracker->procedure_data_list; - while (!data_list.empty()) { - data_list.erase(data_list.begin()); } } diff --git a/system/gd/hci/distance_measurement_manager_test.cc b/system/gd/hci/distance_measurement_manager_test.cc index 8679ec27e3..35a629c53a 100644 --- a/system/gd/hci/distance_measurement_manager_test.cc +++ b/system/gd/hci/distance_measurement_manager_test.cc @@ -21,6 +21,7 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> +#include "common/bind.h" #include "common/strings.h" #include "hal/ranging_hal.h" #include "hal/ranging_hal_mock.h" @@ -32,9 +33,12 @@ #include "hci/hci_layer.h" #include "hci/hci_layer_fake.h" #include "module.h" +#include "os/fake_timer/fake_timerfd.h" #include "packet/packet_view.h" #include "ras/ras_packets.h" +using bluetooth::os::fake_timer::fake_timerfd_advance; +using bluetooth::os::fake_timer::fake_timerfd_reset; using testing::_; using testing::AtLeast; using testing::Return; @@ -42,6 +46,7 @@ using testing::Return; namespace { static constexpr auto kTimeout = std::chrono::seconds(1); static constexpr uint8_t kMaxRetryCounterForCreateConfig = 0x03; +static constexpr uint8_t kMaxRetryCounterForCsEnable = 0x03; } namespace bluetooth { @@ -140,6 +145,20 @@ struct CsConfigCompleteEvent { } }; +struct CsProcedureEnableCompleteEvent { + ErrorCode status = ErrorCode::SUCCESS; + uint8_t config_id = 0; + uint8_t tone_antenna_config_selection = 0; + uint8_t selected_tx_power = 0; // -127 to 20 dBm + uint32_t subevent_len = 2500; // 1250us to 4s + uint8_t subevents_per_event = 1; // 0x01 to 0x20 + uint16_t subevent_interval = 1; // N x 0.625ms + uint16_t event_interval = 0; // number of acl conn interval + uint16_t procedure_interval = 2; // number of acl conn interval + uint16_t procedure_count = 5; // 0x0001 to 0xFFFF + uint16_t max_procedure_len = 10; // N x 0.625 ms +}; + struct StartMeasurementParameters { Address remote_address = Address::FromString("12:34:56:78:9a:bc").value(); uint16_t connection_handle = 64; @@ -165,6 +184,7 @@ protected: EXPECT_CALL(*mock_controller_, SupportsBleChannelSounding()).WillOnce(Return(true)); EXPECT_CALL(*mock_ranging_hal_, IsBound()).Times(AtLeast(1)).WillRepeatedly(Return(true)); + EXPECT_CALL(*mock_ranging_hal_, GetRangingHalVersion).WillRepeatedly(Return(hal::V_2)); handler_ = fake_registry_.GetTestHandler(); dm_manager_ = fake_registry_.Start<DistanceMeasurementManager>(&thread_, handler_); @@ -184,6 +204,19 @@ protected: return dm_session_promise_->get_future(); } + std::future<void> fake_timer_advance(uint64_t ms) { + std::promise<void> promise; + auto future = promise.get_future(); + handler_->Post(common::BindOnce( + [](std::promise<void> promise, uint64_t ms) { + fake_timerfd_advance(ms); + promise.set_value(); + }, + common::Passed(std::move(promise)), ms)); + + return future; + } + void sync_client_handler() { log::assert_that(thread_.GetReactor()->WaitForIdle(kTimeout), "assert failed: thread_.GetReactor()->WaitForIdle(kTimeout)"); @@ -248,6 +281,18 @@ protected: complete_event.t_fcs_time, complete_event.t_pm_time); } + static std::unique_ptr<LeCsProcedureEnableCompleteBuilder> GetProcedureEnableCompleteEvent( + uint16_t connection_handle, Enable enable, + CsProcedureEnableCompleteEvent complete_event) { + return LeCsProcedureEnableCompleteBuilder::Create( + complete_event.status, connection_handle, complete_event.config_id, enable, + complete_event.tone_antenna_config_selection, complete_event.selected_tx_power, + complete_event.subevent_len, complete_event.subevents_per_event, + complete_event.subevent_interval, complete_event.event_interval, + complete_event.procedure_interval, complete_event.procedure_count, + complete_event.max_procedure_len); + } + void StartMeasurement(const StartMeasurementParameters& params) { dm_manager_->StartDistanceMeasurement(params.remote_address, params.connection_handle, params.local_hci_role, params.interval, params.method); @@ -281,8 +326,48 @@ protected: test_hci_layer_->GetCommand(OpCode::LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES); CsReadCapabilitiesCompleteEvent read_cs_complete_event; + test_hci_layer_->IncomingEvent(LeCsReadRemoteSupportedCapabilitiesStatusBuilder::Create( + /*status=*/ErrorCode::SUCCESS, + /*num_hci_command_packets=*/0xFF)); test_hci_layer_->IncomingLeMetaEvent(GetRemoteSupportedCapabilitiesCompleteEvent( params.connection_handle, read_cs_complete_event)); + + test_hci_layer_->GetCommand(OpCode::LE_CS_SET_DEFAULT_SETTINGS); + test_hci_layer_->IncomingEvent(LeCsSetDefaultSettingsCompleteBuilder::Create( + /*num_hci_command_packets=*/static_cast<uint8_t>(0xEE), ErrorCode::SUCCESS, + params.connection_handle)); + } + + void StartMeasurementTillCreateConfig(const StartMeasurementParameters& params) { + StartMeasurementTillReadRemoteCaps(params); + + CsConfigCompleteEvent cs_config_complete_event; + test_hci_layer_->GetCommand(OpCode::LE_CS_CREATE_CONFIG); + test_hci_layer_->IncomingEvent(LeCsCreateConfigStatusBuilder::Create( + /*status=*/ErrorCode::SUCCESS, + /*num_hci_command_packets=*/0xFF)); + test_hci_layer_->IncomingLeMetaEvent( + GetConfigCompleteEvent(params.connection_handle, cs_config_complete_event)); + } + + void StartMeasurementTillSecurityEnable(const StartMeasurementParameters& params) { + StartMeasurementTillCreateConfig(params); + + test_hci_layer_->GetCommand(OpCode::LE_CS_SECURITY_ENABLE); + test_hci_layer_->IncomingEvent(LeCsSecurityEnableStatusBuilder::Create( + /*status=*/ErrorCode::SUCCESS, + /*num_hci_command_packets=*/0xFF)); + test_hci_layer_->IncomingLeMetaEvent(LeCsSecurityEnableCompleteBuilder::Create( + ErrorCode::SUCCESS, params.connection_handle)); + } + + void StartMeasurementTillSetProcedureParameters(const StartMeasurementParameters& params) { + StartMeasurementTillSecurityEnable(params); + + test_hci_layer_->GetCommand(OpCode::LE_CS_SET_PROCEDURE_PARAMETERS); + test_hci_layer_->IncomingEvent(LeCsSetProcedureParametersCompleteBuilder::Create( + /*num_hci_command_packets=*/static_cast<uint8_t>(0xEE), ErrorCode::SUCCESS, + params.connection_handle)); } protected: @@ -373,6 +458,7 @@ TEST_F(DistanceMeasurementManagerTest, error_read_remote_cs_caps_command) { test_hci_layer_->IncomingEvent(LeCsReadRemoteSupportedCapabilitiesStatusBuilder::Create( /*status=*/ErrorCode::COMMAND_DISALLOWED, /*num_hci_command_packets=*/0xff)); + sync_client_handler(); } TEST_F(DistanceMeasurementManagerTest, fail_read_remote_cs_caps_complete) { @@ -396,6 +482,7 @@ TEST_F(DistanceMeasurementManagerTest, fail_read_remote_cs_caps_complete) { read_cs_complete_event.error_code = ErrorCode::COMMAND_DISALLOWED; test_hci_layer_->IncomingLeMetaEvent(GetRemoteSupportedCapabilitiesCompleteEvent( params.connection_handle, read_cs_complete_event)); + sync_client_handler(); } TEST_F(DistanceMeasurementManagerTest, error_create_config_command) { @@ -418,6 +505,7 @@ TEST_F(DistanceMeasurementManagerTest, error_create_config_command) { test_hci_layer_->IncomingEvent(LeCsCreateConfigStatusBuilder::Create( /*status=*/ErrorCode::COMMAND_DISALLOWED, /*num_hci_command_packets=*/0xff)); + sync_client_handler(); } TEST_F(DistanceMeasurementManagerTest, fail_create_config_complete) { @@ -443,6 +531,97 @@ TEST_F(DistanceMeasurementManagerTest, fail_create_config_complete) { test_hci_layer_->IncomingLeMetaEvent( GetConfigCompleteEvent(params.connection_handle, cs_config_complete_event)); } + sync_client_handler(); +} + +TEST_F(DistanceMeasurementManagerTest, retry_fail_procedure_enable_command) { + auto dm_session_future = GetDmSessionFuture(); + StartMeasurementParameters params; + StartMeasurementTillSetProcedureParameters(params); + + EXPECT_CALL(mock_dm_callbacks_, + OnDistanceMeasurementStopped(params.remote_address, + DistanceMeasurementErrorCode::REASON_INTERNAL_ERROR, + DistanceMeasurementMethod::METHOD_CS)) + .WillOnce([this](const Address& /*address*/, DistanceMeasurementErrorCode /*error_code*/, + DistanceMeasurementMethod /*method*/) { + ASSERT_NE(dm_session_promise_, nullptr); + dm_session_promise_->set_value(); + dm_session_promise_.reset(); + }); + + for (int i = 0; i <= kMaxRetryCounterForCsEnable; i++) { + test_hci_layer_->GetCommand(OpCode::LE_CS_PROCEDURE_ENABLE); + test_hci_layer_->IncomingEvent(LeCsProcedureEnableStatusBuilder::Create( + /*status=*/ErrorCode::COMMAND_DISALLOWED, + /*num_hci_command_packets=*/0xff)); + auto future = fake_timer_advance(params.interval + 10); + future.wait_for(kTimeout); + sync_client_handler(); + } + fake_timerfd_reset(); + sync_client_handler(); +} + +TEST_F(DistanceMeasurementManagerTest, retry_fail_procedure_enable_complete) { + auto dm_session_future = GetDmSessionFuture(); + StartMeasurementParameters params; + StartMeasurementTillSetProcedureParameters(params); + + EXPECT_CALL(mock_dm_callbacks_, + OnDistanceMeasurementStopped(params.remote_address, + DistanceMeasurementErrorCode::REASON_INTERNAL_ERROR, + DistanceMeasurementMethod::METHOD_CS)) + .WillOnce([this](const Address& /*address*/, DistanceMeasurementErrorCode /*error_code*/, + DistanceMeasurementMethod /*method*/) { + ASSERT_NE(dm_session_promise_, nullptr); + dm_session_promise_->set_value(); + dm_session_promise_.reset(); + }); + + CsProcedureEnableCompleteEvent complete_event; + complete_event.status = ErrorCode::LINK_LAYER_COLLISION; + for (int i = 0; i <= kMaxRetryCounterForCsEnable; i++) { + test_hci_layer_->GetCommand(OpCode::LE_CS_PROCEDURE_ENABLE); + test_hci_layer_->IncomingEvent(LeCsProcedureEnableStatusBuilder::Create( + /*status=*/ErrorCode::SUCCESS, + /*num_hci_command_packets=*/0xff)); + test_hci_layer_->IncomingLeMetaEvent(GetProcedureEnableCompleteEvent( + params.connection_handle, Enable::ENABLED, complete_event)); + auto future = fake_timer_advance(params.interval + 10); + future.wait_for(kTimeout); + sync_client_handler(); + } + fake_timerfd_reset(); + sync_client_handler(); +} + +TEST_F(DistanceMeasurementManagerTest, unexpected_procedure_enable_complete_as_disable) { + auto dm_session_future = GetDmSessionFuture(); + StartMeasurementParameters params; + StartMeasurementTillSetProcedureParameters(params); + + EXPECT_CALL(mock_dm_callbacks_, + OnDistanceMeasurementStopped(params.remote_address, + DistanceMeasurementErrorCode::REASON_INTERNAL_ERROR, + DistanceMeasurementMethod::METHOD_CS)) + .WillOnce([this](const Address& /*address*/, DistanceMeasurementErrorCode /*error_code*/, + DistanceMeasurementMethod /*method*/) { + ASSERT_NE(dm_session_promise_, nullptr); + dm_session_promise_->set_value(); + dm_session_promise_.reset(); + }); + + test_hci_layer_->GetCommand(OpCode::LE_CS_PROCEDURE_ENABLE); + test_hci_layer_->IncomingEvent(LeCsProcedureEnableStatusBuilder::Create( + /*status=*/ErrorCode::SUCCESS, + /*num_hci_command_packets=*/0xff)); + CsProcedureEnableCompleteEvent complete_event; + complete_event.status = ErrorCode::LINK_LAYER_COLLISION; + test_hci_layer_->IncomingLeMetaEvent(GetProcedureEnableCompleteEvent( + params.connection_handle, Enable::DISABLED, complete_event)); + + sync_client_handler(); } } // namespace |