diff options
38 files changed, 1826 insertions, 93 deletions
diff --git a/src/components/application_manager/include/application_manager/app_extension.h b/src/components/application_manager/include/application_manager/app_extension.h index bf2675e36f..3b1db4de57 100644 --- a/src/components/application_manager/include/application_manager/app_extension.h +++ b/src/components/application_manager/include/application_manager/app_extension.h @@ -74,10 +74,11 @@ class AppExtension { /** * @brief RevertResumption Method called by SDL during revert resumption. - * @param subscriptions Subscriptions from which must discard. Expected that - * SO contains the map of "IVI data" keys and "subscription bool flag" values + * @param resumption_data Resumption data in the SmartObject representation + * that contains subscription (VehicleInfo, RemoteControl, etc.) */ - virtual void RevertResumption(const ns_smart::SmartObject& subscriptions) = 0; + virtual void RevertResumption( + const ns_smart::SmartObject& resumption_data) = 0; private: const AppExtensionUID kUid_; diff --git a/src/components/application_manager/include/application_manager/resumption/resumption_data_processor.h b/src/components/application_manager/include/application_manager/resumption/resumption_data_processor.h index 943022295b..60e2e5d1a4 100644 --- a/src/components/application_manager/include/application_manager/resumption/resumption_data_processor.h +++ b/src/components/application_manager/include/application_manager/resumption/resumption_data_processor.h @@ -29,6 +29,7 @@ #include "application_manager/application.h" #include "application_manager/resumption/resume_ctrl.h" +#include "application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_rpc_types.h" #include "smart_objects/smart_object.h" namespace resumption { @@ -44,6 +45,8 @@ bool IsResponseSuccessful(const smart_objects::SmartObject& response); * @brief The ResumptionRequestID struct contains fields, needed during * processing events, related to responses from HMI to each resumption request */ +using ModuleUid = rc_rpc_plugin::rc_rpc_types::ModuleUid; + struct ResumptionRequestID { hmi_apis::FunctionID::eType function_id; int32_t correlation_id; diff --git a/src/components/application_manager/include/application_manager/resumption/resumption_data_processor_impl.h b/src/components/application_manager/include/application_manager/resumption/resumption_data_processor_impl.h index 0b3c84432b..12d25e2ac5 100644 --- a/src/components/application_manager/include/application_manager/resumption/resumption_data_processor_impl.h +++ b/src/components/application_manager/include/application_manager/resumption/resumption_data_processor_impl.h @@ -52,6 +52,8 @@ struct ApplicationResumptionStatus { std::vector<ResumptionRequest> successful_requests; std::vector<std::string> unsuccessful_vehicle_data_subscriptions_; std::vector<std::string> successful_vehicle_data_subscriptions_; + std::vector<ModuleUid> successful_module_subscriptions_; + std::vector<ModuleUid> unsuccessful_module_subscriptions_; }; /** @@ -339,6 +341,10 @@ class ResumptionDataProcessorImpl const smart_objects::SmartObject& response, ApplicationResumptionStatus& status); + void CheckModuleDataSubscription(const smart_objects::SmartObject& request, + const smart_objects::SmartObject& response, + ApplicationResumptionStatus& status); + /** * @brief Checks whether CreateWindow response successful or not and handles * it diff --git a/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/include/app_service_rpc_plugin/app_service_app_extension.h b/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/include/app_service_rpc_plugin/app_service_app_extension.h index eff9567122..8d307325fc 100644 --- a/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/include/app_service_rpc_plugin/app_service_app_extension.h +++ b/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/include/app_service_rpc_plugin/app_service_app_extension.h @@ -103,7 +103,7 @@ class AppServiceAppExtension : public app_mngr::AppExtension { void ProcessResumption(const smart_objects::SmartObject& saved_app) OVERRIDE; void RevertResumption( - const smart_objects::SmartObject& subscriptions) OVERRIDE; + const smart_objects::SmartObject& resumption_data) OVERRIDE; /** * @brief ExtractVIExtension utility function to extract application extension diff --git a/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/src/app_service_app_extension.cc b/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/src/app_service_app_extension.cc index b5b27fc157..5a1815d974 100644 --- a/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/src/app_service_app_extension.cc +++ b/src/components/application_manager/rpc_plugins/app_service_rpc_plugin/src/app_service_app_extension.cc @@ -113,10 +113,10 @@ void AppServiceAppExtension::ProcessResumption( } void AppServiceAppExtension::RevertResumption( - const smart_objects::SmartObject& subscriptions) { + const smart_objects::SmartObject& resumption_data) { SDL_LOG_AUTO_TRACE(); - UNUSED(subscriptions); + UNUSED(resumption_data); // ToDo: implementation is blocked by // https://github.com/smartdevicelink/sdl_core/issues/3470 } diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/commands/hmi/rc_get_interior_vehicle_data_request.h b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/commands/hmi/rc_get_interior_vehicle_data_request.h index a75020956c..f81919f4fa 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/commands/hmi/rc_get_interior_vehicle_data_request.h +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/commands/hmi/rc_get_interior_vehicle_data_request.h @@ -51,6 +51,8 @@ class RCGetInteriorVehicleDataRequest const RCCommandParams& params); void Run() OVERRIDE; + void onTimeOut() OVERRIDE; + ~RCGetInteriorVehicleDataRequest(); }; diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/interior_data_manager.h b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/interior_data_manager.h index c1fe30fa4d..e265fb7427 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/interior_data_manager.h +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/interior_data_manager.h @@ -87,6 +87,13 @@ class InteriorDataManager { * false. */ virtual bool CheckRequestsToHMIFrequency(const ModuleUid& module) = 0; + + /** + * @brief Reverts resumption data and sends ubsubscribe vehicle data request + * to a HMI + * @param subscriptions Module data that SDL should unsubscribe off + */ + virtual void OnResumptionRevert(const std::set<ModuleUid>& subscriptions) = 0; }; } // namespace rc_rpc_plugin diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/interior_data_manager_impl.h b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/interior_data_manager_impl.h index 791016cdcd..43927b25c8 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/interior_data_manager_impl.h +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/interior_data_manager_impl.h @@ -65,6 +65,8 @@ class InteriorDataManagerImpl : public InteriorDataManager { bool CheckRequestsToHMIFrequency(const ModuleUid& module) OVERRIDE; + void OnResumptionRevert(const std::set<ModuleUid>& subscriptions) OVERRIDE; + private: /** * @brief UpdateHMISubscriptionsOnPolicyUpdated process policy update event. diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_app_extension.h b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_app_extension.h index ab88ac8975..8b2162c9ab 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_app_extension.h +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_app_extension.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Ford Motor Company + * Copyright (c) 2020, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,7 +36,9 @@ #include <memory> #include <set> #include <string> + #include "application_manager/app_extension.h" +#include "application_manager/application.h" #include "utils/macro.h" namespace rc_rpc_plugin { @@ -137,9 +139,13 @@ struct Grid { } }; +class RCRPCPlugin; + class RCAppExtension : public application_manager::AppExtension { public: - explicit RCAppExtension(application_manager::AppExtensionUID uid); + explicit RCAppExtension(application_manager::AppExtensionUID uid, + RCRPCPlugin& plugin, + application_manager::Application& application); ~RCAppExtension(); /** @@ -177,6 +183,36 @@ class RCAppExtension : public application_manager::AppExtension { std::set<ModuleUid> InteriorVehicleDataSubscriptions() const; /** + * @brief AddPendingSubscription adds pending subscription + * @param module interior data specification(zone, data type) + * @return true in case of pending subscription is successful added, otherwise + * false + */ + bool AddPendingSubscription(const ModuleUid& module); + + /** + * @brief RemovePendingSubscription removes some particular pending + * subscription + * @param module interior data specification(zone, data type) + */ + void RemovePendingSubscription(const ModuleUid& module); + + /** + * @brief RemovePendingSubscriptions removes all pending subscriptions + */ + void RemovePendingSubscriptions(); + + /** + * @brief PendingSubscriptions list of preliminary subscriptoins + * That will be moved to subscriptions as soon as HMI will respond with + * success. + * Used for resumption to keep list of preliminary subscriptions and wait for + * HMI response + * @return list of preliminary subscriptions + */ + std::set<ModuleUid> PendingSubscriptions(); + + /** * @brief GetUserLocation * @return grid of user location */ @@ -197,10 +233,25 @@ class RCAppExtension : public application_manager::AppExtension { void SetUserLocation(const Grid& grid); private: + /** + * @brief Checks if the application's pointer is valid and update the + * application's hash in this case + */ + void UpdateHash(); + std::set<ModuleUid> subscribed_interior_vehicle_data_; + std::set<ModuleUid> pending_subscriptions_; + Grid user_location_; + RCRPCPlugin& plugin_; + + /** + * ApplicationSharedPtr needed for updating application's hash + */ + application_manager::Application& application_; + // AppExtension interface public: void SaveResumptionData(smart_objects::SmartObject& resumption_data) OVERRIDE; @@ -208,7 +259,7 @@ class RCAppExtension : public application_manager::AppExtension { void ProcessResumption(const smart_objects::SmartObject& saved_app) OVERRIDE; void RevertResumption( - const smart_objects::SmartObject& subscriptions) OVERRIDE; + const smart_objects::SmartObject& resumption_data) OVERRIDE; }; typedef std::shared_ptr<RCAppExtension> RCAppExtensionPtr; diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_helpers.h b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_helpers.h index eed860fc7f..1bf4a7a259 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_helpers.h +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_helpers.h @@ -80,8 +80,12 @@ class RCHelpers { static RCAppExtensionPtr GetRCExtension( application_manager::Application& app); - static smart_objects::SmartObjectSPtr CreateUnsubscribeRequestToHMI( - const ModuleUid& module, const uint32_t correlation_id); + enum InteriorDataAction { SUBSCRIBE, UNSUBSCRIBE, NONE }; + + static smart_objects::SmartObjectSPtr CreateGetInteriorVDRequestToHMI( + const ModuleUid& module, + const uint32_t correlation_id, + const InteriorDataAction action); static std::vector<application_manager::ApplicationSharedPtr> AppsSubscribedToModule(application_manager::ApplicationManager& app_mngr, @@ -169,6 +173,13 @@ class RCHelpers { static smart_objects::SmartObject MergeArray( const smart_objects::SmartObject& data1, const smart_objects::SmartObject& data2); + + /** + * @brief Determines the success of the response + * judging from message type received from HMI + * @param response from HMI + */ + static bool IsResponseSuccessful(const smart_objects::SmartObject& response); }; } // namespace rc_rpc_plugin diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_pending_resumption_handler.h b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_pending_resumption_handler.h new file mode 100644 index 0000000000..944d47b052 --- /dev/null +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_pending_resumption_handler.h @@ -0,0 +1,165 @@ +#pragma once + +#include <map> +#include <queue> +#include "application_manager/event_engine/event_observer.h" +#include "application_manager/resumption/pending_resumption_handler.h" +#include "application_manager/resumption/resumption_data_processor.h" +#include "application_manager/rpc_service.h" +#include "rc_rpc_plugin/interior_data_cache.h" +#include "rc_rpc_plugin/rc_app_extension.h" + +namespace rc_rpc_plugin { + +/** + * @brief The RCPendingResumptionHandler class + * responsibility to avoid duplication of subscription requests to HMI + * if multiple applications are registering + */ +class RCPendingResumptionHandler : public resumption::PendingResumptionHandler { + public: + RCPendingResumptionHandler( + application_manager::ApplicationManager& application_manager, + rc_rpc_plugin::InteriorDataCache& interior_data_cache); + + void on_event(const application_manager::event_engine::Event& event) override; + + void HandleResumptionSubscriptionRequest( + application_manager::AppExtension& extension, + application_manager::Application& app) override; + + void OnResumptionRevert() override; + + /** + * @brief Creates GetInteriorVehicleData subscription request + * @param module unique identifier of module (moduleType + moduleID) used to + * create the request + * @param correlation_id - unique ID + * @return subscription request in smart object representation + */ + static smart_objects::SmartObjectSPtr CreateSubscriptionRequest( + const ModuleUid& module, const uint32_t correlation_id); + + /** + * @brief Retrieves function id from subscription request + * @param subscription_request a subscription request that contains the + * function id + * @return function id + */ + static hmi_apis::FunctionID::eType GetFunctionId( + const smart_objects::SmartObject& subscription_request); + + /** + * @brief Retrieves module uid from subscription request + * @param subscription_request a subscription request that contains a unique + * module identifier + * @return unique module identifier + */ + static ModuleUid GetModuleUid( + const smart_objects::SmartObject& subscription_request); + + private: + /** + * @brief The PendingRequest struct contains fields, needed during + * processing events, related to responses from HMI to each resumption request + */ + struct PendingRequest { + uint32_t app_id; + smart_objects::SmartObject message; + uint32_t correlation_id() const { + namespace am_strings = app_mngr::strings; + return message[am_strings::params][am_strings::correlation_id].asInt(); + } + }; + + /** + * @brief Handles a successful response from HMI + * @param event contains response from HMI + * @param module_uid a unique identifier for module + */ + void HandleSuccessfulResponse( + const application_manager::event_engine::Event& event, + const ModuleUid& module_uid); + + /** + * @brief Creates next GetInteriorVehicleData subscription request if a + * previous resumption of subscriptions is not successful + * @param module a unique identifier for module + */ + void ProcessNextPausedResumption(const ModuleUid& module); + + /** + * @brief Notifies subscriber about resumption status + * @param subscription_response response from HMI + * @param correlation_id unique message ID + */ + void RaiseEventForResponse( + const smart_objects::SmartObject& subscription_response, + const uint32_t correlation_id) const; + + /** + * @brief Checks if SDL is still waiting on a subscription response for the + * specified module + * @param module the unique identifier for the module to be checked against + */ + bool IsPendingForResponse(const ModuleUid& module) const; + + /** + * @brief Checks if any app except passed is subscribed to a given module + * @param module module to check + * @param app_id app to ignore subscription + * @return true if any app except passed is subscribed to module, otherwise + * false + */ + bool IsOtherAppsSubscribed(const uint32_t app_id, + const ModuleUid& module) const; + + /** + * @brief Returns pending request, which corresponds to correlation ID + * @param corr_id unique message ID + * @return optional object, which contains subscription request, or empty + * optional, if such request wasn't found + */ + utils::Optional<smart_objects::SmartObject> GetPendingRequest( + const uint32_t corr_id); + + /** + * @brief Returns ID of application, related to pending request, which + * corresponds to correlation ID + * @param corr_id unique message ID + * @return optional object, which contains ID of application, or empty + * optional, if such request wasn't found + */ + utils::Optional<uint32_t> GetPendingApp(const uint32_t corr_id); + + /** + * @brief Removes pending request, which corresponds to + * correlation ID + * @param corr_id unique ID + */ + void RemovePendingRequest(const uint32_t corr_id); + + /** + * @brief Adds pending request, related to + * application ID + * @param request_so pending request message + */ + void AddPendingRequest(const uint32_t app_id, + const smart_objects::SmartObject request_so); + + /** + * @brief PendingRequestQueue contains subscription request, + * which will be sent to the HMI in the case that a previous resumption + * attempt for the same module was not successful + */ + using PendingRequestQueue = std::queue<PendingRequest>; + std::map<ModuleUid, PendingRequestQueue> paused_resumptions_; + + sync_primitives::Lock pending_resumption_lock_; + std::vector<PendingRequest> pending_requests_; + + application_manager::rpc_service::RPCService& rpc_service_; + rc_rpc_plugin::InteriorDataCache& interior_data_cache_; +}; + +} // namespace rc_rpc_plugin diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_rpc_plugin.h b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_rpc_plugin.h index 51e0668930..528e116403 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_rpc_plugin.h +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_rpc_plugin.h @@ -37,6 +37,7 @@ #include "application_manager/command_factory.h" #include "application_manager/plugin_manager/rpc_plugin.h" +#include "application_manager/resumption/pending_resumption_handler.h" #include "rc_rpc_plugin/interior_data_cache.h" #include "rc_rpc_plugin/interior_data_manager.h" #include "rc_rpc_plugin/rc_capabilities_manager.h" @@ -103,6 +104,33 @@ class RCRPCPlugin : public plugins::RPCPlugin { void OnApplicationEvent(plugins::ApplicationEvent event, app_mngr::ApplicationSharedPtr application) OVERRIDE; + /** + * @brief ProcessResumptionSubscription send Subscribe vehicle data requests + * to HMI + * @param app application for subscription + * @param ext application extension + */ + void ProcessResumptionSubscription(app_mngr::Application& app, + RCAppExtension& ext); + + /** + * @brief Reverts resumption data, clears all pending resumption and sends + * unsubscribe interior vehicle data requests to HMI + * @param subscriptions Module data that SDL should unsubscribe off + */ + void RevertResumption(const std::set<ModuleUid>& subscriptions); + + /** + * @brief IsOtherAppsSubscribed check if any app except passed is subscribed + * to a given module + * @param module module to check + * @param app_id app to ignore subscription + * @return true if any app except passed is subscribed to module, otherwise + * false + */ + bool IsOtherAppsSubscribed(const rc_rpc_types::ModuleUid& module, + const uint32_t app_id); + static const uint32_t kRCPluginID = 153; typedef std::vector<application_manager::ApplicationSharedPtr> Apps; @@ -118,6 +146,9 @@ class RCRPCPlugin : public plugins::RPCPlugin { std::unique_ptr<InteriorDataCache> interior_data_cache_; std::unique_ptr<InteriorDataManager> interior_data_manager_; std::unique_ptr<RCCapabilitiesManager> rc_capabilities_manager_; + using PendingResumptionHandlerSPtr = + std::shared_ptr<resumption::PendingResumptionHandler>; + PendingResumptionHandlerSPtr pending_resumption_handler_; }; } // namespace rc_rpc_plugin diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/commands/hmi/rc_get_interior_vehicle_data_request.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/commands/hmi/rc_get_interior_vehicle_data_request.cc index ffe124f3bd..fede1dbd11 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/commands/hmi/rc_get_interior_vehicle_data_request.cc +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/commands/hmi/rc_get_interior_vehicle_data_request.cc @@ -31,6 +31,9 @@ */ #include "rc_rpc_plugin/commands/hmi/rc_get_interior_vehicle_data_request.h" +#include "application_manager/message_helper.h" +#include "application_manager/resumption/resume_ctrl.h" + #include "utils/macro.h" namespace rc_rpc_plugin { @@ -54,5 +57,21 @@ void RCGetInteriorVehicleDataRequest::Run() { SendRequest(); } +void RCGetInteriorVehicleDataRequest::onTimeOut() { + SDL_LOG_TRACE("function_id: " << function_id() + << " correlation_id: " << correlation_id()); + using namespace application_manager; + event_engine::Event timeout_event( + hmi_apis::FunctionID::RC_GetInteriorVehicleData); + + auto error_response = MessageHelper::CreateNegativeResponseFromHmi( + function_id(), + correlation_id(), + hmi_apis::Common_Result::GENERIC_ERROR, + std::string("Timed out")); + timeout_event.set_smart_object(*error_response); + timeout_event.raise(application_manager_.event_dispatcher()); +} + } // namespace commands } // namespace rc_rpc_plugin diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/commands/mobile/get_interior_vehicle_data_request.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/commands/mobile/get_interior_vehicle_data_request.cc index 7d274870bc..2b801f7406 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/commands/mobile/get_interior_vehicle_data_request.cc +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/commands/mobile/get_interior_vehicle_data_request.cc @@ -119,21 +119,34 @@ void GetInteriorVehicleDataRequest::ProcessResponseToMobileFromCache( const auto& request_msg_params = (*message_)[app_mngr::strings::msg_params]; SDL_LOG_DEBUG("kSubscribe exist" << request_msg_params.keyExists(message_params::kSubscribe)); + + mobile_apis::Result::eType result_code = mobile_apis::Result::SUCCESS; if (request_msg_params.keyExists(message_params::kSubscribe)) { response_msg_params[message_params::kIsSubscribed] = request_msg_params[message_params::kSubscribe].asBool(); if (request_msg_params[message_params::kSubscribe].asBool()) { auto extension = RCHelpers::GetRCExtension(*app); DCHECK(extension); - extension->SubscribeToInteriorVehicleData(module); + const bool is_app_already_subscribed = + extension->IsSubscribedToInteriorVehicleData(module); + if (is_app_already_subscribed) { + response_msg_params[app_mngr::strings::info] = + "App is already subscribed to the provided module"; + result_code = mobile_apis::Result::WARNINGS; + } else { + extension->SubscribeToInteriorVehicleData(module); + app->UpdateHash(); + } } } - SendResponse( - true, mobile_apis::Result::SUCCESS, nullptr, &response_msg_params); + SendResponse(true, result_code, nullptr, &response_msg_params); if (AppShouldBeUnsubscribed()) { auto extension = RCHelpers::GetRCExtension(*app); DCHECK(extension); - extension->UnsubscribeFromInteriorVehicleData(module); + if (extension->IsSubscribedToInteriorVehicleData(module)) { + extension->UnsubscribeFromInteriorVehicleData(module); + app->UpdateHash(); + } } } @@ -255,6 +268,9 @@ void GetInteriorVehicleDataRequest::on_event( const ModuleUid module(module_type, module_id); if (TheLastAppShouldBeUnsubscribed(app)) { + SDL_LOG_DEBUG("Removing module: [" << module.first << ":" << module.second + << "] " + << "from cache"); interior_data_cache_.Remove(module); } ProccessSubscription(hmi_response); @@ -363,15 +379,19 @@ void GetInteriorVehicleDataRequest::ProccessSubscription( const std::string module_id = ModuleId(); const ModuleUid module(module_type, module_id); - if (response_subscribe) { + if (response_subscribe && + !extension->IsSubscribedToInteriorVehicleData(module)) { SDL_LOG_DEBUG("SubscribeToInteriorVehicleData " << app->app_id() << " " << module_type << " " << module_id); extension->SubscribeToInteriorVehicleData(module); - } else { + } else if (!response_subscribe && + extension->IsSubscribedToInteriorVehicleData(module)) { SDL_LOG_DEBUG("UnsubscribeFromInteriorVehicleData " << app->app_id() << " " << module_type << " " << module_id); extension->UnsubscribeFromInteriorVehicleData(module); } + + app->UpdateHash(); } } diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/interior_data_manager_impl.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/interior_data_manager_impl.cc index a4d4026da7..1db25265e7 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/interior_data_manager_impl.cc +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/interior_data_manager_impl.cc @@ -49,6 +49,13 @@ void InteriorDataManagerImpl::OnDisablingRC() { } } +void InteriorDataManagerImpl::OnResumptionRevert( + const std::set<ModuleUid>& subscriptions) { + for (const auto& module : subscriptions) { + UnsubscribeFromInteriorVehicleData(module); + } +} + void InteriorDataManagerImpl::StoreRequestToHMITime(const ModuleUid& module) { SDL_LOG_AUTO_TRACE(); sync_primitives::AutoLock autolock(requests_to_hmi_history_lock_); @@ -125,8 +132,10 @@ void InteriorDataManagerImpl::UpdateHMISubscriptionsOnAppUnregistered( void InteriorDataManagerImpl::UnsubscribeFromInteriorVehicleData( const ModuleUid& module) { cache_.Remove(module); - auto unsubscribe_request = RCHelpers::CreateUnsubscribeRequestToHMI( - module, app_mngr_.GetNextHMICorrelationID()); + auto unsubscribe_request = RCHelpers::CreateGetInteriorVDRequestToHMI( + module, + app_mngr_.GetNextHMICorrelationID(), + RCHelpers::InteriorDataAction::UNSUBSCRIBE); SDL_LOG_DEBUG("Send Unsubscribe from module type: " << module.first << " id: " << module.second); rpc_service_.ManageHMICommand(unsubscribe_request); @@ -138,8 +147,10 @@ void InteriorDataManagerImpl::UnsubscribeFromInteriorVehicleDataOfType( for (const auto& module : modules) { cache_.Remove(module); - auto unsubscribe_request = RCHelpers::CreateUnsubscribeRequestToHMI( - module, app_mngr_.GetNextHMICorrelationID()); + auto unsubscribe_request = RCHelpers::CreateGetInteriorVDRequestToHMI( + module, + app_mngr_.GetNextHMICorrelationID(), + RCHelpers::InteriorDataAction::UNSUBSCRIBE); SDL_LOG_DEBUG("Send Unsubscribe from module type: " << module.first << " id: " << module.second); rpc_service_.ManageHMICommand(unsubscribe_request); diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_app_extension.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_app_extension.cc index 0f0c6c3ab1..3bfad3095b 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_app_extension.cc +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_app_extension.cc @@ -30,14 +30,51 @@ POSSIBILITY OF SUCH DAMAGE. */ -#include "rc_rpc_plugin/rc_app_extension.h" #include <algorithm> + +#include "rc_rpc_plugin/rc_app_extension.h" + #include "rc_rpc_plugin/rc_module_constants.h" +#include "rc_rpc_plugin/rc_rpc_plugin.h" #include "smart_objects/smart_object.h" +#include "utils/logger.h" + +SDL_CREATE_LOG_VARIABLE("RemoteControlModule") + +namespace { +std::set<rc_rpc_plugin::ModuleUid> ConvertSmartObjectToModuleCollection( + const smart_objects::SmartObject& resumption_data) { + using namespace rc_rpc_plugin; + + if (!resumption_data.keyExists(application_manager::hmi_interface::rc)) { + SDL_LOG_DEBUG("No resumption module data subscription to revert"); + return {}; + } + + const auto& module_data = + resumption_data[application_manager::hmi_interface::rc] + [message_params::kModuleData]; + + std::set<rc_rpc_plugin::ModuleUid> module_collection; + + if (!module_data.empty()) { + for (const auto& module : *(module_data.asArray())) { + const auto module_type = module[message_params::kModuleType].asString(); + const auto module_id = module[message_params::kModuleId].asString(); + + module_collection.insert({module_type, module_id}); + } + } + + return module_collection; +} +} // namespace namespace rc_rpc_plugin { -RCAppExtension::RCAppExtension(application_manager::AppExtensionUID uid) - : AppExtension(uid) {} +RCAppExtension::RCAppExtension(application_manager::AppExtensionUID uid, + RCRPCPlugin& plugin, + application_manager::Application& application) + : AppExtension(uid), plugin_(plugin), application_(application) {} void RCAppExtension::SubscribeToInteriorVehicleData(const ModuleUid& module) { subscribed_interior_vehicle_data_.insert(module); @@ -50,11 +87,19 @@ void RCAppExtension::UnsubscribeFromInteriorVehicleData( void RCAppExtension::UnsubscribeFromInteriorVehicleDataOfType( const std::string& module_type) { + bool unsubscribed = false; for (auto& item : subscribed_interior_vehicle_data_) { if (module_type == item.first) { subscribed_interior_vehicle_data_.erase(item); + unsubscribed = true; } } + + if (unsubscribed) { + // If didin't unsubscribe from some module type, we don't need to update + // application hash + UpdateHash(); + } } void RCAppExtension::UnsubscribeFromInteriorVehicleData() { @@ -81,18 +126,124 @@ bool RCAppExtension::IsSubscribedToInteriorVehicleData( } void RCAppExtension::SaveResumptionData( - smart_objects::SmartObject& resumption_data) {} + smart_objects::SmartObject& resumption_data) { + SDL_LOG_AUTO_TRACE(); + + if (subscribed_interior_vehicle_data_.empty()) { + SDL_LOG_DEBUG("Subscribed modules data is absent"); + return; + } + + resumption_data[message_params::kModuleData] = + smart_objects::SmartObject(smart_objects::SmartType_Array); + auto& module_data = resumption_data[message_params::kModuleData]; + + uint32_t index = 0; + for (const auto& module_uid : subscribed_interior_vehicle_data_) { + SDL_LOG_DEBUG("Save module: [" << module_uid.first << ":" + << module_uid.second << "]"); + auto module_info_so = + smart_objects::SmartObject(smart_objects::SmartType_Map); + module_info_so[message_params::kModuleType] = module_uid.first; + module_info_so[message_params::kModuleId] = module_uid.second; + module_data[index++] = module_info_so; + } +} void RCAppExtension::ProcessResumption( - const smart_objects::SmartObject& saved_app) {} + const smart_objects::SmartObject& saved_app) { + SDL_LOG_AUTO_TRACE(); + SDL_LOG_TRACE("app id : " << application_.app_id()); + + if (!saved_app.keyExists( + application_manager::strings::application_subscriptions)) { + SDL_LOG_DEBUG("application_subscriptions section does not exist"); + return; + } + + const auto& resumption_data = + saved_app[application_manager::strings::application_subscriptions]; + + if (!resumption_data.keyExists(message_params::kModuleData)) { + SDL_LOG_DEBUG("kModuleData section does not exist"); + return; + } + + auto& module_data = resumption_data[message_params::kModuleData]; + + if (0 == module_data.length()) { + SDL_LOG_WARN("Subscribed modules data is absent"); + return; + } + + for (const auto& module_so : *module_data.asArray()) { + const auto module_type = module_so[message_params::kModuleType].asString(); + const auto module_id = module_so[message_params::kModuleId].asString(); + + ModuleUid module{module_type, module_id}; + SDL_LOG_TRACE("app id " << application_.app_id() << " type : " + << module_type << " id <" << module_id); + AddPendingSubscription(module); + } + + plugin_.ProcessResumptionSubscription(application_, *this); +} void RCAppExtension::RevertResumption( - const smart_objects::SmartObject& subscriptions) {} + const smart_objects::SmartObject& resumption_data) { + SDL_LOG_AUTO_TRACE(); + + UnsubscribeFromInteriorVehicleData(); + + const auto module_subscriptions = + ConvertSmartObjectToModuleCollection(resumption_data); + + for (auto& module : module_subscriptions) { + SDL_LOG_TRACE("Requested to unsubscribe module_type " + << module.first << "module_id: " << module.second); + } + std::set<rc_rpc_plugin::ModuleUid> to_be_unsubscribed; + + const auto app_id = application_.app_id(); + auto no_apps_subscribed = [app_id, + this](const rc_rpc_plugin::ModuleUid& module) { + if (plugin_.IsOtherAppsSubscribed(module, app_id)) { + SDL_LOG_DEBUG("Some other app except " << app_id + << " is already subscribed to " + << " module_type " << module.first + << "module_id: " << module.second); + return false; + } + return true; + }; + std::copy_if(module_subscriptions.begin(), + module_subscriptions.end(), + std::inserter(to_be_unsubscribed, to_be_unsubscribed.end()), + no_apps_subscribed); + + plugin_.RevertResumption(to_be_unsubscribed); +} std::set<ModuleUid> RCAppExtension::InteriorVehicleDataSubscriptions() const { return subscribed_interior_vehicle_data_; } +bool RCAppExtension::AddPendingSubscription(const ModuleUid& module) { + return pending_subscriptions_.insert(module).second; +} + +void RCAppExtension::RemovePendingSubscription(const ModuleUid& module) { + pending_subscriptions_.erase(module); +} + +void RCAppExtension::RemovePendingSubscriptions() { + pending_subscriptions_.clear(); +} + +std::set<ModuleUid> RCAppExtension::PendingSubscriptions() { + return pending_subscriptions_; +} + Grid RCAppExtension::GetUserLocation() const { return user_location_; } @@ -113,5 +264,9 @@ void RCAppExtension::SetUserLocation(const Grid& grid) { user_location_ = grid; } +void RCAppExtension::UpdateHash() { + application_.UpdateHash(); +} + RCAppExtension::~RCAppExtension() {} } // namespace rc_rpc_plugin diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_helpers.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_helpers.cc index dea7203717..768502832d 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_helpers.cc +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_helpers.cc @@ -182,8 +182,10 @@ RCAppExtensionPtr RCHelpers::GetRCExtension( return extension; } -smart_objects::SmartObjectSPtr RCHelpers::CreateUnsubscribeRequestToHMI( - const ModuleUid& module, const uint32_t correlation_id) { +smart_objects::SmartObjectSPtr RCHelpers::CreateGetInteriorVDRequestToHMI( + const ModuleUid& module, + const uint32_t correlation_id, + const InteriorDataAction action) { using namespace smart_objects; namespace commands = application_manager::commands; namespace am_strings = application_manager::strings; @@ -200,7 +202,10 @@ smart_objects::SmartObjectSPtr RCHelpers::CreateUnsubscribeRequestToHMI( params[am_strings::correlation_id] = correlation_id; params[am_strings::function_id] = hmi_apis::FunctionID::RC_GetInteriorVehicleData; - msg_params[message_params::kSubscribe] = false; + if (NONE != action) { + msg_params[message_params::kSubscribe] = + (SUBSCRIBE == action) ? true : false; + } msg_params[message_params::kModuleType] = module.first; msg_params[message_params::kModuleId] = module.second; return message; @@ -362,4 +367,27 @@ smart_objects::SmartObject RCHelpers::MergeArray( return result; } +bool RCHelpers::IsResponseSuccessful( + const smart_objects::SmartObject& response) { + hmi_apis::messageType::eType message_type = + static_cast<hmi_apis::messageType::eType>( + response[application_manager::strings::params] + [application_manager::strings::message_type] + .asInt()); + const bool is_correct_message_type = + hmi_apis::messageType::response == message_type; + + bool is_subscribe_successful = false; + + if (response[application_manager::strings::msg_params].keyExists( + rc_rpc_plugin::message_params::kIsSubscribed)) { + is_subscribe_successful = + response[application_manager::strings::msg_params] + [rc_rpc_plugin::message_params::kIsSubscribed] + .asBool(); + } + + return is_correct_message_type && is_subscribe_successful; +} + } // namespace rc_rpc_plugin diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_pending_resumption_handler.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_pending_resumption_handler.cc new file mode 100644 index 0000000000..e66023f27a --- /dev/null +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_pending_resumption_handler.cc @@ -0,0 +1,343 @@ +#include "rc_rpc_plugin/rc_pending_resumption_handler.h" +#include <sstream> +#include "rc_rpc_plugin/rc_helpers.h" +#include "rc_rpc_plugin/rc_module_constants.h" + +namespace rc_rpc_plugin { + +SDL_CREATE_LOG_VARIABLE("RemoteControlModule") + +RCPendingResumptionHandler::RCPendingResumptionHandler( + application_manager::ApplicationManager& application_manager, + InteriorDataCache& interior_data_cache) + : PendingResumptionHandler(application_manager) + , rpc_service_(application_manager.GetRPCService()) + , interior_data_cache_(interior_data_cache) {} + +void RCPendingResumptionHandler::on_event( + const application_manager::event_engine::Event& event) { + SDL_LOG_AUTO_TRACE(); + namespace am_strings = application_manager::strings; + sync_primitives::AutoLock lock(pending_resumption_lock_); + const auto cid = event.smart_object_correlation_id(); + SDL_LOG_TRACE("Received event with function id: " + << event.id() << " and correlation id: " << cid); + + const auto request_optional = GetPendingRequest(cid); + const auto app_id_optional = GetPendingApp(cid); + if (!request_optional) { + SDL_LOG_ERROR("Not waiting for message with correlation id: " << cid); + return; + } + + auto current_request = *request_optional; + const auto app_id = *app_id_optional; + RemovePendingRequest(cid); + auto module_uid = GetModuleUid(current_request); + + auto& response = event.smart_object(); + if (RCHelpers::IsResponseSuccessful(response)) { + SDL_LOG_DEBUG("Resumption of subscriptions is successful" + << " module type: " << module_uid.first + << " module id: " << module_uid.second); + + auto app = application_manager_.application(app_id); + if (app) { + auto rc_app_extension = RCHelpers::GetRCExtension(*app); + rc_app_extension->SubscribeToInteriorVehicleData(module_uid); + } + + if (response[am_strings::msg_params].keyExists( + message_params::kModuleData)) { + const auto module_data = + response[am_strings::msg_params][message_params::kModuleData]; + const auto& data_mapping = RCHelpers::GetModuleTypeToDataMapping(); + if (module_data.keyExists(data_mapping(module_uid.first))) { + const auto control_data = module_data[data_mapping(module_uid.first)]; + interior_data_cache_.Add(module_uid, control_data); + } + } + + HandleSuccessfulResponse(event, module_uid); + } else { + SDL_LOG_DEBUG("Resumption of subscriptions is NOT successful" + << " module type: " << module_uid.first + << " module id: " << module_uid.second); + + ProcessNextPausedResumption(module_uid); + } +} + +template <typename RCModulesCollection> +std::string Stringify(RCModulesCollection& collection) { + std::stringstream ss; + for (const auto& module : collection) { + ss << "{type : " << module.first << " id " << module.second << "} "; + } + return ss.str(); +} + +void RCPendingResumptionHandler::HandleResumptionSubscriptionRequest( + application_manager::AppExtension& extension, + application_manager::Application& app) { + UNUSED(extension); + SDL_LOG_AUTO_TRACE(); + sync_primitives::AutoLock lock(pending_resumption_lock_); + + auto rc_extension = RCHelpers::GetRCExtension(app); + auto subscriptions = rc_extension->PendingSubscriptions(); + rc_extension->RemovePendingSubscriptions(); + SDL_LOG_TRACE("app id " << app.app_id() << " " << Stringify(subscriptions)); + + std::vector<ModuleUid> ignored; + std::vector<ModuleUid> already_pending; + std::vector<ModuleUid> need_to_subscribe; + for (const auto& subscription : subscriptions) { + bool is_another_app_subscribed = + IsOtherAppsSubscribed(app.app_id(), subscription); + bool is_pending_response = IsPendingForResponse(subscription); + if (is_another_app_subscribed && !is_pending_response) { + rc_extension->SubscribeToInteriorVehicleData(subscription); + ignored.push_back(subscription); + } else if (is_pending_response) { + already_pending.push_back(subscription); + } else { + need_to_subscribe.push_back(subscription); + } + } + SDL_LOG_TRACE("ignored: " << Stringify(ignored)); + SDL_LOG_TRACE("already_pending: " << Stringify(already_pending)); + SDL_LOG_TRACE("need_to_subscribe: " << Stringify(need_to_subscribe)); + + for (auto subscription : already_pending) { + const auto cid = application_manager_.GetNextHMICorrelationID(); + const auto subscription_request = + CreateSubscriptionRequest(subscription, cid); + const auto fid = GetFunctionId(*subscription_request); + paused_resumptions_[subscription].push( + {app.app_id(), *subscription_request}); + const auto resumption_request = + MakeResumptionRequest(cid, fid, *subscription_request); + resumption_data_processor().SubscribeToResponse(app.app_id(), + resumption_request); + SDL_LOG_DEBUG("Paused request with correlation_id: " + << cid << " module type: " << subscription.first + << " module id: " << subscription.second); + } + + for (auto module : need_to_subscribe) { + const auto cid = application_manager_.GetNextHMICorrelationID(); + const auto subscription_request = CreateSubscriptionRequest(module, cid); + const auto fid = GetFunctionId(*subscription_request); + const auto resumption_request = + MakeResumptionRequest(cid, fid, *subscription_request); + AddPendingRequest(app.app_id(), *subscription_request); + subscribe_on_event(fid, cid); + resumption_data_processor().SubscribeToResponse(app.app_id(), + resumption_request); + SDL_LOG_DEBUG("Sending request with correlation id: " + << cid << " module type: " << module.first + << " module id: " << module.second); + application_manager_.GetRPCService().ManageHMICommand(subscription_request); + } +} + +void RCPendingResumptionHandler::OnResumptionRevert() { + SDL_LOG_AUTO_TRACE(); +} + +void RCPendingResumptionHandler::HandleSuccessfulResponse( + const application_manager::event_engine::Event& event, + const ModuleUid& module_uid) { + SDL_LOG_AUTO_TRACE(); + + auto& response = event.smart_object(); + auto cid = event.smart_object_correlation_id(); + + const auto& it = paused_resumptions_.find(module_uid); + if (it != paused_resumptions_.end()) { + SDL_LOG_DEBUG("Paused resumptions found"); + auto& queue_paused = it->second; + while (!queue_paused.empty()) { + const auto& resumption_request = queue_paused.front(); + cid = resumption_request.correlation_id(); + RaiseEventForResponse(response, cid); + auto app = application_manager_.application(resumption_request.app_id); + if (app) { + auto rc_app_extension = RCHelpers::GetRCExtension(*app); + rc_app_extension->SubscribeToInteriorVehicleData(module_uid); + } + queue_paused.pop(); + } + paused_resumptions_.erase(it); + } +} + +void RCPendingResumptionHandler::ProcessNextPausedResumption( + const ModuleUid& module_uid) { + SDL_LOG_AUTO_TRACE(); + + auto pop_front_paused_resumptions = [this](const ModuleUid& module_uid) { + const auto& it = paused_resumptions_.find(module_uid); + if (it == paused_resumptions_.end()) { + return std::shared_ptr<PendingRequestQueue::value_type>(nullptr); + } + auto& queue_paused = it->second; + if (queue_paused.empty()) { + paused_resumptions_.erase(it); + return std::shared_ptr<PendingRequestQueue::value_type>(nullptr); + } + auto paused_resumption = + std::make_shared<PendingRequestQueue::value_type>(queue_paused.front()); + queue_paused.pop(); + if (queue_paused.empty()) { + paused_resumptions_.erase(it); + } + return paused_resumption; + }; + + auto paused_resumption = pop_front_paused_resumptions(module_uid); + if (!paused_resumption) { + SDL_LOG_DEBUG("No paused resumptions found"); + return; + } + + auto& resumption_request = *paused_resumption; + auto subscription_request = + std::make_shared<smart_objects::SmartObject>(resumption_request.message); + const auto fid = GetFunctionId(*subscription_request); + const auto cid = + resumption_request + .message[app_mngr::strings::params][app_mngr::strings::correlation_id] + .asInt(); + subscribe_on_event(fid, cid); + AddPendingRequest(resumption_request.app_id, *subscription_request); + SDL_LOG_DEBUG("Sending request with correlation id: " + << cid << " module type: " << module_uid.first + << " module id: " << module_uid.second); + application_manager_.GetRPCService().ManageHMICommand(subscription_request); +} + +void RCPendingResumptionHandler::RaiseEventForResponse( + const smart_objects::SmartObject& subscription_response, + const uint32_t correlation_id) const { + smart_objects::SmartObject event_message = subscription_response; + event_message[app_mngr::strings::params][app_mngr::strings::correlation_id] = + correlation_id; + + app_mngr::event_engine::Event event( + hmi_apis::FunctionID::RC_GetInteriorVehicleData); + event.set_smart_object(event_message); + event.raise(application_manager_.event_dispatcher()); +} + +bool RCPendingResumptionHandler::IsPendingForResponse( + const ModuleUid& module_uid) const { + auto is_module_exists = [&module_uid](const PendingRequest& pending) { + return module_uid == GetModuleUid(pending.message); + }; + auto it = std::find_if( + pending_requests_.begin(), pending_requests_.end(), is_module_exists); + return it != pending_requests_.end(); +} + +bool RCPendingResumptionHandler::IsOtherAppsSubscribed( + const uint32_t app_id, const ModuleUid& module_uid) const { + auto get_subscriptions = [](application_manager::ApplicationSharedPtr app) { + std::set<ModuleUid> result; + auto rc_app_extension = RCHelpers::GetRCExtension(*app); + if (rc_app_extension) { + result = rc_app_extension->InteriorVehicleDataSubscriptions(); + } + return result; + }; + + auto app_subscribed = [module_uid, &get_subscriptions]( + application_manager::ApplicationSharedPtr app) { + auto subscriptions = get_subscriptions(app); + auto it = subscriptions.find(module_uid); + return subscriptions.end() != it; + }; + + std::set<uint32_t> subscribed_apps; + for (auto& app : application_manager_.applications().GetData()) { + if (app_subscribed(app)) { + SDL_LOG_DEBUG("APP " << app->app_id() << " subscribed " + << module_uid.first << " " << module_uid.second); + subscribed_apps.insert(app->app_id()); + } + } + + subscribed_apps.erase(app_id); + return !subscribed_apps.empty(); +} + +utils::Optional<smart_objects::SmartObject> +RCPendingResumptionHandler::GetPendingRequest(const uint32_t corr_id) { + auto corr_id_match = [corr_id](const PendingRequest& item) { + return corr_id == item.correlation_id(); + }; + auto it = std::find_if( + pending_requests_.begin(), pending_requests_.end(), corr_id_match); + if (it == pending_requests_.end()) { + return utils::Optional<smart_objects::SmartObject>::EMPTY; + } + return it->message; +} + +utils::Optional<uint32_t> RCPendingResumptionHandler::GetPendingApp( + const uint32_t corr_id) { + auto corr_id_match = [corr_id](const PendingRequest& item) { + return corr_id == item.correlation_id(); + }; + auto it = std::find_if( + pending_requests_.begin(), pending_requests_.end(), corr_id_match); + if (it == pending_requests_.end()) { + return utils::Optional<uint32_t>::EMPTY; + } + return it->app_id; +} + +void RCPendingResumptionHandler::RemovePendingRequest(const uint32_t corr_id) { + auto corr_id_match = [corr_id](const PendingRequest& item) { + return corr_id == item.correlation_id(); + }; + const auto it = std::find_if( + pending_requests_.begin(), pending_requests_.end(), corr_id_match); + if (it == pending_requests_.end()) { + SDL_LOG_WARN("Pending request with corr_id " << corr_id << " not found"); + return; + } + pending_requests_.erase(it); +} + +void RCPendingResumptionHandler::AddPendingRequest( + const uint32_t app_id, const smart_objects::SmartObject request_so) { + pending_requests_.push_back({app_id, request_so}); +} + +smart_objects::SmartObjectSPtr +RCPendingResumptionHandler::CreateSubscriptionRequest( + const ModuleUid& module, const uint32_t correlation_id) { + return RCHelpers::CreateGetInteriorVDRequestToHMI( + module, correlation_id, RCHelpers::InteriorDataAction::SUBSCRIBE); +} + +hmi_apis::FunctionID::eType RCPendingResumptionHandler::GetFunctionId( + const smart_objects::SmartObject& subscription_request) { + const auto function_id = static_cast<hmi_apis::FunctionID::eType>( + subscription_request[app_mngr::strings::params] + [app_mngr::strings::function_id] + .asInt()); + return function_id; +} + +ModuleUid RCPendingResumptionHandler::GetModuleUid( + const smart_objects::SmartObject& subscription_request) { + const smart_objects::SmartObject& msg_params = + subscription_request[app_mngr::strings::msg_params]; + return ModuleUid(msg_params[message_params::kModuleType].asString(), + msg_params[message_params::kModuleId].asString()); +} + +} // namespace rc_rpc_plugin diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_rpc_plugin.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_rpc_plugin.cc index 6e9a751bb6..4345aa044a 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_rpc_plugin.cc +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_rpc_plugin.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2018, Ford Motor Company + Copyright (c) 2020, Ford Motor Company All rights reserved. Redistribution and use in source and binary forms, with or without @@ -39,6 +39,7 @@ #include "rc_rpc_plugin/rc_command_factory.h" #include "rc_rpc_plugin/rc_consent_manager_impl.h" #include "rc_rpc_plugin/rc_helpers.h" +#include "rc_rpc_plugin/rc_pending_resumption_handler.h" #include "rc_rpc_plugin/resource_allocation_manager_impl.h" #include "utils/helpers.h" @@ -76,6 +77,8 @@ bool RCRPCPlugin::Init( command_factory_.reset(new rc_rpc_plugin::RCCommandFactory(params)); rpc_service_ = &rpc_service; app_mngr_ = &app_manager; + pending_resumption_handler_ = std::make_shared<RCPendingResumptionHandler>( + app_manager, *(interior_data_cache_.get())); // Check all saved consents and remove expired rc_consent_manager_->RemoveExpiredConsents(); @@ -124,9 +127,9 @@ void RCRPCPlugin::OnApplicationEvent( } switch (event) { case plugins::kApplicationRegistered: { - auto extension = - std::shared_ptr<RCAppExtension>(new RCAppExtension(kRCPluginID)); - application->AddExtension(extension); + auto extension = std::shared_ptr<RCAppExtension>( + new RCAppExtension(kRCPluginID, *this, *application)); + DCHECK_OR_RETURN_VOID(application->AddExtension(extension)); const auto driver_location = rc_capabilities_manager_ ->GetDriverLocationFromSeatLocationCapability(); @@ -159,6 +162,49 @@ void RCRPCPlugin::OnApplicationEvent( } } +void RCRPCPlugin::ProcessResumptionSubscription( + application_manager::Application& app, RCAppExtension& ext) { + SDL_LOG_AUTO_TRACE(); + + pending_resumption_handler_->HandleResumptionSubscriptionRequest(ext, app); +} + +void RCRPCPlugin::RevertResumption(const std::set<ModuleUid>& subscriptions) { + SDL_LOG_AUTO_TRACE(); + + interior_data_manager_->OnResumptionRevert(subscriptions); + pending_resumption_handler_->OnResumptionRevert(); +} + +bool RCRPCPlugin::IsOtherAppsSubscribed(const rc_rpc_types::ModuleUid& module, + const uint32_t app_id) { + auto get_subscriptions = [](application_manager::ApplicationSharedPtr app) { + std::set<ModuleUid> result; + auto rc_app_extension = RCHelpers::GetRCExtension(*app); + if (rc_app_extension) { + result = rc_app_extension->InteriorVehicleDataSubscriptions(); + } + return result; + }; + + auto another_app_subscribed = + [app_id, module, &get_subscriptions]( + application_manager::ApplicationSharedPtr app) { + if (app_id == app->app_id()) { + return false; + } + auto subscriptions = get_subscriptions(app); + auto it = subscriptions.find(module); + return subscriptions.end() != it; + }; + + auto accessor = app_mngr_->applications(); + auto it = std::find_if(accessor.GetData().begin(), + accessor.GetData().end(), + another_app_subscribed); + return accessor.GetData().end() != it; +} + RCRPCPlugin::Apps RCRPCPlugin::GetRCApplications( application_manager::ApplicationManager& app_mngr) { using application_manager::ApplicationSet; diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/CMakeLists.txt b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/CMakeLists.txt index bd46bdf11f..16e95bf599 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/CMakeLists.txt +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/CMakeLists.txt @@ -45,6 +45,9 @@ ${CMAKE_CURRENT_SOURCE_DIR}/interior_data_cache_test.cc ${CMAKE_CURRENT_SOURCE_DIR}/rc_consent_manager_impl_test.cc ${CMAKE_CURRENT_SOURCE_DIR}/grid_test.cc ${CMAKE_CURRENT_SOURCE_DIR}/rc_helpers_test.cc +${CMAKE_CURRENT_SOURCE_DIR}/rc_app_extension_test.cc +${CMAKE_CURRENT_SOURCE_DIR}/rc_pending_resumption_handler_test.cc +${COMPONENTS_DIR}/application_manager/test/mock_message_helper.cc ) set(RC_COMMANDS_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/commands) diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/button_press_request_test.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/button_press_request_test.cc index 625b2d6312..6c0962a557 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/button_press_request_test.cc +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/button_press_request_test.cc @@ -82,15 +82,15 @@ class ButtonPressRequestTest : rc_capabilities_(std::make_shared<smart_objects::SmartObject>( smart_objects::SmartType_Map)) , mock_app_(std::make_shared<NiceMock<MockApplication> >()) - , rc_app_extention_( - std::make_shared<rc_rpc_plugin::RCAppExtension>(kModuleId)) {} + , rc_app_extension_(std::make_shared<rc_rpc_plugin::RCAppExtension>( + kModuleId, rc_plugin_, *mock_app_)) {} void SetUp() OVERRIDE { smart_objects::SmartObject control_caps((smart_objects::SmartType_Array)); (*rc_capabilities_)[strings::kradioControlCapabilities] = control_caps; ON_CALL(app_mngr_, application(_)).WillByDefault(Return(mock_app_)); ON_CALL(*mock_app_, QueryInterface(RCRPCPlugin::kRCPluginID)) - .WillByDefault(Return(rc_app_extention_)); + .WillByDefault(Return(rc_app_extension_)); ON_CALL(app_mngr_, GetPolicyHandler()) .WillByDefault(ReturnRef(mock_policy_handler_)); ON_CALL(app_mngr_, hmi_capabilities()) @@ -143,7 +143,8 @@ class ButtonPressRequestTest protected: smart_objects::SmartObjectSPtr rc_capabilities_; std::shared_ptr<MockApplication> mock_app_; - std::shared_ptr<rc_rpc_plugin::RCAppExtension> rc_app_extention_; + RCRPCPlugin rc_plugin_; + std::shared_ptr<rc_rpc_plugin::RCAppExtension> rc_app_extension_; test::components::policy_test::MockPolicyHandlerInterface mock_policy_handler_; testing::NiceMock<rc_rpc_plugin_test::MockResourceAllocationManager> diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/get_interior_vehicle_data_request_test.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/get_interior_vehicle_data_request_test.cc index 82b71f1be4..956a53994d 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/get_interior_vehicle_data_request_test.cc +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/get_interior_vehicle_data_request_test.cc @@ -92,8 +92,10 @@ class GetInteriorVehicleDataRequestTest GetInteriorVehicleDataRequestTest() : mock_app_(std::make_shared<NiceMock<MockApplication> >()) , mock_app2_(std::make_shared<NiceMock<MockApplication> >()) - , rc_app_extention_(std::make_shared<RCAppExtension>(kModuleId)) - , rc_app_extention2_(std::make_shared<RCAppExtension>(kModuleId)) + , rc_app_extension_( + std::make_shared<RCAppExtension>(kModuleId, rc_plugin_, *mock_app_)) + , rc_app_extension2_(std::make_shared<RCAppExtension>( + kModuleId, rc_plugin_, *mock_app2_)) , apps_lock_(std::make_shared<sync_primitives::Lock>()) , apps_da_(apps_, apps_lock_) , rc_capabilities_(std::make_shared<smart_objects::SmartObject>( @@ -105,9 +107,9 @@ class GetInteriorVehicleDataRequestTest ON_CALL(*mock_app2_, is_remote_control_supported()) .WillByDefault(Return(true)); ON_CALL(*mock_app_, QueryInterface(_)) - .WillByDefault(Return(rc_app_extention_)); + .WillByDefault(Return(rc_app_extension_)); ON_CALL(*mock_app2_, QueryInterface(_)) - .WillByDefault(Return(rc_app_extention2_)); + .WillByDefault(Return(rc_app_extension2_)); } /** @@ -183,8 +185,9 @@ class GetInteriorVehicleDataRequestTest protected: std::shared_ptr<MockApplication> mock_app_; std::shared_ptr<MockApplication> mock_app2_; - std::shared_ptr<RCAppExtension> rc_app_extention_; - std::shared_ptr<RCAppExtension> rc_app_extention2_; + RCRPCPlugin rc_plugin_; + std::shared_ptr<RCAppExtension> rc_app_extension_; + std::shared_ptr<RCAppExtension> rc_app_extension2_; testing::NiceMock<rc_rpc_plugin_test::MockResourceAllocationManager> mock_allocation_manager_; testing::NiceMock<rc_rpc_plugin_test::MockInteriorDataCache> @@ -264,7 +267,7 @@ TEST_F( Execute_ExpectMessageNotSentToHMI_SuccessSentToMobile_AppSubscribed_DataFromCache) { // Arrange const ModuleUid module(module_type, module_id); - rc_app_extention_->SubscribeToInteriorVehicleData(module); + rc_app_extension_->SubscribeToInteriorVehicleData(module); MessageSharedPtr mobile_message = CreateBasicMessage(); (*mobile_message)[application_manager::strings::msg_params] [message_params::kModuleType] = module_eType; @@ -313,6 +316,51 @@ TEST_F( TEST_F( GetInteriorVehicleDataRequestTest, + Execute_ExpectMessageNotSentToHMI_DoubleSubscription_WarningsSentToMobile) { + // Arrange + const ModuleUid module(module_type, module_id); + rc_app_extension_->SubscribeToInteriorVehicleData(module); + MessageSharedPtr mobile_message = CreateBasicMessage(); + (*mobile_message)[application_manager::strings::msg_params] + [message_params::kModuleType] = module_eType; + (*mobile_message)[application_manager::strings::msg_params] + [message_params::kModuleId] = module_id; + (*mobile_message)[application_manager::strings::msg_params] + [message_params::kSubscribe] = true; + + auto command = + CreateRCCommand<rc_rpc_plugin::commands::GetInteriorVehicleDataRequest>( + mobile_message); + + // Expectations + EXPECT_CALL(mock_interior_data_cache_, Contains(module)) + .WillOnce(Return(true)); + + smart_objects::SmartObject radio_data; + radio_data[message_params::kBand] = enums_value::kAM; + EXPECT_CALL(mock_interior_data_cache_, Retrieve(module)) + .WillOnce(Return(radio_data)); + + EXPECT_CALL(mock_rpc_service_, ManageHMICommand(_, _)).Times(0); + MessageSharedPtr command_result; + EXPECT_CALL( + mock_rpc_service_, + ManageMobileCommand(MobileResultCodeIs(mobile_apis::Result::WARNINGS), _)) + .WillOnce(DoAll(SaveArg<0>(&command_result), Return(true))); + + // Act + ASSERT_TRUE(command->Init()); + command->Run(); + + // Assert + EXPECT_EQ((*command_result)[application_manager::strings::msg_params] + [message_params::kModuleData] + [message_params::kRadioControlData], + radio_data); +} + +TEST_F( + GetInteriorVehicleDataRequestTest, Execute_ExpectCorrectMessageSentToHMI_LastAppSubscribedUnsubscribe_ClearCache) { // Arrange MessageSharedPtr mobile_message = CreateBasicMessage(); @@ -335,7 +383,7 @@ TEST_F( module_id; apps_.insert(mock_app_); - rc_app_extention_->SubscribeToInteriorVehicleData(module); + rc_app_extension_->SubscribeToInteriorVehicleData(module); ON_CALL(app_mngr_, applications()).WillByDefault(Return(apps_da_)); ON_CALL(mock_interior_data_manager_, CheckRequestsToHMIFrequency(_)) .WillByDefault(Return(true)); @@ -379,8 +427,8 @@ TEST_F(GetInteriorVehicleDataRequestTest, apps_.insert(mock_app_); apps_.insert(mock_app2_); - rc_app_extention_->SubscribeToInteriorVehicleData(module); - rc_app_extention2_->SubscribeToInteriorVehicleData(module); + rc_app_extension_->SubscribeToInteriorVehicleData(module); + rc_app_extension2_->SubscribeToInteriorVehicleData(module); smart_objects::SmartObject radio_data; radio_data[message_params::kBand] = enums_value::kAM; @@ -408,7 +456,7 @@ TEST_F(GetInteriorVehicleDataRequestTest, command->Run(); // Assert - EXPECT_FALSE(rc_app_extention_->IsSubscribedToInteriorVehicleDataOfType( + EXPECT_FALSE(rc_app_extension_->IsSubscribedToInteriorVehicleDataOfType( enums_value::kRadio)); EXPECT_EQ((*command_result)[application_manager::strings::msg_params] [message_params::kModuleData] @@ -571,7 +619,7 @@ TEST_F(GetInteriorVehicleDataRequestTest, hmi_msg_params[application_manager::strings::connection_key] = kConnectionKey; apps_.insert(mock_app_); - rc_app_extention_->SubscribeToInteriorVehicleData(module); + rc_app_extension_->SubscribeToInteriorVehicleData(module); ON_CALL(app_mngr_, applications()).WillByDefault(Return(apps_da_)); ON_CALL(mock_interior_data_manager_, CheckRequestsToHMIFrequency(_)) .WillByDefault(Return(true)); @@ -601,13 +649,13 @@ TEST_F(GetInteriorVehicleDataRequestTest, command->on_event(event); // Assert - EXPECT_TRUE(rc_app_extention_->IsSubscribedToInteriorVehicleData(module)); + EXPECT_TRUE(rc_app_extension_->IsSubscribedToInteriorVehicleData(module)); } TEST_F(GetInteriorVehicleDataRequestTest, Execute_ExpectRejectDuToRequestLimitation_NoCahce) { // Arrange - rc_app_extention_->UnsubscribeFromInteriorVehicleDataOfType( + rc_app_extension_->UnsubscribeFromInteriorVehicleDataOfType( enums_value::kRadio); MessageSharedPtr mobile_message = CreateBasicMessage(); (*mobile_message)[application_manager::strings::msg_params] diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/on_interior_vehicle_data_notification_test.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/on_interior_vehicle_data_notification_test.cc index d6771c534d..6c7a7ba67e 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/on_interior_vehicle_data_notification_test.cc +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/on_interior_vehicle_data_notification_test.cc @@ -74,14 +74,15 @@ class OnInteriorVehicleDataNotificationTest public: OnInteriorVehicleDataNotificationTest() : mock_app_(std::make_shared<NiceMock<MockApplication> >()) - , rc_app_extention_(std::make_shared<RCAppExtension>(kModuleId)) + , rc_app_extension_( + std::make_shared<RCAppExtension>(kModuleId, rc_plugin_, *mock_app_)) , apps_lock_(std::make_shared<sync_primitives::Lock>()) , apps_da_(apps_, apps_lock_) { ON_CALL(*mock_app_, app_id()).WillByDefault(Return(kAppId)); ON_CALL(*mock_app_, is_remote_control_supported()) .WillByDefault(Return(true)); ON_CALL(*mock_app_, QueryInterface(_)) - .WillByDefault(Return(rc_app_extention_)); + .WillByDefault(Return(rc_app_extension_)); } MessageSharedPtr CreateBasicMessage() { @@ -120,7 +121,8 @@ class OnInteriorVehicleDataNotificationTest protected: std::shared_ptr<MockApplication> mock_app_; - std::shared_ptr<RCAppExtension> rc_app_extention_; + RCRPCPlugin rc_plugin_; + std::shared_ptr<RCAppExtension> rc_app_extension_; testing::NiceMock<rc_rpc_plugin_test::MockResourceAllocationManager> mock_allocation_manager_; testing::NiceMock<rc_rpc_plugin_test::MockInteriorDataCache> @@ -141,7 +143,7 @@ TEST_F(OnInteriorVehicleDataNotificationTest, MessageSharedPtr mobile_message = CreateBasicMessage(); apps_.insert(mock_app_); const ModuleUid module(module_type, module_id); - rc_app_extention_->SubscribeToInteriorVehicleData(module); + rc_app_extension_->SubscribeToInteriorVehicleData(module); ON_CALL(app_mngr_, applications()).WillByDefault(Return(apps_da_)); // Expectations diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/rc_get_interior_vehicle_data_consent_test.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/rc_get_interior_vehicle_data_consent_test.cc index e5f96215eb..8fbaeda2f2 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/rc_get_interior_vehicle_data_consent_test.cc +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/rc_get_interior_vehicle_data_consent_test.cc @@ -119,7 +119,8 @@ class RCGetInteriorVehicleDataConsentTest rpc_protection_manager_, hmi_so_factory_, mobile_so_factoy_) - , rc_app_extention_(std::make_shared<RCAppExtension>(kPluginID)) + , rc_app_extension_( + std::make_shared<RCAppExtension>(kPluginID, rc_plugin_, *mock_app_)) , mock_rpc_plugin_manager( std::make_shared<NiceMock<MockRPCPluginManager> >()) , rpc_plugin(mock_rpc_plugin) @@ -136,7 +137,7 @@ class RCGetInteriorVehicleDataConsentTest InterfaceState::STATE_AVAILABLE)); ON_CALL(app_mngr_, application(kAppId)).WillByDefault(Return(mock_app_)); ON_CALL(*mock_app_, QueryInterface(RCRPCPlugin::kRCPluginID)) - .WillByDefault(Return(rc_app_extention_)); + .WillByDefault(Return(rc_app_extension_)); testing::NiceMock<rc_rpc_plugin_test::MockInteriorDataCache> mock_interior_data_cache_; ON_CALL(app_mngr_, GetPolicyHandler()) @@ -217,7 +218,8 @@ class RCGetInteriorVehicleDataConsentTest std::shared_ptr<application_manager::MockRPCProtectionManager> rpc_protection_manager_; am::rpc_service::RPCServiceImpl rpc_service_; - std::shared_ptr<RCAppExtension> rc_app_extention_; + RCRPCPlugin rc_plugin_; + std::shared_ptr<RCAppExtension> rc_app_extension_; std::shared_ptr<am::plugin_manager::MockRPCPluginManager> mock_rpc_plugin_manager; utils::Optional<RPCPlugin> rpc_plugin; diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/set_interior_vehicle_data_request_test.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/set_interior_vehicle_data_request_test.cc index 1e4da625b2..9b06ddb137 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/set_interior_vehicle_data_request_test.cc +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/commands/set_interior_vehicle_data_request_test.cc @@ -73,7 +73,8 @@ class SetInteriorVehicleDataRequestTest public: SetInteriorVehicleDataRequestTest() : mock_app_(std::make_shared<NiceMock<MockApplication> >()) - , rc_app_extention_(std::make_shared<RCAppExtension>(kModuleId)) + , rc_app_extension_( + std::make_shared<RCAppExtension>(kModuleId, rc_plugin_, *mock_app_)) , rc_capabilities_(std::make_shared<smart_objects::SmartObject>( smart_objects::SmartType::SmartType_Array)) {} @@ -89,7 +90,7 @@ class SetInteriorVehicleDataRequestTest InterfaceState::STATE_AVAILABLE)); ON_CALL(app_mngr_, application(kAppId)).WillByDefault(Return(mock_app_)); ON_CALL(*mock_app_, QueryInterface(RCRPCPlugin::kRCPluginID)) - .WillByDefault(Return(rc_app_extention_)); + .WillByDefault(Return(rc_app_extension_)); ON_CALL(*mock_app_, policy_app_id()).WillByDefault(Return(kPolicyAppId)); ON_CALL(mock_allocation_manager_, IsResourceFree(_, _)) @@ -148,7 +149,8 @@ class SetInteriorVehicleDataRequestTest testing::NiceMock<rc_rpc_plugin_test::MockInteriorDataManager> mock_interior_data_manager_; std::shared_ptr<MockApplication> mock_app_; - std::shared_ptr<RCAppExtension> rc_app_extention_; + RCRPCPlugin rc_plugin_; + std::shared_ptr<RCAppExtension> rc_app_extension_; testing::NiceMock<rc_rpc_plugin_test::MockRCCapabilitiesManager> mock_rc_capabilities_manager_; smart_objects::SmartObjectSPtr rc_capabilities_; diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/include/rc_rpc_plugin/mock/mock_interior_data_manager.h b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/include/rc_rpc_plugin/mock/mock_interior_data_manager.h index 231ac2ae36..3e64bb541f 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/include/rc_rpc_plugin/mock/mock_interior_data_manager.h +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/include/rc_rpc_plugin/mock/mock_interior_data_manager.h @@ -49,6 +49,8 @@ class MockInteriorDataManager : public rc_rpc_plugin::InteriorDataManager { MOCK_METHOD1(StoreRequestToHMITime, void(const rc_rpc_plugin::ModuleUid&)); MOCK_METHOD1(CheckRequestsToHMIFrequency, bool(const rc_rpc_plugin::ModuleUid&)); + MOCK_METHOD1(OnResumptionRevert, + void(const std::set<rc_rpc_plugin::ModuleUid>& subscriptions)); }; } // namespace rc_rpc_plugin_test diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/include/rc_rpc_plugin/mock/mock_rc_helpers.h b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/include/rc_rpc_plugin/mock/mock_rc_helpers.h index c73472d2a8..751291c8e2 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/include/rc_rpc_plugin/mock/mock_rc_helpers.h +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/include/rc_rpc_plugin/mock/mock_rc_helpers.h @@ -54,9 +54,11 @@ class MockRCHelpers { MOCK_METHOD1( GetRCExtension, rc_rpc_plugin::RCAppExtensionPtr(application_manager::Application&)); - MOCK_METHOD2(CreateUnsubscribeRequestToHMI, - smart_objects::SmartObjectSPtr(const rc_rpc_plugin::ModuleUid&, - const uint32_t)); + MOCK_METHOD3(CreateGetInteriorVDRequestToHMI, + smart_objects::SmartObjectSPtr( + const rc_rpc_plugin::ModuleUid&, + const uint32_t, + const RCHelpers::InteriorDataAction action)); MOCK_METHOD2(AppsSubscribedToModule, std::vector<application_manager::ApplicationSharedPtr>( application_manager::ApplicationManager&, @@ -89,6 +91,9 @@ class MockRCHelpers { smart_objects::SmartObject(const smart_objects::SmartObject& data1, const smart_objects::SmartObject& data2)); + MOCK_METHOD1(IsResponseSuccessful, + bool(const smart_objects::SmartObject& response)); + static MockRCHelpers* rc_helpers_mock(); }; diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/mock_rc_helpers.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/mock_rc_helpers.cc index 3e60591c6b..2f5fed9971 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/mock_rc_helpers.cc +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/mock_rc_helpers.cc @@ -60,10 +60,12 @@ rc_rpc_plugin::RCAppExtensionPtr rc_rpc_plugin::RCHelpers::GetRCExtension( } smart_objects::SmartObjectSPtr -rc_rpc_plugin::RCHelpers::CreateUnsubscribeRequestToHMI( - const ModuleUid& module, const uint32_t correlation_id) { - return MockRCHelpers::rc_helpers_mock()->CreateUnsubscribeRequestToHMI( - module, correlation_id); +rc_rpc_plugin::RCHelpers::CreateGetInteriorVDRequestToHMI( + const ModuleUid& module, + const uint32_t correlation_id, + const RCHelpers::InteriorDataAction action) { + return MockRCHelpers::rc_helpers_mock()->CreateGetInteriorVDRequestToHMI( + module, correlation_id, action); } std::vector<application_manager::ApplicationSharedPtr> @@ -130,6 +132,11 @@ void RCHelpers::RemoveRedundantGPSDataFromIVDataMsg( msg_params); } +bool RCHelpers::IsResponseSuccessful( + const smart_objects::SmartObject& response) { + return MockRCHelpers::rc_helpers_mock()->IsResponseSuccessful(response); +} + MockRCHelpers* MockRCHelpers::rc_helpers_mock() { static ::testing::NiceMock<MockRCHelpers> mock_rc_helpers; return &mock_rc_helpers; diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/rc_app_extension_test.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/rc_app_extension_test.cc new file mode 100644 index 0000000000..60c3fb9135 --- /dev/null +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/rc_app_extension_test.cc @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2020, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "rc_rpc_plugin/rc_app_extension.h" + +#include <memory> +#include <string> + +#include "application_manager/mock_application.h" +#include "gtest/gtest.h" +#include "rc_rpc_plugin/rc_module_constants.h" +#include "rc_rpc_plugin/rc_rpc_plugin.h" + +namespace { +const uint32_t kRCAppExtensionId = 1ull; +} // namespace + +namespace test { +namespace components { +namespace rc_rpc_plugin_test { +namespace rc_app_extension_test { + +using test::components::application_manager_test::MockApplication; +using ::testing::NiceMock; + +class RcAppExtensionTest : public testing::Test { + public: + RcAppExtensionTest() + : mock_app_(new NiceMock<MockApplication>()) + , rc_app_extension_(std::make_shared<rc_rpc_plugin::RCAppExtension>( + kRCAppExtensionId, rc_plugin_, *mock_app_)) {} + + protected: + std::unique_ptr<MockApplication> mock_app_; + rc_rpc_plugin::RCRPCPlugin rc_plugin_; + rc_rpc_plugin::RCAppExtensionPtr rc_app_extension_; +}; + +TEST_F(RcAppExtensionTest, SubscribeToInteriorVehicleData_AppDoesntUpdateHash) { + const std::string module_type = "CLIMATE"; + const std::string module_id = "9cb963f3-c5e8-41cb-b001-19421cc16552"; + rc_rpc_plugin::ModuleUid module{module_type, module_id}; + + EXPECT_CALL(*mock_app_, UpdateHash()).Times(0); + + rc_app_extension_->SubscribeToInteriorVehicleData(module); + EXPECT_TRUE(rc_app_extension_->IsSubscribedToInteriorVehicleData(module)); + + auto subscription = rc_app_extension_->InteriorVehicleDataSubscriptions(); + EXPECT_EQ(1ull, subscription.size()); +} + +TEST_F(RcAppExtensionTest, + UnsubscribeFromInteriorVehicleData_AppDoesntUpdateHash) { + const std::string module_type = "CLIMATE"; + const std::string module_id = "9cb963f3-c5e8-41cb-b001-19421cc16552"; + rc_rpc_plugin::ModuleUid module{module_type, module_id}; + + EXPECT_CALL(*mock_app_, UpdateHash()).Times(0); + rc_app_extension_->SubscribeToInteriorVehicleData(module); + + EXPECT_CALL(*mock_app_, UpdateHash()).Times(0); + rc_app_extension_->UnsubscribeFromInteriorVehicleData(module); + + EXPECT_FALSE(rc_app_extension_->IsSubscribedToInteriorVehicleData(module)); + + auto subscription = rc_app_extension_->InteriorVehicleDataSubscriptions(); + EXPECT_TRUE(subscription.empty()); +} + +TEST_F(RcAppExtensionTest, + UnsubscribeFromInteriorVehicleDataOfType_AppDoesntUpdateHash) { + const std::string module1_type = "CLIMATE"; + const std::string module1_id = "9cb963f3-c5e8-41cb-b001-19421cc16552"; + rc_rpc_plugin::ModuleUid module1{module1_type, module1_id}; + + const std::string module2_type = "RADIO"; + const std::string module2_id = "357a3918-9f35-4d86-a8b6-60cd4308d76f"; + rc_rpc_plugin::ModuleUid module2{module2_type, module2_id}; + + EXPECT_CALL(*mock_app_, UpdateHash()).Times(0); + rc_app_extension_->SubscribeToInteriorVehicleData(module1); + rc_app_extension_->SubscribeToInteriorVehicleData(module2); + + EXPECT_CALL(*mock_app_, UpdateHash()); + rc_app_extension_->UnsubscribeFromInteriorVehicleDataOfType(module1_type); + + EXPECT_FALSE( + rc_app_extension_->IsSubscribedToInteriorVehicleDataOfType(module1_type)); + EXPECT_TRUE( + rc_app_extension_->IsSubscribedToInteriorVehicleDataOfType(module2_type)); + + auto subscription = rc_app_extension_->InteriorVehicleDataSubscriptions(); + EXPECT_EQ(1ull, subscription.size()); +} + +TEST_F(RcAppExtensionTest, + UnsubscribeFromInteriorVehicleDataOfType_UNSUCCESS_AppDoesntUpdateHash) { + const std::string module1_type = "CLIMATE"; + const std::string module_id = "9cb963f3-c5e8-41cb-b001-19421cc16552"; + rc_rpc_plugin::ModuleUid module{module1_type, module_id}; + + const std::string module2_type = "RADIO"; + + EXPECT_CALL(*mock_app_, UpdateHash()).Times(0); + rc_app_extension_->SubscribeToInteriorVehicleData(module); + + EXPECT_CALL(*mock_app_, UpdateHash()).Times(0); + rc_app_extension_->UnsubscribeFromInteriorVehicleDataOfType(module2_type); + + EXPECT_TRUE(rc_app_extension_->IsSubscribedToInteriorVehicleData(module)); + + auto subscription = rc_app_extension_->InteriorVehicleDataSubscriptions(); + EXPECT_EQ(1ull, subscription.size()); +} + +TEST_F(RcAppExtensionTest, SaveResumptionData_SUCCESS) { + using namespace rc_rpc_plugin; + + const std::string module1_type = "CLIMATE"; + const std::string module1_id = "9cb963f3-c5e8-41cb-b001-19421cc16552"; + ModuleUid module1{module1_type, module1_id}; + + const std::string module2_type = "RADIO"; + const std::string module2_id = "357a3918-9f35-4d86-a8b6-60cd4308d76f"; + ModuleUid module2{module2_type, module2_id}; + + EXPECT_CALL(*mock_app_, UpdateHash()).Times(0); + rc_app_extension_->SubscribeToInteriorVehicleData(module1); + rc_app_extension_->SubscribeToInteriorVehicleData(module2); + + const auto subscriptions = + rc_app_extension_->InteriorVehicleDataSubscriptions(); + + auto subscription_so = + smart_objects::SmartObject(smart_objects::SmartType_Map); + + rc_app_extension_->SaveResumptionData(subscription_so); + + const auto module_data = + subscription_so[message_params::kModuleData].asArray(); + + EXPECT_NE(nullptr, module_data); + + EXPECT_EQ(module_data->size(), subscriptions.size()); + + auto module_info_so = + smart_objects::SmartObject(smart_objects::SmartType_Map); + module_info_so[message_params::kModuleType] = module1.first; + module_info_so[message_params::kModuleId] = module1.second; + + auto found_module = + std::find(module_data->begin(), module_data->end(), module_info_so); + + EXPECT_NE(found_module, module_data->end()); + + module_info_so[message_params::kModuleType] = module2.first; + module_info_so[message_params::kModuleId] = module2.second; + + found_module = + std::find(module_data->begin(), module_data->end(), module_info_so); + + EXPECT_NE(found_module, module_data->end()); +} + +} // namespace rc_app_extension_test +} // namespace rc_rpc_plugin_test +} // namespace components +} // namespace test diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/rc_pending_resumption_handler_test.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/rc_pending_resumption_handler_test.cc new file mode 100644 index 0000000000..fe8ade1e05 --- /dev/null +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/rc_pending_resumption_handler_test.cc @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2020, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ + +#include "rc_rpc_plugin/rc_pending_resumption_handler.h" +#include "application_manager/mock_application.h" +#include "application_manager/mock_event_dispatcher.h" +#include "application_manager/mock_message_helper.h" +#include "application_manager/mock_resume_ctrl.h" +#include "application_manager/mock_resumption_data_processor.h" +#include "application_manager/mock_rpc_service.h" +#include "application_manager/smart_object_keys.h" +#include "gtest/gtest.h" +#include "mock_application_manager.h" +#include "rc_rpc_plugin/interior_data_cache_impl.h" +#include "rc_rpc_plugin/rc_module_constants.h" +#include "rc_rpc_plugin/rc_rpc_plugin.h" + +namespace rc_rpc_plugin_test { + +using ::testing::_; +using ::testing::DoAll; +using ::testing::InSequence; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::ReturnRef; +using ::testing::SaveArg; + +using rc_rpc_plugin::ModuleUid; + +using application_manager::MockMessageHelper; +using test::components::resumption_test::MockResumeCtrl; +using test::components::resumption_test::MockResumptionDataProcessor; +typedef NiceMock< ::test::components::event_engine_test::MockEventDispatcher> + MockEventDispatcher; + +typedef NiceMock< + ::test::components::application_manager_test::MockApplicationManager> + MockApplicationManager; +typedef NiceMock< ::test::components::application_manager_test::MockApplication> + MockApplication; +typedef NiceMock< ::test::components::application_manager_test::MockRPCService> + MockRPCService; +typedef std::shared_ptr<MockApplication> MockAppPtr; + +namespace { +const uint32_t kAppId_1 = 1u; +const uint32_t kAppId_2 = 2u; +const uint32_t kCorrelationId = 10u; +const std::string kModuleType_1 = "CLIMATE"; +const std::string kModuleId_1 = "9cb963f3-c5e8-41cb-b001-19421cc16552"; +const std::string kModuleType_2 = "RADIO"; +const std::string kModuleId_2 = "357a3918-9f35-4d86-a8b6-60cd4308d76f"; +const uint32_t kRCPluginID = rc_rpc_plugin::RCRPCPlugin::kRCPluginID; +const auto kSourceHMI = application_manager::commands::Command::SOURCE_HMI; +} // namespace + +/** + * @brief EventCheck check that event contains apropriate data, + * check that is matched correlation id, + * check that function id is correct + */ +MATCHER_P(EventCheck, expected_corr_id, "") { + namespace strings = application_manager::strings; + const auto& response_message = arg.smart_object(); + const auto cid = + response_message[strings::params][strings::correlation_id].asInt(); + const bool cid_ok = (cid == expected_corr_id); + const auto fid = + response_message[strings::params][strings::function_id].asInt(); + const bool fid_ok = (fid == hmi_apis::FunctionID::RC_GetInteriorVehicleData); + return fid_ok && cid_ok; +} + +/** + * @brief MessageCheck check that message contains apropriate data, + * check that is matched correlation id + */ +MATCHER_P(MessageCheck, correlation_id, "") { + const auto& request = *arg; + const auto cid = + request[app_mngr::strings::params][app_mngr::strings::correlation_id] + .asInt(); + return cid == correlation_id; +} + +class RCPendingResumptionHandlerTest : public ::testing::Test { + public: + RCPendingResumptionHandlerTest() + : applications_lock_(std::make_shared<sync_primitives::Lock>()) + , applications_(application_set_, applications_lock_) + , mock_message_helper_(*MockMessageHelper::message_helper_mock()) {} + + void SetUp() OVERRIDE { + ON_CALL(app_manager_mock_, event_dispatcher()) + .WillByDefault(ReturnRef(event_dispatcher_mock_)); + ON_CALL(app_manager_mock_, GetRPCService()) + .WillByDefault(ReturnRef(mock_rpc_service_)); + ON_CALL(app_manager_mock_, GetNextHMICorrelationID()) + .WillByDefault(Return(kCorrelationId)); + ON_CALL(app_manager_mock_, applications()) + .WillByDefault(Return(applications_)); + ON_CALL(app_manager_mock_, resume_controller()) + .WillByDefault(ReturnRef(resume_ctrl_mock_)); + ON_CALL(resume_ctrl_mock_, resumption_data_processor()) + .WillByDefault(ReturnRef(resumption_data_processor_mock_)); + resumption_handler_.reset(new rc_rpc_plugin::RCPendingResumptionHandler( + app_manager_mock_, cache_)); + } + + smart_objects::SmartObjectSPtr CreateHMIResponseMessage( + const application_manager::MessageType& message_type, + const hmi_apis::Common_Result::eType& response_code, + uint32_t correlation_id) { + namespace strings = application_manager::strings; + namespace hmi_response = application_manager::hmi_response; + smart_objects::SmartObject params(smart_objects::SmartType_Map); + params[strings::function_id] = + hmi_apis::FunctionID::RC_GetInteriorVehicleData; + params[strings::message_type] = message_type; + params[strings::correlation_id] = correlation_id; + const auto hmi_protocol_type = 1; + params[strings::protocol_type] = hmi_protocol_type; + params[hmi_response::code] = response_code; + + smart_objects::SmartObjectSPtr response = + std::make_shared<smart_objects::SmartObject>( + smart_objects::SmartType_Map); + auto& message = *response; + message[strings::params] = params; + message[strings::msg_params] = + smart_objects::SmartObject(smart_objects::SmartType_Map); + message[strings::msg_params][rc_rpc_plugin::message_params::kIsSubscribed] = + true; + return response; + } + + MockAppPtr CreateApp(uint32_t app_id) { + auto mock_app = std::make_shared<MockApplication>(); + ON_CALL(app_manager_mock_, application(app_id)) + .WillByDefault(Return(mock_app)); + ON_CALL(*mock_app, app_id()).WillByDefault(Return(app_id)); + return mock_app; + } + + rc_rpc_plugin::RCAppExtensionPtr CreateExtension(MockApplication& app) { + auto rc_app_ext = std::make_shared<rc_rpc_plugin::RCAppExtension>( + kRCPluginID, rc_plugin_, app); + ON_CALL(app, QueryInterface(kRCPluginID)).WillByDefault(Return(rc_app_ext)); + return rc_app_ext; + } + + protected: + application_manager::ApplicationSet application_set_; + std::shared_ptr<sync_primitives::Lock> applications_lock_; + DataAccessor<application_manager::ApplicationSet> applications_; + MockMessageHelper& mock_message_helper_; + MockResumeCtrl resume_ctrl_mock_; + MockResumptionDataProcessor resumption_data_processor_mock_; + MockApplicationManager app_manager_mock_; + MockEventDispatcher event_dispatcher_mock_; + MockRPCService mock_rpc_service_; + rc_rpc_plugin::RCRPCPlugin rc_plugin_; + rc_rpc_plugin::InteriorDataCacheImpl cache_; + std::unique_ptr<rc_rpc_plugin::RCPendingResumptionHandler> + resumption_handler_; +}; + +TEST_F(RCPendingResumptionHandlerTest, HandleResumptionNoSubscriptionNoAction) { + auto mock_app = CreateApp(kAppId_1); + auto rc_app_ext = CreateExtension(*mock_app); + + EXPECT_CALL(resumption_data_processor_mock_, SubscribeToResponse(_, _)) + .Times(0); + EXPECT_CALL(mock_rpc_service_, ManageHMICommand(_, _)).Times(0); + + resumption_handler_->HandleResumptionSubscriptionRequest(*rc_app_ext, + *mock_app); +} + +TEST_F(RCPendingResumptionHandlerTest, + HandleResumptionOneSubscriptionOnAction) { + auto mock_app = CreateApp(kAppId_1); + auto rc_app_ext = CreateExtension(*mock_app); + + ModuleUid module_uid{kModuleType_1, kModuleId_1}; + rc_app_ext->AddPendingSubscription(module_uid); + + EXPECT_CALL(app_manager_mock_, GetNextHMICorrelationID()) + .WillOnce(Return(kAppId_1)); + EXPECT_CALL(resumption_data_processor_mock_, + SubscribeToResponse(kAppId_1, _)); + EXPECT_CALL(mock_rpc_service_, + ManageHMICommand(MessageCheck(kAppId_1), kSourceHMI)); + + resumption_handler_->HandleResumptionSubscriptionRequest(*rc_app_ext, + *mock_app); +} + +TEST_F(RCPendingResumptionHandlerTest, + HandleResumptionMultipleSubscriptionsMultipleActions) { + auto mock_app = CreateApp(kAppId_1); + auto rc_app_ext = CreateExtension(*mock_app); + + ModuleUid module_uid_1 = {kModuleType_1, kModuleId_1}; + rc_app_ext->AddPendingSubscription(module_uid_1); + + ModuleUid module_uid_2 = {kModuleType_2, kModuleId_2}; + rc_app_ext->AddPendingSubscription(module_uid_2); + + { + InSequence in_sequence; + EXPECT_CALL(app_manager_mock_, GetNextHMICorrelationID()) + .WillOnce(Return(kAppId_1)); + EXPECT_CALL(resumption_data_processor_mock_, + SubscribeToResponse(kAppId_1, _)); + EXPECT_CALL(mock_rpc_service_, + ManageHMICommand(MessageCheck(kAppId_1), kSourceHMI)); + EXPECT_CALL(app_manager_mock_, GetNextHMICorrelationID()) + .WillOnce(Return(kAppId_2)); + EXPECT_CALL(resumption_data_processor_mock_, + SubscribeToResponse(kAppId_1, _)); + EXPECT_CALL(mock_rpc_service_, + ManageHMICommand(MessageCheck(kAppId_2), kSourceHMI)); + } + + resumption_handler_->HandleResumptionSubscriptionRequest(*rc_app_ext, + *mock_app); +} + +TEST_F(RCPendingResumptionHandlerTest, + HandleResumptionWithPendingSubscription) { + auto mock_app = CreateApp(kAppId_1); + auto rc_app_ext = CreateExtension(*mock_app); + + ModuleUid module_uid = {kModuleType_1, kModuleId_1}; + rc_app_ext->AddPendingSubscription(module_uid); + + EXPECT_CALL(app_manager_mock_, GetNextHMICorrelationID()) + .WillOnce(Return(kAppId_1)); + EXPECT_CALL(resumption_data_processor_mock_, + SubscribeToResponse(kAppId_1, _)); + EXPECT_CALL(mock_rpc_service_, + ManageHMICommand(MessageCheck(kAppId_1), kSourceHMI)); + + resumption_handler_->HandleResumptionSubscriptionRequest(*rc_app_ext, + *mock_app); + + auto rc_app_ext_2 = CreateExtension(*mock_app); + rc_app_ext_2->AddPendingSubscription(module_uid); + + EXPECT_CALL(app_manager_mock_, GetNextHMICorrelationID()); + EXPECT_CALL(resumption_data_processor_mock_, + SubscribeToResponse(kAppId_1, _)); + EXPECT_CALL(mock_rpc_service_, ManageHMICommand(_, _)).Times(0); + + resumption_handler_->HandleResumptionSubscriptionRequest(*rc_app_ext_2, + *mock_app); +} + +TEST_F(RCPendingResumptionHandlerTest, + HandleResumptionWithPendingSubscriptionAndNotPendingOne) { + auto mock_app = CreateApp(kAppId_1); + auto rc_app_ext = CreateExtension(*mock_app); + + ModuleUid module_uid_1 = {kModuleType_1, kModuleId_1}; + rc_app_ext->AddPendingSubscription(module_uid_1); + + EXPECT_CALL(app_manager_mock_, GetNextHMICorrelationID()) + .WillOnce(Return(kAppId_1)); + EXPECT_CALL(resumption_data_processor_mock_, + SubscribeToResponse(kAppId_1, _)); + EXPECT_CALL(mock_rpc_service_, + ManageHMICommand(MessageCheck(kAppId_1), kSourceHMI)); + + resumption_handler_->HandleResumptionSubscriptionRequest(*rc_app_ext, + *mock_app); + + auto rc_app_ext_2 = CreateExtension(*mock_app); + ModuleUid module_uid_2 = {kModuleType_2, kModuleId_2}; + rc_app_ext_2->AddPendingSubscription(module_uid_1); + rc_app_ext_2->AddPendingSubscription(module_uid_2); + + { + InSequence in_sequence; + EXPECT_CALL(app_manager_mock_, GetNextHMICorrelationID()) + .WillOnce(Return(kAppId_1)); + EXPECT_CALL(resumption_data_processor_mock_, + SubscribeToResponse(kAppId_1, _)); + EXPECT_CALL(app_manager_mock_, GetNextHMICorrelationID()) + .WillOnce(Return(kAppId_2)); + EXPECT_CALL(resumption_data_processor_mock_, + SubscribeToResponse(kAppId_1, _)); + EXPECT_CALL(mock_rpc_service_, + ManageHMICommand(MessageCheck(kAppId_2), kSourceHMI)); + } + + resumption_handler_->HandleResumptionSubscriptionRequest(*rc_app_ext_2, + *mock_app); +} + +TEST_F(RCPendingResumptionHandlerTest, + Resumption2ApplicationsWithCommonDataSuccess) { + auto mock_app_1 = CreateApp(kAppId_1); + auto rc_app_ext = CreateExtension(*mock_app_1); + + ModuleUid module_uid = {kModuleType_1, kModuleId_1}; + rc_app_ext->AddPendingSubscription(module_uid); + + EXPECT_CALL(app_manager_mock_, GetNextHMICorrelationID()) + .WillOnce(Return(kAppId_1)); + EXPECT_CALL(resumption_data_processor_mock_, + SubscribeToResponse(kAppId_1, _)); + EXPECT_CALL(mock_rpc_service_, + ManageHMICommand(MessageCheck(kAppId_1), kSourceHMI)); + + resumption_handler_->HandleResumptionSubscriptionRequest(*rc_app_ext, + *mock_app_1); + + auto mock_app_2 = CreateApp(kAppId_2); + auto rc_app_ext_2 = CreateExtension(*mock_app_2); + + rc_app_ext_2->AddPendingSubscription(module_uid); + + EXPECT_CALL(app_manager_mock_, GetNextHMICorrelationID()) + .WillOnce(Return(kAppId_2)); + EXPECT_CALL(resumption_data_processor_mock_, + SubscribeToResponse(kAppId_2, _)); + EXPECT_CALL(mock_rpc_service_, ManageHMICommand(_, _)).Times(0); + + resumption_handler_->HandleResumptionSubscriptionRequest(*rc_app_ext_2, + *mock_app_2); + + auto response = + CreateHMIResponseMessage(application_manager::MessageType::kResponse, + hmi_apis::Common_Result::SUCCESS, + kAppId_1); + + application_manager::event_engine::Event event( + hmi_apis::FunctionID::RC_GetInteriorVehicleData); + event.set_smart_object(*response); + + EXPECT_CALL(event_dispatcher_mock_, raise_event(EventCheck(kAppId_2))); + + resumption_handler_->on_event(event); +} + +TEST_F(RCPendingResumptionHandlerTest, + Resumption2ApplicationsWithCommonDataFailedRetry) { + auto mock_app_1 = CreateApp(kAppId_1); + auto rc_app_ext = CreateExtension(*mock_app_1); + + ModuleUid module_uid = {kModuleType_1, kModuleId_1}; + rc_app_ext->AddPendingSubscription(module_uid); + + EXPECT_CALL(app_manager_mock_, GetNextHMICorrelationID()) + .WillOnce(Return(kAppId_1)); + EXPECT_CALL(resumption_data_processor_mock_, + SubscribeToResponse(kAppId_1, _)); + EXPECT_CALL(mock_rpc_service_, ManageHMICommand(_, _)); + + resumption_handler_->HandleResumptionSubscriptionRequest(*rc_app_ext, + *mock_app_1); + + auto mock_app_2 = CreateApp(kAppId_2); + auto rc_app_ext_2 = CreateExtension(*mock_app_2); + + rc_app_ext_2->AddPendingSubscription(module_uid); + + EXPECT_CALL(app_manager_mock_, GetNextHMICorrelationID()) + .WillOnce(Return(kAppId_2)); + EXPECT_CALL(resumption_data_processor_mock_, + SubscribeToResponse(kAppId_2, _)); + EXPECT_CALL(mock_rpc_service_, ManageHMICommand(_, _)).Times(0); + + resumption_handler_->HandleResumptionSubscriptionRequest(*rc_app_ext_2, + *mock_app_2); + + auto response = + CreateHMIResponseMessage(application_manager::MessageType::kErrorResponse, + hmi_apis::Common_Result::SUCCESS, + kAppId_1); + + application_manager::event_engine::Event event( + hmi_apis::FunctionID::RC_GetInteriorVehicleData); + event.set_smart_object(*response); + + EXPECT_CALL(mock_rpc_service_, + ManageHMICommand(MessageCheck(kAppId_2), kSourceHMI)); + + resumption_handler_->on_event(event); +} + +} // namespace rc_rpc_plugin_test diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/resource_allocation_manager/CMakeLists.txt b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/resource_allocation_manager/CMakeLists.txt index 4b10d34643..a22543ba09 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/resource_allocation_manager/CMakeLists.txt +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/resource_allocation_manager/CMakeLists.txt @@ -45,6 +45,7 @@ ${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/src/interior_dat ${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/src/resource_allocation_manager_impl.cc ${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_rpc_plugin.cc ${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_app_extension.cc +${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_pending_resumption_handler.cc ${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_consent_manager_impl.cc ${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_capabilities_manager_impl.cc ${COMPONENTS_DIR}/application_manager/rpc_plugins/rc_rpc_plugin/src/rc_command_factory.cc diff --git a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/resource_allocation_manager/resource_allocation_manager_impl_test.cc b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/resource_allocation_manager/resource_allocation_manager_impl_test.cc index 70ed832cb1..501fbc323d 100644 --- a/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/resource_allocation_manager/resource_allocation_manager_impl_test.cc +++ b/src/components/application_manager/rpc_plugins/rc_rpc_plugin/test/resource_allocation_manager/resource_allocation_manager_impl_test.cc @@ -113,7 +113,8 @@ class RAManagerTest : public ::testing::Test { ON_CALL(mock_app_mngr_, GetPolicyHandler()) .WillByDefault(ReturnRef(mock_policy_handler_)); auto plugin_id = rc_rpc_plugin::RCRPCPlugin::kRCPluginID; - app_ext_ptr_ = std::make_shared<rc_rpc_plugin::RCAppExtension>(plugin_id); + app_ext_ptr_ = std::make_shared<rc_rpc_plugin::RCAppExtension>( + plugin_id, rc_plugin_, *mock_app_1_); ON_CALL(*mock_app_1_, app_id()).WillByDefault(Return(kAppId1)); PrepareResources(); @@ -144,7 +145,9 @@ class RAManagerTest : public ::testing::Test { void SetUp() OVERRIDE { rc_app_extension_ = std::make_shared<rc_rpc_plugin::RCAppExtension>( static_cast<application_manager::AppExtensionUID>( - rc_rpc_plugin::RCRPCPlugin::kRCPluginID)); + rc_rpc_plugin::RCRPCPlugin::kRCPluginID), + rc_plugin_, + *mock_app_1_); ON_CALL(mock_rc_capabilities_manager_, GetDriverLocationFromSeatLocationCapability()) .WillByDefault(Return(kDriverLocation)); @@ -178,6 +181,7 @@ class RAManagerTest : public ::testing::Test { mock_rc_capabilities_manager_; std::vector<ModuleUid> resources_; Grid module_service_area_; + RCRPCPlugin rc_plugin_; RCAppExtensionPtr rc_app_extension_; MockRCHelpers* mock_rc_helpers_; }; @@ -403,9 +407,11 @@ TEST_F(RAManagerTest, AppUnregistered_ReleaseResource) { mock_app_mngr_, mock_rpc_service_, mock_rc_capabilities_manager_); ra_manager.SetAccessMode(hmi_apis::Common_RCAccessMode::eType::AUTO_DENY); - RCAppExtensionPtr rc_extention_ptr = - std::make_shared<RCAppExtension>(application_manager::AppExtensionUID( - rc_rpc_plugin::RCRPCPlugin::kRCPluginID)); + RCAppExtensionPtr rc_extension_ptr = std::make_shared<RCAppExtension>( + application_manager::AppExtensionUID( + rc_rpc_plugin::RCRPCPlugin::kRCPluginID), + rc_plugin_, + *mock_app_1_); EXPECT_EQ(rc_rpc_plugin::AcquireResult::ALLOWED, ra_manager.AcquireResource(kModuleType1, kModuleId, kAppId1)); @@ -477,12 +483,14 @@ TEST_F(RAManagerTest, AppsDisallowed_ReleaseAllResources) { EXPECT_CALL(mock_app_mngr_, applications()).WillRepeatedly(Return(apps_da)); - RCAppExtensionPtr rc_extention_ptr = - std::make_shared<RCAppExtension>(application_manager::AppExtensionUID( - rc_rpc_plugin::RCRPCPlugin::kRCPluginID)); + RCAppExtensionPtr rc_extension_ptr = std::make_shared<RCAppExtension>( + application_manager::AppExtensionUID( + rc_rpc_plugin::RCRPCPlugin::kRCPluginID), + rc_plugin_, + *mock_app_1_); EXPECT_CALL(*mock_app_1_, QueryInterface(RCRPCPlugin::kRCPluginID)) - .WillRepeatedly(Return(rc_extention_ptr)); + .WillRepeatedly(Return(rc_extension_ptr)); // Act ra_manager.OnPolicyEvent( @@ -508,13 +516,15 @@ TEST_F(RAManagerTest, AppGotRevokedModulesWithPTU_ReleaseRevokedResource) { EXPECT_CALL(mock_app_mngr_, application(kAppId1)) .WillRepeatedly(Return(mock_app_1_)); - RCAppExtensionPtr rc_extention_ptr = + RCAppExtensionPtr rc_extension_ptr = std::make_shared<rc_rpc_plugin::RCAppExtension>( application_manager::AppExtensionUID( - rc_rpc_plugin::RCRPCPlugin::kRCPluginID)); + rc_rpc_plugin::RCRPCPlugin::kRCPluginID), + rc_plugin_, + *mock_app_1_); EXPECT_CALL(*mock_app_1_, QueryInterface(RCRPCPlugin::kRCPluginID)) - .WillRepeatedly(Return(rc_extention_ptr)); + .WillRepeatedly(Return(rc_extension_ptr)); ON_CALL(*mock_app_1_, is_remote_control_supported()) .WillByDefault(Return(true)); diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/waypoints_app_extension.h b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/waypoints_app_extension.h index 37ac24bcbb..9243baedee 100644 --- a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/waypoints_app_extension.h +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/include/sdl_rpc_plugin/waypoints_app_extension.h @@ -53,7 +53,7 @@ class WayPointsAppExtension : public app_mngr::AppExtension { void ProcessResumption(const smart_objects::SmartObject& saved_app) OVERRIDE; void RevertResumption( - const smart_objects::SmartObject& subscriptions) OVERRIDE; + const smart_objects::SmartObject& resumption_data) OVERRIDE; /** * @brief WayPointsAppExtensionUID unique identifier of waypoints diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/waypoints_app_extension.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/waypoints_app_extension.cc index 61b5d1624a..ed8283e1f9 100644 --- a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/waypoints_app_extension.cc +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/waypoints_app_extension.cc @@ -67,9 +67,9 @@ void WayPointsAppExtension::ProcessResumption( } void WayPointsAppExtension::RevertResumption( - const smart_objects::SmartObject& subscriptions) { + const smart_objects::SmartObject& resumption_data) { SDL_LOG_AUTO_TRACE(); - UNUSED(subscriptions); + UNUSED(resumption_data); plugin_.RevertResumption(app_); } diff --git a/src/components/application_manager/rpc_plugins/vehicle_info_plugin/include/vehicle_info_plugin/vehicle_info_app_extension.h b/src/components/application_manager/rpc_plugins/vehicle_info_plugin/include/vehicle_info_plugin/vehicle_info_app_extension.h index 2f61ef026a..7e3eabb6a1 100644 --- a/src/components/application_manager/rpc_plugins/vehicle_info_plugin/include/vehicle_info_plugin/vehicle_info_app_extension.h +++ b/src/components/application_manager/rpc_plugins/vehicle_info_plugin/include/vehicle_info_plugin/vehicle_info_app_extension.h @@ -146,7 +146,7 @@ class VehicleInfoAppExtension : public app_mngr::AppExtension { void ProcessResumption(const smart_objects::SmartObject& saved_app) OVERRIDE; void RevertResumption( - const smart_objects::SmartObject& subscriptions) OVERRIDE; + const smart_objects::SmartObject& resumption_data) OVERRIDE; /** * @brief VehicleInfoAppExtensionUID unique identifier of VehicleInfo diff --git a/src/components/application_manager/rpc_plugins/vehicle_info_plugin/src/vehicle_info_app_extension.cc b/src/components/application_manager/rpc_plugins/vehicle_info_plugin/src/vehicle_info_app_extension.cc index 5cd790a75b..dd6d797e39 100644 --- a/src/components/application_manager/rpc_plugins/vehicle_info_plugin/src/vehicle_info_app_extension.cc +++ b/src/components/application_manager/rpc_plugins/vehicle_info_plugin/src/vehicle_info_app_extension.cc @@ -170,11 +170,31 @@ void VehicleInfoAppExtension::ProcessResumption( } void VehicleInfoAppExtension::RevertResumption( - const smart_objects::SmartObject& subscriptions) { + const smart_objects::SmartObject& resumption_data) { SDL_LOG_AUTO_TRACE(); unsubscribeFromVehicleInfo(); - plugin_.RevertResumption(app_, subscriptions.enumerate()); + + if (!resumption_data.keyExists( + application_manager::hmi_interface::vehicle_info)) { + SDL_LOG_DEBUG("No resumption vahicle data subscription to revert"); + return; + } + const auto& resumption_vd_data = + resumption_data[application_manager::hmi_interface::vehicle_info]; + + std::set<std::string> ivi_subscriptions_to_revert; + const auto ivi_subscriptions_keys = resumption_vd_data.enumerate(); + for (const auto& key : ivi_subscriptions_keys) { + // Only boolean keys in subscriptions list are true vehicle data + // subscriptions + if (smart_objects::SmartType::SmartType_Boolean == + resumption_vd_data.getElement(key).getType()) { + ivi_subscriptions_to_revert.insert(key); + } + } + + plugin_.RevertResumption(app_, ivi_subscriptions_to_revert); } VehicleInfoAppExtension& VehicleInfoAppExtension::ExtractVIExtension( diff --git a/src/components/application_manager/src/application_impl.cc b/src/components/application_manager/src/application_impl.cc index 3708c45cfa..60070524a0 100644 --- a/src/components/application_manager/src/application_impl.cc +++ b/src/components/application_manager/src/application_impl.cc @@ -1254,12 +1254,13 @@ AppExtensionPtr ApplicationImpl::QueryInterface(AppExtensionUID uid) { return (*it); } } - return AppExtensionPtr(); } bool ApplicationImpl::AddExtension(AppExtensionPtr extension) { if (!QueryInterface(extension->uid())) { + SDL_LOG_TRACE("Add extenstion to add id" << app_id() << " with uid " + << extension->uid()); extensions_.push_back(extension); return true; } diff --git a/src/components/application_manager/src/resumption/resumption_data_processor_impl.cc b/src/components/application_manager/src/resumption/resumption_data_processor_impl.cc index d1635eb557..c067167041 100644 --- a/src/components/application_manager/src/resumption/resumption_data_processor_impl.cc +++ b/src/components/application_manager/src/resumption/resumption_data_processor_impl.cc @@ -33,6 +33,7 @@ #include "application_manager/event_engine/event_observer.h" #include "application_manager/message_helper.h" #include "application_manager/resumption/resumption_data_processor_impl.h" +#include "application_manager/rpc_plugins/rc_rpc_plugin/include/rc_rpc_plugin/rc_module_constants.h" #include "application_manager/smart_object_keys.h" namespace resumption { @@ -45,8 +46,17 @@ using app_mngr::MessageHelper; namespace strings = app_mngr::strings; namespace event_engine = app_mngr::event_engine; namespace commands = app_mngr::commands; +namespace message_params = rc_rpc_plugin::message_params; SDL_CREATE_LOG_VARIABLE("Resumption") +std::map<hmi_apis::Common_ModuleType::eType, std::string> + module_types_str_mapping{ + {hmi_apis::Common_ModuleType::eType::CLIMATE, {"CLIMATE"}}, + {hmi_apis::Common_ModuleType::eType::RADIO, {"RADIO"}}, + {hmi_apis::Common_ModuleType::eType::SEAT, {"SEAT"}}, + {hmi_apis::Common_ModuleType::eType::AUDIO, {"AUDIO"}}, + {hmi_apis::Common_ModuleType::eType::LIGHT, {"LIGHT"}}, + {hmi_apis::Common_ModuleType::eType::HMI_SETTINGS, {"HMI_SETTINGS"}}}; bool ResumptionRequestID::operator<(const ResumptionRequestID& other) const { return correlation_id < other.correlation_id || @@ -251,6 +261,11 @@ void ResumptionDataProcessorImpl::ProcessResumptionStatus( found_request.request_id.function_id) { CheckCreateWindowResponse(found_request.message, response); } + + if (hmi_apis::FunctionID::RC_GetInteriorVehicleData == + found_request.request_id.function_id) { + CheckModuleDataSubscription(found_request.message, response, status); + } } bool ResumptionDataProcessorImpl::IsResumptionFinished( @@ -297,7 +312,8 @@ bool ResumptionDataProcessorImpl::IsResumptionSuccessful( const ApplicationResumptionStatus& status = it->second; return status.error_requests.empty() && - status.unsuccessful_vehicle_data_subscriptions_.empty(); + status.unsuccessful_vehicle_data_subscriptions_.empty() && + status.unsuccessful_module_subscriptions_.empty(); } void ResumptionDataProcessorImpl::EraseAppResumptionData( @@ -988,15 +1004,44 @@ void ResumptionDataProcessorImpl::DeletePluginsSubscriptions( } const ApplicationResumptionStatus& status = it->second; - smart_objects::SmartObject extension_subscriptions; + smart_objects::SmartObject extension_vd_subscriptions; for (auto ivi : status.successful_vehicle_data_subscriptions_) { SDL_LOG_DEBUG("ivi " << ivi << " should be deleted"); - extension_subscriptions[ivi] = true; + extension_vd_subscriptions[ivi] = true; + } + + smart_objects::SmartObject extension_modules_subscriptions( + smart_objects::SmartType_Map); + + if (!status.successful_module_subscriptions_.empty()) { + extension_modules_subscriptions[message_params::kModuleData] = + new smart_objects::SmartObject(smart_objects::SmartType_Array); + + auto& module_data_so = + extension_modules_subscriptions[message_params::kModuleData]; + + uint32_t index = 0; + for (const auto& module : status.successful_module_subscriptions_) { + module_data_so[index] = + new smart_objects::SmartObject(smart_objects::SmartType_Map); + module_data_so[index][message_params::kModuleType] = module.first; + module_data_so[index][message_params::kModuleId] = module.second; + index++; + } } + + smart_objects::SmartObject resumption_data_to_revert( + smart_objects::SmartType_Map); + resumption_data_to_revert[application_manager::hmi_interface::vehicle_info] = + extension_vd_subscriptions; + resumption_data_to_revert[application_manager::hmi_interface::rc] = + extension_modules_subscriptions; + resumption_status_lock_.Release(); - for (auto& extension : application->Extensions()) { - extension->RevertResumption(extension_subscriptions); + auto extensions = application->Extensions(); + for (auto& extension : extensions) { + extension->RevertResumption(resumption_data_to_revert); } } @@ -1039,6 +1084,70 @@ void ResumptionDataProcessorImpl::CheckVehicleDataResponse( } } +void ResumptionDataProcessorImpl::CheckModuleDataSubscription( + const ns_smart_device_link::ns_smart_objects::SmartObject& request, + const ns_smart_device_link::ns_smart_objects::SmartObject& response, + ApplicationResumptionStatus& status) { + SDL_LOG_AUTO_TRACE(); + + const auto& msg_params_so = request[strings::msg_params]; + const auto requested_module_type = + msg_params_so[message_params::kModuleType].asString(); + const auto requested_module_id = + msg_params_so[message_params::kModuleId].asString(); + const ModuleUid requested_module{requested_module_type, requested_module_id}; + + if (!IsResponseSuccessful(response)) { + SDL_LOG_TRACE("Module data subscription request NOT successful"); + status.unsuccessful_module_subscriptions_.push_back(requested_module); + return; + } + + const auto& response_module_data_so = + response[strings::msg_params][message_params::kModuleData]; + + if (0 == response_module_data_so.length()) { + SDL_LOG_TRACE("Module data subscription request not successful"); + status.unsuccessful_module_subscriptions_.push_back(requested_module); + return; + } + + const auto responsed_module_type_int = + static_cast<hmi_apis::Common_ModuleType::eType>( + response_module_data_so[message_params::kModuleType].asUInt()); + + const auto responsed_module_type_str = + module_types_str_mapping[responsed_module_type_int]; + + const auto response_module_id = + response_module_data_so[message_params::kModuleId].asString(); + const ModuleUid responsed_module{responsed_module_type_str, + response_module_id}; + + bool is_subscribe_success = false; + if (response[application_manager::strings::msg_params].keyExists( + rc_rpc_plugin::message_params::kIsSubscribed)) { + is_subscribe_success = + response[application_manager::strings::msg_params] + [rc_rpc_plugin::message_params::kIsSubscribed] + .asBool(); + } + + const bool is_the_same_module = requested_module == responsed_module; + + if (is_the_same_module && is_subscribe_success) { + SDL_LOG_TRACE("Module [" << requested_module.first << ":" + << requested_module.second + << "] was successfuly subscribed"); + status.successful_module_subscriptions_.push_back(requested_module); + } else { + SDL_LOG_TRACE("Module [" << requested_module.first << ":" + << requested_module.second + << "] was NOT successfuly subscribed"); + status.unsuccessful_module_subscriptions_.push_back(requested_module); + } +} + void ResumptionDataProcessorImpl::CheckCreateWindowResponse( const smart_objects::SmartObject& request, const smart_objects::SmartObject& response) const { |