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

Commit 18198d7c authored by Yu Shan's avatar Yu Shan
Browse files

Add special logic handle setting some props.

Add special logic to handle setting OBD2 properties and
VEHICLE_MAP_SERVICE.

Test: atest FakeVehicleHardwareTest
Bug: 201830716
Change-Id: I9b136efc452944e6c393c12feca14942919993c7
parent bfc7030e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ cc_library {
    static_libs: [
        "VehicleHalUtils",
        "FakeVehicleHalValueGenerators",
        "FakeObd2Frame",
    ],
    shared_libs: [
        "libjsoncpp",
+9 −3
Original line number Diff line number Diff line
@@ -18,9 +18,11 @@
#define android_hardware_automotive_vehicle_aidl_impl_fake_impl_hardware_include_FakeVehicleHardware_H_

#include <DefaultConfig.h>
#include <FakeObd2Frame.h>
#include <IVehicleHardware.h>
#include <VehicleHalTypes.h>
#include <VehiclePropertyStore.h>
#include <android-base/result.h>
#include <android-base/thread_annotations.h>

#include <map>
@@ -85,14 +87,15 @@ class FakeVehicleHardware final : public IVehicleHardware {
    // Expose private methods to unit test.
    friend class FakeVehicleHardwareTestHelper;

    std::unique_ptr<VehiclePropertyStore> mServerSidePropStore;
    // mValuePool is also used in mServerSidePropStore.
    std::shared_ptr<VehiclePropValuePool> mValuePool;
    const std::shared_ptr<VehiclePropValuePool> mValuePool;
    const std::shared_ptr<VehiclePropertyStore> mServerSidePropStore;
    const std::unique_ptr<obd2frame::FakeObd2Frame> mFakeObd2Frame;
    std::mutex mCallbackLock;
    OnPropertyChangeCallback mOnPropertyChangeCallback GUARDED_BY(mCallbackLock);
    OnPropertySetErrorCallback mOnPropertySetErrorCallback GUARDED_BY(mCallbackLock);

    void init(std::shared_ptr<VehiclePropValuePool> valuePool);
    void init();
    // Stores the initial value to property store.
    void storePropInitialValue(const defaultconfig::ConfigDeclaration& config);
    // The callback that would be called when a vehicle property value change happens.
@@ -107,6 +110,9 @@ class FakeVehicleHardware final : public IVehicleHardware {
    ::aidl::android::hardware::automotive::vehicle::StatusCode maybeSetSpecialValue(
            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
            bool* isSpecialValue);
    ::android::base::Result<VehiclePropValuePool::RecyclableType> maybeGetSpecialValue(
            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
            bool* isSpecialValue) const;
    ::aidl::android::hardware::automotive::vehicle::StatusCode setApPowerStateReport(
            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
    VehiclePropValuePool::RecyclableType createApPowerStateReq(
+132 −35
Original line number Diff line number Diff line
@@ -17,7 +17,9 @@
#include "FakeVehicleHardware.h"

#include <DefaultConfig.h>
#include <FakeObd2Frame.h>
#include <JsonFakeValueGenerator.h>
#include <PropertyUtils.h>
#include <VehicleHalTypes.h>
#include <VehicleUtils.h>
#include <android-base/properties.h>
@@ -53,9 +55,27 @@ using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;

using ::android::base::Result;

const char* VENDOR_OVERRIDE_DIR = "/vendor/etc/automotive/vhaloverride/";
const char* OVERRIDE_PROPERTY = "persist.vendor.vhal_init_value_override";

template <class T>
StatusCode getErrorCode(const Result<T>& result) {
    if (result.ok()) {
        return StatusCode::OK;
    }
    return static_cast<StatusCode>(result.error().code());
}

template <class T>
std::string getErrorMsg(const Result<T>& result) {
    if (result.ok()) {
        return "";
    }
    return result.error().message();
}

}  // namespace

void FakeVehicleHardware::storePropInitialValue(const defaultconfig::ConfigDeclaration& config) {
@@ -93,32 +113,51 @@ void FakeVehicleHardware::storePropInitialValue(const defaultconfig::ConfigDecla
        auto result =
                mServerSidePropStore->writeValue(mValuePool->obtain(prop), /*updateStatus=*/true);
        if (!result.ok()) {
            ALOGE("failed to write default config value, error: %s",
                  result.error().message().c_str());
            ALOGE("failed to write default config value, error: %s, status: %d",
                  getErrorMsg(result).c_str(), getErrorCode(result));
        }
    }
}

FakeVehicleHardware::FakeVehicleHardware() {
    mValuePool = std::make_shared<VehiclePropValuePool>();
    init(mValuePool);
FakeVehicleHardware::FakeVehicleHardware()
    : mValuePool(new VehiclePropValuePool),
      mServerSidePropStore(new VehiclePropertyStore(mValuePool)),
      mFakeObd2Frame(new obd2frame::FakeObd2Frame(mServerSidePropStore)) {
    init();
}

FakeVehicleHardware::FakeVehicleHardware(std::unique_ptr<VehiclePropValuePool> valuePool)
    : mValuePool(std::move(valuePool)) {
    init(mValuePool);
    : mValuePool(std::move(valuePool)),
      mServerSidePropStore(new VehiclePropertyStore(mValuePool)),
      mFakeObd2Frame(new obd2frame::FakeObd2Frame(mServerSidePropStore)) {
    init();
}

void FakeVehicleHardware::init(std::shared_ptr<VehiclePropValuePool> valuePool) {
    mServerSidePropStore.reset(new VehiclePropertyStore(valuePool));
void FakeVehicleHardware::init() {
    for (auto& it : defaultconfig::getDefaultConfigs()) {
        VehiclePropConfig cfg = it.config;
        mServerSidePropStore->registerProperty(cfg);
        VehiclePropertyStore::TokenFunction tokenFunction = nullptr;

        if (cfg.prop == OBD2_FREEZE_FRAME) {
            tokenFunction = [](const VehiclePropValue& propValue) { return propValue.timestamp; };
        }

        mServerSidePropStore->registerProperty(cfg, tokenFunction);
        if (obd2frame::FakeObd2Frame::isDiagnosticProperty(cfg)) {
            // Ignore storing default value for diagnostic property. They have special get/set
            // logic.
            continue;
        }
        storePropInitialValue(it);
    }

    maybeOverrideProperties(VENDOR_OVERRIDE_DIR);

    // OBD2_LIVE_FRAME and OBD2_FREEZE_FRAME must be configured in default configs.
    mFakeObd2Frame->initObd2LiveFrame(*mServerSidePropStore->getConfig(OBD2_LIVE_FRAME).value());
    mFakeObd2Frame->initObd2FreezeFrame(
            *mServerSidePropStore->getConfig(OBD2_FREEZE_FRAME).value());

    mServerSidePropStore->setOnValueChangeCallback(
            [this](const VehiclePropValue& value) { return onValueChangeCallback(value); });
}
@@ -146,9 +185,10 @@ StatusCode FakeVehicleHardware::setApPowerStateReport(const VehiclePropValue& va

    if (auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
        !writeResult.ok()) {
        ALOGE("failed to write value into property store, error: %s",
              writeResult.error().message().c_str());
        return StatusCode::INVALID_ARG;
        StatusCode errorCode = getErrorCode(writeResult);
        ALOGE("failed to write value into property store, error: %s, code: %d",
              getErrorMsg(writeResult).c_str(), errorCode);
        return errorCode;
    }

    VehiclePropValuePool::RecyclableType prop;
@@ -168,9 +208,10 @@ StatusCode FakeVehicleHardware::setApPowerStateReport(const VehiclePropValue& va
            if (auto writeResult =
                        mServerSidePropStore->writeValue(std::move(prop), /*updateStatus=*/true);
                !writeResult.ok()) {
                ALOGE("failed to write AP_POWER_STATE_REQ into property store, error: %s",
                      writeResult.error().message().c_str());
                return StatusCode::INTERNAL_ERROR;
                StatusCode errorCode = getErrorCode(writeResult);
                ALOGE("failed to write AP_POWER_STATE_REQ into property store, error: %s, code: %d",
                      getErrorMsg(writeResult).c_str(), errorCode);
                return errorCode;
            }
            break;
        case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
@@ -185,9 +226,10 @@ StatusCode FakeVehicleHardware::setApPowerStateReport(const VehiclePropValue& va
            if (auto writeResult =
                        mServerSidePropStore->writeValue(std::move(prop), /*updateStatus=*/true);
                !writeResult.ok()) {
                ALOGE("failed to write AP_POWER_STATE_REQ into property store, error: %s",
                      writeResult.error().message().c_str());
                return StatusCode::INTERNAL_ERROR;
                StatusCode errorCode = getErrorCode(writeResult);
                ALOGE("failed to write AP_POWER_STATE_REQ into property store, error: %s, code: %d",
                      getErrorMsg(writeResult).c_str(), errorCode);
                return errorCode;
            }
            break;
        default:
@@ -197,6 +239,35 @@ StatusCode FakeVehicleHardware::setApPowerStateReport(const VehiclePropValue& va
    return StatusCode::OK;
}

Result<VehiclePropValuePool::RecyclableType> FakeVehicleHardware::maybeGetSpecialValue(
        const VehiclePropValue& value, bool* isSpecialValue) const {
    *isSpecialValue = false;
    int32_t propId = value.prop;
    Result<VehiclePropValuePool::RecyclableType> result;

    switch (propId) {
        case OBD2_FREEZE_FRAME:
            *isSpecialValue = true;
            result = mFakeObd2Frame->getObd2FreezeFrame(value);
            if (result.ok()) {
                result.value()->timestamp = elapsedRealtimeNano();
            }
            return result;
        case OBD2_FREEZE_FRAME_INFO:
            *isSpecialValue = true;
            result = mFakeObd2Frame->getObd2DtcInfo();
            if (result.ok()) {
                result.value()->timestamp = elapsedRealtimeNano();
            }
            return result;
        default:
            // Do nothing.
            break;
    }

    return nullptr;
}

StatusCode FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValue& value,
                                                     bool* isSpecialValue) {
    *isSpecialValue = false;
@@ -206,6 +277,14 @@ StatusCode FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValue& val
        case toInt(VehicleProperty::AP_POWER_STATE_REPORT):
            *isSpecialValue = true;
            return setApPowerStateReport(value);
        case toInt(VehicleProperty::VEHICLE_MAP_SERVICE):
            // Placeholder for future implementation of VMS property in the default hal. For
            // now, just returns OK; otherwise, hal clients crash with property not supported.
            *isSpecialValue = true;
            return StatusCode::OK;
        case OBD2_FREEZE_FRAME_CLEAR:
            *isSpecialValue = true;
            return mFakeObd2Frame->clearObd2FreezeFrames(value);

#ifdef ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
        case toInt(VehicleProperty::CLUSTER_REPORT_STATE):
@@ -230,9 +309,10 @@ StatusCode FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValue& val
            updatedValue->areaId = value.areaId;
            if (auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
                !writeResult.ok()) {
                ALOGE("failed to write value into property store, error: %s",
                      writeResult.error().message().c_str());
                return StatusCode::INVALID_ARG;
                StatusCode errorCode = getErrorCode(writeResult);
                ALOGE("failed to write value into property store, error: %s, code: %d",
                      getErrorMsg(writeResult).c_str(), errorCode);
                return errorCode;
            }
            return StatusCode::OK;
#endif  // ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
@@ -278,9 +358,10 @@ StatusCode FakeVehicleHardware::setValues(FakeVehicleHardware::SetValuesCallback

        auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
        if (!writeResult.ok()) {
            StatusCode errorCode = getErrorCode(writeResult);
            ALOGE("failed to write value into property store, error: %s, code: %d",
                  writeResult.error().message().c_str(), writeResult.error().code());
            setValueResult.status = StatusCode::INVALID_ARG;
                  getErrorMsg(writeResult).c_str(), errorCode);
            setValueResult.status = errorCode;
        }
        results.push_back(std::move(setValueResult));
    }
@@ -296,22 +377,38 @@ StatusCode FakeVehicleHardware::getValues(FakeVehicleHardware::GetValuesCallback
                                          const std::vector<GetValueRequest>& requests) const {
    std::vector<GetValueResult> results;
    for (auto& request : requests) {
        const VehiclePropValue* value = &request.prop;
        ALOGD("getValues(%d)", value->prop);
        const VehiclePropValue& value = request.prop;
        ALOGD("getValues(%d)", value.prop);

        auto readResult = mServerSidePropStore->readValue(*value);
        GetValueResult getValueResult;
        getValueResult.requestId = request.requestId;
        bool isSpecialValue = false;

        auto result = maybeGetSpecialValue(value, &isSpecialValue);
        if (isSpecialValue) {
            if (!result.ok()) {
                StatusCode errorCode = getErrorCode(result);
                ALOGE("failed to get special value: %d, error: %s, code: %d", value.prop,
                      getErrorMsg(result).c_str(), errorCode);
                getValueResult.status = errorCode;
            } else {
                getValueResult.status = StatusCode::OK;
                getValueResult.prop = *result.value();
            }
            results.push_back(std::move(getValueResult));
            continue;
        }

        auto readResult = mServerSidePropStore->readValue(value);
        if (!readResult.ok()) {
            auto error = readResult.error();
            if (error.code() == toInt(StatusCode::NOT_AVAILABLE)) {
            StatusCode errorCode = getErrorCode(readResult);
            if (errorCode == StatusCode::NOT_AVAILABLE) {
                ALOGW("%s", "value has not been set yet");
                getValueResult.status = StatusCode::NOT_AVAILABLE;
            } else {
                ALOGE("failed to get value, error: %s, code: %d", error.message().c_str(),
                      error.code());
                getValueResult.status = StatusCode::INVALID_ARG;
                ALOGE("failed to get value, error: %s, code: %d", getErrorMsg(readResult).c_str(),
                      errorCode);
            }
            getValueResult.status = errorCode;
        } else {
            getValueResult.status = StatusCode::OK;
            getValueResult.prop = *readResult.value();
@@ -378,8 +475,8 @@ void FakeVehicleHardware::overrideProperties(const char* overrideDir) {
                if (auto result = mServerSidePropStore->writeValue(std::move(propToStore),
                                                                   /*updateStatus=*/true);
                    !result.ok()) {
                    ALOGW("failed to write vendor override properties: %d, error: %s", prop.prop,
                          result.error().message().c_str());
                    ALOGW("failed to write vendor override properties: %d, error: %s, code: %d",
                          prop.prop, getErrorMsg(result).c_str(), getErrorCode(result));
                }
            }
        }
+1 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ cc_test {
        "VehicleHalUtils",
        "FakeVehicleHardware",
        "FakeVehicleHalValueGenerators",
        "FakeObd2Frame",
        "libgtest",
        "libgmock",
    ],
+69 −0
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
#include <FakeVehicleHardware.h>

#include <DefaultConfig.h>
#include <FakeObd2Frame.h>
#include <PropertyUtils.h>
#include <TestPropertyUtils.h>

#include <android-base/expected.h>
@@ -249,6 +251,12 @@ TEST_F(FakeVehicleHardwareTest, testGetDefaultValues) {
    int64_t requestId = 1;

    for (auto& config : defaultconfig::getDefaultConfigs()) {
        if (obd2frame::FakeObd2Frame::isDiagnosticProperty(config.config)) {
            // Ignore storing default value for diagnostic property. They have special get/set
            // logic.
            continue;
        }

        int propId = config.config.prop;
        if (isGlobalProp(propId)) {
            if (config.initialValue == RawPropValues{}) {
@@ -901,6 +909,67 @@ INSTANTIATE_TEST_SUITE_P(
            return info.param.name;
        });

TEST_F(FakeVehicleHardwareTest, testGetObd2FreezeFrame) {
    int64_t timestamp = elapsedRealtimeNano();

    auto result = getValue(VehiclePropValue{.prop = OBD2_FREEZE_FRAME_INFO});

    ASSERT_TRUE(result.ok());

    auto propValue = result.value();
    ASSERT_GE(propValue.timestamp, timestamp);
    ASSERT_EQ(propValue.value.int64Values.size(), static_cast<size_t>(3))
            << "expect 3 obd2 freeze frames stored";

    for (int64_t timestamp : propValue.value.int64Values) {
        auto freezeFrameResult = getValue(VehiclePropValue{
                .prop = OBD2_FREEZE_FRAME,
                .value.int64Values = {timestamp},
        });

        EXPECT_TRUE(result.ok()) << "expect to get freeze frame for timestamp " << timestamp
                                 << " ok";
        EXPECT_GE(freezeFrameResult.value().timestamp, timestamp);
    }
}

TEST_F(FakeVehicleHardwareTest, testClearObd2FreezeFrame) {
    int64_t timestamp = elapsedRealtimeNano();

    auto getValueResult = getValue(VehiclePropValue{.prop = OBD2_FREEZE_FRAME_INFO});

    ASSERT_TRUE(getValueResult.ok());

    auto propValue = getValueResult.value();
    ASSERT_GE(propValue.timestamp, timestamp);
    ASSERT_EQ(propValue.value.int64Values.size(), static_cast<size_t>(3))
            << "expect 3 obd2 freeze frames stored";

    // No int64Values should clear all freeze frames.
    StatusCode status = setValue(VehiclePropValue{.prop = OBD2_FREEZE_FRAME_CLEAR});

    ASSERT_EQ(status, StatusCode::OK);

    getValueResult = getValue(VehiclePropValue{.prop = OBD2_FREEZE_FRAME_INFO});

    ASSERT_TRUE(getValueResult.ok());
    ASSERT_EQ(getValueResult.value().value.int64Values.size(), static_cast<size_t>(0))
            << "expect 0 obd2 freeze frames after cleared";
}

TEST_F(FakeVehicleHardwareTest, testSetVehicleMapService) {
    StatusCode status =
            setValue(VehiclePropValue{.prop = toInt(VehicleProperty::VEHICLE_MAP_SERVICE)});

    EXPECT_EQ(status, StatusCode::OK);

    auto getValueResult =
            getValue(VehiclePropValue{.prop = toInt(VehicleProperty::VEHICLE_MAP_SERVICE)});

    EXPECT_FALSE(getValueResult.ok());
    EXPECT_EQ(getValueResult.error(), StatusCode::NOT_AVAILABLE);
}

}  // namespace fake
}  // namespace vehicle
}  // namespace automotive