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

Commit aa9f3ae1 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 8429428 from 9c15ed74 to tm-release

Change-Id: I420bf930b48013d4111859c2250fb6ce8458a784
parents ae8d49f7 9c15ed74
Loading
Loading
Loading
Loading
+42 −4
Original line number Diff line number Diff line
@@ -90,6 +90,14 @@ interface IVehicle {
     * area ID) are not allowed in a single call. This function must return
     * {@link StatusCode#INVALID_ARG} for duplicate properties.
     *
     * The {@link VehiclePropValue#timestamp} field in request is ignored. The
     * {@link VehiclePropValue#timestamp} field in {@link GetValueResult} must
     * be the system uptime since boot when the value changes for
     * ON_CHANGE property or when the value is checked according to polling rate
     * for CONTINUOUS property. Note that for CONTINUOUS property, VHAL client
     * reading the property multiple times between the polling interval will get
     * the same timestamp.
     *
     * @param callback A callback interface, whose 'onGetValues' would be called
     *    after the value is fetched. Caller should use
     *    {@code android-automotive-large-parcelable} library to parse the
@@ -104,7 +112,7 @@ interface IVehicle {
     * Set vehicle property values.
     *
     * The {@link IVehicleCallback#onSetValues} function would be called after
     * the values set request are sent through vehicle bus or are failed to set.
     * the values set request are sent through vehicle bus or failed to set.
     * If the bus protocol supports confirmation, the callback would be called
     * after getting the confirmation.
     *
@@ -152,11 +160,36 @@ interface IVehicle {
     * Clients must be able to subscribe to multiple properties at a time
     * depending on data provided in options argument.
     *
     * For one callback, the is only one subscription for one property.
     * For one callback, there is only one subscription for one property.
     * A new subscription with a different sample rate would override the old
     * subscription. One property could be subscribed multiple times for
     * different callbacks.
     *
     * If error is returned, some of the properties failed to subscribe.
     * Caller is safe to try again, since subscribing to an already subscribed
     * property is okay.
     *
     * The specified sample rate is just a guidance. It is not guaranteed that
     * the sample rate is achievable depending on how the polling refresh rate
     * is. The actual property event rate might be higher/lower than the
     * specified sampleRate, for example, if the polling rate can be 5 times/s
     * or 10 times/s, subscribing to a sample rate of 7 might use the 5 times/s
     * polling rate, thus generating 5 events/s. We only require that on
     * average, the {@code minSampleRate} and {@code maxSampleRate} can be
     * achieved, all the sampleRate within min and max would on average
     * generates events with rate >= {@code minSampleRate} and <=
     * {@code maxSampleRate}.
     *
     * The {@link VehiclePropValue#timestamp} field for each property event must
     * be the system uptime since boot when the value changes for
     * ON_CHANGE property or when the value is checked according to polling rate
     * for CONTINUOUS property. Note that for CONTINUOUS property, VHAL client
     * reading the property multiple times between the polling interval will get
     * the same timestamp.
     * For example, if the polling rate for a property is 10 times/s, no matter
     * what the sampleRate specified in {@code options}, the timestamp for
     * the timestamp is updated 10 times/s.
     *
     * @param callback The subscription callbacks.
     *    {@link IVehicleCallback#onPropertyEvent} would be called when a new
     *    property event arrives.
@@ -189,8 +222,13 @@ interface IVehicle {
    /**
     * Unsubscribes from property events.
     *
     * If 'callback' is not valid or 'propIds' were not subscribed for this
     * 'callback', this method must return {@link StatusCode#INVALID_ARG}.
     * If 'callback' is not valid this method must return
     * {@link StatusCode#INVALID_ARG}. If a specified propId was not subscribed
     * before, this method must ignore that propId.
     *
     * If error is returned, some of the properties failed to unsubscribe.
     * Caller is safe to try again, since unsubscribing an already unsubscribed
     * property is okay.
     *
     * @param callback The callback used in the previous subscription.
     * @param propIds The IDs for the properties to unsubscribe.
+12 −5
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <FakeObd2Frame.h>
#include <FakeUserHal.h>
#include <IVehicleHardware.h>
#include <RecurrentTimer.h>
#include <VehicleHalTypes.h>
#include <VehiclePropertyStore.h>
#include <android-base/parseint.h>
@@ -82,6 +83,10 @@ class FakeVehicleHardware : public IVehicleHardware {
    void registerOnPropertySetErrorEvent(
            std::unique_ptr<const PropertySetErrorCallback> callback) override;

    // Update the sample rate for the [propId, areaId] pair.
    aidl::android::hardware::automotive::vehicle::StatusCode updateSampleRate(
            int32_t propId, int32_t areaId, float sampleRate) override;

  protected:
    // mValuePool is also used in mServerSidePropStore.
    const std::shared_ptr<VehiclePropValuePool> mValuePool;
@@ -99,11 +104,13 @@ class FakeVehicleHardware : public IVehicleHardware {

    const std::unique_ptr<obd2frame::FakeObd2Frame> mFakeObd2Frame;
    const std::unique_ptr<FakeUserHal> mFakeUserHal;
    std::mutex mCallbackLock;
    std::unique_ptr<const PropertyChangeCallback> mOnPropertyChangeCallback
            GUARDED_BY(mCallbackLock);
    std::unique_ptr<const PropertySetErrorCallback> mOnPropertySetErrorCallback
            GUARDED_BY(mCallbackLock);
    // RecurrentTimer is thread-safe.
    std::unique_ptr<RecurrentTimer> mRecurrentTimer;
    std::mutex mLock;
    std::unique_ptr<const PropertyChangeCallback> mOnPropertyChangeCallback GUARDED_BY(mLock);
    std::unique_ptr<const PropertySetErrorCallback> mOnPropertySetErrorCallback GUARDED_BY(mLock);
    std::unordered_map<PropIdAreaId, std::shared_ptr<RecurrentTimer::Callback>, PropIdAreaIdHash>
            mRecurrentActions GUARDED_BY(mLock);

    void init();
    // Stores the initial value to property store.
+46 −10
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ using ::android::base::EqualsIgnoreCase;
using ::android::base::Error;
using ::android::base::ParseFloat;
using ::android::base::Result;
using ::android::base::ScopedLockAssertion;
using ::android::base::StartsWith;
using ::android::base::StringPrintf;

@@ -131,18 +132,14 @@ void FakeVehicleHardware::storePropInitialValue(const defaultconfig::ConfigDecla
}

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

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

@@ -837,18 +834,57 @@ StatusCode FakeVehicleHardware::checkHealth() {

void FakeVehicleHardware::registerOnPropertyChangeEvent(
        std::unique_ptr<const PropertyChangeCallback> callback) {
    std::scoped_lock<std::mutex> lockGuard(mCallbackLock);
    std::scoped_lock<std::mutex> lockGuard(mLock);
    mOnPropertyChangeCallback = std::move(callback);
}

void FakeVehicleHardware::registerOnPropertySetErrorEvent(
        std::unique_ptr<const PropertySetErrorCallback> callback) {
    std::scoped_lock<std::mutex> lockGuard(mCallbackLock);
    std::scoped_lock<std::mutex> lockGuard(mLock);
    mOnPropertySetErrorCallback = std::move(callback);
}

StatusCode FakeVehicleHardware::updateSampleRate(int32_t propId, int32_t areaId, float sampleRate) {
    // DefaultVehicleHal makes sure that sampleRate must be within minSampleRate and maxSampleRate.
    // For fake implementation, we would write the same value with a new timestamp into propStore
    // at sample rate.
    std::scoped_lock<std::mutex> lockGuard(mLock);

    PropIdAreaId propIdAreaId{
            .propId = propId,
            .areaId = areaId,
    };
    if (mRecurrentActions.find(propIdAreaId) != mRecurrentActions.end()) {
        mRecurrentTimer->unregisterTimerCallback(mRecurrentActions[propIdAreaId]);
    }
    if (sampleRate == 0) {
        return StatusCode::OK;
    }
    int64_t interval = static_cast<int64_t>(1'000'000'000. / sampleRate);
    auto action = std::make_shared<RecurrentTimer::Callback>([this, propId, areaId] {
        // Refresh the property value. In real implementation, this should poll the latest value
        // from vehicle bus. Here, we are just refreshing the existing value with a new timestamp.
        auto result = getValue(VehiclePropValue{
                .prop = propId,
                .areaId = areaId,
        });
        if (!result.ok()) {
            // Failed to read current value, skip refreshing.
            return;
        }
        result.value()->timestamp = elapsedRealtimeNano();
        // Must remove the value before writing, otherwise, we would generate no update event since
        // the value is the same.
        mServerSidePropStore->removeValue(*result.value());
        mServerSidePropStore->writeValue(std::move(result.value()));
    });
    mRecurrentTimer->registerTimerCallback(interval, action);
    mRecurrentActions[propIdAreaId] = action;
    return StatusCode::OK;
}

void FakeVehicleHardware::onValueChangeCallback(const VehiclePropValue& value) {
    std::scoped_lock<std::mutex> lockGuard(mCallbackLock);
    std::scoped_lock<std::mutex> lockGuard(mLock);

    if (mOnPropertyChangeCallback == nullptr) {
        return;
+80 −7
Original line number Diff line number Diff line
@@ -25,12 +25,15 @@
#include <android-base/expected.h>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>

#include <inttypes.h>
#include <chrono>
#include <condition_variable>
#include <vector>

namespace android {
@@ -53,6 +56,7 @@ 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::ScopedLockAssertion;
using ::android::base::StringPrintf;
using ::android::base::unexpected;
using ::testing::ContainerEq;
@@ -60,6 +64,8 @@ using ::testing::ContainsRegex;
using ::testing::Eq;
using ::testing::WhenSortedBy;

using std::chrono::milliseconds;

constexpr int INVALID_PROP_ID = 0;
constexpr char CAR_MAKE[] = "Default Car";

@@ -158,30 +164,65 @@ class FakeVehicleHardwareTest : public ::testing::Test {
    }

    void onSetValues(std::vector<SetValueResult> results) {
        std::scoped_lock<std::mutex> lockGuard(mLock);
        for (auto& result : results) {
            mSetValueResults.push_back(result);
        }
    }

    const std::vector<SetValueResult>& getSetValueResults() { return mSetValueResults; }
    const std::vector<SetValueResult>& getSetValueResults() {
        std::scoped_lock<std::mutex> lockGuard(mLock);
        return mSetValueResults;
    }

    void onGetValues(std::vector<GetValueResult> results) {
        std::scoped_lock<std::mutex> lockGuard(mLock);
        for (auto& result : results) {
            mGetValueResults.push_back(result);
        }
    }

    const std::vector<GetValueResult>& getGetValueResults() { return mGetValueResults; }
    const std::vector<GetValueResult>& getGetValueResults() {
        std::scoped_lock<std::mutex> lockGuard(mLock);
        return mGetValueResults;
    }

    void onPropertyChangeEvent(std::vector<VehiclePropValue> values) {
        std::scoped_lock<std::mutex> lockGuard(mLock);
        for (auto& value : values) {
            mChangedProperties.push_back(value);
            PropIdAreaId propIdAreaId{
                    .propId = value.prop,
                    .areaId = value.areaId,
            };
            mEventCount[propIdAreaId]++;
        }
        mCv.notify_one();
    }

    const std::vector<VehiclePropValue>& getChangedProperties() {
        std::scoped_lock<std::mutex> lockGuard(mLock);
        return mChangedProperties;
    }

    const std::vector<VehiclePropValue>& getChangedProperties() { return mChangedProperties; }
    bool waitForChangedProperties(int32_t propId, int32_t areaId, size_t count,
                                  milliseconds timeout) {
        PropIdAreaId propIdAreaId{
                .propId = propId,
                .areaId = areaId,
        };
        std::unique_lock<std::mutex> lk(mLock);
        return mCv.wait_for(lk, timeout, [this, propIdAreaId, count] {
            ScopedLockAssertion lockAssertion(mLock);
            return mEventCount[propIdAreaId] >= count;
        });
    }

    void clearChangedProperties() { mChangedProperties.clear(); }
    void clearChangedProperties() {
        std::scoped_lock<std::mutex> lockGuard(mLock);
        mEventCount.clear();
        mChangedProperties.clear();
    }

    static void addSetValueRequest(std::vector<SetValueRequest>& requests,
                                   std::vector<SetValueResult>& expectedResults, int64_t requestId,
@@ -246,11 +287,14 @@ class FakeVehicleHardwareTest : public ::testing::Test {

  private:
    FakeVehicleHardware mHardware;
    std::vector<SetValueResult> mSetValueResults;
    std::vector<GetValueResult> mGetValueResults;
    std::vector<VehiclePropValue> mChangedProperties;
    std::shared_ptr<IVehicleHardware::SetValuesCallback> mSetValuesCallback;
    std::shared_ptr<IVehicleHardware::GetValuesCallback> mGetValuesCallback;
    std::condition_variable mCv;
    std::mutex mLock;
    std::unordered_map<PropIdAreaId, size_t, PropIdAreaIdHash> mEventCount GUARDED_BY(mLock);
    std::vector<SetValueResult> mSetValueResults GUARDED_BY(mLock);
    std::vector<GetValueResult> mGetValueResults GUARDED_BY(mLock);
    std::vector<VehiclePropValue> mChangedProperties GUARDED_BY(mLock);
};

TEST_F(FakeVehicleHardwareTest, testGetAllPropertyConfigs) {
@@ -1510,6 +1554,35 @@ TEST_F(FakeVehicleHardwareTest, testGetEchoReverseBytes) {
    ASSERT_EQ(result.value().value.byteValues, std::vector<uint8_t>({0x04, 0x03, 0x02, 0x01}));
}

TEST_F(FakeVehicleHardwareTest, testUpdateSampleRate) {
    int32_t propSpeed = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
    int32_t propSteering = toInt(VehicleProperty::PERF_STEERING_ANGLE);
    int32_t areaId = 0;
    getHardware()->updateSampleRate(propSpeed, areaId, 5);

    ASSERT_TRUE(waitForChangedProperties(propSpeed, areaId, /*count=*/5, milliseconds(1500)))
            << "not enough events generated for speed";

    getHardware()->updateSampleRate(propSteering, areaId, 10);

    ASSERT_TRUE(waitForChangedProperties(propSteering, areaId, /*count=*/10, milliseconds(1500)))
            << "not enough events generated for steering";

    int64_t timestamp = elapsedRealtimeNano();
    // Disable refreshing for propSpeed.
    getHardware()->updateSampleRate(propSpeed, areaId, 0);
    clearChangedProperties();

    ASSERT_TRUE(waitForChangedProperties(propSteering, areaId, /*count=*/5, milliseconds(1500)))
            << "should still receive steering events after disable polling for speed";
    auto updatedValues = getChangedProperties();
    for (auto& value : updatedValues) {
        ASSERT_GE(value.timestamp, timestamp);
        ASSERT_EQ(value.prop, propSteering);
        ASSERT_EQ(value.areaId, areaId);
    }
}

}  // namespace fake
}  // namespace vehicle
}  // namespace automotive
+29 −0
Original line number Diff line number Diff line
@@ -80,6 +80,35 @@ class IVehicleHardware {
            const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&
                    requests) const = 0;

    // Update the sampling rate for the specified property and the specified areaId (0 for global
    // property) if server supports it. The property must be a continuous property.
    // {@code sampleRate} means that for this specific property, the server must generate at least
    // this many OnPropertyChange events per seconds.
    // A sampleRate of 0 means the property is no longer subscribed and server does not need to
    // generate any onPropertyEvent for this property.
    // This would be called if sample rate is updated for a subscriber, a new subscriber is added
    // or an existing subscriber is removed. For example:
    // 1. We have no subscriber for speed.
    // 2. A new subscriber is subscribing speed for 10 times/s, updsateSampleRate would be called
    //    with sampleRate as 10. The impl is now polling vehicle speed from bus 10 times/s.
    // 3. A new subscriber is subscribing speed for 5 times/s, because it is less than 10
    //    times/sec, updateSampleRate would not be called.
    // 4. The initial subscriber is removed, updateSampleRate would be called with sampleRate as
    //    5, because now it only needs to report event 5times/sec. The impl can now poll vehicle
    //    speed 5 times/s. If the impl is still polling at 10 times/s, that is okay as long as
    //    the polling rate is larger than 5times/s. DefaultVehicleHal would ignore the additional
    //    events.
    // 5. The second subscriber is removed, updateSampleRate would be called with sampleRate as 0.
    //    The impl can optionally disable the polling for vehicle speed.
    //
    // If the impl is always polling at {@code maxSampleRate} as specified in config, then this
    // function can be a no-op.
    virtual aidl::android::hardware::automotive::vehicle::StatusCode updateSampleRate(
            [[maybe_unused]] int32_t propId, [[maybe_unused]] int32_t areaId,
            [[maybe_unused]] float sampleRate) {
        return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
    }

    // Dump debug information in the server.
    virtual DumpResult dump(const std::vector<std::string>& options) = 0;

Loading