Vehicle HAL reference impl Part II
Implemented:
- IVehicle::get <-- changed signature
- IVehicle::set
- status_t replaced with StatusCode
- changed error handling to handle errors on SET
Test: unit tests provided
Bug: b/31971746
Change-Id: I9ea3feab7539adf588f1278fb905c0a458fa1627
diff --git a/vehicle/2.0/default/tests/SubscriptionManager_test.cpp b/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
index c3db993..19b11e6 100644
--- a/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
+++ b/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
@@ -50,7 +50,7 @@
{
SubscribeOptions {
.propId = PROP1,
- .vehicleAreas = val(VehicleAreaZone::ROW_1_LEFT),
+ .vehicleAreas = toInt(VehicleAreaZone::ROW_1_LEFT),
.flags = SubscribeFlags::HAL_EVENT
},
});
@@ -67,7 +67,7 @@
{
SubscribeOptions {
.propId = PROP1,
- .vehicleAreas = val(VehicleAreaZone::ROW_1_LEFT),
+ .vehicleAreas = toInt(VehicleAreaZone::ROW_1_LEFT),
.flags = SubscribeFlags::HAL_EVENT
},
SubscribeOptions {
@@ -87,7 +87,7 @@
std::list<sp<HalClient>> clientsToProp1() {
return manager.getSubscribedClients(PROP1,
- val(VehicleAreaZone::ROW_1_LEFT),
+ toInt(VehicleAreaZone::ROW_1_LEFT),
SubscribeFlags::DEFAULT);
}
@@ -104,7 +104,7 @@
auto clients = manager.getSubscribedClients(
PROP1,
- val(VehicleAreaZone::ROW_1_LEFT),
+ toInt(VehicleAreaZone::ROW_1_LEFT),
SubscribeFlags::HAL_EVENT);
ASSERT_ALL_EXISTS({cb1, cb2}, extractCallbacks(clients));
@@ -116,21 +116,21 @@
// Wrong zone
auto clients = manager.getSubscribedClients(
PROP1,
- val(VehicleAreaZone::ROW_2_LEFT),
+ toInt(VehicleAreaZone::ROW_2_LEFT),
SubscribeFlags::HAL_EVENT);
ASSERT_TRUE(clients.empty());
// Wrong prop
clients = manager.getSubscribedClients(
VehicleProperty::AP_POWER_BOOTUP_REASON,
- val(VehicleAreaZone::ROW_1_LEFT),
+ toInt(VehicleAreaZone::ROW_1_LEFT),
SubscribeFlags::HAL_EVENT);
ASSERT_TRUE(clients.empty());
// Wrong flag
clients = manager.getSubscribedClients(
PROP1,
- val(VehicleAreaZone::ROW_1_LEFT),
+ toInt(VehicleAreaZone::ROW_1_LEFT),
SubscribeFlags::SET_CALL);
ASSERT_TRUE(clients.empty());
}
@@ -140,7 +140,7 @@
auto clients = manager.getSubscribedClients(
PROP1,
- val(VehicleAreaZone::ROW_1_LEFT),
+ toInt(VehicleAreaZone::ROW_1_LEFT),
SubscribeFlags::DEFAULT);
ASSERT_EQ((size_t) 1, clients.size());
ASSERT_EQ(cb1, clients.front()->getCallback());
@@ -151,18 +151,18 @@
{
SubscribeOptions {
.propId = PROP1,
- .vehicleAreas = val(VehicleAreaZone::ROW_2),
+ .vehicleAreas = toInt(VehicleAreaZone::ROW_2),
.flags = SubscribeFlags::DEFAULT
}
}));
clients = manager.getSubscribedClients(PROP1,
- val(VehicleAreaZone::ROW_1_LEFT),
+ toInt(VehicleAreaZone::ROW_1_LEFT),
SubscribeFlags::DEFAULT);
ASSERT_ALL_EXISTS({cb1}, extractCallbacks(clients));
clients = manager.getSubscribedClients(PROP1,
- val(VehicleAreaZone::ROW_2),
+ toInt(VehicleAreaZone::ROW_2),
SubscribeFlags::DEFAULT);
ASSERT_ALL_EXISTS({cb1}, extractCallbacks(clients));
}
diff --git a/vehicle/2.0/default/tests/VehicleHalManager_test.cpp b/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
index 1410ddf..6ef1205 100644
--- a/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
+++ b/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
@@ -22,6 +22,7 @@
#include <vehicle_hal_manager/VehiclePropConfigIndex.h>
#include <VehicleHal.h>
#include <vehicle_hal_manager/VehicleHalManager.h>
+#include <utils/SystemClock.h>
#include "vehicle_hal_manager/SubscriptionManager.h"
#include "VehicleHalTestUtils.h"
@@ -35,6 +36,9 @@
using namespace std::placeholders;
+constexpr char kCarMake[] = "Default Car";
+constexpr int kRetriablePropMockedAttempts = 3;
+
class MockedVehicleHal : public VehicleHal {
public:
MockedVehicleHal() {
@@ -46,35 +50,87 @@
return mConfigs;
}
- VehiclePropValuePtr get(VehicleProperty property,
- int32_t areaId,
- status_t* outStatus) override {
- *outStatus = OK;
- return getValuePool()->obtain(mValues[property]);
+ VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue,
+ StatusCode* outStatus) override {
+ *outStatus = StatusCode::OK;
+ VehiclePropValuePtr pValue;
+ VehicleProperty property = requestedPropValue.prop;
+ int32_t areaId = requestedPropValue.areaId;
+
+ switch (property) {
+ case VehicleProperty::INFO_MAKE:
+ pValue = getValuePool()->obtainString(kCarMake);
+ break;
+ case VehicleProperty::INFO_FUEL_CAPACITY:
+ if (fuelCapacityAttemptsLeft-- > 0) {
+ // Emulate property not ready yet.
+ *outStatus = StatusCode::TRY_AGAIN;
+ } else {
+ pValue = getValuePool()->obtainFloat(42.42);
+ }
+ break;
+ default:
+ auto key = makeKey(property, areaId);
+ if (mValues.count(key) == 0) {
+ ALOGW("");
+ }
+ pValue = getValuePool()->obtain(mValues[key]);
+ }
+
+ if (*outStatus == StatusCode::OK && pValue.get() != nullptr) {
+ pValue->prop = property;
+ pValue->areaId = areaId;
+ pValue->timestamp = elapsedRealtimeNano();
+ }
+
+ return pValue;
}
- status_t set(const VehiclePropValue& propValue) override {
- mValues[propValue.prop] = propValue;
- return OK;
+ StatusCode set(const VehiclePropValue& propValue) override {
+ if (VehicleProperty::MIRROR_FOLD == propValue.prop
+ && mirrorFoldAttemptsLeft-- > 0) {
+ return StatusCode::TRY_AGAIN;
+ }
+
+ mValues[makeKey(propValue)] = propValue;
+ return StatusCode::OK;
}
- status_t subscribe(VehicleProperty property,
+ StatusCode subscribe(VehicleProperty property,
int32_t areas,
float sampleRate) override {
- return OK;
+ return StatusCode::OK;
}
- status_t unsubscribe(VehicleProperty property) override {
- return OK;
+ StatusCode unsubscribe(VehicleProperty property) override {
+ return StatusCode::OK;
}
void sendPropEvent(recyclable_ptr<VehiclePropValue> value) {
doHalEvent(std::move(value));
}
+ void sendHalError(StatusCode error, VehicleProperty property,
+ int32_t areaId) {
+ doHalPropertySetError(error, property, areaId);
+ }
+
+public:
+ int fuelCapacityAttemptsLeft = kRetriablePropMockedAttempts;
+ int mirrorFoldAttemptsLeft = kRetriablePropMockedAttempts;
+
+private:
+ int64_t makeKey(const VehiclePropValue& v) const {
+ return makeKey(v.prop, v.areaId);
+ }
+
+ int64_t makeKey(VehicleProperty prop, int32_t area) const {
+ return (static_cast<int64_t>(prop) << 32) | area;
+ }
+
private:
std::vector<VehiclePropConfig> mConfigs;
- std::unordered_map<VehicleProperty, VehiclePropValue> mValues;
+ std::unordered_map<int64_t, VehiclePropValue> mValues;
};
class VehicleHalManagerTest : public ::testing::Test {
@@ -90,37 +146,70 @@
manager.reset(nullptr);
hal.reset(nullptr);
}
+public:
+ void invokeGet(VehicleProperty property, int32_t areaId) {
+ VehiclePropValue requestedValue {};
+ requestedValue.prop = property;
+ requestedValue.areaId = areaId;
+
+ invokeGet(requestedValue);
+ }
+
+ void invokeGet(const VehiclePropValue& requestedPropValue) {
+ actualValue = VehiclePropValue {}; // reset previous values
+
+ StatusCode refStatus;
+ VehiclePropValue refValue;
+ bool called = false;
+ manager->get(requestedPropValue, [&refStatus, &refValue, &called]
+ (StatusCode status, const VehiclePropValue& value) {
+ refStatus = status;
+ refValue = value;
+ called = true;
+ });
+ ASSERT_TRUE(called) << "callback wasn't called for prop: "
+ << enumToHexString(requestedPropValue.prop);
+
+ actualValue = refValue;
+ actualStatusCode = refStatus;
+ }
public:
+ VehiclePropValue actualValue;
+ StatusCode actualStatusCode;
+
VehiclePropValuePool* objectPool;
std::unique_ptr<MockedVehicleHal> hal;
std::unique_ptr<VehicleHalManager> manager;
};
-class HalClientVectorTest : public ::testing::Test {
-public:
- HalClientVector clients;
-};
-
TEST_F(VehicleHalManagerTest, getPropConfigs) {
hidl_vec<VehicleProperty> properties = init_hidl_vec(
{ VehicleProperty::HVAC_FAN_SPEED,VehicleProperty::INFO_MAKE} );
bool called = false;
+
manager->getPropConfigs(properties,
- [&called] (const hidl_vec<VehiclePropConfig>& c) {
+ [&called] (StatusCode status,
+ const hidl_vec<VehiclePropConfig>& c) {
+ ASSERT_EQ(StatusCode::OK, status);
ASSERT_EQ(2u, c.size());
called = true;
});
+
ASSERT_TRUE(called); // Verify callback received.
called = false;
manager->getPropConfigs(init_hidl_vec({VehicleProperty::HVAC_FAN_SPEED}),
- [&called] (const hidl_vec<VehiclePropConfig>& c) {
+ [&called] (StatusCode status,
+ const hidl_vec<VehiclePropConfig>& c) {
+ ASSERT_EQ(StatusCode::OK, status);
ASSERT_EQ(1u, c.size());
ASSERT_EQ(toString(kVehicleProperties[1]), toString(c[0]));
called = true;
});
ASSERT_TRUE(called); // Verify callback received.
+
+ // TODO(pavelm): add case case when property was not declared.
}
TEST_F(VehicleHalManagerTest, getAllPropConfigs) {
@@ -138,6 +227,25 @@
ASSERT_TRUE(called); // Verify callback received.
}
+TEST_F(VehicleHalManagerTest, halErrorEvent) {
+ const VehicleProperty PROP = VehicleProperty::DISPLAY_BRIGHTNESS;
+
+ sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
+
+ hidl_vec<SubscribeOptions> options = init_hidl_vec(
+ {
+ SubscribeOptions {
+ .propId = PROP,
+ .flags = SubscribeFlags::DEFAULT
+ },
+ });
+
+ StatusCode res = manager->subscribe(cb, options);
+ ASSERT_EQ(StatusCode::OK, res);
+
+ hal->sendHalError(StatusCode::TRY_AGAIN, PROP, 0 /* area id*/);
+}
+
TEST_F(VehicleHalManagerTest, subscribe) {
const VehicleProperty PROP = VehicleProperty::DISPLAY_BRIGHTNESS;
@@ -161,9 +269,9 @@
auto& receivedEnvents = cb->getReceivedEvents();
ASSERT_TRUE(cb->waitForExpectedEvents(0)) << " Unexpected events received: "
- << receivedEnvents.size()
- << (receivedEnvents.size() > 0
- ? toString(receivedEnvents.front()[0]) : "");
+ << receivedEnvents.size()
+ << (receivedEnvents.size() > 0
+ ? toString(receivedEnvents.front()[0]) : "");
auto subscribedValue = objectPool->obtain(VehiclePropertyType::INT32);
subscribedValue->prop = PROP;
@@ -174,13 +282,143 @@
hal->sendPropEvent(std::move(subscribedValue));
ASSERT_TRUE(cb->waitForExpectedEvents(1)) << "Events received: "
- << receivedEnvents.size();
+ << receivedEnvents.size();
ASSERT_EQ(toString(actualValue),
toString(cb->getReceivedEvents().front()[0]));
}
-TEST_F(HalClientVectorTest, basic) {
+TEST_F(VehicleHalManagerTest, subscribe_WriteOnly) {
+ const VehicleProperty PROP = VehicleProperty::HVAC_SEAT_TEMPERATURE;
+
+ sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
+
+ hidl_vec<SubscribeOptions> options = init_hidl_vec(
+ {
+ SubscribeOptions {
+ .propId = PROP,
+ .flags = SubscribeFlags::HAL_EVENT
+ },
+ });
+
+ StatusCode res = manager->subscribe(cb, options);
+ // Unable to subscribe on Hal Events for write-only properties.
+ ASSERT_EQ(StatusCode::INVALID_ARG, res);
+
+
+ options[0].flags = SubscribeFlags::SET_CALL;
+
+ res = manager->subscribe(cb, options);
+ // OK to subscribe on SET method call for write-only properties.
+ ASSERT_EQ(StatusCode::OK, res);
+}
+
+TEST_F(VehicleHalManagerTest, get_StaticString) {
+ invokeGet(VehicleProperty::INFO_MAKE, 0);
+
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+ ASSERT_EQ(VehicleProperty::INFO_MAKE, actualValue.prop);
+ ASSERT_STREQ(kCarMake, actualValue.value.stringValue.c_str());
+}
+
+TEST_F(VehicleHalManagerTest, get_NegativeCases) {
+ // Write-only property must fail.
+ invokeGet(VehicleProperty::HVAC_SEAT_TEMPERATURE, 0);
+ ASSERT_EQ(StatusCode::INVALID_ARG, actualStatusCode);
+
+ // Unknown property must fail.
+ invokeGet(VehicleProperty::MIRROR_Z_MOVE, 0);
+ ASSERT_EQ(StatusCode::INVALID_ARG, actualStatusCode);
+}
+
+TEST_F(VehicleHalManagerTest, get_Retriable) {
+ actualStatusCode = StatusCode::TRY_AGAIN;
+ int attempts = 0;
+ while (StatusCode::TRY_AGAIN == actualStatusCode && ++attempts < 10) {
+ invokeGet(VehicleProperty::INFO_FUEL_CAPACITY, 0);
+
+ }
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+ ASSERT_EQ(kRetriablePropMockedAttempts + 1, attempts);
+ ASSERT_FLOAT_EQ(42.42, actualValue.value.floatValues[0]);
+}
+
+TEST_F(VehicleHalManagerTest, set_Basic) {
+ const auto PROP = VehicleProperty::DISPLAY_BRIGHTNESS;
+ const auto VAL = 7;
+
+ auto expectedValue = hal->getValuePool()->obtainInt32(VAL);
+ expectedValue->prop = PROP;
+ expectedValue->areaId = 0;
+
+ actualStatusCode = manager->set(*expectedValue.get());
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+
+ invokeGet(PROP, 0);
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+ ASSERT_EQ(PROP, actualValue.prop);
+ ASSERT_EQ(VAL, actualValue.value.int32Values[0]);
+}
+
+TEST_F(VehicleHalManagerTest, set_DifferentAreas) {
+ const auto PROP = VehicleProperty::HVAC_FAN_SPEED;
+ const auto VAL1 = 1;
+ const auto VAL2 = 2;
+ const auto AREA1 = toInt(VehicleAreaZone::ROW_1_LEFT);
+ const auto AREA2 = toInt(VehicleAreaZone::ROW_1_RIGHT);
+
+ {
+ auto expectedValue1 = hal->getValuePool()->obtainInt32(VAL1);
+ expectedValue1->prop = PROP;
+ expectedValue1->areaId = AREA1;
+ actualStatusCode = manager->set(*expectedValue1.get());
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+
+ auto expectedValue2 = hal->getValuePool()->obtainInt32(VAL2);
+ expectedValue2->prop = PROP;
+ expectedValue2->areaId = AREA2;
+ actualStatusCode = manager->set(*expectedValue2.get());
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+ }
+
+ {
+ invokeGet(PROP, AREA1);
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+ ASSERT_EQ(PROP, actualValue.prop);
+ ASSERT_EQ(AREA1, actualValue.areaId);
+ ASSERT_EQ(VAL1, actualValue.value.int32Values[0]);
+
+ invokeGet(PROP, AREA2);
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+ ASSERT_EQ(PROP, actualValue.prop);
+ ASSERT_EQ(AREA2, actualValue.areaId);
+ ASSERT_EQ(VAL2, actualValue.value.int32Values[0]);
+ }
+}
+
+TEST_F(VehicleHalManagerTest, set_Retriable) {
+ const auto PROP = VehicleProperty::MIRROR_FOLD;
+
+ auto v = hal->getValuePool()->obtainBoolean(true);
+ v->prop = PROP;
+ v->areaId = 0;
+
+ actualStatusCode = StatusCode::TRY_AGAIN;
+ int attempts = 0;
+ while (StatusCode::TRY_AGAIN == actualStatusCode && ++attempts < 10) {
+ actualStatusCode = manager->set(*v.get());
+ }
+
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+ ASSERT_EQ(kRetriablePropMockedAttempts + 1, attempts);
+
+ invokeGet(PROP, 0);
+ ASSERT_EQ(StatusCode::OK, actualStatusCode);
+ ASSERT_TRUE(actualValue.value.int32Values[0]);
+}
+
+TEST(HalClientVectorTest, basic) {
+ HalClientVector clients;
sp<IVehicleCallback> callback1 = new MockedVehicleCallback();
sp<HalClient> c1 = new HalClient(callback1, 10, 20);
diff --git a/vehicle/2.0/default/tests/VehicleHalTestUtils.h b/vehicle/2.0/default/tests/VehicleHalTestUtils.h
index b3b3ffa..16d0be9 100644
--- a/vehicle/2.0/default/tests/VehicleHalTestUtils.h
+++ b/vehicle/2.0/default/tests/VehicleHalTestUtils.h
@@ -44,18 +44,37 @@
.supportedAreas = static_cast<int32_t>(
VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT),
.areaConfigs = init_hidl_vec({
- VehicleAreaConfig {
- .areaId = val(
- VehicleAreaZone::ROW_2_LEFT),
- .minInt32Value = 1,
- .maxInt32Value = 7},
- VehicleAreaConfig {
- .areaId = val(
- VehicleAreaZone::ROW_1_RIGHT),
- .minInt32Value = 1,
- .maxInt32Value = 5,
- }
- }),
+ VehicleAreaConfig {
+ .areaId = toInt(VehicleAreaZone::ROW_1_LEFT),
+ .minInt32Value = 1,
+ .maxInt32Value = 7},
+ VehicleAreaConfig {
+ .areaId = toInt(VehicleAreaZone::ROW_1_RIGHT),
+ .minInt32Value = 1,
+ .maxInt32Value = 5,
+ }
+ }),
+ },
+
+ // Write-only property
+ {
+ .prop = VehicleProperty::HVAC_SEAT_TEMPERATURE,
+ .access = VehiclePropertyAccess::WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_SET,
+ .permissionModel = VehiclePermissionModel::NO_RESTRICTION,
+ .supportedAreas = static_cast<int32_t>(
+ VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT),
+ .areaConfigs = init_hidl_vec({
+ VehicleAreaConfig {
+ .areaId = toInt(VehicleAreaZone::ROW_1_LEFT),
+ .minInt32Value = 64,
+ .maxInt32Value = 80},
+ VehicleAreaConfig {
+ .areaId = toInt(VehicleAreaZone::ROW_1_RIGHT),
+ .minInt32Value = 64,
+ .maxInt32Value = 80,
+ }
+ }),
},
{
@@ -82,12 +101,23 @@
.maxInt32Value = 10
}
})
+ },
+
+ {
+ .prop = VehicleProperty::MIRROR_FOLD,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .permissionModel = VehiclePermissionModel::OEM_ONLY,
+
}
};
constexpr auto kTimeout = std::chrono::milliseconds(500);
class MockedVehicleCallback : public IVehicleCallback {
+private:
+ using MuxGuard = std::lock_guard<std::mutex>;
+ using HidlVecOfValues = hidl_vec<VehiclePropValue>;
public:
// Methods from ::android::hardware::vehicle::V2_0::IVehicleCallback follow.
Return<void> onPropertyEvent(
@@ -102,9 +132,9 @@
Return<void> onPropertySet(const VehiclePropValue& value) override {
return Return<void>();
}
- Return<void> onError(StatusCode errorCode,
- VehicleProperty propId,
- VehiclePropertyOperation operation) override {
+ Return<void> onPropertySetError(StatusCode errorCode,
+ VehicleProperty propId,
+ int32_t areaId) override {
return Return<void>();
}
@@ -129,16 +159,14 @@
mReceivedEvents.clear();
}
- const std::vector<hidl_vec<VehiclePropValue>>& getReceivedEvents() {
+ const std::vector<HidlVecOfValues>& getReceivedEvents() {
return mReceivedEvents;
}
private:
- using MuxGuard = std::lock_guard<std::mutex>;
-
std::mutex mLock;
std::condition_variable mEventCond;
- std::vector<hidl_vec<VehiclePropValue>> mReceivedEvents;
+ std::vector<HidlVecOfValues> mReceivedEvents;
};
template<typename T>
@@ -172,7 +200,7 @@
template<typename T>
inline std::string enumToHexString(T value) {
- return hexString(val(value));
+ return hexString(toInt(value));
}
template <typename T>