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

Commit 4299bb32 authored by Yu Shan's avatar Yu Shan
Browse files

Support subscribe/unsubscribe in VHAL.

Test: atest DefaultVehicleHalTest
Bug: 200737967

Change-Id: I4e7b31af7fa2af445f9bac6ec71dad3bf6c0b8b3
parent 07c256aa
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -67,24 +67,30 @@ inline constexpr bool isSystemProp(int32_t prop) {
}

inline const ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig* getAreaConfig(
        const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue,
        int32_t propId, int32_t areaId,
        const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig& config) {
    if (config.areaConfigs.size() == 0) {
        return nullptr;
    }

    if (isGlobalProp(propValue.prop)) {
    if (isGlobalProp(propId)) {
        return &(config.areaConfigs[0]);
    }

    for (const auto& c : config.areaConfigs) {
        if (c.areaId == propValue.areaId) {
        if (c.areaId == areaId) {
            return &c;
        }
    }
    return nullptr;
}

inline const ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig* getAreaConfig(
        const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue,
        const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig& config) {
    return getAreaConfig(propValue.prop, propValue.areaId, config);
}

inline std::unique_ptr<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>
createVehiclePropValueVec(::aidl::android::hardware::automotive::vehicle::VehiclePropertyType type,
                          size_t vecSize) {
+5 −2
Original line number Diff line number Diff line
@@ -21,9 +21,11 @@

#include <VehicleHalTypes.h>
#include <VehicleUtils.h>
#include <android-base/format.h>
#include <android-base/stringprintf.h>
#include <math/HashCombine.h>

#include <inttypes.h>

namespace android {
namespace hardware {
namespace automotive {
@@ -36,13 +38,14 @@ using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
using ::android::base::Error;
using ::android::base::Result;
using ::android::base::StringPrintf;

bool VehiclePropertyStore::RecordId::operator==(const VehiclePropertyStore::RecordId& other) const {
    return area == other.area && token == other.token;
}

std::string VehiclePropertyStore::RecordId::toString() const {
    return ::fmt::format("RecordID{{.areaId={:d}, .token={:d}}}", area, token);
    return StringPrintf("RecordID{{.areaId=% " PRId32 ", .token=%" PRId64 "}", area, token);
}

size_t VehiclePropertyStore::RecordIdHash::operator()(RecordId const& recordId) const {
+14 −8
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@

#include "PendingRequestPool.h"

#include <IVehicleHardware.h>
#include <VehicleHalTypes.h>

#include <aidl/android/hardware/automotive/vehicle/IVehicleCallback.h>
@@ -51,14 +52,14 @@ class ConnectedClient {
    // Gets the unique ID for this client.
    const void* id();

    // Add client requests. The requests would be registered as pending requests until
    // Adds 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
    // Marks 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);

@@ -110,9 +111,15 @@ class SubscriptionClient final : public ConnectedClient {
                    callback);

    // Gets the callback to be called when the request for this client has finished.
    std::shared_ptr<const std::function<
            void(std::vector<::aidl::android::hardware::automotive::vehicle::GetValueResult>)>>
    getResultCallback();
    std::shared_ptr<const IVehicleHardware::GetValuesCallback> getResultCallback();

    // Marshals the updated values into largeParcelable and sents it through {@code onPropertyEvent}
    // callback.
    static void sendUpdatedValues(
            std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>
                    callback,
            std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
                    updatedValues);

  protected:
    // Gets the callback to be called when the request for this client has timeout.
@@ -121,9 +128,8 @@ class SubscriptionClient final : public ConnectedClient {
  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<::aidl::android::hardware::automotive::vehicle::GetValueResult>)>>
            mResultCallback;
    std::shared_ptr<const IVehicleHardware::GetValuesCallback> mResultCallback;
    std::shared_ptr<const IVehicleHardware::PropertyChangeCallback> mPropertyChangeCallback;

    static void onGetValueResults(
            const void* clientId,
+52 −14
Original line number Diff line number Diff line
@@ -53,7 +53,7 @@ class DefaultVehicleHal final : public ::aidl::android::hardware::automotive::ve

    explicit DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware);

    ~DefaultVehicleHal();
    ~DefaultVehicleHal() = default;

    ::ndk::ScopedAStatus getAllPropConfigs(
            ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs* returnConfigs)
@@ -93,11 +93,40 @@ class DefaultVehicleHal final : public ::aidl::android::hardware::automotive::ve
            GetSetValuesClient<::aidl::android::hardware::automotive::vehicle::SetValueResult,
                               ::aidl::android::hardware::automotive::vehicle::SetValueResults>;

    // A thread safe class to maintain an increasing request ID for each subscribe client. This
    // class is safe to pass to async callbacks.
    class SubscribeIdByClient {
      public:
        int64_t getId(const CallbackType& callback);

      private:
        std::mutex mLock;
        std::unordered_map<CallbackType, int64_t> mIds GUARDED_BY(mLock);
    };

    // A thread safe class to store all subscribe clients. This class is safe to pass to async
    // callbacks.
    class SubscriptionClients {
      public:
        SubscriptionClients(std::shared_ptr<PendingRequestPool> pool) : mPendingRequestPool(pool) {}

        std::shared_ptr<SubscriptionClient> getClient(const CallbackType& callback);

        size_t countClients();

      private:
        std::mutex mLock;
        std::unordered_map<CallbackType, std::shared_ptr<SubscriptionClient>> mClients
                GUARDED_BY(mLock);
        // PendingRequestPool is thread-safe.
        std::shared_ptr<PendingRequestPool> mPendingRequestPool;
    };

    // The default timeout of get or set value requests is 30s.
    // TODO(b/214605968): define TIMEOUT_IN_NANO in IVehicle and allow getValues/setValues/subscribe
    // to specify custom timeouts.
    static constexpr int64_t TIMEOUT_IN_NANO = 30'000'000'000;
    const std::unique_ptr<IVehicleHardware> mVehicleHardware;
    const std::shared_ptr<IVehicleHardware> mVehicleHardware;

    // mConfigsByPropId and mConfigFile are only modified during initialization, so no need to
    // lock guard them.
@@ -108,22 +137,15 @@ class DefaultVehicleHal final : public ::aidl::android::hardware::automotive::ve
    // PendingRequestPool is thread-safe.
    std::shared_ptr<PendingRequestPool> mPendingRequestPool;
    // SubscriptionManager is thread-safe.
    std::unique_ptr<SubscriptionManager> mSubscriptionManager;
    std::shared_ptr<SubscriptionManager> mSubscriptionManager;

    std::mutex mLock;
    std::unordered_map<CallbackType, std::shared_ptr<GetValuesClient>> mGetValuesClients
            GUARDED_BY(mLock);
    std::unordered_map<CallbackType, std::shared_ptr<SetValuesClient>> mSetValuesClients
            GUARDED_BY(mLock);
    std::unordered_map<CallbackType, std::shared_ptr<SubscriptionClient>> mSubscriptionClients
            GUARDED_BY(mLock);
    // An increasing request ID we keep for subscribe clients.
    std::unordered_map<CallbackType, int64_t> mSubscribeIdByClient GUARDED_BY(mLock);

    template <class T>
    std::shared_ptr<T> getOrCreateClient(
            std::unordered_map<CallbackType, std::shared_ptr<T>>* clients,
            const CallbackType& callback) REQUIRES(mLock);
    // SubscriptionClients is thread-safe.
    std::shared_ptr<SubscriptionClients> mSubscriptionClients;

    ::android::base::Result<void> checkProperty(
            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue);
@@ -136,10 +158,26 @@ class DefaultVehicleHal final : public ::aidl::android::hardware::automotive::ve
            const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>&
                    requests);

    void getValueFromHardwareCallCallback(
            const CallbackType& callback,
    ::android::base::Result<void> checkSubscribeOptions(
            const std::vector<::aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
                    options);

    template <class T>
    static std::shared_ptr<T> getOrCreateClient(
            std::unordered_map<CallbackType, std::shared_ptr<T>>* clients,
            const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);

    static void getValueFromHardwareCallCallback(
            std::weak_ptr<IVehicleHardware> vehicleHardware,
            std::shared_ptr<SubscribeIdByClient> subscribeIdByClient,
            std::shared_ptr<SubscriptionClients> subscriptionClients, const CallbackType& callback,
            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);

    static void onPropertyChangeEvent(
            std::weak_ptr<SubscriptionManager> subscriptionManager,
            const std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
                    updatedValues);

    // Test-only
    // Set the default timeout for pending requests.
    void setTimeout(int64_t timeoutInNano);
+28 −22
Original line number Diff line number Diff line
@@ -258,7 +258,7 @@ SubscriptionClient::SubscriptionClient(std::shared_ptr<PendingRequestPool> reque
            });
    auto requestPoolCopy = mRequestPool;
    const void* clientId = reinterpret_cast<const void*>(this);
    mResultCallback = std::make_shared<const std::function<void(std::vector<GetValueResult>)>>(
    mResultCallback = std::make_shared<const IVehicleHardware::GetValuesCallback>(
            [clientId, callback, requestPoolCopy](std::vector<GetValueResult> results) {
                onGetValueResults(clientId, callback, requestPoolCopy, results);
            });
@@ -274,6 +274,32 @@ SubscriptionClient::getTimeoutCallback() {
    return mTimeoutCallback;
}

void SubscriptionClient::sendUpdatedValues(std::shared_ptr<IVehicleCallback> callback,
                                           std::vector<VehiclePropValue>&& updatedValues) {
    if (updatedValues.empty()) {
        return;
    }

    // TODO(b/205189110): Use memory pool here and fill in sharedMemoryId.
    VehiclePropValues vehiclePropValues;
    int32_t sharedMemoryFileCount = 0;
    ScopedAStatus status = vectorToStableLargeParcelable(updatedValues, &vehiclePropValues);
    if (!status.isOk()) {
        int statusCode = status.getServiceSpecificError();
        ALOGE("subscribe: failed to marshal result into large parcelable, error: "
              "%s, code: %d",
              status.getMessage(), statusCode);
        return;
    }

    if (ScopedAStatus callbackStatus =
                callback->onPropertyEvent(vehiclePropValues, sharedMemoryFileCount);
        !callbackStatus.isOk()) {
        ALOGE("subscribe: failed to call callback, error: %s, code: %d", status.getMessage(),
              status.getServiceSpecificError());
    }
}

void SubscriptionClient::onGetValueResults(const void* clientId,
                                           std::shared_ptr<IVehicleCallback> callback,
                                           std::shared_ptr<PendingRequestPool> requestPool,
@@ -308,27 +334,7 @@ void SubscriptionClient::onGetValueResults(const void* clientId,
        propValues.push_back(std::move(result.prop.value()));
    }

    if (propValues.empty()) {
        return;
    }
    // TODO(b/205189110): Use memory pool here and fill in sharedMemoryId.
    VehiclePropValues vehiclePropValues;
    int32_t sharedMemoryFileCount = 0;
    ScopedAStatus status = vectorToStableLargeParcelable(propValues, &vehiclePropValues);
    if (!status.isOk()) {
        int statusCode = status.getServiceSpecificError();
        ALOGE("failed to marshal result into large parcelable, error: "
              "%s, code: %d",
              status.getMessage(), statusCode);
        return;
    }

    if (ScopedAStatus callbackStatus =
                callback->onPropertyEvent(vehiclePropValues, sharedMemoryFileCount);
        !callbackStatus.isOk()) {
        ALOGE("failed to call callback, error: %s, code: %d", status.getMessage(),
              status.getServiceSpecificError());
    }
    sendUpdatedValues(callback, std::move(propValues));
}

}  // namespace vehicle
Loading