Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fba3ac86 authored by Hao Chen's avatar Hao Chen
Browse files

Applying the vehicle connector to the VHAL

Make VHAL to use the connector/server interfaces instead of talking to
the (faked) vehicle directly. Use passthrough connector for now since we
have not moved to the virtualized scenario yet (but soon :)

Bug: b/141493212

Test: On both Osprey and Hawk. Build and flash the image. If on Osprey, see
go/enable-google-vhal-on-osprey; if on hawk, `aae app vhal apply google`
to enable Google VHAL

```
# no VHAL crash
$ adb logcat

$ vts-tradefed
> run vts-hal-auto -m VtsHalAutomotiveVehicleV2_0Host
# 30 passed, 2 failed, the same as the result before this patch

# See value changed in Vehicle HAL tab, KitchenSink app:
$ python packages/services/Car/tools/emulator/prop_event_simulator.py --property
VEHICLEPROPERTY_HVAC_AC_ON --area 0 --value 1

# unit tests
$ atest packages/services/Car/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarPropertyTest.java
```

Change-Id: Iab77a0ae32db2c55b4c65aa8f3e4f73ec9ef2644
parent cda8e6e0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ cc_library_static {
    defaults: ["vhal_v2_0_defaults"],
    srcs: [
        "impl/vhal_v2_0/CommConn.cpp",
        "impl/vhal_v2_0/EmulatedVehicleConnector.cpp",
        "impl/vhal_v2_0/EmulatedVehicleHal.cpp",
        "impl/vhal_v2_0/VehicleEmulator.cpp",
        "impl/vhal_v2_0/PipeComm.cpp",
+5 −2
Original line number Diff line number Diff line
@@ -20,8 +20,9 @@

#include <iostream>

#include <vhal_v2_0/VehicleHalManager.h>
#include <vhal_v2_0/EmulatedVehicleConnector.h>
#include <vhal_v2_0/EmulatedVehicleHal.h>
#include <vhal_v2_0/VehicleHalManager.h>

using namespace android;
using namespace android::hardware;
@@ -29,9 +30,11 @@ using namespace android::hardware::automotive::vehicle::V2_0;

int main(int /* argc */, char* /* argv */ []) {
    auto store = std::make_unique<VehiclePropertyStore>();
    auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get());
    auto connector = impl::makeEmulatedPassthroughConnector();
    auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get(), connector.get());
    auto emulator = std::make_unique<impl::VehicleEmulator>(hal.get());
    auto service = std::make_unique<VehicleHalManager>(hal.get());
    connector->setValuePool(hal->getValuePool());

    configureRpcThreadpool(4, true /* callerWillJoin */);

+20 −159
Original line number Diff line number Diff line
@@ -87,17 +87,19 @@ static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame(size_t numVendorInt
    return sensorStore;
}

EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore)
EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore,
                                       EmulatedVehicleClient* client)
    : mPropStore(propStore),
      mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
      mRecurrentTimer(
          std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)),
      mGeneratorHub(
          std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1)) {
      mVehicleClient(client) {
    initStaticConfig();
    for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
        mPropStore->registerProperty(kVehicleProperties[i].config);
    }
    mVehicleClient->registerPropertyValueCallback(
        std::bind(&EmulatedVehicleHal::onPropertyValue, this, std::placeholders::_1));
}

VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
@@ -162,7 +164,8 @@ StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
    }

    if (propValue.prop == kGenerateFakeDataControllingProperty) {
        StatusCode status = handleGenerateFakeDataRequest(propValue);
        // send the generator controlling request to the server
        auto status = mVehicleClient->setPropertyFromVehicle(propValue);
        if (status != StatusCode::OK) {
            return status;
        }
@@ -186,29 +189,6 @@ StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
                // Placeholder for future implementation of VMS property in the default hal. For
                // now, just returns OK; otherwise, hal clients crash with property not supported.
                return StatusCode::OK;
            case AP_POWER_STATE_REPORT:
                switch (propValue.value.int32Values[0]) {
                    case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
                    case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
                    case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
                        // CPMS is in WAIT_FOR_VHAL state, simply move to ON
                        doHalEvent(createApPowerStateReq(VehicleApPowerStateReq::ON, 0));
                        break;
                    case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
                    case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
                        // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
                        doHalEvent(createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0));
                        break;
                    case toInt(VehicleApPowerStateReport::ON):
                    case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
                    case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
                        // Do nothing
                        break;
                    default:
                        // Unknown state
                        break;
                }
                break;
        }
    }

