[automerger skipped] Merge "Add a native UserHalHelper library." am: 82120a8ce4 am: 67a276e764 am: c9a594fc65 am: e14c0eae69 -s ours

am skip reason: Change-Id I978b39e2f3ee58eb3b154f507c714ca1ba2d1e3b with SHA-1 b33e2abbfe is in history

Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1425310

Change-Id: I4010385f34de99cd9a0dc2b9ccaeb15dbf694dd5
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index d9ac239..9a0d89d 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -108,6 +108,9 @@
     srcs: [
         "impl/vhal_v2_0/EmulatedUserHal.cpp",
     ],
+    whole_static_libs: [
+        "android.hardware.automotive.vehicle@2.0-user-hal-helper-lib",
+    ],
 }
 
 // Vehicle HAL Server reference impl lib
@@ -143,6 +146,7 @@
     ],
     whole_static_libs: [
         "android.hardware.automotive.vehicle@2.0-server-common-lib",
+        "android.hardware.automotive.vehicle@2.0-user-hal-helper-lib",
     ],
     static_libs: [
         "android.hardware.automotive.vehicle@2.0-libproto-native",
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 16c33b9..16e1bf7 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -266,6 +266,20 @@
          .initialValue = {.stringValue = "Toy Vehicle"}},
         {.config =
                  {
+                         .prop = toInt(VehicleProperty::INFO_MODEL),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::STATIC,
+                 },
+         .initialValue = {.stringValue = "Speedy Model"}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::INFO_MODEL_YEAR),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::STATIC,
+                 },
+         .initialValue = {.int32Values = {2020}}},
+        {.config =
+                 {
                          .prop = toInt(VehicleProperty::INFO_EXTERIOR_DIMENSIONS),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::STATIC,
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 ea38cb3..3bdf5a8 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
@@ -15,10 +15,12 @@
  */
 #define LOG_TAG "EmulatedUserHal"
 
+#include "EmulatedUserHal.h"
+
 #include <cutils/log.h>
 #include <utils/SystemClock.h>
 
-#include "EmulatedUserHal.h"
+#include "UserHalHelper.h"
 
 namespace android {
 namespace hardware {
@@ -28,12 +30,35 @@
 
 namespace impl {
 
-constexpr int INITIAL_USER_INFO = static_cast<int>(VehicleProperty::INITIAL_USER_INFO);
-constexpr int SWITCH_USER = static_cast<int>(VehicleProperty::SWITCH_USER);
-constexpr int CREATE_USER = static_cast<int>(VehicleProperty::CREATE_USER);
-constexpr int REMOVE_USER = static_cast<int>(VehicleProperty::REMOVE_USER);
-constexpr int USER_IDENTIFICATION_ASSOCIATION =
-        static_cast<int>(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION);
+namespace {
+
+using android::base::Error;
+using android::base::Result;
+
+constexpr int32_t INITIAL_USER_INFO = static_cast<int32_t>(VehicleProperty::INITIAL_USER_INFO);
+constexpr int32_t SWITCH_USER = static_cast<int32_t>(VehicleProperty::SWITCH_USER);
+constexpr int32_t CREATE_USER = static_cast<int32_t>(VehicleProperty::CREATE_USER);
+constexpr int32_t REMOVE_USER = static_cast<int32_t>(VehicleProperty::REMOVE_USER);
+constexpr int32_t USER_IDENTIFICATION_ASSOCIATION =
+        static_cast<int32_t>(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION);
+
+Result<int32_t> getRequestId(const VehiclePropValue& value) {
+    if (value.value.int32Values.size() < 1) {
+        return Error(static_cast<int>(StatusCode::INVALID_ARG))
+               << "no int32values on " << toString(value);
+    }
+    return value.value.int32Values[0];
+}
+
+Result<SwitchUserMessageType> getSwitchUserMessageType(const VehiclePropValue& value) {
+    if (value.value.int32Values.size() < 2) {
+        return Error(static_cast<int>(StatusCode::INVALID_ARG))
+               << "missing switch user message type " << toString(value);
+    }
+    return user_hal_helper::verifyAndCast<SwitchUserMessageType>(value.value.int32Values[1]);
+}
+
+}  // namespace
 
 bool EmulatedUserHal::isSupported(int32_t prop) {
     switch (prop) {
@@ -48,7 +73,7 @@
     }
 }
 
-android::base::Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetProperty(
+Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetProperty(
         const VehiclePropValue& value) {
     ALOGV("onSetProperty(): %s", toString(value).c_str());
 
@@ -65,12 +90,12 @@
         case USER_IDENTIFICATION_ASSOCIATION:
             return onSetUserIdentificationAssociation(value);
         default:
-            return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
+            return Error(static_cast<int>(StatusCode::INVALID_ARG))
                    << "Unsupported property: " << toString(value);
     }
 }
 
-android::base::Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onGetProperty(
+Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onGetProperty(
         const VehiclePropValue& value) {
     ALOGV("onGetProperty(%s)", toString(value).c_str());
     switch (value.prop) {
@@ -79,42 +104,41 @@
         case CREATE_USER:
         case REMOVE_USER:
             ALOGE("onGetProperty(): %d is only supported on SET", value.prop);
-            return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
-                   << "only supported on SET";
+            return Error(static_cast<int>(StatusCode::INVALID_ARG)) << "only supported on SET";
         case USER_IDENTIFICATION_ASSOCIATION:
             return onGetUserIdentificationAssociation(value);
         default:
             ALOGE("onGetProperty(): %d is not supported", value.prop);
-            return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
-                   << "not supported by User HAL";
+            return Error(static_cast<int>(StatusCode::INVALID_ARG)) << "not supported by User HAL";
     }
 }
 
-android::base::Result<std::unique_ptr<VehiclePropValue>>
-EmulatedUserHal::onGetUserIdentificationAssociation(const VehiclePropValue& value) {
-    if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) {
-        ALOGI("get(USER_IDENTIFICATION_ASSOCIATION): returning %s",
-              toString(*mSetUserIdentificationAssociationResponseFromCmd).c_str());
-        auto newValue = std::unique_ptr<VehiclePropValue>(
-                new VehiclePropValue(*mSetUserIdentificationAssociationResponseFromCmd));
+Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onGetUserIdentificationAssociation(
+        const VehiclePropValue& value) {
+    if (mSetUserIdentificationAssociationResponseFromCmd == nullptr) {
+        return defaultUserIdentificationAssociation(value);
+    }
+    ALOGI("get(USER_IDENTIFICATION_ASSOCIATION): returning %s",
+          toString(*mSetUserIdentificationAssociationResponseFromCmd).c_str());
+    auto newValue = std::unique_ptr<VehiclePropValue>(
+            new VehiclePropValue(*mSetUserIdentificationAssociationResponseFromCmd));
+    auto requestId = getRequestId(value);
+    if (requestId.ok()) {
         // Must use the same requestId
-        if (value.value.int32Values.size() > 0) {
-            newValue->value.int32Values[0] = value.value.int32Values[0];
-        } else {
-            ALOGE("get(USER_IDENTIFICATION_ASSOCIATION): no requestId on %s",
-                  toString(value).c_str());
-        }
-        return newValue;
+        newValue->value.int32Values[0] = *requestId;
+    } else {
+        ALOGE("get(USER_IDENTIFICATION_ASSOCIATION): no requestId on %s", toString(value).c_str());
     }
-    return defaultUserIdentificationAssociation(value);
+    return newValue;
 }
 
-android::base::Result<std::unique_ptr<VehiclePropValue>>
-EmulatedUserHal::onSetInitialUserInfoResponse(const VehiclePropValue& value) {
-    if (value.value.int32Values.size() == 0) {
-        ALOGE("set(INITIAL_USER_INFO): no int32values, ignoring it: %s", toString(value).c_str());
-        return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
-               << "no int32values on " << toString(value);
+Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetInitialUserInfoResponse(
+        const VehiclePropValue& value) {
+    auto requestId = getRequestId(value);
+    if (!requestId.ok()) {
+        ALOGE("Failed to get requestId on set(INITIAL_USER_INFO): %s",
+              requestId.error().message().c_str());
+        return requestId.error();
     }
 
     if (value.areaId != 0) {
@@ -124,85 +148,82 @@
     }
 
     ALOGD("set(INITIAL_USER_INFO) called from Android: %s", toString(value).c_str());
-
-    int32_t requestId = value.value.int32Values[0];
     if (mInitialUserResponseFromCmd != nullptr) {
         ALOGI("replying INITIAL_USER_INFO with lshal value:  %s",
               toString(*mInitialUserResponseFromCmd).c_str());
-        return sendUserHalResponse(std::move(mInitialUserResponseFromCmd), requestId);
+        return sendUserHalResponse(std::move(mInitialUserResponseFromCmd), *requestId);
     }
 
     // Returns default response
-    auto updatedValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue);
-    updatedValue->prop = INITIAL_USER_INFO;
-    updatedValue->timestamp = elapsedRealtimeNano();
-    updatedValue->value.int32Values.resize(2);
-    updatedValue->value.int32Values[0] = requestId;
-    updatedValue->value.int32Values[1] = (int32_t)InitialUserInfoResponseAction::DEFAULT;
-
+    auto updatedValue = user_hal_helper::toVehiclePropValue(InitialUserInfoResponse{
+            .requestId = *requestId,
+            .action = InitialUserInfoResponseAction::DEFAULT,
+    });
     ALOGI("no lshal response; replying with InitialUserInfoResponseAction::DEFAULT: %s",
           toString(*updatedValue).c_str());
-
     return updatedValue;
 }
 
-android::base::Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetSwitchUserResponse(
+Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetSwitchUserResponse(
         const VehiclePropValue& value) {
-    if (value.value.int32Values.size() == 0) {
-        ALOGE("set(SWITCH_USER): no int32values, ignoring it: %s", toString(value).c_str());
-        return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
-               << "no int32values on " << toString(value);
+    auto requestId = getRequestId(value);
+    if (!requestId.ok()) {
+        ALOGE("Failed to get requestId on set(SWITCH_USER): %s",
+              requestId.error().message().c_str());
+        return requestId.error();
+    }
+
+    auto messageType = getSwitchUserMessageType(value);
+    if (!messageType.ok()) {
+        ALOGE("Failed to get messageType on set(SWITCH_USER): %s",
+              messageType.error().message().c_str());
+        return messageType.error();
     }
 
     if (value.areaId != 0) {
+        if (*messageType == SwitchUserMessageType::VEHICLE_REQUEST) {
+            // User HAL can also request a user switch, so we need to check it first
+            ALOGD("set(SWITCH_USER) called from lshal to emulate a vehicle request: %s",
+                  toString(value).c_str());
+            return std::unique_ptr<VehiclePropValue>(new VehiclePropValue(value));
+        }
+        // Otherwise, we store it
         ALOGD("set(SWITCH_USER) called from lshal; storing it: %s", toString(value).c_str());
         mSwitchUserResponseFromCmd.reset(new VehiclePropValue(value));
         return {};
     }
     ALOGD("set(SWITCH_USER) called from Android: %s", toString(value).c_str());
 
-    int32_t requestId = value.value.int32Values[0];
     if (mSwitchUserResponseFromCmd != nullptr) {
         ALOGI("replying SWITCH_USER with lshal value:  %s",
               toString(*mSwitchUserResponseFromCmd).c_str());
-        return sendUserHalResponse(std::move(mSwitchUserResponseFromCmd), requestId);
+        return sendUserHalResponse(std::move(mSwitchUserResponseFromCmd), *requestId);
     }
 
-    if (value.value.int32Values.size() > 1) {
-        auto messageType = static_cast<SwitchUserMessageType>(value.value.int32Values[1]);
-        switch (messageType) {
-            case SwitchUserMessageType::LEGACY_ANDROID_SWITCH:
-                ALOGI("request is LEGACY_ANDROID_SWITCH; ignoring it");
-                return {};
-            case SwitchUserMessageType::ANDROID_POST_SWITCH:
-                ALOGI("request is ANDROID_POST_SWITCH; ignoring it");
-                return {};
-            default:
-                break;
-        }
+    if (*messageType == SwitchUserMessageType::LEGACY_ANDROID_SWITCH ||
+        *messageType == SwitchUserMessageType::ANDROID_POST_SWITCH) {
+        ALOGI("request is %s; ignoring it", toString(*messageType).c_str());
+        return {};
     }
 
     // Returns default response
-    auto updatedValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue);
-    updatedValue->prop = SWITCH_USER;
-    updatedValue->timestamp = elapsedRealtimeNano();
-    updatedValue->value.int32Values.resize(3);
-    updatedValue->value.int32Values[0] = requestId;
-    updatedValue->value.int32Values[1] = (int32_t)SwitchUserMessageType::VEHICLE_RESPONSE;
-    updatedValue->value.int32Values[2] = (int32_t)SwitchUserStatus::SUCCESS;
-
+    auto updatedValue = user_hal_helper::toVehiclePropValue(SwitchUserResponse{
+            .requestId = *requestId,
+            .messageType = SwitchUserMessageType::VEHICLE_RESPONSE,
+            .status = SwitchUserStatus::SUCCESS,
+    });
     ALOGI("no lshal response; replying with VEHICLE_RESPONSE / SUCCESS: %s",
           toString(*updatedValue).c_str());
-
     return updatedValue;
 }
 
-android::base::Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetCreateUserResponse(
+Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetCreateUserResponse(
         const VehiclePropValue& value) {
-    if (value.value.int32Values.size() == 0) {
-        ALOGE("set(CREATE_USER): no int32values, ignoring it: %s", toString(value).c_str());
-        return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
-               << "no int32values on " << toString(value);
+    auto requestId = getRequestId(value);
+    if (!requestId.ok()) {
+        ALOGE("Failed to get requestId on set(CREATE_USER): %s",
+              requestId.error().message().c_str());
+        return requestId.error();
     }
 
     if (value.areaId != 0) {
@@ -212,33 +233,28 @@
     }
     ALOGD("set(CREATE_USER) called from Android: %s", toString(value).c_str());
 
-    int32_t requestId = value.value.int32Values[0];
     if (mCreateUserResponseFromCmd != nullptr) {
         ALOGI("replying CREATE_USER with lshal value:  %s",
               toString(*mCreateUserResponseFromCmd).c_str());
-        return sendUserHalResponse(std::move(mCreateUserResponseFromCmd), requestId);
+        return sendUserHalResponse(std::move(mCreateUserResponseFromCmd), *requestId);
     }
 
     // Returns default response
-    auto updatedValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue);
-    updatedValue->prop = CREATE_USER;
-    updatedValue->timestamp = elapsedRealtimeNano();
-    updatedValue->value.int32Values.resize(2);
-    updatedValue->value.int32Values[0] = requestId;
-    updatedValue->value.int32Values[1] = (int32_t)CreateUserStatus::SUCCESS;
-
+    auto updatedValue = user_hal_helper::toVehiclePropValue(CreateUserResponse{
+            .requestId = *requestId,
+            .status = CreateUserStatus::SUCCESS,
+    });
     ALOGI("no lshal response; replying with SUCCESS: %s", toString(*updatedValue).c_str());
-
     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);
+Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetUserIdentificationAssociation(
+        const VehiclePropValue& value) {
+    auto requestId = getRequestId(value);
+    if (!requestId.ok()) {
+        ALOGE("Failed to get requestId on set(USER_IDENTIFICATION_ASSOCIATION): %s",
+              requestId.error().message().c_str());
+        return requestId.error();
     }
 
     if (value.areaId != 0) {
@@ -249,28 +265,26 @@
     }
     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);
+        return sendUserHalResponse(std::move(copy), *requestId);
     }
-
     // Returns default response
     return defaultUserIdentificationAssociation(value);
 }
 
-android::base::Result<std::unique_ptr<VehiclePropValue>>
-EmulatedUserHal::defaultUserIdentificationAssociation(const VehiclePropValue& request) {
+Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::defaultUserIdentificationAssociation(
+        const VehiclePropValue& request) {
     // TODO(b/159498909): return a response with NOT_ASSOCIATED_ANY_USER for all requested types
     ALOGE("no lshal response for %s; replying with NOT_AVAILABLE", toString(request).c_str());
-    return android::base::Error(static_cast<int>(StatusCode::NOT_AVAILABLE)) << "not set by lshal";
+    return Error(static_cast<int>(StatusCode::NOT_AVAILABLE)) << "not set by lshal";
 }
 
-android::base::Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::sendUserHalResponse(
+Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::sendUserHalResponse(
         std::unique_ptr<VehiclePropValue> response, int32_t requestId) {
     switch (response->areaId) {
         case 1:
@@ -284,17 +298,16 @@
         case 3:
             ALOGD("not generating a property change event because of lshal prop: %s",
                   toString(*response).c_str());
-            return android::base::Error(static_cast<int>(StatusCode::NOT_AVAILABLE))
+            return Error(static_cast<int>(StatusCode::NOT_AVAILABLE))
                    << "not generating a property change event because of lshal prop: "
                    << toString(*response);
         default:
             ALOGE("invalid action on lshal response: %s", toString(*response).c_str());
-            return android::base::Error(static_cast<int>(StatusCode::INTERNAL_ERROR))
+            return Error(static_cast<int>(StatusCode::INTERNAL_ERROR))
                    << "invalid action on lshal response: " << toString(*response);
     }
 
     ALOGD("updating property to: %s", toString(*response).c_str());
-
     return response;
 }
 
diff --git a/automotive/vehicle/2.0/utils/UserHalHelper.cpp b/automotive/vehicle/2.0/utils/UserHalHelper.cpp
index 33b3948..fcfe4bf 100644
--- a/automotive/vehicle/2.0/utils/UserHalHelper.cpp
+++ b/automotive/vehicle/2.0/utils/UserHalHelper.cpp
@@ -36,22 +36,6 @@
 static const size_t kNumFieldsPerUserInfo = 2;
 static const size_t kNumFieldsPerSetAssociation = 2;
 
-template <typename T>
-Result<T> verifyAndCast(int32_t value) {
-    T castValue = static_cast<T>(value);
-    const auto iter = hidl_enum_range<T>();
-    if (castValue < *iter.begin() || castValue > *std::prev(iter.end())) {
-        return Error() << "Value " << value << " not in range [" << toString(*iter.begin()) << ", "
-                       << toString(*std::prev(iter.end())) << "]";
-    }
-    for (const auto& v : hidl_enum_range<T>()) {
-        if (castValue == v) {
-            return castValue;
-        }
-    }
-    return Error() << "Value " << value << " not in enum values";
-}
-
 Result<void> verifyPropValue(const VehiclePropValue& propValue, VehicleProperty vehicleProperty,
                              size_t minInt32Values) {
     auto prop = verifyAndCast<VehicleProperty>(propValue.prop);
@@ -154,6 +138,22 @@
 
 }  // namespace
 
+template <typename T>
+Result<T> verifyAndCast(int32_t value) {
+    T castValue = static_cast<T>(value);
+    const auto iter = hidl_enum_range<T>();
+    if (castValue < *iter.begin() || castValue > *std::prev(iter.end())) {
+        return Error() << "Value " << value << " not in range [" << toString(*iter.begin()) << ", "
+                       << toString(*std::prev(iter.end())) << "]";
+    }
+    for (const auto& v : hidl_enum_range<T>()) {
+        if (castValue == v) {
+            return castValue;
+        }
+    }
+    return Error() << "Value " << value << " not in enum values";
+}
+
 Result<InitialUserInfoRequest> toInitialUserInfoRequest(const VehiclePropValue& propValue) {
     auto ret = verifyPropValue(propValue, VehicleProperty::INITIAL_USER_INFO, 2);
     if (!ret.ok()) {
@@ -186,7 +186,8 @@
     if (*messageType != SwitchUserMessageType::LEGACY_ANDROID_SWITCH &&
         *messageType != SwitchUserMessageType::ANDROID_SWITCH &&
         *messageType != SwitchUserMessageType::ANDROID_POST_SWITCH) {
-        return Error() << "Invalid " << toString(*messageType) << " from Android System";
+        return Error() << "Invalid " << toString(*messageType)
+                       << " message type from Android System";
     }
     request.requestId = propValue.value.int32Values[0];
     request.messageType = *messageType;
diff --git a/automotive/vehicle/2.0/utils/UserHalHelper.h b/automotive/vehicle/2.0/utils/UserHalHelper.h
index bee34cf..fad7145 100644
--- a/automotive/vehicle/2.0/utils/UserHalHelper.h
+++ b/automotive/vehicle/2.0/utils/UserHalHelper.h
@@ -31,6 +31,11 @@
 
 namespace user_hal_helper {
 
+// Verify whether the |value| can be casted to the type |T| and return the casted value on success.
+// Otherwise, return the error.
+template <typename T>
+android::base::Result<T> verifyAndCast(int32_t value);
+
 // Below functions parse VehiclePropValues to the respective User HAL request structs. On success,
 // these functions return the User HAL struct. Otherwise, they return the error.
 android::base::Result<InitialUserInfoRequest> toInitialUserInfoRequest(
diff --git a/sensors/common/default/2.X/multihal/HalProxy.cpp b/sensors/common/default/2.X/multihal/HalProxy.cpp
index 4527c75..8dda0af 100644
--- a/sensors/common/default/2.X/multihal/HalProxy.cpp
+++ b/sensors/common/default/2.X/multihal/HalProxy.cpp
@@ -693,6 +693,10 @@
                                                         int64_t timeoutStart /* = -1 */) {
     if (!mThreadsRun.load()) return;
     std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
+    if (delta > mWakelockRefCount) {
+        ALOGE("Decrementing wakelock ref count by %zu when count is %zu",
+              delta, mWakelockRefCount);
+    }
     if (timeoutStart == -1) timeoutStart = mWakelockTimeoutResetTime;
     if (mWakelockRefCount == 0 || timeoutStart < mWakelockTimeoutResetTime) return;
     mWakelockRefCount -= std::min(mWakelockRefCount, delta);
diff --git a/sensors/common/default/2.X/multihal/ScopedWakelock.cpp b/sensors/common/default/2.X/multihal/ScopedWakelock.cpp
index bf2ad35..2a2baa2 100644
--- a/sensors/common/default/2.X/multihal/ScopedWakelock.cpp
+++ b/sensors/common/default/2.X/multihal/ScopedWakelock.cpp
@@ -28,6 +28,21 @@
             .count();
 }
 
+ScopedWakelock::ScopedWakelock(ScopedWakelock&& other) {
+    *this = std::move(other);
+}
+
+ScopedWakelock& ScopedWakelock::operator=(ScopedWakelock&& other) {
+    mRefCounter = other.mRefCounter;
+    mCreatedAtTimeNs = other.mCreatedAtTimeNs;
+    mLocked = other.mLocked;
+
+    other.mRefCounter = nullptr;
+    other.mCreatedAtTimeNs = 0;
+    other.mLocked = false;
+    return *this;
+}
+
 ScopedWakelock::ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked)
     : mRefCounter(refCounter), mLocked(locked) {
     if (mLocked) {
diff --git a/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h b/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h
index 1cc5cd5..b3f398c 100644
--- a/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h
+++ b/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h
@@ -81,14 +81,15 @@
  */
 class ScopedWakelock {
   public:
-    ScopedWakelock(ScopedWakelock&&) = default;
-    ScopedWakelock& operator=(ScopedWakelock&&) = default;
+    ScopedWakelock(ScopedWakelock&& other);
+    ScopedWakelock& operator=(ScopedWakelock&& other);
     virtual ~ScopedWakelock();
 
     bool isLocked() const { return mLocked; }
 
   private:
     friend class HalProxyCallbackBase;
+    friend class ScopedWakelockTest;
     IScopedWakelockRefCounter* mRefCounter;
     int64_t mCreatedAtTimeNs;
     bool mLocked;
diff --git a/sensors/common/default/2.X/multihal/tests/Android.bp b/sensors/common/default/2.X/multihal/tests/Android.bp
index a15faed..1b60f4b 100644
--- a/sensors/common/default/2.X/multihal/tests/Android.bp
+++ b/sensors/common/default/2.X/multihal/tests/Android.bp
@@ -90,7 +90,10 @@
 
 cc_test {
     name: "android.hardware.sensors@2.X-halproxy-unit-tests",
-    srcs: ["HalProxy_test.cpp"],
+    srcs: [
+        "HalProxy_test.cpp",
+        "ScopedWakelock_test.cpp",
+    ],
     vendor: true,
     header_libs: [
         "android.hardware.sensors@2.X-shared-utils",
diff --git a/sensors/common/default/2.X/multihal/tests/ScopedWakelock_test.cpp b/sensors/common/default/2.X/multihal/tests/ScopedWakelock_test.cpp
new file mode 100644
index 0000000..133d9e8
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/tests/ScopedWakelock_test.cpp
@@ -0,0 +1,110 @@
+//
+// Copyright (C) 2020 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 <gtest/gtest.h>
+
+#include "V2_0/ScopedWakelock.h"
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+class RefCounter : public IScopedWakelockRefCounter {
+  public:
+    size_t incCount = 0;
+    size_t decCount = 0;
+
+    bool incrementRefCountAndMaybeAcquireWakelock(size_t /* delta */,
+                                                  int64_t* /* timeoutStart */) override {
+        incCount++;
+        return true;
+    }
+
+    void decrementRefCountAndMaybeReleaseWakelock(size_t /* delta */,
+                                                  int64_t /* timeoutStart */) override {
+        decCount++;
+    }
+};
+
+class ScopedWakelockTest : public testing::Test {
+  public:
+    ScopedWakelock createScopedWakelock(bool locked) {
+        return ScopedWakelock(&mRefCounter, locked);
+    }
+
+    RefCounter mRefCounter;
+};
+
+TEST_F(ScopedWakelockTest, UnlockedAfterMoved) {
+    ScopedWakelock wakelock = createScopedWakelock(false /* locked */);
+
+    ScopedWakelock movedWakelock(std::move(wakelock));
+
+    EXPECT_FALSE(wakelock.isLocked());
+    EXPECT_FALSE(movedWakelock.isLocked());
+}
+
+TEST_F(ScopedWakelockTest, LockedAfterMoved) {
+    ScopedWakelock wakelock = createScopedWakelock(true /* locked */);
+
+    ScopedWakelock movedWakelock(std::move(wakelock));
+
+    EXPECT_FALSE(wakelock.isLocked());
+    EXPECT_TRUE(movedWakelock.isLocked());
+}
+
+TEST_F(ScopedWakelockTest, Locked) {
+    ScopedWakelock wakelock = createScopedWakelock(true /* locked */);
+
+    EXPECT_TRUE(wakelock.isLocked());
+}
+
+TEST_F(ScopedWakelockTest, Unlocked) {
+    ScopedWakelock wakelock = createScopedWakelock(false /* locked */);
+
+    EXPECT_FALSE(wakelock.isLocked());
+}
+
+TEST_F(ScopedWakelockTest, ScopedLocked) {
+    { createScopedWakelock(true /* locked */); }
+
+    EXPECT_EQ(mRefCounter.incCount, 1);
+    EXPECT_EQ(mRefCounter.decCount, 1);
+}
+
+TEST_F(ScopedWakelockTest, ScopedUnlockIsNoop) {
+    { createScopedWakelock(false /* locked */); }
+
+    EXPECT_EQ(mRefCounter.incCount, 0);
+    EXPECT_EQ(mRefCounter.decCount, 0);
+}
+
+TEST_F(ScopedWakelockTest, ScopedLockedMove) {
+    {
+        ScopedWakelock wakelock = createScopedWakelock(true /* locked */);
+        ScopedWakelock movedWakelock(std::move(wakelock));
+    }
+
+    EXPECT_EQ(mRefCounter.incCount, 1);
+    EXPECT_EQ(mRefCounter.decCount, 1);
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp
index 8747e61..8cba464 100644
--- a/wifi/1.4/default/wifi_chip.cpp
+++ b/wifi/1.4/default/wifi_chip.cpp
@@ -624,6 +624,15 @@
 Return<void> WifiChip::debug(const hidl_handle& handle,
                              const hidl_vec<hidl_string>&) {
     if (handle != nullptr && handle->numFds >= 1) {
+        {
+            std::unique_lock<std::mutex> lk(lock_t);
+            for (const auto& item : ringbuffer_map_) {
+                forceDumpToDebugRingBufferInternal(item.first);
+            }
+            // unique_lock unlocked here
+        }
+        usleep(100 * 1000);  // sleep for 100 milliseconds to wait for
+                             // ringbuffer updates.
         int fd = handle->data[0];
         if (!writeRingbufferFilesInternal()) {
             LOG(ERROR) << "Error writing files to flash";
@@ -1120,6 +1129,9 @@
     legacy_hal::wifi_error legacy_status =
         legacy_hal_.lock()->deregisterRingBufferCallbackHandler(
             getFirstActiveWlanIfaceName());
+    if (legacy_status == legacy_hal::WIFI_SUCCESS) {
+        debug_ring_buffer_cb_registered_ = false;
+    }
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
@@ -1335,7 +1347,7 @@
                     LOG(ERROR) << "Ringname " << name << " not found";
                     return;
                 }
-                // unlock
+                // unique_lock unlocked here
             }
         };
     legacy_hal::wifi_error legacy_status =
@@ -1637,7 +1649,7 @@
                 }
             }
         }
-        // unlock
+        // unique_lock unlocked here
     }
     return true;
 }
diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp
index 29123bf..75f22ec 100644
--- a/wifi/1.4/default/wifi_legacy_hal.cpp
+++ b/wifi/1.4/default/wifi_legacy_hal.cpp
@@ -367,8 +367,8 @@
     }
     LOG(DEBUG) << "Waiting for the driver ready";
     wifi_error status = global_func_table_.wifi_wait_for_driver_ready();
-    if (status == WIFI_ERROR_TIMED_OUT) {
-        LOG(ERROR) << "Timed out awaiting driver ready";
+    if (status == WIFI_ERROR_TIMED_OUT || status == WIFI_ERROR_UNKNOWN) {
+        LOG(ERROR) << "Failed or timed out awaiting driver ready";
         return status;
     }
     property_set(kDriverPropName, "ok");
diff --git a/wifi/1.4/default/wifi_nan_iface.cpp b/wifi/1.4/default/wifi_nan_iface.cpp
index 5764d35..24ffb17 100644
--- a/wifi/1.4/default/wifi_nan_iface.cpp
+++ b/wifi/1.4/default/wifi_nan_iface.cpp
@@ -534,6 +534,9 @@
 }
 
 void WifiNanIface::invalidate() {
+    if (!isValid()) {
+        return;
+    }
     // send commands to HAL to actually disable and destroy interfaces
     legacy_hal_.lock()->nanDisableRequest(ifname_, 0xFFFF);
     legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFE, "aware_data0");