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

Commit 6f543488 authored by Yu Shan's avatar Yu Shan
Browse files

Improve reference VHAL library.

Fix multiple issues pointed out in code comments.

Test: atest DefaultVehicleHalTest
Bug: 238350087
Change-Id: I1865e24cc9ea992c9f13174e798b79843adeffb5
parent 7fc81c5c
Loading
Loading
Loading
Loading
+9 −9
Original line number Diff line number Diff line
@@ -123,10 +123,10 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi
        std::shared_ptr<PendingRequestPool> mPendingRequestPool;
    };

    // A wrapper for binder operations to enable stubbing for test.
    class IBinder {
    // A wrapper for binder lifecycle operations to enable stubbing for test.
    class BinderLifecycleInterface {
      public:
        virtual ~IBinder() = default;
        virtual ~BinderLifecycleInterface() = default;

        virtual binder_status_t linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
                                            void* cookie) = 0;
@@ -134,8 +134,8 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi
        virtual bool isAlive(const AIBinder* binder) = 0;
    };

    // A real implementation for IBinder.
    class AIBinderImpl final : public IBinder {
    // A real implementation for BinderLifecycleInterface.
    class BinderLifecycleHandler final : public BinderLifecycleInterface {
      public:
        binder_status_t linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
                                    void* cookie) override;
@@ -154,7 +154,7 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi
    // BinderDiedUnlinkedEvent represents either an onBinderDied or an onBinderUnlinked event.
    struct BinderDiedUnlinkedEvent {
        // true for onBinderDied, false for onBinderUnlinked.
        bool onBinderDied;
        bool forOnBinderDied;
        const AIBinder* clientId;
    };

@@ -186,8 +186,8 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi
            GUARDED_BY(mLock);
    // SubscriptionClients is thread-safe.
    std::shared_ptr<SubscriptionClients> mSubscriptionClients;
    // mBinderImpl is only going to be changed in test.
    std::unique_ptr<IBinder> mBinderImpl;
    // mBinderLifecycleHandler is only going to be changed in test.
    std::unique_ptr<BinderLifecycleInterface> mBinderLifecycleHandler;

    // Only initialized once.
    std::shared_ptr<std::function<void()>> mRecurrentAction;
@@ -263,7 +263,7 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi
    void setTimeout(int64_t timeoutInNano);

    // Test-only
    void setBinderImpl(std::unique_ptr<IBinder> impl);
    void setBinderLifecycleHandler(std::unique_ptr<BinderLifecycleInterface> impl);
};

}  // namespace vehicle
+16 −17
Original line number Diff line number Diff line
@@ -41,15 +41,15 @@ class ContSubConfigs final {
  public:
    using ClientIdType = const AIBinder*;

    void addClient(const ClientIdType& clientId, float sampleRate);
    void addClient(const ClientIdType& clientId, float sampleRateHz);
    void removeClient(const ClientIdType& clientId);
    float getMaxSampleRate();
    float getMaxSampleRateHz() const;

  private:
    float mMaxSampleRate = 0.;
    std::unordered_map<ClientIdType, float> mSampleRates;
    float mMaxSampleRateHz = 0.;
    std::unordered_map<ClientIdType, float> mSampleRateHzByClient;

    void refreshMaxSampleRate();
    void refreshMaxSampleRateHz();
};