@@ -231,10 +211,16 @@ StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
    /**
     * After checking all conditions, such as the property is available, a real vhal will
     * sent the events to Car ECU to take actions.
     * Google HAL will just add a timestamp for the value and triggle the callback to android.
     */
    VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(propValue);
    updatedPropValue->timestamp = elapsedRealtimeNano();

    // Send the value to the vehicle server, the server will talk to the (real or emulated) car
    auto setValueStatus = mVehicleClient->setProperty(*updatedPropValue);
    if (setValueStatus != StatusCode::OK) {
        return setValueStatus;
    }

    if (!mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus)) {
        return StatusCode::INTERNAL_ERROR;
    }
@@ -361,146 +347,21 @@ bool EmulatedVehicleHal::isContinuousProperty(int32_t propId) const {
}

bool EmulatedVehicleHal::setPropertyFromVehicle(const VehiclePropValue& propValue) {
    static constexpr bool shouldUpdateStatus = true;

    if (propValue.prop == kGenerateFakeDataControllingProperty) {
        StatusCode status = handleGenerateFakeDataRequest(propValue);
        if (status != StatusCode::OK) {
            return false;
        }
    }

    if (mPropStore->writeValue(propValue, shouldUpdateStatus)) {
        doHalEvent(getValuePool()->obtain(propValue));
        return true;
    } else {
        return false;
    }
    return mVehicleClient->setPropertyFromVehicle(propValue) == StatusCode::OK;
}

std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const  {
    return mPropStore->readAllValues();
}

StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
    ALOGI("%s", __func__);
    const auto& v = request.value;
    if (!v.int32Values.size()) {
        ALOGE("%s: expected at least \"command\" field in int32Values", __func__);
        return StatusCode::INVALID_ARG;
    }

    FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);

    switch (command) {
        case FakeDataCommand::StartLinear: {
            ALOGI("%s, FakeDataCommand::StartLinear", __func__);
            if (v.int32Values.size() < 2) {
                ALOGE("%s: expected property ID in int32Values", __func__);
                return StatusCode::INVALID_ARG;
            }
            if (!v.int64Values.size()) {
                ALOGE("%s: interval is not provided in int64Values", __func__);
                return StatusCode::INVALID_ARG;
            }
            if (v.floatValues.size() < 3) {
                ALOGE("%s: expected at least 3 elements in floatValues, got: %zu", __func__,
                      v.floatValues.size());
                return StatusCode::INVALID_ARG;
            }
            int32_t cookie = v.int32Values[1];
            mGeneratorHub.registerGenerator(cookie,
                                            std::make_unique<LinearFakeValueGenerator>(request));
            break;
        }
        case FakeDataCommand::StartJson: {
            ALOGI("%s, FakeDataCommand::StartJson", __func__);
            if (v.stringValue.empty()) {
                ALOGE("%s: path to JSON file is missing", __func__);
                return StatusCode::INVALID_ARG;
            }
            int32_t cookie = std::hash<std::string>()(v.stringValue);
            mGeneratorHub.registerGenerator(cookie,
                                            std::make_unique<JsonFakeValueGenerator>(request));
            break;
        }
        case FakeDataCommand::StopLinear: {
            ALOGI("%s, FakeDataCommand::StopLinear", __func__);
            if (v.int32Values.size() < 2) {
                ALOGE("%s: expected property ID in int32Values", __func__);
                return StatusCode::INVALID_ARG;
            }
            int32_t cookie = v.int32Values[1];
            mGeneratorHub.unregisterGenerator(cookie);
            break;
        }
        case FakeDataCommand::StopJson: {
            ALOGI("%s, FakeDataCommand::StopJson", __func__);
            if (v.stringValue.empty()) {
                ALOGE("%s: path to JSON file is missing", __func__);
                return StatusCode::INVALID_ARG;
            }
            int32_t cookie = std::hash<std::string>()(v.stringValue);
            mGeneratorHub.unregisterGenerator(cookie);
            break;
        }
        case FakeDataCommand::KeyPress: {
            ALOGI("%s, FakeDataCommand::KeyPress", __func__);
            int32_t keyCode = request.value.int32Values[2];
            int32_t display = request.value.int32Values[3];
            doHalEvent(
                createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display));
            doHalEvent(createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display));
            break;
        }
        default: {
            ALOGE("%s: unexpected command: %d", __func__, command);
            return StatusCode::INVALID_ARG;
        }
    }
    return StatusCode::OK;
}

VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createApPowerStateReq(
    VehicleApPowerStateReq state, int32_t param) {
    auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2);
    req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
    req->areaId = 0;
    req->timestamp = elapsedRealtimeNano();
    req->status = VehiclePropertyStatus::AVAILABLE;
    req->value.int32Values[0] = toInt(state);
    req->value.int32Values[1] = param;
    return req;
}

VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createHwInputKeyProp(
    VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) {
    auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3);
    keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT);
    keyEvent->areaId = 0;
    keyEvent->timestamp = elapsedRealtimeNano();
    keyEvent->status = VehiclePropertyStatus::AVAILABLE;
    keyEvent->value.int32Values[0] = toInt(action);
    keyEvent->value.int32Values[1] = keyCode;
    keyEvent->value.int32Values[2] = targetDisplay;
    return keyEvent;
}

void EmulatedVehicleHal::onFakeValueGenerated(const VehiclePropValue& value) {
    ALOGD("%s: %s", __func__, toString(value).c_str());
    static constexpr bool shouldUpdateStatus = false;

void EmulatedVehicleHal::onPropertyValue(const VehiclePropValue& value) {
    static constexpr bool shouldUpdateStatus = true;
    VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value);
    if (updatedPropValue) {
        updatedPropValue->timestamp = value.timestamp;
        updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
        mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus);
        auto changeMode = mPropStore->getConfigOrDie(value.prop)->changeMode;
        if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) {

    if (mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus)) {
        doHalEvent(std::move(updatedPropValue));
    }
}
}

void EmulatedVehicleHal::initStaticConfig() {
    for (auto&& it = std::begin(kVehicleProperties); it != std::end(kVehicleProperties); ++it) {
+5 −6
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include "vhal_v2_0/VehiclePropertyStore.h"

#include "DefaultConfig.h"
#include "EmulatedVehicleConnector.h"
#include "GeneratorHub.h"
#include "VehicleEmulator.h"

@@ -44,7 +45,8 @@ namespace impl {
/** Implementation of VehicleHal that connected to emulator instead of real vehicle network. */
class EmulatedVehicleHal : public EmulatedVehicleHalIface {
public:
    EmulatedVehicleHal(VehiclePropertyStore* propStore);
    EmulatedVehicleHal(VehiclePropertyStore* propStore,
                       EmulatedVehicleClient* client);
    ~EmulatedVehicleHal() = default;

    //  Methods from VehicleHal
@@ -66,10 +68,7 @@ private:
    }

    StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
    void onFakeValueGenerated(const VehiclePropValue& value);
    VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param);
    VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode,
                                             int32_t targetDisplay);
    void onPropertyValue(const VehiclePropValue& value);

    void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
    bool isContinuousProperty(int32_t propId) const;
@@ -85,7 +84,7 @@ private:
    VehiclePropertyStore* mPropStore;
    std::unordered_set<int32_t> mHvacPowerProps;
    RecurrentTimer mRecurrentTimer;
    GeneratorHub mGeneratorHub;
    EmulatedVehicleClient* mVehicleClient;
};

}  // impl