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
create()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
~VehicleEmulator()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
doSetValueFromClient(const VehiclePropValue & propValue)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
doGetConfig(VehicleEmulator::EmulatorMessage & rxMsg,VehicleEmulator::EmulatorMessage & respMsg)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
doGetConfigAll(VehicleEmulator::EmulatorMessage &,VehicleEmulator::EmulatorMessage & respMsg)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
doGetProperty(VehicleEmulator::EmulatorMessage & rxMsg,VehicleEmulator::EmulatorMessage & respMsg)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
doGetPropertyAll(VehicleEmulator::EmulatorMessage &,VehicleEmulator::EmulatorMessage & respMsg)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
doSetProperty(VehicleEmulator::EmulatorMessage & rxMsg,VehicleEmulator::EmulatorMessage & respMsg)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
txMsg(emulator::EmulatorMessage & txMsg)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
parseRxProtoBuf(std::vector<uint8_t> & msg)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
populateProtoVehicleConfig(emulator::VehiclePropConfig * protoCfg,const VehiclePropConfig & cfg)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
populateProtoVehiclePropValue(emulator::VehiclePropValue * protoVal,const VehiclePropValue * val)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
rxMsg()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
rxThread()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