1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16#define LOG_TAG "VehicleEmulator_v2_0" 17#include <android/log.h> 18 19#include <algorithm> 20#include <android-base/properties.h> 21#include <utils/SystemClock.h> 22 23#include <vhal_v2_0/VehicleUtils.h> 24 25#include "PipeComm.h" 26#include "SocketComm.h" 27 28#include "VehicleEmulator.h" 29 30namespace android { 31namespace hardware { 32namespace automotive { 33namespace vehicle { 34namespace V2_0 { 35 36namespace impl { 37 38std::unique_ptr<CommBase> CommFactory::create() { 39 bool isEmulator = android::base::GetBoolProperty("ro.kernel.qemu", false); 40 41 if (isEmulator) { 42 return std::make_unique<PipeComm>(); 43 } else { 44 return std::make_unique<SocketComm>(); 45 } 46} 47 48VehicleEmulator::~VehicleEmulator() { 49 mExit = true; // Notify thread to finish and wait for it to terminate. 50 mComm->stop(); // Close emulator socket if it is open. 51 if (mThread.joinable()) mThread.join(); 52} 53 54void VehicleEmulator::doSetValueFromClient(const VehiclePropValue& propValue) { 55 emulator::EmulatorMessage msg; 56 emulator::VehiclePropValue *val = msg.add_value(); 57 populateProtoVehiclePropValue(val, &propValue); 58 msg.set_status(emulator::RESULT_OK); 59 msg.set_msg_type(emulator::SET_PROPERTY_ASYNC); 60 txMsg(msg); 61} 62 63void VehicleEmulator::doGetConfig(VehicleEmulator::EmulatorMessage& rxMsg, 64 VehicleEmulator::EmulatorMessage& respMsg) { 65 std::vector<VehiclePropConfig> configs = mHal->listProperties(); 66 emulator::VehiclePropGet getProp = rxMsg.prop(0); 67 68 respMsg.set_msg_type(emulator::GET_CONFIG_RESP); 69 respMsg.set_status(emulator::ERROR_INVALID_PROPERTY); 70 71 for (auto& config : configs) { 72 // Find the config we are looking for 73 if (config.prop == getProp.prop()) { 74 emulator::VehiclePropConfig* protoCfg = respMsg.add_config(); 75 populateProtoVehicleConfig(protoCfg, config); 76 respMsg.set_status(emulator::RESULT_OK); 77 break; 78 } 79 } 80} 81 82void VehicleEmulator::doGetConfigAll(VehicleEmulator::EmulatorMessage& /* rxMsg */, 83 VehicleEmulator::EmulatorMessage& respMsg) { 84 std::vector<VehiclePropConfig> configs = mHal->listProperties(); 85 86 respMsg.set_msg_type(emulator::GET_CONFIG_ALL_RESP); 87 respMsg.set_status(emulator::RESULT_OK); 88 89 for (auto& config : configs) { 90 emulator::VehiclePropConfig* protoCfg = respMsg.add_config(); 91 populateProtoVehicleConfig(protoCfg, config); 92 } 93} 94 95void VehicleEmulator::doGetProperty(VehicleEmulator::EmulatorMessage& rxMsg, 96 VehicleEmulator::EmulatorMessage& respMsg) { 97 int32_t areaId = 0; 98 emulator::VehiclePropGet getProp = rxMsg.prop(0); 99 int32_t propId = getProp.prop(); 100 emulator::Status status = emulator::ERROR_INVALID_PROPERTY; 101 102 respMsg.set_msg_type(emulator::GET_PROPERTY_RESP); 103 104 if (getProp.has_area_id()) { 105 areaId = getProp.area_id(); 106 } 107 108 { 109 VehiclePropValue request = { .prop = propId, .areaId = areaId }; 110 StatusCode halStatus; 111 auto val = mHal->get(request, &halStatus); 112 if (val != nullptr) { 113 emulator::VehiclePropValue* protoVal = respMsg.add_value(); 114 populateProtoVehiclePropValue(protoVal, val.get()); 115 status = emulator::RESULT_OK; 116 } 117 } 118 119 respMsg.set_status(status); 120} 121 122void VehicleEmulator::doGetPropertyAll(VehicleEmulator::EmulatorMessage& /* rxMsg */, 123 VehicleEmulator::EmulatorMessage& respMsg) { 124 respMsg.set_msg_type(emulator::GET_PROPERTY_ALL_RESP); 125 respMsg.set_status(emulator::RESULT_OK); 126 127 { 128 for (const auto& prop : mHal->getAllProperties()) { 129 emulator::VehiclePropValue* protoVal = respMsg.add_value(); 130 populateProtoVehiclePropValue(protoVal, &prop); 131 } 132 } 133} 134 135void VehicleEmulator::doSetProperty(VehicleEmulator::EmulatorMessage& rxMsg, 136 VehicleEmulator::EmulatorMessage& respMsg) { 137 emulator::VehiclePropValue protoVal = rxMsg.value(0); 138 VehiclePropValue val = { 139 .prop = protoVal.prop(), 140 .areaId = protoVal.area_id(), 141 .status = (VehiclePropertyStatus)protoVal.status(), 142 .timestamp = elapsedRealtimeNano(), 143 }; 144 145 respMsg.set_msg_type(emulator::SET_PROPERTY_RESP); 146 147 // Copy value data if it is set. This automatically handles complex data types if needed. 148 if (protoVal.has_string_value()) { 149 val.value.stringValue = protoVal.string_value().c_str(); 150 } 151 152 if (protoVal.has_bytes_value()) { 153 val.value.bytes = std::vector<uint8_t> { protoVal.bytes_value().begin(), 154 protoVal.bytes_value().end() }; 155 } 156 157 if (protoVal.int32_values_size() > 0) { 158 val.value.int32Values = std::vector<int32_t> { protoVal.int32_values().begin(), 159 protoVal.int32_values().end() }; 160 } 161 162 if (protoVal.int64_values_size() > 0) { 163 val.value.int64Values = std::vector<int64_t> { protoVal.int64_values().begin(), 164 protoVal.int64_values().end() }; 165 } 166 167 if (protoVal.float_values_size() > 0) { 168 val.value.floatValues = std::vector<float> { protoVal.float_values().begin(), 169 protoVal.float_values().end() }; 170 } 171 172 bool halRes = mHal->setPropertyFromVehicle(val); 173 respMsg.set_status(halRes ? emulator::RESULT_OK : emulator::ERROR_INVALID_PROPERTY); 174} 175 176void VehicleEmulator::txMsg(emulator::EmulatorMessage& txMsg) { 177 int numBytes = txMsg.ByteSize(); 178 std::vector<uint8_t> msg(static_cast<size_t>(numBytes)); 179 180 if (!txMsg.SerializeToArray(msg.data(), static_cast<int32_t>(msg.size()))) { 181 ALOGE("%s: SerializeToString failed!", __func__); 182 return; 183 } 184 185 if (mExit) { 186 ALOGW("%s: unable to transmit a message, connection closed", __func__); 187 return; 188 } 189 190 // Send the message 191 int retVal = mComm->write(msg); 192 if (retVal < 0) { 193 ALOGE("%s: Failed to tx message: retval=%d, errno=%d", __func__, retVal, errno); 194 } 195} 196 197void VehicleEmulator::parseRxProtoBuf(std::vector<uint8_t>& msg) { 198 emulator::EmulatorMessage rxMsg; 199 emulator::EmulatorMessage respMsg; 200 201 if (rxMsg.ParseFromArray(msg.data(), static_cast<int32_t>(msg.size()))) { 202 switch (rxMsg.msg_type()) { 203 case emulator::GET_CONFIG_CMD: 204 doGetConfig(rxMsg, respMsg); 205 break; 206 case emulator::GET_CONFIG_ALL_CMD: 207 doGetConfigAll(rxMsg, respMsg); 208 break; 209 case emulator::GET_PROPERTY_CMD: 210 doGetProperty(rxMsg, respMsg); 211 break; 212 case emulator::GET_PROPERTY_ALL_CMD: 213 doGetPropertyAll(rxMsg, respMsg); 214 break; 215 case emulator::SET_PROPERTY_CMD: 216 doSetProperty(rxMsg, respMsg); 217 break; 218 default: 219 ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type()); 220 respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD); 221 break; 222 } 223 224 // Send the reply 225 txMsg(respMsg); 226 } else { 227 ALOGE("%s: ParseFromString() failed. msgSize=%d", __func__, static_cast<int>(msg.size())); 228 } 229} 230 231void VehicleEmulator::populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg, 232 const VehiclePropConfig& cfg) { 233 protoCfg->set_prop(cfg.prop); 234 protoCfg->set_access(toInt(cfg.access)); 235 protoCfg->set_change_mode(toInt(cfg.changeMode)); 236 protoCfg->set_value_type(toInt(getPropType(cfg.prop))); 237 238 for (auto& configElement : cfg.configArray) { 239 protoCfg->add_config_array(configElement); 240 } 241 242 if (cfg.configString.size() > 0) { 243 protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size()); 244 } 245 246 // Populate the min/max values based on property type 247 switch (getPropType(cfg.prop)) { 248 case VehiclePropertyType::STRING: 249 case VehiclePropertyType::BOOLEAN: 250 case VehiclePropertyType::INT32_VEC: 251 case VehiclePropertyType::INT64_VEC: 252 case VehiclePropertyType::FLOAT_VEC: 253 case VehiclePropertyType::BYTES: 254 case VehiclePropertyType::MIXED: 255 // Do nothing. These types don't have min/max values 256 break; 257 case VehiclePropertyType::INT64: 258 if (cfg.areaConfigs.size() > 0) { 259 emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs(); 260 aCfg->set_min_int64_value(cfg.areaConfigs[0].minInt64Value); 261 aCfg->set_max_int64_value(cfg.areaConfigs[0].maxInt64Value); 262 } 263 break; 264 case VehiclePropertyType::FLOAT: 265 if (cfg.areaConfigs.size() > 0) { 266 emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs(); 267 aCfg->set_min_float_value(cfg.areaConfigs[0].minFloatValue); 268 aCfg->set_max_float_value(cfg.areaConfigs[0].maxFloatValue); 269 } 270 break; 271 case VehiclePropertyType::INT32: 272 if (cfg.areaConfigs.size() > 0) { 273 emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs(); 274 aCfg->set_min_int32_value(cfg.areaConfigs[0].minInt32Value); 275 aCfg->set_max_int32_value(cfg.areaConfigs[0].maxInt32Value); 276 } 277 break; 278 default: 279 ALOGW("%s: Unknown property type: 0x%x", __func__, toInt(getPropType(cfg.prop))); 280 break; 281 } 282 283 protoCfg->set_min_sample_rate(cfg.minSampleRate); 284 protoCfg->set_max_sample_rate(cfg.maxSampleRate); 285} 286 287void VehicleEmulator::populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal, 288 const VehiclePropValue* val) { 289 protoVal->set_prop(val->prop); 290 protoVal->set_value_type(toInt(getPropType(val->prop))); 291 protoVal->set_timestamp(val->timestamp); 292 protoVal->set_status((emulator::VehiclePropStatus)(val->status)); 293 protoVal->set_area_id(val->areaId); 294 295 // Copy value data if it is set. 296 // - for bytes and strings, this is indicated by size > 0 297 // - for int32, int64, and float, copy the values if vectors have data 298 if (val->value.stringValue.size() > 0) { 299 protoVal->set_string_value(val->value.stringValue.c_str(), val->value.stringValue.size()); 300 } 301 302 if (val->value.bytes.size() > 0) { 303 protoVal->set_bytes_value(val->value.bytes.data(), val->value.bytes.size()); 304 } 305 306 for (auto& int32Value : val->value.int32Values) { 307 protoVal->add_int32_values(int32Value); 308 } 309 310 for (auto& int64Value : val->value.int64Values) { 311 protoVal->add_int64_values(int64Value); 312 } 313 314 for (auto& floatValue : val->value.floatValues) { 315 protoVal->add_float_values(floatValue); 316 } 317} 318 319void VehicleEmulator::rxMsg() { 320 while (!mExit) { 321 std::vector<uint8_t> msg = mComm->read(); 322 323 if (msg.size() > 0) { 324 // Received a message. 325 parseRxProtoBuf(msg); 326 } else { 327 // This happens when connection is closed 328 ALOGD("%s: msgSize=%zu", __func__, msg.size()); 329 break; 330 } 331 } 332} 333 334void VehicleEmulator::rxThread() { 335 if (mExit) return; 336 337 int retVal = mComm->open(); 338 if (retVal != 0) mExit = true; 339 340 // Comms are properly opened 341 while (!mExit) { 342 retVal = mComm->connect(); 343 344 if (retVal >= 0) { 345 rxMsg(); 346 } 347 348 // Check every 100ms for a new connection 349 std::this_thread::sleep_for(std::chrono::milliseconds(100)); 350 } 351} 352 353} // impl 354 355} // namespace V2_0 356} // namespace vehicle 357} // namespace automotive 358} // namespace hardware 359} // namespace android 360