Implemented USER_IDENTIFICATION_ASSOCIATION on EmulatedUserHal.

Bug: 150409351

Test: adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default --set 299896587  a 1 i 666 i 1 i 101 i 2
Test: adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default --get 299896587

Change-Id: I4890ae5c0cea22bf024b1d7429449390237ab244
diff --git a/automotive/vehicle/2.0/default/VehicleService.cpp b/automotive/vehicle/2.0/default/VehicleService.cpp
index 32e5e70..47133fd 100644
--- a/automotive/vehicle/2.0/default/VehicleService.cpp
+++ b/automotive/vehicle/2.0/default/VehicleService.cpp
@@ -22,6 +22,7 @@
 
 #include <android/binder_process.h>
 #include <utils/Looper.h>
+#include <vhal_v2_0/EmulatedUserHal.h>
 #include <vhal_v2_0/EmulatedVehicleConnector.h>
 #include <vhal_v2_0/EmulatedVehicleHal.h>
 #include <vhal_v2_0/VehicleHalManager.h>
@@ -34,7 +35,8 @@
 int main(int /* argc */, char* /* argv */ []) {
     auto store = std::make_unique<VehiclePropertyStore>();
     auto connector = impl::makeEmulatedPassthroughConnector();
-    auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get(), connector.get());
+    auto userHal = connector->getEmulatedUserHal();
+    auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get(), connector.get(), userHal);
     auto emulator = std::make_unique<impl::VehicleEmulator>(hal.get());
     auto service = std::make_unique<VehicleHalManager>(hal.get());
     connector->setValuePool(hal->getValuePool());
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp
index c49fadc..d744a06 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp
@@ -30,11 +30,14 @@
 
 constexpr int INITIAL_USER_INFO = static_cast<int>(VehicleProperty::INITIAL_USER_INFO);
 constexpr int SWITCH_USER = static_cast<int>(VehicleProperty::SWITCH_USER);
+constexpr int USER_IDENTIFICATION_ASSOCIATION =
+        static_cast<int>(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION);
 
 bool EmulatedUserHal::isSupported(int32_t prop) {
     switch (prop) {
         case INITIAL_USER_INFO:
         case SWITCH_USER:
+        case USER_IDENTIFICATION_ASSOCIATION:
             return true;
         default:
             return false;
@@ -50,12 +53,41 @@
             return onSetInitialUserInfoResponse(value);
         case SWITCH_USER:
             return onSetSwitchUserResponse(value);
+        case USER_IDENTIFICATION_ASSOCIATION:
+            return onSetUserIdentificationAssociation(value);
         default:
             return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
                    << "Unsupported property: " << toString(value);
     }
 }
 
