Use FakeUserHal in FakeVehicleHardware.

Handle fake user hal properties in FakeVehicleHardware.

Test: atest FakeVehicleHardwareTest
Bug: 201830716

Change-Id: Ia60bbf7ae6a0fc5909dc8d27363af5c9939055d3
diff --git a/automotive/vehicle/TEST_MAPPING b/automotive/vehicle/TEST_MAPPING
index f55016f..3696351 100644
--- a/automotive/vehicle/TEST_MAPPING
+++ b/automotive/vehicle/TEST_MAPPING
@@ -17,6 +17,9 @@
     },
     {
       "name": "FakeObd2FrameTest"
+    },
+    {
+      "name": "FakeUserHalTest"
     }
   ]
 }
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
index f59a6ed..dfc2efc 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
@@ -35,6 +35,7 @@
         "VehicleHalUtils",
         "FakeVehicleHalValueGenerators",
         "FakeObd2Frame",
+        "FakeUserHal",
     ],
     shared_libs: [
         "libjsoncpp",
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index e1cd8bd..46a526c 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -19,6 +19,7 @@
 
 #include <DefaultConfig.h>
 #include <FakeObd2Frame.h>
+#include <FakeUserHal.h>
 #include <IVehicleHardware.h>
 #include <VehicleHalTypes.h>
 #include <VehiclePropertyStore.h>
@@ -91,6 +92,7 @@
     const std::shared_ptr<VehiclePropValuePool> mValuePool;
     const std::shared_ptr<VehiclePropertyStore> mServerSidePropStore;
     const std::unique_ptr<obd2frame::FakeObd2Frame> mFakeObd2Frame;
+    const std::unique_ptr<FakeUserHal> mFakeUserHal;
     std::mutex mCallbackLock;
     OnPropertyChangeCallback mOnPropertyChangeCallback GUARDED_BY(mCallbackLock);
     OnPropertySetErrorCallback mOnPropertySetErrorCallback GUARDED_BY(mCallbackLock);
@@ -107,16 +109,21 @@
     // Override the properties using config files in 'overrideDir'.
     void overrideProperties(const char* overrideDir);
 
-    ::aidl::android::hardware::automotive::vehicle::StatusCode maybeSetSpecialValue(
+    ::android::base::Result<void> maybeSetSpecialValue(
             const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
             bool* isSpecialValue);
     ::android::base::Result<VehiclePropValuePool::RecyclableType> maybeGetSpecialValue(
             const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
             bool* isSpecialValue) const;
-    ::aidl::android::hardware::automotive::vehicle::StatusCode setApPowerStateReport(
+    ::android::base::Result<void> setApPowerStateReport(
             const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
     VehiclePropValuePool::RecyclableType createApPowerStateReq(
             ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq state);
+    ::android::base::Result<void> setUserHalProp(
+            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
+    ::android::base::Result<VehiclePropValuePool::RecyclableType> getUserHalProp(
+            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
+    bool isHvacPropAndHvacNotAvailable(int32_t propId);
 };
 
 }  // namespace fake
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index 15db767..104147a 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -30,6 +30,7 @@
 #include <sys/types.h>
 #include <fstream>
 #include <regex>
+#include <unordered_set>
 #include <vector>
 
 namespace android {
@@ -55,6 +56,7 @@
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 
+using ::android::base::Error;
 using ::android::base::Result;
 
 const char* VENDOR_OVERRIDE_DIR = "/vendor/etc/automotive/vhaloverride/";
@@ -69,6 +71,11 @@
 }
 
 template <class T>
+int getIntErrorCode(const Result<T>& result) {
+    return toInt(getErrorCode(result));
+}
+
+template <class T>
 std::string getErrorMsg(const Result<T>& result) {
     if (result.ok()) {
         return "";
@@ -114,7 +121,7 @@
                 mServerSidePropStore->writeValue(mValuePool->obtain(prop), /*updateStatus=*/true);
         if (!result.ok()) {
             ALOGE("failed to write default config value, error: %s, status: %d",
-                  getErrorMsg(result).c_str(), getErrorCode(result));
+                  getErrorMsg(result).c_str(), getIntErrorCode(result));
         }
     }
 }
@@ -122,14 +129,16 @@
 FakeVehicleHardware::FakeVehicleHardware()
     : mValuePool(new VehiclePropValuePool),
       mServerSidePropStore(new VehiclePropertyStore(mValuePool)),
-      mFakeObd2Frame(new obd2frame::FakeObd2Frame(mServerSidePropStore)) {
+      mFakeObd2Frame(new obd2frame::FakeObd2Frame(mServerSidePropStore)),
+      mFakeUserHal(new FakeUserHal(mValuePool)) {
     init();
 }
 
 FakeVehicleHardware::FakeVehicleHardware(std::unique_ptr<VehiclePropValuePool> valuePool)
     : mValuePool(std::move(valuePool)),
       mServerSidePropStore(new VehiclePropertyStore(mValuePool)),
-      mFakeObd2Frame(new obd2frame::FakeObd2Frame(mServerSidePropStore)) {
+      mFakeObd2Frame(new obd2frame::FakeObd2Frame(mServerSidePropStore)),
+      mFakeUserHal(new FakeUserHal(mValuePool)) {
     init();
 }
 
@@ -179,16 +188,14 @@
     return req;
 }
 
-StatusCode FakeVehicleHardware::setApPowerStateReport(const VehiclePropValue& value) {
+Result<void> FakeVehicleHardware::setApPowerStateReport(const VehiclePropValue& value) {
     auto updatedValue = mValuePool->obtain(value);
     updatedValue->timestamp = elapsedRealtimeNano();
 
     if (auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
         !writeResult.ok()) {
-        StatusCode errorCode = getErrorCode(writeResult);
-        ALOGE("failed to write value into property store, error: %s, code: %d",
-              getErrorMsg(writeResult).c_str(), errorCode);
-        return errorCode;
+        return Error(getIntErrorCode(writeResult))
+               << "failed to write value into property store, error: " << getErrorMsg(writeResult);
     }
 
     VehiclePropValuePool::RecyclableType prop;
@@ -208,10 +215,9 @@
             if (auto writeResult =
                         mServerSidePropStore->writeValue(std::move(prop), /*updateStatus=*/true);
                 !writeResult.ok()) {
-                StatusCode errorCode = getErrorCode(writeResult);
-                ALOGE("failed to write AP_POWER_STATE_REQ into property store, error: %s, code: %d",
-                      getErrorMsg(writeResult).c_str(), errorCode);
-                return errorCode;
+                return Error(getIntErrorCode(writeResult))
+                       << "failed to write AP_POWER_STATE_REQ into property store, error: "
+                       << getErrorMsg(writeResult);
             }
             break;
         case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
@@ -226,17 +232,73 @@
             if (auto writeResult =
                         mServerSidePropStore->writeValue(std::move(prop), /*updateStatus=*/true);
                 !writeResult.ok()) {
-                StatusCode errorCode = getErrorCode(writeResult);
-                ALOGE("failed to write AP_POWER_STATE_REQ into property store, error: %s, code: %d",
-                      getErrorMsg(writeResult).c_str(), errorCode);
-                return errorCode;
+                return Error(getIntErrorCode(writeResult))
+                       << "failed to write AP_POWER_STATE_REQ into property store, error: "
+                       << getErrorMsg(writeResult);
             }
             break;
         default:
             ALOGE("Unknown VehicleApPowerStateReport: %d", state);
             break;
     }
-    return StatusCode::OK;
+    return {};
+}
+
+bool FakeVehicleHardware::isHvacPropAndHvacNotAvailable(int32_t propId) {
+    std::unordered_set<int32_t> powerProps(std::begin(HVAC_POWER_PROPERTIES),
+                                           std::end(HVAC_POWER_PROPERTIES));
+    if (powerProps.count(propId)) {
+        auto hvacPowerOnResult =
+                mServerSidePropStore->readValue(toInt(VehicleProperty::HVAC_POWER_ON), HVAC_ALL);
+
+        if (hvacPowerOnResult.ok() && hvacPowerOnResult.value()->value.int32Values.size() == 1 &&
+            hvacPowerOnResult.value()->value.int32Values[0] == 0) {
+            return true;
+        }
+    }
+    return false;
+}
+
+Result<void> FakeVehicleHardware::setUserHalProp(const VehiclePropValue& value) {
+    auto result = mFakeUserHal->onSetProperty(value);
+    if (!result.ok()) {
+        return Error(getIntErrorCode(result))
+               << "onSetProperty(): HAL returned error: " << getErrorMsg(result);
+    }
+    auto& updatedValue = result.value();
+    if (updatedValue != nullptr) {
+        ALOGI("onSetProperty(): updating property returned by HAL: %s",
+              updatedValue->toString().c_str());
+        if (auto writeResult = mServerSidePropStore->writeValue(std::move(result.value()));
+            !writeResult.ok()) {
+            return Error(getIntErrorCode(writeResult))
+                   << "failed to write value into property store, error: "
+                   << getErrorMsg(writeResult);
+        }
+    }
+    return {};
+}
+
+Result<VehiclePropValuePool::RecyclableType> FakeVehicleHardware::getUserHalProp(
+        const VehiclePropValue& value) const {
+    auto propId = value.prop;
+    ALOGI("get(): getting value for prop %d from User HAL", propId);
+
+    auto result = mFakeUserHal->onGetProperty(value);
+    if (!result.ok()) {
+        return Error(getIntErrorCode(result))
+               << "get(): User HAL returned error: " << getErrorMsg(result);
+    } else {
+        auto& gotValue = result.value();
+        if (gotValue != nullptr) {
+            ALOGI("get(): User HAL returned value: %s", gotValue->toString().c_str());
+            gotValue->timestamp = elapsedRealtimeNano();
+            return result;
+        } else {
+            return Error(toInt(StatusCode::INTERNAL_ERROR))
+                   << "get(): User HAL returned null value";
+        }
+    }
 }
 
 Result<VehiclePropValuePool::RecyclableType> FakeVehicleHardware::maybeGetSpecialValue(
@@ -245,6 +307,11 @@
     int32_t propId = value.prop;
     Result<VehiclePropValuePool::RecyclableType> result;
 
+    if (mFakeUserHal->isSupported(propId)) {
+        *isSpecialValue = true;
+        return getUserHalProp(value);
+    }
+
     switch (propId) {
         case OBD2_FREEZE_FRAME:
             *isSpecialValue = true;
@@ -268,12 +335,23 @@
     return nullptr;
 }
 
-StatusCode FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValue& value,
-                                                     bool* isSpecialValue) {
+Result<void> FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValue& value,
+                                                       bool* isSpecialValue) {
     *isSpecialValue = false;
     VehiclePropValuePool::RecyclableType updatedValue;
+    int32_t propId = value.prop;
 
-    switch (value.prop) {
+    if (mFakeUserHal->isSupported(propId)) {
+        *isSpecialValue = true;
+        return setUserHalProp(value);
+    }
+
+    if (isHvacPropAndHvacNotAvailable(propId)) {
+        *isSpecialValue = true;
+        return Error(toInt(StatusCode::NOT_AVAILABLE)) << "hvac not available";
+    }
+
+    switch (propId) {
         case toInt(VehicleProperty::AP_POWER_STATE_REPORT):
             *isSpecialValue = true;
             return setApPowerStateReport(value);
@@ -281,7 +359,7 @@
             // Placeholder for future implementation of VMS property in the default hal. For
             // now, just returns OK; otherwise, hal clients crash with property not supported.
             *isSpecialValue = true;
-            return StatusCode::OK;
+            return {};
         case OBD2_FREEZE_FRAME_CLEAR:
             *isSpecialValue = true;
             return mFakeObd2Frame->clearObd2FreezeFrames(value);
@@ -309,18 +387,17 @@
             updatedValue->areaId = value.areaId;
             if (auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
                 !writeResult.ok()) {
-                StatusCode errorCode = getErrorCode(writeResult);
-                ALOGE("failed to write value into property store, error: %s, code: %d",
-                      getErrorMsg(writeResult).c_str(), errorCode);
-                return errorCode;
+                return Error(getIntErrorCode(writeResult))
+                       << "failed to write value into property store, error: "
+                       << getErrorMsg(writeResult);
             }
-            return StatusCode::OK;
+            return {};
 #endif  // ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
 
         default:
             break;
     }
-    return StatusCode::OK;
+    return {};
 }
 
 StatusCode FakeVehicleHardware::setValues(FakeVehicleHardware::SetValuesCallback&& callback,
@@ -338,13 +415,14 @@
         setValueResult.status = StatusCode::OK;
 
         bool isSpecialValue = false;
-        StatusCode status = maybeSetSpecialValue(value, &isSpecialValue);
+        auto setSpecialValueResult = maybeSetSpecialValue(value, &isSpecialValue);
 
         if (isSpecialValue) {
-            if (status != StatusCode::OK) {
-                ALOGE("failed to set special value for property ID: %d, status: %d", propId,
-                      status);
-                setValueResult.status = status;
+            if (!setSpecialValueResult.ok()) {
+                ALOGE("failed to set special value for property ID: %d, error: %s, status: %d",
+                      propId, getErrorMsg(setSpecialValueResult).c_str(),
+                      getIntErrorCode(setSpecialValueResult));
+                setValueResult.status = getErrorCode(setSpecialValueResult);
             }
 
             // Special values are already handled.
@@ -358,10 +436,9 @@
 
         auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
         if (!writeResult.ok()) {
-            StatusCode errorCode = getErrorCode(writeResult);
             ALOGE("failed to write value into property store, error: %s, code: %d",
-                  getErrorMsg(writeResult).c_str(), errorCode);
-            setValueResult.status = errorCode;
+                  getErrorMsg(writeResult).c_str(), getIntErrorCode(writeResult));
+            setValueResult.status = getErrorCode(writeResult);
         }
         results.push_back(std::move(setValueResult));
     }
@@ -387,10 +464,9 @@
         auto result = maybeGetSpecialValue(value, &isSpecialValue);
         if (isSpecialValue) {
             if (!result.ok()) {
-                StatusCode errorCode = getErrorCode(result);
                 ALOGE("failed to get special value: %d, error: %s, code: %d", value.prop,
-                      getErrorMsg(result).c_str(), errorCode);
-                getValueResult.status = errorCode;
+                      getErrorMsg(result).c_str(), getIntErrorCode(result));
+                getValueResult.status = getErrorCode(result);
             } else {
                 getValueResult.status = StatusCode::OK;
                 getValueResult.prop = *result.value();
@@ -406,7 +482,7 @@
                 ALOGW("%s", "value has not been set yet");
             } else {
                 ALOGE("failed to get value, error: %s, code: %d", getErrorMsg(readResult).c_str(),
-                      errorCode);
+                      toInt(errorCode));
             }
             getValueResult.status = errorCode;
         } else {
@@ -476,7 +552,7 @@
                                                                    /*updateStatus=*/true);
                     !result.ok()) {
                     ALOGW("failed to write vendor override properties: %d, error: %s, code: %d",
-                          prop.prop, getErrorMsg(result).c_str(), getErrorCode(result));
+                          prop.prop, getErrorMsg(result).c_str(), getIntErrorCode(result));
                 }
             }
         }
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
index b40c906..90d1516 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
@@ -33,6 +33,7 @@
         "FakeVehicleHardware",
         "FakeVehicleHalValueGenerators",
         "FakeObd2Frame",
