OSDN Git Service

Vehicle HAL reference impl Part II
authorPavel Maltsev <pavelm@google.com>
Thu, 27 Oct 2016 22:43:06 +0000 (15:43 -0700)
committerPavel Maltsev <pavelm@google.com>
Wed, 2 Nov 2016 21:31:34 +0000 (14:31 -0700)
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

18 files changed:
vehicle/2.0/IVehicle.hal
vehicle/2.0/IVehicleCallback.hal
vehicle/2.0/default/Android.mk
vehicle/2.0/default/VehicleHal.h
vehicle/2.0/default/impl/DefaultConfig.h
vehicle/2.0/default/impl/DefaultVehicleHal.cpp
vehicle/2.0/default/impl/DefaultVehicleHal.h
vehicle/2.0/default/tests/SubscriptionManager_test.cpp
vehicle/2.0/default/tests/VehicleHalManager_test.cpp
vehicle/2.0/default/tests/VehicleHalTestUtils.h
vehicle/2.0/default/vehicle_hal_manager/ConcurrentQueue.h
vehicle/2.0/default/vehicle_hal_manager/VehicleCallback.cpp [deleted file]
vehicle/2.0/default/vehicle_hal_manager/VehicleCallback.h [deleted file]
vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.cpp
vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.h
vehicle/2.0/default/vehicle_hal_manager/VehicleObjectPool.h
vehicle/2.0/default/vehicle_hal_manager/VehicleUtils.h
vehicle/2.0/types.hal

index 4c02447..5b0df67 100644 (file)
@@ -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);
index 5c1042b..504f782 100644 (file)
@@ -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);
 };
index e14cb19..90353ee 100644 (file)
@@ -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 \
index 89d8ef8..2807f28 100644 (file)
@@ -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;
 };
 
index 6f04626..e620c28 100644 (file)
@@ -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,
                  }
index 6ca0f9f..24d438d 100644 (file)
@@ -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
index 7d0b7cb..4a81da3 100644 (file)
@@ -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;
index c3db993..19b11e6 100644 (file)
@@ -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));
 }
index 1410ddf..6ef1205 100644 (file)
@@ -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);
index b3b3ffa..16d0be9 100644 (file)
@@ -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>
index a64ef46..485f3dc 100644 (file)
@@ -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 (file)
index 985b7dc..0000000
+++ /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 (file)
index d037c94..0000000
+++ /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_
index 8638131..a84f991 100644 (file)
@@ -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
index 0353a15..8353679 100644 (file)
@@ -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;
index 02bfb3f..b4a4b3e 100644 (file)
@@ -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;
index f23a235..5751eb1 100644 (file)
@@ -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);
 }
 
index 03c1021..adcc90c 100644 (file)
@@ -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,
 };