Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c2d60356 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Manage pending requests in default VHAL."

parents 87ee1941 c2308603
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -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>
@@ -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;
};
@@ -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);

@@ -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;
};

+16 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@

#include "ConnectedClient.h"
#include "ParcelableUtils.h"
#include "PendingRequestPool.h"

#include <IVehicleHardware.h>
#include <VehicleUtils.h>
@@ -28,6 +29,7 @@
#include <android/binder_auto_utils.h>

#include <memory>
#include <mutex>
#include <unordered_map>
#include <vector>

@@ -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
@@ -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
+4 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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.
@@ -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;
+96 −6
Original line number Diff line number Diff line
@@ -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);
@@ -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);
            });
}

@@ -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) {
+82 −7
Original line number Diff line number Diff line
@@ -25,6 +25,9 @@
#include <android-base/result.h>
#include <utils/Log.h>

#include <set>
#include <unordered_set>

namespace android {
namespace hardware {
namespace automotive {
@@ -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;
@@ -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();
@@ -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];
}
@@ -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()) {
@@ -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()) {
@@ -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()) {
@@ -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");
    }
@@ -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