// A thread-safe subscription manager that manages all VHAL subscriptions.
@@ -59,7 +59,7 @@ class SubscriptionManager final {
    using CallbackType =
            std::shared_ptr<aidl::android::hardware::automotive::vehicle::IVehicleCallback>;

    explicit SubscriptionManager(IVehicleHardware* hardware);
    explicit SubscriptionManager(IVehicleHardware* vehicleHardware);
    ~SubscriptionManager();

    // Subscribes to properties according to {@code SubscribeOptions}. Note that all option must
@@ -99,13 +99,8 @@ class SubscriptionManager final {
            const std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
                    updatedValues);

    // Gets the sample rate for the continuous property. Returns {@code std::nullopt} if the
    // property has not been subscribed before or is not a continuous property.
    std::optional<float> getSampleRate(const ClientIdType& clientId, int32_t propId,
                                       int32_t areaId);

    // Checks whether the sample rate is valid.
    static bool checkSampleRate(float sampleRate);
    static bool checkSampleRateHz(float sampleRateHz);

  private:
    // Friend class for testing.
@@ -122,17 +117,21 @@ class SubscriptionManager final {
    std::unordered_map<PropIdAreaId, ContSubConfigs, PropIdAreaIdHash> mContSubConfigsByPropIdArea
            GUARDED_BY(mLock);

    VhalResult<void> updateSampleRateLocked(const ClientIdType& clientId,
                                            const PropIdAreaId& propIdAreaId, float sampleRate)
    VhalResult<void> addContinuousSubscriberLocked(const ClientIdType& clientId,
                                                   const PropIdAreaId& propIdAreaId,
                                                   float sampleRateHz) REQUIRES(mLock);
    VhalResult<void> removeContinuousSubscriberLocked(const ClientIdType& clientId,
                                                      const PropIdAreaId& propIdAreaId)
            REQUIRES(mLock);
    VhalResult<void> removeSampleRateLocked(const ClientIdType& clientId,
                                            const PropIdAreaId& propIdAreaId) REQUIRES(mLock);

    VhalResult<void> updateContSubConfigs(const PropIdAreaId& PropIdAreaId,
                                          const ContSubConfigs& newConfig) REQUIRES(mLock);

    // Checks whether the manager is empty. For testing purpose.
    bool isEmpty();

    // Get the interval in nanoseconds accroding to sample rate.
    static android::base::Result<int64_t> getInterval(float sampleRate);
    static android::base::Result<int64_t> getIntervalNanos(float sampleRateHz);
};

}  // namespace vehicle
+51 −48
Original line number Diff line number Diff line
@@ -78,14 +78,14 @@ std::string toString(const std::unordered_set<int64_t>& values) {
    return str;
}

