diff options
51 files changed, 937 insertions, 203 deletions
diff --git a/src/components/application_manager/include/application_manager/application.h b/src/components/application_manager/include/application_manager/application.h index 2abd2eaea0..7a59263299 100644 --- a/src/components/application_manager/include/application_manager/application.h +++ b/src/components/application_manager/include/application_manager/application.h @@ -981,6 +981,12 @@ class Application : public virtual InitialApplicationData, virtual const std::string& cloud_app_certificate() const = 0; /** + * @brief Check whether the given application is a cloud app. + * @return true if the application is a cloud application, false otherwise. + */ + virtual bool is_cloud_app() const = 0; + + /** * @brief Set cloud app endpoint */ virtual void set_cloud_app_endpoint(const std::string& endpoint) = 0; diff --git a/src/components/application_manager/include/application_manager/application_impl.h b/src/components/application_manager/include/application_manager/application_impl.h index 0b43b014b6..6d627d0c67 100644 --- a/src/components/application_manager/include/application_manager/application_impl.h +++ b/src/components/application_manager/include/application_manager/application_impl.h @@ -444,6 +444,12 @@ class ApplicationImpl : public virtual Application, const std::string& cloud_app_certificate() const OVERRIDE; /** + * @brief Check whether the given application is a cloud app. + * @return true if the application is a cloud application, false otherwise. + */ + bool is_cloud_app() const OVERRIDE; + + /** * @brief Set cloud app endpoint */ void set_cloud_app_endpoint(const std::string& endpoint) OVERRIDE; diff --git a/src/components/application_manager/include/application_manager/application_manager_impl.h b/src/components/application_manager/include/application_manager/application_manager_impl.h index 20b8c561a3..a3e3cece72 100644 --- a/src/components/application_manager/include/application_manager/application_manager_impl.h +++ b/src/components/application_manager/include/application_manager/application_manager_impl.h @@ -367,6 +367,21 @@ class ApplicationManagerImpl const transport_manager::DeviceInfo& device_info, connection_handler::DeviceHandle device_id); + /** + * @brief Notifies the applicaiton manager that a cloud connection status has + * updated and should trigger an UpdateAppList RPC to the HMI + */ + void OnConnectionStatusUpdated(); + + /** + * @brief Retrieve the current connection status of a cloud app + * @param app A cloud application + * @return The current CloudConnectionStatus of app + */ + + hmi_apis::Common_CloudConnectionStatus::eType GetCloudAppConnectionStatus( + ApplicationConstSharedPtr app) const; + /* * @brief Returns unique correlation ID for HMI request * @@ -492,9 +507,6 @@ class ApplicationManagerImpl // typedef for Applications list const iterator typedef ApplictionSet::const_iterator ApplictionSetConstIt; - DataAccessor<AppsWaitRegistrationSet> apps_waiting_for_registration() const; - ApplicationConstSharedPtr waiting_app(const uint32_t hmi_id) const; - /** * @brief Notification from PolicyHandler about PTU. * Compares AppHMIType between saved in app and received from PTU. If they are @@ -1487,12 +1499,28 @@ class ApplicationManagerImpl void AddMockApplication(ApplicationSharedPtr mock_app); /** + * @brief Add a mock application to the pending application list without going + * through the formal registration process. Only for unit testing. + * @param mock_app the mock app to be added to the pending application list + */ + void AddMockPendingApplication(ApplicationSharedPtr mock_app); + + /** * @brief set a mock media manager without running Init(). Only for unit * testing. - * @param mock_app the mock app to be registered + * @param mock_media_manager the mock media manager to be assigned */ void SetMockMediaManager(media_manager::MediaManager* mock_media_manager); + /** + * @brief set a mock rpc service directly. Only for unit + * testing. + * @param mock_app the mock rpc service to be assigned + */ + void SetMockRPCService(rpc_service::RPCService* rpc_service) { + rpc_service_.reset(rpc_service); + } + virtual void SetPluginManager( std::unique_ptr<plugin_manager::RPCPluginManager>& plugin_manager) OVERRIDE { diff --git a/src/components/application_manager/include/application_manager/smart_object_keys.h b/src/components/application_manager/include/application_manager/smart_object_keys.h index 62192da391..5e6a3bb377 100644 --- a/src/components/application_manager/include/application_manager/smart_object_keys.h +++ b/src/components/application_manager/include/application_manager/smart_object_keys.h @@ -76,7 +76,7 @@ extern const char* ngn_media_screen_app_name; extern const char* vr_synonyms; extern const char* uses_vehicle_data; extern const char* is_media_application; -extern const char* greyOut; +extern const char* grey_out; extern const char* language_desired; extern const char* auto_activated_id; extern const char* app_type; @@ -192,6 +192,8 @@ extern const char* enabled; extern const char* cloud_app_auth_token; extern const char* cloud_transport_type; extern const char* hybrid_app_preference; +extern const char* is_cloud_application; +extern const char* cloud_connection_status; // PutFile extern const char* sync_file_name; diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/mobile/register_app_interface_request.h b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/mobile/register_app_interface_request.h index 542fdac5f8..f8be896996 100644 --- a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/mobile/register_app_interface_request.h +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/commands/mobile/register_app_interface_request.h @@ -124,11 +124,14 @@ class RegisterAppInterfaceRequest /** * @brief Sends OnAppRegistered notification to HMI * - *@param application_impl application with changed HMI status - * + * @param app application with changed HMI status + * @param resumption If true, resumption-related parameters will be sent to + *the HMI + * @param need_restore_vr If resumption is true, whether or not VR commands + *should be resumed **/ void SendOnAppRegisteredNotificationToHMI( - const app_mngr::Application& application_impl, + app_mngr::ApplicationConstSharedPtr app, bool resumption = false, bool need_restore_vr = false); /* diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/sdl_activate_app_request.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/sdl_activate_app_request.cc index f89ae1f697..92a7020208 100644 --- a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/sdl_activate_app_request.cc +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/sdl_activate_app_request.cc @@ -115,6 +115,8 @@ void SDLActivateAppRequest::Run() { LOG4CXX_AUTO_TRACE(logger_); using namespace hmi_apis::FunctionID; + ApplicationConstSharedPtr app = + application_manager_.WaitingApplicationByID(app_id()); if (application_manager_.state_controller().IsStateActive( HmiState::STATE_ID_DEACTIVATE_HMI)) { LOG4CXX_DEBUG(logger_, @@ -124,6 +126,16 @@ void SDLActivateAppRequest::Run() { static_cast<eType>(function_id()), hmi_apis::Common_Result::REJECTED, "HMIDeactivate is active"); + } else if (app && !app->IsRegistered() && app->is_cloud_app()) { + LOG4CXX_DEBUG(logger_, "Starting cloud application."); + const ApplicationManagerSettings& settings = + application_manager_.get_settings(); + uint32_t total_retry_timeout = (settings.cloud_app_retry_timeout() * + settings.cloud_app_max_retry_attempts()); + application_manager_.updateRequestTimeout( + 0, correlation_id(), default_timeout_ + total_retry_timeout); + subscribe_on_event(BasicCommunication_OnAppRegistered); + application_manager_.connection_handler().ConnectToDevice(app->device()); } else { const uint32_t application_id = app_id(); policy_handler_.OnActivateApp(application_id, correlation_id()); @@ -181,6 +193,18 @@ void SDLActivateAppRequest::Run() { LOG4CXX_DEBUG(logger_, "Application is registered. Activating."); policy_handler_.OnActivateApp(application_id, correlation_id()); return; + } else if (app_to_activate->is_cloud_app()) { + LOG4CXX_DEBUG(logger_, "Starting cloud application."); + const ApplicationManagerSettings& settings = + application_manager_.get_settings(); + uint32_t total_retry_timeout = (settings.cloud_app_retry_timeout() * + settings.cloud_app_max_retry_attempts()); + application_manager_.updateRequestTimeout( + 0, correlation_id(), default_timeout_ + total_retry_timeout); + subscribe_on_event(BasicCommunication_OnAppRegistered); + application_manager_.connection_handler().ConnectToDevice( + app_to_activate->device()); + return; } connection_handler::DeviceHandle device_handle = app_to_activate->device(); @@ -225,8 +249,10 @@ void SDLActivateAppRequest::onTimeOut() { using namespace hmi_apis::Common_Result; using namespace application_manager; unsubscribe_from_event(BasicCommunication_OnAppRegistered); - SendErrorResponse( - correlation_id(), SDL_ActivateApp, APPLICATION_NOT_REGISTERED, ""); + SendErrorResponse(correlation_id(), + SDL_ActivateApp, + APPLICATION_NOT_REGISTERED, + "App registration timed out"); } void SDLActivateAppRequest::on_event(const event_engine::Event& event) { @@ -262,7 +288,7 @@ uint32_t SDLActivateAppRequest::hmi_app_id( LOG4CXX_DEBUG(logger_, application << " section is absent in the message."); return 0; } - if (so[msg_params][application].keyExists(strings::app_id)) { + if (!so[msg_params][application].keyExists(strings::app_id)) { LOG4CXX_DEBUG(logger_, strings::app_id << " section is absent in the message."); return 0; diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/mobile/register_app_interface_request.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/mobile/register_app_interface_request.cc index 7957d9e055..b346ee5798 100644 --- a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/mobile/register_app_interface_request.cc +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/mobile/register_app_interface_request.cc @@ -346,19 +346,6 @@ void RegisterAppInterfaceRequest::Run() { application->set_msg_version(module_version); } - // For resuming application need to restore hmi_app_id from resumeCtrl - resumption::ResumeCtrl& resumer = application_manager_.resume_controller(); - const std::string& device_mac = application->mac_address(); - - // there is side affect with 2 mobile app with the same mobile app_id - if (resumer.IsApplicationSaved(policy_app_id, device_mac)) { - application->set_hmi_application_id( - resumer.GetHMIApplicationID(policy_app_id, device_mac)); - } else { - application->set_hmi_application_id( - application_manager_.GenerateNewHMIAppID()); - } - application->set_is_media_application( msg_params[strings::is_media_application].asBool()); @@ -451,6 +438,8 @@ void RegisterAppInterfaceRequest::Run() { FillDeviceInfo(&device_info); } + const std::string& device_mac = application->mac_address(); + GetPolicyHandler().SetDeviceInfo(device_mac, device_info); SendRegisterAppInterfaceResponseToMobile(ApplicationType::kNewApplication); @@ -816,8 +805,6 @@ void RegisterAppInterfaceRequest::SendRegisterAppInterfaceResponseToMobile( file_system::FileExists(application->app_icon_path()); SendResponse(true, result_code, add_info.c_str(), &response_params); - SendOnAppRegisteredNotificationToHMI( - *(application.get()), resumption, need_restore_vr); if (msg_params.keyExists(strings::app_hmi_type)) { GetPolicyHandler().SetDefaultHmiTypes(application->policy_app_id(), &(msg_params[strings::app_hmi_type])); @@ -826,6 +813,8 @@ void RegisterAppInterfaceRequest::SendRegisterAppInterfaceResponseToMobile( // Default HMI level should be set before any permissions validation, since it // relies on HMI level. application_manager_.OnApplicationRegistered(application); + SendOnAppRegisteredNotificationToHMI( + application, resumption, need_restore_vr); (*notify_upd_manager)(); // Start PTU after successfull registration @@ -877,9 +866,7 @@ void RegisterAppInterfaceRequest::SendChangeRegistrationOnHMI( } void RegisterAppInterfaceRequest::SendOnAppRegisteredNotificationToHMI( - const app_mngr::Application& application_impl, - bool resumption, - bool need_restore_vr) { + ApplicationConstSharedPtr app, bool resumption, bool need_restore_vr) { using namespace smart_objects; SmartObjectSPtr notification = std::make_shared<SmartObject>(SmartType_Map); if (!notification) { @@ -903,15 +890,15 @@ void RegisterAppInterfaceRequest::SendOnAppRegisteredNotificationToHMI( msg_params[strings::resume_vr_grammars] = need_restore_vr; } - if (application_impl.vr_synonyms()) { - msg_params[strings::vr_synonyms] = *(application_impl.vr_synonyms()); + if (app->vr_synonyms()) { + msg_params[strings::vr_synonyms] = *(app->vr_synonyms()); } - if (application_impl.tts_name()) { - msg_params[strings::tts_name] = *(application_impl.tts_name()); + if (app->tts_name()) { + msg_params[strings::tts_name] = *(app->tts_name()); } - const std::string policy_app_id = application_impl.policy_app_id(); + const std::string policy_app_id = app->policy_app_id(); std::string priority; GetPolicyHandler().GetPriority(policy_app_id, &priority); @@ -921,100 +908,13 @@ void RegisterAppInterfaceRequest::SendOnAppRegisteredNotificationToHMI( msg_params[strings::msg_params] = SmartObject(SmartType_Map); smart_objects::SmartObject& application = msg_params[strings::application]; - application[strings::app_name] = application_impl.name(); - application[strings::app_id] = application_impl.app_id(); - application[hmi_response::policy_app_id] = policy_app_id; - if (file_system::FileExists(application_impl.app_icon_path())) { - application[strings::icon] = application_impl.app_icon_path(); - } - - const smart_objects::SmartObject* ngn_media_screen_name = - application_impl.ngn_media_screen_name(); - if (ngn_media_screen_name) { - application[strings::ngn_media_screen_app_name] = *ngn_media_screen_name; - } - - application[strings::hmi_display_language_desired] = - static_cast<int32_t>(application_impl.ui_language()); - - application[strings::is_media_application] = - application_impl.is_media_application(); - - const smart_objects::SmartObject* app_type = application_impl.app_types(); - if (app_type) { - application[strings::app_type] = *app_type; - } - - const policy::RequestType::State app_request_types_state = - GetPolicyHandler().GetAppRequestTypeState(policy_app_id); - if (policy::RequestType::State::AVAILABLE == app_request_types_state) { - const auto request_types = - GetPolicyHandler().GetAppRequestTypes(policy_app_id); - application[strings::request_type] = SmartObject(SmartType_Array); - smart_objects::SmartObject& request_types_array = - application[strings::request_type]; - - size_t index = 0; - for (auto it : request_types) { - request_types_array[index] = it; - ++index; - } - } else if (policy::RequestType::State::EMPTY == app_request_types_state) { - application[strings::request_type] = SmartObject(SmartType_Array); - } - - const policy::RequestSubType::State app_request_subtypes_state = - GetPolicyHandler().GetAppRequestSubTypeState(policy_app_id); - if (policy::RequestSubType::State::AVAILABLE == app_request_subtypes_state) { - const auto request_subtypes = - GetPolicyHandler().GetAppRequestSubTypes(policy_app_id); - application[strings::request_subtype] = SmartObject(SmartType_Array); - smart_objects::SmartObject& request_subtypes_array = - application[strings::request_subtype]; - - size_t index = 0; - for (auto it : request_subtypes) { - request_subtypes_array[index] = it; - ++index; - } - } else if (policy::RequestSubType::State::EMPTY == - app_request_subtypes_state) { - application[strings::request_subtype] = SmartObject(SmartType_Array); - } - const protocol_handler::SessionObserver& session_observer = application_manager_.connection_handler().get_session_observer(); - - application[strings::device_info] = SmartObject(SmartType_Map); - smart_objects::SmartObject& device_info = application[strings::device_info]; - MessageHelper::CreateDeviceInfo(application_impl.device(), - session_observer, - GetPolicyHandler(), - application_manager_, - &device_info); - - if (application_impl.secondary_device() != 0) { - application[strings::secondary_device_info] = SmartObject(SmartType_Map); - smart_objects::SmartObject& secondary_device_info = - application[strings::secondary_device_info]; - MessageHelper::CreateDeviceInfo(application_impl.secondary_device(), - session_observer, - GetPolicyHandler(), - application_manager_, - &secondary_device_info); - } - - const smart_objects::SmartObject* day_color_scheme = - application_impl.day_color_scheme(); - if (day_color_scheme) { - application[strings::day_color_scheme] = *day_color_scheme; - } - - const smart_objects::SmartObject* night_color_scheme = - application_impl.night_color_scheme(); - if (night_color_scheme) { - application[strings::night_color_scheme] = *night_color_scheme; - } + MessageHelper::CreateHMIApplicationStruct(app, + session_observer, + GetPolicyHandler(), + &application, + application_manager_); DCHECK(rpc_service_.ManageHMICommand(notification)); } diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/sdl_activate_app_request_test.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/sdl_activate_app_request_test.cc index 38cbc7b069..ea345e3b83 100644 --- a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/sdl_activate_app_request_test.cc +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/sdl_activate_app_request_test.cc @@ -61,8 +61,10 @@ using testing::Mock; using testing::Return; using testing::ReturnRef; using testing::Mock; +using testing::Gt; using ::testing::NiceMock; using policy_test::MockPolicyHandlerInterface; +using connection_handler_test::MockConnectionHandler; using am::event_engine::Event; namespace { @@ -148,7 +150,7 @@ TEST_F(SDLActivateAppRequestTest, Run_ActivateApp_SUCCESS) { command->Run(); } -TEST_F(SDLActivateAppRequestTest, DISABLED_Run_DactivateApp_REJECTED) { +TEST_F(SDLActivateAppRequestTest, DISABLED_Run_DeactivateApp_REJECTED) { MessageSharedPtr msg = CreateMessage(); SetCorrelationAndAppID(msg); (*msg)[strings::msg_params][strings::function_id] = @@ -189,6 +191,7 @@ TEST_F(SDLActivateAppRequestTest, FindAppToRegister_SUCCESS) { .WillOnce(Return(false)); EXPECT_CALL(*mock_app, IsRegistered()).WillOnce(Return(false)); + EXPECT_CALL(*mock_app, is_cloud_app()).WillOnce(Return(false)); ON_CALL(*mock_app, device()).WillByDefault(Return(kHandle)); MockAppPtr mock_app_first(CreateMockApp()); @@ -250,6 +253,7 @@ TEST_F(SDLActivateAppRequestTest, DevicesAppsEmpty_SUCCESS) { .WillOnce(Return(false)); EXPECT_CALL(*mock_app, IsRegistered()).WillOnce(Return(false)); + EXPECT_CALL(*mock_app, is_cloud_app()).WillOnce(Return(false)); ON_CALL(*mock_app, device()).WillByDefault(Return(kHandle)); DataAccessor<ApplicationSet> accessor(app_list_, lock_); @@ -336,6 +340,7 @@ TEST_F(SDLActivateAppRequestTest, FirstAppIsForeground_SUCCESS) { EXPECT_CALL(*mock_app, device()).WillOnce(Return(kHandle)); EXPECT_CALL(*mock_app, IsRegistered()).WillOnce(Return(false)); + EXPECT_CALL(*mock_app, is_cloud_app()).WillOnce(Return(false)); EXPECT_CALL(app_mngr_, state_controller()) .WillOnce(ReturnRef(mock_state_controller_)); EXPECT_CALL(mock_state_controller_, @@ -427,6 +432,53 @@ TEST_F(SDLActivateAppRequestTest, FirstAppNotRegistered_SUCCESS) { } #endif +TEST_F(SDLActivateAppRequestTest, WaitingCloudApplication_ConnectDevice) { + MessageSharedPtr msg = CreateMessage(); + SetCorrelationAndAppID(msg); + + std::shared_ptr<SDLActivateAppRequest> command( + CreateCommand<SDLActivateAppRequest>(msg)); + + MockAppPtr mock_app(CreateMockApp()); + + EXPECT_CALL(*mock_app, device()).WillOnce(Return(kHandle)); + EXPECT_CALL(*mock_app, IsRegistered()).WillOnce(Return(false)); + EXPECT_CALL(*mock_app, is_cloud_app()).WillOnce(Return(true)); + + EXPECT_CALL(app_mngr_, application(kAppID)) + .WillOnce(Return(ApplicationSharedPtr())); + EXPECT_CALL(app_mngr_, WaitingApplicationByID(kAppID)) + .WillOnce(Return(mock_app)); + + EXPECT_CALL(app_mngr_, state_controller()) + .WillOnce(ReturnRef(mock_state_controller_)); + EXPECT_CALL(mock_state_controller_, + IsStateActive(am::HmiState::StateID::STATE_ID_DEACTIVATE_HMI)) + .WillOnce(Return(false)); + + const uint16_t kRetries = 3; + const uint32_t kRetryTimeout = 2000; + const uint32_t kMinimumTimeout = kRetries * kRetryTimeout; + + MockApplicationManagerSettings settings; + EXPECT_CALL(settings, cloud_app_max_retry_attempts()) + .WillOnce(Return(kRetries)); + EXPECT_CALL(settings, cloud_app_retry_timeout()) + .WillOnce(Return(kRetryTimeout)); + EXPECT_CALL(app_mngr_, get_settings()).WillOnce(ReturnRef(settings)); + + EXPECT_CALL( + app_mngr_, + updateRequestTimeout(0, kCorrelationID, Gt(kMinimumTimeout))); + + MockConnectionHandler connection_handler; + EXPECT_CALL(connection_handler, ConnectToDevice(kHandle)); + + EXPECT_CALL(app_mngr_, connection_handler()).WillOnce(ReturnRef(connection_handler)); + + command->Run(); +} + TEST_F(SDLActivateAppRequestTest, OnTimeout_SUCCESS) { MessageSharedPtr msg = CreateMessage(); SetCorrelationAndAppID(msg); diff --git a/src/components/application_manager/src/application_impl.cc b/src/components/application_manager/src/application_impl.cc index 558a4638c1..80b25dc814 100644 --- a/src/components/application_manager/src/application_impl.cc +++ b/src/components/application_manager/src/application_impl.cc @@ -1184,6 +1184,11 @@ const std::string& ApplicationImpl::cloud_app_certificate() const { return certificate_; } +bool ApplicationImpl::is_cloud_app() const { + return !endpoint_.empty() && + hybrid_app_preference_ != mobile_apis::HybridAppPreference::MOBILE; +} + void ApplicationImpl::set_cloud_app_endpoint(const std::string& endpoint) { endpoint_ = endpoint; } diff --git a/src/components/application_manager/src/application_manager_impl.cc b/src/components/application_manager/src/application_manager_impl.cc index ef008b7200..0923c054cc 100644 --- a/src/components/application_manager/src/application_manager_impl.cc +++ b/src/components/application_manager/src/application_manager_impl.cc @@ -381,21 +381,6 @@ void ApplicationManagerImpl::OnApplicationRegistered(ApplicationSharedPtr app) { plugin.OnApplicationEvent(plugin_manager::kApplicationRegistered, app); }; plugin_manager_->ForEachPlugin(on_app_registered); - - // TODO(AOleynik): Is neccessary to be able to know that registration process - // has been completed and default HMI level is set, otherwise policy will - // block all the requests/notifications to mobile - // APPLINK-20764 - introduce usage of internal events or re-implement - event_engine::Event event( - hmi_apis::FunctionID::BasicCommunication_OnAppRegistered); - - smart_objects::SmartObject msg; - msg[strings::params][strings::message_type] = - hmi_apis::messageType::notification; - msg[strings::params][strings::app_id] = app->app_id(); - - event.set_smart_object(msg); - event.raise(event_dispatcher()); } void ApplicationManagerImpl::OnApplicationSwitched(ApplicationSharedPtr app) { @@ -541,6 +526,7 @@ ApplicationSharedPtr ApplicationManagerImpl::RegisterApplication( app_name, GetPolicyHandler().GetStatisticManager(), *this)); + if (!application) { std::shared_ptr<smart_objects::SmartObject> response( MessageHelper::CreateNegativeResponse( @@ -610,13 +596,48 @@ ApplicationSharedPtr ApplicationManagerImpl::RegisterApplication( // Keep HMI add id in case app is present in "waiting for registration" list apps_to_register_list_lock_ptr_->Acquire(); - AppsWaitRegistrationSet::iterator it = apps_to_register_.find(application); - if (apps_to_register_.end() != it) { + PolicyAppIdPredicate finder(application->policy_app_id()); + ApplicationSet::iterator it = + std::find_if(apps_to_register_.begin(), apps_to_register_.end(), finder); + bool is_mismatched_cloud_app = false; + + if (apps_to_register_.end() == it) { + DevicePredicate finder(application->device()); + it = std::find_if( + apps_to_register_.begin(), apps_to_register_.end(), finder); + + bool found = apps_to_register_.end() != it; + is_mismatched_cloud_app = found && (*it)->is_cloud_app() && + policy_app_id != (*it)->policy_app_id(); + } else { application->set_hmi_application_id((*it)->hmi_app_id()); - apps_to_register_.erase(application); + + // Set cloud app parameters + application->set_cloud_app_endpoint((*it)->cloud_app_endpoint()); + application->set_cloud_app_certificate((*it)->cloud_app_certificate()); + application->set_cloud_app_auth_token((*it)->cloud_app_auth_token()); + application->set_cloud_app_transport_type( + (*it)->cloud_app_transport_type()); + application->set_hybrid_app_preference((*it)->hybrid_app_preference()); + apps_to_register_.erase(it); } apps_to_register_list_lock_ptr_->Release(); + // Reject registration request if a cloud app registers with the incorrect + // appID + if (is_mismatched_cloud_app) { + std::shared_ptr<smart_objects::SmartObject> response( + MessageHelper::CreateNegativeResponse( + connection_key, + mobile_apis::FunctionID::RegisterAppInterfaceID, + message[strings::params][strings::correlation_id].asUInt(), + mobile_apis::Result::DISALLOWED)); + (*response)[strings::msg_params][strings::info] = + "Cloud app registered with incorrect app id"; + rpc_service_->ManageMobileCommand(response, commands::Command::SOURCE_SDL); + return ApplicationSharedPtr(); + } + if (!application->hmi_app_id()) { const bool is_saved = resume_controller().IsApplicationSaved(policy_app_id, device_mac); @@ -855,7 +876,7 @@ void ApplicationManagerImpl::CreatePendingApplication( *this)); if (!application) { - LOG4CXX_INFO(logger_, "Could not streate application"); + LOG4CXX_INFO(logger_, "Could not create application"); return; } @@ -897,6 +918,28 @@ void ApplicationManagerImpl::CreatePendingApplication( SendUpdateAppList(); } +void ApplicationManagerImpl::OnConnectionStatusUpdated() { + SendUpdateAppList(); +} + +hmi_apis::Common_CloudConnectionStatus::eType +ApplicationManagerImpl::GetCloudAppConnectionStatus( + ApplicationConstSharedPtr app) const { + transport_manager::ConnectionStatus status = + connection_handler().GetConnectionStatus(app->device()); + switch (status) { + case transport_manager::ConnectionStatus::CONNECTED: + return hmi_apis::Common_CloudConnectionStatus::CONNECTED; + case transport_manager::ConnectionStatus::RETRY: + return hmi_apis::Common_CloudConnectionStatus::RETRY; + case transport_manager::ConnectionStatus::PENDING: + case transport_manager::ConnectionStatus::CLOSING: + return hmi_apis::Common_CloudConnectionStatus::NOT_CONNECTED; + default: + return hmi_apis::Common_CloudConnectionStatus::INVALID_ENUM; + } +} + uint32_t ApplicationManagerImpl::GetNextHMICorrelationID() { if (corelation_id_ < max_corelation_id_) { corelation_id_++; @@ -3758,6 +3801,13 @@ void ApplicationManagerImpl::AddMockApplication(ApplicationSharedPtr mock_app) { applications_list_lock_ptr_->Release(); } +void ApplicationManagerImpl::AddMockPendingApplication( + ApplicationSharedPtr mock_app) { + apps_to_register_list_lock_ptr_->Acquire(); + apps_to_register_.insert(mock_app); + apps_to_register_list_lock_ptr_->Release(); +} + void ApplicationManagerImpl::SetMockMediaManager( media_manager::MediaManager* mock_media_manager) { media_manager_ = mock_media_manager; diff --git a/src/components/application_manager/src/message_helper/message_helper.cc b/src/components/application_manager/src/message_helper/message_helper.cc index 2f86c50013..58d5171f84 100644 --- a/src/components/application_manager/src/message_helper/message_helper.cc +++ b/src/components/application_manager/src/message_helper/message_helper.cc @@ -1542,15 +1542,19 @@ bool MessageHelper::CreateHMIApplicationStruct( message = smart_objects::SmartObject(smart_objects::SmartType_Map); message[strings::app_name] = app->name(); message[strings::app_id] = app->hmi_app_id(); + + const std::string policy_app_id = app->policy_app_id(); + message[hmi_response::policy_app_id] = policy_app_id; + const std::string icon_path = app->app_icon_path(); - if (!icon_path.empty()) { + if (file_system::FileExists(app->app_icon_path())) { message[strings::icon] = icon_path; } if (app->IsRegistered()) { message[strings::hmi_display_language_desired] = app->ui_language(); message[strings::is_media_application] = app->is_media_application(); } else { - message[strings::greyOut] = app->is_greyed_out(); + message[strings::grey_out] = app->is_greyed_out(); } if (app->tts_name() && !app->tts_name()->empty()) { message[json::ttsName] = *(app->tts_name()); @@ -1566,6 +1570,46 @@ bool MessageHelper::CreateHMIApplicationStruct( message[strings::app_type] = *app_types; } + const policy::RequestType::State app_request_types_state = + policy_handler.GetAppRequestTypeState(policy_app_id); + if (policy::RequestType::State::AVAILABLE == app_request_types_state) { + const auto request_types = policy_handler.GetAppRequestTypes(policy_app_id); + message[strings::request_type] = + SmartObject(smart_objects::SmartType_Array); + smart_objects::SmartObject& request_types_array = + message[strings::request_type]; + + size_t index = 0; + for (auto it : request_types) { + request_types_array[index] = it; + ++index; + } + } else if (policy::RequestType::State::EMPTY == app_request_types_state) { + message[strings::request_type] = + SmartObject(smart_objects::SmartType_Array); + } + + const policy::RequestSubType::State app_request_subtypes_state = + policy_handler.GetAppRequestSubTypeState(policy_app_id); + if (policy::RequestSubType::State::AVAILABLE == app_request_subtypes_state) { + const auto request_subtypes = + policy_handler.GetAppRequestSubTypes(policy_app_id); + message[strings::request_subtype] = + SmartObject(smart_objects::SmartType_Array); + smart_objects::SmartObject& request_subtypes_array = + message[strings::request_subtype]; + + size_t index = 0; + for (auto it : request_subtypes) { + request_subtypes_array[index] = it; + ++index; + } + } else if (policy::RequestSubType::State::EMPTY == + app_request_subtypes_state) { + message[strings::request_subtype] = + SmartObject(smart_objects::SmartType_Array); + } + if (day_color_scheme) { message[strings::day_color_scheme] = *day_color_scheme; } @@ -1592,6 +1636,12 @@ bool MessageHelper::CreateHMIApplicationStruct( &secondary_device_info); } + message[strings::is_cloud_application] = app->is_cloud_app(); + if (app->is_cloud_app()) { + message[strings::cloud_connection_status] = + app_mngr.GetCloudAppConnectionStatus(app); + } + return true; } diff --git a/src/components/application_manager/src/resumption/resume_ctrl_impl.cc b/src/components/application_manager/src/resumption/resume_ctrl_impl.cc index 3e77078ee5..6af8826491 100644 --- a/src/components/application_manager/src/resumption/resume_ctrl_impl.cc +++ b/src/components/application_manager/src/resumption/resume_ctrl_impl.cc @@ -399,7 +399,13 @@ bool ResumeCtrlImpl::StartResumption(ApplicationSharedPtr application, << " hmi_app_id = " << application->hmi_app_id() << " policy_id = " << application->policy_app_id() << " received hash = " << hash); - SetupDefaultHMILevel(application); + if (!application->is_cloud_app()) { + // Default HMI Level is already set before resumption in + // ApplicationManager::OnApplicationRegistered, and handling low bandwidth + // transports doesn't apply to cloud apps, so this step can be skipped for + // such apps + SetupDefaultHMILevel(application); + } smart_objects::SmartObject saved_app; const std::string& device_mac = application->mac_address(); bool result = resumption_storage_->GetSavedApplication( @@ -426,7 +432,13 @@ bool ResumeCtrlImpl::StartResumptionOnlyHMILevel( << application->app_id() << "with hmi_app_id " << application->hmi_app_id() << ", policy_app_id " << application->policy_app_id()); - SetupDefaultHMILevel(application); + if (!application->is_cloud_app()) { + // Default HMI Level is already set before resumption in + // ApplicationManager::OnApplicationRegistered, and handling low bandwidth + // transports doesn't apply to cloud apps, so this step can be skipped for + // such apps + SetupDefaultHMILevel(application); + } const std::string& device_mac = application->mac_address(); smart_objects::SmartObject saved_app; bool result = resumption_storage_->GetSavedApplication( diff --git a/src/components/application_manager/src/smart_object_keys.cc b/src/components/application_manager/src/smart_object_keys.cc index 3e2951c553..70581466eb 100644 --- a/src/components/application_manager/src/smart_object_keys.cc +++ b/src/components/application_manager/src/smart_object_keys.cc @@ -43,7 +43,7 @@ const char* ngn_media_screen_app_name = "ngnMediaScreenAppName"; const char* vr_synonyms = "vrSynonyms"; const char* uses_vehicle_data = "usesVehicleData"; const char* is_media_application = "isMediaApplication"; -const char* greyOut = "greyOut"; +const char* grey_out = "greyOut"; const char* language_desired = "languageDesired"; const char* auto_activated_id = "autoActivateID"; const char* app_type = "appType"; @@ -159,6 +159,8 @@ const char* enabled = "enabled"; const char* cloud_app_auth_token = "cloudAppAuthToken"; const char* cloud_transport_type = "cloudTransportType"; const char* hybrid_app_preference = "hybridAppPreference"; +const char* is_cloud_application = "isCloudApplication"; +const char* cloud_connection_status = "cloudConnectionStatus"; // PutFile const char* sync_file_name = "syncFileName"; diff --git a/src/components/application_manager/test/application_manager_impl_test.cc b/src/components/application_manager/test/application_manager_impl_test.cc index 7e57b51329..4ea44e5aca 100644 --- a/src/components/application_manager/test/application_manager_impl_test.cc +++ b/src/components/application_manager/test/application_manager_impl_test.cc @@ -96,6 +96,14 @@ connection_handler::DeviceHandle kDeviceId = 12345u; const std::string kAppId = "someID"; const uint32_t kConnectionKey = 1232u; const std::string kAppName = "appName"; + +// Cloud application params +const std::string kEndpoint = "endpoint"; +const std::string kAuthToken = "auth_token"; +const std::string kCertificate = "cert"; +const std::string kTransportType = "WS"; +const mobile_api::HybridAppPreference::eType kHybridAppPreference = + mobile_api::HybridAppPreference::CLOUD; } // namespace class ApplicationManagerImplTest : public ::testing::Test { @@ -122,11 +130,11 @@ class ApplicationManagerImplTest : public ::testing::Test { protected: void SetUp() OVERRIDE { CreateAppManager(); - ON_CALL(mock_connection_handler_, GetDataOnSessionKey(_, _, _, &kDeviceId)) - .WillByDefault(DoAll(SetArgPointee<3u>(app_id_), Return(0))); + ON_CALL(mock_session_observer_, GetDataOnSessionKey(_, _, _, _)) + .WillByDefault(DoAll(SetArgPointee<3u>(kDeviceId), Return(0))); ON_CALL(mock_connection_handler_, get_session_observer()) .WillByDefault(ReturnRef(mock_session_observer_)); - app_manager_impl_->SetRPCService(mock_rpc_service_); + app_manager_impl_->SetMockRPCService(mock_rpc_service_); app_manager_impl_->resume_controller().set_resumption_storage( mock_storage_); app_manager_impl_->set_connection_handler(&mock_connection_handler_); @@ -200,7 +208,7 @@ class ApplicationManagerImplTest : public ::testing::Test { NiceMock<policy_test::MockPolicySettings> mock_policy_settings_; std::shared_ptr<NiceMock<resumption_test::MockResumptionData> > mock_storage_; - std::unique_ptr<rpc_service::RPCService> mock_rpc_service_; + MockRPCService* mock_rpc_service_; NiceMock<con_test::MockConnectionHandler> mock_connection_handler_; NiceMock<protocol_handler_test::MockSessionObserver> mock_session_observer_; NiceMock<MockApplicationManagerSettings> mock_application_manager_settings_; @@ -1413,6 +1421,121 @@ TEST_F(ApplicationManagerImplTest, EXPECT_TRUE(file_system::RemoveDirectory(kDirectoryName, true)); } +TEST_F(ApplicationManagerImplTest, + RegisterApplication_CloudAppRegisterSuccess) { + std::shared_ptr<MockApplication> waiting_app = + std::make_shared<MockApplication>(); + ON_CALL(*waiting_app, device()).WillByDefault(Return(kDeviceId)); + EXPECT_CALL(*waiting_app, cloud_app_endpoint()) + .WillOnce(ReturnRef(kEndpoint)); + EXPECT_CALL(*waiting_app, cloud_app_auth_token()) + .WillOnce(ReturnRef(kAuthToken)); + EXPECT_CALL(*waiting_app, cloud_app_certificate()) + .WillOnce(ReturnRef(kCertificate)); + EXPECT_CALL(*waiting_app, cloud_app_transport_type()) + .WillOnce(ReturnRef(kTransportType)); + EXPECT_CALL(*waiting_app, hybrid_app_preference()) + .WillOnce(ReturnRef(kHybridAppPreference)); + ON_CALL(*waiting_app, is_cloud_app()).WillByDefault(Return(true)); + EXPECT_CALL(*waiting_app, policy_app_id()).WillRepeatedly(Return(kAppId)); + app_manager_impl_->AddMockPendingApplication(waiting_app); + + EXPECT_CALL( + mock_session_observer_, + GetDataOnSessionKey(kConnectionKey, + _, + _, + testing::An<connection_handler::DeviceHandle*>())) + .WillOnce(DoAll(SetArgPointee<3u>(kDeviceId), Return(0))); + EXPECT_CALL(*mock_rpc_service_, + ManageMobileCommand(_, commands::Command::SOURCE_SDL)).Times(0); + smart_objects::SmartObject request_for_registration( + smart_objects::SmartType_Map); + + smart_objects::SmartObject& params = + request_for_registration[strings::msg_params]; + params[strings::app_id] = kAppId; + params[strings::language_desired] = mobile_api::Language::EN_US; + params[strings::hmi_display_language_desired] = mobile_api::Language::EN_US; + + request_for_registration[strings::params][strings::connection_key] = + kConnectionKey; + request_for_registration[strings::msg_params][strings::app_name] = kAppName; + request_for_registration[strings::msg_params][strings::sync_msg_version] + [strings::minor_version] = APIVersion::kAPIV2; + request_for_registration[strings::msg_params][strings::sync_msg_version] + [strings::major_version] = APIVersion::kAPIV3; + + request_for_registration[strings::params][strings::protocol_version] = + protocol_handler::MajorProtocolVersion::PROTOCOL_VERSION_2; + + smart_objects::SmartObjectSPtr request_for_registration_ptr = + std::make_shared<smart_objects::SmartObject>(request_for_registration); + + ApplicationSharedPtr application = + app_manager_impl_->RegisterApplication(request_for_registration_ptr); + + EXPECT_EQ(protocol_handler::MajorProtocolVersion::PROTOCOL_VERSION_2, + application->protocol_version()); + EXPECT_EQ(APIVersion::kAPIV2, + application->version().min_supported_api_version); + EXPECT_EQ(APIVersion::kAPIV3, + application->version().max_supported_api_version); + EXPECT_EQ(kEndpoint, application->cloud_app_endpoint()); + EXPECT_EQ(kAuthToken, application->cloud_app_auth_token()); + EXPECT_EQ(kCertificate, application->cloud_app_certificate()); + EXPECT_EQ(kTransportType, application->cloud_app_transport_type()); + EXPECT_EQ(kHybridAppPreference, application->hybrid_app_preference()); +} + +TEST_F(ApplicationManagerImplTest, + RegisterApplication_CloudAppRegisterFailed_DISALLOWED) { + std::shared_ptr<MockApplication> waiting_app = + std::make_shared<MockApplication>(); + EXPECT_CALL(*waiting_app, device()).WillRepeatedly(Return(kDeviceId)); + EXPECT_CALL(*waiting_app, is_cloud_app()).WillRepeatedly(Return(true)); + EXPECT_CALL(*waiting_app, policy_app_id()) + .WillRepeatedly(Return("Fake" + kAppId)); + app_manager_impl_->AddMockPendingApplication(waiting_app); + + EXPECT_CALL( + mock_session_observer_, + GetDataOnSessionKey(kConnectionKey, + _, + _, + testing::An<connection_handler::DeviceHandle*>())) + .WillOnce(DoAll(SetArgPointee<3u>(kDeviceId), Return(0))); + EXPECT_CALL(*mock_rpc_service_, + ManageMobileCommand(_, commands::Command::SOURCE_SDL)) + .WillOnce(Return(true)); + smart_objects::SmartObject request_for_registration( + smart_objects::SmartType_Map); + + smart_objects::SmartObject& params = + request_for_registration[strings::msg_params]; + params[strings::app_id] = kAppId; + params[strings::language_desired] = mobile_api::Language::EN_US; + params[strings::hmi_display_language_desired] = mobile_api::Language::EN_US; + + request_for_registration[strings::params][strings::connection_key] = + kConnectionKey; + request_for_registration[strings::msg_params][strings::app_name] = kAppName; + request_for_registration[strings::msg_params][strings::sync_msg_version] + [strings::minor_version] = APIVersion::kAPIV2; + request_for_registration[strings::msg_params][strings::sync_msg_version] + [strings::major_version] = APIVersion::kAPIV3; + + request_for_registration[strings::params][strings::protocol_version] = + protocol_handler::MajorProtocolVersion::PROTOCOL_VERSION_2; + + smart_objects::SmartObjectSPtr request_for_registration_ptr = + std::make_shared<smart_objects::SmartObject>(request_for_registration); + + ApplicationSharedPtr application = + app_manager_impl_->RegisterApplication(request_for_registration_ptr); + EXPECT_EQ(0, application.use_count()); +} + } // application_manager_test } // namespace components } // namespace test diff --git a/src/components/application_manager/test/include/application_manager/mock_application.h b/src/components/application_manager/test/include/application_manager/mock_application.h index 9c9041284c..d5b3752936 100644 --- a/src/components/application_manager/test/include/application_manager/mock_application.h +++ b/src/components/application_manager/test/include/application_manager/mock_application.h @@ -348,6 +348,7 @@ class MockApplication : public ::application_manager::Application { MOCK_CONST_METHOD0(hybrid_app_preference, const mobile_apis::HybridAppPreference::eType&()); MOCK_CONST_METHOD0(cloud_app_certificate, const std::string&()); + MOCK_CONST_METHOD0(is_cloud_app, bool()); MOCK_METHOD1(set_cloud_app_endpoint, void(const std::string& endpoint)); MOCK_METHOD1(set_cloud_app_auth_token, void(const std::string& auth_token)); MOCK_METHOD1(set_cloud_app_transport_type, diff --git a/src/components/application_manager/test/resumption/resume_ctrl_test.cc b/src/components/application_manager/test/resumption/resume_ctrl_test.cc index 1c2339096c..2413421c7f 100644 --- a/src/components/application_manager/test/resumption/resume_ctrl_test.cc +++ b/src/components/application_manager/test/resumption/resume_ctrl_test.cc @@ -153,6 +153,7 @@ class ResumeCtrlTest : public ::testing::Test { ON_CALL(*mock_app_, mac_address()).WillByDefault(ReturnRef(kMacAddress_)); ON_CALL(*mock_app_, device()).WillByDefault(Return(kTestDevId_)); ON_CALL(*mock_app_, app_id()).WillByDefault(Return(kTestAppId_)); + ON_CALL(*mock_app_, is_cloud_app()).WillByDefault(Return(false)); } NiceMock<event_engine_test::MockEventDispatcher> mock_event_dispatcher_; diff --git a/src/components/connection_handler/include/connection_handler/connection_handler_impl.h b/src/components/connection_handler/include/connection_handler/connection_handler_impl.h index 7be94c5f70..b8153bcf42 100644 --- a/src/components/connection_handler/include/connection_handler/connection_handler_impl.h +++ b/src/components/connection_handler/include/connection_handler/connection_handler_impl.h @@ -102,11 +102,21 @@ class ConnectionHandlerImpl /** * \brief Connects to all services of device - * \param deviceHandle Handle of device to connect to + * \param device_handle Handle of device to connect to */ void ConnectToDevice(connection_handler::DeviceHandle device_handle) OVERRIDE; /** + * @brief Retrieves the connection status of a given device + * + * @param device_handle Handle of device to query + * + * @return The connection status of the given device + */ + transport_manager::ConnectionStatus GetConnectionStatus( + const DeviceHandle& device_handle) const OVERRIDE; + + /** * @brief RunAppOnDevice allows to run specific application on the certain *device. * @@ -166,6 +176,8 @@ class ConnectionHandlerImpl void OnScanDevicesFailed( const transport_manager::SearchDeviceError& error) OVERRIDE; + void OnConnectionStatusUpdated() OVERRIDE; + /** * \brief Notifies about pending connection. * diff --git a/src/components/connection_handler/src/connection_handler_impl.cc b/src/components/connection_handler/src/connection_handler_impl.cc index ed2522593c..f72cab61f3 100644 --- a/src/components/connection_handler/src/connection_handler_impl.cc +++ b/src/components/connection_handler/src/connection_handler_impl.cc @@ -249,6 +249,10 @@ void ConnectionHandlerImpl::OnScanDevicesFailed( LOG4CXX_WARN(logger_, "Scan devices failed. " << error.text()); } +void ConnectionHandlerImpl::OnConnectionStatusUpdated() { + connection_handler_observer_->OnConnectionStatusUpdated(); +} + void ConnectionHandlerImpl::OnConnectionPending( const transport_manager::DeviceInfo& device_info, const transport_manager::ConnectionUID connection_id) { @@ -1292,6 +1296,11 @@ void ConnectionHandlerImpl::ConnectToDevice( } } +transport_manager::ConnectionStatus ConnectionHandlerImpl::GetConnectionStatus( + const DeviceHandle& device_handle) const { + return transport_manager_.GetConnectionStatus(device_handle); +} + void ConnectionHandlerImpl::RunAppOnDevice(const std::string& device_mac, const std::string& bundle_id) const { for (DeviceMap::const_iterator i = device_list_.begin(); diff --git a/src/components/include/application_manager/application_manager.h b/src/components/include/application_manager/application_manager.h index e6e5c89f45..9e979da08e 100644 --- a/src/components/include/application_manager/application_manager.h +++ b/src/components/include/application_manager/application_manager.h @@ -427,6 +427,14 @@ class ApplicationManager { virtual void OnHMIStartedCooperation() = 0; + /** + * @brief Retrieve the current connection status of a cloud app + * @param app A cloud application + * @return The current CloudConnectionStatus of app + */ + virtual hmi_apis::Common_CloudConnectionStatus::eType + GetCloudAppConnectionStatus(ApplicationConstSharedPtr app) const = 0; + virtual bool IsHMICooperating() const = 0; /** * @brief Notifies all components interested in Vehicle Data update diff --git a/src/components/include/application_manager/application_manager_settings.h b/src/components/include/application_manager/application_manager_settings.h index 8fdca4125f..fc16f1f1ed 100644 --- a/src/components/include/application_manager/application_manager_settings.h +++ b/src/components/include/application_manager/application_manager_settings.h @@ -85,6 +85,8 @@ class ApplicationManagerSettings : public RequestControlerSettings, virtual const std::string& audio_stream_file() const = 0; virtual bool use_full_app_id() const = 0; + virtual uint32_t cloud_app_retry_timeout() const = 0; + virtual uint16_t cloud_app_max_retry_attempts() const = 0; virtual bool use_db_for_resumption() const = 0; virtual const uint32_t& app_resumption_save_persistent_data_timeout() const = 0; diff --git a/src/components/include/connection_handler/connection_handler.h b/src/components/include/connection_handler/connection_handler.h index 93939fc782..eb41141842 100644 --- a/src/components/include/connection_handler/connection_handler.h +++ b/src/components/include/connection_handler/connection_handler.h @@ -80,6 +80,16 @@ class ConnectionHandler { connection_handler::DeviceHandle device_handle) = 0; /** + * @brief Retrieves the connection status of a given device + * + * @param device_handle Handle of device to query + * + * @return The connection status of the given device + */ + virtual transport_manager::ConnectionStatus GetConnectionStatus( + const DeviceHandle& device_handle) const = 0; + + /** * @brief RunAppOnDevice allows to run specific application on the certain *device. * diff --git a/src/components/include/connection_handler/connection_handler_observer.h b/src/components/include/connection_handler/connection_handler_observer.h index 298f98803a..f683318ada 100644 --- a/src/components/include/connection_handler/connection_handler_observer.h +++ b/src/components/include/connection_handler/connection_handler_observer.h @@ -161,6 +161,8 @@ class ConnectionHandlerObserver { */ virtual void OnSecondaryTransportEndedCallback(const int32_t session_key) = 0; + virtual void OnConnectionStatusUpdated() = 0; + virtual void CreatePendingApplication( const transport_manager::ConnectionUID connection_id, const transport_manager::DeviceInfo& device_info, diff --git a/src/components/include/test/application_manager/mock_application_manager.h b/src/components/include/test/application_manager/mock_application_manager.h index 7f5f17a93d..ca8aa2eb96 100644 --- a/src/components/include/test/application_manager/mock_application_manager.h +++ b/src/components/include/test/application_manager/mock_application_manager.h @@ -166,6 +166,9 @@ class MockApplicationManager : public application_manager::ApplicationManager { MOCK_METHOD1(EndAudioPassThru, bool(uint32_t app_id)); MOCK_METHOD1(ConnectToDevice, void(const std::string& device_mac)); MOCK_METHOD0(OnHMIStartedCooperation, void()); + MOCK_CONST_METHOD1(GetCloudAppConnectionStatus, + hmi_apis::Common_CloudConnectionStatus::eType( + application_manager::ApplicationConstSharedPtr app)); MOCK_CONST_METHOD0(IsHMICooperating, bool()); MOCK_METHOD2(IviInfoUpdated, void(mobile_apis::VehicleDataType::eType vehicle_info, diff --git a/src/components/include/test/application_manager/mock_application_manager_settings.h b/src/components/include/test/application_manager/mock_application_manager_settings.h index cfabf41b91..0f9ca194b1 100644 --- a/src/components/include/test/application_manager/mock_application_manager_settings.h +++ b/src/components/include/test/application_manager/mock_application_manager_settings.h @@ -90,6 +90,8 @@ class MockApplicationManagerSettings MOCK_CONST_METHOD0(video_stream_file, const std::string&()); MOCK_CONST_METHOD0(audio_stream_file, const std::string&()); MOCK_CONST_METHOD0(use_full_app_id, bool()); + MOCK_CONST_METHOD0(cloud_app_retry_timeout, uint32_t()); + MOCK_CONST_METHOD0(cloud_app_max_retry_attempts, uint16_t()); MOCK_CONST_METHOD0(use_db_for_resumption, bool()); MOCK_CONST_METHOD0(app_resumption_save_persistent_data_timeout, const uint32_t&()); diff --git a/src/components/include/test/connection_handler/mock_connection_handler.h b/src/components/include/test/connection_handler/mock_connection_handler.h index bdc0469844..5836626ae3 100644 --- a/src/components/include/test/connection_handler/mock_connection_handler.h +++ b/src/components/include/test/connection_handler/mock_connection_handler.h @@ -60,6 +60,9 @@ class MockConnectionHandler : public connection_handler::ConnectionHandler { MOCK_METHOD0(StartTransportManager, void()); MOCK_METHOD1(ConnectToDevice, void(connection_handler::DeviceHandle device_handle)); + MOCK_CONST_METHOD1( + GetConnectionStatus, + transport_manager::ConnectionStatus(const DeviceHandle& device_handle)); MOCK_CONST_METHOD2(RunAppOnDevice, void(const std::string&, const std::string&)); MOCK_METHOD0(ConnectToAllDevices, void()); diff --git a/src/components/include/test/connection_handler/mock_connection_handler_observer.h b/src/components/include/test/connection_handler/mock_connection_handler_observer.h index 2984b2e471..0a8e71c085 100644 --- a/src/components/include/test/connection_handler/mock_connection_handler_observer.h +++ b/src/components/include/test/connection_handler/mock_connection_handler_observer.h @@ -74,6 +74,7 @@ class MockConnectionHandlerObserver const int32_t session_key)); MOCK_METHOD1(OnSecondaryTransportEndedCallback, void(const int32_t session_key)); + MOCK_METHOD0(OnConnectionStatusUpdated, void()); MOCK_METHOD3(CreatePendingApplication, void(const transport_manager::ConnectionUID connection_id, const transport_manager::DeviceInfo& device_info, diff --git a/src/components/include/test/transport_manager/mock_transport_manager.h b/src/components/include/test/transport_manager/mock_transport_manager.h index e3f01fccb5..555d51bf76 100644 --- a/src/components/include/test/transport_manager/mock_transport_manager.h +++ b/src/components/include/test/transport_manager/mock_transport_manager.h @@ -63,6 +63,9 @@ class MockTransportManager : public ::transport_manager::TransportManager, void(const std::string& endpoint, const std::string& cloud_transport_type)); MOCK_METHOD1(ConnectDevice, int(const DeviceHandle)); + MOCK_CONST_METHOD1( + GetConnectionStatus, + transport_manager::ConnectionStatus(const DeviceHandle& device_handle)); MOCK_METHOD1(DisconnectDevice, int(const DeviceHandle)); MOCK_METHOD1(Disconnect, int(const ConnectionUID)); MOCK_METHOD1(DisconnectForce, int(const ConnectionUID)); diff --git a/src/components/include/test/transport_manager/mock_transport_manager_listener.h b/src/components/include/test/transport_manager/mock_transport_manager_listener.h index 734651f455..04408f945b 100644 --- a/src/components/include/test/transport_manager/mock_transport_manager_listener.h +++ b/src/components/include/test/transport_manager/mock_transport_manager_listener.h @@ -55,6 +55,7 @@ class MockTransportManagerListener : public TransportManagerListener { MOCK_METHOD1(OnDeviceRemoved, void(const DeviceInfo& device_info)); MOCK_METHOD0(OnScanDevicesFinished, void()); MOCK_METHOD1(OnScanDevicesFailed, void(const SearchDeviceError& error)); + MOCK_METHOD0(OnConnectionStatusUpdated, void()); MOCK_METHOD2(OnConnectionPending, void(const DeviceInfo& device_info, const ConnectionUID connection_id)); diff --git a/src/components/include/test/transport_manager/transport_adapter/mock_transport_adapter.h b/src/components/include/test/transport_manager/transport_adapter/mock_transport_adapter.h index 0be4da1063..c993f245b9 100644 --- a/src/components/include/test/transport_manager/transport_adapter/mock_transport_adapter.h +++ b/src/components/include/test/transport_manager/transport_adapter/mock_transport_adapter.h @@ -66,6 +66,10 @@ class MockTransportAdapter MOCK_METHOD1(ConnectDevice, ::transport_manager::transport_adapter::TransportAdapter::Error( const ::transport_manager::DeviceUID& device_handle)); + MOCK_CONST_METHOD1(GetConnectionStatus, + ::transport_manager::ConnectionStatus( + const ::transport_manager::DeviceUID& device_handle)); + MOCK_METHOD0(ConnectionStatusUpdated, void()); MOCK_METHOD2(RunAppOnDevice, void(const std::string&, const std::string&)); MOCK_CONST_METHOD0(IsClientOriginatedConnectSupported, bool()); MOCK_METHOD0( diff --git a/src/components/include/transport_manager/common.h b/src/components/include/transport_manager/common.h index 58bcf6bb17..b36dcde67e 100644 --- a/src/components/include/transport_manager/common.h +++ b/src/components/include/transport_manager/common.h @@ -56,6 +56,8 @@ enum { E_INTERNAL_ERROR }; +enum ConnectionStatus { INVALID = -1, PENDING, RETRY, CONNECTED, CLOSING }; + /** * @brief Type definition for variable that hold handle of device. */ diff --git a/src/components/include/transport_manager/transport_adapter/device.h b/src/components/include/transport_manager/transport_adapter/device.h index 1ac1424477..ad035245d8 100644 --- a/src/components/include/transport_manager/transport_adapter/device.h +++ b/src/components/include/transport_manager/transport_adapter/device.h @@ -58,7 +58,9 @@ class Device { Device(const std::string& name, const DeviceUID& unique_device_id) : name_(name) , unique_device_id_(unique_device_id) - , keep_on_disconnect_(false) {} + , keep_on_disconnect_(false) + , status_(ConnectionStatus::PENDING) + , retry_count_(0) {} /** * Constructor for creating device supporting transport switch @@ -73,7 +75,9 @@ class Device { : name_(name) , unique_device_id_(unique_device_id) , transport_switch_id_(transport_switch_id) - , keep_on_disconnect_(false) {} + , keep_on_disconnect_(false) + , status_(ConnectionStatus::PENDING) + , retry_count_(0) {} /** * @brief Destructor. @@ -132,6 +136,44 @@ class Device { } /** + * @brief Get @link status_ @endlink value + * @return current value + */ + inline ConnectionStatus connection_status() const { + return status_; + } + + /** + * @brief Set @link status_ @endlink value + * @param status new value + */ + inline void set_connection_status(ConnectionStatus status) { + status_ = status; + } + + /** + * @brief Get @link retry_count_ @endlink value + * @return current value + */ + inline uint16_t retry_count() const { + return retry_count_; + } + + /** + * @brief Increment @link retry_count_ @endlink value + */ + inline void next_retry() { + retry_count_++; + } + + /** + * @brief Reset @link retry_count_ @endlink value to 0 + */ + inline void reset_retry_count() { + retry_count_ = 0; + } + + /** * @brief transport_switch_id Returns id used for transport switching * flow of device. Filled if applicable, otherwise - empty. */ @@ -160,6 +202,10 @@ class Device { *finished. **/ bool keep_on_disconnect_; + + ConnectionStatus status_; + + uint16_t retry_count_; }; typedef std::shared_ptr<Device> DeviceSptr; typedef std::vector<DeviceSptr> DeviceVector; diff --git a/src/components/include/transport_manager/transport_adapter/transport_adapter.h b/src/components/include/transport_manager/transport_adapter/transport_adapter.h index aae4a8b569..f4ce19eb5f 100644 --- a/src/components/include/transport_manager/transport_adapter/transport_adapter.h +++ b/src/components/include/transport_manager/transport_adapter/transport_adapter.h @@ -197,6 +197,18 @@ class TransportAdapter { virtual Error ConnectDevice(const DeviceUID& device_handle) = 0; /** + * @brief Retrieves the connection status of a given device + * + * @param device_handle Handle of device to query + * + * @return The connection status of the given device + */ + virtual ConnectionStatus GetConnectionStatus( + const DeviceUID& device_handle) const = 0; + + virtual void ConnectionStatusUpdated() = 0; + + /** * @brief RunAppOnDevice allows to run specific application on the certain *device. * diff --git a/src/components/include/transport_manager/transport_adapter/transport_adapter_event.h b/src/components/include/transport_manager/transport_adapter/transport_adapter_event.h index 921562333b..63d1678ed0 100644 --- a/src/components/include/transport_manager/transport_adapter/transport_adapter_event.h +++ b/src/components/include/transport_manager/transport_adapter/transport_adapter_event.h @@ -59,7 +59,8 @@ enum class EventTypeEnum { ON_UNEXPECTED_DISCONNECT, ON_TRANSPORT_SWITCH_REQUESTED, ON_TRANSPORT_CONFIG_UPDATED, - ON_CONNECT_PENDING + ON_CONNECT_PENDING, + ON_CONNECTION_STATUS_UPDATED }; class TransportAdapterEvent { diff --git a/src/components/include/transport_manager/transport_manager.h b/src/components/include/transport_manager/transport_manager.h index b5dfa3671b..3ecf815097 100644 --- a/src/components/include/transport_manager/transport_manager.h +++ b/src/components/include/transport_manager/transport_manager.h @@ -88,6 +88,16 @@ class TransportManager { virtual int ConnectDevice(const DeviceHandle device_id) = 0; /** + * @brief Retrieves the connection status of a given device + * + * @param device_handle Handle of device to query + * + * @return The connection status of the given device + */ + virtual ConnectionStatus GetConnectionStatus( + const DeviceHandle& device_handle) const = 0; + + /** * @brief Disconnect from all applications connected on device. * * @param device_id Handle of device to Disconnect from. diff --git a/src/components/include/transport_manager/transport_manager_listener.h b/src/components/include/transport_manager/transport_manager_listener.h index 7da4bcc2f5..22ee519a67 100644 --- a/src/components/include/transport_manager/transport_manager_listener.h +++ b/src/components/include/transport_manager/transport_manager_listener.h @@ -101,6 +101,11 @@ class TransportManagerListener { virtual void OnScanDevicesFailed(const SearchDeviceError& error) = 0; /** + * @brief Reaction to the event, when the cloud connection status is updated. + */ + virtual void OnConnectionStatusUpdated() = 0; + + /** * @brief Reaction to the event, when connection is pending. * * @param devcie_info Variable that hold information about device. diff --git a/src/components/include/transport_manager/transport_manager_listener_empty.h b/src/components/include/transport_manager/transport_manager_listener_empty.h index c0a713f38e..193a86819c 100644 --- a/src/components/include/transport_manager/transport_manager_listener_empty.h +++ b/src/components/include/transport_manager/transport_manager_listener_empty.h @@ -59,6 +59,8 @@ class TransportManagerListenerEmpty : public TransportManagerListener { void OnFindNewApplicationsRequest() OVERRIDE {} + void OnConnectionStatusUpdated() OVERRIDE {} + /** * @brief Reaction to the event, when the device is found. * diff --git a/src/components/interfaces/HMI_API.xml b/src/components/interfaces/HMI_API.xml index a11cfbfd8a..7adb5fb51e 100644 --- a/src/components/interfaces/HMI_API.xml +++ b/src/components/interfaces/HMI_API.xml @@ -292,6 +292,18 @@ <element name="REMOTE_CONTROL" /> </enum> +<enum name="CloudConnectionStatus"> + <element name="NOT_CONNECTED"> + <description>No active websocket session or ongoing connection attempts</description> + </element> + <element name="CONNECTED"> + <description>Websocket is active</description> + </element> + <element name="RETRY"> + <description>Websocket connection failed and retry attempts are ongoing</description> + </element> +</enum> + <enum name="WayPointType"> <description>Describes what kind of waypoint is requested/provided.</description> <element name="ALL" /> @@ -2620,16 +2632,18 @@ <description>If SDL omits this parameter - none RequestType is allowed for this app</description> <description>(either this is a pre-registered app or such is dictated by policies).</description> </param> - <param name="requestSubType" type="String" maxlength="100" minsize="0" maxsize="100" array="true" mandatory="false"> - <description> - The list of SystemRequest's requestSubTypes allowed by policies for the named application. - If the app sends a requestSubType which is not specified in this list, then that request should be rejected. - An empty array signifies that any value of requestSubType is allowed for this app. - If this parameter is omitted, then a request with any value of requestSubType is now allowed for this app - </description> + <param name="requestSubType" type="String" maxlength="100" minsize="0" maxsize="100" array="true" mandatory="false"> + <description> + The list of SystemRequest's requestSubTypes allowed by policies for the named application. + If the app sends a requestSubType which is not specified in this list, then that request should be rejected. + An empty array signifies that any value of requestSubType is allowed for this app. + If this parameter is omitted, then a request with any value of requestSubType is now allowed for this app + </description> </param> <param name="dayColorScheme" type="Common.TemplateColorScheme" mandatory="false"></param> <param name="nightColorScheme" type="Common.TemplateColorScheme" mandatory="false"></param> + <param name="isCloudApplication" type="Boolean" mandatory="false"></param> + <param name="cloudConnectionStatus" type="Common.CloudConnectionStatus" mandatory="false"></param> </struct> <struct name="MenuParams"> diff --git a/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_impl.h b/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_impl.h index 0af1f2b614..8d03bdb2c7 100644 --- a/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_impl.h +++ b/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_impl.h @@ -41,6 +41,7 @@ #include "utils/lock.h" #include "utils/rwlock.h" +#include "utils/timer.h" #include "transport_manager/transport_adapter/transport_adapter.h" #include "transport_manager/transport_adapter/transport_adapter_controller.h" @@ -61,6 +62,8 @@ class DeviceScanner; class ServerConnectionFactory; class ClientConnectionListener; +typedef std::shared_ptr<timer::Timer> TimerSPtr; + /* * @brief Implementation of device adapter class. **/ @@ -147,6 +150,18 @@ class TransportAdapterImpl : public TransportAdapter, const DeviceUID& device_handle) OVERRIDE; /** + * @brief Retrieves the connection status of a given device + * + * @param device_handle Handle of device to query + * + * @return The connection status of the given device + */ + ConnectionStatus GetConnectionStatus( + const DeviceUID& device_handle) const OVERRIDE; + + void ConnectionStatusUpdated() OVERRIDE; + + /** * @brief Disconnect from specified session. * * @param devcie_handle Device unique identifier. @@ -547,6 +562,23 @@ class TransportAdapterImpl : public TransportAdapter, TransportAdapter::Error ConnectDevice(DeviceSptr device); /** + * @brief Reattempt the last failed connection to a device + */ + void RetryConnection(); + + /** + * @brief Clear any retry timers which have been completed + */ + void ClearCompletedTimers(); + + /** + * @brief Retrieve the next device available for a reattempted connection + * @return The handle first device with an expired retry timer if present, + * otherwise an empty string + */ + DeviceUID GetNextRetryDevice(); + + /** * @brief Remove specified device * @param device_handle Device unique identifier. */ @@ -578,7 +610,7 @@ class TransportAdapterImpl : public TransportAdapter, ConnectionSPtr connection; DeviceUID device_id; ApplicationHandle app_handle; - enum { NEW, ESTABLISHED, FINALISING, PENDING, RETRY } state; + enum { NEW, ESTABLISHED, FINALISING, PENDING } state; }; /** @@ -608,6 +640,18 @@ class TransportAdapterImpl : public TransportAdapter, ConnectionMap connections_; /** + * @brief Queue of retry timers. + */ + std::queue<std::pair<TimerSPtr, DeviceUID> > retry_timer_pool_; + sync_primitives::Lock retry_timer_pool_lock_; + + /** + * @brief Queue of completed retry timers. + */ + std::queue<std::pair<TimerSPtr, DeviceUID> > completed_timer_pool_; + sync_primitives::Lock completed_timer_pool_lock_; + + /** * @brief Mutex restricting access to connections map. **/ mutable sync_primitives::RWLock connections_lock_; diff --git a/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_listener.h b/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_listener.h index b0368869e7..a0e0a51c1e 100644 --- a/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_listener.h +++ b/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_listener.h @@ -92,6 +92,12 @@ class TransportAdapterListener { const TransportAdapter* adapter) = 0; /** + * @brief Reaction to connection status update + * @param adapter Current transport adapter + */ + virtual void OnConnectionStatusUpdated(const TransportAdapter* adapter) = 0; + + /** * @brief Search specified device adapter in the container of shared pointers * to device adapters to be sure it is available, * launch event ON_CONNECT_PENDING in transport manager. diff --git a/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_listener_impl.h b/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_listener_impl.h index 76271229ad..0c9c6ef6a2 100644 --- a/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_listener_impl.h +++ b/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_listener_impl.h @@ -88,6 +88,11 @@ class TransportAdapterListenerImpl virtual void OnFindNewApplicationsRequest(const TransportAdapter* adapter); /** + * @brief Passes notification to that the cloud conection status has updated + */ + virtual void OnConnectionStatusUpdated(const TransportAdapter* adapter); + + /** * @brief Search specified device adapter in the container of shared pointers * to device adapters to be sure it is available, * launch event ON_CONNECT_PENDING in transport manager. diff --git a/src/components/transport_manager/include/transport_manager/transport_manager_impl.h b/src/components/transport_manager/include/transport_manager/transport_manager_impl.h index dcb3b6922c..c84b1e9a39 100644 --- a/src/components/transport_manager/include/transport_manager/transport_manager_impl.h +++ b/src/components/transport_manager/include/transport_manager/transport_manager_impl.h @@ -43,7 +43,6 @@ #include <functional> #include "utils/timer.h" -#include "utils/timer_task_impl.h" #include "utils/rwlock.h" #include "transport_manager/transport_manager.h" @@ -153,6 +152,16 @@ class TransportManagerImpl int ConnectDevice(const DeviceHandle device_id) OVERRIDE; /** + * @brief Retrieves the connection status of a given device + * + * @param device_handle Handle of device to query + * + * @return The connection status of the given device + */ + ConnectionStatus GetConnectionStatus( + const DeviceHandle& device_handle) const OVERRIDE; + + /** * @brief Disconnect from all applications connected on device. * * @param device_id Handle of device to Disconnect from. @@ -368,7 +377,7 @@ class TransportManagerImpl * @brief Converter variable (Device ID -> Device Handle; Device Handle -> * Device ID) */ - Handle2GUIDConverter converter_; + mutable Handle2GUIDConverter converter_; #ifdef BUILD_TESTS public: @@ -383,7 +392,7 @@ class TransportManagerImpl int connection_id_counter_; sync_primitives::RWLock connections_lock_; std::vector<ConnectionInternal> connections_; - sync_primitives::RWLock device_to_adapter_map_lock_; + mutable sync_primitives::RWLock device_to_adapter_map_lock_; typedef std::map<DeviceUID, TransportAdapter*> DeviceToAdapterMap; DeviceToAdapterMap device_to_adapter_map_; std::vector<TransportAdapter*> transport_adapters_; diff --git a/src/components/transport_manager/src/cloud/cloud_device.cc b/src/components/transport_manager/src/cloud/cloud_device.cc index 90a485c069..184fcc10cc 100644 --- a/src/components/transport_manager/src/cloud/cloud_device.cc +++ b/src/components/transport_manager/src/cloud/cloud_device.cc @@ -60,7 +60,7 @@ bool CloudDevice::IsSameAs(const Device* other) const { } ApplicationList CloudDevice::GetApplicationList() const { - return ApplicationList{100}; + return ApplicationList{0}; } const std::string& CloudDevice::GetHost() const { diff --git a/src/components/transport_manager/src/cloud/cloud_websocket_transport_adapter.cc b/src/components/transport_manager/src/cloud/cloud_websocket_transport_adapter.cc index 24efdfb2a4..5093e6c2af 100644 --- a/src/components/transport_manager/src/cloud/cloud_websocket_transport_adapter.cc +++ b/src/components/transport_manager/src/cloud/cloud_websocket_transport_adapter.cc @@ -74,11 +74,31 @@ void CloudWebsocketTransportAdapter::CreateDevice(const std::string& uid) { } LOG4CXX_DEBUG(logger_, "Valid Endpoint: " << uid); - std::size_t pos = uid.find(":"); - pos = uid.find(":", pos + 1); - // std::size_t size = uid.length(); - std::string host = uid.substr(0, pos); - std::string port = uid.substr(pos + 1); + + // Port after second colon in valid endpoint string + std::size_t pos_port = uid.find(":"); + pos_port = uid.find(":", pos_port + 1); + + // Extract host and port from endpoint string + boost::regex group_pattern( + "(wss?:\\/\\/)([A-Z\\d\\.-]{2,}\\.?([A-Z]{2,})?)(:)(\\d{2,4})(\\/)"); + boost::smatch results; + + std::string host = ""; + std::string port = ""; + if (boost::regex_search(str, results, group_pattern)) { + host = results[2]; + port = results[5]; + + LOG4CXX_DEBUG(logger_, + "Results: " << results[0] << " " << results[1] << " " + << results[2] << " " << results[3] << " " + << results[4] << " " << results[5] << " "); + } else { + LOG4CXX_DEBUG(logger_, "Invalid Pattern: " << uid); + return; + } + std::string device_id = uid; LOG4CXX_DEBUG(logger_, @@ -101,4 +121,4 @@ void CloudWebsocketTransportAdapter::CreateDevice(const std::string& uid) { return; } } -}
\ No newline at end of file +} diff --git a/src/components/transport_manager/src/transport_adapter/transport_adapter_impl.cc b/src/components/transport_manager/src/transport_adapter/transport_adapter_impl.cc index 38b9bd3998..8928ecb4d2 100644 --- a/src/components/transport_manager/src/transport_adapter/transport_adapter_impl.cc +++ b/src/components/transport_manager/src/transport_adapter/transport_adapter_impl.cc @@ -31,8 +31,9 @@ */ #include "config_profile/profile.h" -#include "utils/logger.h" #include "utils/helpers.h" +#include "utils/logger.h" +#include "utils/timer_task_impl.h" #include "transport_manager/transport_adapter/transport_adapter_impl.h" #include "transport_manager/transport_adapter/transport_adapter_listener.h" @@ -209,17 +210,21 @@ TransportAdapter::Error TransportAdapterImpl::Connect( } connections_lock_.AcquireForWriting(); + + std::pair<DeviceUID, ApplicationHandle> connection_key = + std::make_pair(device_id, app_handle); const bool already_exists = - connections_.end() != - connections_.find(std::make_pair(device_id, app_handle)); + connections_.end() != connections_.find(connection_key); + ConnectionInfo& info = connections_[connection_key]; if (!already_exists) { - ConnectionInfo& info = connections_[std::make_pair(device_id, app_handle)]; info.app_handle = app_handle; info.device_id = device_id; info.state = ConnectionInfo::NEW; } + const bool pending_app = ConnectionInfo::PENDING == info.state; connections_lock_.Release(); - if (already_exists) { + + if (already_exists && !pending_app) { LOG4CXX_TRACE(logger_, "exit with ALREADY_EXISTS"); return ALREADY_EXISTS; } @@ -241,6 +246,36 @@ TransportAdapter::Error TransportAdapterImpl::ConnectDevice( DeviceSptr device = FindDevice(device_handle); if (device) { TransportAdapter::Error err = ConnectDevice(device); + if (FAIL == err && GetDeviceType() == DeviceType::CLOUD_WEBSOCKET) { + LOG4CXX_TRACE(logger_, + "Error occurred while connecting cloud app: " << err); + // Update retry count + if (device->retry_count() >= + get_settings().cloud_app_max_retry_attempts()) { + device->set_connection_status(ConnectionStatus::PENDING); + device->reset_retry_count(); + ConnectionStatusUpdated(); + return err; + } else if (device->connection_status() == ConnectionStatus::PENDING) { + device->set_connection_status(ConnectionStatus::RETRY); + ConnectionStatusUpdated(); + } + + device->next_retry(); + + // Start timer for next retry + TimerSPtr retry_timer(std::make_shared<timer::Timer>( + "RetryConnectionTimer", + new timer::TimerTaskImpl<TransportAdapterImpl>( + this, &TransportAdapterImpl::RetryConnection))); + sync_primitives::AutoLock locker(retry_timer_pool_lock_); + retry_timer_pool_.push(std::make_pair(retry_timer, device_handle)); + retry_timer->Start(get_settings().cloud_app_retry_timeout(), + timer::kSingleShot); + } else if (OK == err) { + device->set_connection_status(ConnectionStatus::CONNECTED); + ConnectionStatusUpdated(); + } LOG4CXX_TRACE(logger_, "exit with error: " << err); return err; } else { @@ -249,6 +284,58 @@ TransportAdapter::Error TransportAdapterImpl::ConnectDevice( } } +void TransportAdapterImpl::RetryConnection() { + ClearCompletedTimers(); + const DeviceUID device_id = GetNextRetryDevice(); + if (device_id.empty()) { + LOG4CXX_ERROR(logger_, + "Unable to find timer, ignoring RetryConnection request"); + return; + } + ConnectDevice(device_id); +} + +void TransportAdapterImpl::ClearCompletedTimers() { + // Cleanup any retry timers which have completed execution + sync_primitives::AutoLock locker(completed_timer_pool_lock_); + while (!completed_timer_pool_.empty()) { + auto timer_entry = completed_timer_pool_.front(); + if (timer_entry.first->is_completed()) { + completed_timer_pool_.pop(); + } + } +} + +DeviceUID TransportAdapterImpl::GetNextRetryDevice() { + sync_primitives::AutoLock retry_locker(retry_timer_pool_lock_); + if (retry_timer_pool_.empty()) { + return std::string(); + } + auto timer_entry = retry_timer_pool_.front(); + retry_timer_pool_.pop(); + + // Store reference for cleanup later + sync_primitives::AutoLock completed_locker(completed_timer_pool_lock_); + completed_timer_pool_.push(timer_entry); + + return timer_entry.second; +} + +ConnectionStatus TransportAdapterImpl::GetConnectionStatus( + const DeviceUID& device_handle) const { + DeviceSptr device = FindDevice(device_handle); + return device.use_count() == 0 ? ConnectionStatus::INVALID + : device->connection_status(); +} + +void TransportAdapterImpl::ConnectionStatusUpdated() { + for (TransportAdapterListenerList::iterator it = listeners_.begin(); + it != listeners_.end(); + ++it) { + (*it)->OnConnectionStatusUpdated(this); + } +} + TransportAdapter::Error TransportAdapterImpl::Disconnect( const DeviceUID& device_id, const ApplicationHandle& app_handle) { LOG4CXX_TRACE(logger_, @@ -278,6 +365,9 @@ TransportAdapter::Error TransportAdapterImpl::DisconnectDevice( } Error error = OK; + DeviceSptr device = FindDevice(device_id); + device->set_connection_status(ConnectionStatus::CLOSING); + ConnectionStatusUpdated(); std::vector<ConnectionInfo> to_disconnect; connections_lock_.AcquireForReading(); @@ -397,6 +487,7 @@ DeviceSptr TransportAdapterImpl::AddDevice(DeviceSptr device) { LOG4CXX_TRACE(logger_, "exit with TRUE. Condition: same_device_found"); return existing_device; } else { + device->set_connection_status(ConnectionStatus::PENDING); for (TransportAdapterListenerList::iterator it = listeners_.begin(); it != listeners_.end(); ++it) { diff --git a/src/components/transport_manager/src/transport_adapter/transport_adapter_listener_impl.cc b/src/components/transport_manager/src/transport_adapter/transport_adapter_listener_impl.cc index 73750fe2f3..4ef685adbc 100644 --- a/src/components/transport_manager/src/transport_adapter/transport_adapter_listener_impl.cc +++ b/src/components/transport_manager/src/transport_adapter/transport_adapter_listener_impl.cc @@ -116,6 +116,23 @@ void TransportAdapterListenerImpl::OnFindNewApplicationsRequest( LOG4CXX_TRACE(logger_, "exit"); } +void TransportAdapterListenerImpl::OnConnectionStatusUpdated( + const TransportAdapter* adapter) { + LOG4CXX_TRACE(logger_, "enter. adapter* " << adapter); + const TransportAdapterEvent event(EventTypeEnum::ON_CONNECTION_STATUS_UPDATED, + transport_adapter_, + "", + 0, + ::protocol_handler::RawMessagePtr(), + BaseErrorPtr(new BaseError())); + if (transport_manager_ != NULL && + transport_manager::E_SUCCESS != + transport_manager_->ReceiveEventFromDevice(event)) { + LOG4CXX_WARN(logger_, "Failed to receive event from device"); + } + LOG4CXX_TRACE(logger_, "exit"); +} + void TransportAdapterListenerImpl::OnConnectPending( const TransportAdapter* adapter, const DeviceUID& device, diff --git a/src/components/transport_manager/src/transport_manager_impl.cc b/src/components/transport_manager/src/transport_manager_impl.cc index 300ed27718..518a5639db 100644 --- a/src/components/transport_manager/src/transport_manager_impl.cc +++ b/src/components/transport_manager/src/transport_manager_impl.cc @@ -177,6 +177,22 @@ int TransportManagerImpl::ConnectDevice(const DeviceHandle device_handle) { return err; } +ConnectionStatus TransportManagerImpl::GetConnectionStatus( + const DeviceHandle& device_handle) const { + DeviceUID device_id = converter_.HandleToUid(device_handle); + + sync_primitives::AutoReadLock lock(device_to_adapter_map_lock_); + DeviceToAdapterMap::const_iterator it = + device_to_adapter_map_.find(device_id); + if (it == device_to_adapter_map_.end()) { + LOG4CXX_ERROR(logger_, "No device adapter found by id " << device_handle); + LOG4CXX_TRACE(logger_, "exit with E_INVALID_HANDLE. Condition: NULL == ta"); + return ConnectionStatus::INVALID; + } + transport_adapter::TransportAdapter* ta = it->second; + return ta->GetConnectionStatus(device_id); +} + int TransportManagerImpl::DisconnectDevice(const DeviceHandle device_handle) { LOG4CXX_TRACE(logger_, "enter. DeviceHandle: " << &device_handle); if (!this->is_initialized_) { @@ -974,6 +990,11 @@ void TransportManagerImpl::Handle(TransportAdapterEvent event) { LOG4CXX_DEBUG(logger_, "event_type = ON_FIND_NEW_APPLICATIONS_REQUEST"); break; } + case EventTypeEnum::ON_CONNECTION_STATUS_UPDATED: { + RaiseEvent(&TransportManagerListener::OnConnectionStatusUpdated); + LOG4CXX_DEBUG(logger_, "event_type = ON_CONNECTION_STATUS_UPDATED"); + break; + } case EventTypeEnum::ON_CONNECT_PENDING: { const DeviceHandle device_handle = converter_.UidToHandle( event.device_uid, event.transport_adapter->GetConnectionType()); diff --git a/src/components/transport_manager/test/include/transport_manager/transport_adapter/mock_transport_adapter_impl.h b/src/components/transport_manager/test/include/transport_manager/transport_adapter/mock_transport_adapter_impl.h index 384f55605a..e18d1bc53b 100644 --- a/src/components/transport_manager/test/include/transport_manager/transport_adapter/mock_transport_adapter_impl.h +++ b/src/components/transport_manager/test/include/transport_manager/transport_adapter/mock_transport_adapter_impl.h @@ -70,15 +70,15 @@ class MockTransportAdapterImpl : public TransportAdapterImpl { } virtual ~MockTransportAdapterImpl() {} - virtual DeviceType GetDeviceType() const { - return DeviceType::UNKNOWN; - } - MOCK_CONST_METHOD0(Store, void()); MOCK_METHOD0(Restore, bool()); MOCK_CONST_METHOD1(FindDevice, transport_manager::transport_adapter::DeviceSptr( const DeviceUID& device_id)); + MOCK_METHOD0(ConnectionStatusUpdated, void()); + MOCK_CONST_METHOD0(GetDeviceType, + ::transport_manager::transport_adapter::DeviceType()); + MOCK_METHOD0(RetryConnection, void()); }; } // namespace transport_manager_test diff --git a/src/components/transport_manager/test/include/transport_manager/transport_adapter/mock_transport_adapter_listener.h b/src/components/transport_manager/test/include/transport_manager/transport_adapter/mock_transport_adapter_listener.h index 81e133ec2b..f7bebf69c3 100644 --- a/src/components/transport_manager/test/include/transport_manager/transport_adapter/mock_transport_adapter_listener.h +++ b/src/components/transport_manager/test/include/transport_manager/transport_adapter/mock_transport_adapter_listener.h @@ -59,6 +59,8 @@ class MockTransportAdapterListener : public TransportAdapterListener { const SearchDeviceError& error)); MOCK_METHOD1(OnFindNewApplicationsRequest, void(const TransportAdapter* adapter)); + MOCK_METHOD1(OnConnectionStatusUpdated, + void(const TransportAdapter* adapter)); MOCK_METHOD3(OnConnectPending, void(const TransportAdapter* adapter, const DeviceUID& device_handle, diff --git a/src/components/transport_manager/test/transport_adapter_test.cc b/src/components/transport_manager/test/transport_adapter_test.cc index 9e602332c6..b917c60187 100644 --- a/src/components/transport_manager/test/transport_adapter_test.cc +++ b/src/components/transport_manager/test/transport_adapter_test.cc @@ -31,14 +31,15 @@ */ #include "gtest/gtest.h" -#include "transport_manager/transport_adapter/mock_device_scanner.h" +#include "transport_manager/mock_transport_manager_settings.h" #include "transport_manager/transport_adapter/mock_client_connection_listener.h" -#include "transport_manager/transport_adapter/mock_server_connection_factory.h" -#include "transport_manager/transport_adapter/mock_device.h" #include "transport_manager/transport_adapter/mock_connection.h" -#include "transport_manager/transport_adapter/mock_transport_adapter_listener.h" +#include "transport_manager/transport_adapter/mock_device.h" +#include "transport_manager/transport_adapter/mock_device_scanner.h" +#include "transport_manager/transport_adapter/mock_server_connection_factory.h" #include "transport_manager/transport_adapter/mock_transport_adapter_impl.h" -#include "transport_manager/mock_transport_manager_settings.h" +#include "transport_manager/transport_adapter/mock_transport_adapter_listener.h" +#include "utils/test_async_waiter.h" #include "transport_manager/transport_adapter/transport_adapter_impl.h" #include "transport_manager/transport_adapter/transport_adapter_listener.h" @@ -73,6 +74,11 @@ class TransportAdapterTest : public ::testing::Test { .WillByDefault(Return(true)); } + void SetDefaultExpectations(MockTransportAdapterImpl& adapter) { + ON_CALL(adapter, GetDeviceType()) + .WillByDefault(Return(DeviceType::UNKNOWN)); + } + NiceMock<MockTransportManagerSettings> transport_manager_settings; resumption::LastStateImpl last_state_; std::string dev_id; @@ -89,6 +95,7 @@ TEST_F(TransportAdapterTest, Init) { clientMock, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*dev_mock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(*clientMock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(*serverMock, Init()).WillOnce(Return(TransportAdapter::OK)); @@ -123,6 +130,7 @@ TEST_F(TransportAdapterTest, SearchDevices_DeviceNotInitialized) { MockDeviceScanner* dev_mock = new MockDeviceScanner(); MockTransportAdapterImpl transport_adapter( dev_mock, NULL, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*dev_mock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); @@ -138,6 +146,7 @@ TEST_F(TransportAdapterTest, SearchDevices_DeviceInitialized) { MockDeviceScanner* dev_mock = new MockDeviceScanner(); MockTransportAdapterImpl transport_adapter( dev_mock, NULL, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*dev_mock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); @@ -153,6 +162,7 @@ TEST_F(TransportAdapterTest, SearchDevices_DeviceInitialized) { TEST_F(TransportAdapterTest, SearchDeviceDone_DeviceExisting) { MockTransportAdapterImpl transport_adapter( NULL, NULL, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); transport_adapter.Init(); @@ -169,6 +179,7 @@ TEST_F(TransportAdapterTest, SearchDeviceDone_DeviceExisting) { TEST_F(TransportAdapterTest, SearchDeviceFailed) { MockTransportAdapterImpl transport_adapter( NULL, NULL, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); transport_adapter.Init(); @@ -183,6 +194,7 @@ TEST_F(TransportAdapterTest, SearchDeviceFailed) { TEST_F(TransportAdapterTest, AddDevice) { MockTransportAdapterImpl transport_adapter( NULL, NULL, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); transport_adapter.Init(); @@ -200,6 +212,7 @@ TEST_F(TransportAdapterTest, Connect_ServerNotSupported) { MockClientConnectionListener* clientMock = new MockClientConnectionListener(); MockTransportAdapterImpl transport_adapter( NULL, NULL, clientMock, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*clientMock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); @@ -217,6 +230,7 @@ TEST_F(TransportAdapterTest, Connect_ServerNotInitialized) { MockServerConnectionFactory* serverMock = new MockServerConnectionFactory(); MockTransportAdapterImpl transport_adapter( NULL, serverMock, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*serverMock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); @@ -234,6 +248,7 @@ TEST_F(TransportAdapterTest, Connect_Success) { MockServerConnectionFactory* serverMock = new MockServerConnectionFactory(); MockTransportAdapterImpl transport_adapter( NULL, serverMock, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*serverMock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); @@ -252,6 +267,7 @@ TEST_F(TransportAdapterTest, Connect_DeviceAddedTwice) { MockServerConnectionFactory* serverMock = new MockServerConnectionFactory(); MockTransportAdapterImpl transport_adapter( NULL, serverMock, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*serverMock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); @@ -274,6 +290,7 @@ TEST_F(TransportAdapterTest, Connect_DeviceAddedTwice) { TEST_F(TransportAdapterTest, ConnectDevice_ServerNotAdded_DeviceAdded) { MockTransportAdapterImpl transport_adapter( NULL, NULL, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); transport_adapter.Init(); @@ -292,12 +309,14 @@ TEST_F(TransportAdapterTest, ConnectDevice_ServerNotAdded_DeviceAdded) { TransportAdapter::Error res = transport_adapter.ConnectDevice(uniq_id); EXPECT_EQ(TransportAdapter::FAIL, res); + EXPECT_NE(ConnectionStatus::CONNECTED, mockdev->connection_status()); } TEST_F(TransportAdapterTest, ConnectDevice_DeviceNotAdded) { MockServerConnectionFactory* serverMock = new MockServerConnectionFactory(); MockTransportAdapterImpl transport_adapter( NULL, serverMock, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*serverMock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); transport_adapter.Init(); @@ -318,6 +337,7 @@ TEST_F(TransportAdapterTest, ConnectDevice_DeviceAdded) { MockServerConnectionFactory* serverMock = new MockServerConnectionFactory(); MockTransportAdapterImpl transport_adapter( NULL, serverMock, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*serverMock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); @@ -339,16 +359,58 @@ TEST_F(TransportAdapterTest, ConnectDevice_DeviceAdded) { EXPECT_CALL(*serverMock, CreateConnection(uniq_id, app_handle)) .WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(transport_adapter, FindDevice(uniq_id)).WillOnce(Return(mockdev)); + EXPECT_CALL(transport_adapter, ConnectionStatusUpdated()); TransportAdapter::Error res = transport_adapter.ConnectDevice(uniq_id); EXPECT_EQ(TransportAdapter::OK, res); + EXPECT_EQ(ConnectionStatus::CONNECTED, mockdev->connection_status()); EXPECT_CALL(*serverMock, Terminate()); } +TEST_F(TransportAdapterTest, ConnectDevice_DeviceAdded_ConnectFailedRetry) { + MockServerConnectionFactory* server_mock = new MockServerConnectionFactory(); + MockTransportAdapterImpl transport_adapter( + NULL, server_mock, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); + // transport_adapter.SetDeviceType(DeviceType::CLOUD_WEBSOCKET); + + EXPECT_CALL(*server_mock, Init()).WillOnce(Return(TransportAdapter::OK)); + EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); + transport_adapter.Init(); + + std::shared_ptr<MockDevice> mockdev = + std::make_shared<MockDevice>(dev_id, uniq_id); + transport_adapter.AddDevice(mockdev); + + std::vector<std::string> dev_list = transport_adapter.GetDeviceList(); + ASSERT_EQ(1u, dev_list.size()); + EXPECT_EQ(uniq_id, dev_list[0]); + + int app_handle = 1; + std::vector<int> int_list = {app_handle}; + EXPECT_CALL(*mockdev, GetApplicationList()).WillOnce(Return(int_list)); + + EXPECT_CALL(*server_mock, IsInitialised()).WillOnce(Return(true)); + EXPECT_CALL(*server_mock, CreateConnection(uniq_id, app_handle)) + .WillOnce(Return(TransportAdapter::FAIL)); + EXPECT_CALL(transport_adapter, FindDevice(uniq_id)).WillOnce(Return(mockdev)); + EXPECT_CALL(transport_adapter, GetDeviceType()) + .WillOnce(Return(DeviceType::CLOUD_WEBSOCKET)); + EXPECT_CALL(transport_adapter, ConnectionStatusUpdated()); + EXPECT_CALL(transport_manager_settings, cloud_app_max_retry_attempts()) + .WillOnce(Return(0)); + TransportAdapter::Error res = transport_adapter.ConnectDevice(uniq_id); + EXPECT_EQ(TransportAdapter::FAIL, res); + EXPECT_EQ(ConnectionStatus::PENDING, mockdev->connection_status()); + + EXPECT_CALL(*server_mock, Terminate()); +} + TEST_F(TransportAdapterTest, ConnectDevice_DeviceAddedTwice) { MockServerConnectionFactory* serverMock = new MockServerConnectionFactory(); MockTransportAdapterImpl transport_adapter( NULL, serverMock, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*serverMock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); @@ -370,8 +432,10 @@ TEST_F(TransportAdapterTest, ConnectDevice_DeviceAddedTwice) { EXPECT_CALL(*serverMock, CreateConnection(uniq_id, app_handle)) .WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(transport_adapter, FindDevice(uniq_id)).WillOnce(Return(mockdev)); + EXPECT_CALL(transport_adapter, ConnectionStatusUpdated()); TransportAdapter::Error res = transport_adapter.ConnectDevice(uniq_id); EXPECT_EQ(TransportAdapter::OK, res); + EXPECT_EQ(ConnectionStatus::CONNECTED, mockdev->connection_status()); // Try to connect device second time @@ -380,8 +444,10 @@ TEST_F(TransportAdapterTest, ConnectDevice_DeviceAddedTwice) { EXPECT_CALL(*serverMock, IsInitialised()).WillOnce(Return(true)); EXPECT_CALL(*serverMock, CreateConnection(uniq_id, app_handle)).Times(0); EXPECT_CALL(transport_adapter, FindDevice(uniq_id)).WillOnce(Return(mockdev)); + EXPECT_CALL(transport_adapter, ConnectionStatusUpdated()); TransportAdapter::Error newres = transport_adapter.ConnectDevice(uniq_id); EXPECT_EQ(TransportAdapter::OK, newres); + EXPECT_EQ(ConnectionStatus::CONNECTED, mockdev->connection_status()); EXPECT_CALL(*serverMock, Terminate()); } @@ -390,6 +456,7 @@ TEST_F(TransportAdapterTest, Disconnect_ConnectDoneSuccess) { MockServerConnectionFactory* serverMock = new MockServerConnectionFactory(); MockTransportAdapterImpl transport_adapter( NULL, serverMock, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*serverMock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); @@ -420,6 +487,7 @@ TEST_F(TransportAdapterTest, DisconnectDevice_DeviceAddedConnectionCreated) { MockServerConnectionFactory* serverMock = new MockServerConnectionFactory(); MockTransportAdapterImpl transport_adapter( NULL, serverMock, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*serverMock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); @@ -439,9 +507,12 @@ TEST_F(TransportAdapterTest, DisconnectDevice_DeviceAddedConnectionCreated) { EXPECT_CALL(*serverMock, IsInitialised()).WillOnce(Return(true)); EXPECT_CALL(*serverMock, CreateConnection(uniq_id, app_handle)) .WillOnce(Return(TransportAdapter::OK)); - EXPECT_CALL(transport_adapter, FindDevice(uniq_id)).WillOnce(Return(mockdev)); + EXPECT_CALL(transport_adapter, FindDevice(uniq_id)) + .WillRepeatedly(Return(mockdev)); + EXPECT_CALL(transport_adapter, ConnectionStatusUpdated()); TransportAdapter::Error res = transport_adapter.ConnectDevice(uniq_id); EXPECT_EQ(TransportAdapter::OK, res); + EXPECT_EQ(ConnectionStatus::CONNECTED, mockdev->connection_status()); auto mock_connection = std::make_shared<MockConnection>(); transport_adapter.ConnectionCreated(mock_connection, uniq_id, app_handle); @@ -449,8 +520,10 @@ TEST_F(TransportAdapterTest, DisconnectDevice_DeviceAddedConnectionCreated) { EXPECT_CALL(*mock_connection, Disconnect()) .WillOnce(Return(TransportAdapter::OK)); + EXPECT_CALL(transport_adapter, ConnectionStatusUpdated()); TransportAdapter::Error new_res = transport_adapter.DisconnectDevice(uniq_id); EXPECT_EQ(TransportAdapter::OK, new_res); + EXPECT_EQ(ConnectionStatus::CLOSING, mockdev->connection_status()); EXPECT_CALL(*serverMock, Terminate()); } @@ -459,6 +532,7 @@ TEST_F(TransportAdapterTest, DeviceDisconnected) { MockServerConnectionFactory* serverMock = new MockServerConnectionFactory(); MockTransportAdapterImpl transport_adapter( NULL, serverMock, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*serverMock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); @@ -482,8 +556,10 @@ TEST_F(TransportAdapterTest, DeviceDisconnected) { EXPECT_CALL(*serverMock, IsInitialised()).WillOnce(Return(true)); EXPECT_CALL(*serverMock, CreateConnection(uniq_id, app_handle)) .WillOnce(Return(TransportAdapter::OK)); + EXPECT_CALL(transport_adapter, ConnectionStatusUpdated()); TransportAdapter::Error res = transport_adapter.ConnectDevice(uniq_id); EXPECT_EQ(TransportAdapter::OK, res); + EXPECT_EQ(ConnectionStatus::CONNECTED, mockdev->connection_status()); std::shared_ptr<MockConnection> mock_connection = std::make_shared<MockConnection>(); @@ -507,6 +583,7 @@ TEST_F(TransportAdapterTest, AbortedConnectSuccess) { MockServerConnectionFactory* serverMock = new MockServerConnectionFactory(); MockTransportAdapterImpl transport_adapter( NULL, serverMock, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*serverMock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); @@ -533,6 +610,7 @@ TEST_F(TransportAdapterTest, SendData) { MockServerConnectionFactory* serverMock = new MockServerConnectionFactory(); MockTransportAdapterImpl transport_adapter( dev_mock, serverMock, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*dev_mock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(*serverMock, Init()).WillOnce(Return(TransportAdapter::OK)); @@ -574,6 +652,7 @@ TEST_F(TransportAdapterTest, SendData_ConnectionNotEstablished) { clientMock, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*dev_mock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(*clientMock, Init()).WillOnce(Return(TransportAdapter::OK)); @@ -609,6 +688,7 @@ TEST_F(TransportAdapterTest, StartClientListening_ClientNotInitialized) { MockClientConnectionListener* clientMock = new MockClientConnectionListener(); MockTransportAdapterImpl transport_adapter( dev_mock, NULL, clientMock, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*dev_mock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(*clientMock, Init()).WillOnce(Return(TransportAdapter::OK)); @@ -630,6 +710,7 @@ TEST_F(TransportAdapterTest, StartClientListening) { MockClientConnectionListener* clientMock = new MockClientConnectionListener(); MockTransportAdapterImpl transport_adapter( dev_mock, NULL, clientMock, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*dev_mock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(*clientMock, Init()).WillOnce(Return(TransportAdapter::OK)); @@ -656,6 +737,7 @@ TEST_F(TransportAdapterTest, StopClientListening_Success) { clientMock, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*dev_mock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(*clientMock, Init()).WillOnce(Return(TransportAdapter::OK)); @@ -690,6 +772,7 @@ TEST_F(TransportAdapterTest, FindNewApplicationsRequest) { clientMock, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*dev_mock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(*clientMock, Init()).WillOnce(Return(TransportAdapter::OK)); @@ -711,6 +794,7 @@ TEST_F(TransportAdapterTest, FindNewApplicationsRequest) { TEST_F(TransportAdapterTest, GetDeviceAndApplicationLists) { MockTransportAdapterImpl transport_adapter( NULL, NULL, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); transport_adapter.Init(); @@ -735,6 +819,7 @@ TEST_F(TransportAdapterTest, FindEstablishedConnection) { MockServerConnectionFactory* serverMock = new MockServerConnectionFactory(); MockTransportAdapterImpl transport_adapter( NULL, serverMock, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(*serverMock, Init()).WillOnce(Return(TransportAdapter::OK)); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); @@ -764,6 +849,7 @@ TEST_F(TransportAdapterTest, RunAppOnDevice_NoDeviseWithAskedId_UNSUCCESS) { MockTransportAdapterImpl transport_adapter( NULL, NULL, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); std::shared_ptr<MockDevice> mock_device = std::make_shared<MockDevice>("test_device_name", "test_device_uid0"); @@ -783,6 +869,7 @@ TEST_F(TransportAdapterTest, RunAppOnDevice_DeviseWithAskedIdWasFound_SUCCESS) { MockTransportAdapterImpl transport_adapter( NULL, NULL, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); std::shared_ptr<MockDevice> mock_device = std::make_shared<MockDevice>("test_device_name", device_uid); @@ -814,6 +901,7 @@ TEST_F(TransportAdapterTest, StopDevice) { TEST_F(TransportAdapterTest, TransportConfigUpdated) { MockTransportAdapterImpl transport_adapter( NULL, NULL, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); transport_adapter.Init(); @@ -832,6 +920,7 @@ TEST_F(TransportAdapterTest, TransportConfigUpdated) { TEST_F(TransportAdapterTest, GetTransportConfigration) { MockTransportAdapterImpl transport_adapter( NULL, NULL, NULL, last_state_, transport_manager_settings); + SetDefaultExpectations(transport_adapter); EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); transport_adapter.Init(); diff --git a/src/components/utils/include/utils/timer.h b/src/components/utils/include/utils/timer.h index e391db992c..b012b97e6a 100644 --- a/src/components/utils/include/utils/timer.h +++ b/src/components/utils/include/utils/timer.h @@ -102,6 +102,8 @@ class Timer { */ bool is_running() const; + bool is_completed() const; + /** * @brief Gets current timer timeout * @return Current timeout in milliseconds. @@ -119,7 +121,7 @@ class Timer { * @brief Constructor * @param timer Timer instance pointer for callback calling */ - TimerDelegate(const Timer* timer, sync_primitives::Lock& state_lock_ref); + TimerDelegate(Timer* timer, sync_primitives::Lock& state_lock_ref); /** * @brief Sets timer timeout @@ -161,7 +163,7 @@ class Timer { void exitThreadMain() OVERRIDE; private: - const Timer* timer_; + Timer* timer_; Milliseconds timeout_; /** @@ -187,13 +189,13 @@ class Timer { * Not thread-safe * @param timeout Timer timeout */ - void StartDelegate(const Milliseconds timeout) const; + void StartDelegate(const Milliseconds timeout); /** * @brief Sets up timer delegate to stop state. * Not thread-safe */ - void StopDelegate() const; + void StopDelegate(); /** * @brief Starts timer thread. @@ -211,14 +213,14 @@ class Timer { * @brief Callback called on timeout. * Not thread-safe */ - void OnTimeout() const; + void OnTimeout(); const std::string name_; TimerTask* task_; mutable sync_primitives::Lock state_lock_; - mutable std::unique_ptr<TimerDelegate> delegate_; + std::unique_ptr<TimerDelegate> delegate_; threads::Thread* thread_; /** @@ -226,6 +228,8 @@ class Timer { */ bool single_shot_; + bool completed_flag_; + DISALLOW_COPY_AND_ASSIGN(Timer); }; diff --git a/src/components/utils/src/timer.cc b/src/components/utils/src/timer.cc index b819b56f54..68693dfc55 100644 --- a/src/components/utils/src/timer.cc +++ b/src/components/utils/src/timer.cc @@ -49,7 +49,8 @@ timer::Timer::Timer(const std::string& name, TimerTask* task) , state_lock_() , delegate_(new TimerDelegate(this, state_lock_)) , thread_(threads::CreateThread(name_.c_str(), delegate_.get())) - , single_shot_(true) { + , single_shot_(true) + , completed_flag_(false) { LOG4CXX_AUTO_TRACE(logger_); DCHECK(!name_.empty()); DCHECK(task_); @@ -76,6 +77,7 @@ void timer::Timer::Start(const Milliseconds timeout, LOG4CXX_AUTO_TRACE(logger_); sync_primitives::AutoLock auto_lock(state_lock_); StopThread(); + completed_flag_ = false; switch (timer_type) { case kSingleShot: { single_shot_ = true; @@ -106,17 +108,21 @@ bool timer::Timer::is_running() const { return !delegate_->stop_flag(); } +bool timer::Timer::is_completed() const { + return completed_flag_; +} + timer::Milliseconds timer::Timer::timeout() const { sync_primitives::AutoLock auto_lock(state_lock_); return delegate_->timeout(); } -void timer::Timer::StartDelegate(const Milliseconds timeout) const { +void timer::Timer::StartDelegate(const Milliseconds timeout) { delegate_->set_stop_flag(false); delegate_->set_timeout(timeout); } -void timer::Timer::StopDelegate() const { +void timer::Timer::StopDelegate() { delegate_->set_stop_flag(true); delegate_->set_timeout(0); } @@ -148,7 +154,7 @@ void timer::Timer::StopThread() { } } -void timer::Timer::OnTimeout() const { +void timer::Timer::OnTimeout() { { sync_primitives::AutoLock auto_lock(state_lock_); if (single_shot_) { @@ -158,10 +164,11 @@ void timer::Timer::OnTimeout() const { DCHECK_OR_RETURN_VOID(task_); task_->run(); + completed_flag_ = true; } timer::Timer::TimerDelegate::TimerDelegate( - const Timer* timer, sync_primitives::Lock& state_lock_ref) + Timer* timer, sync_primitives::Lock& state_lock_ref) : timer_(timer) , timeout_(0) , stop_flag_(true) |