From a8bc472e43245c650aee10839ed529fb1f8f539b Mon Sep 17 00:00:00 2001 From: Yu Shan Date: Fri, 5 Nov 2021 16:06:27 -0700 Subject: [PATCH 1/3] Add ParcelableUtils. Add some helper functions to manage parsing/marshaling large parcelable. Test: None. Bug: 200737967 Change-Id: I48729915aafe6d23de725e38ca5f653ba3147253 --- .../utils/common/include/VehicleHalTypes.h | 2 + .../impl/utils/common/include/VehicleUtils.h | 32 +++++++ .../aidl/impl/vhal/include/ParcelableUtils.h | 89 +++++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 automotive/vehicle/aidl/impl/vhal/include/ParcelableUtils.h diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h index 2b36c72bb1..013d1773c8 100644 --- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h +++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h index dfc7cbf748..63eb747965 100644 --- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h +++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h @@ -19,6 +19,7 @@ #include +#include #include #include @@ -208,6 +209,37 @@ std::string getErrorMsg(const ::android::base::Result& result) { return result.error().message(); } +template +::ndk::ScopedAStatus toScopedAStatus( + const ::android::base::Result& result, + ::aidl::android::hardware::automotive::vehicle::StatusCode status, + std::string additionalErrorMsg) { + if (result.ok()) { + return ::ndk::ScopedAStatus::ok(); + } + return ::ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage( + toInt(status), + fmt::format("{}, error: {}", additionalErrorMsg, getErrorMsg(result)).c_str()); +} + +template +::ndk::ScopedAStatus toScopedAStatus( + const ::android::base::Result& result, + ::aidl::android::hardware::automotive::vehicle::StatusCode status) { + return toScopedAStatus(result, status, ""); +} + +template +::ndk::ScopedAStatus toScopedAStatus(const ::android::base::Result& result) { + return toScopedAStatus(result, getErrorCode(result)); +} + +template +::ndk::ScopedAStatus toScopedAStatus(const ::android::base::Result& result, + std::string additionalErrorMsg) { + return toScopedAStatus(result, getErrorCode(result), additionalErrorMsg); +} + } // namespace vehicle } // namespace automotive } // namespace hardware diff --git a/automotive/vehicle/aidl/impl/vhal/include/ParcelableUtils.h b/automotive/vehicle/aidl/impl/vhal/include/ParcelableUtils.h new file mode 100644 index 0000000000..dcb15b9c63 --- /dev/null +++ b/automotive/vehicle/aidl/impl/vhal/include/ParcelableUtils.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2021 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. + */ + +#ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_include_ParcelableUtils_H_ +#define android_hardware_automotive_vehicle_aidl_impl_vhal_include_ParcelableUtils_H_ + +#include +#include +#include + +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { + +template +::ndk::ScopedAStatus vectorToStableLargeParcelable(std::vector&& 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) { + // If we no longer needs values, move it inside the payloads to avoid copying. + output->payloads = std::move(values); + } else { + // Move the returned ScopedFileDescriptor pointer to ScopedFileDescriptor value in + // 'sharedMemoryFd' field. + output->sharedMemoryFd = std::move(*fd); + } + return ::ndk::ScopedAStatus::ok(); +} + +template +::ndk::ScopedAStatus vectorToStableLargeParcelable(const std::vector& values, T2* output) { + // Because 'values' is passed in as const reference, we have to do a copy here. + std::vector valuesCopy = values; + + return vectorToStableLargeParcelable(std::move(valuesCopy), output); +} + +template +::android::base::expected, ::ndk::ScopedAStatus> stableLargeParcelableToVector( + const T2& largeParcelable) { + ::android::base::Result>> result = + ::android::automotive::car_binder_lib::LargeParcelableBase:: + stableLargeParcelableToParcelableVector(largeParcelable.sharedMemoryFd); + + if (!result.ok()) { + return ::android::base::unexpected(toScopedAStatus( + result, ::aidl::android::hardware::automotive::vehicle::StatusCode::INVALID_ARG, + "failed to parse large parcelable")); + } + + if (!result.value().has_value()) { + return ::android::base::unexpected( + ::ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage( + toInt(::aidl::android::hardware::automotive::vehicle::StatusCode:: + INVALID_ARG), + "empty request")); + } + + return std::move(result.value().value()); +} + +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_aidl_impl_vhal_include_ParcelableUtils_H_ From 8c24b293eb7fe08c0cf593a09fff2c0f590c8d7e Mon Sep 17 00:00:00 2001 From: Yu Shan Date: Fri, 5 Nov 2021 16:54:30 -0700 Subject: [PATCH 2/3] Add MockVehicleCallback for testing. Test: None Bug: 200737967 Change-Id: I2d34138a865be684720a1e0582cc9ea5a8a8ff04 --- .../impl/vhal/test/MockVehicleCallback.cpp | 89 +++++++++++++++++++ .../aidl/impl/vhal/test/MockVehicleCallback.h | 69 ++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp create mode 100644 automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp new file mode 100644 index 0000000000..ca366cd746 --- /dev/null +++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2021 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 "MockVehicleCallback.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { + +namespace { + +using ::aidl::android::hardware::automotive::vehicle::GetValueResults; +using ::aidl::android::hardware::automotive::vehicle::SetValueResults; +using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors; +using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues; +using ::ndk::ScopedAStatus; +using ::ndk::ScopedFileDescriptor; + +template +std::optional pop(std::list& items) { + if (items.size() > 0) { + auto item = std::move(items.front()); + items.pop_front(); + return item; + } + return std::nullopt; +} + +template +static ScopedAStatus storeResults(const T& results, std::list* storedResults) { + T resultsCopy{ + .payloads = results.payloads, + }; + int fd = results.sharedMemoryFd.get(); + if (fd != -1) { + resultsCopy.sharedMemoryFd = ScopedFileDescriptor(dup(fd)); + } + storedResults->push_back(std::move(resultsCopy)); + return ScopedAStatus::ok(); +} + +} // namespace + +ScopedAStatus MockVehicleCallback::onGetValues(const GetValueResults& results) { + std::scoped_lock lockGuard(mLock); + return storeResults(results, &mGetValueResults); +} + +ScopedAStatus MockVehicleCallback::onSetValues(const SetValueResults& results) { + std::scoped_lock lockGuard(mLock); + return storeResults(results, &mSetValueResults); +} + +ScopedAStatus MockVehicleCallback::onPropertyEvent(const VehiclePropValues&, int32_t) { + return ScopedAStatus::ok(); +} + +ScopedAStatus MockVehicleCallback::onPropertySetError(const VehiclePropErrors&) { + return ScopedAStatus::ok(); +} + +std::optional MockVehicleCallback::nextGetValueResults() { + std::scoped_lock lockGuard(mLock); + return pop(mGetValueResults); +} + +std::optional MockVehicleCallback::nextSetValueResults() { + std::scoped_lock lockGuard(mLock); + return pop(mSetValueResults); +} + +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h new file mode 100644 index 0000000000..916575abdc --- /dev/null +++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2021 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. + */ + +#ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_test_MockVehicleCallback_H_ +#define android_hardware_automotive_vehicle_aidl_impl_vhal_test_MockVehicleCallback_H_ + +#include + +#include +#include + +#include +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { + +// MockVehicleCallback is a mock VehicleCallback implementation that simply stores the results. +class MockVehicleCallback final + : public ::aidl::android::hardware::automotive::vehicle::BnVehicleCallback { + public: + ::ndk::ScopedAStatus onGetValues( + const ::aidl::android::hardware::automotive::vehicle::GetValueResults& results) + override; + ::ndk::ScopedAStatus onSetValues( + const ::aidl::android::hardware::automotive::vehicle::SetValueResults& results) + override; + ::ndk::ScopedAStatus onPropertyEvent( + const ::aidl::android::hardware::automotive::vehicle::VehiclePropValues&, + int32_t) override; + ::ndk::ScopedAStatus onPropertySetError( + const ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors&) override; + + // Test functions + std::optional<::aidl::android::hardware::automotive::vehicle::GetValueResults> + nextGetValueResults(); + std::optional<::aidl::android::hardware::automotive::vehicle::SetValueResults> + nextSetValueResults(); + + private: + std::mutex mLock; + std::list<::aidl::android::hardware::automotive::vehicle::GetValueResults> mGetValueResults + GUARDED_BY(mLock); + std::list<::aidl::android::hardware::automotive::vehicle::SetValueResults> mSetValueResults + GUARDED_BY(mLock); +}; + +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_aidl_impl_vhal_test_MockVehicleCallback_H_ From 7a1c24fd5f064274df1008a6f903dee7018a3df1 Mon Sep 17 00:00:00 2001 From: Yu Shan Date: Fri, 5 Nov 2021 17:13:24 -0700 Subject: [PATCH 3/3] Create ConnectedClient to manage VHAL clients. Create a class to represent each VHAL client for each operations. This class would manage the pending requests and maintain callbacks that should be called when we get the result for async requests or when the request time-out. Test: atest DefaultVehicleHalTest Bug: 200737967 Change-Id: I0e0be46f4a77b5dd5569fa949f67618a9aa9ac73 --- automotive/vehicle/aidl/impl/vhal/Android.bp | 5 +- .../aidl/impl/vhal/include/ConnectedClient.h | 82 +++++++ .../aidl/impl/vhal/src/ConnectedClient.cpp | 160 ++++++++++++++ .../impl/vhal/test/ConnectedClientTest.cpp | 208 ++++++++++++++++++ 4 files changed, 454 insertions(+), 1 deletion(-) create mode 100644 automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h create mode 100644 automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp create mode 100644 automotive/vehicle/aidl/impl/vhal/test/ConnectedClientTest.cpp diff --git a/automotive/vehicle/aidl/impl/vhal/Android.bp b/automotive/vehicle/aidl/impl/vhal/Android.bp index ef1d0f18ef..79d3ebd82e 100644 --- a/automotive/vehicle/aidl/impl/vhal/Android.bp +++ b/automotive/vehicle/aidl/impl/vhal/Android.bp @@ -53,7 +53,10 @@ cc_library { ], local_include_dirs: ["include"], export_include_dirs: ["include"], - srcs: ["src/DefaultVehicleHal.cpp"], + srcs: [ + "src/ConnectedClient.cpp", + "src/DefaultVehicleHal.cpp", + ], static_libs: [ "VehicleHalUtils", "android-automotive-large-parcelable-vendor-lib", diff --git a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h new file mode 100644 index 0000000000..43a96036cb --- /dev/null +++ b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2021 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. + */ + +#ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_include_ConnectedClient_H_ +#define android_hardware_automotive_vehicle_aidl_impl_vhal_include_ConnectedClient_H_ + +#include + +#include +#include + +#include +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { + +// A class to represent a binder client with a callback interface. Each callback function, e.g. +// GetValues or SetValues for a specific binder client is a separate {@code ConnectedClient}. +// For one {@code ConnectedClient}, we use one pending request pool to manage all pending requests, +// so the request IDs must be unique for one client. We also manage a set of callback functions +// for one client, e.g. timeoutCallback which could be passed to hardware. +// This class is thread-safe. +class ConnectedClient { + public: + ConnectedClient( + std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> + callback); + + virtual ~ConnectedClient() = default; + + protected: + const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> + mCallback; +}; + +// A class to represent a client that calls {@code IVehicle.setValues} or {@code +// IVehicle.getValues}. +template +class GetSetValuesClient final : public ConnectedClient { + public: + GetSetValuesClient( + std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> + callback); + + // Sends the results to this client. + void sendResults(const std::vector& results); + + // Sends each result separately to this client. Each result would be sent through one callback + // invocation. + void sendResultsSeparately(const std::vector& results); + + // Gets the callback to be called when the request for this client has finished. + std::shared_ptr)>> getResultCallback(); + + private: + // The following members are only initialized during construction. + std::shared_ptr)>> mResultCallback; +}; + +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_aidl_impl_vhal_include_ConnectedClient_H_ diff --git a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp new file mode 100644 index 0000000000..656dfaf579 --- /dev/null +++ b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2021 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 "ConnectedClient.h" +#include "ParcelableUtils.h" + +#include + +#include + +#include +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { + +namespace { + +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::SetValueResult; +using ::aidl::android::hardware::automotive::vehicle::SetValueResults; +using ::aidl::android::hardware::automotive::vehicle::StatusCode; +using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue; +using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues; +using ::android::base::Result; +using ::ndk::ScopedAStatus; + +// A function to call the specific callback based on results type. +template +ScopedAStatus callCallback(std::shared_ptr callback, const T& results); + +template <> +ScopedAStatus callCallback(std::shared_ptr callback, + const GetValueResults& results) { + return callback->onGetValues(results); +} + +template <> +ScopedAStatus callCallback(std::shared_ptr callback, + const SetValueResults& results) { + return callback->onSetValues(results); +} + +// Send a single GetValue/SetValue result through the callback. +template +void sendGetOrSetValueResult(std::shared_ptr callback, const ResultType& result) { + ResultsType parcelableResults; + parcelableResults.payloads.resize(1); + parcelableResults.payloads[0] = result; + if (ScopedAStatus callbackStatus = callCallback(callback, parcelableResults); + !callbackStatus.isOk()) { + ALOGE("failed to call callback, error: %s, code: %d", callbackStatus.getMessage(), + callbackStatus.getServiceSpecificError()); + } +} + +// Send all the GetValue/SetValue results through callback, one result in each callback invocation. +template +void sendGetOrSetValueResultsSeparately(std::shared_ptr callback, + const std::vector& results) { + for (const auto& result : results) { + sendGetOrSetValueResult(callback, result); + } +} + +// Send all the GetValue/SetValue results through callback in a single callback invocation. +template +void sendGetOrSetValueResults(std::shared_ptr callback, + const std::vector& results) { + ResultsType parcelableResults; + ScopedAStatus status = vectorToStableLargeParcelable(results, &parcelableResults); + if (status.isOk()) { + if (ScopedAStatus callbackStatus = callCallback(callback, parcelableResults); + !callbackStatus.isOk()) { + ALOGE("failed to call callback, error: %s, code: %d", status.getMessage(), + status.getServiceSpecificError()); + } + return; + } + int statusCode = status.getServiceSpecificError(); + ALOGE("failed to marshal result into large parcelable, error: " + "%s, code: %d", + status.getMessage(), statusCode); + sendGetOrSetValueResultsSeparately(callback, results); +} + +// Specify the functions for GetValues and SetValues types. +template void sendGetOrSetValueResult( + std::shared_ptr callback, const GetValueResult& result); +template void sendGetOrSetValueResult( + std::shared_ptr callback, const SetValueResult& result); + +template void sendGetOrSetValueResults( + std::shared_ptr callback, const std::vector& results); +template void sendGetOrSetValueResults( + std::shared_ptr callback, const std::vector& results); + +template void sendGetOrSetValueResultsSeparately( + std::shared_ptr callback, const std::vector& results); +template void sendGetOrSetValueResultsSeparately( + std::shared_ptr callback, const std::vector& results); + +} // namespace + +ConnectedClient::ConnectedClient(std::shared_ptr callback) + : mCallback(callback) {} + +template +GetSetValuesClient::GetSetValuesClient( + std::shared_ptr callback) + : ConnectedClient(callback) { + mResultCallback = std::make_shared)>>( + [callback](std::vector results) { + return sendGetOrSetValueResults(callback, results); + }); +} + +template +std::shared_ptr)>> +GetSetValuesClient::getResultCallback() { + return mResultCallback; +} + +template +void GetSetValuesClient::sendResults( + const std::vector& results) { + return sendGetOrSetValueResults(mCallback, results); +} + +template +void GetSetValuesClient::sendResultsSeparately( + const std::vector& results) { + return sendGetOrSetValueResultsSeparately(mCallback, results); +} + +template class GetSetValuesClient; +template class GetSetValuesClient; + +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/automotive/vehicle/aidl/impl/vhal/test/ConnectedClientTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/ConnectedClientTest.cpp new file mode 100644 index 0000000000..ddd0c65ec5 --- /dev/null +++ b/automotive/vehicle/aidl/impl/vhal/test/ConnectedClientTest.cpp @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2021 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 "ConnectedClient.h" +#include "MockVehicleCallback.h" + +#include + +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { + +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::SetValueResult; +using ::aidl::android::hardware::automotive::vehicle::SetValueResults; +using ::aidl::android::hardware::automotive::vehicle::StatusCode; +using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue; + +class ConnectedClientTest : public ::testing::Test { + public: + void SetUp() override { + mCallback = ndk::SharedRefBase::make(); + mCallbackClient = IVehicleCallback::fromBinder(mCallback->asBinder()); + } + + std::shared_ptr getCallbackClient() { return mCallbackClient; } + + MockVehicleCallback* getCallback() { return mCallback.get(); } + + protected: + using GetValuesClient = GetSetValuesClient; + using SetValuesClient = GetSetValuesClient; + + private: + std::shared_ptr mCallback; + std::shared_ptr mCallbackClient; +}; + +TEST_F(ConnectedClientTest, testSendGetValueResults) { + std::vector results = {{ + .requestId = 0, + .status = StatusCode::OK, + .prop = + VehiclePropValue{ + .prop = 0, + }, + }, + { + .requestId = 1, + .status = StatusCode::OK, + .prop = + VehiclePropValue{ + .prop = 1, + }, + }}; + + GetValuesClient client(getCallbackClient()); + + client.sendResults(results); + + auto maybeGetValueResults = getCallback()->nextGetValueResults(); + ASSERT_TRUE(maybeGetValueResults.has_value()); + ASSERT_EQ(maybeGetValueResults.value().payloads, results); +} + +TEST_F(ConnectedClientTest, testSendGetValueResultsSeparately) { + std::vector results = {{ + .requestId = 0, + .status = StatusCode::OK, + .prop = + VehiclePropValue{ + .prop = 0, + }, + }, + { + .requestId = 1, + .status = StatusCode::OK, + .prop = + VehiclePropValue{ + .prop = 1, + }, + }}; + + GetValuesClient client(getCallbackClient()); + + client.sendResultsSeparately(results); + + for (auto& result : results) { + auto maybeGetValueResults = getCallback()->nextGetValueResults(); + EXPECT_TRUE(maybeGetValueResults.has_value()); + if (!maybeGetValueResults.has_value()) { + continue; + } + EXPECT_EQ(maybeGetValueResults.value().payloads, std::vector({result})); + } +} + +TEST_F(ConnectedClientTest, testGetValuesGnResultCallback) { + std::vector results = {{ + .requestId = 0, + .status = StatusCode::OK, + .prop = + VehiclePropValue{ + .prop = 0, + }, + }, + { + .requestId = 1, + .status = StatusCode::OK, + .prop = + VehiclePropValue{ + .prop = 1, + }, + }}; + + GetValuesClient client(getCallbackClient()); + + (*(client.getResultCallback()))(results); + + auto maybeGetValueResults = getCallback()->nextGetValueResults(); + ASSERT_TRUE(maybeGetValueResults.has_value()); + ASSERT_EQ(maybeGetValueResults.value().payloads, results); +} + +TEST_F(ConnectedClientTest, testSendSetValueResults) { + std::vector results = {{ + .requestId = 0, + .status = StatusCode::OK, + }, + { + .requestId = 1, + .status = StatusCode::OK, + }}; + + SetValuesClient client(getCallbackClient()); + + client.sendResults(results); + + auto maybeSetValueResults = getCallback()->nextSetValueResults(); + ASSERT_TRUE(maybeSetValueResults.has_value()); + ASSERT_EQ(maybeSetValueResults.value().payloads, results); +} + +TEST_F(ConnectedClientTest, testSendSetValueResultsSeparately) { + std::vector results = {{ + .requestId = 0, + .status = StatusCode::OK, + }, + { + .requestId = 1, + .status = StatusCode::OK, + }}; + + SetValuesClient client(getCallbackClient()); + + client.sendResultsSeparately(results); + + for (auto& result : results) { + auto maybeSetValueResults = getCallback()->nextSetValueResults(); + EXPECT_TRUE(maybeSetValueResults.has_value()); + if (!maybeSetValueResults.has_value()) { + continue; + } + EXPECT_EQ(maybeSetValueResults.value().payloads, std::vector({result})); + } +} + +TEST_F(ConnectedClientTest, testSetValuesGetResultCallback) { + std::vector results = {{ + .requestId = 0, + .status = StatusCode::OK, + }, + { + .requestId = 1, + .status = StatusCode::OK, + }}; + + SetValuesClient client(getCallbackClient()); + + (*(client.getResultCallback()))(results); + + auto maybeSetValueResults = getCallback()->nextSetValueResults(); + ASSERT_TRUE(maybeSetValueResults.has_value()); + ASSERT_EQ(maybeSetValueResults.value().payloads, results); +} + +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android