Loading services/vibratorservice/VibratorHalController.cpp +0 −134 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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) { Loading @@ -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 services/vibratorservice/VibratorHalWrapper.cpp +101 −90 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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()); } Loading Loading @@ -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(); Loading @@ -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() { Loading @@ -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); Loading Loading @@ -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()>&) { Loading services/vibratorservice/VibratorManagerHalWrapper.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -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() { Loading services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp +116 −111 File changed.Preview size limit exceeded, changes collapsed. Show changes services/vibratorservice/include/vibratorservice/VibratorHalController.h +55 −40 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading
services/vibratorservice/VibratorHalController.cpp +0 −134 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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) { Loading @@ -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
services/vibratorservice/VibratorHalWrapper.cpp +101 −90 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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()); } Loading Loading @@ -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(); Loading @@ -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() { Loading @@ -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); Loading Loading @@ -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()>&) { Loading
services/vibratorservice/VibratorManagerHalWrapper.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -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() { Loading
services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp +116 −111 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/vibratorservice/include/vibratorservice/VibratorHalController.h +55 −40 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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