Home | History | Annotate | Download | only in vhal_v2_0
      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