463 lines
16 KiB
C++
463 lines
16 KiB
C++
/*
|
|
* 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 <aidl/android/hardware/automotive/vehicle/StatusCode.h>
|
|
#include <android-base/result.h>
|
|
#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
|
|
#include <gtest/gtest.h>
|
|
#include <utils/StrongPointer.h>
|
|
|
|
#include <VehicleUtils.h>
|
|
|
|
#include <vector>
|
|
|
|
namespace android {
|
|
namespace frameworks {
|
|
namespace automotive {
|
|
namespace vhal {
|
|
namespace hidl_test {
|
|
|
|
using ::android::sp;
|
|
using ::android::hardware::hidl_vec;
|
|
using ::android::hardware::Return;
|
|
using ::android::hardware::automotive::vehicle::toInt;
|
|
using ::android::hardware::automotive::vehicle::VhalResult;
|
|
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<void> getAllPropConfigs(IVehicle::getAllPropConfigs_cb callback) override {
|
|
callback(mPropConfigs);
|
|
return {};
|
|
}
|
|
|
|
Return<void> getPropConfigs(const hidl_vec<int32_t>& props,
|
|
IVehicle::getPropConfigs_cb callback) override {
|
|
mGetPropConfigsProps = props;
|
|
callback(mStatus, mPropConfigs);
|
|
return {};
|
|
}
|
|
|
|
Return<void> get(const VehiclePropValue& requestPropValue, IVehicle::get_cb callback) override {
|
|
mRequestPropValue = requestPropValue;
|
|
callback(mStatus, mPropValue);
|
|
return {};
|
|
}
|
|
|
|
Return<StatusCode> set(const VehiclePropValue& value) override {
|
|
mRequestPropValue = value;
|
|
return mStatus;
|
|
}
|
|
|
|
Return<StatusCode> subscribe(const sp<IVehicleCallback>& callback,
|
|
const hidl_vec<SubscribeOptions>& options) override {
|
|
mSubscribedCallback = callback;
|
|
mSubscribeOptions = options;
|
|
return mStatus;
|
|
}
|
|
|
|
Return<StatusCode> unsubscribe([[maybe_unused]] const sp<IVehicleCallback>& callback,
|
|
int32_t propId) override {
|
|
mUnsubscribedPropId = propId;
|
|
return mStatus;
|
|
}
|
|
|
|
Return<void> debugDump([[maybe_unused]] IVehicle::debugDump_cb callback) override { return {}; }
|
|
|
|
// Test functions
|
|
|
|
void setPropConfigs(std::vector<VehiclePropConfig> configs) { mPropConfigs = configs; }
|
|
|
|
void setStatus(StatusCode status) { mStatus = status; }
|
|
|
|
void setVehiclePropValue(VehiclePropValue value) { mPropValue = value; }
|
|
|
|
std::vector<int32_t> getGetPropConfigsProps() { return mGetPropConfigsProps; }
|
|
|
|
VehiclePropValue getRequestPropValue() { return mRequestPropValue; }
|
|
|
|
std::vector<SubscribeOptions> getSubscribeOptions() { return mSubscribeOptions; }
|
|
|
|
int32_t getUnsubscribedPropId() { return mUnsubscribedPropId; }
|
|
|
|
void triggerOnPropertyEvent(const std::vector<VehiclePropValue>& values) {
|
|
mSubscribedCallback->onPropertyEvent(values);
|
|
}
|
|
|
|
void triggerSetErrorEvent(StatusCode status, int32_t propId, int32_t areaId) {
|
|
mSubscribedCallback->onPropertySetError(status, propId, areaId);
|
|
}
|
|
|
|
private:
|
|
std::vector<VehiclePropConfig> mPropConfigs;
|
|
StatusCode mStatus = StatusCode::OK;
|
|
VehiclePropValue mPropValue;
|
|
|
|
std::vector<int32_t> mGetPropConfigsProps;
|
|
VehiclePropValue mRequestPropValue;
|
|
sp<IVehicleCallback> mSubscribedCallback;
|
|
std::vector<SubscribeOptions> mSubscribeOptions;
|
|
int32_t mUnsubscribedPropId;
|
|
};
|
|
|
|
class MockSubscriptionCallback final : public ISubscriptionCallback {
|
|
public:
|
|
void onPropertyEvent(const std::vector<std::unique_ptr<IHalPropValue>>& values) override {
|
|
for (const auto& value : values) {
|
|
mEventPropIds.push_back(value->getPropId());
|
|
}
|
|
}
|
|
void onPropertySetError(const std::vector<HalPropError>& errors) override { mErrors = errors; }
|
|
|
|
std::vector<int32_t> getEventPropIds() { return mEventPropIds; }
|
|
|
|
std::vector<HalPropError> getErrors() { return mErrors; }
|
|
|
|
private:
|
|
std::vector<int32_t> mEventPropIds;
|
|
std::vector<HalPropError> 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;
|
|
|
|
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<HidlVhalClient>(mVhal);
|
|
}
|
|
|
|
MockVhal* getVhal() { return mVhal.get(); }
|
|
|
|
HidlVhalClient* getClient() { return mVhalClient.get(); }
|
|
|
|
void triggerBinderDied() { mVhalClient->onBinderDied(); }
|
|
|
|
private:
|
|
sp<MockVhal> mVhal;
|
|
std::unique_ptr<HidlVhalClient> mVhalClient;
|
|
};
|
|
|
|
TEST_F(HidlVhalClientTest, testIsAidl) {
|
|
ASSERT_FALSE(getClient()->isAidlVhal());
|
|
}
|
|
|
|
TEST_F(HidlVhalClientTest, testGetValue) {
|
|
VhalResult<std::unique_ptr<IHalPropValue>> result;
|
|
VhalResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
|
|
bool gotResult = false;
|
|
bool* gotResultPtr = &gotResult;
|
|
auto callback = std::make_shared<HidlVhalClient::GetValueCallbackFunc>(
|
|
[resultPtr, gotResultPtr](VhalResult<std::unique_ptr<IHalPropValue>> 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->getInt32Values(), std::vector<int32_t>({1}));
|
|
}
|
|
|
|
TEST_F(HidlVhalClientTest, testGetValueError) {
|
|
getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
|
|
|
|
VhalResult<std::unique_ptr<IHalPropValue>> result;
|
|
VhalResult<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
|
|
bool gotResult = false;
|
|
bool* gotResultPtr = &gotResult;
|
|
auto callback = std::make_shared<HidlVhalClient::GetValueCallbackFunc>(
|
|
[resultPtr, gotResultPtr](VhalResult<std::unique_ptr<IHalPropValue>> 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) {
|
|
VhalResult<void> result;
|
|
VhalResult<void>* resultPtr = &result;
|
|
bool gotResult = false;
|
|
bool* gotResultPtr = &gotResult;
|
|
auto callback = std::make_shared<HidlVhalClient::SetValueCallbackFunc>(
|
|
[resultPtr, gotResultPtr](VhalResult<void> 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);
|
|
|
|
VhalResult<void> result;
|
|
VhalResult<void>* resultPtr = &result;
|
|
bool gotResult = false;
|
|
bool* gotResultPtr = &gotResult;
|
|
auto callback = std::make_shared<HidlVhalClient::SetValueCallbackFunc>(
|
|
[resultPtr, gotResultPtr](VhalResult<void> 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<HidlVhalClient::OnBinderDiedCallbackFunc>(
|
|
[&result] { result.callbackOneCalled = true; }));
|
|
getClient()->addOnBinderDiedCallback(std::make_shared<HidlVhalClient::OnBinderDiedCallbackFunc>(
|
|
[&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<HidlVhalClient::OnBinderDiedCallbackFunc>(
|
|
[&result] { result.callbackOneCalled = true; });
|
|
auto callbackTwo = std::make_shared<HidlVhalClient::OnBinderDiedCallbackFunc>(
|
|
[&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,
|
|
}},
|
|
},
|
|
VehiclePropConfig{
|
|
.prop = TEST_PROP_ID_2,
|
|
},
|
|
});
|
|
|
|
auto result = getClient()->getAllPropConfigs();
|
|
|
|
ASSERT_TRUE(result.ok());
|
|
std::vector<std::unique_ptr<IHalPropConfig>> configs = std::move(result.value());
|
|
|
|
ASSERT_EQ(configs.size(), static_cast<size_t>(2));
|
|
ASSERT_EQ(configs[0]->getPropId(), TEST_PROP_ID);
|
|
ASSERT_EQ(configs[0]->getAreaConfigSize(), static_cast<size_t>(1));
|
|
|
|
const IHalAreaConfig* areaConfig = configs[0]->getAreaConfigs();
|
|
ASSERT_EQ(areaConfig->getAreaId(), TEST_AREA_ID);
|
|
ASSERT_EQ(areaConfig->getMinInt32Value(), 0);
|
|
ASSERT_EQ(areaConfig->getMaxInt32Value(), 1);
|
|
|
|
ASSERT_EQ(configs[1]->getPropId(), TEST_PROP_ID_2);
|
|
ASSERT_EQ(configs[1]->getAreaConfigSize(), static_cast<size_t>(0));
|
|
}
|
|
|
|
TEST_F(HidlVhalClientTest, testGetPropConfigs) {
|
|
getVhal()->setPropConfigs({
|
|
VehiclePropConfig{
|
|
.prop = TEST_PROP_ID,
|
|
.areaConfigs = {{
|
|
.areaId = TEST_AREA_ID,
|
|
.minInt32Value = 0,
|
|
.maxInt32Value = 1,
|
|
}},
|
|
},
|
|
VehiclePropConfig{
|
|
.prop = TEST_PROP_ID_2,
|
|
},
|
|
});
|
|
|
|
std::vector<int32_t> propIds = {TEST_PROP_ID, TEST_PROP_ID_2};
|
|
auto result = getClient()->getPropConfigs(propIds);
|
|
|
|
ASSERT_EQ(getVhal()->getGetPropConfigsProps(), propIds);
|
|
ASSERT_TRUE(result.ok());
|
|
std::vector<std::unique_ptr<IHalPropConfig>> configs = std::move(result.value());
|
|
|
|
ASSERT_EQ(configs.size(), static_cast<size_t>(2));
|
|
ASSERT_EQ(configs[0]->getPropId(), TEST_PROP_ID);
|
|
ASSERT_EQ(configs[0]->getAreaConfigSize(), static_cast<size_t>(1));
|
|
|
|
const IHalAreaConfig* areaConfig = configs[0]->getAreaConfigs();
|
|
ASSERT_EQ(areaConfig->getAreaId(), TEST_AREA_ID);
|
|
ASSERT_EQ(areaConfig->getMinInt32Value(), 0);
|
|
ASSERT_EQ(areaConfig->getMaxInt32Value(), 1);
|
|
|
|
ASSERT_EQ(configs[1]->getPropId(), TEST_PROP_ID_2);
|
|
ASSERT_EQ(configs[1]->getAreaConfigSize(), static_cast<size_t>(0));
|
|
}
|
|
|
|
TEST_F(HidlVhalClientTest, testGetPropConfigsError) {
|
|
getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
|
|
|
|
std::vector<int32_t> 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<SubscribeOptions> 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<MockSubscriptionCallback>();
|
|
auto subscriptionClient = getClient()->getSubscriptionClient(callback);
|
|
auto result = subscriptionClient->subscribe(options);
|
|
|
|
ASSERT_TRUE(result.ok());
|
|
ASSERT_EQ(getVhal()->getSubscribeOptions(), hidlOptions);
|
|
|
|
getVhal()->triggerOnPropertyEvent(std::vector<VehiclePropValue>{
|
|
{
|
|
.prop = TEST_PROP_ID,
|
|
.areaId = TEST_AREA_ID,
|
|
.value.int32Values = {1},
|
|
},
|
|
});
|
|
|
|
ASSERT_EQ(callback->getEventPropIds(), std::vector<int32_t>({TEST_PROP_ID}));
|
|
|
|
getVhal()->triggerSetErrorEvent(StatusCode::INTERNAL_ERROR, TEST_PROP_ID, TEST_AREA_ID);
|
|
|
|
auto errors = callback->getErrors();
|
|
ASSERT_EQ(errors.size(), static_cast<size_t>(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<MockSubscriptionCallback>();
|
|
auto subscriptionClient = getClient()->getSubscriptionClient(callback);
|
|
auto result = subscriptionClient->subscribe(options);
|
|
|
|
ASSERT_FALSE(result.ok());
|
|
}
|
|
|
|
TEST_F(HidlVhalClientTest, testUnubscribe) {
|
|
auto callback = std::make_shared<MockSubscriptionCallback>();
|
|
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<MockSubscriptionCallback>();
|
|
auto subscriptionClient = getClient()->getSubscriptionClient(callback);
|
|
auto result = subscriptionClient->unsubscribe({TEST_PROP_ID});
|
|
|
|
ASSERT_FALSE(result.ok());
|
|
}
|
|
|
|
} // namespace hidl_test
|
|
} // namespace vhal
|
|
} // namespace automotive
|
|
} // namespace frameworks
|
|
} // namespace android
|