Loading automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h +27 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ #ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_include_ConnectedClient_H_ #define android_hardware_automotive_vehicle_aidl_impl_vhal_include_ConnectedClient_H_ #include "PendingRequestPool.h" #include <VehicleHalTypes.h> #include <aidl/android/hardware/automotive/vehicle/IVehicleCallback.h> Loading @@ -40,12 +42,31 @@ namespace vehicle { class ConnectedClient { public: ConnectedClient( std::shared_ptr<PendingRequestPool> requestPool, std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback); virtual ~ConnectedClient() = default; // Gets the unique ID for this client. const void* id(); // Add client requests. The requests would be registered as pending requests until // {@code tryFinishRequests} is called for them. // Returns {@code INVALID_ARG} error if any of the requestIds are duplicate with one of the // pending request IDs or {@code TRY_AGAIN} error if the pending request pool is full and could // no longer add requests. ::android::base::Result<void> addRequests(const std::unordered_set<int64_t>& requestIds); // Mark the requests as finished. Returns a list of request IDs that was pending and has been // finished. It must be a set of the requested request IDs. std::unordered_set<int64_t> tryFinishRequests(const std::unordered_set<int64_t>& requestIds); protected: // Gets the callback to be called when the request for this client has timeout. virtual std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> getTimeoutCallback() = 0; const std::shared_ptr<PendingRequestPool> mRequestPool; const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> mCallback; }; Loading @@ -56,6 +77,7 @@ template <class ResultType, class ResultsType> class GetSetValuesClient final : public ConnectedClient { public: GetSetValuesClient( std::shared_ptr<PendingRequestPool> requestPool, std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback); Loading @@ -69,8 +91,13 @@ class GetSetValuesClient final : public ConnectedClient { // Gets the callback to be called when the request for this client has finished. std::shared_ptr<const std::function<void(std::vector<ResultType>)>> getResultCallback(); protected: // Gets the callback to be called when the request for this client has timeout. std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> getTimeoutCallback() override; private: // The following members are only initialized during construction. std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> mTimeoutCallback; std::shared_ptr<const std::function<void(std::vector<ResultType>)>> mResultCallback; }; Loading automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h +16 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include "ConnectedClient.h" #include "ParcelableUtils.h" #include "PendingRequestPool.h" #include <IVehicleHardware.h> #include <VehicleUtils.h> Loading @@ -28,6 +29,7 @@ #include <android/binder_auto_utils.h> #include <memory> #include <mutex> #include <unordered_map> #include <vector> Loading Loading @@ -100,6 +102,8 @@ class DefaultVehicleHal final : public ::aidl::android::hardware::automotive::ve mConfigsByPropId; // Only modified in constructor, so thread-safe. std::unique_ptr<::ndk::ScopedFileDescriptor> mConfigFile; // PendingRequestPool is thread-safe. std::shared_ptr<PendingRequestPool> mPendingRequestPool; std::mutex mLock; std::unordered_map<CallbackType, std::shared_ptr<GetValuesClient>> mGetValuesClients Loading @@ -114,6 +118,18 @@ class DefaultVehicleHal final : public ::aidl::android::hardware::automotive::ve ::android::base::Result<void> checkProperty( const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue); ::android::base::Result<std::vector<int64_t>> checkDuplicateRequests( const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>& requests); ::android::base::Result<std::vector<int64_t>> checkDuplicateRequests( const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>& requests); // Test-only // Set the default timeout for pending requests. void setTimeout(int64_t timeoutInNano); }; } // namespace vehicle Loading automotive/vehicle/aidl/impl/vhal/include/PendingRequestPool.h +4 −2 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ class PendingRequestPool final { // seconds. android::base::Result<void> addRequests(const void* clientId, const std::unordered_set<int64_t>& requestIds, std::shared_ptr<TimeoutCallbackFunc> callback); std::shared_ptr<const TimeoutCallbackFunc> callback); // Checks whether the request is currently pending. bool isRequestPending(const void* clientId, int64_t requestId) const; Loading @@ -66,6 +66,8 @@ class PendingRequestPool final { // Returns how many pending requests in the pool, for testing purpose. size_t countPendingRequests(const void* clientId) const; size_t countPendingRequests() const; private: // The maximum number of pending requests allowed per client. If exceeds this number, adding // more requests would fail. This is to prevent spamming from client. Loading @@ -74,7 +76,7 @@ class PendingRequestPool final { struct PendingRequest { std::unordered_set<int64_t> requestIds; int64_t timeoutTimestamp; std::shared_ptr<TimeoutCallbackFunc> callback; std::shared_ptr<const TimeoutCallbackFunc> callback; }; int64_t mTimeoutInNano; Loading automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp +96 −6 Original line number Diff line number Diff line Loading @@ -102,6 +102,53 @@ void sendGetOrSetValueResults(std::shared_ptr<IVehicleCallback> callback, sendGetOrSetValueResultsSeparately<ResultType, ResultsType>(callback, results); } // The timeout callback for GetValues/SetValues. template <class ResultType, class ResultsType> void onTimeout( std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, const std::unordered_set<int64_t>& timeoutIds) { std::vector<ResultType> timeoutResults; for (int64_t requestId : timeoutIds) { ALOGD("hardware request timeout, request ID: %" PRId64, requestId); timeoutResults.push_back({ .requestId = requestId, .status = StatusCode::TRY_AGAIN, }); } sendGetOrSetValueResults<ResultType, ResultsType>(callback, timeoutResults); } // The on-results callback for GetValues/SetValues. template <class ResultType, class ResultsType> void getOrSetValuesCallback( const void* clientId, std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, std::vector<ResultType> results, std::shared_ptr<PendingRequestPool> requestPool) { std::unordered_set<int64_t> requestIds; for (const auto& result : results) { requestIds.insert(result.requestId); } auto finishedRequests = requestPool->tryFinishRequests(clientId, requestIds); auto it = results.begin(); while (it != results.end()) { int64_t requestId = it->requestId; if (finishedRequests.find(requestId) == finishedRequests.end()) { ALOGD("no pending request for the result from hardware, " "possibly already time-out, ID: %" PRId64, requestId); it = results.erase(it); } else { it++; } } if (!results.empty()) { sendGetOrSetValueResults<ResultType, ResultsType>(callback, results); } } // Specify the functions for GetValues and SetValues types. template void sendGetOrSetValueResult<GetValueResult, GetValueResults>( std::shared_ptr<IVehicleCallback> callback, const GetValueResult& result); Loading @@ -118,18 +165,55 @@ template void sendGetOrSetValueResultsSeparately<GetValueResult, GetValueResults template void sendGetOrSetValueResultsSeparately<SetValueResult, SetValueResults>( std::shared_ptr<IVehicleCallback> callback, const std::vector<SetValueResult>& results); template void onTimeout<GetValueResult, GetValueResults>( std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, const std::unordered_set<int64_t>& timeoutIds); template void onTimeout<SetValueResult, SetValueResults>( std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, const std::unordered_set<int64_t>& timeoutIds); template void getOrSetValuesCallback<GetValueResult, GetValueResults>( const void* clientId, std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, std::vector<GetValueResult> results, std::shared_ptr<PendingRequestPool> requestPool); template void getOrSetValuesCallback<SetValueResult, SetValueResults>( const void* clientId, std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, std::vector<SetValueResult> results, std::shared_ptr<PendingRequestPool> requestPool); } // namespace ConnectedClient::ConnectedClient(std::shared_ptr<IVehicleCallback> callback) : mCallback(callback) {} ConnectedClient::ConnectedClient(std::shared_ptr<PendingRequestPool> requestPool, std::shared_ptr<IVehicleCallback> callback) : mRequestPool(requestPool), mCallback(callback) {} const void* ConnectedClient::id() { return reinterpret_cast<const void*>(this); } Result<void> ConnectedClient::addRequests(const std::unordered_set<int64_t>& requestIds) { return mRequestPool->addRequests(id(), requestIds, getTimeoutCallback()); } std::unordered_set<int64_t> ConnectedClient::tryFinishRequests( const std::unordered_set<int64_t>& requestIds) { return mRequestPool->tryFinishRequests(id(), requestIds); } template <class ResultType, class ResultsType> GetSetValuesClient<ResultType, ResultsType>::GetSetValuesClient( std::shared_ptr<IVehicleCallback> callback) : ConnectedClient(callback) { std::shared_ptr<PendingRequestPool> requestPool, std::shared_ptr<IVehicleCallback> callback) : ConnectedClient(requestPool, callback) { mTimeoutCallback = std::make_shared<const PendingRequestPool::TimeoutCallbackFunc>( [callback](const std::unordered_set<int64_t>& timeoutIds) { return onTimeout<ResultType, ResultsType>(callback, timeoutIds); }); auto requestPoolCopy = mRequestPool; const void* clientId = id(); mResultCallback = std::make_shared<const std::function<void(std::vector<ResultType>)>>( [callback](std::vector<ResultType> results) { return sendGetOrSetValueResults<ResultType, ResultsType>(callback, results); [clientId, callback, requestPoolCopy](std::vector<ResultType> results) { return getOrSetValuesCallback<ResultType, ResultsType>( clientId, callback, std::move(results), requestPoolCopy); }); } Loading @@ -139,6 +223,12 @@ GetSetValuesClient<ResultType, ResultsType>::getResultCallback() { return mResultCallback; } template <class ResultType, class ResultsType> std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> GetSetValuesClient<ResultType, ResultsType>::getTimeoutCallback() { return mTimeoutCallback; } template <class ResultType, class ResultsType> void GetSetValuesClient<ResultType, ResultsType>::sendResults( const std::vector<ResultType>& results) { Loading automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp +82 −7 Original line number Diff line number Diff line Loading @@ -25,6 +25,9 @@ #include <android-base/result.h> #include <utils/Log.h> #include <set> #include <unordered_set> namespace android { namespace hardware { namespace automotive { Loading Loading @@ -52,7 +55,8 @@ using ::android::base::Result; using ::ndk::ScopedAStatus; DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware) : mVehicleHardware(std::move(hardware)) { : mVehicleHardware(std::move(hardware)), mPendingRequestPool(std::make_shared<PendingRequestPool>(TIMEOUT_IN_NANO)) { auto configs = mVehicleHardware->getAllPropertyConfigs(); for (auto& config : configs) { mConfigsByPropId[config.prop] = config; Loading @@ -71,6 +75,10 @@ DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware) } } void DefaultVehicleHal::setTimeout(int64_t timeoutInNano) { mPendingRequestPool = std::make_unique<PendingRequestPool>(timeoutInNano); } ScopedAStatus DefaultVehicleHal::getAllPropConfigs(VehiclePropConfigs* output) { if (mConfigFile != nullptr) { output->payloads.clear(); Loading @@ -90,7 +98,7 @@ std::shared_ptr<T> DefaultVehicleHal::getOrCreateClient( 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); (*clients)[callback] = std::make_shared<T>(mPendingRequestPool, callback); } return (*clients)[callback]; } Loading Loading @@ -132,8 +140,6 @@ Result<void> DefaultVehicleHal::checkProperty(const VehiclePropValue& propValue) ScopedAStatus DefaultVehicleHal::getValues(const CallbackType& callback, const GetValueRequests& requests) { // TODO(b/203713317): check for duplicate properties and duplicate request IDs. expected<LargeParcelableBase::BorrowedOwnedObject<GetValueRequests>, ScopedAStatus> deserializedResults = fromStableLargeParcelable(requests); if (!deserializedResults.ok()) { Loading @@ -143,26 +149,42 @@ ScopedAStatus DefaultVehicleHal::getValues(const CallbackType& callback, const std::vector<GetValueRequest>& getValueRequests = deserializedResults.value().getObject()->payloads; auto maybeRequestIds = checkDuplicateRequests(getValueRequests); if (!maybeRequestIds.ok()) { ALOGE("duplicate request ID"); return toScopedAStatus(maybeRequestIds, StatusCode::INVALID_ARG); } // The set of request Ids that we would send to hardware. std::unordered_set<int64_t> hardwareRequestIds(maybeRequestIds.value().begin(), maybeRequestIds.value().end()); std::shared_ptr<GetValuesClient> client; { std::scoped_lock<std::mutex> lockGuard(mLock); client = getOrCreateClient(&mGetValuesClients, callback); } // Register the pending hardware requests and also check for duplicate request Ids. if (auto addRequestResult = client->addRequests(hardwareRequestIds); !addRequestResult.ok()) { ALOGE("failed to add pending requests, error: %s", addRequestResult.error().message().c_str()); return toScopedAStatus(addRequestResult); } if (StatusCode status = mVehicleHardware->getValues(client->getResultCallback(), getValueRequests); status != StatusCode::OK) { // If the hardware returns error, finish all the pending requests for this request because // we never expect hardware to call callback for these requests. client->tryFinishRequests(hardwareRequestIds); ALOGE("failed to get value from VehicleHardware, status: %d", toInt(status)); return ScopedAStatus::fromServiceSpecificErrorWithMessage( toInt(status), "failed to get value from VehicleHardware"); } return ScopedAStatus::ok(); } ScopedAStatus DefaultVehicleHal::setValues(const CallbackType& callback, const SetValueRequests& requests) { // TODO(b/203713317): check for duplicate properties and duplicate request IDs. expected<LargeParcelableBase::BorrowedOwnedObject<SetValueRequests>, ScopedAStatus> deserializedResults = fromStableLargeParcelable(requests); if (!deserializedResults.ok()) { Loading @@ -177,6 +199,12 @@ ScopedAStatus DefaultVehicleHal::setValues(const CallbackType& callback, // The list of requests that we would send to hardware. std::vector<SetValueRequest> hardwareRequests; auto maybeRequestIds = checkDuplicateRequests(setValueRequests); if (!maybeRequestIds.ok()) { ALOGE("duplicate request ID"); return toScopedAStatus(maybeRequestIds, StatusCode::INVALID_ARG); } for (auto& request : setValueRequests) { int64_t requestId = request.requestId; if (auto result = checkProperty(request.value); !result.ok()) { Loading @@ -187,22 +215,41 @@ ScopedAStatus DefaultVehicleHal::setValues(const CallbackType& callback, }); continue; } hardwareRequests.push_back(request); } // The set of request Ids that we would send to hardware. std::unordered_set<int64_t> hardwareRequestIds; for (const auto& request : hardwareRequests) { hardwareRequestIds.insert(request.requestId); } std::shared_ptr<SetValuesClient> client; { std::scoped_lock<std::mutex> lockGuard(mLock); client = getOrCreateClient(&mSetValuesClients, callback); } // Register the pending hardware requests and also check for duplicate request Ids. if (auto addRequestResult = client->addRequests(hardwareRequestIds); !addRequestResult.ok()) { ALOGE("failed to add pending requests, error: %s", addRequestResult.error().message().c_str()); return toScopedAStatus(addRequestResult, StatusCode::INVALID_ARG); } if (!failedResults.empty()) { // First send the failed results we already know back to the client. client->sendResults(failedResults); } if (StatusCode status = mVehicleHardware->setValues(client->getResultCallback(), hardwareRequests); status != StatusCode::OK) { // If the hardware returns error, finish all the pending requests for this request because // we never expect hardware to call callback for these requests. client->tryFinishRequests(hardwareRequestIds); ALOGE("failed to set value to VehicleHardware, status: %d", toInt(status)); return ScopedAStatus::fromServiceSpecificErrorWithMessage( toInt(status), "failed to set value to VehicleHardware"); } Loading @@ -210,6 +257,34 @@ ScopedAStatus DefaultVehicleHal::setValues(const CallbackType& callback, return ScopedAStatus::ok(); } #define CHECK_DUPLICATE_REQUESTS(PROP_NAME) \ do { \ std::vector<int64_t> requestIds; \ std::set<::aidl::android::hardware::automotive::vehicle::VehiclePropValue> requestProps; \ for (const auto& request : requests) { \ const auto& prop = request.PROP_NAME; \ if (requestProps.count(prop) != 0) { \ return ::android::base::Error() \ << "duplicate request for property: " << prop.toString(); \ } \ requestProps.insert(prop); \ requestIds.push_back(request.requestId); \ } \ return requestIds; \ } while (0); ::android::base::Result<std::vector<int64_t>> DefaultVehicleHal::checkDuplicateRequests( const std::vector<GetValueRequest>& requests) { CHECK_DUPLICATE_REQUESTS(prop); } ::android::base::Result<std::vector<int64_t>> DefaultVehicleHal::checkDuplicateRequests( const std::vector<SetValueRequest>& requests) { CHECK_DUPLICATE_REQUESTS(value); } #undef CHECK_DUPLICATE_REQUESTS ScopedAStatus DefaultVehicleHal::getPropConfigs(const std::vector<int32_t>& props, VehiclePropConfigs* output) { std::vector<VehiclePropConfig> configs; Loading Loading
automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h +27 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ #ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_include_ConnectedClient_H_ #define android_hardware_automotive_vehicle_aidl_impl_vhal_include_ConnectedClient_H_ #include "PendingRequestPool.h" #include <VehicleHalTypes.h> #include <aidl/android/hardware/automotive/vehicle/IVehicleCallback.h> Loading @@ -40,12 +42,31 @@ namespace vehicle { class ConnectedClient { public: ConnectedClient( std::shared_ptr<PendingRequestPool> requestPool, std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback); virtual ~ConnectedClient() = default; // Gets the unique ID for this client. const void* id(); // Add client requests. The requests would be registered as pending requests until // {@code tryFinishRequests} is called for them. // Returns {@code INVALID_ARG} error if any of the requestIds are duplicate with one of the // pending request IDs or {@code TRY_AGAIN} error if the pending request pool is full and could // no longer add requests. ::android::base::Result<void> addRequests(const std::unordered_set<int64_t>& requestIds); // Mark the requests as finished. Returns a list of request IDs that was pending and has been // finished. It must be a set of the requested request IDs. std::unordered_set<int64_t> tryFinishRequests(const std::unordered_set<int64_t>& requestIds); protected: // Gets the callback to be called when the request for this client has timeout. virtual std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> getTimeoutCallback() = 0; const std::shared_ptr<PendingRequestPool> mRequestPool; const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> mCallback; }; Loading @@ -56,6 +77,7 @@ template <class ResultType, class ResultsType> class GetSetValuesClient final : public ConnectedClient { public: GetSetValuesClient( std::shared_ptr<PendingRequestPool> requestPool, std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback); Loading @@ -69,8 +91,13 @@ class GetSetValuesClient final : public ConnectedClient { // Gets the callback to be called when the request for this client has finished. std::shared_ptr<const std::function<void(std::vector<ResultType>)>> getResultCallback(); protected: // Gets the callback to be called when the request for this client has timeout. std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> getTimeoutCallback() override; private: // The following members are only initialized during construction. std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> mTimeoutCallback; std::shared_ptr<const std::function<void(std::vector<ResultType>)>> mResultCallback; }; Loading
automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h +16 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include "ConnectedClient.h" #include "ParcelableUtils.h" #include "PendingRequestPool.h" #include <IVehicleHardware.h> #include <VehicleUtils.h> Loading @@ -28,6 +29,7 @@ #include <android/binder_auto_utils.h> #include <memory> #include <mutex> #include <unordered_map> #include <vector> Loading Loading @@ -100,6 +102,8 @@ class DefaultVehicleHal final : public ::aidl::android::hardware::automotive::ve mConfigsByPropId; // Only modified in constructor, so thread-safe. std::unique_ptr<::ndk::ScopedFileDescriptor> mConfigFile; // PendingRequestPool is thread-safe. std::shared_ptr<PendingRequestPool> mPendingRequestPool; std::mutex mLock; std::unordered_map<CallbackType, std::shared_ptr<GetValuesClient>> mGetValuesClients Loading @@ -114,6 +118,18 @@ class DefaultVehicleHal final : public ::aidl::android::hardware::automotive::ve ::android::base::Result<void> checkProperty( const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue); ::android::base::Result<std::vector<int64_t>> checkDuplicateRequests( const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>& requests); ::android::base::Result<std::vector<int64_t>> checkDuplicateRequests( const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>& requests); // Test-only // Set the default timeout for pending requests. void setTimeout(int64_t timeoutInNano); }; } // namespace vehicle Loading
automotive/vehicle/aidl/impl/vhal/include/PendingRequestPool.h +4 −2 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ class PendingRequestPool final { // seconds. android::base::Result<void> addRequests(const void* clientId, const std::unordered_set<int64_t>& requestIds, std::shared_ptr<TimeoutCallbackFunc> callback); std::shared_ptr<const TimeoutCallbackFunc> callback); // Checks whether the request is currently pending. bool isRequestPending(const void* clientId, int64_t requestId) const; Loading @@ -66,6 +66,8 @@ class PendingRequestPool final { // Returns how many pending requests in the pool, for testing purpose. size_t countPendingRequests(const void* clientId) const; size_t countPendingRequests() const; private: // The maximum number of pending requests allowed per client. If exceeds this number, adding // more requests would fail. This is to prevent spamming from client. Loading @@ -74,7 +76,7 @@ class PendingRequestPool final { struct PendingRequest { std::unordered_set<int64_t> requestIds; int64_t timeoutTimestamp; std::shared_ptr<TimeoutCallbackFunc> callback; std::shared_ptr<const TimeoutCallbackFunc> callback; }; int64_t mTimeoutInNano; Loading
automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp +96 −6 Original line number Diff line number Diff line Loading @@ -102,6 +102,53 @@ void sendGetOrSetValueResults(std::shared_ptr<IVehicleCallback> callback, sendGetOrSetValueResultsSeparately<ResultType, ResultsType>(callback, results); } // The timeout callback for GetValues/SetValues. template <class ResultType, class ResultsType> void onTimeout( std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, const std::unordered_set<int64_t>& timeoutIds) { std::vector<ResultType> timeoutResults; for (int64_t requestId : timeoutIds) { ALOGD("hardware request timeout, request ID: %" PRId64, requestId); timeoutResults.push_back({ .requestId = requestId, .status = StatusCode::TRY_AGAIN, }); } sendGetOrSetValueResults<ResultType, ResultsType>(callback, timeoutResults); } // The on-results callback for GetValues/SetValues. template <class ResultType, class ResultsType> void getOrSetValuesCallback( const void* clientId, std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, std::vector<ResultType> results, std::shared_ptr<PendingRequestPool> requestPool) { std::unordered_set<int64_t> requestIds; for (const auto& result : results) { requestIds.insert(result.requestId); } auto finishedRequests = requestPool->tryFinishRequests(clientId, requestIds); auto it = results.begin(); while (it != results.end()) { int64_t requestId = it->requestId; if (finishedRequests.find(requestId) == finishedRequests.end()) { ALOGD("no pending request for the result from hardware, " "possibly already time-out, ID: %" PRId64, requestId); it = results.erase(it); } else { it++; } } if (!results.empty()) { sendGetOrSetValueResults<ResultType, ResultsType>(callback, results); } } // Specify the functions for GetValues and SetValues types. template void sendGetOrSetValueResult<GetValueResult, GetValueResults>( std::shared_ptr<IVehicleCallback> callback, const GetValueResult& result); Loading @@ -118,18 +165,55 @@ template void sendGetOrSetValueResultsSeparately<GetValueResult, GetValueResults template void sendGetOrSetValueResultsSeparately<SetValueResult, SetValueResults>( std::shared_ptr<IVehicleCallback> callback, const std::vector<SetValueResult>& results); template void onTimeout<GetValueResult, GetValueResults>( std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, const std::unordered_set<int64_t>& timeoutIds); template void onTimeout<SetValueResult, SetValueResults>( std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, const std::unordered_set<int64_t>& timeoutIds); template void getOrSetValuesCallback<GetValueResult, GetValueResults>( const void* clientId, std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, std::vector<GetValueResult> results, std::shared_ptr<PendingRequestPool> requestPool); template void getOrSetValuesCallback<SetValueResult, SetValueResults>( const void* clientId, std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback> callback, std::vector<SetValueResult> results, std::shared_ptr<PendingRequestPool> requestPool); } // namespace ConnectedClient::ConnectedClient(std::shared_ptr<IVehicleCallback> callback) : mCallback(callback) {} ConnectedClient::ConnectedClient(std::shared_ptr<PendingRequestPool> requestPool, std::shared_ptr<IVehicleCallback> callback) : mRequestPool(requestPool), mCallback(callback) {} const void* ConnectedClient::id() { return reinterpret_cast<const void*>(this); } Result<void> ConnectedClient::addRequests(const std::unordered_set<int64_t>& requestIds) { return mRequestPool->addRequests(id(), requestIds, getTimeoutCallback()); } std::unordered_set<int64_t> ConnectedClient::tryFinishRequests( const std::unordered_set<int64_t>& requestIds) { return mRequestPool->tryFinishRequests(id(), requestIds); } template <class ResultType, class ResultsType> GetSetValuesClient<ResultType, ResultsType>::GetSetValuesClient( std::shared_ptr<IVehicleCallback> callback) : ConnectedClient(callback) { std::shared_ptr<PendingRequestPool> requestPool, std::shared_ptr<IVehicleCallback> callback) : ConnectedClient(requestPool, callback) { mTimeoutCallback = std::make_shared<const PendingRequestPool::TimeoutCallbackFunc>( [callback](const std::unordered_set<int64_t>& timeoutIds) { return onTimeout<ResultType, ResultsType>(callback, timeoutIds); }); auto requestPoolCopy = mRequestPool; const void* clientId = id(); mResultCallback = std::make_shared<const std::function<void(std::vector<ResultType>)>>( [callback](std::vector<ResultType> results) { return sendGetOrSetValueResults<ResultType, ResultsType>(callback, results); [clientId, callback, requestPoolCopy](std::vector<ResultType> results) { return getOrSetValuesCallback<ResultType, ResultsType>( clientId, callback, std::move(results), requestPoolCopy); }); } Loading @@ -139,6 +223,12 @@ GetSetValuesClient<ResultType, ResultsType>::getResultCallback() { return mResultCallback; } template <class ResultType, class ResultsType> std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> GetSetValuesClient<ResultType, ResultsType>::getTimeoutCallback() { return mTimeoutCallback; } template <class ResultType, class ResultsType> void GetSetValuesClient<ResultType, ResultsType>::sendResults( const std::vector<ResultType>& results) { Loading
automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp +82 −7 Original line number Diff line number Diff line Loading @@ -25,6 +25,9 @@ #include <android-base/result.h> #include <utils/Log.h> #include <set> #include <unordered_set> namespace android { namespace hardware { namespace automotive { Loading Loading @@ -52,7 +55,8 @@ using ::android::base::Result; using ::ndk::ScopedAStatus; DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware) : mVehicleHardware(std::move(hardware)) { : mVehicleHardware(std::move(hardware)), mPendingRequestPool(std::make_shared<PendingRequestPool>(TIMEOUT_IN_NANO)) { auto configs = mVehicleHardware->getAllPropertyConfigs(); for (auto& config : configs) { mConfigsByPropId[config.prop] = config; Loading @@ -71,6 +75,10 @@ DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware) } } void DefaultVehicleHal::setTimeout(int64_t timeoutInNano) { mPendingRequestPool = std::make_unique<PendingRequestPool>(timeoutInNano); } ScopedAStatus DefaultVehicleHal::getAllPropConfigs(VehiclePropConfigs* output) { if (mConfigFile != nullptr) { output->payloads.clear(); Loading @@ -90,7 +98,7 @@ std::shared_ptr<T> DefaultVehicleHal::getOrCreateClient( 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); (*clients)[callback] = std::make_shared<T>(mPendingRequestPool, callback); } return (*clients)[callback]; } Loading Loading @@ -132,8 +140,6 @@ Result<void> DefaultVehicleHal::checkProperty(const VehiclePropValue& propValue) ScopedAStatus DefaultVehicleHal::getValues(const CallbackType& callback, const GetValueRequests& requests) { // TODO(b/203713317): check for duplicate properties and duplicate request IDs. expected<LargeParcelableBase::BorrowedOwnedObject<GetValueRequests>, ScopedAStatus> deserializedResults = fromStableLargeParcelable(requests); if (!deserializedResults.ok()) { Loading @@ -143,26 +149,42 @@ ScopedAStatus DefaultVehicleHal::getValues(const CallbackType& callback, const std::vector<GetValueRequest>& getValueRequests = deserializedResults.value().getObject()->payloads; auto maybeRequestIds = checkDuplicateRequests(getValueRequests); if (!maybeRequestIds.ok()) { ALOGE("duplicate request ID"); return toScopedAStatus(maybeRequestIds, StatusCode::INVALID_ARG); } // The set of request Ids that we would send to hardware. std::unordered_set<int64_t> hardwareRequestIds(maybeRequestIds.value().begin(), maybeRequestIds.value().end()); std::shared_ptr<GetValuesClient> client; { std::scoped_lock<std::mutex> lockGuard(mLock); client = getOrCreateClient(&mGetValuesClients, callback); } // Register the pending hardware requests and also check for duplicate request Ids. if (auto addRequestResult = client->addRequests(hardwareRequestIds); !addRequestResult.ok()) { ALOGE("failed to add pending requests, error: %s", addRequestResult.error().message().c_str()); return toScopedAStatus(addRequestResult); } if (StatusCode status = mVehicleHardware->getValues(client->getResultCallback(), getValueRequests); status != StatusCode::OK) { // If the hardware returns error, finish all the pending requests for this request because // we never expect hardware to call callback for these requests. client->tryFinishRequests(hardwareRequestIds); ALOGE("failed to get value from VehicleHardware, status: %d", toInt(status)); return ScopedAStatus::fromServiceSpecificErrorWithMessage( toInt(status), "failed to get value from VehicleHardware"); } return ScopedAStatus::ok(); } ScopedAStatus DefaultVehicleHal::setValues(const CallbackType& callback, const SetValueRequests& requests) { // TODO(b/203713317): check for duplicate properties and duplicate request IDs. expected<LargeParcelableBase::BorrowedOwnedObject<SetValueRequests>, ScopedAStatus> deserializedResults = fromStableLargeParcelable(requests); if (!deserializedResults.ok()) { Loading @@ -177,6 +199,12 @@ ScopedAStatus DefaultVehicleHal::setValues(const CallbackType& callback, // The list of requests that we would send to hardware. std::vector<SetValueRequest> hardwareRequests; auto maybeRequestIds = checkDuplicateRequests(setValueRequests); if (!maybeRequestIds.ok()) { ALOGE("duplicate request ID"); return toScopedAStatus(maybeRequestIds, StatusCode::INVALID_ARG); } for (auto& request : setValueRequests) { int64_t requestId = request.requestId; if (auto result = checkProperty(request.value); !result.ok()) { Loading @@ -187,22 +215,41 @@ ScopedAStatus DefaultVehicleHal::setValues(const CallbackType& callback, }); continue; } hardwareRequests.push_back(request); } // The set of request Ids that we would send to hardware. std::unordered_set<int64_t> hardwareRequestIds; for (const auto& request : hardwareRequests) { hardwareRequestIds.insert(request.requestId); } std::shared_ptr<SetValuesClient> client; { std::scoped_lock<std::mutex> lockGuard(mLock); client = getOrCreateClient(&mSetValuesClients, callback); } // Register the pending hardware requests and also check for duplicate request Ids. if (auto addRequestResult = client->addRequests(hardwareRequestIds); !addRequestResult.ok()) { ALOGE("failed to add pending requests, error: %s", addRequestResult.error().message().c_str()); return toScopedAStatus(addRequestResult, StatusCode::INVALID_ARG); } if (!failedResults.empty()) { // First send the failed results we already know back to the client. client->sendResults(failedResults); } if (StatusCode status = mVehicleHardware->setValues(client->getResultCallback(), hardwareRequests); status != StatusCode::OK) { // If the hardware returns error, finish all the pending requests for this request because // we never expect hardware to call callback for these requests. client->tryFinishRequests(hardwareRequestIds); ALOGE("failed to set value to VehicleHardware, status: %d", toInt(status)); return ScopedAStatus::fromServiceSpecificErrorWithMessage( toInt(status), "failed to set value to VehicleHardware"); } Loading @@ -210,6 +257,34 @@ ScopedAStatus DefaultVehicleHal::setValues(const CallbackType& callback, return ScopedAStatus::ok(); } #define CHECK_DUPLICATE_REQUESTS(PROP_NAME) \ do { \ std::vector<int64_t> requestIds; \ std::set<::aidl::android::hardware::automotive::vehicle::VehiclePropValue> requestProps; \ for (const auto& request : requests) { \ const auto& prop = request.PROP_NAME; \ if (requestProps.count(prop) != 0) { \ return ::android::base::Error() \ << "duplicate request for property: " << prop.toString(); \ } \ requestProps.insert(prop); \ requestIds.push_back(request.requestId); \ } \ return requestIds; \ } while (0); ::android::base::Result<std::vector<int64_t>> DefaultVehicleHal::checkDuplicateRequests( const std::vector<GetValueRequest>& requests) { CHECK_DUPLICATE_REQUESTS(prop); } ::android::base::Result<std::vector<int64_t>> DefaultVehicleHal::checkDuplicateRequests( const std::vector<SetValueRequest>& requests) { CHECK_DUPLICATE_REQUESTS(value); } #undef CHECK_DUPLICATE_REQUESTS ScopedAStatus DefaultVehicleHal::getPropConfigs(const std::vector<int32_t>& props, VehiclePropConfigs* output) { std::vector<VehiclePropConfig> configs; Loading