+android::base::Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onGetProperty(
+        int32_t prop) {
+    ALOGV("onGetProperty(%d)", prop);
+    switch (prop) {
+        case INITIAL_USER_INFO:
+        case SWITCH_USER:
+            ALOGE("onGetProperty(): %d is only supported on SET", prop);
+            return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
+                   << "only supported on SET";
+        case USER_IDENTIFICATION_ASSOCIATION:
+            if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) {
+                ALOGI("onGetProperty(%d): returning %s", prop,
+                      toString(*mSetUserIdentificationAssociationResponseFromCmd).c_str());
+                auto value = std::unique_ptr<VehiclePropValue>(
+                        new VehiclePropValue(*mSetUserIdentificationAssociationResponseFromCmd));
+                return value;
+            }
+            ALOGE("onGetProperty(%d): USER_IDENTIFICATION_ASSOCIATION not set by lshal", prop);
+            return android::base::Error(static_cast<int>(StatusCode::NOT_AVAILABLE))
+                   << "not set by lshal";
+        default:
+            ALOGE("onGetProperty(): %d is not supported", prop);
+            return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
+                   << "not supported by User HAL";
+    }
+}
+
 android::base::Result<std::unique_ptr<VehiclePropValue>>
 EmulatedUserHal::onSetInitialUserInfoResponse(const VehiclePropValue& value) {
     if (value.value.int32Values.size() == 0) {
@@ -130,6 +162,46 @@
     return updatedValue;
 }
 
+android::base::Result<std::unique_ptr<VehiclePropValue>>
+EmulatedUserHal::onSetUserIdentificationAssociation(const VehiclePropValue& value) {
+    if (value.value.int32Values.size() == 0) {
+        ALOGE("set(USER_IDENTIFICATION_ASSOCIATION): no int32values, ignoring it: %s",
+              toString(value).c_str());
+        return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
+               << "no int32values on " << toString(value);
+    }
+
+    if (value.areaId != 0) {
+        ALOGD("set(USER_IDENTIFICATION_ASSOCIATION) called from lshal; storing it: %s",
+              toString(value).c_str());
+        mSetUserIdentificationAssociationResponseFromCmd.reset(new VehiclePropValue(value));
+        return {};
+    }
+    ALOGD("set(USER_IDENTIFICATION_ASSOCIATION) called from Android: %s", toString(value).c_str());
+
+    int32_t requestId = value.value.int32Values[0];
+    if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) {
+        ALOGI("replying USER_IDENTIFICATION_ASSOCIATION with lshal value:  %s",
+              toString(*mSetUserIdentificationAssociationResponseFromCmd).c_str());
+        // Not moving response so it can be used on GET requests
+        auto copy = std::unique_ptr<VehiclePropValue>(
+                new VehiclePropValue(*mSetUserIdentificationAssociationResponseFromCmd));
+        return sendUserHalResponse(std::move(copy), requestId);
+    }
+
+    // Returns default response
+    auto updatedValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue);
+    updatedValue->prop = USER_IDENTIFICATION_ASSOCIATION;
+    updatedValue->timestamp = elapsedRealtimeNano();
+    updatedValue->value.int32Values.resize(1);
+    updatedValue->value.int32Values[0] = requestId;
+    updatedValue->value.stringValue = "Response not set by LSHAL";
+
+    ALOGI("no lshal response; replying with an error message: %s", toString(*updatedValue).c_str());
+
+    return updatedValue;
+}
+
 android::base::Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::sendUserHalResponse(
         std::unique_ptr<VehiclePropValue> response, int32_t requestId) {
     switch (response->areaId) {
@@ -175,6 +247,12 @@
     } else {
         dprintf(fd, "%sNo SwitchUser response\n", indent.c_str());
     }
+    if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) {
+        dprintf(fd, "%sSetUserIdentificationAssociation response: %s\n", indent.c_str(),
+                toString(*mSetUserIdentificationAssociationResponseFromCmd).c_str());
+    } else {
+        dprintf(fd, "%sNo SetUserIdentificationAssociation response\n", indent.c_str());
+    }
 }
 
 }  // namespace impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.h
index b25efcb..3168d75 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.h
@@ -46,7 +46,7 @@
     bool isSupported(int32_t prop);
 
     /**
-     * Lets the emulator handle the property.
+     * Lets the emulator set the property.
      *
      * @return updated property and StatusCode
      */
@@ -54,6 +54,13 @@
             const VehiclePropValue& value);
 
     /**
+     * Gets the property value from the emulator.
+     *
+     * @return property value and StatusCode
+     */
+    android::base::Result<std::unique_ptr<VehiclePropValue>> onGetProperty(int32_t prop);
+
+    /**
      * Shows the User HAL emulation help.
      */
     void showDumpHelp(int fd);
@@ -97,11 +104,19 @@
     android::base::Result<std::unique_ptr<VehiclePropValue>> onSetSwitchUserResponse(
             const VehiclePropValue& value);
 
+    /**
+     * Used to emulate USER_IDENTIFICATION_ASSOCIATION - see onSetInitialUserInfoResponse() for
+     * usage.
+     */
+    android::base::Result<std::unique_ptr<VehiclePropValue>> onSetUserIdentificationAssociation(
+            const VehiclePropValue& value);
+
     android::base::Result<std::unique_ptr<VehiclePropValue>> sendUserHalResponse(
             std::unique_ptr<VehiclePropValue> response, int32_t requestId);
 
     std::unique_ptr<VehiclePropValue> mInitialUserResponseFromCmd;
     std::unique_ptr<VehiclePropValue> mSwitchUserResponseFromCmd;
+    std::unique_ptr<VehiclePropValue> mSetUserIdentificationAssociationResponseFromCmd;
 };
 
 }  // namespace impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index 02c00c1..9cfcc1c 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -92,12 +92,14 @@
     return sensorStore;
 }
 
-EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client)
+EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client,
+                                       EmulatedUserHal* emulatedUserHal)
     : mPropStore(propStore),
       mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
       mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this,
                                 std::placeholders::_1)),
-      mVehicleClient(client) {
+      mVehicleClient(client),
+      mEmulatedUserHal(emulatedUserHal) {
     initStaticConfig();
     for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
         mPropStore->registerProperty(kVehicleProperties[i].config);
@@ -134,6 +136,8 @@
 VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
         const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
     auto propId = requestedPropValue.prop;
+    ALOGV("get(%d)", propId);
+
     auto& pool = *getValuePool();
     VehiclePropValuePtr v = nullptr;
 
@@ -147,6 +151,26 @@
             *outStatus = fillObd2DtcInfo(v.get());
             break;
         default:
+            if (mEmulatedUserHal != nullptr && mEmulatedUserHal->isSupported(propId)) {
+                ALOGI("get(): getting value for prop %d from User HAL", propId);
+                const auto& ret = mEmulatedUserHal->onGetProperty(propId);
+                if (!ret.ok()) {
+                    ALOGE("get(): User HAL returned error: %s", ret.error().message().c_str());
+                    *outStatus = StatusCode(ret.error().code());
+                } else {
+                    auto value = ret.value().get();
+                    if (value != nullptr) {
+                        ALOGI("get(): User HAL returned value: %s", toString(*value).c_str());
+                        v = getValuePool()->obtain(*value);
+                        *outStatus = StatusCode::OK;
+                    } else {
+                        ALOGE("get(): User HAL returned null value");
+                        *outStatus = StatusCode::INTERNAL_ERROR;
+                    }
+                }
+                break;
+            }
+
             auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue);
             if (internalPropValue != nullptr) {
                 v = getValuePool()->obtain(*internalPropValue);
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index cba4b8a..eb38d7d 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -30,6 +30,7 @@
 #include "vhal_v2_0/VehiclePropertyStore.h"
 
 #include "DefaultConfig.h"
+#include "EmulatedUserHal.h"
 #include "EmulatedVehicleConnector.h"
 #include "GeneratorHub.h"
 #include "VehicleEmulator.h"
@@ -45,8 +46,8 @@
 /** Implementation of VehicleHal that connected to emulator instead of real vehicle network. */
 class EmulatedVehicleHal : public EmulatedVehicleHalIface {
 public:
-    EmulatedVehicleHal(VehiclePropertyStore* propStore,
-                       VehicleHalClient* client);
+    EmulatedVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client,
+                       EmulatedUserHal* emulatedUserHal = nullptr);
     ~EmulatedVehicleHal() = default;
 
     //  Methods from VehicleHal
@@ -90,6 +91,7 @@
     bool mInEmulator;
     bool mInitVhalValueOverride;
     std::vector<VehiclePropValue> mVehiclePropertiesOverride;
+    EmulatedUserHal* mEmulatedUserHal;
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp
index ad5096e..36f2534 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp
@@ -41,6 +41,10 @@
     return mValuePool;
 }
 
+EmulatedUserHal* VehicleHalServer::getEmulatedUserHal() {
+    return &mEmulatedUserHal;
+}
+
 void VehicleHalServer::setValuePool(VehiclePropValuePool* valuePool) {
     if (!valuePool) {
         LOG(WARNING) << __func__ << ": Setting value pool to nullptr!";
@@ -197,6 +201,7 @@
         }
         return StatusCode::OK;
     }
+    LOG(DEBUG) << "onSetProperty(" << value.prop << ")";
 
     // Some properties need to be treated non-trivially
     switch (value.prop) {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h
index 2841fbe..fca78bc 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h
@@ -38,6 +38,8 @@
     // Set the Property Value Pool used in this server
     void setValuePool(VehiclePropValuePool* valuePool);
 
+    EmulatedUserHal* getEmulatedUserHal();
+
   private:
     using VehiclePropValuePtr = recyclable_ptr<VehiclePropValue>;