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

Commit bef03540 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add vendor override property to fake VHAL hardware."

parents 64b82c36 d7575f76
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -30,6 +30,12 @@ cc_library {
        "VehicleHalDefaultConfig",
    ],
    export_header_lib_headers: ["IVehicleHardware"],
    static_libs: ["VehicleHalUtils"],
    static_libs: [
        "VehicleHalUtils",
        "FakeVehicleHalValueGenerators",
    ],
    shared_libs: [
        "libjsoncpp",
    ],
    export_static_lib_headers: ["VehicleHalUtils"],
}
+14 −4
Original line number Diff line number Diff line
@@ -82,10 +82,8 @@ class FakeVehicleHardware final : public IVehicleHardware {
    void registerOnPropertySetErrorEvent(OnPropertySetErrorCallback&& callback) override;

  private:
    void storePropInitialValue(const defaultconfig::ConfigDeclaration& config);
    void init(std::shared_ptr<VehiclePropValuePool> valuePool);
    void onValueChangeCallback(
            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
    // Expose private methods to unit test.
    friend class FakeVehicleHardwareTestHelper;

    std::unique_ptr<VehiclePropertyStore> mServerSidePropStore;
    // mValuePool is also used in mServerSidePropStore.
@@ -93,6 +91,18 @@ class FakeVehicleHardware final : public IVehicleHardware {
    std::mutex mCallbackLock;
    OnPropertyChangeCallback mOnPropertyChangeCallback GUARDED_BY(mCallbackLock);
    OnPropertySetErrorCallback mOnPropertySetErrorCallback GUARDED_BY(mCallbackLock);

    void init(std::shared_ptr<VehiclePropValuePool> valuePool);
    // 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.
    void onValueChangeCallback(
            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
    // If property "persist.vendor.vhal_init_value_override" is set to true, override the properties
    // using config files in 'overrideDir'.
    void maybeOverrideProperties(const char* overrideDir);
    // Override the properties using config files in 'overrideDir'.
    void overrideProperties(const char* overrideDir);
};

}  // namespace fake
+48 −0
Original line number Diff line number Diff line
@@ -17,11 +17,17 @@
#include "FakeVehicleHardware.h"

#include <DefaultConfig.h>
#include <JsonFakeValueGenerator.h>
#include <VehicleHalTypes.h>
#include <VehicleUtils.h>
#include <android-base/properties.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>

#include <dirent.h>
#include <sys/types.h>
#include <fstream>
#include <regex>
#include <vector>

namespace android {
@@ -30,6 +36,8 @@ namespace automotive {
namespace vehicle {
namespace fake {

namespace {

using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
@@ -40,6 +48,11 @@ using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;

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

}  // namespace

void FakeVehicleHardware::storePropInitialValue(const defaultconfig::ConfigDeclaration& config) {
    const VehiclePropConfig& vehiclePropConfig = config.config;
    int propId = vehiclePropConfig.prop;
@@ -99,6 +112,8 @@ void FakeVehicleHardware::init(std::shared_ptr<VehiclePropValuePool> valuePool)
        storePropInitialValue(it);
    }

    maybeOverrideProperties(VENDOR_OVERRIDE_DIR);

    mServerSidePropStore->setOnValueChangeCallback(
            [this](const VehiclePropValue& value) { return onValueChangeCallback(value); });
}
@@ -201,6 +216,39 @@ void FakeVehicleHardware::onValueChangeCallback(const VehiclePropValue& value) {
    }
}

void FakeVehicleHardware::maybeOverrideProperties(const char* overrideDir) {
    if (android::base::GetBoolProperty(OVERRIDE_PROPERTY, false)) {
        overrideProperties(overrideDir);
    }
}

void FakeVehicleHardware::overrideProperties(const char* overrideDir) {
    ALOGI("loading vendor override properties from %s", overrideDir);
    if (auto dir = opendir(overrideDir); dir != NULL) {
        std::regex regJson(".*[.]json", std::regex::icase);
        while (auto f = readdir(dir)) {
            if (!std::regex_match(f->d_name, regJson)) {
                continue;
            }
            std::string file = overrideDir + std::string(f->d_name);
            JsonFakeValueGenerator tmpGenerator(file);

            std::vector<VehiclePropValue> propValues = tmpGenerator.getAllEvents();
            for (const VehiclePropValue& prop : propValues) {
                auto propToStore = mValuePool->obtain(prop);
                propToStore->timestamp = elapsedRealtimeNano();
                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());
                }
            }
        }
        closedir(dir);
    }
}

}  // namespace fake
}  // namespace vehicle
}  // namespace automotive
+12 −0
Original line number Diff line number Diff line
@@ -29,9 +29,21 @@ cc_test {
    static_libs: [
        "VehicleHalUtils",
        "FakeVehicleHardware",
        "FakeVehicleHalValueGenerators",
        "libgtest",
        "libgmock",
    ],
    shared_libs: [
        "libjsoncpp",
    ],
    data: [
        ":FakeVehicleHardwareTestOverrideJson",
    ],
    defaults: ["VehicleHalDefaults"],
    test_suites: ["device-tests"],
}

