• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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