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

Commit b6209ad5 authored by Michael Wright's avatar Michael Wright Committed by Android (Google) Code Review
Browse files

Merge "Create vibrator::Info to hold all vibrator data" into sc-dev

parents 699f06dd 965284b7
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