diff options
Diffstat (limited to 'automotive/vehicle/aidl/impl/vhal/src')
-rw-r--r-- | automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp | 49 | ||||
-rw-r--r-- | automotive/vehicle/aidl/impl/vhal/src/PendingRequestPool.cpp | 220 |
2 files changed, 240 insertions, 29 deletions
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp index e98f02112e..7f09a59fbb 100644 --- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp +++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp @@ -57,7 +57,9 @@ DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware) for (auto& config : configs) { mConfigsByPropId[config.prop] = config; } - auto result = LargeParcelableBase::parcelableVectorToStableLargeParcelable(configs); + VehiclePropConfigs vehiclePropConfigs; + vehiclePropConfigs.payloads = std::move(configs); + auto result = LargeParcelableBase::parcelableToStableLargeParcelable(vehiclePropConfigs); if (!result.ok()) { ALOGE("failed to convert configs to shared memory file, error: %s, code: %d", getErrorMsg(result).c_str(), getIntErrorCode(result)); @@ -71,6 +73,7 @@ DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware) ScopedAStatus DefaultVehicleHal::getAllPropConfigs(VehiclePropConfigs* output) { if (mConfigFile != nullptr) { + output->payloads.clear(); output->sharedMemoryFd.set(dup(mConfigFile->get())); return ScopedAStatus::ok(); } @@ -131,20 +134,14 @@ 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(); + expected<LargeParcelableBase::BorrowedOwnedObject<GetValueRequests>, ScopedAStatus> + deserializedResults = fromStableLargeParcelable(requests); + if (!deserializedResults.ok()) { + ALOGE("getValues: failed to parse getValues requests"); + return std::move(deserializedResults.error()); } + const std::vector<GetValueRequest>& getValueRequests = + deserializedResults.value().getObject()->payloads; std::shared_ptr<GetValuesClient> client; { @@ -153,7 +150,7 @@ ScopedAStatus DefaultVehicleHal::getValues(const CallbackType& callback, } if (StatusCode status = - mVehicleHardware->getValues(client->getResultCallback(), *getValueRequests); + mVehicleHardware->getValues(client->getResultCallback(), getValueRequests); status != StatusCode::OK) { return ScopedAStatus::fromServiceSpecificErrorWithMessage( toInt(status), "failed to get value from VehicleHardware"); @@ -166,27 +163,21 @@ ScopedAStatus DefaultVehicleHal::setValues(const CallbackType& callback, const SetValueRequests& requests) { // TODO(b/203713317): check for duplicate properties and duplicate request IDs. - const std::vector<SetValueRequest>* setValueRequests; - // Define deserializedResults here because we need it to have the same lifetime as - // setValueRequests. - expected<std::vector<SetValueRequest>, ScopedAStatus> deserializedResults; - if (!requests.payloads.empty()) { - setValueRequests = &requests.payloads; - } else { - deserializedResults = stableLargeParcelableToVector<SetValueRequest>(requests); - if (!deserializedResults.ok()) { - ALOGE("failed to parse setValues requests"); - return std::move(deserializedResults.error()); - } - setValueRequests = &deserializedResults.value(); + expected<LargeParcelableBase::BorrowedOwnedObject<SetValueRequests>, ScopedAStatus> + deserializedResults = fromStableLargeParcelable(requests); + if (!deserializedResults.ok()) { + ALOGE("setValues: failed to parse setValues requests"); + return std::move(deserializedResults.error()); } + const std::vector<SetValueRequest>& setValueRequests = + deserializedResults.value().getObject()->payloads; // A list of failed result we already know before sending to hardware. std::vector<SetValueResult> failedResults; // The list of requests that we would send to hardware. std::vector<SetValueRequest> hardwareRequests; - for (auto& request : *setValueRequests) { + for (auto& request : setValueRequests) { int64_t requestId = request.requestId; if (auto result = checkProperty(request.value); !result.ok()) { ALOGW("property not valid: %s", result.error().message().c_str()); diff --git a/automotive/vehicle/aidl/impl/vhal/src/PendingRequestPool.cpp b/automotive/vehicle/aidl/impl/vhal/src/PendingRequestPool.cpp new file mode 100644 index 0000000000..c2d6f89c2d --- /dev/null +++ b/automotive/vehicle/aidl/impl/vhal/src/PendingRequestPool.cpp @@ -0,0 +1,220 @@ +/* + * 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 "PendingRequestPool.h" + +#include <VehicleHalTypes.h> +#include <VehicleUtils.h> + +#include <utils/Log.h> +#include <utils/SystemClock.h> + +#include <vector> + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { + +namespace { + +using ::aidl::android::hardware::automotive::vehicle::StatusCode; +using ::android::base::Error; +using ::android::base::Result; + +// At least check every 1s. +constexpr int64_t CHECK_TIME_IN_NANO = 1000000000; + +} // namespace + +PendingRequestPool::PendingRequestPool(int64_t timeoutInNano) + : mTimeoutInNano(timeoutInNano), mThread([this] { + // [this] must be alive within this thread because destructor would wait for this thread + // to exit. + int64_t sleepTime = std::min(mTimeoutInNano, static_cast<int64_t>(CHECK_TIME_IN_NANO)); + std::unique_lock<std::mutex> lk(mCvLock); + while (!mCv.wait_for(lk, std::chrono::nanoseconds(sleepTime), + [this] { return mThreadStop.load(); })) { + checkTimeout(); + } + }) {} + +PendingRequestPool::~PendingRequestPool() { + mThreadStop = true; + mCv.notify_all(); + if (mThread.joinable()) { + mThread.join(); + } + + // If this pool is being destructed, send out all pending requests as timeout. + { + std::scoped_lock<std::mutex> lockGuard(mLock); + + for (auto& [_, pendingRequests] : mPendingRequestsByClient) { + for (const auto& request : pendingRequests) { + (*request.callback)(request.requestIds); + } + } + mPendingRequestsByClient.clear(); + } +} + +Result<void> PendingRequestPool::addRequests(const void* clientId, + const std::unordered_set<int64_t>& requestIds, + std::shared_ptr<TimeoutCallbackFunc> callback) { + std::scoped_lock<std::mutex> lockGuard(mLock); + std::list<PendingRequest>* pendingRequests; + size_t pendingRequestCount = 0; + if (mPendingRequestsByClient.find(clientId) != mPendingRequestsByClient.end()) { + pendingRequests = &mPendingRequestsByClient[clientId]; + for (const auto& pendingRequest : *pendingRequests) { + const auto& pendingRequestIds = pendingRequest.requestIds; + for (int64_t requestId : requestIds) { + if (pendingRequestIds.find(requestId) != pendingRequestIds.end()) { + return Error(toInt(StatusCode::INVALID_ARG)) + << "duplicate request ID: " << requestId; + } + } + pendingRequestCount += pendingRequestIds.size(); + } + } else { + // Create a new empty list for this client. + pendingRequests = &mPendingRequestsByClient[clientId]; + } + + if (requestIds.size() > MAX_PENDING_REQUEST_PER_CLIENT - pendingRequestCount) { + return Error(toInt(StatusCode::TRY_AGAIN)) << "too many pending requests"; + } + + int64_t currentTime = elapsedRealtimeNano(); + int64_t timeoutTimestamp = currentTime + mTimeoutInNano; + + pendingRequests->push_back({ + .requestIds = std::unordered_set<int64_t>(requestIds.begin(), requestIds.end()), + .timeoutTimestamp = timeoutTimestamp, + .callback = callback, + }); + + return {}; +} + +bool PendingRequestPool::isRequestPending(const void* clientId, int64_t requestId) const { + std::scoped_lock<std::mutex> lockGuard(mLock); + + return isRequestPendingLocked(clientId, requestId); +} + +size_t PendingRequestPool::countPendingRequests(const void* clientId) const { + std::scoped_lock<std::mutex> lockGuard(mLock); + + auto it = mPendingRequestsByClient.find(clientId); + if (it == mPendingRequestsByClient.end()) { + return 0; + } + + size_t count = 0; + for (const auto& pendingRequest : it->second) { + count += pendingRequest.requestIds.size(); + } + + return count; +} + +bool PendingRequestPool::isRequestPendingLocked(const void* clientId, int64_t requestId) const { + auto it = mPendingRequestsByClient.find(clientId); + if (it == mPendingRequestsByClient.end()) { + return false; + } + for (const auto& pendingRequest : it->second) { + const auto& requestIds = pendingRequest.requestIds; + if (requestIds.find(requestId) != requestIds.end()) { + return true; + } + } + return false; +} + +void PendingRequestPool::checkTimeout() { + std::vector<PendingRequest> timeoutRequests; + { + std::scoped_lock<std::mutex> lockGuard(mLock); + + int64_t currentTime = elapsedRealtimeNano(); + + std::vector<const void*> clientsWithEmptyRequests; + + for (auto& [clientId, pendingRequests] : mPendingRequestsByClient) { + auto it = pendingRequests.begin(); + while (it != pendingRequests.end()) { + if (it->timeoutTimestamp >= currentTime) { + break; + } + timeoutRequests.push_back(std::move(*it)); + it = pendingRequests.erase(it); + } + + if (pendingRequests.empty()) { + clientsWithEmptyRequests.push_back(clientId); + } + } + + for (const void* clientId : clientsWithEmptyRequests) { + mPendingRequestsByClient.erase(clientId); + } + } + + // Call the callback outside the lock. + for (const auto& request : timeoutRequests) { + (*request.callback)(request.requestIds); + } +} + +std::unordered_set<int64_t> PendingRequestPool::tryFinishRequests( + const void* clientId, const std::unordered_set<int64_t>& requestIds) { + std::scoped_lock<std::mutex> lockGuard(mLock); + + std::unordered_set<int64_t> foundIds; + + if (mPendingRequestsByClient.find(clientId) == mPendingRequestsByClient.end()) { + return foundIds; + } + + auto& pendingRequests = mPendingRequestsByClient[clientId]; + auto it = pendingRequests.begin(); + while (it != pendingRequests.end()) { + auto& pendingRequestIds = it->requestIds; + for (int64_t requestId : requestIds) { + auto idIt = pendingRequestIds.find(requestId); + if (idIt == pendingRequestIds.end()) { + continue; + } + pendingRequestIds.erase(idIt); + foundIds.insert(requestId); + } + if (pendingRequestIds.empty()) { + it = pendingRequests.erase(it); + continue; + } + it++; + } + + return foundIds; +} + +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android |