/* * Copyright (C) 2022 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 "HidlHalPropValue.h" #include "HidlVhalClient.h" #include #include #include #include #include #include #include namespace android { namespace frameworks { namespace automotive { namespace vhal { namespace hidl_test { using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus; using ::android::sp; using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::automotive::vehicle::toInt; using ::android::hardware::automotive::vehicle::V2_0::IVehicle; using ::android::hardware::automotive::vehicle::V2_0::IVehicleCallback; using ::android::hardware::automotive::vehicle::V2_0::StatusCode; using ::android::hardware::automotive::vehicle::V2_0::SubscribeFlags; using ::android::hardware::automotive::vehicle::V2_0::SubscribeOptions; using ::android::hardware::automotive::vehicle::V2_0::VehiclePropConfig; using ::android::hardware::automotive::vehicle::V2_0::VehiclePropValue; class MockVhal final : public IVehicle { public: Return getAllPropConfigs(IVehicle::getAllPropConfigs_cb callback) override { callback(mPropConfigs); return {}; } Return getPropConfigs(const hidl_vec& props, IVehicle::getPropConfigs_cb callback) override { mGetPropConfigsProps = props; callback(mStatus, mPropConfigs); return {}; } Return get(const VehiclePropValue& requestPropValue, IVehicle::get_cb callback) override { mRequestPropValue = requestPropValue; callback(mStatus, mPropValue); return {}; } Return set(const VehiclePropValue& value) override { mRequestPropValue = value; return mStatus; } Return subscribe(const sp& callback, const hidl_vec& options) override { mSubscribedCallback = callback; mSubscribeOptions = options; return mStatus; } Return unsubscribe([[maybe_unused]] const sp& callback, int32_t propId) override { mUnsubscribedPropId = propId; return mStatus; } Return debugDump([[maybe_unused]] IVehicle::debugDump_cb callback) override { return {}; } // Test functions void setPropConfigs(std::vector configs) { mPropConfigs = configs; } void setStatus(StatusCode status) { mStatus = status; } void setVehiclePropValue(VehiclePropValue value) { mPropValue = value; } std::vector getGetPropConfigsProps() { return mGetPropConfigsProps; } VehiclePropValue getRequestPropValue() { return mRequestPropValue; } std::vector getSubscribeOptions() { return mSubscribeOptions; } int32_t getUnsubscribedPropId() { return mUnsubscribedPropId; } void triggerOnPropertyEvent(const std::vector& values) { mSubscribedCallback->onPropertyEvent(values); } void triggerSetErrorEvent(StatusCode status, int32_t propId, int32_t areaId) { mSubscribedCallback->onPropertySetError(status, propId, areaId); } private: std::vector mPropConfigs; StatusCode mStatus = StatusCode::OK; VehiclePropValue mPropValue; std::vector mGetPropConfigsProps; VehiclePropValue mRequestPropValue; sp mSubscribedCallback; std::vector mSubscribeOptions; int32_t mUnsubscribedPropId; }; class MockSubscriptionCallback final : public ISubscriptionCallback { public: void onPropertyEvent(const std::vector>& values) override { for (const auto& value : values) { mEventPropIds.push_back(value->getPropId()); } } void onPropertySetError(const std::vector& errors) override { mErrors = errors; } std::vector getEventPropIds() { return mEventPropIds; } std::vector getErrors() { return mErrors; } private: std::vector mEventPropIds; std::vector mErrors; }; class HidlVhalClientTest : public ::testing::Test { protected: constexpr static int32_t TEST_PROP_ID = 1; constexpr static int32_t TEST_AREA_ID = 2; constexpr static int32_t TEST_PROP_ID_2 = 3; constexpr static int32_t TEST_AREA_ID_2 = 4; const VehiclePropValue TEST_VALUE{ .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, .value.int32Values = {1}, }; void SetUp() override { mVhal = new MockVhal(); mVhalClient = std::make_unique(mVhal); } MockVhal* getVhal() { return mVhal.get(); } HidlVhalClient* getClient() { return mVhalClient.get(); } void triggerBinderDied() { mVhalClient->onBinderDied(); } private: sp mVhal; std::unique_ptr mVhalClient; }; TEST_F(HidlVhalClientTest, testIsAidl) { ASSERT_FALSE(getClient()->isAidlVhal()); } TEST_F(HidlVhalClientTest, testGetValue) { VhalClientResult> result; VhalClientResult>* resultPtr = &result; bool gotResult = false; bool* gotResultPtr = &gotResult; auto callback = std::make_shared( [resultPtr, gotResultPtr](VhalClientResult> r) { *resultPtr = std::move(r); *gotResultPtr = true; }); getVhal()->setVehiclePropValue(TEST_VALUE); getClient()->getValue(HidlHalPropValue(TEST_PROP_ID, TEST_AREA_ID), callback); ASSERT_TRUE(gotResult); ASSERT_EQ(getVhal()->getRequestPropValue().prop, TEST_PROP_ID); ASSERT_EQ(getVhal()->getRequestPropValue().areaId, TEST_AREA_ID); ASSERT_TRUE(result.ok()); auto gotValue = std::move(result.value()); ASSERT_EQ(gotValue->getPropId(), TEST_PROP_ID); ASSERT_EQ(gotValue->getAreaId(), TEST_AREA_ID); ASSERT_EQ(gotValue->getStatus(), VehiclePropertyStatus::AVAILABLE); ASSERT_EQ(gotValue->getInt32Values(), std::vector({1})); } TEST_F(HidlVhalClientTest, testGetValueUnavailableStatus) { VhalClientResult> result; VhalClientResult>* resultPtr = &result; bool gotResult = false; bool* gotResultPtr = &gotResult; auto callback = std::make_shared( [resultPtr, gotResultPtr](VhalClientResult> r) { *resultPtr = std::move(r); *gotResultPtr = true; }); getVhal()->setVehiclePropValue(VehiclePropValue{ .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, .status = android::hardware::automotive::vehicle::V2_0::VehiclePropertyStatus:: UNAVAILABLE, }); getClient()->getValue(HidlHalPropValue(TEST_PROP_ID, TEST_AREA_ID), callback); ASSERT_TRUE(gotResult); ASSERT_EQ(getVhal()->getRequestPropValue().prop, TEST_PROP_ID); ASSERT_EQ(getVhal()->getRequestPropValue().areaId, TEST_AREA_ID); ASSERT_TRUE(result.ok()); auto gotValue = std::move(result.value()); ASSERT_EQ(gotValue->getPropId(), TEST_PROP_ID); ASSERT_EQ(gotValue->getAreaId(), TEST_AREA_ID); ASSERT_EQ(gotValue->getStatus(), VehiclePropertyStatus::UNAVAILABLE); } TEST_F(HidlVhalClientTest, testGetValueError) { getVhal()->setStatus(StatusCode::INTERNAL_ERROR); VhalClientResult> result; VhalClientResult>* resultPtr = &result; bool gotResult = false; bool* gotResultPtr = &gotResult; auto callback = std::make_shared( [resultPtr, gotResultPtr](VhalClientResult> r) { *resultPtr = std::move(r); *gotResultPtr = true; }); getClient()->getValue(HidlHalPropValue(TEST_PROP_ID, TEST_AREA_ID), callback); ASSERT_TRUE(gotResult); ASSERT_FALSE(result.ok()); } TEST_F(HidlVhalClientTest, testSetValue) { VhalClientResult result; VhalClientResult* resultPtr = &result; bool gotResult = false; bool* gotResultPtr = &gotResult; auto callback = std::make_shared( [resultPtr, gotResultPtr](VhalClientResult r) { *resultPtr = std::move(r); *gotResultPtr = true; }); getClient()->setValue(HidlHalPropValue(TEST_PROP_ID, TEST_AREA_ID), callback); ASSERT_TRUE(gotResult); ASSERT_EQ(getVhal()->getRequestPropValue().prop, TEST_PROP_ID); ASSERT_EQ(getVhal()->getRequestPropValue().areaId, TEST_AREA_ID); ASSERT_TRUE(result.ok()); } TEST_F(HidlVhalClientTest, testSetValueError) { getVhal()->setStatus(StatusCode::INTERNAL_ERROR); VhalClientResult result; VhalClientResult* resultPtr = &result; bool gotResult = false; bool* gotResultPtr = &gotResult; auto callback = std::make_shared( [resultPtr, gotResultPtr](VhalClientResult r) { *resultPtr = std::move(r); *gotResultPtr = true; }); getClient()->setValue(HidlHalPropValue(TEST_PROP_ID, TEST_AREA_ID), callback); ASSERT_TRUE(gotResult); ASSERT_FALSE(result.ok()); } TEST_F(HidlVhalClientTest, testAddOnBinderDiedCallback) { struct Result { bool callbackOneCalled = false; bool callbackTwoCalled = false; } result; getClient()->addOnBinderDiedCallback(std::make_shared( [&result] { result.callbackOneCalled = true; })); getClient()->addOnBinderDiedCallback(std::make_shared( [&result] { result.callbackTwoCalled = true; })); triggerBinderDied(); ASSERT_TRUE(result.callbackOneCalled); ASSERT_TRUE(result.callbackTwoCalled); } TEST_F(HidlVhalClientTest, testRemoveOnBinderDiedCallback) { struct Result { bool callbackOneCalled = false; bool callbackTwoCalled = false; } result; auto callbackOne = std::make_shared( [&result] { result.callbackOneCalled = true; }); auto callbackTwo = std::make_shared( [&result] { result.callbackTwoCalled = true; }); getClient()->addOnBinderDiedCallback(callbackOne); getClient()->addOnBinderDiedCallback(callbackTwo); getClient()->removeOnBinderDiedCallback(callbackOne); triggerBinderDied(); ASSERT_FALSE(result.callbackOneCalled); ASSERT_TRUE(result.callbackTwoCalled); } TEST_F(HidlVhalClientTest, testGetAllPropConfigs) { getVhal()->setPropConfigs({ VehiclePropConfig{ .prop = TEST_PROP_ID, .areaConfigs = {{ .areaId = TEST_AREA_ID, .minInt32Value = 0, .maxInt32Value = 1, }, { .areaId = TEST_AREA_ID_2, .minInt32Value = 2, .maxInt32Value = 3, }}, }, VehiclePropConfig{ .prop = TEST_PROP_ID_2, }, }); auto result = getClient()->getAllPropConfigs(); ASSERT_TRUE(result.ok()); std::vector> configs = std::move(result.value()); ASSERT_EQ(configs.size(), static_cast(2)); ASSERT_EQ(configs[0]->getPropId(), TEST_PROP_ID); ASSERT_EQ(configs[0]->getAccess(), 0); ASSERT_EQ(configs[0]->getAreaConfigSize(), static_cast(2)); const std::unique_ptr& areaConfig0 = configs[0]->getAreaConfigs()[0]; ASSERT_EQ(areaConfig0->getAreaId(), TEST_AREA_ID); ASSERT_EQ(areaConfig0->getAccess(), 0); ASSERT_EQ(areaConfig0->getMinInt32Value(), 0); ASSERT_EQ(areaConfig0->getMaxInt32Value(), 1); ASSERT_FALSE(areaConfig0->isVariableUpdateRateSupported()); const std::unique_ptr& areaConfig1 = configs[0]->getAreaConfigs()[1]; ASSERT_EQ(areaConfig1->getAreaId(), TEST_AREA_ID_2); ASSERT_EQ(areaConfig1->getAccess(), 0); ASSERT_EQ(areaConfig1->getMinInt32Value(), 2); ASSERT_EQ(areaConfig1->getMaxInt32Value(), 3); ASSERT_FALSE(areaConfig1->isVariableUpdateRateSupported()); ASSERT_EQ(configs[1]->getPropId(), TEST_PROP_ID_2); ASSERT_EQ(configs[1]->getAccess(), 0); ASSERT_EQ(configs[1]->getAreaConfigSize(), static_cast(1)); const std::unique_ptr& areaConfig2 = configs[1]->getAreaConfigs()[0]; ASSERT_EQ(areaConfig2->getAreaId(), 0); ASSERT_EQ(areaConfig2->getAccess(), 0); ASSERT_FALSE(areaConfig2->isVariableUpdateRateSupported()); } TEST_F(HidlVhalClientTest, testGetPropConfigs) { getVhal()->setPropConfigs({ VehiclePropConfig{ .prop = TEST_PROP_ID, .areaConfigs = {{ .areaId = TEST_AREA_ID, .minInt32Value = 0, .maxInt32Value = 1, }, { .areaId = TEST_AREA_ID_2, .minInt32Value = 2, .maxInt32Value = 3, }}, }, VehiclePropConfig{ .prop = TEST_PROP_ID_2, }, }); std::vector propIds = {TEST_PROP_ID, TEST_PROP_ID_2}; auto result = getClient()->getPropConfigs(propIds); ASSERT_EQ(getVhal()->getGetPropConfigsProps(), propIds); ASSERT_TRUE(result.ok()); std::vector> configs = std::move(result.value()); ASSERT_EQ(configs.size(), static_cast(2)); ASSERT_EQ(configs[0]->getPropId(), TEST_PROP_ID); ASSERT_EQ(configs[0]->getAccess(), 0); ASSERT_EQ(configs[0]->getAreaConfigSize(), static_cast(2)); const std::unique_ptr& areaConfig0 = configs[0]->getAreaConfigs()[0]; ASSERT_EQ(areaConfig0->getAreaId(), TEST_AREA_ID); ASSERT_EQ(areaConfig0->getAccess(), 0); ASSERT_EQ(areaConfig0->getMinInt32Value(), 0); ASSERT_EQ(areaConfig0->getMaxInt32Value(), 1); ASSERT_FALSE(areaConfig0->isVariableUpdateRateSupported()); const std::unique_ptr& areaConfig1 = configs[0]->getAreaConfigs()[1]; ASSERT_EQ(areaConfig1->getAreaId(), TEST_AREA_ID_2); ASSERT_EQ(areaConfig1->getAccess(), 0); ASSERT_EQ(areaConfig1->getMinInt32Value(), 2); ASSERT_EQ(areaConfig1->getMaxInt32Value(), 3); ASSERT_FALSE(areaConfig1->isVariableUpdateRateSupported()); ASSERT_EQ(configs[1]->getPropId(), TEST_PROP_ID_2); ASSERT_EQ(configs[1]->getAccess(), 0); ASSERT_EQ(configs[1]->getAreaConfigSize(), static_cast(1)); const std::unique_ptr& areaConfig2 = configs[1]->getAreaConfigs()[0]; ASSERT_EQ(areaConfig2->getAreaId(), 0); ASSERT_EQ(areaConfig2->getAccess(), 0); ASSERT_FALSE(areaConfig2->isVariableUpdateRateSupported()); } TEST_F(HidlVhalClientTest, testGetPropConfigsError) { getVhal()->setStatus(StatusCode::INTERNAL_ERROR); std::vector propIds = {TEST_PROP_ID, TEST_PROP_ID_2}; auto result = getClient()->getPropConfigs(propIds); ASSERT_FALSE(result.ok()); } TEST_F(HidlVhalClientTest, testSubscribe) { std::vector<::aidl::android::hardware::automotive::vehicle::SubscribeOptions> options = { { .propId = TEST_PROP_ID, .areaIds = {TEST_AREA_ID}, .sampleRate = 1.0, }, { .propId = TEST_PROP_ID_2, .sampleRate = 2.0, }, }; std::vector hidlOptions = { { .propId = TEST_PROP_ID, .flags = SubscribeFlags::EVENTS_FROM_CAR, .sampleRate = 1.0, }, { .propId = TEST_PROP_ID_2, .flags = SubscribeFlags::EVENTS_FROM_CAR, .sampleRate = 2.0, }, }; auto callback = std::make_shared(); auto subscriptionClient = getClient()->getSubscriptionClient(callback); auto result = subscriptionClient->subscribe(options); ASSERT_TRUE(result.ok()); ASSERT_EQ(getVhal()->getSubscribeOptions(), hidlOptions); getVhal()->triggerOnPropertyEvent(std::vector{ { .prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, .value.int32Values = {1}, }, }); ASSERT_EQ(callback->getEventPropIds(), std::vector({TEST_PROP_ID})); getVhal()->triggerSetErrorEvent(StatusCode::INTERNAL_ERROR, TEST_PROP_ID, TEST_AREA_ID); auto errors = callback->getErrors(); ASSERT_EQ(errors.size(), static_cast(1)); ASSERT_EQ(errors[0].propId, TEST_PROP_ID); ASSERT_EQ(errors[0].areaId, TEST_AREA_ID); ASSERT_EQ(errors[0].status, ::aidl::android::hardware::automotive::vehicle::StatusCode::INTERNAL_ERROR); } TEST_F(HidlVhalClientTest, testSubscribeError) { std::vector<::aidl::android::hardware::automotive::vehicle::SubscribeOptions> options = { { .propId = TEST_PROP_ID, .areaIds = {TEST_AREA_ID}, .sampleRate = 1.0, }, { .propId = TEST_PROP_ID_2, .sampleRate = 2.0, }, }; getVhal()->setStatus(StatusCode::INTERNAL_ERROR); auto callback = std::make_shared(); auto subscriptionClient = getClient()->getSubscriptionClient(callback); auto result = subscriptionClient->subscribe(options); ASSERT_FALSE(result.ok()); } TEST_F(HidlVhalClientTest, testUnubscribe) { auto callback = std::make_shared(); auto subscriptionClient = getClient()->getSubscriptionClient(callback); auto result = subscriptionClient->unsubscribe({TEST_PROP_ID}); ASSERT_TRUE(result.ok()); ASSERT_EQ(getVhal()->getUnsubscribedPropId(), TEST_PROP_ID); } TEST_F(HidlVhalClientTest, testUnubscribeError) { getVhal()->setStatus(StatusCode::INTERNAL_ERROR); auto callback = std::make_shared(); auto subscriptionClient = getClient()->getSubscriptionClient(callback); auto result = subscriptionClient->unsubscribe({TEST_PROP_ID}); ASSERT_FALSE(result.ok()); } TEST_F(HidlVhalClientTest, testGetRemoteInterfaceVersion) { // getRemoteInterfaceVersion will always return 0 for HIDL client. ASSERT_EQ(getClient()->getRemoteInterfaceVersion(), 0); } TEST_F(HidlVhalClientTest, testHidlHalPropValueClone_valueIsTheSame) { VehiclePropValue testProp{.prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, .value = { .int32Values = {1, 2}, .floatValues = {1.1, 2.2}, }}; auto testPropCopy = testProp; std::unique_ptr halPropValue = std::make_unique(std::move(testPropCopy)); auto halPropValueClone = halPropValue->clone(); EXPECT_EQ(halPropValueClone->getPropId(), TEST_PROP_ID); EXPECT_EQ(halPropValueClone->getAreaId(), TEST_AREA_ID); EXPECT_EQ(halPropValueClone->getInt32Values(), std::vector({1, 2})); EXPECT_EQ(halPropValueClone->getFloatValues(), std::vector({1.1, 2.2})); } TEST_F(HidlVhalClientTest, testHidlHalPropValueClone_modifyCloneDoesNotAffectOrig) { std::vector int32Values1 = {1, 2}; std::vector floatValues1 = {1.1, 2.2}; std::vector int32Values2 = {5, 4, 3, 2, 1}; std::vector floatValues2 = {3.3, 2.2, 1.1}; VehiclePropValue testProp{.prop = TEST_PROP_ID, .areaId = TEST_AREA_ID, .value = { .int32Values = int32Values1, .floatValues = floatValues1, }}; auto testPropCopy = testProp; std::unique_ptr halPropValue = std::make_unique(std::move(testPropCopy)); auto halPropValueClone = halPropValue->clone(); halPropValueClone->setInt32Values(int32Values2); halPropValueClone->setFloatValues(floatValues2); EXPECT_EQ(halPropValue->getInt32Values(), int32Values1); EXPECT_EQ(halPropValue->getFloatValues(), floatValues1); EXPECT_EQ(halPropValueClone->getInt32Values(), int32Values2); EXPECT_EQ(halPropValueClone->getFloatValues(), floatValues2); } } // namespace hidl_test } // namespace vhal } // namespace automotive } // namespace frameworks } // namespace android