float getDefaultSampleRate(float sampleRate, float minSampleRate, float maxSampleRate) {
    if (sampleRate < minSampleRate) {
        return minSampleRate;
float getDefaultSampleRateHz(float sampleRateHz, float minSampleRateHz, float maxSampleRateHz) {
    if (sampleRateHz < minSampleRateHz) {
        return minSampleRateHz;
    }
    if (sampleRate > maxSampleRate) {
        return maxSampleRate;
    if (sampleRateHz > maxSampleRateHz) {
        return maxSampleRateHz;
    }
    return sampleRate;
    return sampleRateHz;
}

}  // namespace
@@ -123,8 +123,8 @@ size_t DefaultVehicleHal::SubscriptionClients::countClients() {
    return mClients.size();
}

DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware)
    : mVehicleHardware(std::move(hardware)),
DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> vehicleHardware)
    : mVehicleHardware(std::move(vehicleHardware)),
      mPendingRequestPool(std::make_shared<PendingRequestPool>(TIMEOUT_IN_NANO)) {
    auto configs = mVehicleHardware->getAllPropertyConfigs();
    for (auto& config : configs) {
@@ -143,12 +143,11 @@ DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware)
        mConfigFile = std::move(result.value());
    }

    mSubscriptionClients = std::make_shared<SubscriptionClients>(mPendingRequestPool);
    mSubscriptionClients = std::make_shared<SubscriptionClients>(mPendingRequestPool);

    auto subscribeIdByClient = std::make_shared<SubscribeIdByClient>();
    IVehicleHardware* hardwarePtr = mVehicleHardware.get();
    mSubscriptionManager = std::make_shared<SubscriptionManager>(hardwarePtr);
    IVehicleHardware* vehicleHardwarePtr = mVehicleHardware.get();
    mSubscriptionManager = std::make_shared<SubscriptionManager>(vehicleHardwarePtr);

    std::weak_ptr<SubscriptionManager> subscriptionManagerCopy = mSubscriptionManager;
    mVehicleHardware->registerOnPropertyChangeEvent(
@@ -158,13 +157,13 @@ DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware)
                    }));

    // Register heartbeat event.
    mRecurrentAction =
            std::make_shared<std::function<void()>>([hardwarePtr, subscriptionManagerCopy]() {
                checkHealth(hardwarePtr, subscriptionManagerCopy);
    mRecurrentAction = std::make_shared<std::function<void()>>(
            [vehicleHardwarePtr, subscriptionManagerCopy]() {
                checkHealth(vehicleHardwarePtr, subscriptionManagerCopy);
            });
    mRecurrentTimer.registerTimerCallback(HEART_BEAT_INTERVAL_IN_NANO, mRecurrentAction);

    mBinderImpl = std::make_unique<AIBinderImpl>();
    mBinderLifecycleHandler = std::make_unique<BinderLifecycleHandler>();
    mOnBinderDiedUnlinkedHandlerThread = std::thread([this] { onBinderDiedUnlinkedHandler(); });
    mDeathRecipient = ScopedAIBinder_DeathRecipient(
            AIBinder_DeathRecipient_new(&DefaultVehicleHal::onBinderDied));
@@ -220,7 +219,7 @@ std::shared_ptr<T> DefaultVehicleHal::getOrCreateClient(
bool DefaultVehicleHal::monitorBinderLifeCycleLocked(const AIBinder* clientId) {
    OnBinderDiedContext* contextPtr = nullptr;
    if (mOnBinderDiedContexts.find(clientId) != mOnBinderDiedContexts.end()) {
        return mBinderImpl->isAlive(clientId);
        return mBinderLifecycleHandler->isAlive(clientId);
    } else {
        std::unique_ptr<OnBinderDiedContext> context = std::make_unique<OnBinderDiedContext>(
                OnBinderDiedContext{.vhal = this, .clientId = clientId});
@@ -232,7 +231,7 @@ bool DefaultVehicleHal::monitorBinderLifeCycleLocked(const AIBinder* clientId) {
    }

    // If this function fails, onBinderUnlinked would be called to remove the added context.
    binder_status_t status = mBinderImpl->linkToDeath(
    binder_status_t status = mBinderLifecycleHandler->linkToDeath(
            const_cast<AIBinder*>(clientId), mDeathRecipient.get(), static_cast<void*>(contextPtr));
    if (status == STATUS_OK) {
        return true;
@@ -246,7 +245,8 @@ void DefaultVehicleHal::onBinderDied(void* cookie) {
    OnBinderDiedContext* context = reinterpret_cast<OnBinderDiedContext*>(cookie);
    // To be handled in mOnBinderDiedUnlinkedHandlerThread. We cannot handle the event in the same
    // thread because we might be holding the mLock the handler requires.
    context->vhal->mBinderEvents.push(BinderDiedUnlinkedEvent{true, context->clientId});
    context->vhal->mBinderEvents.push(
            BinderDiedUnlinkedEvent{/*forOnBinderDied=*/true, context->clientId});
}

void DefaultVehicleHal::onBinderDiedWithContext(const AIBinder* clientId) {
@@ -262,7 +262,8 @@ void DefaultVehicleHal::onBinderUnlinked(void* cookie) {
    OnBinderDiedContext* context = reinterpret_cast<OnBinderDiedContext*>(cookie);
    // To be handled in mOnBinderDiedUnlinkedHandlerThread. We cannot handle the event in the same
    // thread because we might be holding the mLock the handler requires.
    context->vhal->mBinderEvents.push(BinderDiedUnlinkedEvent{false, context->clientId});
    context->vhal->mBinderEvents.push(
            BinderDiedUnlinkedEvent{/*forOnBinderDied=*/false, context->clientId});
}

void DefaultVehicleHal::onBinderUnlinkedWithContext(const AIBinder* clientId) {
@@ -275,7 +276,7 @@ void DefaultVehicleHal::onBinderUnlinkedWithContext(const AIBinder* clientId) {
void DefaultVehicleHal::onBinderDiedUnlinkedHandler() {
    while (mBinderEvents.waitForItems()) {
        for (BinderDiedUnlinkedEvent& event : mBinderEvents.flush()) {
            if (event.onBinderDied) {
            if (event.forOnBinderDied) {
                onBinderDiedWithContext(event.clientId);
            } else {
                onBinderUnlinkedWithContext(event.clientId);
@@ -349,15 +350,15 @@ Result<void> DefaultVehicleHal::checkProperty(const VehiclePropValue& propValue)

ScopedAStatus DefaultVehicleHal::getValues(const CallbackType& callback,
                                           const GetValueRequests& requests) {
    if (callback == nullptr) {
        return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
    }
    expected<LargeParcelableBase::BorrowedOwnedObject<GetValueRequests>, ScopedAStatus>
            deserializedResults = fromStableLargeParcelable(requests);
    if (!deserializedResults.ok()) {
        ALOGE("getValues: failed to parse getValues requests");
        return std::move(deserializedResults.error());
    }
    if (callback == nullptr) {
        return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
    }
    const std::vector<GetValueRequest>& getValueRequests =
            deserializedResults.value().getObject()->payloads;

@@ -435,15 +436,15 @@ ScopedAStatus DefaultVehicleHal::getValues(const CallbackType& callback,

ScopedAStatus DefaultVehicleHal::setValues(const CallbackType& callback,
                                           const SetValueRequests& requests) {
    if (callback == nullptr) {
        return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
    }
    expected<LargeParcelableBase::BorrowedOwnedObject<SetValueRequests>, ScopedAStatus>
            deserializedResults = fromStableLargeParcelable(requests);
    if (!deserializedResults.ok()) {
        ALOGE("setValues: failed to parse setValues requests");
        return std::move(deserializedResults.error());
    }
    if (callback == nullptr) {
        return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
    }
    const std::vector<SetValueRequest>& setValueRequests =
            deserializedResults.value().getObject()->payloads;

@@ -595,18 +596,20 @@ VhalResult<void> DefaultVehicleHal::checkSubscribeOptions(
        }

        if (config.changeMode == VehiclePropertyChangeMode::CONTINUOUS) {
            float sampleRate = option.sampleRate;
            float minSampleRate = config.minSampleRate;
            float maxSampleRate = config.maxSampleRate;
            if (sampleRate < minSampleRate || sampleRate > maxSampleRate) {
                float defaultRate = getDefaultSampleRate(sampleRate, minSampleRate, maxSampleRate);
                ALOGW("sample rate: %f out of range, must be within %f and %f, set to %f",
                      sampleRate, minSampleRate, maxSampleRate, defaultRate);
                sampleRate = defaultRate;
            }
            if (!SubscriptionManager::checkSampleRate(sampleRate)) {
            float sampleRateHz = option.sampleRate;
            float minSampleRateHz = config.minSampleRate;
            float maxSampleRateHz = config.maxSampleRate;
            float defaultRateHz =
                    getDefaultSampleRateHz(sampleRateHz, minSampleRateHz, maxSampleRateHz);
            if (sampleRateHz != defaultRateHz) {
                ALOGW("sample rate: %f HZ out of range, must be within %f HZ and %f HZ , set to %f "
                      "HZ",
                      sampleRateHz, minSampleRateHz, maxSampleRateHz, defaultRateHz);
                sampleRateHz = defaultRateHz;
            }
            if (!SubscriptionManager::checkSampleRateHz(sampleRateHz)) {
                return StatusError(StatusCode::INVALID_ARG)
                       << "invalid sample rate: " << sampleRate;
                       << "invalid sample rate: " << sampleRateHz << " HZ";
            }
        }

@@ -631,13 +634,13 @@ ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType& callback,
                                           const std::vector<SubscribeOptions>& options,
                                           [[maybe_unused]] int32_t maxSharedMemoryFileCount) {
    // TODO(b/205189110): Use shared memory file count.
    if (callback == nullptr) {
        return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
    }
    if (auto result = checkSubscribeOptions(options); !result.ok()) {
        ALOGE("subscribe: invalid subscribe options: %s", getErrorMsg(result).c_str());
        return toScopedAStatus(result);
    }
    if (callback == nullptr) {
        return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
    }
    std::vector<SubscribeOptions> onChangeSubscriptions;
    std::vector<SubscribeOptions> continuousSubscriptions;
    for (const auto& option : options) {
@@ -658,7 +661,7 @@ ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType& callback,
        }

        if (config.changeMode == VehiclePropertyChangeMode::CONTINUOUS) {
            optionCopy.sampleRate = getDefaultSampleRate(
            optionCopy.sampleRate = getDefaultSampleRateHz(
                    optionCopy.sampleRate, config.minSampleRate, config.maxSampleRate);
            continuousSubscriptions.push_back(std::move(optionCopy));
        } else {
@@ -740,9 +743,9 @@ VhalResult<void> DefaultVehicleHal::checkReadPermission(const VehiclePropValue&
    return {};
}

void DefaultVehicleHal::checkHealth(IVehicleHardware* hardware,
void DefaultVehicleHal::checkHealth(IVehicleHardware* vehicleHardware,
                                    std::weak_ptr<SubscriptionManager> subscriptionManager) {
    StatusCode status = hardware->checkHealth();
    StatusCode status = vehicleHardware->checkHealth();
    if (status != StatusCode::OK) {
        ALOGE("VHAL check health returns non-okay status");
        return;
@@ -757,18 +760,18 @@ void DefaultVehicleHal::checkHealth(IVehicleHardware* hardware,
    return;
}

binder_status_t DefaultVehicleHal::AIBinderImpl::linkToDeath(AIBinder* binder,
                                                             AIBinder_DeathRecipient* recipient,
                                                             void* cookie) {
binder_status_t DefaultVehicleHal::BinderLifecycleHandler::linkToDeath(
        AIBinder* binder, AIBinder_DeathRecipient* recipient, void* cookie) {
    return AIBinder_linkToDeath(binder, recipient, cookie);
}

bool DefaultVehicleHal::AIBinderImpl::isAlive(const AIBinder* binder) {
bool DefaultVehicleHal::BinderLifecycleHandler::isAlive(const AIBinder* binder) {
    return AIBinder_isAlive(binder);
}

void DefaultVehicleHal::setBinderImpl(std::unique_ptr<IBinder> impl) {
    mBinderImpl = std::move(impl);
void DefaultVehicleHal::setBinderLifecycleHandler(
        std::unique_ptr<BinderLifecycleInterface> handler) {
    mBinderLifecycleHandler = std::move(handler);
}

bool DefaultVehicleHal::checkDumpPermission() {
+53 −65
Original line number Diff line number Diff line
@@ -42,7 +42,8 @@ using ::android::base::Result;
using ::android::base::StringPrintf;
using ::ndk::ScopedAStatus;

SubscriptionManager::SubscriptionManager(IVehicleHardware* hardware) : mVehicleHardware(hardware) {}
SubscriptionManager::SubscriptionManager(IVehicleHardware* vehicleHardware)
    : mVehicleHardware(vehicleHardware) {}

SubscriptionManager::~SubscriptionManager() {
    std::scoped_lock<std::mutex> lockGuard(mLock);
@@ -51,94 +52,82 @@ SubscriptionManager::~SubscriptionManager() {
    mSubscribedPropsByClient.clear();
}

bool SubscriptionManager::checkSampleRate(float sampleRate) {
    return getInterval(sampleRate).ok();
bool SubscriptionManager::checkSampleRateHz(float sampleRateHz) {
    return getIntervalNanos(sampleRateHz).ok();
}

Result<int64_t> SubscriptionManager::getInterval(float sampleRate) {
    int64_t interval = 0;
    if (sampleRate <= 0) {
Result<int64_t> SubscriptionManager::getIntervalNanos(float sampleRateHz) {
    int64_t intervalNanos = 0;
    if (sampleRateHz <= 0) {
        return Error() << "invalid sample rate, must be a positive number";
    }
    if (sampleRate <= (ONE_SECOND_IN_NANO / static_cast<float>(INT64_MAX))) {
        return Error() << "invalid sample rate: " << sampleRate << ", too small";
    if (sampleRateHz <= (ONE_SECOND_IN_NANO / static_cast<float>(INT64_MAX))) {
        return Error() << "invalid sample rate: " << sampleRateHz << ", too small";
    }
    interval = static_cast<int64_t>(ONE_SECOND_IN_NANO / sampleRate);
    return interval;
    intervalNanos = static_cast<int64_t>(ONE_SECOND_IN_NANO / sampleRateHz);
    return intervalNanos;
}

void ContSubConfigs::refreshMaxSampleRate() {
    float maxSampleRate = 0.;
void ContSubConfigs::refreshMaxSampleRateHz() {
    float maxSampleRateHz = 0.;
    // This is not called frequently so a brute-focre is okay. More efficient way exists but this
    // is simpler.
    for (const auto& [_, sampleRate] : mSampleRates) {
        if (sampleRate > maxSampleRate) {
            maxSampleRate = sampleRate;
    for (const auto& [_, sampleRateHz] : mSampleRateHzByClient) {
        if (sampleRateHz > maxSampleRateHz) {
            maxSampleRateHz = sampleRateHz;
        }
    }
    mMaxSampleRate = maxSampleRate;
    mMaxSampleRateHz = maxSampleRateHz;
}

void ContSubConfigs::addClient(const ClientIdType& clientId, float sampleRate) {
    mSampleRates[clientId] = sampleRate;
    refreshMaxSampleRate();
void ContSubConfigs::addClient(const ClientIdType& clientId, float sampleRateHz) {
    mSampleRateHzByClient[clientId] = sampleRateHz;
    refreshMaxSampleRateHz();
}

void ContSubConfigs::removeClient(const ClientIdType& clientId) {
    mSampleRates.erase(clientId);
    refreshMaxSampleRate();
    mSampleRateHzByClient.erase(clientId);
    refreshMaxSampleRateHz();
}

float ContSubConfigs::getMaxSampleRate() {
    return mMaxSampleRate;
float ContSubConfigs::getMaxSampleRateHz() const {
    return mMaxSampleRateHz;
}

VhalResult<void> SubscriptionManager::updateSampleRateLocked(const ClientIdType& clientId,
                                                             const PropIdAreaId& propIdAreaId,
                                                             float sampleRate) {
VhalResult<void> SubscriptionManager::addContinuousSubscriberLocked(
        const ClientIdType& clientId, const PropIdAreaId& propIdAreaId, float sampleRateHz) {
    // Make a copy so that we don't modify 'mContSubConfigsByPropIdArea' on failure cases.
    ContSubConfigs infoCopy = mContSubConfigsByPropIdArea[propIdAreaId];
    infoCopy.addClient(clientId, sampleRate);
    if (infoCopy.getMaxSampleRate() ==
        mContSubConfigsByPropIdArea[propIdAreaId].getMaxSampleRate()) {
        mContSubConfigsByPropIdArea[propIdAreaId] = infoCopy;
        return {};
    }
    float newRate = infoCopy.getMaxSampleRate();
    int32_t propId = propIdAreaId.propId;
    int32_t areaId = propIdAreaId.areaId;
    if (auto status = mVehicleHardware->updateSampleRate(propId, areaId, newRate);
        status != StatusCode::OK) {
        return StatusError(status) << StringPrintf("failed to update sample rate for prop: %" PRId32
                                                   ", area"
                                                   ": %" PRId32 ", sample rate: %f",
                                                   propId, areaId, newRate);
    }
    mContSubConfigsByPropIdArea[propIdAreaId] = infoCopy;
    return {};
    ContSubConfigs newConfig = mContSubConfigsByPropIdArea[propIdAreaId];
    newConfig.addClient(clientId, sampleRateHz);
    return updateContSubConfigs(propIdAreaId, newConfig);
}

VhalResult<void> SubscriptionManager::removeSampleRateLocked(const ClientIdType& clientId,
                                                             const PropIdAreaId& propIdAreaId) {
VhalResult<void> SubscriptionManager::removeContinuousSubscriberLocked(
        const ClientIdType& clientId, const PropIdAreaId& propIdAreaId) {
    // Make a copy so that we don't modify 'mContSubConfigsByPropIdArea' on failure cases.
    ContSubConfigs infoCopy = mContSubConfigsByPropIdArea[propIdAreaId];
    infoCopy.removeClient(clientId);
    if (infoCopy.getMaxSampleRate() ==
        mContSubConfigsByPropIdArea[propIdAreaId].getMaxSampleRate()) {
        mContSubConfigsByPropIdArea[propIdAreaId] = infoCopy;
    ContSubConfigs newConfig = mContSubConfigsByPropIdArea[propIdAreaId];
    newConfig.removeClient(clientId);
    return updateContSubConfigs(propIdAreaId, newConfig);
}

VhalResult<void> SubscriptionManager::updateContSubConfigs(const PropIdAreaId& propIdAreaId,
                                                           const ContSubConfigs& newConfig) {
    if (newConfig.getMaxSampleRateHz() ==
        mContSubConfigsByPropIdArea[propIdAreaId].getMaxSampleRateHz()) {
        mContSubConfigsByPropIdArea[propIdAreaId] = newConfig;
        return {};
    }
    float newRate = infoCopy.getMaxSampleRate();
    float newRateHz = newConfig.getMaxSampleRateHz();
    int32_t propId = propIdAreaId.propId;
    int32_t areaId = propIdAreaId.areaId;
    if (auto status = mVehicleHardware->updateSampleRate(propId, areaId, newRate);
    if (auto status = mVehicleHardware->updateSampleRate(propId, areaId, newRateHz);
        status != StatusCode::OK) {
        return StatusError(status) << StringPrintf("failed to update sample rate for prop: %" PRId32
                                                   ", area"
                                                   ": %" PRId32 ", sample rate: %f",
                                                   propId, areaId, newRate);
                                                   ": %" PRId32 ", sample rate: %f HZ",
                                                   propId, areaId, newRateHz);
    }
    mContSubConfigsByPropIdArea[propIdAreaId] = infoCopy;
    mContSubConfigsByPropIdArea[propIdAreaId] = newConfig;
    return {};
}

@@ -147,14 +136,12 @@ VhalResult<void> SubscriptionManager::subscribe(const std::shared_ptr<IVehicleCa
                                                bool isContinuousProperty) {
    std::scoped_lock<std::mutex> lockGuard(mLock);

    std::vector<int64_t> intervals;
    for (const auto& option : options) {
        float sampleRate = option.sampleRate;
        float sampleRateHz = option.sampleRate;

        if (isContinuousProperty) {
            auto intervalResult = getInterval(sampleRate);
            if (!intervalResult.ok()) {
                return StatusError(StatusCode::INVALID_ARG) << intervalResult.error().message();
            if (auto result = getIntervalNanos(sampleRateHz); !result.ok()) {
                return StatusError(StatusCode::INVALID_ARG) << result.error().message();
            }
        }

@@ -176,7 +163,8 @@ VhalResult<void> SubscriptionManager::subscribe(const std::shared_ptr<IVehicleCa
                    .areaId = areaId,
            };
            if (isContinuousProperty) {
                if (auto result = updateSampleRateLocked(clientId, propIdAreaId, option.sampleRate);
                if (auto result = addContinuousSubscriberLocked(clientId, propIdAreaId,
                                                                option.sampleRate);
                    !result.ok()) {
                    return result;
                }
@@ -214,7 +202,7 @@ VhalResult<void> SubscriptionManager::unsubscribe(SubscriptionManager::ClientIdT
    while (it != propIdAreaIds.end()) {
        int32_t propId = it->propId;
        if (std::find(propIds.begin(), propIds.end(), propId) != propIds.end()) {
            if (auto result = removeSampleRateLocked(clientId, *it); !result.ok()) {
            if (auto result = removeContinuousSubscriberLocked(clientId, *it); !result.ok()) {
                return result;
            }

@@ -244,7 +232,7 @@ VhalResult<void> SubscriptionManager::unsubscribe(SubscriptionManager::ClientIdT

    auto& subscriptions = mSubscribedPropsByClient[clientId];
    for (auto const& propIdAreaId : subscriptions) {
        if (auto result = removeSampleRateLocked(clientId, propIdAreaId); !result.ok()) {
        if (auto result = removeContinuousSubscriberLocked(clientId, propIdAreaId); !result.ok()) {
            return result;
        }

+6 −6

File changed.

Preview size limit exceeded, changes collapsed.

Loading