+        "FakeUserHal",
         "libgtest",
         "libgmock",
     ],
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index 6f59ce7..88834f3 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -18,6 +18,7 @@
 
 #include <DefaultConfig.h>
 #include <FakeObd2Frame.h>
+#include <FakeUserHal.h>
 #include <PropertyUtils.h>
 #include <TestPropertyUtils.h>
 
@@ -74,7 +75,12 @@
 
 class FakeVehicleHardwareTest : public ::testing::Test {
   protected:
-    void SetUp() override {}
+    void SetUp() override {
+        getHardware()->registerOnPropertyChangeEvent(
+                [this](const std::vector<VehiclePropValue>& values) {
+                    return onPropertyChangeEvent(values);
+                });
+    }
 
     FakeVehicleHardware* getHardware() { return &mHardware; }
 
@@ -171,6 +177,8 @@
 
     const std::vector<VehiclePropValue>& getChangedProperties() { return mChangedProperties; }
 
+    void clearChangedProperties() { mChangedProperties.clear(); }
+
     static void addSetValueRequest(std::vector<SetValueRequest>& requests,
                                    std::vector<SetValueResult>& expectedResults, int64_t requestId,
                                    const VehiclePropValue& value, StatusCode expectedStatus) {
@@ -257,6 +265,11 @@
             continue;
         }
 
+        if (FakeUserHal::isSupported(config.config.prop)) {
+            // Ignore fake user HAL properties, they have special logic for getting values.
+            continue;
+        }
+
         int propId = config.config.prop;
         if (isGlobalProp(propId)) {
             if (config.initialValue == RawPropValues{}) {
@@ -353,6 +366,7 @@
 }
 
 TEST_F(FakeVehicleHardwareTest, testRegisterOnPropertyChangeEvent) {
+    // We have already registered this callback in Setup, here we are registering again.
     getHardware()->registerOnPropertyChangeEvent(std::bind(
             &FakeVehicleHardwareTest_testRegisterOnPropertyChangeEvent_Test::onPropertyChangeEvent,
             this, std::placeholders::_1));
@@ -870,11 +884,6 @@
       public testing::WithParamInterface<SetSpecialValueTestCase> {};
 
 TEST_P(FakeVehicleHardwareSpecialValuesTest, testSetSpecialProperties) {
-    getHardware()->registerOnPropertyChangeEvent(
-            [this](const std::vector<VehiclePropValue>& values) {
-                return onPropertyChangeEvent(values);
-            });
-
     const SetSpecialValueTestCase& tc = GetParam();
 
     for (const auto& value : tc.valuesToSet) {
@@ -970,6 +979,227 @@
     EXPECT_EQ(getValueResult.error(), StatusCode::NOT_AVAILABLE);
 }
 
+TEST_F(FakeVehicleHardwareTest, testGetUserPropertySetOnly) {
+    for (VehicleProperty prop : std::vector<VehicleProperty>({
+                 VehicleProperty::INITIAL_USER_INFO,
+                 VehicleProperty::SWITCH_USER,
+                 VehicleProperty::CREATE_USER,
+                 VehicleProperty::REMOVE_USER,
+         })) {
+        auto result = getValue(VehiclePropValue{.prop = toInt(prop)});
+
+        EXPECT_FALSE(result.ok());
+        if (!result.ok()) {
+            EXPECT_EQ(result.error(), StatusCode::INVALID_ARG);
+        }
+    }
+}
+
+TEST_F(FakeVehicleHardwareTest, testGetUserIdAssoc) {
+    int32_t userIdAssocProp = toInt(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION);
+
+    auto result = getValue(VehiclePropValue{.prop = userIdAssocProp});
+
+    // Default returns NOT_AVAILABLE.
+    ASSERT_FALSE(result.ok());
+    ASSERT_EQ(result.error(), StatusCode::NOT_AVAILABLE);
+
+    // This is the same example as used in User HAL Emulation doc.
+    VehiclePropValue valueToSet = {
+            .prop = toInt(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION),
+            .areaId = 1,
+            .value.int32Values = {666, 1, 1, 2},
+    };
+
+    StatusCode status = setValue(valueToSet);
+
+    ASSERT_EQ(status, StatusCode::OK);
+
+    result = getValue(VehiclePropValue{
+            .prop = userIdAssocProp,
+            // Request ID
+            .value.int32Values = {1},
+    });
+
+    ASSERT_TRUE(result.ok());
+
+    auto& gotValue = result.value();
+    gotValue.timestamp = 0;
+
+    // Expect to get the same request ID.
+    valueToSet.value.int32Values[0] = 1;
+
+    ASSERT_EQ(gotValue, valueToSet);
+}
+
+TEST_F(FakeVehicleHardwareTest, testSwitchUser) {
+    // This is the same example as used in User HAL Emulation doc.
+    VehiclePropValue valueToSet = {
+            .prop = toInt(VehicleProperty::SWITCH_USER),
+            .areaId = 1,
+            .value.int32Values = {666, 3, 2},
+    };
+
+    StatusCode status = setValue(valueToSet);
+
+    ASSERT_EQ(status, StatusCode::OK);
+
+    // Simulate a request from Android side.
+    VehiclePropValue switchUserRequest = {
+            .prop = toInt(VehicleProperty::SWITCH_USER),
+            .areaId = 0,
+            .value.int32Values = {666, 3},
+    };
+    // Clear existing events.
+    clearChangedProperties();
+
+    status = setValue(switchUserRequest);
+
+    ASSERT_EQ(status, StatusCode::OK);
+
+    // Should generate an event for user hal response.
+    auto events = getChangedProperties();
+    ASSERT_EQ(events.size(), static_cast<size_t>(1));
+
+    events[0].timestamp = 0;
+    ASSERT_EQ(events[0], valueToSet);
+
+    // Try to get switch_user again, should return default value.
+    clearChangedProperties();
+    status = setValue(switchUserRequest);
+    ASSERT_EQ(status, StatusCode::OK);
+
+    events = getChangedProperties();
+    ASSERT_EQ(events.size(), static_cast<size_t>(1));
+    events[0].timestamp = 0;
+    ASSERT_EQ(events[0], (VehiclePropValue{
+                                 .areaId = 0,
+                                 .prop = toInt(VehicleProperty::SWITCH_USER),
+                                 .value.int32Values =
+                                         {
+                                                 // Request ID
+                                                 666,
+                                                 // VEHICLE_RESPONSE
+                                                 3,
+                                                 // SUCCESS
+                                                 1,
+                                         },
+                         }));
+}
+
+TEST_F(FakeVehicleHardwareTest, testCreateUser) {
+    // This is the same example as used in User HAL Emulation doc.
+    VehiclePropValue valueToSet = {
+            .prop = toInt(VehicleProperty::CREATE_USER),
+            .areaId = 1,
+            .value.int32Values = {666, 2},
+    };
+
+    StatusCode status = setValue(valueToSet);
+
+    ASSERT_EQ(status, StatusCode::OK);
+
+    // Simulate a request from Android side.
+    VehiclePropValue createUserRequest = {
+            .prop = toInt(VehicleProperty::CREATE_USER),
+            .areaId = 0,
+            .value.int32Values = {666},
+    };
+    // Clear existing events.
+    clearChangedProperties();
+
+    status = setValue(createUserRequest);
+
+    ASSERT_EQ(status, StatusCode::OK);
+
+    // Should generate an event for user hal response.
+    auto events = getChangedProperties();
+    ASSERT_EQ(events.size(), static_cast<size_t>(1));
+    events[0].timestamp = 0;
+    EXPECT_EQ(events[0], valueToSet);
+
+    // Try to get create_user again, should return default value.
+    clearChangedProperties();
+    status = setValue(createUserRequest);
+    ASSERT_EQ(status, StatusCode::OK);
+
+    events = getChangedProperties();
+    ASSERT_EQ(events.size(), static_cast<size_t>(1));
+    events[0].timestamp = 0;
+    ASSERT_EQ(events[0], (VehiclePropValue{
+                                 .areaId = 0,
+                                 .prop = toInt(VehicleProperty::CREATE_USER),
+                                 .value.int32Values =
+                                         {
+                                                 // Request ID
+                                                 666,
+                                                 // SUCCESS
+                                                 1,
+                                         },
+                         }));
+}
+
+TEST_F(FakeVehicleHardwareTest, testInitialUserInfo) {
+    // This is the same example as used in User HAL Emulation doc.
+    VehiclePropValue valueToSet = {
+            .prop = toInt(VehicleProperty::INITIAL_USER_INFO),
+            .areaId = 1,
+            .value.int32Values = {666, 1, 11},
+    };
+
+    StatusCode status = setValue(valueToSet);
+
+    ASSERT_EQ(status, StatusCode::OK);
+
+    // Simulate a request from Android side.
+    VehiclePropValue initialUserInfoRequest = {
+            .prop = toInt(VehicleProperty::INITIAL_USER_INFO),
+            .areaId = 0,
+            .value.int32Values = {3},
+    };
+    // Clear existing events.
+    clearChangedProperties();
+
+    status = setValue(initialUserInfoRequest);
+
+    ASSERT_EQ(status, StatusCode::OK);
+
+    // Should generate an event for user hal response.
+    auto events = getChangedProperties();
+    ASSERT_EQ(events.size(), static_cast<size_t>(1));
+    events[0].timestamp = 0;
+    EXPECT_EQ(events[0], (VehiclePropValue{
+                                 .areaId = 1,
+                                 .prop = toInt(VehicleProperty::INITIAL_USER_INFO),
+                                 .value.int32Values = {3, 1, 11},
+                         }));
+
+    // Try to get create_user again, should return default value.
+    clearChangedProperties();
+    status = setValue(initialUserInfoRequest);
+    ASSERT_EQ(status, StatusCode::OK);
+
+    events = getChangedProperties();
+    ASSERT_EQ(events.size(), static_cast<size_t>(1));
+    events[0].timestamp = 0;
+    EXPECT_EQ(events[0], (VehiclePropValue{
+                                 .areaId = 0,
+                                 .prop = toInt(VehicleProperty::INITIAL_USER_INFO),
+                                 .value.int32Values =
+                                         {
+                                                 // Request ID
+                                                 3,
+                                                 // ACTION: DEFAULT
+                                                 0,
+                                                 // User id: 0
+                                                 0,
+                                                 // Flags: 0
+                                                 0,
+                                         },
+                                 .value.stringValue = "||",
+                         }));
+}
+
 }  // namespace fake
 }  // namespace vehicle
 }  // namespace automotive
diff --git a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/include/FakeObd2Frame.h b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/include/FakeObd2Frame.h
index aee6866..118bb34 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/include/FakeObd2Frame.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/include/FakeObd2Frame.h
@@ -42,7 +42,7 @@
             const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue&
                     requestedPropValue) const;
     ::android::base::Result<VehiclePropValuePool::RecyclableType> getObd2DtcInfo() const;
