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