Override subscribe/unsubscribe.
Override subscribe/unsubscribe in FakeVehicleHardware, now it will only
generate property change events for subscribed properties.
Test: atest DefaultVehicleHalTest android.car.cts.CarPropertyManagerTest
Bug: 306262618
Change-Id: Ice39f059820d4ec6039acb4daf9975514f2eb22b
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index 844bea5..6115c49 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -91,9 +91,13 @@
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;
+ // Subscribe to a new [propId, areaId] or change the update rate.
+ aidl::android::hardware::automotive::vehicle::StatusCode subscribe(
+ aidl::android::hardware::automotive::vehicle::SubscribeOptions options) override;
+
+ // Unsubscribe to a [propId, areaId].
+ aidl::android::hardware::automotive::vehicle::StatusCode unsubscribe(int32_t propId,
+ int32_t areaId) override;
protected:
// mValuePool is also used in mServerSidePropStore.
@@ -154,6 +158,7 @@
mRecurrentActions GUARDED_BY(mLock);
std::unordered_map<PropIdAreaId, VehiclePropValuePool::RecyclableType, PropIdAreaIdHash>
mSavedProps GUARDED_BY(mLock);
+ std::unordered_set<PropIdAreaId, PropIdAreaIdHash> mSubOnChangePropIdAreaIds GUARDED_BY(mLock);
// PendingRequestHandler is thread-safe.
mutable PendingRequestHandler<GetValuesCallback,
aidl::android::hardware::automotive::vehicle::GetValueRequest>
@@ -176,7 +181,8 @@
void storePropInitialValue(const 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);
+ const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value)
+ EXCLUDES(mLock);
// Load the config files in format '*.json' from the directory and parse the config files
// into a map from property ID to ConfigDeclarations.
void loadPropConfigsFromDir(const std::string& dirPath,
@@ -262,6 +268,11 @@
void generateVendorConfigs(
std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>&) const;
+ aidl::android::hardware::automotive::vehicle::StatusCode subscribePropIdAreaIdLocked(
+ int32_t propId, int32_t areaId, float sampleRateHz,
+ aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode changeMode)
+ REQUIRES(mLock);
+
static aidl::android::hardware::automotive::vehicle::VehiclePropValue createHwInputKeyProp(
aidl::android::hardware::automotive::vehicle::VehicleHwKeyInputAction action,
int32_t keyCode, int32_t targetDisplay);
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index ee24fbd..bc66f6d 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -60,6 +60,8 @@
using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::toString;
using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReport;
using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
@@ -67,6 +69,7 @@
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
@@ -1926,43 +1929,85 @@
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);
+StatusCode FakeVehicleHardware::subscribe(SubscribeOptions options) {
+ int32_t propId = options.propId;
+ auto configResult = mServerSidePropStore->getConfig(propId);
+ if (!configResult.ok()) {
+ ALOGE("subscribe: property: %" PRId32 " is not supported", propId);
+ return StatusCode::INVALID_ARG;
+ }
+
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ for (int areaId : options.areaIds) {
+ if (StatusCode status = subscribePropIdAreaIdLocked(propId, areaId, options.sampleRate,
+ configResult.value()->changeMode);
+ status != StatusCode::OK) {
+ return status;
+ }
+ }
+ return StatusCode::OK;
+}
+
+StatusCode FakeVehicleHardware::subscribePropIdAreaIdLocked(int32_t propId, int32_t areaId,
+ float sampleRateHz,
+ VehiclePropertyChangeMode changeMode) {
+ PropIdAreaId propIdAreaId{
+ .propId = propId,
+ .areaId = areaId,
+ };
+ switch (changeMode) {
+ case VehiclePropertyChangeMode::STATIC:
+ ALOGW("subscribe to a static property, do nothing.");
+ return StatusCode::OK;
+ case VehiclePropertyChangeMode::ON_CHANGE:
+ mSubOnChangePropIdAreaIds.insert(std::move(propIdAreaId));
+ return StatusCode::OK;
+ case VehiclePropertyChangeMode::CONTINUOUS:
+ if (sampleRateHz == 0.f) {
+ ALOGE("Must not use sample rate 0 for a continuous property");
+ return StatusCode::INTERNAL_ERROR;
+ }
+ if (mRecurrentActions.find(propIdAreaId) != mRecurrentActions.end()) {
+ mRecurrentTimer->unregisterTimerCallback(mRecurrentActions[propIdAreaId]);
+ }
+ int64_t intervalInNanos = static_cast<int64_t>(1'000'000'000. / sampleRateHz);
+ 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{
+ .areaId = areaId,
+ .prop = propId,
+ .value = {},
+ });
+ if (!result.ok()) {
+ // Failed to read current value, skip refreshing.
+ return;
+ }
+ result.value()->timestamp = elapsedRealtimeNano();
+ // For continuous properties, we must generate a new onPropertyChange event
+ // periodically according to the sample rate.
+ mServerSidePropStore->writeValue(std::move(result.value()), /*updateStatus=*/true,
+ VehiclePropertyStore::EventMode::ALWAYS);
+ });
+ mRecurrentTimer->registerTimerCallback(intervalInNanos, action);
+ mRecurrentActions[propIdAreaId] = action;
+ return StatusCode::OK;
+ }
+}
+
+StatusCode FakeVehicleHardware::unsubscribe(int32_t propId, int32_t areaId) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
PropIdAreaId propIdAreaId{
.propId = propId,
.areaId = areaId,
};
if (mRecurrentActions.find(propIdAreaId) != mRecurrentActions.end()) {
mRecurrentTimer->unregisterTimerCallback(mRecurrentActions[propIdAreaId]);
+ mRecurrentActions.erase(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{
- .areaId = areaId,
- .prop = propId,
- .value = {},
- });
- if (!result.ok()) {
- // Failed to read current value, skip refreshing.
- return;
- }
- result.value()->timestamp = elapsedRealtimeNano();
- // For continuous properties, we must generate a new onPropertyChange event periodically
- // according to the sample rate.
- mServerSidePropStore->writeValue(std::move(result.value()), /*updateStatus=*/true,
- VehiclePropertyStore::EventMode::ALWAYS);
- });
- mRecurrentTimer->registerTimerCallback(interval, action);
- mRecurrentActions[propIdAreaId] = action;
+ mSubOnChangePropIdAreaIds.erase(propIdAreaId);
return StatusCode::OK;
}
@@ -1971,6 +2016,23 @@
return;
}
+ PropIdAreaId propIdAreaId{
+ .propId = value.prop,
+ .areaId = value.areaId,
+ };
+
+ {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ if (mRecurrentActions.find(propIdAreaId) == mRecurrentActions.end() &&
+ mSubOnChangePropIdAreaIds.find(propIdAreaId) == mSubOnChangePropIdAreaIds.end()) {
+ if (FAKE_VEHICLEHARDWARE_DEBUG) {
+ ALOGD("The updated property value: %s is not subscribed, ignore",
+ value.toString().c_str());
+ }
+ return;
+ }
+ }
+
std::vector<VehiclePropValue> updatedValues;
updatedValues.push_back(value);
(*mOnPropertyChangeCallback)(std::move(updatedValues));
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index cf9beee..85eefa4 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -72,6 +72,7 @@
using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReport;
using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateShutdownParam;
@@ -149,6 +150,15 @@
mHardware = std::move(hardware);
}
+ static SubscribeOptions newSubscribeOptions(int32_t propId, int32_t areaId,
+ float sampleRateHz) {
+ SubscribeOptions options;
+ options.areaIds = {areaId};
+ options.propId = propId;
+ options.sampleRate = sampleRateHz;
+ return options;
+ }
+
StatusCode setValues(const std::vector<SetValueRequest>& requests) {
{
std::scoped_lock<std::mutex> lockGuard(mLock);
@@ -336,6 +346,13 @@
return mEventCount[propIdAreaId];
}
+ void subscribe(int32_t propId, int32_t areaId, float sampleRateHz) {
+ ASSERT_EQ(StatusCode::OK,
+ getHardware()->subscribe(newSubscribeOptions(propId, areaId, sampleRateHz)))
+ << "failed to subscribe to propId: " << propId << "areaId: " << areaId
+ << ", sampleRateHz: " << sampleRateHz;
+ }
+
static void addSetValueRequest(std::vector<SetValueRequest>& requests,
std::vector<SetValueResult>& expectedResults, int64_t requestId,
const VehiclePropValue& value, StatusCode expectedStatus) {
@@ -370,24 +387,24 @@
}
std::vector<VehiclePropValue> getTestPropValues() {
- VehiclePropValue fuelCapacity = {
- .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
- .value = {.floatValues = {1.0}},
+ VehiclePropValue oilLevel = {
+ .prop = toInt(VehicleProperty::ENGINE_OIL_LEVEL),
+ .value = {.int32Values = {1}},
};
- VehiclePropValue leftTirePressure = {
- .prop = toInt(VehicleProperty::TIRE_PRESSURE),
+ VehiclePropValue leftHvacTemp = {
+ .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_CURRENT),
.value = {.floatValues = {170.0}},
- .areaId = WHEEL_FRONT_LEFT,
+ .areaId = SEAT_1_LEFT,
};
- VehiclePropValue rightTirePressure = {
- .prop = toInt(VehicleProperty::TIRE_PRESSURE),
+ VehiclePropValue rightHvacTemp = {
+ .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_CURRENT),
.value = {.floatValues = {180.0}},
- .areaId = WHEEL_FRONT_RIGHT,
+ .areaId = SEAT_1_RIGHT,
};
- return {fuelCapacity, leftTirePressure, rightTirePressure};
+ return {oilLevel, leftHvacTemp, rightHvacTemp};
}
struct PropValueCmp {
@@ -559,17 +576,13 @@
ASSERT_THAT(getSetValueResults(), ContainerEq(expectedResults));
}
-TEST_F(FakeVehicleHardwareTest, testRegisterOnPropertyChangeEvent) {
- // We have already registered this callback in Setup, here we are registering again.
- auto callback = std::make_unique<IVehicleHardware::PropertyChangeCallback>(
- [this](const std::vector<VehiclePropValue>& values) { onPropertyChangeEvent(values); });
- getHardware()->registerOnPropertyChangeEvent(std::move(callback));
-
+TEST_F(FakeVehicleHardwareTest, testSetValues_getUpdateEvents) {
auto testValues = getTestPropValues();
std::vector<SetValueRequest> requests;
std::vector<SetValueResult> expectedResults;
int64_t requestId = 1;
for (auto& value : testValues) {
+ subscribe(value.prop, value.areaId, /*sampleRateHz=*/0);
addSetValueRequest(requests, expectedResults, requestId++, value, StatusCode::OK);
}
int64_t timestamp = elapsedRealtimeNano();
@@ -1624,27 +1637,30 @@
return info.param.name;
});
-TEST_F(FakeVehicleHardwareTest, testSetWaitForVhalAfterCarServiceCrash) {
- int32_t propId = toInt(VehicleProperty::AP_POWER_STATE_REPORT);
+TEST_F(FakeVehicleHardwareTest, testSetWaitForVhal_alwaysTriggerEvents) {
+ int32_t powerReq = toInt(VehicleProperty::AP_POWER_STATE_REQ);
+ subscribe(powerReq, /*areaId*/ 0, /*sampleRateHz*/ 0);
+
+ int32_t powerReport = toInt(VehicleProperty::AP_POWER_STATE_REPORT);
VehiclePropValue request = VehiclePropValue{
- .prop = propId,
+ .prop = powerReport,
.value.int32Values = {toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL)},
};
- ASSERT_EQ(setValue(request), StatusCode::OK) << "failed to set property " << propId;
+ ASSERT_EQ(setValue(request), StatusCode::OK) << "failed to set property " << powerReport;
// Clear existing events.
clearChangedProperties();
// Simulate a Car Service crash, Car Service would restart and send the message again.
- ASSERT_EQ(setValue(request), StatusCode::OK) << "failed to set property " << propId;
+ ASSERT_EQ(setValue(request), StatusCode::OK) << "failed to set property " << powerReport;
std::vector<VehiclePropValue> events = getChangedProperties();
// Even though the state is already ON, we should receive another ON event.
- ASSERT_EQ(events.size(), 1u);
+ ASSERT_EQ(events.size(), 1u) << "failed to receive on-change events AP_POWER_STATE_REQ ON";
// Erase the timestamp for comparison.
events[0].timestamp = 0;
auto expectedValue = VehiclePropValue{
- .prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
+ .prop = powerReq,
.status = VehiclePropertyStatus::AVAILABLE,
.value.int32Values = {toInt(VehicleApPowerStateReq::ON), 0},
};
@@ -2015,6 +2031,22 @@
},
},
};
+
+ // First subscribe to all the properties that we will change.
+ for (auto& enabledToErrorStateProps : adasEnabledPropToAdasPropWithErrorState) {
+ std::unordered_set<int32_t> expectedChangedPropIds(enabledToErrorStateProps.second.begin(),
+ enabledToErrorStateProps.second.end());
+ expectedChangedPropIds.insert(enabledToErrorStateProps.first);
+
+ for (int32_t propId : expectedChangedPropIds) {
+ int32_t areaId = 0;
+ if (propId == toInt(VehicleProperty::BLIND_SPOT_WARNING_STATE)) {
+ areaId = toInt(VehicleAreaMirror::DRIVER_LEFT);
+ }
+ subscribe(propId, areaId, /*sampleRateHz*/ 0);
+ }
+ }
+
for (auto& enabledToErrorStateProps : adasEnabledPropToAdasPropWithErrorState) {
int32_t adasEnabledPropertyId = enabledToErrorStateProps.first;
StatusCode status =
@@ -2095,9 +2127,16 @@
}
TEST_F(FakeVehicleHardwareTest, testSwitchUser) {
+ SubscribeOptions options;
+ int32_t propSwitchUser = toInt(VehicleProperty::SWITCH_USER);
+ options.propId = propSwitchUser;
+ options.areaIds = {0, 1};
+ ASSERT_EQ(StatusCode::OK, getHardware()->subscribe(options))
+ << "failed to subscribe to propId: " << propSwitchUser;
+
// This is the same example as used in User HAL Emulation doc.
VehiclePropValue valueToSet = {
- .prop = toInt(VehicleProperty::SWITCH_USER),
+ .prop = propSwitchUser,
.areaId = 1,
.value.int32Values = {666, 3, 2},
};
@@ -2108,7 +2147,7 @@
// Simulate a request from Android side.
VehiclePropValue switchUserRequest = {
- .prop = toInt(VehicleProperty::SWITCH_USER),
+ .prop = propSwitchUser,
.areaId = 0,
.value.int32Values = {666, 3},
};
@@ -2138,7 +2177,7 @@
events[0].timestamp = 0;
auto expectedValue = VehiclePropValue{
.areaId = 0,
- .prop = toInt(VehicleProperty::SWITCH_USER),
+ .prop = propSwitchUser,
.value.int32Values =
{
// Request ID
@@ -2153,6 +2192,13 @@
}
TEST_F(FakeVehicleHardwareTest, testCreateUser) {
+ SubscribeOptions options;
+ int32_t propCreateUser = toInt(VehicleProperty::CREATE_USER);
+ options.propId = propCreateUser;
+ options.areaIds = {0, 1};
+ ASSERT_EQ(StatusCode::OK, getHardware()->subscribe(options))
+ << "failed to subscribe to propId: " << propCreateUser;
+
// This is the same example as used in User HAL Emulation doc.
VehiclePropValue valueToSet = {
.prop = toInt(VehicleProperty::CREATE_USER),
@@ -2166,7 +2212,7 @@
// Simulate a request from Android side.
VehiclePropValue createUserRequest = {
- .prop = toInt(VehicleProperty::CREATE_USER),
+ .prop = propCreateUser,
.areaId = 0,
.value.int32Values = {666},
};
@@ -2195,7 +2241,7 @@
events[0].timestamp = 0;
auto expectedValue = VehiclePropValue{
.areaId = 0,
- .prop = toInt(VehicleProperty::CREATE_USER),
+ .prop = propCreateUser,
.value.int32Values =
{
// Request ID
@@ -2208,9 +2254,16 @@
}
TEST_F(FakeVehicleHardwareTest, testInitialUserInfo) {
+ SubscribeOptions options;
+ int32_t propInitialUserInfo = toInt(VehicleProperty::INITIAL_USER_INFO);
+ options.propId = propInitialUserInfo;
+ options.areaIds = {0, 1};
+ ASSERT_EQ(StatusCode::OK, getHardware()->subscribe(options))
+ << "failed to subscribe to propId: " << propInitialUserInfo;
+
// This is the same example as used in User HAL Emulation doc.
VehiclePropValue valueToSet = {
- .prop = toInt(VehicleProperty::INITIAL_USER_INFO),
+ .prop = propInitialUserInfo,
.areaId = 1,
.value.int32Values = {666, 1, 11},
};
@@ -2221,7 +2274,7 @@
// Simulate a request from Android side.
VehiclePropValue initialUserInfoRequest = {
- .prop = toInt(VehicleProperty::INITIAL_USER_INFO),
+ .prop = propInitialUserInfo,
.areaId = 0,
.value.int32Values = {3},
};
@@ -2238,7 +2291,7 @@
events[0].timestamp = 0;
auto expectedValue = VehiclePropValue{
.areaId = 0,
- .prop = toInt(VehicleProperty::INITIAL_USER_INFO),
+ .prop = propInitialUserInfo,
.value.int32Values = {3, 1, 11},
};
EXPECT_EQ(events[0], expectedValue);
@@ -2253,7 +2306,7 @@
events[0].timestamp = 0;
expectedValue = VehiclePropValue{
.areaId = 0,
- .prop = toInt(VehicleProperty::INITIAL_USER_INFO),
+ .prop = propInitialUserInfo,
.value.int32Values =
{
// Request ID
@@ -2395,13 +2448,14 @@
}
TEST_F(FakeVehicleHardwareTest, testDumpInjectEvent) {
- int32_t prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
+ int32_t prop = toInt(VehicleProperty::ENGINE_OIL_LEVEL);
std::string propIdStr = std::to_string(prop);
+ subscribe(prop, /*areaId*/ 0, /*sampleRateHz*/ 0);
+
int64_t timestamp = elapsedRealtimeNano();
- // Inject an event with float value 123.4 and timestamp.
DumpResult result = getHardware()->dump(
- {"--inject-event", propIdStr, "-f", "123.4", "-t", std::to_string(timestamp)});
+ {"--inject-event", propIdStr, "-i", "1234", "-t", std::to_string(timestamp)});
ASSERT_FALSE(result.callerShouldDumpState);
ASSERT_THAT(result.buffer,
@@ -2412,7 +2466,7 @@
ASSERT_EQ(events.size(), 1u);
auto event = events[0];
ASSERT_EQ(event.timestamp, timestamp);
- ASSERT_EQ(event.value.floatValues, std::vector<float>({123.4}));
+ ASSERT_EQ(event.value.int32Values, std::vector<int32_t>({1234}));
}
TEST_F(FakeVehicleHardwareTest, testDumpInvalidOptions) {
@@ -2755,9 +2809,13 @@
});
TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataLinear) {
- // Start a fake linear data generator for vehicle speed at 0.1s interval.
+ // Start a fake linear data generator for engine oil level at 0.1s interval.
// range: 0 - 100, current value: 30, step: 20.
- std::string propIdString = StringPrintf("%d", toInt(VehicleProperty::PERF_VEHICLE_SPEED));
+ int32_t prop = toInt(VehicleProperty::ENGINE_OIL_LEVEL);
+
+ subscribe(prop, /*areaId*/ 0, /*sampleRateHz*/ 0);
+
+ std::string propIdString = StringPrintf("%d", prop);
std::vector<std::string> options = {"--genfakedata", "--startlinear", propIdString,
/*middleValue=*/"50",
/*currentValue=*/"30",
@@ -2770,15 +2828,14 @@
ASSERT_FALSE(result.callerShouldDumpState);
ASSERT_THAT(result.buffer, HasSubstr("successfully"));
- ASSERT_TRUE(waitForChangedProperties(toInt(VehicleProperty::PERF_VEHICLE_SPEED), 0, /*count=*/5,
- milliseconds(1000)))
+ ASSERT_TRUE(waitForChangedProperties(prop, 0, /*count=*/5, milliseconds(1000)))
<< "not enough events generated for linear data generator";
int32_t value = 30;
auto events = getChangedProperties();
for (size_t i = 0; i < 5; i++) {
- ASSERT_EQ(1u, events[i].value.floatValues.size());
- EXPECT_EQ(static_cast<float>(value), events[i].value.floatValues[0]);
+ ASSERT_EQ(1u, events[i].value.int32Values.size());
+ EXPECT_EQ(value, events[i].value.int32Values[0]);
value = (value + 20) % 100;
}
@@ -2794,7 +2851,7 @@
std::this_thread::sleep_for(std::chrono::milliseconds(200));
// There should be no new events generated.
- EXPECT_EQ(0u, getEventCount(toInt(VehicleProperty::PERF_VEHICLE_SPEED), 0));
+ EXPECT_EQ(0u, getEventCount(prop, 0));
}
std::string getTestFilePath(const char* filename) {
@@ -2803,6 +2860,8 @@
}
TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataJson) {
+ subscribe(toInt(VehicleProperty::GEAR_SELECTION), /*areaId*/ 0, /*sampleRateHz*/ 0);
+
std::vector<std::string> options = {"--genfakedata", "--startjson", "--path",
getTestFilePath("prop.json"), "2"};
@@ -2829,6 +2888,8 @@
}
TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataJsonByContent) {
+ subscribe(toInt(VehicleProperty::GEAR_SELECTION), /*areaId*/ 0, /*sampleRateHz*/ 0);
+
std::vector<std::string> options = {
"--genfakedata", "--startjson", "--content",
"[{\"timestamp\":1000000,\"areaId\":0,\"value\":8,\"prop\":289408000}]", "1"};
@@ -2903,8 +2964,11 @@
}
TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataKeyPress) {
+ int32_t propHwKeyInput = toInt(VehicleProperty::HW_KEY_INPUT);
std::vector<std::string> options = {"--genfakedata", "--keypress", "1", "2"};
+ subscribe(propHwKeyInput, /*areaId*/ 0, /*sampleRateHz*/ 0);
+
DumpResult result = getHardware()->dump(options);
ASSERT_FALSE(result.callerShouldDumpState);
@@ -2912,8 +2976,8 @@
auto events = getChangedProperties();
ASSERT_EQ(2u, events.size());
- EXPECT_EQ(toInt(VehicleProperty::HW_KEY_INPUT), events[0].prop);
- EXPECT_EQ(toInt(VehicleProperty::HW_KEY_INPUT), events[1].prop);
+ EXPECT_EQ(propHwKeyInput, events[0].prop);
+ EXPECT_EQ(propHwKeyInput, events[1].prop);
ASSERT_EQ(3u, events[0].value.int32Values.size());
ASSERT_EQ(3u, events[1].value.int32Values.size());
EXPECT_EQ(toInt(VehicleHwKeyInputAction::ACTION_DOWN), events[0].value.int32Values[0]);
@@ -2925,8 +2989,11 @@
}
TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataKeyInputV2) {
+ int32_t propHwKeyInputV2 = toInt(VehicleProperty::HW_KEY_INPUT_V2);
std::vector<std::string> options = {"--genfakedata", "--keyinputv2", "1", "2", "3", "4", "5"};
+ subscribe(propHwKeyInputV2, /*areaId*/ 1, /*sampleRateHz*/ 0);
+
DumpResult result = getHardware()->dump(options);
ASSERT_FALSE(result.callerShouldDumpState);
@@ -2944,6 +3011,7 @@
}
TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataMotionInput) {
+ int32_t propHwMotionInput = toInt(VehicleProperty::HW_MOTION_INPUT);
std::vector<std::string> options = {"--genfakedata",
"--motioninput",
"1",
@@ -2966,6 +3034,8 @@
"65.5",
"76.6"};
+ subscribe(propHwMotionInput, /*areaId*/ 1, /*sampleRateHz*/ 0);
+
DumpResult result = getHardware()->dump(options);
ASSERT_FALSE(result.callerShouldDumpState);
@@ -2973,7 +3043,7 @@
auto events = getChangedProperties();
ASSERT_EQ(1u, events.size());
- EXPECT_EQ(toInt(VehicleProperty::HW_MOTION_INPUT), events[0].prop);
+ EXPECT_EQ(propHwMotionInput, events[0].prop);
ASSERT_EQ(9u, events[0].value.int32Values.size());
EXPECT_EQ(2, events[0].value.int32Values[0]);
EXPECT_EQ(3, events[0].value.int32Values[1]);
@@ -3014,23 +3084,27 @@
ASSERT_EQ(result.value().value.byteValues, std::vector<uint8_t>({0x04, 0x03, 0x02, 0x01}));
}
-TEST_F(FakeVehicleHardwareTest, testUpdateSampleRate) {
+TEST_F(FakeVehicleHardwareTest, testSubscribeUnsubscribe_continuous) {
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);
+
+ auto status = getHardware()->subscribe(newSubscribeOptions(propSpeed, areaId, 5));
+ ASSERT_EQ(status, StatusCode::OK) << "failed to subscribe";
ASSERT_TRUE(waitForChangedProperties(propSpeed, areaId, /*count=*/5, milliseconds(1500)))
<< "not enough events generated for speed";
- getHardware()->updateSampleRate(propSteering, areaId, 10);
+ status = getHardware()->subscribe(newSubscribeOptions(propSteering, areaId, 10));
+ ASSERT_EQ(status, StatusCode::OK) << "failed to subscribe";
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);
+ status = getHardware()->unsubscribe(propSpeed, areaId);
+ ASSERT_EQ(status, StatusCode::OK) << "failed to unsubscribe";
clearChangedProperties();
ASSERT_TRUE(waitForChangedProperties(propSteering, areaId, /*count=*/5, milliseconds(1500)))
@@ -3043,12 +3117,58 @@
}
}
+TEST_F(FakeVehicleHardwareTest, testSubscribeUnusubscribe_onChange) {
+ int32_t propHvac = toInt(VehicleProperty::HVAC_TEMPERATURE_SET);
+ int32_t areaId = SEAT_1_LEFT;
+
+ auto status = getHardware()->subscribe(newSubscribeOptions(propHvac, areaId, 0));
+ ASSERT_EQ(status, StatusCode::OK) << "failed to subscribe";
+
+ status = setValue({
+ .prop = propHvac,
+ .areaId = areaId,
+ .value.floatValues = {20.0f},
+ });
+ ASSERT_EQ(status, StatusCode::OK) << "failed to set hvac value";
+
+ ASSERT_TRUE(waitForChangedProperties(propHvac, areaId, /*count=*/1, milliseconds(100)))
+ << "not enough on change events generated for hvac";
+ clearChangedProperties();
+
+ status = setValue({
+ .prop = propHvac,
+ .areaId = areaId,
+ .value.floatValues = {21.0f},
+ });
+ ASSERT_EQ(status, StatusCode::OK) << "failed to set hvac value";
+
+ ASSERT_TRUE(waitForChangedProperties(propHvac, areaId, /*count=*/1, milliseconds(100)))
+ << "not enough on change events generated for hvac";
+ clearChangedProperties();
+
+ status = getHardware()->unsubscribe(propHvac, areaId);
+ ASSERT_EQ(status, StatusCode::OK);
+
+ status = setValue({
+ .prop = propHvac,
+ .areaId = areaId,
+ .value.floatValues = {22.0f},
+ });
+ ASSERT_EQ(status, StatusCode::OK) << "failed to set hvac value";
+
+ ASSERT_FALSE(waitForChangedProperties(propHvac, areaId, /*count=*/1, milliseconds(100)))
+ << "must not receive on change events if the propId, areaId is unsubscribed";
+}
+
TEST_F(FakeVehicleHardwareTest, testSetHvacTemperatureValueSuggestion) {
float CELSIUS = static_cast<float>(toInt(VehicleUnit::CELSIUS));
float FAHRENHEIT = static_cast<float>(toInt(VehicleUnit::FAHRENHEIT));
+ int32_t propHvacTempValueSuggest = toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION);
+
+ subscribe(propHvacTempValueSuggest, HVAC_ALL, /*sampleRateHz*/ 0);
VehiclePropValue floatArraySizeFour = {
- .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {0, CELSIUS, 0, 0},
};
@@ -3056,14 +3176,14 @@
EXPECT_EQ(status, StatusCode::OK);
VehiclePropValue floatArraySizeZero = {
- .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
};
status = setValue(floatArraySizeZero);
EXPECT_EQ(status, StatusCode::INVALID_ARG);
VehiclePropValue floatArraySizeFive = {
- .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {0, CELSIUS, 0, 0, 0},
};
@@ -3071,7 +3191,7 @@
EXPECT_EQ(status, StatusCode::INVALID_ARG);
VehiclePropValue invalidUnit = {
- .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {0, 0, 0, 0},
};
@@ -3102,9 +3222,7 @@
.valuesToSet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {minTempInCelsius, CELSIUS, 0, 0},
},
@@ -3112,9 +3230,7 @@
.expectedValuesToGet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {minTempInCelsius, CELSIUS,
minTempInCelsius,
@@ -3127,9 +3243,7 @@
.valuesToSet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {minTempInFahrenheit, FAHRENHEIT,
0, 0},
@@ -3138,9 +3252,7 @@
.expectedValuesToGet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {minTempInFahrenheit, FAHRENHEIT,
minTempInCelsius,
@@ -3153,9 +3265,7 @@
.valuesToSet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {maxTempInCelsius, CELSIUS, 0, 0},
},
@@ -3163,9 +3273,7 @@
.expectedValuesToGet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {maxTempInCelsius, CELSIUS,
maxTempInCelsius,
@@ -3178,9 +3286,7 @@
.valuesToSet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {maxTempInFahrenheit, FAHRENHEIT,
0, 0},
@@ -3189,9 +3295,7 @@
.expectedValuesToGet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {maxTempInFahrenheit, FAHRENHEIT,
maxTempInCelsius,
@@ -3204,9 +3308,7 @@
.valuesToSet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {minTempInCelsius - 1, CELSIUS, 0,
0},
@@ -3215,9 +3317,7 @@
.expectedValuesToGet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {minTempInCelsius - 1, CELSIUS,
minTempInCelsius,
@@ -3230,9 +3330,7 @@
.valuesToSet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {minTempInFahrenheit - 1,
FAHRENHEIT, 0, 0},
@@ -3241,9 +3339,7 @@
.expectedValuesToGet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {minTempInFahrenheit - 1,
FAHRENHEIT, minTempInCelsius,
@@ -3256,9 +3352,7 @@
.valuesToSet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {maxTempInCelsius + 1, CELSIUS, 0,
0},
@@ -3267,9 +3361,7 @@
.expectedValuesToGet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {maxTempInCelsius + 1, CELSIUS,
maxTempInCelsius,
@@ -3282,9 +3374,7 @@
.valuesToSet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {maxTempInFahrenheit + 1,
FAHRENHEIT, 0, 0},
@@ -3293,9 +3383,7 @@
.expectedValuesToGet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {maxTempInFahrenheit + 1,
FAHRENHEIT, maxTempInCelsius,
@@ -3308,9 +3396,7 @@
.valuesToSet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {minTempInCelsius +
incrementInCelsius * 2.5f,
@@ -3320,9 +3406,7 @@
.expectedValuesToGet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues =
{minTempInCelsius + incrementInCelsius * 2.5f,
@@ -3338,9 +3422,7 @@
.valuesToSet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues = {minTempInFahrenheit +
incrementInFahrenheit *
@@ -3351,9 +3433,7 @@
.expectedValuesToGet =
{
VehiclePropValue{
- .prop = toInt(
- VehicleProperty::
- HVAC_TEMPERATURE_VALUE_SUGGESTION),
+ .prop = propHvacTempValueSuggest,
.areaId = HVAC_ALL,
.value.floatValues =
{minTempInFahrenheit +