/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_OS_VIBRATORHALWRAPPER_H #define ANDROID_OS_VIBRATORHALWRAPPER_H #include #include #include #include #include #include namespace android { namespace vibrator { // ------------------------------------------------------------------------------------------------- // Result of a call to the Vibrator HAL wrapper, holding data if successful. template class HalResult { public: static HalResult ok(T value) { return HalResult(value); } static HalResult failed(std::string msg) { return HalResult(std::move(msg), /* unsupported= */ false); } static HalResult unsupported() { return HalResult("", /* unsupported= */ true); } static HalResult fromStatus(binder::Status status, T data) { if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION || status.transactionError() == android::UNKNOWN_TRANSACTION) { // UNKNOWN_TRANSACTION means the HAL implementation is an older version, so this is // the same as the operation being unsupported by this HAL. Should not retry. return HalResult::unsupported(); } if (status.isOk()) { return HalResult::ok(data); } return HalResult::failed(status.toString8().c_str()); } static HalResult fromStatus(hardware::vibrator::V1_0::Status status, T data); template static HalResult fromReturn(hardware::Return& ret, T data); template static HalResult fromReturn(hardware::Return& ret, hardware::vibrator::V1_0::Status status, T data); // This will throw std::bad_optional_access if this result is not ok. const T& value() const { return mValue.value(); } const T valueOr(T&& defaultValue) const { return mValue.value_or(defaultValue); } bool isOk() const { return !mUnsupported && mValue.has_value(); } bool isFailed() const { return !mUnsupported && !mValue.has_value(); } bool isUnsupported() const { return mUnsupported; } const char* errorMessage() const { return mErrorMessage.c_str(); } bool checkAndLogFailure(const char* functionName) const { if (isFailed()) { ALOGE("%s failed: %s", functionName, errorMessage()); return true; } return false; } private: std::optional mValue; std::string mErrorMessage; bool mUnsupported; explicit HalResult(T value) : mValue(std::make_optional(value)), mErrorMessage(), mUnsupported(false) {} explicit HalResult(std::string errorMessage, bool unsupported) : mValue(), mErrorMessage(std::move(errorMessage)), mUnsupported(unsupported) {} }; // Empty result of a call to the Vibrator HAL wrapper. template <> class HalResult { public: static HalResult ok() { return HalResult(); } static HalResult failed(std::string msg) { return HalResult(std::move(msg)); } static HalResult unsupported() { return HalResult(/* unsupported= */ true); } static HalResult fromStatus(status_t status); static HalResult fromStatus(binder::Status status); static HalResult fromStatus(hardware::vibrator::V1_0::Status status); template static HalResult fromReturn(hardware::Return& ret); bool isOk() const { return !mUnsupported && !mFailed; } bool isFailed() const { return !mUnsupported && mFailed; } bool isUnsupported() const { return mUnsupported; } const char* errorMessage() const { return mErrorMessage.c_str(); } bool checkAndLogFailure(const char* functionName) const { if (isFailed()) { ALOGE("%s failed: %s", functionName, errorMessage()); return true; } return false; } private: std::string mErrorMessage; bool mFailed; bool mUnsupported; explicit HalResult(bool unsupported = false) : mErrorMessage(), mFailed(false), mUnsupported(unsupported) {} explicit HalResult(std::string errorMessage) : mErrorMessage(std::move(errorMessage)), mFailed(true), mUnsupported(false) {} }; class HalCallbackWrapper : public hardware::vibrator::BnVibratorCallback { public: HalCallbackWrapper(std::function completionCallback) : mCompletionCallback(completionCallback) {} binder::Status onComplete() override { mCompletionCallback(); return binder::Status::ok(); } private: const std::function mCompletionCallback; }; // ------------------------------------------------------------------------------------------------- // Vibrator HAL capabilities. enum class Capabilities : int32_t { NONE = 0, ON_CALLBACK = hardware::vibrator::IVibrator::CAP_ON_CALLBACK, PERFORM_CALLBACK = hardware::vibrator::IVibrator::CAP_PERFORM_CALLBACK, AMPLITUDE_CONTROL = hardware::vibrator::IVibrator::CAP_AMPLITUDE_CONTROL, EXTERNAL_CONTROL = hardware::vibrator::IVibrator::CAP_EXTERNAL_CONTROL, EXTERNAL_AMPLITUDE_CONTROL = hardware::vibrator::IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL, COMPOSE_EFFECTS = hardware::vibrator::IVibrator::CAP_COMPOSE_EFFECTS, COMPOSE_PWLE_EFFECTS = hardware::vibrator::IVibrator::CAP_COMPOSE_PWLE_EFFECTS, ALWAYS_ON_CONTROL = hardware::vibrator::IVibrator::CAP_ALWAYS_ON_CONTROL, }; inline Capabilities operator|(Capabilities lhs, Capabilities rhs) { using underlying = typename std::underlying_type::type; return static_cast(static_cast(lhs) | static_cast(rhs)); } inline Capabilities& operator|=(Capabilities& lhs, Capabilities rhs) { return lhs = lhs | rhs; } inline Capabilities operator&(Capabilities lhs, Capabilities rhs) { using underlying = typename std::underlying_type::type; return static_cast(static_cast(lhs) & static_cast(rhs)); } inline Capabilities& operator&=(Capabilities& lhs, Capabilities rhs) { return lhs = lhs & rhs; } // ------------------------------------------------------------------------------------------------- class Info { public: const HalResult capabilities; const HalResult> supportedEffects; const HalResult> supportedBraking; const HalResult> supportedPrimitives; const HalResult> primitiveDurations; const HalResult primitiveDelayMax; const HalResult pwlePrimitiveDurationMax; const HalResult compositionSizeMax; const HalResult pwleSizeMax; const HalResult minFrequency; const HalResult resonantFrequency; const HalResult frequencyResolution; const HalResult qFactor; const HalResult> maxAmplitudes; bool checkAndLogFailure(const char*) const { return capabilities.checkAndLogFailure("getCapabilities") || supportedEffects.checkAndLogFailure("getSupportedEffects") || supportedBraking.checkAndLogFailure("getSupportedBraking") || supportedPrimitives.checkAndLogFailure("getSupportedPrimitives") || primitiveDurations.checkAndLogFailure("getPrimitiveDuration") || primitiveDelayMax.checkAndLogFailure("getPrimitiveDelayMax") || pwlePrimitiveDurationMax.checkAndLogFailure("getPwlePrimitiveDurationMax") || compositionSizeMax.checkAndLogFailure("getCompositionSizeMax") || pwleSizeMax.checkAndLogFailure("getPwleSizeMax") || minFrequency.checkAndLogFailure("getMinFrequency") || resonantFrequency.checkAndLogFailure("getResonantFrequency") || frequencyResolution.checkAndLogFailure("getFrequencyResolution") || qFactor.checkAndLogFailure("getQFactor") || maxAmplitudes.checkAndLogFailure("getMaxAmplitudes"); } }; class InfoCache { public: Info get() { return {mCapabilities, mSupportedEffects, mSupportedBraking, mSupportedPrimitives, mPrimitiveDurations, mPrimitiveDelayMax, mPwlePrimitiveDurationMax, mCompositionSizeMax, mPwleSizeMax, mMinFrequency, mResonantFrequency, mFrequencyResolution, mQFactor, mMaxAmplitudes}; } private: static const constexpr char* MSG = "never loaded"; HalResult mCapabilities = HalResult::failed(MSG); HalResult> mSupportedEffects = HalResult>::failed(MSG); HalResult> mSupportedBraking = HalResult>::failed(MSG); HalResult> mSupportedPrimitives = HalResult>::failed(MSG); HalResult> mPrimitiveDurations = HalResult>::failed(MSG); HalResult mPrimitiveDelayMax = HalResult::failed(MSG); HalResult mPwlePrimitiveDurationMax = HalResult::failed(MSG); HalResult mCompositionSizeMax = HalResult::failed(MSG); HalResult mPwleSizeMax = HalResult::failed(MSG); HalResult mMinFrequency = HalResult::failed(MSG); HalResult mResonantFrequency = HalResult::failed(MSG); HalResult mFrequencyResolution = HalResult::failed(MSG); HalResult mQFactor = HalResult::failed(MSG); HalResult> mMaxAmplitudes = HalResult>::failed(MSG); friend class HalWrapper; }; // Wrapper for Vibrator HAL handlers. class HalWrapper { public: explicit HalWrapper(std::shared_ptr scheduler) : mCallbackScheduler(std::move(scheduler)) {} virtual ~HalWrapper() = default; /* reloads wrapped HAL service instance without waiting. This can be used to reconnect when the * service restarts, to rapidly retry after a failure. */ virtual void tryReconnect() = 0; Info getInfo(); virtual HalResult ping() = 0; virtual HalResult on(std::chrono::milliseconds timeout, const std::function& completionCallback) = 0; virtual HalResult off() = 0; virtual HalResult setAmplitude(float amplitude) = 0; virtual HalResult setExternalControl(bool enabled) = 0; virtual HalResult alwaysOnEnable(int32_t id, hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength) = 0; virtual HalResult alwaysOnDisable(int32_t id) = 0; virtual HalResult performEffect( hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength, const std::function& completionCallback) = 0; virtual HalResult performComposedEffect( const std::vector& primitives, const std::function& completionCallback); virtual HalResult performPwleEffect( const std::vector& primitives, const std::function& completionCallback); protected: // Shared pointer to allow CallbackScheduler to outlive this wrapper. const std::shared_ptr mCallbackScheduler; // Load and cache vibrator info, returning cached result is present. HalResult getCapabilities(); HalResult> getPrimitiveDurations(); // Request vibrator info to HAL skipping cache. virtual HalResult getCapabilitiesInternal() = 0; virtual HalResult> getSupportedEffectsInternal(); virtual HalResult> getSupportedBrakingInternal(); virtual HalResult> getSupportedPrimitivesInternal(); virtual HalResult> getPrimitiveDurationsInternal( const std::vector& supportedPrimitives); virtual HalResult getPrimitiveDelayMaxInternal(); virtual HalResult getPrimitiveDurationMaxInternal(); virtual HalResult getCompositionSizeMaxInternal(); virtual HalResult getPwleSizeMaxInternal(); virtual HalResult getMinFrequencyInternal(); virtual HalResult getResonantFrequencyInternal(); virtual HalResult getFrequencyResolutionInternal(); virtual HalResult getQFactorInternal(); virtual HalResult> getMaxAmplitudesInternal(); private: std::mutex mInfoMutex; InfoCache mInfoCache GUARDED_BY(mInfoMutex); }; // Wrapper for the AIDL Vibrator HAL. class AidlHalWrapper : public HalWrapper { public: AidlHalWrapper( std::shared_ptr scheduler, sp handle, std::function>()> reconnectFn = []() { return HalResult>::ok( checkVintfService()); }) : HalWrapper(std::move(scheduler)), mReconnectFn(reconnectFn), mHandle(std::move(handle)) {} virtual ~AidlHalWrapper() = default; HalResult ping() override final; void tryReconnect() override final; HalResult on(std::chrono::milliseconds timeout, const std::function& completionCallback) override final; HalResult off() override final; HalResult setAmplitude(float amplitude) override final; HalResult setExternalControl(bool enabled) override final; HalResult alwaysOnEnable(int32_t id, hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength) override final; HalResult alwaysOnDisable(int32_t id) override final; HalResult performEffect( hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength, const std::function& completionCallback) override final; HalResult performComposedEffect( const std::vector& primitives, const std::function& completionCallback) override final; HalResult performPwleEffect( const std::vector& primitives, const std::function& completionCallback) override final; protected: HalResult getCapabilitiesInternal() override final; HalResult> getSupportedEffectsInternal() override final; HalResult> getSupportedBrakingInternal() override final; HalResult> getSupportedPrimitivesInternal() override final; HalResult> getPrimitiveDurationsInternal( const std::vector& supportedPrimitives) override final; HalResult getPrimitiveDelayMaxInternal() override final; HalResult getPrimitiveDurationMaxInternal() override final; HalResult getCompositionSizeMaxInternal() override final; HalResult getPwleSizeMaxInternal() override final; HalResult getMinFrequencyInternal() override final; HalResult getResonantFrequencyInternal() override final; HalResult getFrequencyResolutionInternal() override final; HalResult getQFactorInternal() override final; HalResult> getMaxAmplitudesInternal() override final; private: const std::function>()> mReconnectFn; std::mutex mHandleMutex; sp mHandle GUARDED_BY(mHandleMutex); sp getHal(); }; // Wrapper for the HDIL Vibrator HALs. template class HidlHalWrapper : public HalWrapper { public: HidlHalWrapper(std::shared_ptr scheduler, sp handle) : HalWrapper(std::move(scheduler)), mHandle(std::move(handle)) {} virtual ~HidlHalWrapper() = default; HalResult ping() override final; void tryReconnect() override final; HalResult on(std::chrono::milliseconds timeout, const std::function& completionCallback) override final; HalResult off() override final; HalResult setAmplitude(float amplitude) override final; virtual HalResult setExternalControl(bool enabled) override; HalResult alwaysOnEnable(int32_t id, hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength) override final; HalResult alwaysOnDisable(int32_t id) override final; protected: std::mutex mHandleMutex; sp mHandle GUARDED_BY(mHandleMutex); virtual HalResult getCapabilitiesInternal() override; template using perform_fn = hardware::Return (I::*)(T, hardware::vibrator::V1_0::EffectStrength, hardware::vibrator::V1_0::IVibrator::perform_cb); template HalResult performInternal( perform_fn performFn, sp handle, T effect, hardware::vibrator::EffectStrength strength, const std::function& completionCallback); sp getHal(); }; // Wrapper for the HDIL Vibrator HAL v1.0. class HidlHalWrapperV1_0 : public HidlHalWrapper { public: HidlHalWrapperV1_0(std::shared_ptr scheduler, sp handle) : HidlHalWrapper(std::move(scheduler), std::move(handle)) {} virtual ~HidlHalWrapperV1_0() = default; HalResult performEffect( hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength, const std::function& completionCallback) override final; }; // Wrapper for the HDIL Vibrator HAL v1.1. class HidlHalWrapperV1_1 : public HidlHalWrapper { public: HidlHalWrapperV1_1(std::shared_ptr scheduler, sp handle) : HidlHalWrapper(std::move(scheduler), std::move(handle)) {} virtual ~HidlHalWrapperV1_1() = default; HalResult performEffect( hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength, const std::function& completionCallback) override final; }; // Wrapper for the HDIL Vibrator HAL v1.2. class HidlHalWrapperV1_2 : public HidlHalWrapper { public: HidlHalWrapperV1_2(std::shared_ptr scheduler, sp handle) : HidlHalWrapper(std::move(scheduler), std::move(handle)) {} virtual ~HidlHalWrapperV1_2() = default; HalResult performEffect( hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength, const std::function& completionCallback) override final; }; // Wrapper for the HDIL Vibrator HAL v1.3. class HidlHalWrapperV1_3 : public HidlHalWrapper { public: HidlHalWrapperV1_3(std::shared_ptr scheduler, sp handle) : HidlHalWrapper(std::move(scheduler), std::move(handle)) {} virtual ~HidlHalWrapperV1_3() = default; HalResult setExternalControl(bool enabled) override final; HalResult performEffect( hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength, const std::function& completionCallback) override final; protected: HalResult getCapabilitiesInternal() override final; }; // ------------------------------------------------------------------------------------------------- }; // namespace vibrator }; // namespace android #endif // ANDROID_OS_VIBRATORHALWRAPPER_H