/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "VehicleEmulator_v2_0" #include #include #include #include #include #include #include #include "PipeComm.h" #include "SocketComm.h" #include "VehicleEmulator.h" namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace V2_0 { namespace impl { VehicleEmulator::VehicleEmulator(EmulatedServerIface* hal) : mHal{hal} { mHal->registerEmulator(this); ALOGI("Starting SocketComm"); mSocketComm = std::make_unique(this); mSocketComm->start(); if (isInQEMU()) { ALOGI("Starting PipeComm"); mPipeComm = std::make_unique(this); mPipeComm->start(); } } VehicleEmulator::~VehicleEmulator() { mSocketComm->stop(); if (mPipeComm) { mPipeComm->stop(); } } /** * This is called by the HAL when a property changes. We need to notify our clients that it has * changed. */ void VehicleEmulator::doSetValueFromClient(const VehiclePropValue& propValue) { vhal_proto::EmulatorMessage msg; vhal_proto::VehiclePropValue* val = msg.add_value(); populateProtoVehiclePropValue(val, &propValue); msg.set_status(vhal_proto::RESULT_OK); msg.set_msg_type(vhal_proto::SET_PROPERTY_ASYNC); mSocketComm->sendMessage(msg); if (mPipeComm) { mPipeComm->sendMessage(msg); } } void VehicleEmulator::doGetConfig(const VehicleEmulator::EmulatorMessage& rxMsg, VehicleEmulator::EmulatorMessage* respMsg) { std::vector configs = mHal->listProperties(); vhal_proto::VehiclePropGet getProp = rxMsg.prop(0); respMsg->set_msg_type(vhal_proto::GET_CONFIG_RESP); respMsg->set_status(vhal_proto::ERROR_INVALID_PROPERTY); for (auto& config : configs) { // Find the config we are looking for if (config.prop == getProp.prop()) { vhal_proto::VehiclePropConfig* protoCfg = respMsg->add_config(); populateProtoVehicleConfig(protoCfg, config); respMsg->set_status(vhal_proto::RESULT_OK); break; } } } void VehicleEmulator::doGetConfigAll(const VehicleEmulator::EmulatorMessage& /* rxMsg */, VehicleEmulator::EmulatorMessage* respMsg) { std::vector configs = mHal->listProperties(); respMsg->set_msg_type(vhal_proto::GET_CONFIG_ALL_RESP); respMsg->set_status(vhal_proto::RESULT_OK); for (auto& config : configs) { vhal_proto::VehiclePropConfig* protoCfg = respMsg->add_config(); populateProtoVehicleConfig(protoCfg, config); } } void VehicleEmulator::doGetProperty(const VehicleEmulator::EmulatorMessage& rxMsg, VehicleEmulator::EmulatorMessage* respMsg) { int32_t areaId = 0; vhal_proto::VehiclePropGet getProp = rxMsg.prop(0); int32_t propId = getProp.prop(); vhal_proto::Status status = vhal_proto::ERROR_INVALID_PROPERTY; respMsg->set_msg_type(vhal_proto::GET_PROPERTY_RESP); if (getProp.has_area_id()) { areaId = getProp.area_id(); } { VehiclePropValue request = { .areaId = areaId, .prop = propId, }; StatusCode halStatus; auto val = mHal->get(request, &halStatus); if (val != nullptr) { vhal_proto::VehiclePropValue* protoVal = respMsg->add_value(); populateProtoVehiclePropValue(protoVal, val.get()); status = vhal_proto::RESULT_OK; } } respMsg->set_status(status); } void VehicleEmulator::doGetPropertyAll(const VehicleEmulator::EmulatorMessage& /* rxMsg */, VehicleEmulator::EmulatorMessage* respMsg) { respMsg->set_msg_type(vhal_proto::GET_PROPERTY_ALL_RESP); respMsg->set_status(vhal_proto::RESULT_OK); { for (const auto& prop : mHal->getAllProperties()) { vhal_proto::VehiclePropValue* protoVal = respMsg->add_value(); populateProtoVehiclePropValue(protoVal, &prop); } } } void VehicleEmulator::doSetProperty(const VehicleEmulator::EmulatorMessage& rxMsg, VehicleEmulator::EmulatorMessage* respMsg) { vhal_proto::VehiclePropValue protoVal = rxMsg.value(0); VehiclePropValue val = { .timestamp = elapsedRealtimeNano(), .areaId = protoVal.area_id(), .prop = protoVal.prop(), .status = (VehiclePropertyStatus)protoVal.status(), }; respMsg->set_msg_type(vhal_proto::SET_PROPERTY_RESP); // Copy value data if it is set. This automatically handles complex data types if needed. if (protoVal.has_string_value()) { val.value.stringValue = protoVal.string_value().c_str(); } if (protoVal.has_bytes_value()) { val.value.bytes = std::vector { protoVal.bytes_value().begin(), protoVal.bytes_value().end() }; } if (protoVal.int32_values_size() > 0) { val.value.int32Values = std::vector { protoVal.int32_values().begin(), protoVal.int32_values().end() }; } if (protoVal.int64_values_size() > 0) { val.value.int64Values = std::vector { protoVal.int64_values().begin(), protoVal.int64_values().end() }; } if (protoVal.float_values_size() > 0) { val.value.floatValues = std::vector { protoVal.float_values().begin(), protoVal.float_values().end() }; } bool halRes = mHal->setPropertyFromVehicle(val); respMsg->set_status(halRes ? vhal_proto::RESULT_OK : vhal_proto::ERROR_INVALID_PROPERTY); } void VehicleEmulator::doDebug(const vhal_proto::EmulatorMessage& rxMsg, vhal_proto::EmulatorMessage* respMsg) { auto protoCommands = rxMsg.debug_commands(); std::vector commands = std::vector( protoCommands.begin(), protoCommands.end()); IVehicleServer::DumpResult result = mHal->debug(commands); respMsg->set_status(vhal_proto::RESULT_OK); respMsg->set_msg_type(vhal_proto::DEBUG_RESP); respMsg->set_debug_result(result.buffer); } void VehicleEmulator::processMessage(const vhal_proto::EmulatorMessage& rxMsg, vhal_proto::EmulatorMessage* respMsg) { switch (rxMsg.msg_type()) { case vhal_proto::GET_CONFIG_CMD: doGetConfig(rxMsg, respMsg); break; case vhal_proto::GET_CONFIG_ALL_CMD: doGetConfigAll(rxMsg, respMsg); break; case vhal_proto::GET_PROPERTY_CMD: doGetProperty(rxMsg, respMsg); break; case vhal_proto::GET_PROPERTY_ALL_CMD: doGetPropertyAll(rxMsg, respMsg); break; case vhal_proto::SET_PROPERTY_CMD: doSetProperty(rxMsg, respMsg); break; case vhal_proto::DEBUG_CMD: doDebug(rxMsg, respMsg); break; default: ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type()); respMsg->set_status(vhal_proto::ERROR_UNIMPLEMENTED_CMD); break; } } void VehicleEmulator::populateProtoVehicleConfig(vhal_proto::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg) { return proto_msg_converter::toProto(protoCfg, cfg); } void VehicleEmulator::populateProtoVehiclePropValue(vhal_proto::VehiclePropValue* protoVal, const VehiclePropValue* val) { return proto_msg_converter::toProto(protoVal, *val); } bool isInQEMU() { return android::base::GetBoolProperty("ro.boot.qemu", false); } } // impl } // namespace V2_0 } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android