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

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

Merge "Add on-value-change callback to propstore."

parents 5c289a70 f527463e
Loading
Loading
Loading
Loading
+13 −3
Original line number Diff line number Diff line
@@ -40,11 +40,17 @@ namespace vehicle {
// to get value for all areas for particular property.
//
// This class is thread-safe, however it uses blocking synchronization across all methods.
class VehiclePropertyStore {
class VehiclePropertyStore final {
  public:
    explicit VehiclePropertyStore(std::shared_ptr<VehiclePropValuePool> valuePool)
        : mValuePool(valuePool) {}

    ~VehiclePropertyStore();

    // Callback when a property value has been updated or a new value added.
    using OnValueChangeCallback = std::function<void(
            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue&)>;

    // Function that used to calculate unique token for given VehiclePropValue.
    using TokenFunction = ::std::function<int64_t(
            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value)>;
@@ -97,6 +103,9 @@ class VehiclePropertyStore {
            const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig*>
    getConfig(int32_t propId) const;

    // Set a callback that would be called when a property value has been updated.
    void setOnValueChangeCallback(const OnValueChangeCallback& callback);

  private:
    struct RecordId {
        int32_t area;
@@ -117,10 +126,11 @@ class VehiclePropertyStore {
        std::unordered_map<RecordId, VehiclePropValuePool::RecyclableType, RecordIdHash> values;
    };

    mutable std::mutex mLock;
    std::unordered_map<int32_t, Record> mRecordsByPropId GUARDED_BY(mLock);
    // {@code VehiclePropValuePool} is thread-safe.
    std::shared_ptr<VehiclePropValuePool> mValuePool;
    mutable std::mutex mLock;
    std::unordered_map<int32_t, Record> mRecordsByPropId GUARDED_BY(mLock);
    OnValueChangeCallback mOnValueChangeCallback GUARDED_BY(mLock);

    const Record* getRecordLocked(int32_t propId) const;

+38 −19
Original line number Diff line number Diff line
@@ -49,6 +49,14 @@ size_t VehiclePropertyStore::RecordIdHash::operator()(RecordId const& recordId)
    return res;
}

VehiclePropertyStore::~VehiclePropertyStore() {
    std::lock_guard<std::mutex> lockGuard(mLock);

    // Recycling record requires mValuePool, so need to recycle them before destroying mValuePool.
    mRecordsByPropId.clear();
    mValuePool.reset();
}

const VehiclePropertyStore::Record* VehiclePropertyStore::getRecordLocked(int32_t propId) const
        REQUIRES(mLock) {
    auto RecordIt = mRecordsByPropId.find(propId);
@@ -75,12 +83,11 @@ VehiclePropertyStore::RecordId VehiclePropertyStore::getRecordIdLocked(

Result<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readValueLocked(
        const RecordId& recId, const Record& record) const REQUIRES(mLock) {
    auto it = record.values.find(recId);
    if (it == record.values.end()) {
        return Errorf("Record ID: {} is not found", recId.toString());
    }
    if (auto it = record.values.find(recId); it != record.values.end()) {
        return mValuePool->obtain(*(it->second));
    }
    return Errorf("Record ID: {} is not found", recId.toString());
}

void VehiclePropertyStore::registerProperty(const VehiclePropConfig& config,
                                            VehiclePropertyStore::TokenFunction tokenFunc) {
@@ -108,26 +115,31 @@ Result<void> VehiclePropertyStore::writeValue(VehiclePropValuePool::RecyclableTy
    }

    VehiclePropertyStore::RecordId recId = getRecordIdLocked(*propValue, *record);
    auto it = record->values.find(recId);
    if (it == record->values.end()) {
        record->values[recId] = std::move(propValue);
        if (!updateStatus) {
            record->values[recId]->status = VehiclePropertyStatus::AVAILABLE;
        }
        return {};
    }
    bool valueUpdated = true;
    if (auto it = record->values.find(recId); it != record->values.end()) {
        const VehiclePropValue* valueToUpdate = it->second.get();
    long oldTimestamp = valueToUpdate->timestamp;
        int64_t oldTimestamp = valueToUpdate->timestamp;
        VehiclePropertyStatus oldStatus = valueToUpdate->status;
        // propValue is outdated and drops it.
        if (oldTimestamp > propValue->timestamp) {
            return Errorf("outdated timestamp: {:d}", propValue->timestamp);
        }
    record->values[recId] = std::move(propValue);
        if (!updateStatus) {
        record->values[recId]->status = oldStatus;
            propValue->status = oldStatus;
        }

        valueUpdated = (valueToUpdate->value != propValue->value ||
                        valueToUpdate->status != propValue->status ||
                        valueToUpdate->prop != propValue->prop ||
                        valueToUpdate->areaId != propValue->areaId);
    } else if (!updateStatus) {
        propValue->status = VehiclePropertyStatus::AVAILABLE;
    }

    record->values[recId] = std::move(propValue);
    if (valueUpdated && mOnValueChangeCallback != nullptr) {
        mOnValueChangeCallback(*(record->values[recId]));
    }
    return {};
}

@@ -236,6 +248,13 @@ Result<const VehiclePropConfig*> VehiclePropertyStore::getConfig(int32_t propId)
    return &record->propConfig;
}

void VehiclePropertyStore::setOnValueChangeCallback(
        const VehiclePropertyStore::OnValueChangeCallback& callback) {
    std::lock_guard<std::mutex> g(mLock);

    mOnValueChangeCallback = callback;
}

}  // namespace vehicle
}  // namespace automotive
}  // namespace hardware
+51 −0
Original line number Diff line number Diff line
@@ -382,6 +382,57 @@ TEST_F(VehiclePropertyStoreTest, testWriteValueNoUpdateStatusForNewValue) {
    ASSERT_EQ(result.value()->status, VehiclePropertyStatus::AVAILABLE);
}

TEST_F(VehiclePropertyStoreTest, testPropertyChangeCallbackNewValue) {
    VehiclePropValue updatedValue;
    mStore->setOnValueChangeCallback(
            [&updatedValue](const VehiclePropValue& value) { updatedValue = value; });
    VehiclePropValue fuelCapacity = {
            .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
            .value = {.floatValues = {1.0}},
    };
    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));

    ASSERT_EQ(updatedValue, fuelCapacity);
}

TEST_F(VehiclePropertyStoreTest, testPropertyChangeCallbackUpdateValue) {
    VehiclePropValue updatedValue;
    VehiclePropValue fuelCapacity = {
            .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
            .value = {.floatValues = {1.0}},
    };
    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));

    mStore->setOnValueChangeCallback(
            [&updatedValue](const VehiclePropValue& value) { updatedValue = value; });

    fuelCapacity.value.floatValues[0] = 2.0;
    fuelCapacity.timestamp = 1;

    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));

    ASSERT_EQ(updatedValue, fuelCapacity);
}

TEST_F(VehiclePropertyStoreTest, testPropertyChangeCallbackNoUpdate) {
    VehiclePropValue updatedValue{
            .prop = INVALID_PROP_ID,
    };
    VehiclePropValue fuelCapacity = {
            .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
            .value = {.floatValues = {1.0}},
    };
    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));

    mStore->setOnValueChangeCallback(
            [&updatedValue](const VehiclePropValue& value) { updatedValue = value; });

    // Write the same value again should succeed but should not trigger callback.
    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));

    ASSERT_EQ(updatedValue.prop, INVALID_PROP_ID);
}

}  // namespace vehicle
}  // namespace automotive
}  // namespace hardware