summaryrefslogtreecommitdiff
path: root/src/components/application_manager/src/rpc_handler_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/application_manager/src/rpc_handler_impl.cc')
-rw-r--r--src/components/application_manager/src/rpc_handler_impl.cc427
1 files changed, 427 insertions, 0 deletions
diff --git a/src/components/application_manager/src/rpc_handler_impl.cc b/src/components/application_manager/src/rpc_handler_impl.cc
new file mode 100644
index 0000000000..939b3d1ce6
--- /dev/null
+++ b/src/components/application_manager/src/rpc_handler_impl.cc
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 2018, 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 "application_manager/rpc_handler_impl.h"
+
+namespace application_manager {
+namespace rpc_handler {
+
+CREATE_LOGGERPTR_LOCAL(logger_, "RPCHandlerImpl")
+namespace formatters = ns_smart_device_link::ns_json_handler::formatters;
+namespace jhs = ns_smart_device_link::ns_json_handler::strings;
+
+RPCHandlerImpl::RPCHandlerImpl(ApplicationManager& app_manager)
+ : app_manager_(app_manager)
+ , messages_from_mobile_("AM FromMobile", this)
+ , messages_from_hmi_("AM FromHMI", this)
+ , hmi_so_factory_(hmi_apis::HMI_API())
+ , mobile_so_factory_(mobile_apis::MOBILE_API())
+#ifdef TELEMETRY_MONITOR
+ , metric_observer_(NULL)
+#endif // TELEMETRY_MONITOR
+{
+}
+
+RPCHandlerImpl::~RPCHandlerImpl() {}
+
+void RPCHandlerImpl::ProcessMessageFromMobile(
+ const std::shared_ptr<Message> message) {
+ LOG4CXX_AUTO_TRACE(logger_);
+#ifdef TELEMETRY_MONITOR
+ AMTelemetryObserver::MessageMetricSharedPtr metric(
+ new AMTelemetryObserver::MessageMetric());
+ metric->begin = date_time::getCurrentTime();
+#endif // TELEMETRY_MONITOR
+ smart_objects::SmartObjectSPtr so_from_mobile =
+ std::make_shared<smart_objects::SmartObject>();
+
+ DCHECK_OR_RETURN_VOID(so_from_mobile);
+ 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 TELEMETRY_MONITOR
+ metric->message = so_from_mobile;
+#endif // TELEMETRY_MONITOR
+
+ if (!app_manager_.GetRPCService().ManageMobileCommand(
+ so_from_mobile, commands::Command::SOURCE_MOBILE)) {
+ LOG4CXX_ERROR(logger_, "Received command didn't run successfully");
+ }
+#ifdef TELEMETRY_MONITOR
+ metric->end = date_time::getCurrentTime();
+ if (metric_observer_) {
+ metric_observer_->OnMessage(metric);
+ }
+#endif // TELEMETRY_MONITOR
+}
+
+void RPCHandlerImpl::ProcessMessageFromHMI(
+ const std::shared_ptr<Message> message) {
+ LOG4CXX_AUTO_TRACE(logger_);
+ smart_objects::SmartObjectSPtr smart_object =
+ std::make_shared<smart_objects::SmartObject>();
+
+ if (!smart_object) {
+ LOG4CXX_ERROR(logger_, "Null pointer");
+ return;
+ }
+
+ if (!ConvertMessageToSO(*message, *smart_object)) {
+ if (application_manager::MessageType::kResponse ==
+ (*smart_object)[strings::params][strings::message_type].asInt()) {
+ (*smart_object).erase(strings::msg_params);
+ (*smart_object)[strings::params][hmi_response::code] =
+ hmi_apis::Common_Result::GENERIC_ERROR;
+ (*smart_object)[strings::msg_params][strings::info] =
+ std::string("Invalid message received from vehicle");
+ } else {
+ LOG4CXX_ERROR(logger_, "Cannot create smart object from message");
+ return;
+ }
+ }
+
+ LOG4CXX_DEBUG(logger_, "Converted message, trying to create hmi command");
+ if (!app_manager_.GetRPCService().ManageHMICommand(smart_object)) {
+ LOG4CXX_ERROR(logger_, "Received command didn't run successfully");
+ }
+}
+void RPCHandlerImpl::Handle(const impl::MessageFromMobile message) {
+ LOG4CXX_AUTO_TRACE(logger_);
+
+ if (!message) {
+ LOG4CXX_ERROR(logger_, "Null-pointer message received.");
+ return;
+ }
+ if (app_manager_.is_stopping()) {
+ LOG4CXX_INFO(logger_, "Application manager is stopping");
+ return;
+ }
+
+ ProcessMessageFromMobile(message);
+}
+
+void RPCHandlerImpl::Handle(const impl::MessageFromHmi message) {
+ LOG4CXX_AUTO_TRACE(logger_);
+
+ if (!message) {
+ LOG4CXX_ERROR(logger_, "Null-pointer message received.");
+ return;
+ }
+ ProcessMessageFromHMI(message);
+}
+
+void RPCHandlerImpl::OnMessageReceived(
+ const protocol_handler::RawMessagePtr message) {
+ LOG4CXX_AUTO_TRACE(logger_);
+
+ if (!message) {
+ LOG4CXX_ERROR(logger_, "Null-pointer message received.");
+ NOTREACHED();
+ return;
+ }
+
+ std::shared_ptr<Message> outgoing_message = ConvertRawMsgToMessage(message);
+
+ if (outgoing_message) {
+ LOG4CXX_DEBUG(logger_, "Posting new Message");
+ messages_from_mobile_.PostMessage(
+ impl::MessageFromMobile(outgoing_message));
+ }
+}
+
+void RPCHandlerImpl::OnMobileMessageSent(
+ const protocol_handler::RawMessagePtr message) {
+ LOG4CXX_AUTO_TRACE(logger_);
+}
+
+void RPCHandlerImpl::OnMessageReceived(
+ hmi_message_handler::MessageSharedPointer message) {
+ LOG4CXX_AUTO_TRACE(logger_);
+
+ if (!message) {
+ LOG4CXX_ERROR(logger_, "Null-pointer message received.");
+ NOTREACHED();
+ return;
+ }
+
+ messages_from_hmi_.PostMessage(impl::MessageFromHmi(message));
+}
+
+void RPCHandlerImpl::OnErrorSending(
+ hmi_message_handler::MessageSharedPointer message) {
+ return;
+}
+
+#ifdef TELEMETRY_MONITOR
+void RPCHandlerImpl::SetTelemetryObserver(AMTelemetryObserver* observer) {
+ metric_observer_ = observer;
+}
+
+#endif // TELEMETRY_MONITOR
+
+void RPCHandlerImpl::GetMessageVersion(
+ ns_smart_device_link::ns_smart_objects::SmartObject& output,
+ utils::SemanticVersion& message_version) {
+ if (output.keyExists(
+ ns_smart_device_link::ns_json_handler::strings::S_MSG_PARAMS) &&
+ output[ns_smart_device_link::ns_json_handler::strings::S_MSG_PARAMS]
+ .keyExists(strings::sync_msg_version)) {
+ // SyncMsgVersion exists, check if it is valid.
+ auto sync_msg_version =
+ output[ns_smart_device_link::ns_json_handler::strings::S_MSG_PARAMS]
+ [strings::sync_msg_version];
+ uint16_t major = 0;
+ uint16_t minor = 0;
+ uint16_t patch = 0;
+ if (sync_msg_version.keyExists(strings::major_version)) {
+ major = sync_msg_version[strings::major_version].asUInt();
+ }
+ if (sync_msg_version.keyExists(strings::minor_version)) {
+ minor = sync_msg_version[strings::minor_version].asUInt();
+ }
+ if (sync_msg_version.keyExists(strings::patch_version)) {
+ patch = sync_msg_version[strings::patch_version].asUInt();
+ }
+ utils::SemanticVersion temp_version(major, minor, patch);
+ if (temp_version.isValid()) {
+ message_version = (temp_version >= utils::rpc_version_5)
+ ? temp_version
+ : utils::base_rpc_version;
+ }
+ }
+}
+
+bool RPCHandlerImpl::ConvertMessageToSO(
+ const Message& message,
+ ns_smart_device_link::ns_smart_objects::SmartObject& output) {
+ LOG4CXX_AUTO_TRACE(logger_);
+ LOG4CXX_DEBUG(logger_,
+ "\t\t\tMessage to convert: protocol "
+ << message.protocol_version() << "; json "
+ << message.json_message());
+
+ switch (message.protocol_version()) {
+ case protocol_handler::MajorProtocolVersion::PROTOCOL_VERSION_5:
+ case protocol_handler::MajorProtocolVersion::PROTOCOL_VERSION_4:
+ case protocol_handler::MajorProtocolVersion::PROTOCOL_VERSION_3:
+ case protocol_handler::MajorProtocolVersion::PROTOCOL_VERSION_2: {
+ const bool conversion_result =
+ formatters::CFormatterJsonSDLRPCv2::fromString(
+ message.json_message(),
+ output,
+ message.function_id(),
+ message.type(),
+ message.correlation_id());
+
+ rpc::ValidationReport report("RPC");
+
+ // Attach RPC version to SmartObject if it does not exist yet.
+ auto app_ptr = app_manager_.application(message.connection_key());
+ utils::SemanticVersion msg_version(0, 0, 0);
+ if (app_ptr) {
+ msg_version = app_ptr->msg_version();
+ } else if (mobile_apis::FunctionID::RegisterAppInterfaceID ==
+ static_cast<mobile_apis::FunctionID::eType>(
+ output[strings::params][strings::function_id].asInt())) {
+ GetMessageVersion(output, msg_version);
+ }
+
+ if (!conversion_result ||
+ !mobile_so_factory().attachSchema(output, true, msg_version) ||
+ ((output.validate(&report, msg_version) !=
+ smart_objects::errors::OK))) {
+ LOG4CXX_WARN(logger_,
+ "Failed to parse string to smart object with API version "
+ << msg_version.toString() << " : "
+ << message.json_message());
+ std::shared_ptr<smart_objects::SmartObject> response(
+ MessageHelper::CreateNegativeResponse(
+ message.connection_key(),
+ message.function_id(),
+ message.correlation_id(),
+ mobile_apis::Result::INVALID_DATA));
+
+ (*response)[strings::msg_params][strings::info] =
+ rpc::PrettyFormat(report);
+ app_manager_.GetRPCService().ManageMobileCommand(
+ response, commands::Command::SOURCE_SDL);
+ return false;
+ }
+ LOG4CXX_DEBUG(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());
+ std::shared_ptr<smart_objects::SmartObject> response(
+ MessageHelper::CreateNegativeResponse(
+ message.connection_key(),
+ message.function_id(),
+ message.correlation_id(),
+ mobile_apis::Result::INVALID_DATA));
+ app_manager_.GetRPCService().ManageMobileCommand(
+ response, commands::Command::SOURCE_SDL);
+ return false;
+ }
+ output[strings::params][strings::binary_data] =
+ *(message.binary_data());
+ }
+ break;
+ }
+ case protocol_handler::MajorProtocolVersion::PROTOCOL_VERSION_HMI: {
+#ifdef ENABLE_LOG
+ int32_t result =
+#endif
+ formatters::FormatterJsonRpc::FromString<
+ hmi_apis::FunctionID::eType,
+ hmi_apis::messageType::eType>(message.json_message(), output);
+ LOG4CXX_DEBUG(logger_,
+ "Convertion result: "
+ << result << " function id "
+ << output[jhs::S_PARAMS][jhs::S_FUNCTION_ID].asInt());
+ if (!hmi_so_factory().attachSchema(output, false)) {
+ LOG4CXX_WARN(logger_, "Failed to attach schema to object.");
+ return false;
+ }
+
+ rpc::ValidationReport report("RPC");
+
+ if (output.validate(&report) != smart_objects::errors::OK) {
+ LOG4CXX_ERROR(logger_,
+ "Incorrect parameter from HMI"
+ << rpc::PrettyFormat(report));
+
+ output.erase(strings::msg_params);
+ output[strings::params][hmi_response::code] =
+ hmi_apis::Common_Result::INVALID_DATA;
+ output[strings::msg_params][strings::info] = rpc::PrettyFormat(report);
+ return false;
+ }
+ break;
+ }
+ case protocol_handler::MajorProtocolVersion::PROTOCOL_VERSION_1: {
+ static ns_smart_device_link_rpc::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<
+ ns_smart_device_link_rpc::V1::FunctionID::eType,
+ ns_smart_device_link_rpc::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] =
+ ns_smart_device_link_rpc::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] =
+ ns_smart_device_link_rpc::V1::Result::UNSUPPORTED_VERSION;
+
+ smart_objects::SmartObjectSPtr msg_to_send =
+ std::make_shared<smart_objects::SmartObject>(output);
+ v1_shema.attachSchema(*msg_to_send, false);
+ app_manager_.GetRPCService().SendMessageToMobile(msg_to_send);
+ return false;
+ }
+ }
+ break;
+ }
+ default:
+ LOG4CXX_WARN(logger_,
+ "Application used unsupported protocol :"
+ << message.protocol_version() << ".");
+ return false;
+ }
+
+ LOG4CXX_DEBUG(logger_, "Successfully parsed message into smart object");
+ return true;
+}
+
+std::shared_ptr<Message> RPCHandlerImpl::ConvertRawMsgToMessage(
+ const protocol_handler::RawMessagePtr message) {
+ LOG4CXX_AUTO_TRACE(logger_);
+ DCHECK(message);
+ std::shared_ptr<Message> outgoing_message;
+
+ LOG4CXX_DEBUG(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 =
+ MobileMessageHandler::HandleIncomingMessageProtocol(message);
+
+ if (convertion_result) {
+ outgoing_message = std::shared_ptr<Message>(convertion_result);
+ } else {
+ LOG4CXX_ERROR(logger_, "Received invalid message");
+ }
+ return outgoing_message;
+}
+
+hmi_apis::HMI_API& RPCHandlerImpl::hmi_so_factory() {
+ return hmi_so_factory_;
+}
+
+mobile_apis::MOBILE_API& RPCHandlerImpl::mobile_so_factory() {
+ return mobile_so_factory_;
+}
+}
+}