-    ::aidl::android::hardware::automotive::vehicle::StatusCode clearObd2FreezeFrames(
+    ::android::base::Result<void> clearObd2FreezeFrames(
             const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue);
     static bool isDiagnosticProperty(
             const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig& propConfig);
diff --git a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/src/FakeObd2Frame.cpp b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/src/FakeObd2Frame.cpp
index a9e865d..5585fb4 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/src/FakeObd2Frame.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/src/FakeObd2Frame.cpp
@@ -169,20 +169,21 @@
     return outValue;
 }
 
-StatusCode FakeObd2Frame::clearObd2FreezeFrames(const VehiclePropValue& propValue) {
+Result<void> FakeObd2Frame::clearObd2FreezeFrames(const VehiclePropValue& propValue) {
     if (propValue.value.int64Values.size() == 0) {
         mPropStore->removeValuesForProperty(OBD2_FREEZE_FRAME);
-        return StatusCode::OK;
+        return {};
     }
     for (int64_t timestamp : propValue.value.int64Values) {
-        auto result = mPropStore->readValue(OBD2_FREEZE_FRAME, /*area=*/0, timestamp);
+        auto result = mPropStore->readValue(OBD2_FREEZE_FRAME, 0, timestamp);
         if (!result.ok()) {
-            ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp");
-            return StatusCode::INVALID_ARG;
+            return Error(toInt(StatusCode::INVALID_ARG))
+                   << "asked for OBD2_FREEZE_FRAME at invalid timestamp, error: %s"
+                   << result.error().message();
         }
         mPropStore->removeValue(*result.value());
     }
-    return StatusCode::OK;
+    return {};
 }
 
 bool FakeObd2Frame::isDiagnosticProperty(const VehiclePropConfig& propConfig) {
diff --git a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/test/FakeObd2FrameTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/test/FakeObd2FrameTest.cpp
index 987115a..54ec1b2 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/test/FakeObd2FrameTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/test/FakeObd2FrameTest.cpp
@@ -167,7 +167,7 @@
     ASSERT_EQ(result.value()->prop, OBD2_FREEZE_FRAME_INFO);
     ASSERT_EQ(result.value()->value.int64Values.size(), static_cast<size_t>(3));
 
-    getFakeObd2Frame()->clearObd2FreezeFrames(VehiclePropValue{});
+    ASSERT_TRUE(getFakeObd2Frame()->clearObd2FreezeFrames(VehiclePropValue{}).ok());
 
     result = getFakeObd2Frame()->getObd2DtcInfo();
 
@@ -185,9 +185,11 @@
     ASSERT_EQ(result.value()->prop, OBD2_FREEZE_FRAME_INFO);
     ASSERT_EQ(result.value()->value.int64Values.size(), static_cast<size_t>(3));
 
-    getFakeObd2Frame()->clearObd2FreezeFrames(
-            VehiclePropValue{.value.int64Values = {result.value()->value.int64Values[0],
-                                                   result.value()->value.int64Values[1]}});
+    ASSERT_TRUE(getFakeObd2Frame()
+                        ->clearObd2FreezeFrames(VehiclePropValue{
+                                .value.int64Values = {result.value()->value.int64Values[0],
+                                                      result.value()->value.int64Values[1]}})
+                        .ok());
 
     result = getFakeObd2Frame()->getObd2DtcInfo();
 
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
index 441c54b..2743578 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
@@ -107,7 +107,7 @@
 constexpr int HVAC_RIGHT = SEAT_1_RIGHT | SEAT_2_RIGHT;
 constexpr int HVAC_ALL = HVAC_LEFT | HVAC_RIGHT;
 
-const int32_t kHvacPowerProperties[] = {
+const int32_t HVAC_POWER_PROPERTIES[] = {
         toInt(propertyutils_impl::VehicleProperty::HVAC_FAN_SPEED),
         toInt(propertyutils_impl::VehicleProperty::HVAC_FAN_DIRECTION),
 };