diff options
Diffstat (limited to 'src/components/application_manager/src/application_manager_impl.cc')
-rw-r--r-- | src/components/application_manager/src/application_manager_impl.cc | 2338 |
1 files changed, 2338 insertions, 0 deletions
diff --git a/src/components/application_manager/src/application_manager_impl.cc b/src/components/application_manager/src/application_manager_impl.cc new file mode 100644 index 0000000000..d6beb3c497 --- /dev/null +++ b/src/components/application_manager/src/application_manager_impl.cc @@ -0,0 +1,2338 @@ +/* + * Copyright (c) 2014, 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 <stdlib.h> // for rand() + +#include <climits> +#include <string> +#include <fstream> + +#include "application_manager/application_manager_impl.h" +#include "application_manager/mobile_command_factory.h" +#include "application_manager/commands/command_impl.h" +#include "application_manager/commands/command_notification_impl.h" +#include "application_manager/message_helper.h" +#include "application_manager/mobile_message_handler.h" +#include "application_manager/policies/policy_handler.h" +#include "hmi_message_handler/hmi_message_handler.h" +#include "connection_handler/connection_handler_impl.h" +#include "formatters/formatter_json_rpc.h" +#include "formatters/CFormatterJsonSDLRPCv2.hpp" +#include "formatters/CFormatterJsonSDLRPCv1.hpp" +#include "config_profile/profile.h" +#include "utils/threads/thread.h" +#include "utils/file_system.h" +#include "application_manager/application_impl.h" +#include "usage_statistics/counter.h" +#include <time.h> + +namespace application_manager { + +CREATE_LOGGERPTR_GLOBAL(logger_, "ApplicationManager") + +uint32_t ApplicationManagerImpl::corelation_id_ = 0; +const uint32_t ApplicationManagerImpl::max_corelation_id_ = UINT_MAX; + +namespace formatters = NsSmartDeviceLink::NsJSONHandler::Formatters; +namespace jhs = NsSmartDeviceLink::NsJSONHandler::strings; + +ApplicationManagerImpl::ApplicationManagerImpl() + : applications_list_lock_(true), + audio_pass_thru_active_(false), + is_distracting_driver_(false), + is_vr_session_strated_(false), + hmi_cooperating_(false), + is_all_apps_allowed_(true), + media_manager_(NULL), + hmi_handler_(NULL), + connection_handler_(NULL), + protocol_handler_(NULL), + request_ctrl_(), + hmi_so_factory_(NULL), + mobile_so_factory_(NULL), + messages_from_mobile_("AM FromMobile", this), + messages_to_mobile_("AM ToMobile", this), + messages_from_hmi_("AM FromHMI", this), + messages_to_hmi_("AM ToHMI", this), + hmi_capabilities_(this), + unregister_reason_(mobile_api::AppInterfaceUnregisteredReason::IGNITION_OFF), + resume_ctrl_(this), +#ifdef TIME_TESTER + metric_observer_(NULL), +#endif // TIME_TESTER + application_list_update_timer_(new ApplicationListUpdateTimer(this)), + tts_global_properties_timer_("TTSGLPRTimer", + this, + &ApplicationManagerImpl::OnTimerSendTTSGlobalProperties, + true) { + std::srand(std::time(0)); +} + +ApplicationManagerImpl::~ApplicationManagerImpl() { + LOG4CXX_INFO(logger_, "Destructing ApplicationManager."); + + SendOnSDLClose(); + media_manager_ = NULL; + hmi_handler_ = NULL; + connection_handler_ = NULL; + if (hmi_so_factory_) { + delete hmi_so_factory_; + } + hmi_so_factory_ = NULL; + if (mobile_so_factory_) { + delete mobile_so_factory_; + } + mobile_so_factory_ = NULL; + protocol_handler_ = NULL; + media_manager_ = NULL; + LOG4CXX_INFO(logger_, "Destroying Policy Handler"); + policy::PolicyHandler::destroy(); +} + +bool ApplicationManagerImpl::Stop() { + LOG4CXX_INFO(logger_, "Stop ApplicationManager."); + application_list_update_timer_->stop(); + try { + UnregisterAllApplications(); + } catch (...) { + LOG4CXX_ERROR(logger_, + "An error occurred during unregistering applications."); + } + + + // for PASA customer policy backup should happen OnExitAllApp(SUSPEND) + LOG4CXX_INFO(logger_, "Unloading policy library."); + policy::PolicyHandler::instance()->UnloadPolicyLibrary(); + + return true; +} + +ApplicationSharedPtr ApplicationManagerImpl::application(uint32_t app_id) const { + sync_primitives::AutoLock lock(applications_list_lock_); + + std::set<ApplicationSharedPtr>::const_iterator it = + application_list_.begin(); + for (; it != application_list_.end(); ++it) { + if ((*it)->app_id() == app_id) { + return (*it); + } + } + return ApplicationSharedPtr(); +} + +ApplicationSharedPtr ApplicationManagerImpl::application_by_hmi_app( + uint32_t hmi_app_id) const { + sync_primitives::AutoLock lock(applications_list_lock_); + + std::set<ApplicationSharedPtr>::const_iterator it = + application_list_.begin(); + for (; it != application_list_.end(); ++it) { + if ((*it)->hmi_app_id() == hmi_app_id) { + return (*it); + } + } + return ApplicationSharedPtr(); +} + +ApplicationSharedPtr ApplicationManagerImpl::application_by_policy_id( + const std::string& policy_app_id) const { + sync_primitives::AutoLock lock(applications_list_lock_); + + std::vector<ApplicationSharedPtr> result; + for (std::set<ApplicationSharedPtr>::iterator it = application_list_.begin(); + application_list_.end() != it; + ++it) { + if (policy_app_id.compare((*it)->mobile_app_id()->asString()) == 0) { + return *it; + } + } + return ApplicationSharedPtr(); +} + +ApplicationSharedPtr ApplicationManagerImpl::active_application() const { + // TODO(DK) : check driver distraction + for (std::set<ApplicationSharedPtr>::iterator it = application_list_.begin(); + application_list_.end() != it; + ++it) { + if ((*it)->IsFullscreen()) { + return *it; + } + } + return ApplicationSharedPtr(); +} + +std::vector<ApplicationSharedPtr> ApplicationManagerImpl::applications_by_button( + uint32_t button) { + std::vector<ApplicationSharedPtr> result; + for (std::set<ApplicationSharedPtr>::iterator it = application_list_.begin(); + application_list_.end() != it; ++it) { + if ((*it)->IsSubscribedToButton( + static_cast<mobile_apis::ButtonName::eType>(button))) { + result.push_back(*it); + } + } + return result; +} + +std::vector<utils::SharedPtr<Application>> ApplicationManagerImpl::IviInfoUpdated( +VehicleDataType vehicle_info, int value) { + // Notify Policy Manager if available about info it's interested in, + // i.e. odometer etc + switch (vehicle_info) { + case ODOMETER: + policy::PolicyHandler::instance()->KmsChanged(value); + break; + default: + break; + } + + std::vector<utils::SharedPtr<application_manager::Application>> result; + for (std::set<utils::SharedPtr<application_manager::Application>>::iterator it = application_list_.begin(); + application_list_.end() != it; ++it) { + if ((*it)->IsSubscribedToIVI(static_cast<uint32_t>(vehicle_info))) { + result.push_back(*it); + } + } + return result; +} + +std::vector<ApplicationSharedPtr> ApplicationManagerImpl::applications_with_navi() { + std::vector<ApplicationSharedPtr> result; + for (std::set<ApplicationSharedPtr>::iterator it = application_list_.begin(); + application_list_.end() != it; + ++it) { + if ((*it)->allowed_support_navigation()) { + result.push_back(*it); + } + } + return result; +} + +ApplicationSharedPtr ApplicationManagerImpl::RegisterApplication( + const utils::SharedPtr<smart_objects::SmartObject>& + request_for_registration) { + + LOG4CXX_DEBUG(logger_, "Restarting application list update timer"); + uint32_t timeout = profile::Profile::instance()->application_list_update_timeout(); + application_list_update_timer_->start(timeout); + + smart_objects::SmartObject& message = *request_for_registration; + uint32_t connection_key = + message[strings::params][strings::connection_key].asInt(); + + if (false == is_all_apps_allowed_) { + LOG4CXX_INFO(logger_, + "RegisterApplication: access to app's disabled by user"); + utils::SharedPtr<smart_objects::SmartObject> response( + MessageHelper::CreateNegativeResponse( + connection_key, mobile_apis::FunctionID::RegisterAppInterfaceID, + message[strings::params][strings::correlation_id].asUInt(), + mobile_apis::Result::DISALLOWED)); + ManageMobileCommand(response); + return ApplicationSharedPtr(); + } + + // app_id is SDL "internal" ID + // original app_id can be gotten via ApplicationImpl::mobile_app_id() + uint32_t app_id = 0; + std::list<int32_t> sessions_list; + uint32_t device_id = 0; + + if (connection_handler_) { + connection_handler::ConnectionHandlerImpl* con_handler_impl = + static_cast<connection_handler::ConnectionHandlerImpl*>( + + connection_handler_); + if (con_handler_impl->GetDataOnSessionKey(connection_key, &app_id, + &sessions_list, &device_id) + == -1) { + LOG4CXX_ERROR(logger_, + "Failed to create application: no connection info."); + utils::SharedPtr<smart_objects::SmartObject> response( + MessageHelper::CreateNegativeResponse( + connection_key, mobile_apis::FunctionID::RegisterAppInterfaceID, + message[strings::params][strings::correlation_id].asUInt(), + mobile_apis::Result::GENERIC_ERROR)); + ManageMobileCommand(response); + return ApplicationSharedPtr(); + } + } + + smart_objects::SmartObject& params = message[strings::msg_params]; + + const std::string& mobile_app_id = params[strings::app_id].asString(); + const std::string& app_name = + message[strings::msg_params][strings::app_name].asString(); + + ApplicationSharedPtr application( + new ApplicationImpl(app_id, + mobile_app_id, app_name, + policy::PolicyHandler::instance()->GetStatisticManager())); + if (!application) { + usage_statistics::AppCounter count_of_rejections_sync_out_of_memory( + policy::PolicyHandler::instance()->GetStatisticManager(), mobile_app_id, + usage_statistics::REJECTIONS_SYNC_OUT_OF_MEMORY); + ++count_of_rejections_sync_out_of_memory; + + utils::SharedPtr<smart_objects::SmartObject> response( + MessageHelper::CreateNegativeResponse( + connection_key, mobile_apis::FunctionID::RegisterAppInterfaceID, + message[strings::params][strings::correlation_id].asUInt(), + mobile_apis::Result::OUT_OF_MEMORY)); + ManageMobileCommand(response); + return ApplicationSharedPtr(); + } + application->set_device(device_id); + application->set_grammar_id(GenerateGrammarID()); + mobile_api::Language::eType launguage_desired = + static_cast<mobile_api::Language::eType>(params[strings::language_desired] + .asInt()); + application->set_language(launguage_desired); + application->usage_report().RecordAppRegistrationVuiLanguage( + launguage_desired); + + mobile_api::Language::eType hmi_display_language_desired = + static_cast<mobile_api::Language::eType>(params[strings::hmi_display_language_desired] + .asInt()); + application->set_ui_language(hmi_display_language_desired); + application->usage_report().RecordAppRegistrationGuiLanguage( + hmi_display_language_desired); + + Version version; + int32_t min_version = + message[strings::msg_params][strings::sync_msg_version] + [strings::minor_version].asInt(); + + /*if (min_version < APIVersion::kAPIV2) { + LOG4CXX_ERROR(logger_, "UNSUPPORTED_VERSION"); + utils::SharedPtr<smart_objects::SmartObject> response( + MessageHelper::CreateNegativeResponse( + connection_key, mobile_apis::FunctionID::RegisterAppInterfaceID, + message[strings::params][strings::correlation_id], + mobile_apis::Result::UNSUPPORTED_VERSION)); + ManageMobileCommand(response); + delete application; + return NULL; + }*/ + version.min_supported_api_version = static_cast<APIVersion>(min_version); + + int32_t max_version = + message[strings::msg_params][strings::sync_msg_version] + [strings::major_version].asInt(); + + /*if (max_version > APIVersion::kAPIV2) { + LOG4CXX_ERROR(logger_, "UNSUPPORTED_VERSION"); + utils::SharedPtr<smart_objects::SmartObject> response( + MessageHelper::CreateNegativeResponse( + connection_key, mobile_apis::FunctionID::RegisterAppInterfaceID, + message[strings::params][strings::correlation_id], + mobile_apis::Result::UNSUPPORTED_VERSION)); + ManageMobileCommand(response); + delete application; + return NULL; + }*/ + version.max_supported_api_version = static_cast<APIVersion>(max_version); + application->set_version(version); + + ProtocolVersion protocol_version = static_cast<ProtocolVersion>( + message[strings::params][strings::protocol_version].asInt()); + application->set_protocol_version(protocol_version); + + if (connection_handler_) { + if (ProtocolVersion::kUnknownProtocol != protocol_version) { + connection_handler_->BindProtocolVersionWithSession( + connection_key, static_cast<uint8_t>(protocol_version)); + } + if (ProtocolVersion::kV3 == protocol_version) { + connection_handler_->StartSessionHeartBeat(connection_key); + } + } + + sync_primitives::AutoLock lock(applications_list_lock_); + + application_list_.insert(application); + + return application; +} + +bool ApplicationManagerImpl::RemoveAppDataFromHMI(ApplicationSharedPtr app) { + return true; +} + +bool ApplicationManagerImpl::LoadAppDataToHMI(ApplicationSharedPtr app) { + return true; +} + +bool ApplicationManagerImpl::ActivateApplication(ApplicationSharedPtr app) { + if (!app) { + LOG4CXX_ERROR(logger_, "Null-pointer application received."); + NOTREACHED(); + return false; + } + + bool is_new_app_media = app->is_media_application(); + + if (app->IsFullscreen()) { + LOG4CXX_WARN(logger_, "Application is already active."); + return false; + } + if (mobile_api::HMILevel::eType::HMI_LIMITED != + app->hmi_level()) { + if (app->has_been_activated()) { + MessageHelper::SendAppDataToHMI(app); + } + } + app->MakeFullscreen(); + for (std::set<ApplicationSharedPtr>::iterator it = application_list_.begin(); + application_list_.end() != it; + ++it) { + ApplicationSharedPtr curr_app = *it; + if (app->app_id() == curr_app->app_id()) { + continue; + } else { + if (is_new_app_media) { + if (curr_app->IsAudible()) { + curr_app->MakeNotAudible(); + MessageHelper::SendHMIStatusNotification(*curr_app); + } + } + if (curr_app->IsFullscreen()) { + if (true == curr_app->is_media_application()) { + PutApplicationInLimited(app); + } else { + app->set_hmi_level(mobile_api::HMILevel::HMI_BACKGROUND); + } + MessageHelper::SendHMIStatusNotification(*curr_app); + } + } + } + return true; +} + +mobile_apis::HMILevel::eType ApplicationManagerImpl::PutApplicationInLimited( + ApplicationSharedPtr app) { + DCHECK(app.get()) + + mobile_api::HMILevel::eType result = mobile_api::HMILevel::HMI_LIMITED; + + for (std::set<ApplicationSharedPtr>::iterator it = application_list_.begin(); + application_list_.end() != it; + ++it) { + ApplicationSharedPtr curr_app = *it; + if (app->app_id() == curr_app->app_id()) { + continue; + } + + if (curr_app->hmi_level() == mobile_api::HMILevel::HMI_LIMITED) { + result = mobile_api::HMILevel::HMI_BACKGROUND; + break; + } + if (curr_app->hmi_level() == mobile_api::HMILevel::HMI_FULL) { + if (curr_app->is_media_application()) { + result = mobile_api::HMILevel::HMI_BACKGROUND; + break; + } else { + result = mobile_api::HMILevel::HMI_LIMITED; + } + } + + } + app->set_hmi_level(result); + return result; +} + +mobile_api::HMILevel::eType ApplicationManagerImpl::PutApplicationInFull( + ApplicationSharedPtr app) { + DCHECK(app.get()) + + bool is_new_app_media = app->is_media_application(); + mobile_api::HMILevel::eType result = mobile_api::HMILevel::HMI_FULL; + + std::set<ApplicationSharedPtr>::iterator it = application_list_.begin(); + for (; application_list_.end() != it; ++it) { + ApplicationSharedPtr curr_app = *it; + if (app->app_id() == curr_app->app_id()) { + continue; + } + + if (is_new_app_media) { + if (curr_app->hmi_level() == mobile_api::HMILevel::HMI_FULL) { + if (curr_app->is_media_application()) { + result = mobile_api::HMILevel::HMI_BACKGROUND; + break; + } else { + result = mobile_api::HMILevel::HMI_LIMITED; + } + } + if (curr_app->hmi_level() == mobile_api::HMILevel::HMI_LIMITED) { + result = mobile_api::HMILevel::HMI_BACKGROUND; + break; + } + } else { + if (curr_app->hmi_level() == mobile_api::HMILevel::HMI_FULL) { + result = mobile_api::HMILevel::HMI_BACKGROUND; + break; + } + if (curr_app->hmi_level() == mobile_api::HMILevel::HMI_LIMITED) { + result = mobile_api::HMILevel::HMI_FULL; + } + } + } + + if (result == mobile_api::HMILevel::HMI_FULL) { + app->set_hmi_level(result); + MessageHelper::SendActivateAppToHMI(app->app_id()); + } + return result; +} + +void ApplicationManagerImpl::ConnectToDevice(uint32_t id) { + // TODO(VS): Call function from ConnectionHandler + if (!connection_handler_) { + LOG4CXX_WARN(logger_, "Connection handler is not set."); + return; + } + + connection_handler_->ConnectToDevice(id); +} + +void ApplicationManagerImpl::OnHMIStartedCooperation() { + hmi_cooperating_ = true; + LOG4CXX_INFO(logger_, "ApplicationManagerImpl::OnHMIStartedCooperation()"); + + utils::SharedPtr<smart_objects::SmartObject> is_vr_ready( + MessageHelper::CreateModuleInfoSO( + static_cast<uint32_t>(hmi_apis::FunctionID::VR_IsReady))); + ManageHMICommand(is_vr_ready); + + utils::SharedPtr<smart_objects::SmartObject> is_tts_ready( + MessageHelper::CreateModuleInfoSO(hmi_apis::FunctionID::TTS_IsReady)); + ManageHMICommand(is_tts_ready); + + utils::SharedPtr<smart_objects::SmartObject> is_ui_ready( + MessageHelper::CreateModuleInfoSO(hmi_apis::FunctionID::UI_IsReady)); + ManageHMICommand(is_ui_ready); + + utils::SharedPtr<smart_objects::SmartObject> is_navi_ready( + MessageHelper::CreateModuleInfoSO( + hmi_apis::FunctionID::Navigation_IsReady)); + ManageHMICommand(is_navi_ready); + + utils::SharedPtr<smart_objects::SmartObject> is_ivi_ready( + MessageHelper::CreateModuleInfoSO( + hmi_apis::FunctionID::VehicleInfo_IsReady)); + ManageHMICommand(is_ivi_ready); + + utils::SharedPtr<smart_objects::SmartObject> button_capabilities( + MessageHelper::CreateModuleInfoSO( + hmi_apis::FunctionID::Buttons_GetCapabilities)); + ManageHMICommand(button_capabilities); + + utils::SharedPtr<smart_objects::SmartObject> mixing_audio_supported_request( + MessageHelper::CreateModuleInfoSO( + hmi_apis::FunctionID::BasicCommunication_MixingAudioSupported)); + ManageHMICommand(mixing_audio_supported_request); +} + +uint32_t ApplicationManagerImpl::GetNextHMICorrelationID() { + if (corelation_id_ < max_corelation_id_) { + corelation_id_++; + } else { + corelation_id_ = 0; + } + + return corelation_id_; +} + +bool ApplicationManagerImpl::begin_audio_pass_thru() { + sync_primitives::AutoLock lock(audio_pass_thru_lock_); + if (audio_pass_thru_active_) { + return false; + } else { + audio_pass_thru_active_ = true; + return true; + } +} + +bool ApplicationManagerImpl::end_audio_pass_thru() { + sync_primitives::AutoLock lock(audio_pass_thru_lock_); + if (audio_pass_thru_active_) { + audio_pass_thru_active_ = false; + return true; + } else { + return false; + } +} + +void ApplicationManagerImpl::set_driver_distraction(bool is_distracting) { + is_distracting_driver_ = is_distracting; +} + +void ApplicationManagerImpl::set_vr_session_started(const bool& state) { + is_vr_session_strated_ = state; +} + +void ApplicationManagerImpl::set_all_apps_allowed(const bool& allowed) { + is_all_apps_allowed_ = allowed; +} + +void ApplicationManagerImpl::StartAudioPassThruThread(int32_t session_key, + int32_t correlation_id, int32_t max_duration, int32_t sampling_rate, + int32_t bits_per_sample, int32_t audio_type) { + LOG4CXX_INFO(logger_, "START MICROPHONE RECORDER"); + if (NULL != media_manager_) { + media_manager_->StartMicrophoneRecording( + session_key, + profile::Profile::instance()->recording_file_name(), + max_duration); + } +} + +void ApplicationManagerImpl::SendAudioPassThroughNotification( + uint32_t session_key, + std::vector<uint8_t> binaryData) { + LOG4CXX_TRACE_ENTER(logger_); + + if (!audio_pass_thru_active_) { + LOG4CXX_ERROR(logger_, "Trying to send PassThroughNotification" + " when PassThrough is not active"); + return; + } + smart_objects::SmartObject* on_audio_pass = NULL; + on_audio_pass = new smart_objects::SmartObject(); + + if (NULL == on_audio_pass) { + LOG4CXX_ERROR_EXT(logger_, "OnAudioPassThru NULL pointer"); + + return; + } + + LOG4CXX_INFO_EXT(logger_, "Fill smart object"); + + (*on_audio_pass)[strings::params][strings::message_type] = + application_manager::MessageType::kNotification; + + (*on_audio_pass)[strings::params][strings::connection_key] = + static_cast<int32_t>(session_key); + (*on_audio_pass)[strings::params][strings::function_id] = + mobile_apis::FunctionID::OnAudioPassThruID; + + LOG4CXX_INFO_EXT(logger_, "Fill binary data"); + // binary data + (*on_audio_pass)[strings::params][strings::binary_data] = + smart_objects::SmartObject(binaryData); + + LOG4CXX_INFO_EXT(logger_, "After fill binary data"); + + LOG4CXX_INFO_EXT(logger_, "Send data"); + CommandSharedPtr command ( + MobileCommandFactory::CreateCommand(&(*on_audio_pass))); + command->Init(); + command->Run(); + command->CleanUp(); +} + +void ApplicationManagerImpl::StopAudioPassThru(int32_t application_key) { + LOG4CXX_TRACE_ENTER(logger_); + sync_primitives::AutoLock lock(audio_pass_thru_lock_); + if (NULL != media_manager_) { + media_manager_->StopMicrophoneRecording(application_key); + } +} + +std::string ApplicationManagerImpl::GetDeviceName( + connection_handler::DeviceHandle handle) { + DCHECK(connection_handler_ != 0); + + std::string device_name = ""; + connection_handler::ConnectionHandlerImpl* con_handler_impl = + static_cast<connection_handler::ConnectionHandlerImpl*>( + connection_handler_); + if (con_handler_impl->GetDataOnDeviceID(handle, &device_name, + NULL) == -1) { + LOG4CXX_ERROR(logger_, "Failed to extract device name for id " << handle); + } else { + LOG4CXX_INFO(logger_, "\t\t\t\t\tDevice name is " << device_name); + } + + return device_name; +} + +void ApplicationManagerImpl::OnMessageReceived( + const RawMessagePtr message) { + LOG4CXX_INFO(logger_, "ApplicationManagerImpl::OnMessageReceived"); + + if (!message) { + LOG4CXX_ERROR(logger_, "Null-pointer message received."); + NOTREACHED(); + return; + } + + utils::SharedPtr<Message> outgoing_message = ConvertRawMsgToMessage(message); + + if (outgoing_message) { + messages_from_mobile_.PostMessage( + impl::MessageFromMobile(outgoing_message)); + } +} + +void ApplicationManagerImpl::OnMobileMessageSent( + const RawMessagePtr message) { + LOG4CXX_INFO(logger_, "ApplicationManagerImpl::OnMobileMessageSent"); +} + +void ApplicationManagerImpl::OnMessageReceived( + hmi_message_handler::MessageSharedPointer message) { + LOG4CXX_INFO(logger_, "ApplicationManagerImpl::OnMessageReceived"); + + if (!message) { + LOG4CXX_ERROR(logger_, "Null-pointer message received."); + NOTREACHED(); + return; + } + + messages_from_hmi_.PostMessage(impl::MessageFromHmi(message)); +} + +void ApplicationManagerImpl::OnErrorSending( + hmi_message_handler::MessageSharedPointer message) { + return; +} + +void ApplicationManagerImpl::OnDeviceListUpdated( + const connection_handler::DeviceMap& device_list) { + LOG4CXX_INFO(logger_, "ApplicationManagerImpl::OnDeviceListUpdated"); + + smart_objects::SmartObject* update_list = new smart_objects::SmartObject; + smart_objects::SmartObject& so_to_send = *update_list; + so_to_send[jhs::S_PARAMS][jhs::S_FUNCTION_ID] = + hmi_apis::FunctionID::BasicCommunication_UpdateDeviceList; + so_to_send[jhs::S_PARAMS][jhs::S_MESSAGE_TYPE] = + hmi_apis::messageType::request; + so_to_send[jhs::S_PARAMS][jhs::S_PROTOCOL_VERSION] = 3; + so_to_send[jhs::S_PARAMS][jhs::S_PROTOCOL_TYPE] = 1; + so_to_send[jhs::S_PARAMS][jhs::S_CORRELATION_ID] = GetNextHMICorrelationID(); + smart_objects::SmartObject* msg_params = MessageHelper::CreateDeviceListSO( + device_list); + if (!msg_params) { + LOG4CXX_WARN(logger_, "Failed to create sub-smart object."); + delete update_list; + return; + } + so_to_send[jhs::S_MSG_PARAMS] = *msg_params; + ManageHMICommand(update_list); +} + +void ApplicationManagerImpl::OnFindNewApplicationsRequest() { + connection_handler_->ConnectToAllDevices(); + LOG4CXX_DEBUG(logger_, "Starting application list update timer"); + uint32_t timeout = profile::Profile::instance()->application_list_update_timeout(); + application_list_update_timer_->start(timeout); +} + +void ApplicationManagerImpl::SendUpdateAppList(const std::list<uint32_t>& applications_ids) { + LOG4CXX_TRACE(logger_, "SendUpdateAppList"); + + LOG4CXX_DEBUG(logger_, applications_ids.size() << " applications."); + + smart_objects::SmartObject* request = MessageHelper::CreateModuleInfoSO( + hmi_apis::FunctionID::BasicCommunication_UpdateAppList); + (*request)[strings::msg_params][strings::applications] = + smart_objects::SmartObject(smart_objects::SmartType_Array); + + smart_objects::SmartObject& applications = + (*request)[strings::msg_params][strings::applications]; + + uint32_t app_count = 0; + for (std::list<uint32_t>::const_iterator it = applications_ids.begin(); + it != applications_ids.end(); ++it) { + ApplicationSharedPtr app = application(*it); + + if (!app.valid()) { + LOG4CXX_ERROR(logger_, "Application not found , id = " << *it); + continue; + } + + smart_objects::SmartObject hmi_application(smart_objects::SmartType_Map);; + if (!MessageHelper::CreateHMIApplicationStruct(app, hmi_application)) { + LOG4CXX_ERROR(logger_, "Can't CreateHMIApplicationStruct ', id = " << *it); + continue; + } + applications[app_count++] = hmi_application; + } + if (app_count <= 0) { + LOG4CXX_WARN(logger_, "Empty applications list"); + } + ManageHMICommand(request); +} + +void ApplicationManagerImpl::RemoveDevice( + const connection_handler::DeviceHandle& device_handle) { + LOG4CXX_INFO(logger_, "device_handle " << device_handle); +} + +bool ApplicationManagerImpl::IsAudioStreamingAllowed(uint32_t application_key) const { + ApplicationSharedPtr app = application(application_key); + + if (!app) { + LOG4CXX_WARN(logger_, "An application is not registered."); + return false; + } + + const mobile_api::HMILevel::eType& hmi_level = app->hmi_level(); + + if (mobile_api::HMILevel::HMI_FULL == hmi_level || + mobile_api::HMILevel::HMI_LIMITED == hmi_level) { + return true; + } + + return false; +} + +bool ApplicationManagerImpl::IsVideoStreamingAllowed(uint32_t application_key) const { + ApplicationSharedPtr app = application(application_key); + + if (!app) { + LOG4CXX_WARN(logger_, "An application is not registered."); + return false; + } + + const mobile_api::HMILevel::eType& hmi_level = app->hmi_level(); + + if (mobile_api::HMILevel::HMI_FULL == hmi_level && + app->hmi_supports_navi_video_streaming()) { + return true; + } + + return false; +} + +uint32_t ApplicationManagerImpl::GenerateGrammarID() { + return rand(); +} + +uint32_t ApplicationManagerImpl::GenerateNewHMIAppID() { + uint32_t hmi_app_id = rand(); + + while (resume_ctrl_.IsHMIApplicationIdExist(hmi_app_id)) { + hmi_app_id = rand(); + } + + return hmi_app_id; +} + +void ApplicationManagerImpl::ReplaceMobileByHMIAppId( + smart_objects::SmartObject& message) { + MessageHelper::PrintSmartObject(message); + flush(std::cout); + if (message.keyExists(strings::app_id)) { + ApplicationSharedPtr application = + ApplicationManagerImpl::instance()->application( + message[strings::app_id].asUInt()); + if (application.valid()) { + LOG4CXX_INFO(logger_, "ReplaceMobileByHMIAppId from " << message[strings::app_id].asInt() + << " to " << application->hmi_app_id()); + message[strings::app_id] = application->hmi_app_id(); + } + } else { + switch (message.getType()) { + case smart_objects::SmartType::SmartType_Array: { + smart_objects::SmartArray* message_array = message.asArray(); + smart_objects::SmartArray::iterator it = message_array->begin(); + for(; it != message_array->end(); ++it) { + ReplaceMobileByHMIAppId(*it); + } + break; + } + case smart_objects::SmartType::SmartType_Map: { + std::set<std::string> keys = message.enumerate(); + std::set<std::string>::const_iterator key = keys.begin(); + for (; key != keys.end(); ++key) { + std::string k = *key; + ReplaceMobileByHMIAppId(message[*key]); + } + break; + } + default: { + break; + } + } + } +} + +void ApplicationManagerImpl::ReplaceHMIByMobileAppId( + smart_objects::SmartObject& message) { + if (message.keyExists(strings::app_id)) { + ApplicationSharedPtr application = + ApplicationManagerImpl::instance()->application_by_hmi_app( + message[strings::app_id].asUInt()); + + if (application.valid()) { + LOG4CXX_INFO(logger_, "ReplaceHMIByMobileAppId from " << message[strings::app_id].asInt() + << " to " << application->app_id()); + message[strings::app_id] = application->app_id(); + } + } else { + switch (message.getType()) { + case smart_objects::SmartType::SmartType_Array: { + smart_objects::SmartArray* message_array = message.asArray(); + smart_objects::SmartArray::iterator it = message_array->begin(); + for(; it != message_array->end(); ++it) { + ReplaceHMIByMobileAppId(*it); + } + break; + } + case smart_objects::SmartType::SmartType_Map: { + std::set<std::string> keys = message.enumerate(); + std::set<std::string>::const_iterator key = keys.begin(); + for (; key != keys.end(); ++key) { + ReplaceHMIByMobileAppId(message[*key]); + } + break; + } + default: { + break; + } + } + } +} + +bool ApplicationManagerImpl::OnServiceStartedCallback( + const connection_handler::DeviceHandle& device_handle, + const int32_t& session_key, + const protocol_handler::ServiceType& type) { + LOG4CXX_INFO(logger_, + "OnServiceStartedCallback " << type << " in session " << session_key); + ApplicationSharedPtr app = application(session_key); + + switch (type) { + case protocol_handler::kRpc: { + LOG4CXX_INFO(logger_, "RPC service is about to be started."); + break; + } + case protocol_handler::kMobileNav: { + LOG4CXX_INFO(logger_, "Video service is about to be started."); + if (media_manager_) { + if (!app) { + LOG4CXX_ERROR_EXT(logger_, "An application is not registered."); + return false; + } + if (app->allowed_support_navigation()) { + media_manager_->StartVideoStreaming(session_key); + } else { + return false; + } + } + break; + } + case protocol_handler::kAudio: { + LOG4CXX_INFO(logger_, "Audio service is about to be started."); + if (media_manager_) { + if (!app) { + LOG4CXX_ERROR_EXT(logger_, "An application is not registered."); + return false; + } + if (app->allowed_support_navigation()) { + media_manager_->StartAudioStreaming(session_key); + } else { + return false; + } + } + break; + } + default: { + LOG4CXX_WARN(logger_, "Unknown type of service to be started."); + break; + } + } + + return true; +} + +void ApplicationManagerImpl::OnServiceEndedCallback(const int32_t& session_key, + const protocol_handler::ServiceType& type) { + LOG4CXX_INFO_EXT( + logger_, + "OnServiceEndedCallback " << type << " in session " << session_key); + + switch (type) { + case protocol_handler::kRpc: { + LOG4CXX_INFO(logger_, "Remove application."); + /* in case it was unexpected disconnect application will be removed + and we will notify HMI that it was unexpected disconnect, + but in case it was closed by mobile we will be unable to find it in the list + */ + UnregisterApplication(session_key, mobile_apis::Result::INVALID_ENUM, + true, true); + break; + } + case protocol_handler::kMobileNav: { + LOG4CXX_INFO(logger_, "Stop video streaming."); + if (media_manager_) { + media_manager_->StopVideoStreaming(session_key); + } + break; + } + case protocol_handler::kAudio: { + LOG4CXX_INFO(logger_, "Stop audio service."); + if (media_manager_) { + media_manager_->StopAudioStreaming(session_key); + } + break; + } + default: + LOG4CXX_WARN(logger_, "Unknown type of service to be ended." << + type); + break; + } +} + +void ApplicationManagerImpl::set_hmi_message_handler( + hmi_message_handler::HMIMessageHandler* handler) { + hmi_handler_ = handler; +} + +void ApplicationManagerImpl::set_connection_handler( + connection_handler::ConnectionHandler* handler) { + connection_handler_ = handler; +} + +connection_handler::ConnectionHandler* ApplicationManagerImpl::connection_handler() { + return connection_handler_; +} + +void ApplicationManagerImpl::set_protocol_handler( + protocol_handler::ProtocolHandler* handler) { + protocol_handler_ = handler; +} + +void ApplicationManagerImpl::StartDevicesDiscovery() { + connection_handler::ConnectionHandlerImpl::instance()-> + StartDevicesDiscovery(); +} + +void ApplicationManagerImpl::SendMessageToMobile( + const utils::SharedPtr<smart_objects::SmartObject>& message, + bool final_message) { + LOG4CXX_INFO(logger_, "ApplicationManagerImpl::SendMessageToMobile"); + + if (!message) { + LOG4CXX_ERROR(logger_, "Null-pointer message received."); + NOTREACHED(); + return; + } + + if (!protocol_handler_) { + LOG4CXX_WARN(logger_, "No Protocol Handler set"); + return; + } + + ApplicationSharedPtr app = application( + (*message)[strings::params][strings::connection_key].asUInt()); + + if (!app) { + LOG4CXX_ERROR_EXT(logger_, + "No application associated with connection key"); + if ((*message)[strings::msg_params].keyExists(strings::result_code) && + ((*message)[strings::msg_params][strings::result_code] == + NsSmartDeviceLinkRPC::V1::Result::UNSUPPORTED_VERSION)) { + (*message)[strings::params][strings::protocol_version] = + ProtocolVersion::kV1; + } else { + (*message)[strings::params][strings::protocol_version] = + ProtocolVersion::kV3; + } + } else { + (*message)[strings::params][strings::protocol_version] = + app->protocol_version(); + } + + mobile_so_factory().attachSchema(*message); + LOG4CXX_INFO( + logger_, + "Attached schema to message, result if valid: " << message->isValid()); + + // Messages to mobile are not yet prioritized so use default priority value + utils::SharedPtr<Message> message_to_send(new Message( + protocol_handler::MessagePriority::kDefault)); + if (!ConvertSOtoMessage((*message), (*message_to_send))) { + LOG4CXX_WARN(logger_, "Can't send msg to Mobile: failed to create string"); + return; + } + + smart_objects::SmartObject& msg_to_mobile = *message; + // If correlation_id is not present, it is from-HMI message which should be + // checked against policy permissions + if (msg_to_mobile[strings::params].keyExists(strings::correlation_id)) { + request_ctrl_.terminateMobileRequest( + msg_to_mobile[strings::params][strings::correlation_id].asInt()); + } else if (app) { + mobile_apis::FunctionID::eType function_id = + static_cast<mobile_apis::FunctionID::eType>( + (*message)[strings::params][strings::function_id].asUInt()); + RPCParams params; + + const smart_objects::SmartObject& s_map = (*message)[strings::msg_params]; + if (smart_objects::SmartType_Map == s_map.getType()) { + smart_objects::SmartMap::iterator iter = s_map.map_begin(); + smart_objects::SmartMap::iterator iter_end = s_map.map_end(); + + for (; iter != iter_end; ++iter) { + params.push_back(iter->first); + } + } + const mobile_apis::Result::eType check_result = + CheckPolicyPermissions( app->mobile_app_id()->asString(), + app->hmi_level(), function_id, params); + if (mobile_apis::Result::SUCCESS != check_result) { + const std::string string_functionID = + MessageHelper::StringifiedFunctionID(function_id); + LOG4CXX_WARN(logger_, "Function \"" << string_functionID << "\" (#" + << function_id << ") not allowed by policy"); + return; + } + + if (function_id == mobile_apis::FunctionID::OnSystemRequestID) { + policy::PolicyHandler::instance()->OnUpdateRequestSentToMobile(); + } + } + + messages_to_mobile_.PostMessage(impl::MessageToMobile(message_to_send, + final_message)); +} + +bool ApplicationManagerImpl::ManageMobileCommand( + const utils::SharedPtr<smart_objects::SmartObject>& message) { + LOG4CXX_INFO(logger_, "ApplicationManagerImpl::ManageMobileCommand"); + + if (!message) { + LOG4CXX_WARN(logger_, "RET Null-pointer message received."); + NOTREACHED() + return false; + } + +#ifdef DEBUG + MessageHelper::PrintSmartObject(*message); +#endif + + LOG4CXX_INFO(logger_, "Trying to create message in mobile factory."); + commands::Command* command = MobileCommandFactory::CreateCommand(message); + + if (!command) { + LOG4CXX_WARN(logger_, "RET Failed to create mobile command from smart object"); + return false; + } + + mobile_apis::FunctionID::eType function_id = + static_cast<mobile_apis::FunctionID::eType>( + (*message)[strings::params][strings::function_id].asInt()); + + // Notifications from HMI have no such parameter + uint32_t correlation_id = + (*message)[strings::params].keyExists(strings::correlation_id) + ? (*message)[strings::params][strings::correlation_id].asUInt() + : 0; + + uint32_t connection_key = + (*message)[strings::params][strings::connection_key].asUInt(); + + int32_t protocol_type = + (*message)[strings::params][strings::protocol_type].asUInt(); + + ApplicationSharedPtr app; + int32_t message_type = (*message)[strings::params][strings::message_type].asInt(); + + if (((mobile_apis::FunctionID::RegisterAppInterfaceID != function_id) && + (protocol_type == commands::CommandImpl::mobile_protocol_type_)) && + (mobile_apis::FunctionID::UnregisterAppInterfaceID != function_id)) { + app = ApplicationManagerImpl::instance()->application(connection_key); + if (!app) { + LOG4CXX_ERROR_EXT(logger_, "RET APPLICATION_NOT_REGISTERED"); + smart_objects::SmartObject* response = + MessageHelper::CreateNegativeResponse( + connection_key, + static_cast<int32_t>(function_id), + correlation_id, + static_cast<int32_t>(mobile_apis::Result::APPLICATION_NOT_REGISTERED)); + + SendMessageToMobile(response); + return false; + } + + // Message for "CheckPermission" must be with attached schema + mobile_so_factory().attachSchema(*message); + } + + if (message_type == + mobile_apis::messageType::response) { + if (command->Init()) { + command->Run(); + command->CleanUp(); + } + delete command; + return true; + } + if (message_type == + mobile_apis::messageType::notification) { + commands::CommandNotificationImpl* command_notify = + static_cast<commands::CommandNotificationImpl*>(command); + request_ctrl_.addNotification(command_notify); + if (command_notify->Init()) { + command_notify->Run(); + if (command_notify->CleanUp()) { + request_ctrl_.removeNotification(command_notify); + } + // If CleanUp returned false notification should remove it self. + } + return true; + } + + if (message_type == + mobile_apis::messageType::request) { + + commands::CommandRequestImpl* command_request = + static_cast<commands::CommandRequestImpl*>(command); + // commands will be launched from requesr_ctrl + mobile_apis::HMILevel::eType app_hmi_level = mobile_apis::HMILevel::INVALID_ENUM; + if (app) { + app_hmi_level = app->hmi_level(); + } + + // commands will be launched from request_ctrl + + request_controller::RequestController::TResult result = + request_ctrl_.addMobileRequest(command_request, app_hmi_level); + + if (result == request_controller::RequestController::SUCCESS) { + LOG4CXX_INFO(logger_, "Perform request"); + } else if (result == + request_controller::RequestController:: + TOO_MANY_PENDING_REQUESTS) { + LOG4CXX_ERROR_EXT(logger_, "RET Unable top perform request: " << + "TOO_MANY_PENDING_REQUESTS"); + + smart_objects::SmartObject* response = + MessageHelper::CreateNegativeResponse( + connection_key, + static_cast<int32_t>(function_id), + correlation_id, + static_cast<int32_t>(mobile_apis::Result::TOO_MANY_PENDING_REQUESTS)); + + SendMessageToMobile(response); + return false; + } else if (result == + request_controller::RequestController::TOO_MANY_REQUESTS) { + LOG4CXX_ERROR_EXT(logger_, "RET Unable to perform request: " << + "TOO_MANY_REQUESTS"); + + MessageHelper::SendOnAppInterfaceUnregisteredNotificationToMobile( + connection_key, + mobile_api::AppInterfaceUnregisteredReason::TOO_MANY_REQUESTS); + + UnregisterApplication(connection_key, + mobile_apis::Result::TOO_MANY_PENDING_REQUESTS, + false); + return false; + } else if (result == + request_controller::RequestController:: + NONE_HMI_LEVEL_MANY_REQUESTS) { + LOG4CXX_ERROR_EXT(logger_, "RET Unable to perform request: " << + "REQUEST_WHILE_IN_NONE_HMI_LEVEL"); + + MessageHelper::SendOnAppInterfaceUnregisteredNotificationToMobile( + connection_key, mobile_api::AppInterfaceUnregisteredReason:: + REQUEST_WHILE_IN_NONE_HMI_LEVEL); + + application(connection_key)->usage_report().RecordRemovalsForBadBehavior(); + UnregisterApplication(connection_key, mobile_apis::Result::INVALID_ENUM, + false); + return false; + } else { + LOG4CXX_ERROR_EXT(logger_, "RET Unable to perform request: Unknown case"); + return false; + } + return true; + } + + LOG4CXX_ERROR(logger_, "RET UNKNOWN MESSAGE TYPE " << message_type); + return false; +} + +void ApplicationManagerImpl::SendMessageToHMI( + const utils::SharedPtr<smart_objects::SmartObject>& message) { + LOG4CXX_INFO(logger_, "ApplicationManagerImpl::SendMessageToHMI"); + + if (!message) { + LOG4CXX_WARN(logger_, "Null-pointer message received."); + NOTREACHED(); + return; + } + + if (!hmi_handler_) { + LOG4CXX_WARN(logger_, "No HMI Handler set"); + return; + } + + // SmartObject |message| has no way to declare priority for now + utils::SharedPtr<Message> message_to_send( + new Message(protocol_handler::MessagePriority::kDefault)); + if (!message_to_send) { + LOG4CXX_ERROR(logger_, "Null pointer"); + return; + } + + hmi_so_factory().attachSchema(*message); + LOG4CXX_INFO( + logger_, + "Attached schema to message, result if valid: " << message->isValid()); + + +#ifdef HMI_DBUS_API + message_to_send->set_smart_object(*message); +#else + if (!ConvertSOtoMessage(*message, *message_to_send)) { + LOG4CXX_WARN(logger_, + "Cannot send message to HMI: failed to create string"); + return; + } +#endif // HMI_DBUS_API + + messages_to_hmi_.PostMessage(impl::MessageToHmi(message_to_send)); +} + +bool ApplicationManagerImpl::ManageHMICommand( + const utils::SharedPtr<smart_objects::SmartObject>& message) { + LOG4CXX_INFO(logger_, "ApplicationManagerImpl::ManageHMICommand"); + + if (!message) { + LOG4CXX_WARN(logger_, "Null-pointer message received."); + NOTREACHED(); + return false; + } + + + MessageHelper::PrintSmartObject(*message); + + CommandSharedPtr command = HMICommandFactory::CreateCommand(message); + if (!command) { + LOG4CXX_WARN(logger_, "Failed to create command from smart object"); + return false; + } + + int32_t message_type = (*(message.get()))[strings::params][strings::message_type].asInt(); + + if (kRequest == message_type) { + LOG4CXX_DEBUG(logger_, "ManageHMICommand"); + request_ctrl_.addHMIRequest(command); + } + + if (command->Init()) { + command->Run(); + if (kResponse == message_type) { + int32_t correlation_id = (*(message.get()))[strings::params][strings::correlation_id].asInt(); + request_ctrl_.terminateHMIRequest(correlation_id); + } + return true; + } + return false; +} + +bool ApplicationManagerImpl::Init() { + LOG4CXX_TRACE(logger_, "Init application manager"); + if (policy::PolicyHandler::instance()->PolicyEnabled()) { + if(!policy::PolicyHandler::instance()->LoadPolicyLibrary()) { + LOG4CXX_ERROR(logger_, "Policy library is not loaded. Check LD_LIBRARY_PATH"); + return false; + } + LOG4CXX_INFO(logger_, "Policy library is loaded, now initing PT"); + if (!policy::PolicyHandler::instance()->InitPolicyTable()) { + LOG4CXX_ERROR(logger_, "Policy table is not initialized."); + return false; + } + } else { + LOG4CXX_WARN(logger_, "System is configured to work without policy functionality."); + } + const std::string app_storage_folder = + profile::Profile::instance()->app_storage_folder(); + if (!file_system::DirectoryExists(app_storage_folder)) { + LOG4CXX_WARN(logger_, "Storage directory doesn't exist"); + // if storage directory doesn't exist try to create it + if (!file_system::CreateDirectoryRecursively(app_storage_folder)) { + LOG4CXX_ERROR(logger_, "Unable to create Storage directory " + << app_storage_folder); + return false; + } + } + if (!(file_system::IsWritingAllowed(app_storage_folder) && + file_system::IsReadingAllowed(app_storage_folder))) { + LOG4CXX_ERROR(logger_, + "Storage directory doesn't have read/write permissions"); + return false; + } + + const std::string system_files_path = + profile::Profile::instance()->system_files_path(); + if (!file_system::DirectoryExists(system_files_path)) { + LOG4CXX_WARN(logger_, "System files directory doesn't exist"); + // if system directory doesn't exist try to create it + if (!file_system::CreateDirectoryRecursively(system_files_path)) { + LOG4CXX_ERROR(logger_, "Unable to create System directory " + << system_files_path); + return false; + } + } + if (!(file_system::IsWritingAllowed(system_files_path) && + file_system::IsReadingAllowed(system_files_path))) { + LOG4CXX_ERROR(logger_, + "System directory doesn't have read/write permissions"); + return false; + } + media_manager_ = media_manager::MediaManagerImpl::instance(); + return true; +} + +bool ApplicationManagerImpl::ConvertMessageToSO( + const Message& message, smart_objects::SmartObject& output) { + LOG4CXX_INFO( + logger_, + "\t\t\tMessage to convert: protocol " << message.protocol_version() + << "; json " << message.json_message()); + + switch (message.protocol_version()) { + case ProtocolVersion::kV3: + case ProtocolVersion::kV2: { + const bool conversion_result = + formatters::CFormatterJsonSDLRPCv2::fromString( + message.json_message(), output, message.function_id(), + message.type(), message.correlation_id()); + if (!conversion_result + || !mobile_so_factory().attachSchema(output) + || ((output.validate() != smart_objects::Errors::OK)) ) { + LOG4CXX_WARN(logger_, "Failed to parse string to smart object :" + << message.json_message()); + utils::SharedPtr<smart_objects::SmartObject> response( + MessageHelper::CreateNegativeResponse( + message.connection_key(), message.function_id(), + message.correlation_id(), mobile_apis::Result::INVALID_DATA)); + ManageMobileCommand(response); + return false; + } + LOG4CXX_INFO( + logger_, + "Convertion result for sdl object is true" << " function_id " + << output[jhs::S_PARAMS][jhs::S_FUNCTION_ID].asInt()); + output[strings::params][strings::connection_key] = + message.connection_key(); + output[strings::params][strings::protocol_version] = + message.protocol_version(); + if (message.binary_data()) { + if (message.payload_size() < message.data_size()) { + LOG4CXX_ERROR(logger_, "Incomplete binary" << + " binary size should be " << message.data_size() << + " payload data size is " << message.payload_size()); + utils::SharedPtr<smart_objects::SmartObject> response( + MessageHelper::CreateNegativeResponse( + message.connection_key(), message.function_id(), + message.correlation_id(), mobile_apis::Result::INVALID_DATA)); + ManageMobileCommand(response); + return false; + } + output[strings::params][strings::binary_data] = + *(message.binary_data()); + } + break; + } + case ProtocolVersion::kHMI: { +#ifdef ENABLE_LOG + int32_t result = +#endif + formatters::FormatterJsonRpc::FromString < + hmi_apis::FunctionID::eType, hmi_apis::messageType::eType > ( + message.json_message(), output); + LOG4CXX_INFO( + logger_, + "Convertion result: " << result << " function id " + << output[jhs::S_PARAMS][jhs::S_FUNCTION_ID].asInt()); + if (!hmi_so_factory().attachSchema(output)) { + LOG4CXX_WARN(logger_, "Failed to attach schema to object."); + return false; + } + if (output.validate() != smart_objects::Errors::OK) { + LOG4CXX_WARN(logger_, "Incorrect parameter from HMI"); + output.erase(strings::msg_params); + output[strings::params][hmi_response::code] = + hmi_apis::Common_Result::INVALID_DATA; + output[strings::msg_params][strings::info] = + std::string("Received invalid data on HMI response"); + } + break; + } + case ProtocolVersion::kV1: { + static NsSmartDeviceLinkRPC::V1::v4_protocol_v1_2_no_extra v1_shema; + + if (message.function_id() == 0 || message.type() == kUnknownType) { + LOG4CXX_ERROR(logger_, "Message received: UNSUPPORTED_VERSION"); + + int32_t conversation_result = + formatters::CFormatterJsonSDLRPCv1::fromString < + NsSmartDeviceLinkRPC::V1::FunctionID::eType, + NsSmartDeviceLinkRPC::V1::messageType::eType > ( + message.json_message(), output); + + if (formatters::CFormatterJsonSDLRPCv1::kSuccess + == conversation_result) { + + smart_objects::SmartObject params = smart_objects::SmartObject(smart_objects::SmartType::SmartType_Map); + + output[strings::params][strings::message_type] = + NsSmartDeviceLinkRPC::V1::messageType::response; + output[strings::params][strings::connection_key] = message.connection_key(); + + output[strings::msg_params] = + smart_objects::SmartObject(smart_objects::SmartType::SmartType_Map); + output[strings::msg_params][strings::success] = false; + output[strings::msg_params][strings::result_code] = + NsSmartDeviceLinkRPC::V1::Result::UNSUPPORTED_VERSION; + + smart_objects::SmartObject* msg_to_send = new smart_objects::SmartObject(output); + v1_shema.attachSchema(*msg_to_send); + SendMessageToMobile(msg_to_send); + return false; + } + } + + break; + } + default: + // TODO(PV): + // removed NOTREACHED() because some app can still have vesion 1. + LOG4CXX_WARN( + logger_, + "Application used unsupported protocol :" << message.protocol_version() + << "."); + return false; + } + + LOG4CXX_INFO(logger_, "Successfully parsed message into smart object"); + return true; +} + +bool ApplicationManagerImpl::ConvertSOtoMessage( + const smart_objects::SmartObject& message, Message& output) { + LOG4CXX_INFO(logger_, "Message to convert"); + + if (smart_objects::SmartType_Null == message.getType() + || smart_objects::SmartType_Invalid == message.getType()) { + LOG4CXX_WARN(logger_, "Invalid smart object received."); + return false; + } + + LOG4CXX_INFO( + logger_, + "Message with protocol: " + << message.getElement(jhs::S_PARAMS).getElement(jhs::S_PROTOCOL_TYPE) + .asInt()); + + std::string output_string; + switch (message.getElement(jhs::S_PARAMS).getElement(jhs::S_PROTOCOL_TYPE) + .asInt()) { + case 0: { + if (message.getElement(jhs::S_PARAMS).getElement(jhs::S_PROTOCOL_VERSION).asInt() == 1) { + if (!formatters::CFormatterJsonSDLRPCv1::toString(message, + output_string)) { + LOG4CXX_WARN(logger_, "Failed to serialize smart object"); + return false; + } + output.set_protocol_version(application_manager::kV1); + } else { + if (!formatters::CFormatterJsonSDLRPCv2::toString(message, + output_string)) { + LOG4CXX_WARN(logger_, "Failed to serialize smart object"); + return false; + } + output.set_protocol_version( + static_cast<ProtocolVersion>( + message.getElement(jhs::S_PARAMS).getElement( + jhs::S_PROTOCOL_VERSION).asUInt())); + } + + break; + } + case 1: { + if (!formatters::FormatterJsonRpc::ToString(message, output_string)) { + LOG4CXX_WARN(logger_, "Failed to serialize smart object"); + return false; + } + output.set_protocol_version(application_manager::kHMI); + break; + } + default: + NOTREACHED(); + return false; + } + + LOG4CXX_INFO(logger_, "Convertion result: " << output_string); + + output.set_connection_key( + message.getElement(jhs::S_PARAMS).getElement(strings::connection_key) + .asInt()); + + output.set_function_id( + message.getElement(jhs::S_PARAMS).getElement(jhs::S_FUNCTION_ID).asInt()); + + output.set_correlation_id( + message.getElement(jhs::S_PARAMS).getElement(jhs::S_CORRELATION_ID) + .asInt()); + output.set_message_type( + static_cast<MessageType>(message.getElement(jhs::S_PARAMS).getElement( + jhs::S_MESSAGE_TYPE).asInt())); + + // Currently formatter creates JSON = 3 bytes for empty SmartObject. + // workaround for notification. JSON must be empty + if (mobile_apis::FunctionID::OnAudioPassThruID + != message.getElement(jhs::S_PARAMS).getElement(strings::function_id) + .asInt()) { + output.set_json_message(output_string); + } + + if (message.getElement(jhs::S_PARAMS).keyExists(strings::binary_data)) { + application_manager::BinaryData* binaryData = + new application_manager::BinaryData( + message.getElement(jhs::S_PARAMS).getElement(strings::binary_data) + .asBinary()); + + if (NULL == binaryData) { + LOG4CXX_ERROR(logger_, "Null pointer"); + return false; + } + output.set_binary_data(binaryData); + } + + LOG4CXX_INFO(logger_, "Successfully parsed smart object into message"); + return true; +} + +utils::SharedPtr<Message> ApplicationManagerImpl::ConvertRawMsgToMessage( + const RawMessagePtr message) { + DCHECK(message); + utils::SharedPtr<Message> outgoing_message; + + LOG4CXX_INFO(logger_, "Service type." << message->service_type()); + + if (message->service_type() != protocol_handler::kRpc + && + message->service_type() != protocol_handler::kBulk) { + // skip this message, not under handling of ApplicationManager + LOG4CXX_TRACE(logger_, "Skipping message; not the under AM handling."); + return outgoing_message; + } + + Message* convertion_result = NULL; + if (message->protocol_version() == 1) { + convertion_result = + MobileMessageHandler::HandleIncomingMessageProtocolV1(message); + } else if ((message->protocol_version() == 2) || + (message->protocol_version() == 3)) { + convertion_result = + MobileMessageHandler::HandleIncomingMessageProtocolV2(message); + } else { + LOG4CXX_WARN(logger_, "Unknown protocol version."); + return outgoing_message; + } + + if (convertion_result) { + outgoing_message = convertion_result; + } else { + LOG4CXX_ERROR(logger_, "Received invalid message"); + } + return outgoing_message; +} + +void ApplicationManagerImpl::ProcessMessageFromMobile( + const utils::SharedPtr<Message>& message) { + LOG4CXX_INFO(logger_, "ApplicationManagerImpl::ProcessMessageFromMobile()"); +#ifdef TIME_TESTER + AMMetricObserver::MessageMetricSharedPtr metric(new AMMetricObserver::MessageMetric()); + metric->begin = date_time::DateTime::getCurrentTime(); +#endif // TIME_TESTER + utils::SharedPtr<smart_objects::SmartObject> so_from_mobile( + new smart_objects::SmartObject); + + if (!so_from_mobile) { + LOG4CXX_ERROR(logger_, "Null pointer"); + return; + } + + if (!ConvertMessageToSO(*message, *so_from_mobile)) { + LOG4CXX_ERROR(logger_, "Cannot create smart object from message"); + return; + } +#ifdef TIME_TESTER + metric->message = so_from_mobile; +#endif // TIME_TESTER + + if (!ManageMobileCommand(so_from_mobile)) { + LOG4CXX_ERROR(logger_, "Received command didn't run successfully"); + } +#ifdef TIME_TESTER + metric->end = date_time::DateTime::getCurrentTime(); + if (metric_observer_) { + metric_observer_->OnMessage(metric); + } +#endif // TIME_TESTER +} + +void ApplicationManagerImpl::ProcessMessageFromHMI( + const utils::SharedPtr<Message>& message) { + LOG4CXX_INFO(logger_, "ApplicationManagerImpl::ProcessMessageFromHMI()"); + utils::SharedPtr<smart_objects::SmartObject> smart_object( + new smart_objects::SmartObject); + + if (!smart_object) { + LOG4CXX_ERROR(logger_, "Null pointer"); + return; + } + +#ifdef HMI_DBUS_API + *smart_object = message->smart_object(); +#else + if (!ConvertMessageToSO(*message, *smart_object)) { + LOG4CXX_ERROR(logger_, "Cannot create smart object from message"); + return; + } +#endif // HMI_DBUS_API + + LOG4CXX_INFO(logger_, "Converted message, trying to create hmi command"); + if (!ManageHMICommand(smart_object)) { + LOG4CXX_ERROR(logger_, "Received command didn't run successfully"); + } +} + +hmi_apis::HMI_API& ApplicationManagerImpl::hmi_so_factory() { + if (!hmi_so_factory_) { + hmi_so_factory_ = new hmi_apis::HMI_API; + if (!hmi_so_factory_) { + LOG4CXX_ERROR(logger_, "Out of memory"); + NOTREACHED(); + } + } + return *hmi_so_factory_; +} + +mobile_apis::MOBILE_API& ApplicationManagerImpl::mobile_so_factory() { + if (!mobile_so_factory_) { + mobile_so_factory_ = new mobile_apis::MOBILE_API; + if (!mobile_so_factory_) { + LOG4CXX_ERROR(logger_, "Out of memory."); + NOTREACHED(); + } + } + return *mobile_so_factory_; +} + +HMICapabilities& ApplicationManagerImpl::hmi_capabilities() { + return hmi_capabilities_; +} + +#ifdef TIME_TESTER +void ApplicationManagerImpl::SetTimeMetricObserver(AMMetricObserver* observer) { + metric_observer_ = observer; +} +#endif // TIME_TESTER + +void ApplicationManagerImpl::addNotification(const CommandSharedPtr ptr) { + request_ctrl_.addNotification(ptr); +} + +void ApplicationManagerImpl::removeNotification(const commands::Command* notification) { + request_ctrl_.removeNotification(notification); +} + +void ApplicationManagerImpl::updateRequestTimeout(uint32_t connection_key, + uint32_t mobile_correlation_id, + uint32_t new_timeout_value) { + request_ctrl_.updateRequestTimeout(connection_key, mobile_correlation_id, + new_timeout_value); +} + +const uint32_t ApplicationManagerImpl::application_id +(const int32_t correlation_id) { + // ykazakov: there is no erase for const iterator for QNX + std::map<const int32_t, const uint32_t>::iterator it = + appID_list_.find(correlation_id); + if (appID_list_.end() != it) { + const uint32_t app_id = it->second; + appID_list_.erase(it); + return app_id; + } else { + return 0; + } +} + +void ApplicationManagerImpl::set_application_id(const int32_t correlation_id, + const uint32_t app_id) { + appID_list_.insert(std::pair<const int32_t, const uint32_t> + (correlation_id, app_id)); +} + +void ApplicationManagerImpl::SetUnregisterAllApplicationsReason( + mobile_api::AppInterfaceUnregisteredReason::eType reason) { + unregister_reason_ = reason; +} + +void ApplicationManagerImpl::HeadUnitReset( + mobile_api::AppInterfaceUnregisteredReason::eType reason) { + switch (reason) { + case mobile_api::AppInterfaceUnregisteredReason::MASTER_RESET: { + file_system::remove_directory_content(profile::Profile::instance()->app_storage_folder()); + resume_controller().ClearResumptionInfo(); + policy::PolicyHandler::instance()->ResetPolicyTable(); + break; + } + case mobile_api::AppInterfaceUnregisteredReason::FACTORY_DEFAULTS: { + policy::PolicyHandler::instance()->ClearUserConsent(); + break; + } + default: { + LOG4CXX_ERROR(logger_, "Bad AppInterfaceUnregisteredReason"); + return; + } + } +} + +void ApplicationManagerImpl::HeadUnitSuspend() { + LOG4CXX_INFO(logger_, "ApplicationManagerImpl::HeadUnitSuspend"); +} + +void ApplicationManagerImpl::SendOnSDLClose() { + LOG4CXX_INFO(logger_, "ApplicationManagerImpl::SendOnSDLClose"); + + // must be sent to PASA HMI on shutdown synchronously + smart_objects::SmartObject* msg = new smart_objects::SmartObject( + smart_objects::SmartType_Map); + + (*msg)[strings::params][strings::function_id] = + hmi_apis::FunctionID::BasicCommunication_OnSDLClose; + (*msg)[strings::params][strings::message_type] = + MessageType::kNotification; + (*msg)[strings::params][strings::protocol_type] = + commands::CommandImpl::hmi_protocol_type_; + (*msg)[strings::params][strings::protocol_version] = + commands::CommandImpl::protocol_version_; + + if (!msg) { + LOG4CXX_WARN(logger_, "Null-pointer message received."); + NOTREACHED(); + return; + } + + // SmartObject |message| has no way to declare priority for now + utils::SharedPtr<Message> message_to_send( + new Message(protocol_handler::MessagePriority::kDefault)); + + hmi_so_factory().attachSchema(*msg); + LOG4CXX_INFO( + logger_, + "Attached schema to message, result if valid: " << msg->isValid()); + + +#ifdef HMI_DBUS_API + message_to_send->set_smart_object(*msg); +#else + if (!ConvertSOtoMessage(*msg, *message_to_send)) { + LOG4CXX_WARN(logger_, + "Cannot send message to HMI: failed to create string"); + return; + } +#endif // HMI_DBUS_API + + if (!hmi_handler_) { + LOG4CXX_WARN(logger_, "No HMI Handler set"); + return; + } + + delete msg; + hmi_handler_->SendMessageToHMI(message_to_send); +} + +void ApplicationManagerImpl::UnregisterAllApplications(bool generated_by_hmi) { + LOG4CXX_INFO(logger_, "ApplicationManagerImpl::UnregisterAllApplications " << + unregister_reason_); + + hmi_cooperating_ = false; + + bool is_ignition_off = + unregister_reason_ == + mobile_api::AppInterfaceUnregisteredReason::IGNITION_OFF ? true : false; + + bool is_unexpected_disconnect = (generated_by_hmi != true); + + sync_primitives::AutoLock lock(applications_list_lock_); + + std::set<ApplicationSharedPtr>::iterator it = application_list_.begin(); + while (it != application_list_.end()) { + ApplicationSharedPtr app_to_remove = *it; + MessageHelper::SendOnAppInterfaceUnregisteredNotificationToMobile( + app_to_remove->app_id(), unregister_reason_); + UnregisterApplication(app_to_remove->app_id(), + mobile_apis::Result::INVALID_ENUM, is_ignition_off, + is_unexpected_disconnect); + + connection_handler_->CloseSession(app_to_remove->app_id()); + it = application_list_.begin(); + } + + if (is_ignition_off) { + resume_controller().IgnitionOff(); + } + request_ctrl_.terminateAllHMIRequests(); +} + +void ApplicationManagerImpl::UnregisterApplication( + const uint32_t& app_id, mobile_apis::Result::eType reason, + bool is_resuming, bool is_unexpected_disconnect) { + LOG4CXX_INFO(logger_, + "ApplicationManagerImpl::UnregisterApplication " << app_id); + //remove appID from tts_global_properties_app_list_ + RemoveAppFromTTSGlobalPropertiesList(app_id); + + sync_primitives::AutoLock lock(applications_list_lock_); + + switch (reason) { + case mobile_apis::Result::SUCCESS:break; + case mobile_apis::Result::DISALLOWED: break; + case mobile_apis::Result::USER_DISALLOWED:break; + case mobile_apis::Result::INVALID_CERT: break; + case mobile_apis::Result::EXPIRED_CERT: break; + case mobile_apis::Result::TOO_MANY_PENDING_REQUESTS: { + application(app_id)->usage_report().RecordRemovalsForBadBehavior(); + break; + } + default: { + LOG4CXX_ERROR(logger_, "Unknown unregister reason " << reason); + break; + } + } + + ApplicationSharedPtr app_to_remove; + std::set<ApplicationSharedPtr>::const_iterator it = application_list_.begin(); + for (; it != application_list_.end(); ++it) { + if ((*it)->app_id() == app_id) { + app_to_remove = *it; + break; + } + } + if (!app_to_remove) { + LOG4CXX_ERROR(logger_, "Cant find application with app_id = " << app_id); + return; + } + application_list_.erase(app_to_remove); + + if (is_resuming) { + resume_ctrl_.SaveApplication(app_to_remove); + } + + if (audio_pass_thru_active_) { + // May be better to put this code in MessageHelper? + end_audio_pass_thru(); + StopAudioPassThru(app_id); + MessageHelper::SendStopAudioPathThru(); + } + MessageHelper::SendOnAppUnregNotificationToHMI(app_to_remove, + is_unexpected_disconnect); + + request_ctrl_.terminateAppRequests(app_id); + return; +} + + +void ApplicationManagerImpl::UnregisterRevokedApplication( + const uint32_t& app_id, mobile_apis::Result::eType reason) { + UnregisterApplication(app_id, reason); + + connection_handler_->CloseSession(app_id); + + if (application_list_.empty()) { + connection_handler_->CloseRevokedConnection(app_id); + } +} + +void ApplicationManagerImpl::Handle(const impl::MessageFromMobile message) { + LOG4CXX_INFO(logger_, "Received message from Mobile side"); + + if (!message) { + LOG4CXX_ERROR(logger_, "Null-pointer message received."); + return; + } + ProcessMessageFromMobile(message); +} + +void ApplicationManagerImpl::Handle(const impl::MessageToMobile message) { + protocol_handler::RawMessage* rawMessage = 0; + if (message->protocol_version() == application_manager::kV1) { + rawMessage = MobileMessageHandler::HandleOutgoingMessageProtocolV1(message); + } else if ((message->protocol_version() == application_manager::kV2) || + (message->protocol_version() == application_manager::kV3)) { + rawMessage = MobileMessageHandler::HandleOutgoingMessageProtocolV2(message); + } else { + return; + } + if (!rawMessage) { + LOG4CXX_ERROR(logger_, "Failed to create raw message."); + return; + } + + if (!protocol_handler_) { + LOG4CXX_WARN(logger_, + "Protocol Handler is not set; cannot send message to mobile."); + return; + } + + + bool is_final = message.is_final; + bool close_session = false; + if (is_final) { + if (1 < connection_handler_->GetConnectionSessionsCount(message->connection_key())) { + is_final = false; + close_session = true; + } + } + + protocol_handler_->SendMessageToMobileApp(rawMessage, is_final); + LOG4CXX_INFO(logger_, "Message for mobile given away"); + + if (close_session) { + connection_handler_->CloseSession(message->connection_key()); + } +} + +void ApplicationManagerImpl::Handle(const impl::MessageFromHmi message) { + LOG4CXX_INFO(logger_, "Received message from hmi"); + + if (!message) { + LOG4CXX_ERROR(logger_, "Null-pointer message received."); + return; + } + + ProcessMessageFromHMI(message); +} + +void ApplicationManagerImpl::Handle(const impl::MessageToHmi message) { + LOG4CXX_INFO(logger_, "Received message to hmi"); + if (!hmi_handler_) { + LOG4CXX_ERROR(logger_, "Observer is not set for HMIMessageHandler"); + return; + } + + hmi_handler_->SendMessageToHMI(message); + LOG4CXX_INFO(logger_, "Message to hmi given away."); +} + +mobile_apis::Result::eType ApplicationManagerImpl::CheckPolicyPermissions( + const std::string& policy_app_id, + mobile_apis::HMILevel::eType hmi_level, + mobile_apis::FunctionID::eType function_id, + const RPCParams& rpc_params, + CommandParametersPermissions* params_permissions) { + LOG4CXX_INFO(logger_, "CheckPolicyPermissions"); + // TODO(AOleynik): Remove check of policy_enable, when this flag will be + // unused in config file + if (!policy::PolicyHandler::instance()->PolicyEnabled()) { + return mobile_apis::Result::SUCCESS; + } + + const std::string stringified_functionID = + MessageHelper::StringifiedFunctionID(function_id); + const std::string stringified_hmi_level = + MessageHelper::StringifiedHMILevel(hmi_level); + LOG4CXX_INFO( + logger_, + "Checking permissions for " << policy_app_id << + " in " << stringified_hmi_level << + " rpc " << stringified_functionID); + policy::CheckPermissionResult result; + policy::PolicyHandler::instance()->CheckPermissions( + policy_app_id, + stringified_hmi_level, + stringified_functionID, + rpc_params, + result); + + if (NULL != params_permissions) { + params_permissions->allowed_params = result.list_of_allowed_params; + params_permissions->disallowed_params = result.list_of_disallowed_params; + params_permissions->undefined_params = result.list_of_undefined_params; + } + + if (hmi_level == mobile_apis::HMILevel::HMI_NONE + && function_id != mobile_apis::FunctionID::UnregisterAppInterfaceID) { + ApplicationSharedPtr app = application_by_policy_id(policy_app_id); + if (!app) { + LOG4CXX_ERROR(logger_, "No application for policy id " << policy_app_id); + return mobile_apis::Result::GENERIC_ERROR; + } + if (result.hmi_level_permitted != policy::kRpcAllowed) { + app->usage_report().RecordRpcSentInHMINone(); + } + } + + const std::string log_msg = "Application: "+ policy_app_id+ + ", RPC: "+stringified_functionID+ + ", HMI status: "+stringified_hmi_level; + + if (result.hmi_level_permitted != policy::kRpcAllowed) { + LOG4CXX_WARN(logger_, "Request is blocked by policies. " << log_msg ); + + application_by_policy_id(policy_app_id)-> + usage_report().RecordPolicyRejectedRpcCall(); + + switch (result.hmi_level_permitted) { + case policy::kRpcDisallowed: + return mobile_apis::Result::DISALLOWED; + case policy::kRpcUserDisallowed: + return mobile_apis::Result::USER_DISALLOWED; + default: + return mobile_apis::Result::INVALID_ENUM; + } + } + LOG4CXX_INFO(logger_, "Request is allowed by policies. "+log_msg); + return mobile_api::Result::SUCCESS; +} + +void ApplicationManagerImpl::Mute(VRTTSSessionChanging changing_state) { + mobile_apis::AudioStreamingState::eType state = + hmi_capabilities_.attenuated_supported() + ? mobile_apis::AudioStreamingState::ATTENUATED + : mobile_apis::AudioStreamingState::NOT_AUDIBLE; + ApplicationManagerImpl::ApplicationListAccessor accessor; + ApplicationManagerImpl::TAppList local_app_list = accessor.applications(); + + ApplicationManagerImpl::TAppListConstIt it = local_app_list.begin(); + ApplicationManagerImpl::TAppListConstIt itEnd = local_app_list.end(); + for (; it != itEnd; ++it) { + if ((*it).valid()) { + if ((*it)->is_media_application()) { + if (kTTSSessionChanging == changing_state) { + (*it)->set_tts_speak_state(true); + } + if ((*it)->audio_streaming_state() != state && + (mobile_api::HMILevel::HMI_NONE != (*it)->hmi_level()) && + (mobile_api::HMILevel::HMI_BACKGROUND != (*it)->hmi_level())) { + (*it)->set_audio_streaming_state(state); + MessageHelper::SendHMIStatusNotification(*(*it)); + } + } + } + } +} + +void ApplicationManagerImpl::Unmute(VRTTSSessionChanging changing_state) { + + ApplicationManagerImpl::ApplicationListAccessor accessor; + ApplicationManagerImpl::TAppList local_app_list = application_list_; + ApplicationManagerImpl::TAppListConstIt it = local_app_list.begin(); + ApplicationManagerImpl::TAppListConstIt itEnd = local_app_list.end(); + + for (; it != itEnd; ++it) { + if ((*it).valid()) { + if ((*it)->is_media_application()) { + if (kTTSSessionChanging == changing_state) { + (*it)->set_tts_speak_state(false); + } + if ((!(vr_session_started())) && + (!((*it)->tts_speak_state())) && + ((*it)->audio_streaming_state() != + mobile_apis::AudioStreamingState::AUDIBLE) && + (mobile_api::HMILevel::HMI_NONE != (*it)->hmi_level()) && + (mobile_api::HMILevel::HMI_BACKGROUND != (*it)->hmi_level())) { + (*it)->set_audio_streaming_state( + mobile_apis::AudioStreamingState::AUDIBLE); + MessageHelper::SendHMIStatusNotification(*(*it)); + } + } + } + } +} + +mobile_apis::Result::eType ApplicationManagerImpl::SaveBinary( + const std::vector<uint8_t>& binary_data, const std::string& file_path, + const std::string& file_name, const int64_t offset) { + LOG4CXX_INFO(logger_, + "SaveBinaryWithOffset binary_size = " << binary_data.size() + << " offset = " << offset); + + if (binary_data.size() > file_system::GetAvailableDiskSpace(file_path)) { + LOG4CXX_ERROR(logger_, "Out of free disc space."); + return mobile_apis::Result::OUT_OF_MEMORY; + } + + const std::string full_file_path = file_path + "/" + file_name; + int64_t file_size = file_system::FileSize(full_file_path); + std::ofstream* file_stream; + if (offset != 0) { + if (file_size != offset) { + LOG4CXX_INFO(logger_, + "ApplicationManagerImpl::SaveBinaryWithOffset offset" + << " does'n match existing file size"); + return mobile_apis::Result::INVALID_DATA; + } + file_stream = file_system::Open(full_file_path, std::ios_base::app); + } else { + LOG4CXX_INFO( + logger_, + "ApplicationManagerImpl::SaveBinaryWithOffset offset is 0, rewrite"); + // if offset == 0: rewrite file + file_stream = file_system::Open(full_file_path, std::ios_base::out); + } + + if (!file_system::Write(file_stream, binary_data.data(), + binary_data.size())) { + file_system::Close(file_stream); + return mobile_apis::Result::GENERIC_ERROR; + } + + file_system::Close(file_stream); + LOG4CXX_INFO(logger_, "Successfully write data to file"); + return mobile_apis::Result::SUCCESS; +} + +uint32_t ApplicationManagerImpl::GetAvailableSpaceForApp( + const std::string& folder_name) { + const uint32_t app_quota = profile::Profile::instance()->app_dir_quota(); + std::string app_storage_path = + profile::Profile::instance()->app_storage_folder(); + + app_storage_path += "/"; + app_storage_path += folder_name; + + if (file_system::DirectoryExists(app_storage_path)) { + size_t size_of_directory = file_system::DirectorySize(app_storage_path); + if (app_quota < size_of_directory) { + return 0; + } + + uint32_t current_app_quota = app_quota - size_of_directory; + uint32_t available_disk_space = + file_system::GetAvailableDiskSpace(app_storage_path); + + if (current_app_quota > available_disk_space) { + return available_disk_space; + } else { + return current_app_quota; + } + } else { + return app_quota; + } +} + +bool ApplicationManagerImpl::IsHMICooperating() const { + return hmi_cooperating_; +} + +void ApplicationManagerImpl::OnApplicationListUpdateTimer() { + LOG4CXX_DEBUG(logger_, "Application list update timer finished"); + + std::list <uint32_t> applications_ids; + + applications_list_lock_.Acquire(); + for (std::set<ApplicationSharedPtr>::const_iterator i = application_list_.begin(); + i != application_list_.end(); ++i) { + ApplicationSharedPtr application = *i; + uint32_t app_id = application->app_id(); + applications_ids.push_back(app_id); + } + applications_list_lock_.Release(); + + SendUpdateAppList(applications_ids); +} + +void ApplicationManagerImpl::OnTimerSendTTSGlobalProperties() { + std::vector<uint32_t> app_list; + { + sync_primitives::AutoLock lock(tts_global_properties_app_list_lock_); + std::map<uint32_t, TimevalStruct>::iterator it = + tts_global_properties_app_list_.begin(); + std::map<uint32_t, TimevalStruct>::iterator it_end = + tts_global_properties_app_list_.end(); + date_time::TimeCompare time_comp; + for (; it != it_end; ++it) { + time_comp = date_time::DateTime::compareTime( + date_time::DateTime::getCurrentTime(), it->second); + if (date_time::GREATER == time_comp || date_time::EQUAL == time_comp) { + app_list.push_back(it->first); + } + } + } + if (!app_list.empty()) { + for (uint32_t i = 0; i < app_list.size(); ++i) { + LOG4CXX_INFO(logger_, "Send TTS GlobalProperties to HMI with default helpPrompt"); + MessageHelper::SendTTSGlobalProperties(application(app_list[i]), true); + RemoveAppFromTTSGlobalPropertiesList(app_list[i]); + } + } +} + +void ApplicationManagerImpl::AddAppToTTSGlobalPropertiesList( + const uint32_t app_id) { + LOG4CXX_INFO(logger_, "ApplicationManagerImpl::AddAppToTTSGlobalPropertiesList"); + uint16_t timeout = profile::Profile::instance()->tts_global_properties_timeout(); + TimevalStruct current_time = date_time::DateTime::getCurrentTime(); + current_time.tv_sec += timeout; + sync_primitives::AutoLock lock(tts_global_properties_app_list_lock_); + if (tts_global_properties_app_list_.end() == + tts_global_properties_app_list_.find(app_id)) { + tts_global_properties_app_list_[app_id] = current_time; + } + //if add first item need to start timer on one second + if (1 == tts_global_properties_app_list_.size()) { + LOG4CXX_INFO(logger_, "Start tts_global_properties_timer_"); + tts_global_properties_timer_.start(1); + } +} + +void ApplicationManagerImpl::RemoveAppFromTTSGlobalPropertiesList( + const uint32_t app_id) { + LOG4CXX_INFO(logger_, "ApplicationManagerImpl::RemoveAppFromTTSGlobalPropertiesList"); + sync_primitives::AutoLock lock(tts_global_properties_app_list_lock_); + std::map<uint32_t, TimevalStruct>::iterator it = + tts_global_properties_app_list_.find(app_id); + if (tts_global_properties_app_list_.end() != it) { + tts_global_properties_app_list_.erase(it); + if (!(tts_global_properties_app_list_.size())) { + LOG4CXX_INFO(logger_, "Stop tts_global_properties_timer_"); + //if container is empty need to stop timer + tts_global_properties_timer_.stop(); + } + } +} + +} // namespace application_manager |