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 30 namespace android { 31 namespace hardware { 32 namespace automotive { 33 namespace vehicle { 34 namespace V2_0 { 35 36 namespace impl { 37 38 std::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 48 VehicleEmulator::~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 54 void 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 63 void 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 82 void 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 95 void 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 122 void 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 135 void 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 .timestamp = elapsedRealtimeNano(), 142 }; 143 144 respMsg.set_msg_type(emulator::SET_PROPERTY_RESP); 145 146 // Copy value data if it is set. This automatically handles complex data types if needed. 147 if (protoVal.has_string_value()) { 148 val.value.stringValue = protoVal.string_value().c_str(); 149 } 150 151 if (protoVal.has_bytes_value()) { 152 val.value.bytes = std::vector<uint8_t> { protoVal.bytes_value().begin(), 153 protoVal.bytes_value().end() }; 154 } 155 156 if (protoVal.int32_values_size() > 0) { 157 val.value.int32Values = std::vector<int32_t> { protoVal.int32_values().begin(), 158 protoVal.int32_values().end() }; 159 } 160 161 if (protoVal.int64_values_size() > 0) { 162 val.value.int64Values = std::vector<int64_t> { protoVal.int64_values().begin(), 163 protoVal.int64_values().end() }; 164 } 165 166 if (protoVal.float_values_size() > 0) { 167 val.value.floatValues = std::vector<float> { protoVal.float_values().begin(), 168 protoVal.float_values().end() }; 169 } 170 171 bool halRes = mHal->setPropertyFromVehicle(val); 172 respMsg.set_status(halRes ? emulator::RESULT_OK : emulator::ERROR_INVALID_PROPERTY); 173 } 174 175 void VehicleEmulator::txMsg(emulator::EmulatorMessage& txMsg) { 176 int numBytes = txMsg.ByteSize(); 177 std::vector<uint8_t> msg(static_cast<size_t>(numBytes)); 178 179 if (!txMsg.SerializeToArray(msg.data(), static_cast<int32_t>(msg.size()))) { 180 ALOGE("%s: SerializeToString failed!", __func__); 181 return; 182 } 183 184 if (mExit) { 185 ALOGW("%s: unable to transmit a message, connection closed", __func__); 186 return; 187 } 188 189 // Send the message 190 int retVal = mComm->write(msg); 191 if (retVal < 0) { 192 ALOGE("%s: Failed to tx message: retval=%d, errno=%d", __func__, retVal, errno); 193 } 194 } 195 196 void VehicleEmulator::parseRxProtoBuf(std::vector<uint8_t>& msg) { 197 emulator::EmulatorMessage rxMsg; 198 emulator::EmulatorMessage respMsg; 199 200 if (rxMsg.ParseFromArray(msg.data(), static_cast<int32_t>(msg.size()))) { 201 switch (rxMsg.msg_type()) { 202 case emulator::GET_CONFIG_CMD: 203 doGetConfig(rxMsg, respMsg); 204 break; 205 case emulator::GET_CONFIG_ALL_CMD: 206 doGetConfigAll(rxMsg, respMsg); 207 break; 208 case emulator::GET_PROPERTY_CMD: 209 doGetProperty(rxMsg, respMsg); 210 break; 211 case emulator::GET_PROPERTY_ALL_CMD: 212 doGetPropertyAll(rxMsg, respMsg); 213 break; 214 case emulator::SET_PROPERTY_CMD: 215 doSetProperty(rxMsg, respMsg); 216 break; 217 default: 218 ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type()); 219 respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD); 220 break; 221 } 222 223 // Send the reply 224 txMsg(respMsg); 225 } else { 226 ALOGE("%s: ParseFromString() failed. msgSize=%d", __func__, static_cast<int>(msg.size())); 227 } 228 } 229 230 void VehicleEmulator::populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg, 231 const VehiclePropConfig& cfg) { 232 protoCfg->set_prop(cfg.prop); 233 protoCfg->set_access(toInt(cfg.access)); 234 protoCfg->set_change_mode(toInt(cfg.changeMode)); 235 protoCfg->set_value_type(toInt(getPropType(cfg.prop))); 236 237 if (!isGlobalProp(cfg.prop)) { 238 protoCfg->set_supported_areas(cfg.supportedAreas); 239 } 240 241 for (auto& configElement : cfg.configArray) { 242 protoCfg->add_config_array(configElement); 243 } 244 245 if (cfg.configString.size() > 0) { 246 protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size()); 247 } 248 249 // Populate the min/max values based on property type 250 switch (getPropType(cfg.prop)) { 251 case VehiclePropertyType::STRING: 252 case VehiclePropertyType::BOOLEAN: 253 case VehiclePropertyType::INT32_VEC: 254 case VehiclePropertyType::FLOAT_VEC: 255 case VehiclePropertyType::BYTES: 256 case VehiclePropertyType::COMPLEX: 257 // Do nothing. These types don't have min/max values 258 break; 259 case VehiclePropertyType::INT64: 260 if (cfg.areaConfigs.size() > 0) { 261 emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs(); 262 aCfg->set_min_int64_value(cfg.areaConfigs[0].minInt64Value); 263 aCfg->set_max_int64_value(cfg.areaConfigs[0].maxInt64Value); 264 } 265 break; 266 case VehiclePropertyType::FLOAT: 267 if (cfg.areaConfigs.size() > 0) { 268 emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs(); 269 aCfg->set_min_float_value(cfg.areaConfigs[0].minFloatValue); 270 aCfg->set_max_float_value(cfg.areaConfigs[0].maxFloatValue); 271 } 272 break; 273 case VehiclePropertyType::INT32: 274 if (cfg.areaConfigs.size() > 0) { 275 emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs(); 276 aCfg->set_min_int32_value(cfg.areaConfigs[0].minInt32Value); 277 aCfg->set_max_int32_value(cfg.areaConfigs[0].maxInt32Value); 278 } 279 break; 280 default: 281 ALOGW("%s: Unknown property type: 0x%x", __func__, toInt(getPropType(cfg.prop))); 282 break; 283 } 284 285 protoCfg->set_min_sample_rate(cfg.minSampleRate); 286 protoCfg->set_max_sample_rate(cfg.maxSampleRate); 287 } 288 289 void VehicleEmulator::populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal, 290 const VehiclePropValue* val) { 291 protoVal->set_prop(val->prop); 292 protoVal->set_value_type(toInt(getPropType(val->prop))); 293 protoVal->set_timestamp(val->timestamp); 294 protoVal->set_area_id(val->areaId); 295 296 // Copy value data if it is set. 297 // - for bytes and strings, this is indicated by size > 0 298 // - for int32, int64, and float, copy the values if vectors have data 299 if (val->value.stringValue.size() > 0) { 300 protoVal->set_string_value(val->value.stringValue.c_str(), val->value.stringValue.size()); 301 } 302 303 if (val->value.bytes.size() > 0) { 304 protoVal->set_bytes_value(val->value.bytes.data(), val->value.bytes.size()); 305 } 306 307 for (auto& int32Value : val->value.int32Values) { 308 protoVal->add_int32_values(int32Value); 309 } 310 311 for (auto& int64Value : val->value.int64Values) { 312 protoVal->add_int64_values(int64Value); 313 } 314 315 for (auto& floatValue : val->value.floatValues) { 316 protoVal->add_float_values(floatValue); 317 } 318 } 319 320 void VehicleEmulator::rxMsg() { 321 while (!mExit) { 322 std::vector<uint8_t> msg = mComm->read(); 323 324 if (msg.size() > 0) { 325 // Received a message. 326 parseRxProtoBuf(msg); 327 } else { 328 // This happens when connection is closed 329 ALOGD("%s: msgSize=%zu", __func__, msg.size()); 330 break; 331 } 332 } 333 } 334 335 void VehicleEmulator::rxThread() { 336 if (mExit) return; 337 338 int retVal = mComm->open(); 339 if (retVal != 0) mExit = true; 340 341 // Comms are properly opened 342 while (!mExit) { 343 retVal = mComm->connect(); 344 345 if (retVal >= 0) { 346 rxMsg(); 347 } 348 349 // Check every 100ms for a new connection 350 std::this_thread::sleep_for(std::chrono::milliseconds(100)); 351 } 352 } 353 354 } // impl 355 356 } // namespace V2_0 357 } // namespace vehicle 358 } // namespace automotive 359 } // namespace hardware 360 } // namespace android 361