blob: 68d6647ede12595f1993de5bf2371b645ccdaa1e [file] [log] [blame]
/*
* 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 <android-base/thread_annotations.h>
#include <android/hardware/vibrator/1.3/IVibrator.h>
#include <android/hardware/vibrator/BnVibratorCallback.h>
#include <android/hardware/vibrator/IVibrator.h>
#include <binder/IServiceManager.h>
#include <vibratorservice/VibratorCallbackScheduler.h>
namespace android {
namespace vibrator {
// -------------------------------------------------------------------------------------------------
// Result of a call to the Vibrator HAL wrapper, holding data if successful.
template <typename T>
class HalResult {
public:
static HalResult<T> ok(T value) { return HalResult(value); }
static HalResult<T> failed(std::string msg) {
return HalResult(std::move(msg), /* unsupported= */ false);
}
static HalResult<T> unsupported() { return HalResult("", /* unsupported= */ true); }
static HalResult<T> 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<T>::unsupported();
}
if (status.isOk()) {
return HalResult<T>::ok(data);
}
return HalResult<T>::failed(status.toString8().c_str());
}
static HalResult<T> fromStatus(hardware::vibrator::V1_0::Status status, T data);
template <typename R>
static HalResult<T> fromReturn(hardware::Return<R>& ret, T data);
template <typename R>
static HalResult<T> fromReturn(hardware::Return<R>& 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<T> 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<void> {
public:
static HalResult<void> ok() { return HalResult(); }
static HalResult<void> failed(std::string msg) { return HalResult(std::move(msg)); }
static HalResult<void> unsupported() { return HalResult(/* unsupported= */ true); }
static HalResult<void> fromStatus(status_t status);
static HalResult<void> fromStatus(binder::Status status);
static HalResult<void> fromStatus(hardware::vibrator::V1_0::Status status);
template <typename R>
static HalResult<void> fromReturn(hardware::Return<R>& 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<void()> completionCallback)
: mCompletionCallback(completionCallback) {}
binder::Status onComplete() override {
mCompletionCallback();
return binder::Status::ok();
}
private:
const std::function<void()> 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<Capabilities>::type;
return static_cast<Capabilities>(static_cast<underlying>(lhs) | static_cast<underlying>(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<Capabilities>::type;
return static_cast<Capabilities>(static_cast<underlying>(lhs) & static_cast<underlying>(rhs));
}
inline Capabilities& operator&=(Capabilities& lhs, Capabilities rhs) {
return lhs = lhs & rhs;
}
// -------------------------------------------------------------------------------------------------
class Info {
public:
const HalResult<Capabilities> capabilities;
const HalResult<std::vector<hardware::vibrator::Effect>> supportedEffects;
const HalResult<std::vector<hardware::vibrator::Braking>> supportedBraking;
const HalResult<std::vector<hardware::vibrator::CompositePrimitive>> supportedPrimitives;
const HalResult<std::vector<std::chrono::milliseconds>> primitiveDurations;
const HalResult<std::chrono::milliseconds> primitiveDelayMax;
const HalResult<std::chrono::milliseconds> pwlePrimitiveDurationMax;
const HalResult<int32_t> compositionSizeMax;
const HalResult<int32_t> pwleSizeMax;
const HalResult<float> minFrequency;
const HalResult<float> resonantFrequency;
const HalResult<float> frequencyResolution;
const HalResult<float> qFactor;
const HalResult<std::vector<float>> 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<Capabilities> mCapabilities = HalResult<Capabilities>::failed(MSG);
HalResult<std::vector<hardware::vibrator::Effect>> mSupportedEffects =
HalResult<std::vector<hardware::vibrator::Effect>>::failed(MSG);
HalResult<std::vector<hardware::vibrator::Braking>> mSupportedBraking =
HalResult<std::vector<hardware::vibrator::Braking>>::failed(MSG);
HalResult<std::vector<hardware::vibrator::CompositePrimitive>> mSupportedPrimitives =
HalResult<std::vector<hardware::vibrator::CompositePrimitive>>::failed(MSG);
HalResult<std::vector<std::chrono::milliseconds>> mPrimitiveDurations =
HalResult<std::vector<std::chrono::milliseconds>>::failed(MSG);
HalResult<std::chrono::milliseconds> mPrimitiveDelayMax =
HalResult<std::chrono::milliseconds>::failed(MSG);
HalResult<std::chrono::milliseconds> mPwlePrimitiveDurationMax =
HalResult<std::chrono::milliseconds>::failed(MSG);
HalResult<int32_t> mCompositionSizeMax = HalResult<int>::failed(MSG);
HalResult<int32_t> mPwleSizeMax = HalResult<int>::failed(MSG);
HalResult<float> mMinFrequency = HalResult<float>::failed(MSG);
HalResult<float> mResonantFrequency = HalResult<float>::failed(MSG);
HalResult<float> mFrequencyResolution = HalResult<float>::failed(MSG);
HalResult<float> mQFactor = HalResult<float>::failed(MSG);
HalResult<std::vector<float>> mMaxAmplitudes = HalResult<std::vector<float>>::failed(MSG);
friend class HalWrapper;
};
// Wrapper for Vibrator HAL handlers.
class HalWrapper {
public:
explicit HalWrapper(std::shared_ptr<CallbackScheduler> 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<void> ping() = 0;
virtual HalResult<void> on(std::chrono::milliseconds timeout,
const std::function<void()>& completionCallback) = 0;
virtual HalResult<void> off() = 0;
virtual HalResult<void> setAmplitude(float amplitude) = 0;
virtual HalResult<void> setExternalControl(bool enabled) = 0;
virtual HalResult<void> alwaysOnEnable(int32_t id, hardware::vibrator::Effect effect,
hardware::vibrator::EffectStrength strength) = 0;
virtual HalResult<void> alwaysOnDisable(int32_t id) = 0;
virtual HalResult<std::chrono::milliseconds> performEffect(
hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
const std::function<void()>& completionCallback) = 0;
virtual HalResult<std::chrono::milliseconds> performComposedEffect(
const std::vector<hardware::vibrator::CompositeEffect>& primitives,
const std::function<void()>& completionCallback);
virtual HalResult<void> performPwleEffect(
const std::vector<hardware::vibrator::PrimitivePwle>& primitives,
const std::function<void()>& completionCallback);
protected:
// Shared pointer to allow CallbackScheduler to outlive this wrapper.
const std::shared_ptr<CallbackScheduler> mCallbackScheduler;
// Load and cache vibrator info, returning cached result is present.
HalResult<Capabilities> getCapabilities();
HalResult<std::vector<std::chrono::milliseconds>> getPrimitiveDurations();
// Request vibrator info to HAL skipping cache.
virtual HalResult<Capabilities> getCapabilitiesInternal() = 0;
virtual HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffectsInternal();
virtual HalResult<std::vector<hardware::vibrator::Braking>> getSupportedBrakingInternal();
virtual HalResult<std::vector<hardware::vibrator::CompositePrimitive>>
getSupportedPrimitivesInternal();
virtual HalResult<std::vector<std::chrono::milliseconds>> getPrimitiveDurationsInternal(
const std::vector<hardware::vibrator::CompositePrimitive>& supportedPrimitives);
virtual HalResult<std::chrono::milliseconds> getPrimitiveDelayMaxInternal();
virtual HalResult<std::chrono::milliseconds> getPrimitiveDurationMaxInternal();
virtual HalResult<int32_t> getCompositionSizeMaxInternal();
virtual HalResult<int32_t> getPwleSizeMaxInternal();
virtual HalResult<float> getMinFrequencyInternal();
virtual HalResult<float> getResonantFrequencyInternal();
virtual HalResult<float> getFrequencyResolutionInternal();
virtual HalResult<float> getQFactorInternal();
virtual HalResult<std::vector<float>> 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<CallbackScheduler> scheduler, sp<hardware::vibrator::IVibrator> handle,
std::function<HalResult<sp<hardware::vibrator::IVibrator>>()> reconnectFn =
[]() {
return HalResult<sp<hardware::vibrator::IVibrator>>::ok(
checkVintfService<hardware::vibrator::IVibrator>());
})
: HalWrapper(std::move(scheduler)),
mReconnectFn(reconnectFn),
mHandle(std::move(handle)) {}
virtual ~AidlHalWrapper() = default;
HalResult<void> ping() override final;
void tryReconnect() override final;
HalResult<void> on(std::chrono::milliseconds timeout,
const std::function<void()>& completionCallback) override final;
HalResult<void> off() override final;
HalResult<void> setAmplitude(float amplitude) override final;
HalResult<void> setExternalControl(bool enabled) override final;
HalResult<void> alwaysOnEnable(int32_t id, hardware::vibrator::Effect effect,
hardware::vibrator::EffectStrength strength) override final;
HalResult<void> alwaysOnDisable(int32_t id) override final;
HalResult<std::chrono::milliseconds> performEffect(
hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
const std::function<void()>& completionCallback) override final;
HalResult<std::chrono::milliseconds> performComposedEffect(
const std::vector<hardware::vibrator::CompositeEffect>& primitives,
const std::function<void()>& completionCallback) override final;
HalResult<void> performPwleEffect(
const std::vector<hardware::vibrator::PrimitivePwle>& primitives,
const std::function<void()>& completionCallback) override final;
protected:
HalResult<Capabilities> getCapabilitiesInternal() override final;
HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffectsInternal() override final;
HalResult<std::vector<hardware::vibrator::Braking>> getSupportedBrakingInternal()
override final;
HalResult<std::vector<hardware::vibrator::CompositePrimitive>> getSupportedPrimitivesInternal()
override final;
HalResult<std::vector<std::chrono::milliseconds>> getPrimitiveDurationsInternal(
const std::vector<hardware::vibrator::CompositePrimitive>& supportedPrimitives)
override final;
HalResult<std::chrono::milliseconds> getPrimitiveDelayMaxInternal() override final;
HalResult<std::chrono::milliseconds> getPrimitiveDurationMaxInternal() override final;
HalResult<int32_t> getCompositionSizeMaxInternal() override final;
HalResult<int32_t> getPwleSizeMaxInternal() override final;
HalResult<float> getMinFrequencyInternal() override final;
HalResult<float> getResonantFrequencyInternal() override final;
HalResult<float> getFrequencyResolutionInternal() override final;
HalResult<float> getQFactorInternal() override final;
HalResult<std::vector<float>> getMaxAmplitudesInternal() override final;
private:
const std::function<HalResult<sp<hardware::vibrator::IVibrator>>()> mReconnectFn;
std::mutex mHandleMutex;
sp<hardware::vibrator::IVibrator> mHandle GUARDED_BY(mHandleMutex);
sp<hardware::vibrator::IVibrator> getHal();
};
// Wrapper for the HDIL Vibrator HALs.
template <typename I>
class HidlHalWrapper : public HalWrapper {
public:
HidlHalWrapper(std::shared_ptr<CallbackScheduler> scheduler, sp<I> handle)
: HalWrapper(std::move(scheduler)), mHandle(std::move(handle)) {}
virtual ~HidlHalWrapper() = default;
HalResult<void> ping() override final;
void tryReconnect() override final;
HalResult<void> on(std::chrono::milliseconds timeout,
const std::function<void()>& completionCallback) override final;
HalResult<void> off() override final;
HalResult<void> setAmplitude(float amplitude) override final;
virtual HalResult<void> setExternalControl(bool enabled) override;
HalResult<void> alwaysOnEnable(int32_t id, hardware::vibrator::Effect effect,
hardware::vibrator::EffectStrength strength) override final;
HalResult<void> alwaysOnDisable(int32_t id) override final;
protected:
std::mutex mHandleMutex;
sp<I> mHandle GUARDED_BY(mHandleMutex);
virtual HalResult<Capabilities> getCapabilitiesInternal() override;
template <class T>
using perform_fn =
hardware::Return<void> (I::*)(T, hardware::vibrator::V1_0::EffectStrength,
hardware::vibrator::V1_0::IVibrator::perform_cb);
template <class T>
HalResult<std::chrono::milliseconds> performInternal(
perform_fn<T> performFn, sp<I> handle, T effect,
hardware::vibrator::EffectStrength strength,
const std::function<void()>& completionCallback);
sp<I> getHal();
};
// Wrapper for the HDIL Vibrator HAL v1.0.
class HidlHalWrapperV1_0 : public HidlHalWrapper<hardware::vibrator::V1_0::IVibrator> {
public:
HidlHalWrapperV1_0(std::shared_ptr<CallbackScheduler> scheduler,
sp<hardware::vibrator::V1_0::IVibrator> handle)
: HidlHalWrapper<hardware::vibrator::V1_0::IVibrator>(std::move(scheduler),
std::move(handle)) {}
virtual ~HidlHalWrapperV1_0() = default;
HalResult<std::chrono::milliseconds> performEffect(
hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
const std::function<void()>& completionCallback) override final;
};
// Wrapper for the HDIL Vibrator HAL v1.1.
class HidlHalWrapperV1_1 : public HidlHalWrapper<hardware::vibrator::V1_1::IVibrator> {
public:
HidlHalWrapperV1_1(std::shared_ptr<CallbackScheduler> scheduler,
sp<hardware::vibrator::V1_1::IVibrator> handle)
: HidlHalWrapper<hardware::vibrator::V1_1::IVibrator>(std::move(scheduler),
std::move(handle)) {}
virtual ~HidlHalWrapperV1_1() = default;
HalResult<std::chrono::milliseconds> performEffect(
hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
const std::function<void()>& completionCallback) override final;
};
// Wrapper for the HDIL Vibrator HAL v1.2.
class HidlHalWrapperV1_2 : public HidlHalWrapper<hardware::vibrator::V1_2::IVibrator> {
public:
HidlHalWrapperV1_2(std::shared_ptr<CallbackScheduler> scheduler,
sp<hardware::vibrator::V1_2::IVibrator> handle)
: HidlHalWrapper<hardware::vibrator::V1_2::IVibrator>(std::move(scheduler),
std::move(handle)) {}
virtual ~HidlHalWrapperV1_2() = default;
HalResult<std::chrono::milliseconds> performEffect(
hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
const std::function<void()>& completionCallback) override final;
};
// Wrapper for the HDIL Vibrator HAL v1.3.
class HidlHalWrapperV1_3 : public HidlHalWrapper<hardware::vibrator::V1_3::IVibrator> {
public:
HidlHalWrapperV1_3(std::shared_ptr<CallbackScheduler> scheduler,
sp<hardware::vibrator::V1_3::IVibrator> handle)
: HidlHalWrapper<hardware::vibrator::V1_3::IVibrator>(std::move(scheduler),
std::move(handle)) {}
virtual ~HidlHalWrapperV1_3() = default;
HalResult<void> setExternalControl(bool enabled) override final;
HalResult<std::chrono::milliseconds> performEffect(
hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
const std::function<void()>& completionCallback) override final;
protected:
HalResult<Capabilities> getCapabilitiesInternal() override final;
};
// -------------------------------------------------------------------------------------------------
}; // namespace vibrator
}; // namespace android
#endif // ANDROID_OS_VIBRATORHALWRAPPER_H