diff options
author | Jacob Keeler <jacob.keeler@livioradio.com> | 2018-05-16 08:00:31 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-05-16 08:00:31 -0700 |
commit | 65c1e7eb77fa949cce9c07f229e2cf747f297e14 (patch) | |
tree | cba393e5de7af28eecd97d8788b9e2c0470cdb87 | |
parent | 1fa0f493c60b09b90db55de7b16a86c7ba8c82d2 (diff) | |
parent | 028ca237522c1c1693ca54049cf462a5122598e4 (diff) | |
download | sdl_core-65c1e7eb77fa949cce9c07f229e2cf747f297e14.tar.gz |
Merge pull request #2101 from smartdevicelink/fix/event_dispatcher_crashsubmenu_icon
Fix EventDispatcher crash by rejecting duplicate correlation_ids
3 files changed, 77 insertions, 1 deletions
diff --git a/src/components/application_manager/include/application_manager/request_controller.h b/src/components/application_manager/include/application_manager/request_controller.h index d3a5a0b821..c0bae1aac8 100644 --- a/src/components/application_manager/include/application_manager/request_controller.h +++ b/src/components/application_manager/include/application_manager/request_controller.h @@ -289,6 +289,13 @@ class RequestController { */ std::list<RequestPtr> notification_list_; + /** + * @brief Map keeping track of how many duplicate messages were sent for a + * given correlation id, to prevent early termination of a request + */ + std::map<uint32_t, uint32_t> duplicate_message_count_; + sync_primitives::Lock duplicate_message_count_lock_; + /* * timer for checking requests timeout */ diff --git a/src/components/application_manager/src/request_controller.cc b/src/components/application_manager/src/request_controller.cc index 1b9bd7ffb9..f341967842 100644 --- a/src/components/application_manager/src/request_controller.cc +++ b/src/components/application_manager/src/request_controller.cc @@ -50,6 +50,7 @@ RequestController::RequestController(const RequestControlerSettings& settings) : pool_state_(UNDEFINED) , pool_size_(settings.thread_pool_size()) , request_tracker_(settings) + , duplicate_message_count_() , timer_("AM RequestCtrlTimer", new timer::TimerTaskImpl<RequestController>( this, &RequestController::TimeoutThread)) @@ -230,6 +231,21 @@ void RequestController::TerminateRequest(const uint32_t correlation_id, << correlation_id << " connection_key = " << connection_key << " function_id = " << function_id << " force_terminate = " << force_terminate); + { + AutoLock auto_lock(duplicate_message_count_lock_); + auto dup_it = duplicate_message_count_.find(correlation_id); + if (duplicate_message_count_.end() != dup_it) { + duplicate_message_count_[correlation_id]--; + if (0 == duplicate_message_count_[correlation_id]) { + duplicate_message_count_.erase(dup_it); + } + LOG4CXX_DEBUG(logger_, + "Ignoring termination request due to duplicate correlation " + "ID being sent"); + return; + } + } + RequestInfoPtr request = waiting_for_response_.Find(connection_key, correlation_id); if (!request) { @@ -474,7 +490,24 @@ void RequestController::Worker::threadMain() { RequestInfoPtr request_info_ptr = utils::MakeShared<MobileRequestInfo>(request_ptr, timeout_in_mseconds); - request_controller_->waiting_for_response_.Add(request_info_ptr); + if (!request_controller_->waiting_for_response_.Add(request_info_ptr)) { + commands::CommandRequestImpl* cmd_request = + dynamic_cast<commands::CommandRequestImpl*>(request_ptr.get()); + if (cmd_request != NULL) { + uint32_t corr_id = cmd_request->correlation_id(); + request_controller_->duplicate_message_count_lock_.Acquire(); + auto dup_it = + request_controller_->duplicate_message_count_.find(corr_id); + if (request_controller_->duplicate_message_count_.end() == dup_it) { + request_controller_->duplicate_message_count_[corr_id] = 0; + } + request_controller_->duplicate_message_count_[corr_id]++; + request_controller_->duplicate_message_count_lock_.Release(); + cmd_request->SendResponse( + false, mobile_apis::Result::INVALID_ID, "Duplicate correlation_id"); + } + continue; + } LOG4CXX_DEBUG(logger_, "timeout_in_mseconds " << timeout_in_mseconds); if (0 != timeout_in_mseconds) { diff --git a/src/components/application_manager/test/request_controller/request_controller_test.cc b/src/components/application_manager/test/request_controller/request_controller_test.cc index e053d51c34..c2912fdc0b 100644 --- a/src/components/application_manager/test/request_controller/request_controller_test.cc +++ b/src/components/application_manager/test/request_controller/request_controller_test.cc @@ -62,6 +62,7 @@ using ::application_manager::request_controller::RequestInfo; using ::testing::Return; using ::testing::ReturnRef; using ::testing::NiceMock; +using ::testing::_; typedef NiceMock<application_manager_test::MockRequest> MRequest; typedef utils::SharedPtr<MRequest> RequestPtr; @@ -114,6 +115,7 @@ class RequestControllerTestClass : public ::testing::Test { RequestPtr output = utils::MakeShared<MRequest>(connection_key, correlation_id); ON_CALL(*output, default_timeout()).WillByDefault(Return(default_timeout)); + ON_CALL(*output, CheckPermissions()).WillByDefault(Return(true)); return output; } @@ -159,6 +161,40 @@ class RequestControllerTestClass : public ::testing::Test { }; TEST_F(RequestControllerTestClass, + AddMobileRequest_DuplicateCorrelationId_INVALID_ID) { + RequestPtr request_valid = GetMockRequest(); + TestAsyncWaiter waiter_valid; + ON_CALL(*request_valid, default_timeout()).WillByDefault(Return(0)); + EXPECT_CALL(*request_valid, Init()).WillOnce(Return(true)); + EXPECT_CALL(*request_valid, Run()) + .Times(1) + .WillRepeatedly(NotifyTestAsyncWaiter(&waiter_valid)); + + EXPECT_EQ(RequestController::SUCCESS, + AddRequest(default_settings_, + request_valid, + RequestInfo::RequestType::MobileRequest, + mobile_apis::HMILevel::HMI_NONE)); + EXPECT_TRUE(waiter_valid.WaitFor(1, 1000)); + + // The command should not be run if another command with the same + // correlation_id is waiting for a response + RequestPtr request_dup_corr_id = GetMockRequest(); + TestAsyncWaiter waiter_dup; + ON_CALL(*request_dup_corr_id, default_timeout()).WillByDefault(Return(0)); + EXPECT_CALL(*request_dup_corr_id, Init()).WillOnce(Return(true)); + ON_CALL(*request_dup_corr_id, Run()) + .WillByDefault(NotifyTestAsyncWaiter(&waiter_dup)); + + EXPECT_EQ(RequestController::SUCCESS, + AddRequest(default_settings_, + request_dup_corr_id, + RequestInfo::RequestType::MobileRequest, + mobile_apis::HMILevel::HMI_NONE)); + EXPECT_FALSE(waiter_dup.WaitFor(1, 1000)); +} + +TEST_F(RequestControllerTestClass, CheckPosibilitytoAdd_ZeroValueLimiters_SUCCESS) { // Test case than pending_requests_amount, // app_time_scale_max_requests_ and |