filegroup {
    name: "FakeVehicleHardwareTestOverrideJson",
    srcs: ["override/*"],
}
+156 −1
Original line number Diff line number Diff line
@@ -16,16 +16,21 @@

#include <DefaultConfig.h>
#include <FakeVehicleHardware.h>

#include <android-base/expected.h>
#include <android-base/file.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>

#include <inttypes.h>

namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace fake {

namespace {

using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
@@ -38,6 +43,8 @@ using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
using ::android::base::expected;
using ::android::base::unexpected;
using ::testing::ContainerEq;
using ::testing::Eq;
using ::testing::WhenSortedBy;
@@ -46,6 +53,17 @@ constexpr int INVALID_PROP_ID = 0;

}  // namespace

// A helper class to access private methods for FakeVehicleHardware.
class FakeVehicleHardwareTestHelper {
  public:
    FakeVehicleHardwareTestHelper(FakeVehicleHardware* hardware) { mHardware = hardware; }

    void overrideProperties(const char* overrideDir) { mHardware->overrideProperties(overrideDir); }

  private:
    FakeVehicleHardware* mHardware;
};

class FakeVehicleHardwareTest : public ::testing::Test {
  protected:
    void SetUp() override {}
@@ -64,6 +82,63 @@ class FakeVehicleHardwareTest : public ::testing::Test {
                requests);
    }

    StatusCode setValue(const VehiclePropValue& value) {
        std::vector<SetValueRequest> requests = {
                SetValueRequest{
                        .requestId = 0,
                        .value = value,
                },
        };

        if (StatusCode status = setValues(requests); status != StatusCode::OK) {
            return status;
        }

        const SetValueResult& result = getSetValueResults().back();

        if (result.requestId != 0) {
            ALOGE("request ID mismatch, got %" PRId64 ", expect 0", result.requestId);
            return StatusCode::INTERNAL_ERROR;
        }

        return result.status;
    }

    expected<VehiclePropValue, StatusCode> getValue(const VehiclePropValue& value) {
        std::vector<GetValueRequest> requests = {
                GetValueRequest{
                        .requestId = 0,
                        .prop = value,
                },
        };

        if (StatusCode status = getValues(requests); status != StatusCode::OK) {
            return unexpected(status);
        }

        const GetValueResult& result = getGetValueResults().back();
        if (result.requestId != 0) {
            ALOGE("request ID mismatch, got %" PRId64 ", expect 0", result.requestId);
            return unexpected(StatusCode::INTERNAL_ERROR);
        }

        if (result.status != StatusCode::OK) {
            return unexpected(result.status);
        }

        if (!result.prop.has_value()) {
            ALOGE("%s", "result property is empty");
            return unexpected(StatusCode::INTERNAL_ERROR);
        }

        return result.prop.value();
    }

    template <class T>
    int getStatus(expected<T, StatusCode> result) {
        return toInt(result.error());
    }

    void onSetValues(const std::vector<SetValueResult> results) {
        for (auto& result : results) {
            mSetValueResults.push_back(result);
@@ -424,6 +499,86 @@ TEST_F(FakeVehicleHardwareTest, testSetStatusMustIgnore) {
    ASSERT_EQ(getGetValueResults()[1].prop->status, VehiclePropertyStatus::AVAILABLE);
}

TEST_F(FakeVehicleHardwareTest, testVendorOverrideProperties) {
    std::string overrideDir = android::base::GetExecutableDirectory() + "/override/";
    // Set vendor override directory.
    FakeVehicleHardwareTestHelper helper(getHardware());
    helper.overrideProperties(overrideDir.c_str());

    // This is the same as the prop in 'gear_selection.json'.
    int gearProp = toInt(VehicleProperty::GEAR_SELECTION);

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

    ASSERT_TRUE(result.ok()) << "expect to get the overridden property ok: " << getStatus(result);
    ASSERT_EQ(static_cast<size_t>(1), result.value().value.int32Values.size());
    ASSERT_EQ(8, result.value().value.int32Values[0]);

    // If we set the value, it should update despite the override.
    ASSERT_EQ(setValue(VehiclePropValue{
                      .prop = gearProp,
                      .value =
                              {
                                      .int32Values = {5},
                              },
                      .timestamp = elapsedRealtimeNano(),
              }),
              StatusCode::OK)
            << "expect to set the overridden property ok";

    result = getValue(VehiclePropValue{
            .prop = gearProp,
    });

    ASSERT_TRUE(result.ok()) << "expect to get the overridden property after setting value ok";
    ASSERT_EQ(static_cast<size_t>(1), result.value().value.int32Values.size());
    ASSERT_EQ(5, result.value().value.int32Values[0]);
}

TEST_F(FakeVehicleHardwareTest, testVendorOverridePropertiesMultipleAreas) {
    std::string overrideDir = android::base::GetExecutableDirectory() + "/override/";
    // Set vendor override directory.
    FakeVehicleHardwareTestHelper helper(getHardware());
    helper.overrideProperties(overrideDir.c_str());

    // This is the same as the prop in 'hvac_temperature_set.json'.
    int hvacProp = toInt(VehicleProperty::HVAC_TEMPERATURE_SET);

    auto result = getValue(VehiclePropValue{
            .prop = hvacProp,
            .areaId = HVAC_LEFT,
    });

    ASSERT_TRUE(result.ok()) << "expect to get the overridden property ok: " << getStatus(result);
    ASSERT_EQ(static_cast<size_t>(1), result.value().value.floatValues.size());
    ASSERT_EQ(30.0f, result.value().value.floatValues[0]);

    // HVAC_RIGHT should not be affected and return the default value.
    result = getValue(VehiclePropValue{
            .prop = hvacProp,
            .areaId = HVAC_RIGHT,
    });

    ASSERT_TRUE(result.ok()) << "expect to get the default property ok: " << getStatus(result);
    ASSERT_EQ(static_cast<size_t>(1), result.value().value.floatValues.size());
    ASSERT_EQ(20.0f, result.value().value.floatValues[0]);
}

TEST_F(FakeVehicleHardwareTest, testVendorOverridePropertiesDirDoesNotExist) {
    // Set vendor override directory to a non-existing dir
    FakeVehicleHardwareTestHelper helper(getHardware());
    helper.overrideProperties("123");
    auto result = getValue(VehiclePropValue{
            .prop = toInt(VehicleProperty::GEAR_SELECTION),
    });

    ASSERT_TRUE(result.ok()) << "expect to get the default property ok: " << getStatus(result);
    ASSERT_EQ(static_cast<size_t>(1), result.value().value.int32Values.size());
    ASSERT_EQ(4, result.value().value.int32Values[0]);
}

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