diff options
author | Pavel Maltsev <pavelm@google.com> | 2016-10-27 15:43:06 -0700 |
---|---|---|
committer | Pavel Maltsev <pavelm@google.com> | 2016-11-02 14:31:34 -0700 |
commit | db179c5ec470269e1c88d8da5fafdff40a539bc6 (patch) | |
tree | 8c97ad60053f10f5fb978b10d989b2d3d1f06943 /vehicle | |
parent | 4ae948a52ba96cd10995c292a84392a46f436ae2 (diff) | |
download | platform_hardware_interfaces-db179c5ec470269e1c88d8da5fafdff40a539bc6.tar.gz platform_hardware_interfaces-db179c5ec470269e1c88d8da5fafdff40a539bc6.tar.bz2 platform_hardware_interfaces-db179c5ec470269e1c88d8da5fafdff40a539bc6.zip |
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
Diffstat (limited to 'vehicle')
18 files changed, 613 insertions, 328 deletions
diff --git a/vehicle/2.0/IVehicle.hal b/vehicle/2.0/IVehicle.hal index 4c02447bf6..5b0df67170 100644 --- a/vehicle/2.0/IVehicle.hal +++ b/vehicle/2.0/IVehicle.hal @@ -27,9 +27,13 @@ interface IVehicle { /* * Returns a list of property configurations for given properties. + * + * If requested VehicleProperty wasn't found it must return + * StatusCode::INVALID_ARG, otherwise a list of vehicle property + * configurations with StatusCode::OK */ getPropConfigs(vec<VehicleProperty> props) - generates (vec<VehiclePropConfig> propConfigs); + generates (StatusCode status, vec<VehiclePropConfig> propConfigs); /** * Get a vehicle property value. @@ -39,11 +43,14 @@ interface IVehicle { * For VehiclePropertyChangeMode::ON_CHANGE properties, it must return the * latest available value. * + * Some properties like AUDIO_VOLUME requires to pass additional data in + * GET request in VehiclePropValue object. + * * If there is no data available yet, which can happen during initial stage, * this call must return immediately with an error code of * StatusCode::TRY_AGAIN. */ - get(VehicleProperty propId, int32_t areaId) + get(VehiclePropValue requestedPropValue) generates (StatusCode status, VehiclePropValue propValue); /** @@ -75,7 +82,7 @@ interface IVehicle { * Unsubscribes from property events. * * If this client wasn't subscribed to the given property, this method - * must return StatusCode::INVALID_ARGUMENT. + * must return StatusCode::INVALID_ARG. */ unsubscribe(IVehicleCallback callback, VehicleProperty propId) generates (StatusCode status); diff --git a/vehicle/2.0/IVehicleCallback.hal b/vehicle/2.0/IVehicleCallback.hal index 5c1042b26c..504f782017 100644 --- a/vehicle/2.0/IVehicleCallback.hal +++ b/vehicle/2.0/IVehicleCallback.hal @@ -43,14 +43,17 @@ interface IVehicleCallback { oneway onPropertySet(VehiclePropValue propValue); /* - * Called by HAL server when error condition has occurred. + * Set property value is usually asynchronous operation. Thus even if + * client received StatusCode::OK from the IVehicle::set(...) this + * doesn't guarantee that the value was successfully propagated to the + * vehicle network. If such rare event occurs this method must be called. * * @param errorCode - any value from StatusCode enum. - * @parm property - a property where error has happened. If this is - * a generic error, this value should be VehicleProperty::INVALID. - * @param operation Represent the operation where the error has happened. + * @param property - a property where error has happened. + * @param areaId - bitmask that specifies in which areas the problem has + * occurred, must be 0 for global properties */ - oneway onError(StatusCode errorCode, - VehicleProperty propId, - VehiclePropertyOperation operation); + oneway onPropertySetError(StatusCode errorCode, + VehicleProperty propId, + int32_t areaId); }; diff --git a/vehicle/2.0/default/Android.mk b/vehicle/2.0/default/Android.mk index e14cb19114..90353ee091 100644 --- a/vehicle/2.0/default/Android.mk +++ b/vehicle/2.0/default/Android.mk @@ -24,7 +24,6 @@ LOCAL_MODULE := $(module_prefix)-manager-lib LOCAL_SRC_FILES := \ vehicle_hal_manager/SubscriptionManager.cpp \ vehicle_hal_manager/VehicleHalManager.cpp \ - vehicle_hal_manager/VehicleCallback.cpp \ LOCAL_SHARED_LIBRARIES := \ liblog \ diff --git a/vehicle/2.0/default/VehicleHal.h b/vehicle/2.0/default/VehicleHal.h index 89d8ef8816..2807f28750 100644 --- a/vehicle/2.0/default/VehicleHal.h +++ b/vehicle/2.0/default/VehicleHal.h @@ -36,18 +36,15 @@ public: using HalEventFunction = std::function<void(VehiclePropValuePtr)>; using HalErrorFunction = std::function<void( - VehicleProperty property, - status_t errorCode, - VehiclePropertyOperation operation)>; + StatusCode errorCode, VehicleProperty property, int32_t areaId)>; virtual ~VehicleHal() {} virtual std::vector<VehiclePropConfig> listProperties() = 0; - virtual VehiclePropValuePtr get(VehicleProperty property, - int32_t areaId, - status_t* outStatus) = 0; + virtual VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue, + StatusCode* outStatus) = 0; - virtual status_t set(const VehiclePropValue& propValue) = 0; + virtual StatusCode set(const VehiclePropValue& propValue) = 0; /** * Subscribe to HAL property events. This method might be called multiple @@ -60,7 +57,7 @@ public: * rate, e.g. for properties with * VehiclePropertyChangeMode::CONTINUOUS */ - virtual status_t subscribe(VehicleProperty property, + virtual StatusCode subscribe(VehicleProperty property, int32_t areas, float sampleRate) = 0; @@ -69,7 +66,7 @@ public: * * @param property vehicle property to unsubscribe */ - virtual status_t unsubscribe(VehicleProperty property) = 0; + virtual StatusCode unsubscribe(VehicleProperty property) = 0; /** * Override this method if you need to do one-time initialization. @@ -82,7 +79,7 @@ public: const HalErrorFunction& onHalError) { mValuePool = valueObjectPool; mOnHalEvent = onHalEvent; - mOnHalError = onHalError; + mOnHalPropertySetError = onHalError; onCreate(); } @@ -91,19 +88,20 @@ public: return mValuePool; } protected: + /* Propagates property change events to vehicle HAL clients. */ void doHalEvent(VehiclePropValuePtr v) { mOnHalEvent(std::move(v)); } - void doHalError(VehicleProperty property, - status_t errorCode, - VehiclePropertyOperation operation) { - mOnHalError(property, errorCode, operation); + /* Propagates error during set operation to the vehicle HAL clients. */ + void doHalPropertySetError(StatusCode errorCode, + VehicleProperty propId, int32_t areaId) { + mOnHalPropertySetError(errorCode, propId, areaId); } private: HalEventFunction mOnHalEvent; - HalErrorFunction mOnHalError; + HalErrorFunction mOnHalPropertySetError; VehiclePropValuePool* mValuePool; }; diff --git a/vehicle/2.0/default/impl/DefaultConfig.h b/vehicle/2.0/default/impl/DefaultConfig.h index 6f04626ba8..e620c28634 100644 --- a/vehicle/2.0/default/impl/DefaultConfig.h +++ b/vehicle/2.0/default/impl/DefaultConfig.h @@ -43,11 +43,11 @@ const VehiclePropConfig kVehicleProperties[] = { VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT), .areaConfigs = init_hidl_vec({ VehicleAreaConfig { - .areaId = val(VehicleAreaZone::ROW_2_LEFT), + .areaId = toInt(VehicleAreaZone::ROW_2_LEFT), .minInt32Value = 1, .maxInt32Value = 7}, VehicleAreaConfig { - .areaId = val(VehicleAreaZone::ROW_1_RIGHT), + .areaId = toInt(VehicleAreaZone::ROW_1_RIGHT), .minInt32Value = 1, .maxInt32Value = 5, } diff --git a/vehicle/2.0/default/impl/DefaultVehicleHal.cpp b/vehicle/2.0/default/impl/DefaultVehicleHal.cpp index 6ca0f9fd6e..24d438dc52 100644 --- a/vehicle/2.0/default/impl/DefaultVehicleHal.cpp +++ b/vehicle/2.0/default/impl/DefaultVehicleHal.cpp @@ -23,12 +23,13 @@ namespace V2_0 { namespace impl { -VehicleHal::VehiclePropValuePtr DefaultVehicleHal::get(VehicleProperty property, - int32_t areaId, - status_t* outStatus) { - *outStatus = OK; +VehicleHal::VehiclePropValuePtr DefaultVehicleHal::get( + const VehiclePropValue& requestedPropValue, StatusCode* outStatus) { + *outStatus = StatusCode::OK; VehiclePropValuePtr v; + VehicleProperty property = requestedPropValue.prop; + int32_t areaId = requestedPropValue.areaId; switch (property) { case VehicleProperty::INFO_MAKE: @@ -36,7 +37,8 @@ VehicleHal::VehiclePropValuePtr DefaultVehicleHal::get(VehicleProperty property, break; case VehicleProperty::HVAC_FAN_SPEED: int32_t value; - if ((*outStatus = getHvacFanSpeed(areaId, &value)) == OK) { + *outStatus = getHvacFanSpeed(areaId, &value); + if (StatusCode::OK == *outStatus) { v = getValuePool()->obtainInt32(value); } break; @@ -47,10 +49,10 @@ VehicleHal::VehiclePropValuePtr DefaultVehicleHal::get(VehicleProperty property, v = getValuePool()->obtainInt32(brightness); break; default: - *outStatus = BAD_VALUE; + *outStatus = StatusCode::INVALID_ARG; } - if (*outStatus == OK && v.get() != nullptr) { + if (StatusCode::OK == *outStatus && v.get() != nullptr) { v->prop = property; v->areaId = areaId; v->timestamp = elapsedRealtimeNano(); @@ -59,10 +61,10 @@ VehicleHal::VehiclePropValuePtr DefaultVehicleHal::get(VehicleProperty property, return v; } -status_t DefaultVehicleHal::set(const VehiclePropValue& propValue) { +StatusCode DefaultVehicleHal::set(const VehiclePropValue& propValue) { auto property = propValue.prop; - status_t status = OK; + StatusCode status = StatusCode::OK; switch (property) { case VehicleProperty::HVAC_FAN_SPEED: @@ -73,33 +75,33 @@ status_t DefaultVehicleHal::set(const VehiclePropValue& propValue) { brightness = propValue.value.int32Values[0]; break; default: - status = BAD_VALUE; + status = StatusCode::INVALID_ARG; } return status; } -status_t DefaultVehicleHal::getHvacFanSpeed(int32_t areaId, +StatusCode DefaultVehicleHal::getHvacFanSpeed(int32_t areaId, int32_t* outValue) { - if (areaId == val(VehicleAreaZone::ROW_1_LEFT)) { + if (areaId == toInt(VehicleAreaZone::ROW_1_LEFT)) { *outValue = fanSpeedRow1Left; - } else if (areaId == val(VehicleAreaZone::ROW_2_RIGHT)) { + } else if (areaId == toInt(VehicleAreaZone::ROW_2_RIGHT)) { *outValue = fanSpeedRow1Right; } else { - return BAD_VALUE; + return StatusCode::INVALID_ARG; } - return OK; + return StatusCode::OK; } -status_t DefaultVehicleHal::setHvacFanSpeed(int32_t areaId, int32_t value) { - if (areaId == val(VehicleAreaZone::ROW_1_LEFT)) { +StatusCode DefaultVehicleHal::setHvacFanSpeed(int32_t areaId, int32_t value) { + if (areaId == toInt(VehicleAreaZone::ROW_1_LEFT)) { fanSpeedRow1Left = value; - } else if (areaId == val(VehicleAreaZone::ROW_2_RIGHT)) { + } else if (areaId == toInt(VehicleAreaZone::ROW_2_RIGHT)) { fanSpeedRow1Right = value; } else { - return BAD_VALUE; + return StatusCode::INVALID_ARG; } - return OK; + return StatusCode::OK; } } // impl diff --git a/vehicle/2.0/default/impl/DefaultVehicleHal.h b/vehicle/2.0/default/impl/DefaultVehicleHal.h index 7d0b7cbf84..4a81da35ca 100644 --- a/vehicle/2.0/default/impl/DefaultVehicleHal.h +++ b/vehicle/2.0/default/impl/DefaultVehicleHal.h @@ -35,27 +35,26 @@ public: std::end(kVehicleProperties)); } - VehiclePropValuePtr get(VehicleProperty property, - int32_t areaId, - status_t* outStatus) override; + VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue, + StatusCode* outStatus) override; - status_t set(const VehiclePropValue& propValue) override; + StatusCode set(const VehiclePropValue& propValue) override; - status_t subscribe(VehicleProperty property, + StatusCode subscribe(VehicleProperty property, int32_t areas, float sampleRate) { // TODO(pavelm): implement - return OK; + return StatusCode::OK; } - status_t unsubscribe(VehicleProperty property) { + StatusCode unsubscribe(VehicleProperty property) { // TODO(pavelm): implement - return OK; + return StatusCode::OK; } private: - status_t getHvacFanSpeed(int32_t areaId, int32_t* outValue); - status_t setHvacFanSpeed(int32_t areaId, int32_t value); + StatusCode getHvacFanSpeed(int32_t areaId, int32_t* outValue); + StatusCode setHvacFanSpeed(int32_t areaId, int32_t value); private: int32_t fanSpeedRow1Left = 3; int32_t fanSpeedRow1Right = 5; diff --git a/vehicle/2.0/default/tests/SubscriptionManager_test.cpp b/vehicle/2.0/default/tests/SubscriptionManager_test.cpp index c3db993dd8..19b11e6b72 100644 --- a/vehicle/2.0/default/tests/SubscriptionManager_test.cpp +++ b/vehicle/2.0/default/tests/SubscriptionManager_test.cpp @@ -50,7 +50,7 @@ public: { SubscribeOptions { .propId = PROP1, - .vehicleAreas = val(VehicleAreaZone::ROW_1_LEFT), + .vehicleAreas = toInt(VehicleAreaZone::ROW_1_LEFT), .flags = SubscribeFlags::HAL_EVENT }, }); @@ -67,7 +67,7 @@ public: { SubscribeOptions { .propId = PROP1, - .vehicleAreas = val(VehicleAreaZone::ROW_1_LEFT), + .vehicleAreas = toInt(VehicleAreaZone::ROW_1_LEFT), .flags = SubscribeFlags::HAL_EVENT }, SubscribeOptions { @@ -87,7 +87,7 @@ public: 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 @@ TEST_F(SubscriptionManagerTest, multipleClients) { 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 @@ TEST_F(SubscriptionManagerTest, negativeCases) { // 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 @@ TEST_F(SubscriptionManagerTest, mulipleSubscriptions) { 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 @@ TEST_F(SubscriptionManagerTest, mulipleSubscriptions) { { 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 1410ddf8c1..6ef12052d1 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 @@ namespace { using namespace std::placeholders; +constexpr char kCarMake[] = "Default Car"; +constexpr int kRetriablePropMockedAttempts = 3; + class MockedVehicleHal : public VehicleHal { public: MockedVehicleHal() { @@ -46,35 +50,87 @@ public: 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 @@ protected: 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 @@ TEST_F(VehicleHalManagerTest, getAllPropConfigs) { 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 @@ TEST_F(VehicleHalManagerTest, subscribe) { 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 @@ TEST_F(VehicleHalManagerTest, subscribe) { 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 b3b3ffa979..16d0be912f 100644 --- a/vehicle/2.0/default/tests/VehicleHalTestUtils.h +++ b/vehicle/2.0/default/tests/VehicleHalTestUtils.h @@ -44,18 +44,37 @@ const VehiclePropConfig kVehicleProperties[] = { .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 @@ const VehiclePropConfig kVehicleProperties[] = { .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 @@ public: 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 @@ public: 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 @@ inline void assertAllExistsAnyOrder( template<typename T> inline std::string enumToHexString(T value) { - return hexString(val(value)); + return hexString(toInt(value)); } template <typename T> diff --git a/vehicle/2.0/default/vehicle_hal_manager/ConcurrentQueue.h b/vehicle/2.0/default/vehicle_hal_manager/ConcurrentQueue.h index a64ef464bd..485f3dc383 100644 --- a/vehicle/2.0/default/vehicle_hal_manager/ConcurrentQueue.h +++ b/vehicle/2.0/default/vehicle_hal_manager/ConcurrentQueue.h @@ -113,14 +113,15 @@ public: void requestStop() { if (mState.exchange(State::STOP_REQUESTED) != State::RUNNING) { - mState = State::STOPPED; - } + mState = State::STOPPED; + mCondStopped.notify_one(); + } } void waitStopped() { std::unique_lock<std::mutex> g(mLock); while (State::STOPPED != mState) { - mCondStopped.wait_for(g, std::chrono::seconds(1)); + mCondStopped.wait(g); } } diff --git a/vehicle/2.0/default/vehicle_hal_manager/VehicleCallback.cpp b/vehicle/2.0/default/vehicle_hal_manager/VehicleCallback.cpp deleted file mode 100644 index 985b7dc5cf..0000000000 --- a/vehicle/2.0/default/vehicle_hal_manager/VehicleCallback.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "VehicleCallback.h" - -namespace android { -namespace hardware { -namespace vehicle { -namespace V2_0 { -namespace implementation { - -// Methods from ::android::hardware::vehicle::V2_0::IVehicleCallback follow. -Return<void> VehicleCallback::onPropertyEvent(const hidl_vec<VehiclePropValue>& value) { - // TODO(pavelm): add default implementation - return Void(); -} - -// Methods from ::android::hardware::vehicle::V2_0::IVehicleCallback follow. -Return<void> VehicleCallback::onPropertySet(const VehiclePropValue& value) { - // TODO(pavelm): add default implementation - return Void(); -} - -Return<void> VehicleCallback::onError(StatusCode errorCode, - VehicleProperty propId, - VehiclePropertyOperation operation) { - // TODO(pavelm): add default implementation - return Void(); -} - - -IVehicleCallback* HIDL_FETCH_IVehicleCallback(const char* /* name */) { - return new VehicleCallback(); -} - -} // namespace implementation -} // namespace V2_0 -} // namespace vehicle -} // namespace hardware -} // namespace android diff --git a/vehicle/2.0/default/vehicle_hal_manager/VehicleCallback.h b/vehicle/2.0/default/vehicle_hal_manager/VehicleCallback.h deleted file mode 100644 index d037c94cf8..0000000000 --- a/vehicle/2.0/default/vehicle_hal_manager/VehicleCallback.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef HIDL_GENERATED_android_hardware_vehicle_V2_0_VehicleCallback_H_ -#define HIDL_GENERATED_android_hardware_vehicle_V2_0_VehicleCallback_H_ - -#include <android/hardware/vehicle/2.0/IVehicleCallback.h> -#include <hidl/Status.h> - -#include <hidl/MQDescriptor.h> -namespace android { -namespace hardware { -namespace vehicle { -namespace V2_0 { -namespace implementation { - -using ::android::hardware::vehicle::V2_0::IVehicleCallback; -using ::android::hardware::vehicle::V2_0::VehiclePropValue; -using ::android::hardware::vehicle::V2_0::VehicleProperty; -using ::android::hardware::vehicle::V2_0::VehiclePropertyOperation; -using ::android::hardware::Return; -using ::android::hardware::Void; -using ::android::hardware::hidl_vec; -using ::android::hardware::hidl_string; -using ::android::sp; - -struct VehicleCallback : public IVehicleCallback { - // Methods from ::android::hardware::vehicle::V2_0::IVehicleCallback follow. - Return<void> onPropertyEvent(const hidl_vec<VehiclePropValue>& values) override; - Return<void> onPropertySet(const VehiclePropValue& value) override; - Return<void> onError(StatusCode errorCode, VehicleProperty propId, VehiclePropertyOperation operation) override; - -}; - -extern "C" IVehicleCallback* HIDL_FETCH_IVehicleCallback(const char* name); - -} // namespace implementation -} // namespace V2_0 -} // namespace vehicle -} // namespace hardware -} // namespace android - -#endif // HIDL_GENERATED_android_hardware_vehicle_V2_0_VehicleCallback_H_ diff --git a/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.cpp b/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.cpp index 8638131f2a..a84f991df2 100644 --- a/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.cpp +++ b/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.cpp @@ -20,6 +20,8 @@ #include <utils/Errors.h> #include <utils/Log.h> #include <hidl/Status.h> +#include <future> +#include <bitset> #include "VehicleHalManager.h" @@ -32,6 +34,8 @@ using namespace std::placeholders; constexpr std::chrono::milliseconds kHalEventBatchingTimeWindow(10); +const VehiclePropValue kEmptyValue{}; + /** * Indicates what's the maximum size of hidl_vec<VehiclePropValue> we want * to store in reusable object pool. @@ -40,6 +44,7 @@ constexpr auto kMaxHidlVecOfVehiclPropValuePoolSize = 20; Return<void> VehicleHalManager::getAllPropConfigs( getAllPropConfigs_cb _hidl_cb) { + ALOGI("getAllPropConfigs called"); hidl_vec<VehiclePropConfig> hidlConfigs; auto& halConfig = mConfigIndex->getAllConfigs(); @@ -47,45 +52,72 @@ Return<void> VehicleHalManager::getAllPropConfigs( const_cast<VehiclePropConfig *>(halConfig.data()), halConfig.size()); + ALOGI("getAllPropConfigs calling callback"); _hidl_cb(hidlConfigs); - return hardware::Return<void>(); + ALOGI("getAllPropConfigs done"); + return Void(); } Return<void> VehicleHalManager::getPropConfigs( const hidl_vec<VehicleProperty> &properties, getPropConfigs_cb _hidl_cb) { - Vector<VehiclePropConfig> configs; + std::vector<VehiclePropConfig> configs; for (size_t i = 0; i < properties.size(); i++) { VehicleProperty prop = properties[i]; if (mConfigIndex->hasConfig(prop)) { - configs.add(mConfigIndex->getConfig(prop)); + configs.push_back(mConfigIndex->getConfig(prop)); } else { - // TODO: return error + ALOGW("Requested config for undefined property: 0x%x", prop); + _hidl_cb(StatusCode::INVALID_ARG, hidl_vec<VehiclePropConfig>()); } } - hidl_vec<VehiclePropConfig> hidlConfigs; - hidlConfigs.setToExternal( - const_cast<VehiclePropConfig*>(configs.array()), - configs.size()); - - _hidl_cb(hidlConfigs); + _hidl_cb(StatusCode::OK, configs); - return hardware::Return<void>(); + return Void(); } Return<void> VehicleHalManager::get( - VehicleProperty propId, int32_t areaId, get_cb _hidl_cb) { + const VehiclePropValue& requestedPropValue, get_cb _hidl_cb) { + const auto* config = getPropConfigOrNull(requestedPropValue.prop); + if (config == nullptr) { + ALOGE("Failed to get value: config not found, property: 0x%x", + requestedPropValue.prop); + _hidl_cb(StatusCode::INVALID_ARG, kEmptyValue); + return Void(); + } - return hardware::Return<void>(); + if (!checkReadPermission(*config, getCallee())) { + _hidl_cb(StatusCode::INVALID_ARG, kEmptyValue); + return Void(); + } + + StatusCode status; + auto value = mHal->get(requestedPropValue, &status); + _hidl_cb(status, value.get() ? *value : kEmptyValue); + + + return Void(); } Return<StatusCode> VehicleHalManager::set(const VehiclePropValue &value) { - // TODO(pavelm): check permission, etc - // TODO(pavelm): check SET subscription - // TODO(pavelm): propagate SET call to VehicleHal - return hardware::Return<StatusCode>(StatusCode::OK); + auto prop = value.prop; + const auto* config = getPropConfigOrNull(prop); + if (config == nullptr) { + ALOGE("Failed to set value: config not found, property: 0x%x", prop); + return StatusCode::INVALID_ARG; + } + + if (!checkWritePermission(*config, getCallee())) { + return StatusCode::INVALID_ARG; + } + + handlePropertySetEvent(value); + + auto status = mHal->set(value); + + return Return<StatusCode>(status); } Return<StatusCode> VehicleHalManager::subscribe( @@ -96,45 +128,40 @@ Return<StatusCode> VehicleHalManager::subscribe( SubscribeOptions& ops = verifiedOptions[i]; VehicleProperty prop = ops.propId; - if (!mConfigIndex->hasConfig(prop)) { - ALOGE("Failed to subscribe: config not found for property: 0x%x", + const auto* config = getPropConfigOrNull(prop); + if (config == nullptr) { + ALOGE("Failed to subscribe: config not found, property: 0x%x", prop); - return invalidArg(); + return StatusCode::INVALID_ARG; } - const VehiclePropConfig& config = mConfigIndex->getConfig(prop); - if (!isSubscribable(config)) { - ALOGE("Failed to subscribe: property is not subscribable: 0x%x", + if (!isSubscribable(*config, ops.flags)) { + ALOGE("Failed to subscribe: property 0x%x is not subscribable", prop); - return invalidArg(); + return StatusCode::INVALID_ARG; } - int32_t areas = isGlobalProp(prop) ? 0 : ops.vehicleAreas; - if (areas != 0 && ((areas & config.supportedAreas) != areas)) { + if (areas != 0 && ((areas & config->supportedAreas) != areas)) { ALOGE("Failed to subscribe property 0x%x. Requested areas 0x%x are " "out of supported range of 0x%x", prop, ops.vehicleAreas, - config.supportedAreas); - return invalidArg(); + config->supportedAreas); + return StatusCode::INVALID_ARG; } ops.vehicleAreas = areas; - ops.sampleRate = checkSampleRate(config, ops.sampleRate); + ops.sampleRate = checkSampleRate(*config, ops.sampleRate); } - std::list<SubscribeOptions> updatedOptions = - mSubscriptionManager.addOrUpdateSubscription(callback, - verifiedOptions); + std::list<SubscribeOptions> updatedOptions = + mSubscriptionManager.addOrUpdateSubscription(callback, verifiedOptions); for (auto opt : updatedOptions) { mHal->subscribe(opt.propId, opt.vehicleAreas, opt.sampleRate); } - - // TODO(pavelm): call immediately onHalEvent method during subscription - // when appropriate // TODO(pavelm): link to death callback (not implemented yet in HIDL) - return ok(); + return StatusCode::OK; } Return<StatusCode> VehicleHalManager::unsubscribe( @@ -142,12 +169,12 @@ Return<StatusCode> VehicleHalManager::unsubscribe( if (mSubscriptionManager.unsubscribe(callback, propId)) { mHal->unsubscribe(propId); } - return ok(); + return StatusCode::OK; } Return<void> VehicleHalManager::debugDump(IVehicle::debugDump_cb _hidl_cb) { _hidl_cb(""); - return hardware::Return<void>(); + return Void(); } void VehicleHalManager::init() { @@ -155,6 +182,7 @@ void VehicleHalManager::init() { mHidlVecOfVehiclePropValuePool.resize(kMaxHidlVecOfVehiclPropValuePoolSize); + mBatchingConsumer.run(&mEventQueue, kHalEventBatchingTimeWindow, std::bind(&VehicleHalManager::onBatchHalEvent, @@ -162,7 +190,8 @@ void VehicleHalManager::init() { mHal->init(&mValueObjectPool, std::bind(&VehicleHalManager::onHalEvent, this, _1), - std::bind(&VehicleHalManager::onHalError, this, _1, _2, _3)); + std::bind(&VehicleHalManager::onHalPropertySetError, this, + _1, _2, _3)); // Initialize index with vehicle configurations received from VehicleHal. mConfigIndex.reset(new VehiclePropConfigIndex(mHal->listProperties())); @@ -181,9 +210,15 @@ void VehicleHalManager::onHalEvent(VehiclePropValuePtr v) { mEventQueue.push(std::move(v)); } -void VehicleHalManager::onHalError(VehicleProperty property, status_t errorCode, - VehiclePropertyOperation operation) { - // TODO(pavelm): find subscribed clients and propagate error +void VehicleHalManager::onHalPropertySetError(StatusCode errorCode, + VehicleProperty property, + int32_t areaId) { + const auto& clients = mSubscriptionManager.getSubscribedClients( + property, 0, SubscribeFlags::HAL_EVENT); + + for (auto client : clients) { + client->getCallback()->onPropertySetError(errorCode, property, areaId); + } } void VehicleHalManager::onBatchHalEvent( @@ -192,7 +227,7 @@ void VehicleHalManager::onBatchHalEvent( values, SubscribeFlags::HAL_EVENT); for (const HalClientValues& cv : clientValues) { - int vecSize = cv.values.size(); + auto vecSize = cv.values.size(); hidl_vec<VehiclePropValue> vec; if (vecSize < kMaxHidlVecOfVehiclPropValuePoolSize) { vec.setToExternal(&mHidlVecOfVehiclePropValuePool[0], vecSize); @@ -236,9 +271,12 @@ float VehicleHalManager::checkSampleRate(const VehiclePropConfig &config, return sampleRate; // Provided sample rate was good, no changes. } -bool VehicleHalManager::isSubscribable(const VehiclePropConfig& config) { - if (!(config.access & VehiclePropertyAccess::READ)) { - ALOGW("Cannot subscribe, property 0x%x is write only", config.prop); +bool VehicleHalManager::isSubscribable(const VehiclePropConfig& config, + SubscribeFlags flags) { + bool isReadable = config.access & VehiclePropertyAccess::READ; + + if (!isReadable && (SubscribeFlags::HAL_EVENT & flags)) { + ALOGW("Cannot subscribe, property 0x%x is not readable", config.prop); return false; } if (config.changeMode == VehiclePropertyChangeMode::STATIC) { @@ -254,6 +292,49 @@ bool VehicleHalManager::isSubscribable(const VehiclePropConfig& config) { return true; } +bool VehicleHalManager::checkWritePermission(const VehiclePropConfig &config, + const Callee& callee) { + if (!(config.access & VehiclePropertyAccess::WRITE)) { + ALOGW("Property 0%x has no write access", config.prop); + return false; + } + //TODO(pavelm): check pid/uid has write access + return true; +} + +bool VehicleHalManager::checkReadPermission(const VehiclePropConfig &config, + const Callee& callee) { + if (!(config.access & VehiclePropertyAccess::READ)) { + ALOGW("Property 0%x has no read access", config.prop); + return false; + } + //TODO(pavelm): check pid/uid has read access + return true; +} + +void VehicleHalManager::handlePropertySetEvent(const VehiclePropValue& value) { + auto clients = mSubscriptionManager.getSubscribedClients( + value.prop, value.areaId, SubscribeFlags::SET_CALL); + for (auto client : clients) { + client->getCallback()->onPropertySet(value); + } +} + +const VehiclePropConfig* VehicleHalManager::getPropConfigOrNull( + VehicleProperty prop) const { + return mConfigIndex->hasConfig(prop) + ? &mConfigIndex->getConfig(prop) : nullptr; +} + +Callee VehicleHalManager::getCallee() { + Callee callee; + IPCThreadState* self = IPCThreadState::self(); + callee.pid = self->getCallingPid(); + callee.uid = self->getCallingUid(); + + return callee; +} + } // namespace V2_0 } // namespace vehicle } // namespace hardware diff --git a/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.h b/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.h index 0353a153a4..8353679807 100644 --- a/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.h +++ b/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.h @@ -40,6 +40,11 @@ namespace hardware { namespace vehicle { namespace V2_0 { +struct Callee { + pid_t pid; + uid_t uid; +}; + /** * This class is a thick proxy between IVehicle HIDL interface and vendor's implementation. * @@ -62,7 +67,8 @@ public: Return<void> getAllPropConfigs(getAllPropConfigs_cb _hidl_cb) override; Return<void> getPropConfigs(const hidl_vec<VehicleProperty>& properties, getPropConfigs_cb _hidl_cb) override; - Return<void> get(VehicleProperty propId, int32_t areaId, get_cb _hidl_cb) override; + Return<void> get(const VehiclePropValue& requestedPropValue, + get_cb _hidl_cb) override; Return<StatusCode> set(const VehiclePropValue& value) override; Return<StatusCode> subscribe(const sp<IVehicleCallback>& callback, const hidl_vec<SubscribeOptions>& options) override; @@ -72,29 +78,34 @@ public: private: using VehiclePropValuePtr = VehicleHal::VehiclePropValuePtr; + // Returns true if needs to call again shortly. + using RetriableAction = std::function<bool()>; // --------------------------------------------------------------------------------------------- // Events received from VehicleHal void onHalEvent(VehiclePropValuePtr v); - void onHalError(VehicleProperty property, - status_t errorCode, - VehiclePropertyOperation operation); + void onHalPropertySetError(StatusCode errorCode, VehicleProperty property, + int32_t areaId); // --------------------------------------------------------------------------------------------- // This method will be called from BatchingConsumer thread void onBatchHalEvent(const std::vector<VehiclePropValuePtr >& values); - static bool isSubscribable(const VehiclePropConfig& config); + void handlePropertySetEvent(const VehiclePropValue& value); + + const VehiclePropConfig* getPropConfigOrNull(VehicleProperty prop) const; + + static bool isSubscribable(const VehiclePropConfig& config, + SubscribeFlags flags); static bool isSampleRateFixed(VehiclePropertyChangeMode mode); static float checkSampleRate(const VehiclePropConfig& config, float sampleRate); + static bool checkWritePermission(const VehiclePropConfig &config, + const Callee& callee); + static bool checkReadPermission(const VehiclePropConfig &config, + const Callee& callee); - static Return<StatusCode> ok() { - return Return<StatusCode>(StatusCode::OK); - } - static Return<StatusCode> invalidArg() { - return Return<StatusCode>(StatusCode::INVALID_ARG); - } + static Callee getCallee(); private: VehicleHal* mHal; diff --git a/vehicle/2.0/default/vehicle_hal_manager/VehicleObjectPool.h b/vehicle/2.0/default/vehicle_hal_manager/VehicleObjectPool.h index 02bfb3f4f9..b4a4b3e1f9 100644 --- a/vehicle/2.0/default/vehicle_hal_manager/VehicleObjectPool.h +++ b/vehicle/2.0/default/vehicle_hal_manager/VehicleObjectPool.h @@ -194,6 +194,10 @@ public: } RecyclableType obtain(const VehiclePropValue& src) { + if (src.prop == VehicleProperty::INVALID) { + ALOGE("Unable to obtain an object from pool for unknown property"); + return RecyclableType(); + } VehiclePropertyType type = getPropType(src.prop); size_t vecSize = getVehicleRawValueVectorSize(src.value, type);; auto dest = obtain(type, vecSize); @@ -206,6 +210,10 @@ public: return dest; } + RecyclableType obtainBoolean(bool value) { + return obtainInt32(value); + } + RecyclableType obtainInt32(int32_t value) { auto val = obtain(VehiclePropertyType::INT32); val->value.int32Values[0] = value; diff --git a/vehicle/2.0/default/vehicle_hal_manager/VehicleUtils.h b/vehicle/2.0/default/vehicle_hal_manager/VehicleUtils.h index f23a235c3f..5751eb1f3b 100644 --- a/vehicle/2.0/default/vehicle_hal_manager/VehicleUtils.h +++ b/vehicle/2.0/default/vehicle_hal_manager/VehicleUtils.h @@ -54,7 +54,7 @@ inline typename std::underlying_type<ENUM>::type operator &(ENUM v1, ENUM v2) { /** Returns underlying (integer) value for given enum. */ template <typename ENUM> -inline typename std::underlying_type<ENUM>::type val(ENUM const value) { +inline typename std::underlying_type<ENUM>::type toInt(ENUM const value) { return static_cast<typename std::underlying_type<ENUM>::type>(value); } diff --git a/vehicle/2.0/types.hal b/vehicle/2.0/types.hal index 03c1021c06..adcc90ce36 100644 --- a/vehicle/2.0/types.hal +++ b/vehicle/2.0/types.hal @@ -611,20 +611,24 @@ enum VehicleProperty: int32_t { * Property to control audio volume of each audio context. * * VehiclePropConfig - * configArray[0] : bit flags of all supported audio contexts. If this - * is 0, audio volume is controlled per physical stream + * configArray[0] : bit flags of all supported audio contexts from + * VehicleAudioContextFlag. If this is 0, audio volume is + * controlled per physical stream. * configArray[1] : flags defined in VehicleAudioVolumeCapabilityFlag to - * represent audio module's capability. + * represent audio module's capability. + * configArray[2..3] : reserved + * configArray[4..N+3] : maximum values for each audio context, where N is + * the number of audio contexts provided in + * configArray[0], minimum value is always 0 which + * indicates mute state. * * Data type looks like: * int32Values[0] : stream context as defined in VehicleAudioContextFlag. * If only physical stream is supported * (configArray[0] == 0), this must represent physical - stream number. - * int32Values[1] : volume level, valid range is 0 to int32MaxValue - * defined in config. - * 0 must be mute state. int32MinValue config must be - * always 0. + * stream number. + * int32Values[1] : volume level, valid range is 0 (mute) to max level + * defined in the config. * int32Values[2] : One of VehicleAudioVolumeState. * * This property requires per stream based get. HAL implementation must @@ -765,7 +769,7 @@ enum VehicleProperty: int32_t { * will be set to 0x2|0x4. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:WRITE|VehiclePropertyAccess:READ_WRITE + * @access VehiclePropertyAccess:READ_WRITE * @config_string List of all avaiable external source in the system. */ AUDIO_EXT_ROUTING_HINT = ( @@ -790,7 +794,7 @@ enum VehicleProperty: int32_t { * to other displays. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ|VehiclePropertyAccess:READ_WRITE + * @access VehiclePropertyAccess:READ_WRITE */ DISPLAY_BRIGHTNESS = ( 0x0A01 @@ -909,7 +913,7 @@ enum VehicleProperty: int32_t { * ability to write this property. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ DOOR_POS = ( 0x0B00 @@ -921,7 +925,7 @@ enum VehicleProperty: int32_t { * Door move * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ_WRITE|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ DOOR_MOVE = ( 0x0B01 @@ -963,7 +967,7 @@ enum VehicleProperty: int32_t { * Positive value indicates tilt upwards, negative value is downwards * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ_WRITE|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ MIRROR_Z_MOVE = ( 0x0B41 @@ -991,7 +995,7 @@ enum VehicleProperty: int32_t { * Positive value indicate tilt right, negative value is left * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ_WRITE|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ MIRROR_Y_MOVE = ( 0x0B43 @@ -1042,11 +1046,15 @@ enum VehicleProperty: int32_t { | VehicleArea:GLOBAL), /* - * Seat memory set + * Seat memory select * - * This setting allows the user to save the current seat position settings - * into the selected preset slot. The maxValue for each seat position shall - * match the maxValue for SEAT_MEMORY_SELECT. + * This parameter selects the memory preset to use to select the seat + * position. The minValue is always 0, and the maxValue determines the + * number of seat positions available. + * + * For instance, if the driver's seat has 3 memory presets, the maxValue + * will be 3. When the user wants to select a preset, the desired preset + * number (1, 2, or 3) is set. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE * @access VehiclePropertyAccess:WRITE @@ -1082,7 +1090,7 @@ enum VehicleProperty: int32_t { * no known cars at this time, but you never know... * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ SEAT_BELT_BUCKLED = ( 0x0B82 @@ -1110,7 +1118,7 @@ enum VehicleProperty: int32_t { * Seatbelt height move * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ_WRITE|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ SEAT_BELT_HEIGHT_MOVE = ( 0x0B84 @@ -1140,7 +1148,7 @@ enum VehicleProperty: int32_t { * Moves the seat position forward and aft. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ_WRITE|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ SEAT_FORE_AFT_MOVE = ( 0x0B86 @@ -1170,7 +1178,7 @@ enum VehicleProperty: int32_t { * Moves the backrest forward or recline. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ_WRITE|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ SEAT_BACKREST_ANGLE_1_MOVE = ( 0x0B88 @@ -1200,7 +1208,7 @@ enum VehicleProperty: int32_t { * Moves the backrest forward or recline. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ_WRITE|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ SEAT_BACKREST_ANGLE_2_MOVE = ( 0x0B8A @@ -1230,7 +1238,7 @@ enum VehicleProperty: int32_t { * Moves the seat height. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ_WRITE|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ SEAT_HEIGHT_MOVE = ( 0x0B8C @@ -1260,7 +1268,7 @@ enum VehicleProperty: int32_t { * Adjusts the seat depth. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ_WRITE|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ SEAT_DEPTH_MOVE = ( 0x0B8E @@ -1290,7 +1298,7 @@ enum VehicleProperty: int32_t { * Tilts the seat. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ_WRITE|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ SEAT_TILT_MOVE = ( 0x0B90 @@ -1320,7 +1328,7 @@ enum VehicleProperty: int32_t { * Adjusts the lumbar support. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ_WRITE|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ SEAT_LUMBAR_FORE_AFT_MOVE = ( 0x0B92 @@ -1350,7 +1358,7 @@ enum VehicleProperty: int32_t { * Adjusts the amount of lateral lumbar support. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ_WRITE|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ SEAT_LUMBAR_SIDE_SUPPORT_MOVE = ( 0x0B94 @@ -1380,7 +1388,7 @@ enum VehicleProperty: int32_t { * Moves the headrest up and down. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ_WRITE|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ SEAT_HEADREST_HEIGHT_MOVE = ( 0x0B96 @@ -1410,7 +1418,7 @@ enum VehicleProperty: int32_t { * Adjusts the angle of the headrest * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ_WRITE|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ SEAT_HEADREST_ANGLE_MOVE = ( 0x0B98 @@ -1432,7 +1440,7 @@ enum VehicleProperty: int32_t { /* * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ_WRITE|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ SEAT_HEADREST_FORE_AFT_MOVE = ( 0x0B9A @@ -1464,7 +1472,7 @@ enum VehicleProperty: int32_t { * the window. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ_WRITE|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ WINDOW_MOVE = ( 0x0BC1 @@ -1498,7 +1506,7 @@ enum VehicleProperty: int32_t { * Min = vent closed * * @change_mode VehiclePropertyChangeMode:ON_CHANGE - * @access VehiclePropertyAccess:READ_WRITE|VehiclePropertyAccess:WRITE + * @access VehiclePropertyAccess:READ_WRITE */ WINDOW_VENT_MOVE = ( 0x0BC3 @@ -1716,8 +1724,8 @@ enum VehicleAudioVolumeCapabilityFlag : int32_t { /* * External audio module or vehicle hal has persistent storage * to keep the volume level. This must be set only when per context - * volume level is supproted. When this is set, audio volume level per - * each context will be retrieved from the property when systen starts up. + * volume level is supported. When this is set, audio volume level per + * each context will be retrieved from the property when system starts up. * And external audio module is also expected to adjust volume automatically * whenever there is an audio context change. * When this flag is not set, android side will assume that there is no @@ -1755,7 +1763,7 @@ enum VehicleAudioVolumeState : int32_t { enum VehicleAudioVolumeIndex : int32_t { INDEX_STREAM = 0, INDEX_VOLUME = 1, - NDEX_STATE = 2, + INDEX_STATE = 2, }; /* @@ -2336,12 +2344,15 @@ enum VehiclePropertyOperation : int32_t { enum SubscribeFlags { UNDEFINED = 0x0, - /* Subscribe to event that was originated in vehicle HAL (most luckly this + /* + * Subscribe to event that was originated in vehicle HAL (most luckly this * event came from vehicle itself). */ HAL_EVENT = 0x1, - /* Use this flag to subscribe on events when IVehicle#set(...) was called by - * vehicle HAL's client (e.g. Car Service). */ + /* + * Use this flag to subscribe on events when IVehicle#set(...) was called by + * vehicle HAL's client (e.g. Car Service). + */ SET_CALL = 0x2, DEFAULT = HAL_EVENT, @@ -2352,10 +2363,12 @@ enum SubscribeFlags { */ struct SubscribeOptions { /* Property to subscribe */ - VehicleProperty propId; - /* Area ids - this must be a bit mask of areas to subscribe or 0 to subscribe to all areas. */ + /* + * Area ids - this must be a bit mask of areas to subscribe or 0 to subscribe + * to all areas. + */ int32_t vehicleAreas; /* @@ -2380,15 +2393,21 @@ enum StatusCode { OK = 0, /* Try again. */ - TRY_AGAIN = -11, + TRY_AGAIN = 1, /* Invalid argument provided. */ - INVALID_ARG = -22, + INVALID_ARG = 2, /* * This code must be returned when device that associated with the vehicle * property is not available. For example, when client tries to set HVAC * temperature when the whole HVAC unit is turned OFF. */ - NOT_AVAILABLE = -108, + NOT_AVAILABLE = 3, + + /* Access denied */ + ACCESS_DENIED = 4, + + /* Something unexpected has happened in Vehicle HAL */ + INTERNAL_ERROR = 5, }; |