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

Commit 965284b7 authored by Lais Andrade's avatar Lais Andrade
Browse files

Create vibrator::Info to hold all vibrator data

Create an wrapper to hold all data to be loaded from the vibrator
HAL and sent to the VibratorManagerService, in preparation for
adding all frequency control new required fields.

Bug: 167947076
Test: libvibratorservice_test
Change-Id: Idfa4066616345ff14de9afdd1ab59ff5569f88c8
parent de5779f8
Loading
Loading
Loading
Loading
+0 −134
Original line number Diff line number Diff line
@@ -87,45 +87,6 @@ std::shared_ptr<HalWrapper> connectHal(std::shared_ptr<CallbackScheduler> schedu

// -------------------------------------------------------------------------------------------------

static constexpr int MAX_RETRIES = 1;

template <typename T>
HalResult<T> HalController::processHalResult(HalResult<T> result, const char* functionName) {
    if (result.isFailed()) {
        ALOGE("%s failed: %s", functionName, result.errorMessage());
        std::lock_guard<std::mutex> lock(mConnectedHalMutex);
        mConnectedHal->tryReconnect();
    }
    return result;
}

template <typename T>
HalResult<T> HalController::apply(HalController::hal_fn<T>& halFn, const char* functionName) {
    std::shared_ptr<HalWrapper> hal = nullptr;
    {
        std::lock_guard<std::mutex> lock(mConnectedHalMutex);
        if (mConnectedHal == nullptr) {
            // Init was never called, so connect to HAL for the first time during this call.
            mConnectedHal = mConnector(mCallbackScheduler);

            if (mConnectedHal == nullptr) {
                ALOGV("Skipped %s because Vibrator HAL is not available", functionName);
                return HalResult<T>::unsupported();
            }
        }
        hal = mConnectedHal;
    }

    HalResult<T> ret = processHalResult(halFn(hal), functionName);
    for (int i = 0; i < MAX_RETRIES && ret.isFailed(); i++) {
        ret = processHalResult(halFn(hal), functionName);
    }

    return ret;
}

// -------------------------------------------------------------------------------------------------

bool HalController::init() {
    std::lock_guard<std::mutex> lock(mConnectedHalMutex);
    if (mConnectedHal == nullptr) {
@@ -134,11 +95,6 @@ bool HalController::init() {
    return mConnectedHal != nullptr;
}

HalResult<void> HalController::ping() {
    hal_fn<void> pingFn = [](std::shared_ptr<HalWrapper> hal) { return hal->ping(); };
    return apply(pingFn, "ping");
}

void HalController::tryReconnect() {
    std::lock_guard<std::mutex> lock(mConnectedHalMutex);
    if (mConnectedHal == nullptr) {
@@ -148,96 +104,6 @@ void HalController::tryReconnect() {
    }
}

HalResult<void> HalController::on(milliseconds timeout,
                                  const std::function<void()>& completionCallback) {
    hal_fn<void> onFn = [&](std::shared_ptr<HalWrapper> hal) {
        return hal->on(timeout, completionCallback);
    };
    return apply(onFn, "on");
}

HalResult<void> HalController::off() {
    hal_fn<void> offFn = [](std::shared_ptr<HalWrapper> hal) { return hal->off(); };
    return apply(offFn, "off");
}

HalResult<void> HalController::setAmplitude(float amplitude) {
    hal_fn<void> setAmplitudeFn = [&](std::shared_ptr<HalWrapper> hal) {
        return hal->setAmplitude(amplitude);
    };
    return apply(setAmplitudeFn, "setAmplitude");
}

HalResult<void> HalController::setExternalControl(bool enabled) {
    hal_fn<void> setExternalControlFn = [&](std::shared_ptr<HalWrapper> hal) {
        return hal->setExternalControl(enabled);
    };
    return apply(setExternalControlFn, "setExternalControl");
}

HalResult<void> HalController::alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) {
    hal_fn<void> alwaysOnEnableFn = [&](std::shared_ptr<HalWrapper> hal) {
        return hal->alwaysOnEnable(id, effect, strength);
    };
    return apply(alwaysOnEnableFn, "alwaysOnEnable");
}

HalResult<void> HalController::alwaysOnDisable(int32_t id) {
    hal_fn<void> alwaysOnDisableFn = [&](std::shared_ptr<HalWrapper> hal) {
        return hal->alwaysOnDisable(id);
    };
    return apply(alwaysOnDisableFn, "alwaysOnDisable");
}

HalResult<Capabilities> HalController::getCapabilities() {
    hal_fn<Capabilities> getCapabilitiesFn = [](std::shared_ptr<HalWrapper> hal) {
        return hal->getCapabilities();
    };
    return apply(getCapabilitiesFn, "getCapabilities");
}

HalResult<std::vector<Effect>> HalController::getSupportedEffects() {
    hal_fn<std::vector<Effect>> getSupportedEffectsFn = [](std::shared_ptr<HalWrapper> hal) {
        return hal->getSupportedEffects();
    };
    return apply(getSupportedEffectsFn, "getSupportedEffects");
}

HalResult<std::vector<CompositePrimitive>> HalController::getSupportedPrimitives() {
    hal_fn<std::vector<CompositePrimitive>> getSupportedPrimitivesFn =
            [](std::shared_ptr<HalWrapper> hal) { return hal->getSupportedPrimitives(); };
    return apply(getSupportedPrimitivesFn, "getSupportedPrimitives");
}

HalResult<float> HalController::getResonantFrequency() {
    hal_fn<float> getResonantFrequencyFn = [](std::shared_ptr<HalWrapper> hal) {
        return hal->getResonantFrequency();
    };
    return apply(getResonantFrequencyFn, "getResonantFrequency");
}

HalResult<float> HalController::getQFactor() {
    hal_fn<float> getQFactorFn = [](std::shared_ptr<HalWrapper> hal) { return hal->getQFactor(); };
    return apply(getQFactorFn, "getQFactor");
}

HalResult<milliseconds> HalController::performEffect(
        Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
    hal_fn<milliseconds> performEffectFn = [&](std::shared_ptr<HalWrapper> hal) {
        return hal->performEffect(effect, strength, completionCallback);
    };
    return apply(performEffectFn, "performEffect");
}

HalResult<milliseconds> HalController::performComposedEffect(
        const std::vector<CompositeEffect>& primitiveEffects,
        const std::function<void()>& completionCallback) {
    hal_fn<milliseconds> performComposedEffectFn = [&](std::shared_ptr<HalWrapper> hal) {
        return hal->performComposedEffect(primitiveEffects, completionCallback);
    };
    return apply(performComposedEffectFn, "performComposedEffect");
}

}; // namespace vibrator

}; // namespace android
+101 −90
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <android/hardware/vibrator/1.3/IVibrator.h>
#include <android/hardware/vibrator/IVibrator.h>
#include <hardware/vibrator.h>
#include <cmath>

#include <utils/Log.h>

@@ -133,6 +134,73 @@ HalResult<void> HalResult<void>::fromReturn(hardware::Return<R>& ret) {

// -------------------------------------------------------------------------------------------------

Info HalWrapper::getInfo() {
    getCapabilities();
    getPrimitiveDurations();
    std::lock_guard<std::mutex> lock(mInfoMutex);
    if (mInfoCache.mSupportedEffects.isFailed()) {
        mInfoCache.mSupportedEffects = getSupportedEffectsInternal();
    }
    if (mInfoCache.mResonantFrequency.isFailed()) {
        mInfoCache.mResonantFrequency = getResonantFrequencyInternal();
    }
    if (mInfoCache.mQFactor.isFailed()) {
        mInfoCache.mQFactor = getQFactorInternal();
    }
    return mInfoCache.get();
}

HalResult<Capabilities> HalWrapper::getCapabilities() {
    std::lock_guard<std::mutex> lock(mInfoMutex);
    if (mInfoCache.mCapabilities.isFailed()) {
        mInfoCache.mCapabilities = getCapabilitiesInternal();
    }
    return mInfoCache.mCapabilities;
}

HalResult<std::vector<milliseconds>> HalWrapper::getPrimitiveDurations() {
    std::lock_guard<std::mutex> lock(mInfoMutex);
    if (mInfoCache.mSupportedPrimitives.isFailed()) {
        mInfoCache.mSupportedPrimitives = getSupportedPrimitivesInternal();
        if (mInfoCache.mSupportedPrimitives.isUnsupported()) {
            mInfoCache.mPrimitiveDurations = HalResult<std::vector<milliseconds>>::unsupported();
        }
    }
    if (mInfoCache.mPrimitiveDurations.isFailed() && mInfoCache.mSupportedPrimitives.isOk()) {
        mInfoCache.mPrimitiveDurations =
                getPrimitiveDurationsInternal(mInfoCache.mSupportedPrimitives.value());
    }
    return mInfoCache.mPrimitiveDurations;
}

HalResult<std::vector<Effect>> HalWrapper::getSupportedEffectsInternal() {
    ALOGV("Skipped getSupportedEffects because it's not available in Vibrator HAL");
    return HalResult<std::vector<Effect>>::unsupported();
}

HalResult<std::vector<CompositePrimitive>> HalWrapper::getSupportedPrimitivesInternal() {
    ALOGV("Skipped getSupportedPrimitives because it's not available in Vibrator HAL");
    return HalResult<std::vector<CompositePrimitive>>::unsupported();
}

HalResult<std::vector<milliseconds>> HalWrapper::getPrimitiveDurationsInternal(
        const std::vector<CompositePrimitive>&) {
    ALOGV("Skipped getPrimitiveDurations because it's not available in Vibrator HAL");
    return HalResult<std::vector<milliseconds>>::unsupported();
}

HalResult<float> HalWrapper::getResonantFrequencyInternal() {
    ALOGV("Skipped getResonantFrequency because it's not available in Vibrator HAL");
    return HalResult<float>::unsupported();
}

HalResult<float> HalWrapper::getQFactorInternal() {
    ALOGV("Skipped getQFactor because it's not available in Vibrator HAL");
    return HalResult<float>::unsupported();
}

// -------------------------------------------------------------------------------------------------

HalResult<void> AidlHalWrapper::ping() {
    return HalResult<void>::fromStatus(IInterface::asBinder(getHal())->pingBinder());
}
@@ -184,37 +252,6 @@ HalResult<void> AidlHalWrapper::alwaysOnDisable(int32_t id) {
    return HalResult<void>::fromStatus(getHal()->alwaysOnDisable(id));
}

HalResult<Capabilities> AidlHalWrapper::getCapabilities() {
    std::lock_guard<std::mutex> lock(mCapabilitiesMutex);
    return loadCached<Capabilities>(std::bind(&AidlHalWrapper::getCapabilitiesInternal, this),
                                    mCapabilities);
}

HalResult<std::vector<Effect>> AidlHalWrapper::getSupportedEffects() {
    std::lock_guard<std::mutex> lock(mSupportedEffectsMutex);
    return loadCached<std::vector<Effect>>(std::bind(&AidlHalWrapper::getSupportedEffectsInternal,
                                                     this),
                                           mSupportedEffects);
}

HalResult<std::vector<CompositePrimitive>> AidlHalWrapper::getSupportedPrimitives() {
    std::lock_guard<std::mutex> lock(mSupportedPrimitivesMutex);
    return loadCached<std::vector<
            CompositePrimitive>>(std::bind(&AidlHalWrapper::getSupportedPrimitivesInternal, this),
                                 mSupportedPrimitives);
}

HalResult<float> AidlHalWrapper::getResonantFrequency() {
    std::lock_guard<std::mutex> lock(mResonantFrequencyMutex);
    return loadCached<float>(std::bind(&AidlHalWrapper::getResonantFrequencyInternal, this),
                             mResonantFrequency);
}

HalResult<float> AidlHalWrapper::getQFactor() {
    std::lock_guard<std::mutex> lock(mQFactorMutex);
    return loadCached<float>(std::bind(&AidlHalWrapper::getQFactorInternal, this), mQFactor);
}

HalResult<milliseconds> AidlHalWrapper::performEffect(
        Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
    HalResult<Capabilities> capabilities = getCapabilities();
@@ -239,40 +276,21 @@ HalResult<milliseconds> AidlHalWrapper::performComposedEffect(
        const std::function<void()>& completionCallback) {
    // This method should always support callbacks, so no need to double check.
    auto cb = new HalCallbackWrapper(completionCallback);

    auto durations = getPrimitiveDurations().valueOr({});
    milliseconds duration(0);
    for (const auto& effect : primitiveEffects) {
        auto durationResult = getPrimitiveDuration(effect.primitive);
        if (durationResult.isOk()) {
            duration += durationResult.value();
        auto primitiveIdx = static_cast<size_t>(effect.primitive);
        if (primitiveIdx < durations.size()) {
            duration += durations[primitiveIdx];
        } else {
            // Make sure the returned duration is positive to indicate successful vibration.
            duration += milliseconds(1);
        }
        duration += milliseconds(effect.delayMs);
    }
    return HalResult<milliseconds>::fromStatus(getHal()->compose(primitiveEffects, cb), duration);
}

HalResult<milliseconds> AidlHalWrapper::getPrimitiveDuration(CompositePrimitive primitive) {
    std::lock_guard<std::mutex> lock(mSupportedPrimitivesMutex);
    if (mPrimitiveDurations.empty()) {
        constexpr auto primitiveRange = enum_range<CompositePrimitive>();
        constexpr auto primitiveCount = std::distance(primitiveRange.begin(), primitiveRange.end());
        mPrimitiveDurations.resize(primitiveCount);
    }
    auto primitiveIdx = static_cast<size_t>(primitive);
    if (primitiveIdx >= mPrimitiveDurations.size()) {
        // Safety check, should not happen if enum_range is correct.
        return HalResult<milliseconds>::unsupported();
    }
    auto& cache = mPrimitiveDurations[primitiveIdx];
    if (cache.has_value()) {
        return HalResult<milliseconds>::ok(*cache);
    }
    int32_t duration;
    auto result = getHal()->getPrimitiveDuration(primitive, &duration);
    if (result.isOk()) {
        // Cache copy of returned value.
        cache.emplace(duration);
    }
    return HalResult<milliseconds>::fromStatus(result, milliseconds(duration));
    return HalResult<milliseconds>::fromStatus(getHal()->compose(primitiveEffects, cb), duration);
}

HalResult<Capabilities> AidlHalWrapper::getCapabilitiesInternal() {
@@ -293,6 +311,30 @@ HalResult<std::vector<CompositePrimitive>> AidlHalWrapper::getSupportedPrimitive
    return HalResult<std::vector<CompositePrimitive>>::fromStatus(result, supportedPrimitives);
}

HalResult<std::vector<milliseconds>> AidlHalWrapper::getPrimitiveDurationsInternal(
        const std::vector<CompositePrimitive>& supportedPrimitives) {
    std::vector<milliseconds> durations;
    constexpr auto primitiveRange = enum_range<CompositePrimitive>();
    constexpr auto primitiveCount = std::distance(primitiveRange.begin(), primitiveRange.end());
    durations.resize(primitiveCount);

    for (auto primitive : supportedPrimitives) {
        auto primitiveIdx = static_cast<size_t>(primitive);
        if (primitiveIdx >= durations.size()) {
            // Safety check, should not happen if enum_range is correct.
            continue;
        }
        int32_t duration = 0;
        auto status = getHal()->getPrimitiveDuration(primitive, &duration);
        if (!status.isOk()) {
            return HalResult<std::vector<milliseconds>>::failed(status.toString8().c_str());
        }
        durations[primitiveIdx] = milliseconds(duration);
    }

    return HalResult<std::vector<milliseconds>>::ok(durations);
}

HalResult<float> AidlHalWrapper::getResonantFrequencyInternal() {
    float f0 = 0;
    auto result = getHal()->getResonantFrequency(&f0);
@@ -369,37 +411,6 @@ HalResult<void> HidlHalWrapper<I>::alwaysOnDisable(int32_t) {
    return HalResult<void>::unsupported();
}

template <typename I>
HalResult<Capabilities> HidlHalWrapper<I>::getCapabilities() {
    std::lock_guard<std::mutex> lock(mCapabilitiesMutex);
    return loadCached<Capabilities>(std::bind(&HidlHalWrapper<I>::getCapabilitiesInternal, this),
                                    mCapabilities);
}

template <typename I>
HalResult<std::vector<Effect>> HidlHalWrapper<I>::getSupportedEffects() {
    ALOGV("Skipped getSupportedEffects because Vibrator HAL AIDL is not available");
    return HalResult<std::vector<Effect>>::unsupported();
}

template <typename I>
HalResult<std::vector<CompositePrimitive>> HidlHalWrapper<I>::getSupportedPrimitives() {
    ALOGV("Skipped getSupportedPrimitives because Vibrator HAL AIDL is not available");
    return HalResult<std::vector<CompositePrimitive>>::unsupported();
}

template <typename I>
HalResult<float> HidlHalWrapper<I>::getResonantFrequency() {
    ALOGV("Skipped getResonantFrequency because Vibrator HAL AIDL is not available");
    return HalResult<float>::unsupported();
}

template <typename I>
HalResult<float> HidlHalWrapper<I>::getQFactor() {
    ALOGV("Skipped getQFactor because Vibrator HAL AIDL is not available");
    return HalResult<float>::unsupported();
}

template <typename I>
HalResult<std::chrono::milliseconds> HidlHalWrapper<I>::performComposedEffect(
        const std::vector<CompositeEffect>&, const std::function<void()>&) {
+2 −1
Original line number Diff line number Diff line
@@ -30,7 +30,8 @@ constexpr int32_t SINGLE_VIBRATOR_ID = 0;
const constexpr char* MISSING_VIBRATOR_MESSAGE_PREFIX = "No vibrator with id=";

HalResult<void> LegacyManagerHalWrapper::ping() {
    return mController->ping();
    auto pingFn = [](std::shared_ptr<HalWrapper> hal) { return hal->ping(); };
    return mController->doWithRetry<void>(pingFn, "ping");
}

void LegacyManagerHalWrapper::tryReconnect() {
+116 −111

File changed.

Preview size limit exceeded, changes collapsed.

+55 −40
Original line number Diff line number Diff line
@@ -29,19 +29,22 @@ namespace vibrator {

std::shared_ptr<HalWrapper> connectHal(std::shared_ptr<CallbackScheduler> scheduler);

template <typename T>
using HalFunction = std::function<T(std::shared_ptr<HalWrapper>)>;

// Controller for Vibrator HAL handle.
// This relies on a given Connector to connect to the underlying Vibrator HAL service and reconnects
// after each failed api call. This also ensures connecting to the service is thread-safe.
class HalController : public HalWrapper {
class HalController {
public:
    using Connector =
            std::function<std::shared_ptr<HalWrapper>(std::shared_ptr<CallbackScheduler>)>;

    HalController() : HalController(std::make_shared<CallbackScheduler>(), &connectHal) {}
    HalController(std::shared_ptr<CallbackScheduler> callbackScheduler, Connector connector)
          : HalWrapper(std::move(callbackScheduler)),
            mConnector(connector),
            mConnectedHal(nullptr) {}
          : mConnector(connector),
            mConnectedHal(nullptr),
            mCallbackScheduler(std::move(callbackScheduler)) {}
    virtual ~HalController() = default;

    /* Connects to the newest HAL version available, possibly waiting for the registered service to
@@ -51,53 +54,65 @@ public:
     */
    virtual bool init();

    /* reloads HAL service instance without waiting. This relies on the HAL version found by init()
    /* Reloads HAL service instance without waiting. This relies on the HAL version found by init()
     * to rapidly reconnect to the specific HAL service, or defers to init() if it was never called.
     */
    virtual void tryReconnect() override;

    virtual HalResult<void> ping() override;
    HalResult<void> on(std::chrono::milliseconds timeout,
                       const std::function<void()>& completionCallback) final override;
    HalResult<void> off() final override;

    HalResult<void> setAmplitude(float amplitude) final override;
    HalResult<void> setExternalControl(bool enabled) final override;

    HalResult<void> alwaysOnEnable(int32_t id, hardware::vibrator::Effect effect,
                                   hardware::vibrator::EffectStrength strength) final override;
    HalResult<void> alwaysOnDisable(int32_t id) final override;
    virtual void tryReconnect();

    HalResult<Capabilities> getCapabilities() final override;
    HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffects() final override;
    HalResult<std::vector<hardware::vibrator::CompositePrimitive>> getSupportedPrimitives()
            final override;

    HalResult<float> getResonantFrequency() final override;
    HalResult<float> getQFactor() final override;

    HalResult<std::chrono::milliseconds> performEffect(
            hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
            const std::function<void()>& completionCallback) final override;

    HalResult<std::chrono::milliseconds> performComposedEffect(
            const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
            const std::function<void()>& completionCallback) final override;
    /* Returns info loaded from the connected HAL. This allows partial results to be returned if any
     * of the Info fields has failed, but also retried on any failure.
     */
    Info getInfo() {
        static Info sDefaultInfo = InfoCache().get();
        return apply<Info>([](std::shared_ptr<HalWrapper> hal) { return hal->getInfo(); },
                           sDefaultInfo, "getInfo");
    }

    /* Calls given HAL function, applying automatic retries to reconnect with the HAL when the
     * result has failed. Parameter functionName is for logging purposes.
     */
    template <typename T>
    HalResult<T> doWithRetry(const HalFunction<HalResult<T>>& halFn, const char* functionName) {
        return apply(halFn, HalResult<T>::unsupported(), functionName);
    }

private:
    static constexpr int MAX_RETRIES = 1;

    Connector mConnector;
    std::mutex mConnectedHalMutex;
    // Shared pointer to allow local copies to be used by different threads.
    std::shared_ptr<HalWrapper> mConnectedHal GUARDED_BY(mConnectedHalMutex);
    // Shared pointer to allow copies to be passed to possible recreated mConnectedHal instances.
    std::shared_ptr<CallbackScheduler> mCallbackScheduler;

    /* Calls given HAL function, applying automatic retries to reconnect with the HAL when the
     * result has failed. Given default value is returned when no HAL is available, and given
     * function name is for logging purposes.
     */
    template <typename T>
    HalResult<T> processHalResult(HalResult<T> result, const char* functionName);

    template <typename T>
    using hal_fn = std::function<HalResult<T>(std::shared_ptr<HalWrapper>)>;

    template <typename T>
    HalResult<T> apply(hal_fn<T>& halFn, const char* functionName);
    T apply(const HalFunction<T>& halFn, T defaultValue, const char* functionName) {
        if (!init()) {
            ALOGV("Skipped %s because Vibrator HAL is not available", functionName);
            return defaultValue;
        }
        std::shared_ptr<HalWrapper> hal;
        {
            std::lock_guard<std::mutex> lock(mConnectedHalMutex);
            hal = mConnectedHal;
        }

        for (int i = 0; i < MAX_RETRIES; i++) {
            T result = halFn(hal);
            if (result.checkAndLogFailure(functionName)) {
                tryReconnect();
            } else {
                return result;
            }
        }

        return halFn(hal);
    }
};

}; // namespace vibrator
Loading