Implment getValues in Default VHAL.
Test: atest DefaultVehicleHalTest
Bug: 200737967
Change-Id: I46a0ebdf1c8e211cacc7568e7a8e6f5332083c14
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index 43bdca2..da83e94 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -17,10 +17,15 @@
#ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_include_DefaultVehicleHal_H_
#define android_hardware_automotive_vehicle_aidl_impl_vhal_include_DefaultVehicleHal_H_
+#include "ConnectedClient.h"
+#include "ParcelableUtils.h"
+
#include <IVehicleHardware.h>
#include <LargeParcelableBase.h>
#include <VehicleUtils.h>
#include <aidl/android/hardware/automotive/vehicle/BnVehicle.h>
+#include <android-base/expected.h>
+#include <android-base/thread_annotations.h>
#include <android/binder_auto_utils.h>
#include <memory>
@@ -40,12 +45,20 @@
template <class T>
::ndk::ScopedAStatus toScopedAStatus(
const ::android::base::Result<T>& result,
- ::aidl::android::hardware::automotive::vehicle::StatusCode status) {
+ ::aidl::android::hardware::automotive::vehicle::StatusCode status,
+ const std::string& additionalErrorMsg) {
if (result.ok()) {
return ::ndk::ScopedAStatus::ok();
}
- return ::ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(toInt(status),
- getErrorMsg(result).c_str());
+ return ::ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ toInt(status), (additionalErrorMsg + getErrorMsg(result)).c_str());
+}
+
+template <class T>
+::ndk::ScopedAStatus toScopedAStatus(
+ const ::android::base::Result<T>& result,
+ ::aidl::android::hardware::automotive::vehicle::StatusCode status) {
+ return toScopedAStatus(result, status, "");
}
template <class T>
@@ -53,43 +66,30 @@
return toScopedAStatus(result, getErrorCode(result));
}
-template <class T1, class T2>
-::ndk::ScopedAStatus vectorToStableLargeParcelable(std::vector<T1>& values, T2* output) {
- auto result = ::android::automotive::car_binder_lib::LargeParcelableBase::
- parcelableVectorToStableLargeParcelable(values);
- if (!result.ok()) {
- return toScopedAStatus(
- result, ::aidl::android::hardware::automotive::vehicle::StatusCode::INTERNAL_ERROR);
- }
- auto& fd = result.value();
- if (fd == nullptr) {
- output->payloads = values;
- } else {
- // Move the returned ScopedFileDescriptor pointer to ScopedFileDescriptor value in
- // 'sharedMemoryFd' field.
- output->sharedMemoryFd.set(fd->get());
- *(fd->getR()) = INVALID_MEMORY_FD;
- }
- return ::ndk::ScopedAStatus::ok();
+template <class T>
+::ndk::ScopedAStatus toScopedAStatus(const ::android::base::Result<T>& result,
+ const std::string& additionalErrorMsg) {
+ return toScopedAStatus(result, getErrorCode(result), additionalErrorMsg);
}
} // namespace defaultvehiclehal_impl
class DefaultVehicleHal final : public ::aidl::android::hardware::automotive::vehicle::BnVehicle {
public:
+ using CallbackType =
+ std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>;
+
explicit DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware);
::ndk::ScopedAStatus getAllPropConfigs(
::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs* returnConfigs)
override;
::ndk::ScopedAStatus getValues(
- const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>&
- callback,
+ const CallbackType& callback,
const ::aidl::android::hardware::automotive::vehicle::GetValueRequests& requests)
override;
::ndk::ScopedAStatus setValues(
- const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>&
- callback,
+ const CallbackType& callback,
const ::aidl::android::hardware::automotive::vehicle::SetValueRequests& requests)
override;
::ndk::ScopedAStatus getPropConfigs(
@@ -97,27 +97,38 @@
::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs* returnConfigs)
override;
::ndk::ScopedAStatus subscribe(
- const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>&
- callback,
+ const CallbackType& callback,
const std::vector<::aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
options,
int32_t maxSharedMemoryFileCount) override;
- ::ndk::ScopedAStatus unsubscribe(
- const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>&
- callback,
- const std::vector<int32_t>& propIds) override;
- ::ndk::ScopedAStatus returnSharedMemory(
- const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>&
- callback,
- int64_t sharedMemoryId) override;
+ ::ndk::ScopedAStatus unsubscribe(const CallbackType& callback,
+ const std::vector<int32_t>& propIds) override;
+ ::ndk::ScopedAStatus returnSharedMemory(const CallbackType& callback,
+ int64_t sharedMemoryId) override;
IVehicleHardware* getHardware();
private:
+ // friend class for unit testing.
+ friend class DefaultVehicleHalTest;
+
+ using GetValuesClient =
+ GetSetValuesClient<::aidl::android::hardware::automotive::vehicle::GetValueResult,
+ ::aidl::android::hardware::automotive::vehicle::GetValueResults>;
+
const std::unique_ptr<IVehicleHardware> mVehicleHardware;
std::unordered_map<int32_t, ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
mConfigsByPropId;
std::unique_ptr<::ndk::ScopedFileDescriptor> mConfigFile;
+
+ std::mutex mLock;
+ std::unordered_map<CallbackType, std::shared_ptr<GetValuesClient>> mGetValuesClients
+ GUARDED_BY(mLock);
+
+ template <class T>
+ std::shared_ptr<T> getOrCreateClient(
+ std::unordered_map<CallbackType, std::shared_ptr<T>>* clients,
+ const CallbackType& callback) REQUIRES(mLock);
};
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index fd9e331..41753a6 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -21,6 +21,7 @@
#include <LargeParcelableBase.h>
#include <VehicleHalTypes.h>
#include <VehicleUtils.h>
+
#include <android-base/result.h>
#include <utils/Log.h>
@@ -29,14 +30,19 @@
namespace automotive {
namespace vehicle {
+using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
using ::aidl::android::hardware::automotive::vehicle::GetValueRequests;
+using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::GetValueResults;
using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
using ::aidl::android::hardware::automotive::vehicle::SetValueRequests;
using ::aidl::android::hardware::automotive::vehicle::StatusCode;
using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
using ::android::automotive::car_binder_lib::LargeParcelableBase;
+using ::android::base::expected;
using ::android::base::Result;
using ::ndk::ScopedAStatus;
@@ -70,14 +76,58 @@
return ScopedAStatus::ok();
}
-ScopedAStatus DefaultVehicleHal::getValues(const std::shared_ptr<IVehicleCallback>&,
- const GetValueRequests&) {
- // TODO(b/200737967): implement this.
+template <class T>
+std::shared_ptr<T> DefaultVehicleHal::getOrCreateClient(
+ std::unordered_map<CallbackType, std::shared_ptr<T>>* clients,
+ const CallbackType& callback) {
+ if (clients->find(callback) == clients->end()) {
+ // TODO(b/204943359): Remove client from clients when linkToDeath is implemented.
+ (*clients)[callback] = std::make_shared<T>(callback);
+ }
+ return (*clients)[callback];
+}
+
+template std::shared_ptr<DefaultVehicleHal::GetValuesClient>
+DefaultVehicleHal::getOrCreateClient<DefaultVehicleHal::GetValuesClient>(
+ std::unordered_map<CallbackType, std::shared_ptr<GetValuesClient>>* clients,
+ const CallbackType& callback);
+
+ScopedAStatus DefaultVehicleHal::getValues(const CallbackType& callback,
+ const GetValueRequests& requests) {
+ // TODO(b/203713317): check for duplicate properties and duplicate request IDs.
+
+ const std::vector<GetValueRequest>* getValueRequests;
+ // Define deserializedResults here because we need it to have the same lifetime as
+ // getValueRequests.
+ expected<std::vector<GetValueRequest>, ScopedAStatus> deserializedResults;
+ if (!requests.payloads.empty()) {
+ getValueRequests = &requests.payloads;
+ } else {
+ deserializedResults = stableLargeParcelableToVector<GetValueRequest>(requests);
+ if (!deserializedResults.ok()) {
+ ALOGE("failed to parse getValues requests");
+ return std::move(deserializedResults.error());
+ }
+ getValueRequests = &deserializedResults.value();
+ }
+
+ std::shared_ptr<GetValuesClient> client;
+ {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ client = getOrCreateClient(&mGetValuesClients, callback);
+ }
+
+ if (StatusCode status =
+ mVehicleHardware->getValues(client->getResultCallback(), *getValueRequests);
+ status != StatusCode::OK) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ toInt(status), "failed to get value from VehicleHardware");
+ }
+
return ScopedAStatus::ok();
}
-ScopedAStatus DefaultVehicleHal::setValues(const std::shared_ptr<IVehicleCallback>&,
- const SetValueRequests&) {
+ScopedAStatus DefaultVehicleHal::setValues(const CallbackType&, const SetValueRequests&) {
// TODO(b/200737967): implement this.
return ScopedAStatus::ok();
}
@@ -90,23 +140,21 @@
configs.push_back(mConfigsByPropId[prop]);
}
}
- return defaultvehiclehal_impl::vectorToStableLargeParcelable(configs, output);
+ return vectorToStableLargeParcelable(std::move(configs), output);
}
-ScopedAStatus DefaultVehicleHal::subscribe(const std::shared_ptr<IVehicleCallback>&,
+ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType&,
const std::vector<SubscribeOptions>&, int32_t) {
// TODO(b/200737967): implement this.
return ScopedAStatus::ok();
}
-ScopedAStatus DefaultVehicleHal::unsubscribe(const std::shared_ptr<IVehicleCallback>&,
- const std::vector<int32_t>&) {
+ScopedAStatus DefaultVehicleHal::unsubscribe(const CallbackType&, const std::vector<int32_t>&) {
// TODO(b/200737967): implement this.
return ScopedAStatus::ok();
}
-ScopedAStatus DefaultVehicleHal::returnSharedMemory(const std::shared_ptr<IVehicleCallback>&,
- int64_t) {
+ScopedAStatus DefaultVehicleHal::returnSharedMemory(const CallbackType&, int64_t) {
// TODO(b/200737967): implement this.
return ScopedAStatus::ok();
}
diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
index 2b5ca70..26380b3 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
@@ -15,17 +15,23 @@
*/
#include "DefaultVehicleHal.h"
+#include "MockVehicleCallback.h"
#include <IVehicleHardware.h>
#include <LargeParcelableBase.h>
#include <aidl/android/hardware/automotive/vehicle/IVehicle.h>
-#include <android-base/thread_annotations.h>
+#include <aidl/android/hardware/automotive/vehicle/IVehicleCallback.h>
+#include <android-base/thread_annotations.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <utils/Log.h>
+#include <list>
#include <memory>
+#include <mutex>
#include <optional>
+#include <unordered_map>
#include <vector>
namespace android {
@@ -36,21 +42,40 @@
namespace {
using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
+using ::aidl::android::hardware::automotive::vehicle::GetValueRequests;
using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::GetValueResults;
using ::aidl::android::hardware::automotive::vehicle::IVehicle;
+using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
using ::aidl::android::hardware::automotive::vehicle::StatusCode;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues;
using ::android::automotive::car_binder_lib::LargeParcelableBase;
using ::android::base::Result;
+using ::ndk::ScopedAStatus;
+using ::ndk::ScopedFileDescriptor;
+
using ::testing::Eq;
using ::testing::WhenSortedBy;
+template <class T>
+std::optional<T> pop(std::list<T>& items) {
+ if (items.size() > 0) {
+ auto item = std::move(items.front());
+ items.pop_front();
+ return item;
+ }
+ return std::nullopt;
+}
+
class MockVehicleHardware final : public IVehicleHardware {
public:
std::vector<VehiclePropConfig> getAllPropertyConfigs() const override {
@@ -58,16 +83,16 @@
return mPropertyConfigs;
}
- StatusCode setValues(std::shared_ptr<const SetValuesCallback>,
- const std::vector<SetValueRequest>&) override {
- // TODO(b/200737967): mock this.
- return StatusCode::OK;
+ StatusCode setValues(std::shared_ptr<const SetValuesCallback> callback,
+ const std::vector<SetValueRequest>& requests) override {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return handleRequests(__func__, callback, requests, mSetValueRequests, mSetValueResponses);
}
- StatusCode getValues(std::shared_ptr<const GetValuesCallback>,
- const std::vector<GetValueRequest>&) const override {
- // TODO(b/200737967): mock this.
- return StatusCode::OK;
+ StatusCode getValues(std::shared_ptr<const GetValuesCallback> callback,
+ const std::vector<GetValueRequest>& requests) const override {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return handleRequests(__func__, callback, requests, mGetValueRequests, mGetValueResponses);
}
DumpResult dump(const std::vector<std::string>&) override {
@@ -94,11 +119,110 @@
mPropertyConfigs = configs;
}
+ void addGetValueResponses(const std::vector<GetValueResult>& responses) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mGetValueResponses.push_back(responses);
+ }
+
+ std::vector<GetValueRequest> nextGetValueRequests() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ std::optional<std::vector<GetValueRequest>> request = pop(mGetValueRequests);
+ if (!request.has_value()) {
+ return std::vector<GetValueRequest>();
+ }
+ return std::move(request.value());
+ }
+
+ std::vector<SetValueRequest> nextSetValueRequests() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ std::optional<std::vector<SetValueRequest>> request = pop(mSetValueRequests);
+ if (!request.has_value()) {
+ return std::vector<SetValueRequest>();
+ }
+ return std::move(request.value());
+ }
+
+ void setStatus(const char* functionName, StatusCode status) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mStatusByFunctions[functionName] = status;
+ }
+
private:
mutable std::mutex mLock;
std::vector<VehiclePropConfig> mPropertyConfigs GUARDED_BY(mLock);
+ mutable std::list<std::vector<GetValueRequest>> mGetValueRequests GUARDED_BY(mLock);
+ mutable std::list<std::vector<GetValueResult>> mGetValueResponses GUARDED_BY(mLock);
+ mutable std::list<std::vector<SetValueRequest>> mSetValueRequests GUARDED_BY(mLock);
+ mutable std::list<std::vector<SetValueResult>> mSetValueResponses GUARDED_BY(mLock);
+ std::unordered_map<const char*, StatusCode> mStatusByFunctions GUARDED_BY(mLock);
+
+ template <class ResultType>
+ StatusCode returnResponse(
+ std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
+ std::list<std::vector<ResultType>>& storedResponses) const;
+
+ template <class RequestType, class ResultType>
+ StatusCode handleRequests(
+ const char* functionName,
+ std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
+ const std::vector<RequestType>& requests,
+ std::list<std::vector<RequestType>>& storedRequests,
+ std::list<std::vector<ResultType>>& storedResponses) const REQUIRES(mLock);
};
+template <class ResultType>
+StatusCode MockVehicleHardware::returnResponse(
+ std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
+ std::list<std::vector<ResultType>>& storedResponses) const {
+ if (storedResponses.size() > 0) {
+ (*callback)(std::move(storedResponses.front()));
+ storedResponses.pop_front();
+ return StatusCode::OK;
+ } else {
+ ALOGE("no more response");
+ return StatusCode::INTERNAL_ERROR;
+ }
+}
+
+template StatusCode MockVehicleHardware::returnResponse<GetValueResult>(
+ std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>> callback,
+ std::list<std::vector<GetValueResult>>& storedResponses) const;
+
+template StatusCode MockVehicleHardware::returnResponse<SetValueResult>(
+ std::shared_ptr<const std::function<void(std::vector<SetValueResult>)>> callback,
+ std::list<std::vector<SetValueResult>>& storedResponses) const;
+
+template <class RequestType, class ResultType>
+StatusCode MockVehicleHardware::handleRequests(
+ const char* functionName,
+ std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
+ const std::vector<RequestType>& requests,
+ std::list<std::vector<RequestType>>& storedRequests,
+ std::list<std::vector<ResultType>>& storedResponses) const {
+ storedRequests.push_back(requests);
+ if (auto it = mStatusByFunctions.find(functionName); it != mStatusByFunctions.end()) {
+ if (StatusCode status = it->second; status != StatusCode::OK) {
+ return status;
+ }
+ }
+
+ return returnResponse(callback, storedResponses);
+}
+
+template StatusCode MockVehicleHardware::handleRequests<GetValueRequest, GetValueResult>(
+ const char* functionName,
+ std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>> callback,
+ const std::vector<GetValueRequest>& requests,
+ std::list<std::vector<GetValueRequest>>& storedRequests,
+ std::list<std::vector<GetValueResult>>& storedResponses) const;
+
+template StatusCode MockVehicleHardware::handleRequests<SetValueRequest, SetValueResult>(
+ const char* functionName,
+ std::shared_ptr<const std::function<void(std::vector<SetValueResult>)>> callback,
+ const std::vector<SetValueRequest>& requests,
+ std::list<std::vector<SetValueRequest>>& storedRequests,
+ std::list<std::vector<SetValueResult>>& storedResponses) const;
+
struct PropConfigCmp {
bool operator()(const VehiclePropConfig& a, const VehiclePropConfig& b) const {
return (a.prop < b.prop);
@@ -107,7 +231,77 @@
} // namespace
-TEST(DefaultVehicleHalTest, testGetAllPropConfigsSmall) {
+class DefaultVehicleHalTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ auto hardware = std::make_unique<MockVehicleHardware>();
+ mHardwarePtr = hardware.get();
+ mVhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
+ mVhalClient = IVehicle::fromBinder(mVhal->asBinder());
+ mCallback = ndk::SharedRefBase::make<MockVehicleCallback>();
+ mCallbackClient = IVehicleCallback::fromBinder(mCallback->asBinder());
+ }
+
+ MockVehicleHardware* getHardware() { return mHardwarePtr; }
+
+ std::shared_ptr<IVehicle> getClient() { return mVhal; }
+
+ std::shared_ptr<IVehicleCallback> getCallbackClient() { return mCallbackClient; }
+
+ MockVehicleCallback* getCallback() { return mCallback.get(); }
+
+ static Result<void> getValuesTestCases(size_t size, GetValueRequests& requests,
+ std::vector<GetValueResult>& expectedResults,
+ std::vector<GetValueRequest>& expectedHardwareRequests) {
+ expectedHardwareRequests.clear();
+ for (size_t i = 0; i < size; i++) {
+ int64_t requestId = static_cast<int64_t>(i);
+ int32_t propId = static_cast<int32_t>(i);
+ expectedHardwareRequests.push_back(GetValueRequest{
+ .prop =
+ VehiclePropValue{
+ .prop = propId,
+ },
+ .requestId = requestId,
+ });
+ expectedResults.push_back(GetValueResult{
+ .requestId = requestId,
+ .status = StatusCode::OK,
+ .prop =
+ VehiclePropValue{
+ .prop = propId,
+ .value.int32Values = {1, 2, 3, 4},
+ },
+ });
+ }
+
+ auto result = LargeParcelableBase::parcelableVectorToStableLargeParcelable(
+ expectedHardwareRequests);
+ if (!result.ok()) {
+ return result.error();
+ }
+ if (result.value() == nullptr) {
+ requests.payloads = expectedHardwareRequests;
+ } else {
+ requests.sharedMemoryFd = std::move(*result.value());
+ }
+ return {};
+ }
+
+ size_t countClients() {
+ std::scoped_lock<std::mutex> lockGuard(mVhal->mLock);
+ return mVhal->mGetValuesClients.size();
+ }
+
+ private:
+ std::shared_ptr<DefaultVehicleHal> mVhal;
+ std::shared_ptr<IVehicle> mVhalClient;
+ MockVehicleHardware* mHardwarePtr;
+ std::shared_ptr<MockVehicleCallback> mCallback;
+ std::shared_ptr<IVehicleCallback> mCallbackClient;
+};
+
+TEST_F(DefaultVehicleHalTest, testGetAllPropConfigsSmall) {
auto testConfigs = std::vector<VehiclePropConfig>({
VehiclePropConfig{
.prop = 1,
@@ -125,14 +319,14 @@
VehiclePropConfigs output;
auto status = client->getAllPropConfigs(&output);
- ASSERT_TRUE(status.isOk());
+ ASSERT_TRUE(status.isOk()) << "getAllPropConfigs failed: " << status.getMessage();
ASSERT_THAT(output.payloads, WhenSortedBy(propConfigCmp, Eq(testConfigs)));
}
-TEST(DefaultVehicleHalTest, testGetAllPropConfigsLarge) {
+TEST_F(DefaultVehicleHalTest, testGetAllPropConfigsLarge) {
std::vector<VehiclePropConfig> testConfigs;
- // 10000 VehiclePropConfig exceeds 4k memory limit, so it would be sent through shared memory.
- for (size_t i = 0; i < 10000; i++) {
+ // 5000 VehiclePropConfig exceeds 4k memory limit, so it would be sent through shared memory.
+ for (size_t i = 0; i < 5000; i++) {
testConfigs.push_back(VehiclePropConfig{
.prop = static_cast<int32_t>(i),
});
@@ -146,16 +340,95 @@
VehiclePropConfigs output;
auto status = client->getAllPropConfigs(&output);
- ASSERT_TRUE(status.isOk());
+ ASSERT_TRUE(status.isOk()) << "getAllPropConfigs failed: " << status.getMessage();
ASSERT_TRUE(output.payloads.empty());
Result<std::optional<std::vector<VehiclePropConfig>>> result =
LargeParcelableBase::stableLargeParcelableToParcelableVector<VehiclePropConfig>(
output.sharedMemoryFd);
- ASSERT_TRUE(result.ok());
- ASSERT_TRUE(result.value().has_value());
+ ASSERT_TRUE(result.ok()) << "failed to parse result shared memory file: "
+ << result.error().message();
+ ASSERT_TRUE(result.value().has_value()) << "empty parsed value";
ASSERT_EQ(result.value().value(), testConfigs);
}
+TEST_F(DefaultVehicleHalTest, testGetValuesSmall) {
+ GetValueRequests requests;
+ std::vector<GetValueResult> expectedResults;
+ std::vector<GetValueRequest> expectedHardwareRequests;
+
+ ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+ getHardware()->addGetValueResponses(expectedResults);
+
+ auto status = getClient()->getValues(getCallbackClient(), requests);
+
+ ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
+
+ EXPECT_EQ(getHardware()->nextGetValueRequests(), expectedHardwareRequests)
+ << "requests to hardware mismatch";
+
+ auto maybeGetValueResults = getCallback()->nextGetValueResults();
+ ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
+ EXPECT_EQ(maybeGetValueResults.value().payloads, expectedResults) << "results mismatch";
+ EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesLarge) {
+ GetValueRequests requests;
+ std::vector<GetValueResult> expectedResults;
+ std::vector<GetValueRequest> expectedHardwareRequests;
+
+ ASSERT_TRUE(getValuesTestCases(5000, requests, expectedResults, expectedHardwareRequests).ok())
+ << "requests to hardware mismatch";
+ ;
+
+ getHardware()->addGetValueResponses(expectedResults);
+
+ auto status = getClient()->getValues(getCallbackClient(), requests);
+
+ ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
+
+ EXPECT_EQ(getHardware()->nextGetValueRequests(), expectedHardwareRequests);
+
+ auto maybeGetValueResults = getCallback()->nextGetValueResults();
+ ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
+ const GetValueResults& getValueResults = maybeGetValueResults.value();
+ ASSERT_TRUE(getValueResults.payloads.empty())
+ << "payload should be empty, shared memory file should be used";
+
+ auto result = LargeParcelableBase::stableLargeParcelableToParcelableVector<GetValueResult>(
+ getValueResults.sharedMemoryFd);
+ ASSERT_TRUE(result.ok()) << "failed to parse shared memory file";
+ ASSERT_TRUE(result.value().has_value()) << "no parsed value";
+ ASSERT_EQ(result.value().value(), expectedResults) << "results mismatch";
+ EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesErrorFromHardware) {
+ GetValueRequests requests;
+ std::vector<GetValueResult> expectedResults;
+ std::vector<GetValueRequest> expectedHardwareRequests;
+
+ ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+ getHardware()->setStatus("getValues", StatusCode::INTERNAL_ERROR);
+
+ auto status = getClient()->getValues(getCallbackClient(), requests);
+
+ ASSERT_FALSE(status.isOk()) << "expect getValues to fail when hardware returns error";
+ ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INTERNAL_ERROR));
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesInvalidLargeParcelableInput) {
+ GetValueRequests requests;
+ requests.sharedMemoryFd = ScopedFileDescriptor(0);
+
+ auto status = getClient()->getValues(getCallbackClient(), requests);
+
+ ASSERT_FALSE(status.isOk()) << "expect getValues to fail when input parcelable is not valid";
+ ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware