Create CallbackScheduler for Vibrator HAL callbacks

This scheduler keeps a single thread looping and executing callbacks
after a delay. This mechanism is used to simulate the callbacks that
some Vibrator HALs do not support.

Bug: 153418251
Test: atest libvibratorservice_test
Change-Id: If19481dfe2eca662d33738a11257bd4509fe81ca
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index db27bd9..1420bf5 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -23,6 +23,7 @@
 
 #include <utils/Log.h>
 
+#include <vibratorservice/VibratorCallbackScheduler.h>
 #include <vibratorservice/VibratorHalWrapper.h>
 
 using android::hardware::vibrator::CompositeEffect;
@@ -46,10 +47,12 @@
 template <class T>
 HalResult<T> loadCached(const std::function<HalResult<T>()>& loadFn, std::optional<T>& cache) {
     if (cache.has_value()) {
-        return HalResult<T>::ok(cache.value());
+        // Return copy of cached value.
+        return HalResult<T>::ok(*cache);
     }
     HalResult<T> ret = loadFn();
     if (ret.isOk()) {
+        // Cache copy of returned value.
         cache.emplace(ret.value());
     }
     return ret;
@@ -62,27 +65,6 @@
     return castEffect >= *iter.begin() && castEffect <= *std::prev(iter.end());
 }
 
-template <class I, class T>
-using perform_fn = hardware::Return<void> (I::*)(T, V1_0::EffectStrength,
-                                                 V1_0::IVibrator::perform_cb);
-
-template <class I, class T>
-HalResult<milliseconds> perform(perform_fn<I, T> performFn, sp<I> handle, T effect,
-                                EffectStrength strength) {
-    V1_0::Status status;
-    int32_t lengthMs;
-    V1_0::IVibrator::perform_cb effectCallback = [&status, &lengthMs](V1_0::Status retStatus,
-                                                                      uint32_t retLengthMs) {
-        status = retStatus;
-        lengthMs = retLengthMs;
-    };
-
-    V1_0::EffectStrength effectStrength = static_cast<V1_0::EffectStrength>(strength);
-    auto result = std::invoke(performFn, handle, effect, effectStrength, effectCallback);
-
-    return HalResult<milliseconds>::fromReturn(result, status, milliseconds(lengthMs));
-}
-
 // -------------------------------------------------------------------------------------------------
 
 template <typename T>
@@ -179,7 +161,7 @@
 
 class HalCallbackWrapper : public Aidl::BnVibratorCallback {
 public:
-    HalCallbackWrapper(const std::function<void()>& completionCallback)
+    HalCallbackWrapper(std::function<void()> completionCallback)
           : mCompletionCallback(completionCallback) {}
 
     binder::Status onComplete() override {
@@ -200,8 +182,17 @@
 
 HalResult<void> AidlHalWrapper::on(milliseconds timeout,
                                    const std::function<void()>& completionCallback) {
-    auto cb = new HalCallbackWrapper(completionCallback);
-    return HalResult<void>::fromStatus(mHandle->on(timeout.count(), cb));
+    HalResult<Capabilities> capabilities = getCapabilities();
+    bool supportsCallback = capabilities.isOk() &&
+            static_cast<int32_t>(capabilities.value() & Capabilities::ON_CALLBACK);
+    auto cb = supportsCallback ? new HalCallbackWrapper(completionCallback) : nullptr;
+
+    auto ret = HalResult<void>::fromStatus(mHandle->on(timeout.count(), cb));
+    if (!supportsCallback && ret.isOk()) {
+        mCallbackScheduler->schedule(completionCallback, timeout);
+    }
+
+    return ret;
 }
 
 HalResult<void> AidlHalWrapper::off() {
@@ -227,39 +218,56 @@
 
 HalResult<Capabilities> AidlHalWrapper::getCapabilities() {
     std::lock_guard<std::mutex> lock(mCapabilitiesMutex);
-    static auto loadFn = [this]() {
-        int32_t capabilities = 0;
-        auto result = mHandle->getCapabilities(&capabilities);
-        return HalResult<Capabilities>::fromStatus(result, static_cast<Capabilities>(capabilities));
-    };
-    return loadCached<Capabilities>(loadFn, mCapabilities);
+    return loadCached<Capabilities>(std::bind(&AidlHalWrapper::getCapabilitiesInternal, this),
+                                    mCapabilities);
 }
 
 HalResult<std::vector<Effect>> AidlHalWrapper::getSupportedEffects() {
     std::lock_guard<std::mutex> lock(mSupportedEffectsMutex);
-    static auto loadFn = [this]() {
-        std::vector<Effect> supportedEffects;
-        auto result = mHandle->getSupportedEffects(&supportedEffects);
-        return HalResult<std::vector<Effect>>::fromStatus(result, supportedEffects);
-    };
-    return loadCached<std::vector<Effect>>(loadFn, mSupportedEffects);
+    return loadCached<std::vector<Effect>>(std::bind(&AidlHalWrapper::getSupportedEffectsInternal,
+                                                     this),
+                                           mSupportedEffects);
 }
 
 HalResult<milliseconds> AidlHalWrapper::performEffect(
         Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+    HalResult<Capabilities> capabilities = getCapabilities();
+    bool supportsCallback = capabilities.isOk() &&
+            static_cast<int32_t>(capabilities.value() & Capabilities::PERFORM_CALLBACK);
+    auto cb = supportsCallback ? new HalCallbackWrapper(completionCallback) : nullptr;
+
     int32_t lengthMs;
-    auto cb = new HalCallbackWrapper(completionCallback);
     auto result = mHandle->perform(effect, strength, cb, &lengthMs);
-    return HalResult<milliseconds>::fromStatus(result, milliseconds(lengthMs));
+    milliseconds length = milliseconds(lengthMs);
+
+    auto ret = HalResult<milliseconds>::fromStatus(result, length);
+    if (!supportsCallback && ret.isOk()) {
+        mCallbackScheduler->schedule(completionCallback, length);
+    }
+
+    return ret;
 }
 
 HalResult<void> AidlHalWrapper::performComposedEffect(
         const std::vector<CompositeEffect>& primitiveEffects,
         const std::function<void()>& completionCallback) {
+    // This method should always support callbacks, so no need to double check.
     auto cb = new HalCallbackWrapper(completionCallback);
     return HalResult<void>::fromStatus(mHandle->compose(primitiveEffects, cb));
 }
 
+HalResult<Capabilities> AidlHalWrapper::getCapabilitiesInternal() {
+    int32_t capabilities = 0;
+    auto result = mHandle->getCapabilities(&capabilities);
+    return HalResult<Capabilities>::fromStatus(result, static_cast<Capabilities>(capabilities));
+}
+
+HalResult<std::vector<Effect>> AidlHalWrapper::getSupportedEffectsInternal() {
+    std::vector<Effect> supportedEffects;
+    auto result = mHandle->getSupportedEffects(&supportedEffects);
+    return HalResult<std::vector<Effect>>::fromStatus(result, supportedEffects);
+}
+
 // -------------------------------------------------------------------------------------------------
 
 HalResult<void> HidlHalWrapperV1_0::ping() {
@@ -267,10 +275,14 @@
     return HalResult<void>::fromReturn(result);
 }
 
-HalResult<void> HidlHalWrapperV1_0::on(milliseconds timeout, const std::function<void()>&) {
+HalResult<void> HidlHalWrapperV1_0::on(milliseconds timeout,
+                                       const std::function<void()>& completionCallback) {
     auto result = mHandleV1_0->on(timeout.count());
-    auto status = result.withDefault(V1_0::Status::UNKNOWN_ERROR);
-    return HalResult<void>::fromStatus(status);
+    auto ret = HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
+    if (ret.isOk()) {
+        mCallbackScheduler->schedule(completionCallback, timeout);
+    }
+    return ret;
 }
 
 HalResult<void> HidlHalWrapperV1_0::off() {
@@ -309,11 +321,10 @@
     return HalResult<std::vector<Effect>>::unsupported();
 }
 
-HalResult<milliseconds> HidlHalWrapperV1_0::performEffect(Effect effect, EffectStrength strength,
-                                                          const std::function<void()>&) {
+HalResult<milliseconds> HidlHalWrapperV1_0::performEffect(
+        Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
     if (isStaticCastValid<V1_0::Effect>(effect)) {
-        V1_0::Effect e = static_cast<V1_0::Effect>(effect);
-        return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength);
+        return performInternalV1_0(effect, strength, completionCallback);
     }
 
     ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
@@ -334,17 +345,44 @@
     return HalResult<Capabilities>::fromReturn(result, capabilities);
 }
 
+template <class I, class T>
+HalResult<milliseconds> HidlHalWrapperV1_0::performInternal(
+        perform_fn<I, T> performFn, sp<I> handle, T effect, EffectStrength strength,
+        const std::function<void()>& completionCallback) {
+    V1_0::Status status;
+    int32_t lengthMs;
+    auto effectCallback = [&status, &lengthMs](V1_0::Status retStatus, uint32_t retLengthMs) {
+        status = retStatus;
+        lengthMs = retLengthMs;
+    };
+
+    V1_0::EffectStrength effectStrength = static_cast<V1_0::EffectStrength>(strength);
+    auto result = std::invoke(performFn, handle, effect, effectStrength, effectCallback);
+    milliseconds length = milliseconds(lengthMs);
+
+    auto ret = HalResult<milliseconds>::fromReturn(result, status, length);
+    if (ret.isOk()) {
+        mCallbackScheduler->schedule(completionCallback, length);
+    }
+
+    return ret;
+}
+
+HalResult<milliseconds> HidlHalWrapperV1_0::performInternalV1_0(
+        Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+    V1_0::Effect e = static_cast<V1_0::Effect>(effect);
+    return performInternal(&V1_0::IVibrator::perform, mHandleV1_0, e, strength, completionCallback);
+}
+
 // -------------------------------------------------------------------------------------------------
 
-HalResult<milliseconds> HidlHalWrapperV1_1::performEffect(Effect effect, EffectStrength strength,
-                                                          const std::function<void()>&) {
+HalResult<milliseconds> HidlHalWrapperV1_1::performEffect(
+        Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
     if (isStaticCastValid<V1_0::Effect>(effect)) {
-        V1_0::Effect e = static_cast<V1_0::Effect>(effect);
-        return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength);
+        return performInternalV1_0(effect, strength, completionCallback);
     }
     if (isStaticCastValid<V1_1::Effect_1_1>(effect)) {
-        V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect);
-        return perform(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength);
+        return performInternalV1_1(effect, strength, completionCallback);
     }
 
     ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
@@ -352,21 +390,25 @@
     return HalResult<milliseconds>::unsupported();
 }
 
+HalResult<milliseconds> HidlHalWrapperV1_1::performInternalV1_1(
+        Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+    V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect);
+    return performInternal(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength,
+                           completionCallback);
+}
+
 // -------------------------------------------------------------------------------------------------
 
-HalResult<milliseconds> HidlHalWrapperV1_2::performEffect(Effect effect, EffectStrength strength,
-                                                          const std::function<void()>&) {
+HalResult<milliseconds> HidlHalWrapperV1_2::performEffect(
+        Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
     if (isStaticCastValid<V1_0::Effect>(effect)) {
-        V1_0::Effect e = static_cast<V1_0::Effect>(effect);
-        return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength);
+        return performInternalV1_0(effect, strength, completionCallback);
     }
     if (isStaticCastValid<V1_1::Effect_1_1>(effect)) {
-        V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect);
-        return perform(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength);
+        return performInternalV1_1(effect, strength, completionCallback);
     }
     if (isStaticCastValid<V1_2::Effect>(effect)) {
-        V1_2::Effect e = static_cast<V1_2::Effect>(effect);
-        return perform(&V1_2::IVibrator::perform_1_2, mHandleV1_2, e, strength);
+        return performInternalV1_2(effect, strength, completionCallback);
     }
 
     ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
@@ -374,6 +416,13 @@
     return HalResult<milliseconds>::unsupported();
 }
 
+HalResult<milliseconds> HidlHalWrapperV1_2::performInternalV1_2(
+        Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+    V1_2::Effect e = static_cast<V1_2::Effect>(effect);
+    return performInternal(&V1_2::IVibrator::perform_1_2, mHandleV1_2, e, strength,
+                           completionCallback);
+}
+
 // -------------------------------------------------------------------------------------------------
 
 HalResult<void> HidlHalWrapperV1_3::setExternalControl(bool enabled) {
@@ -381,23 +430,19 @@
     return HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
 }
 
-HalResult<milliseconds> HidlHalWrapperV1_3::performEffect(Effect effect, EffectStrength strength,
-                                                          const std::function<void()>&) {
+HalResult<milliseconds> HidlHalWrapperV1_3::performEffect(
+        Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
     if (isStaticCastValid<V1_0::Effect>(effect)) {
-        V1_0::Effect e = static_cast<V1_0::Effect>(effect);
-        return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength);
+        return performInternalV1_0(effect, strength, completionCallback);
     }
     if (isStaticCastValid<V1_1::Effect_1_1>(effect)) {
-        V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect);
-        return perform(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength);
+        return performInternalV1_1(effect, strength, completionCallback);
     }
     if (isStaticCastValid<V1_2::Effect>(effect)) {
-        V1_2::Effect e = static_cast<V1_2::Effect>(effect);
-        return perform(&V1_2::IVibrator::perform_1_2, mHandleV1_2, e, strength);
+        return performInternalV1_2(effect, strength, completionCallback);
     }
     if (isStaticCastValid<V1_3::Effect>(effect)) {
-        V1_3::Effect e = static_cast<V1_3::Effect>(effect);
-        return perform(&V1_3::IVibrator::perform_1_3, mHandleV1_3, e, strength);
+        return performInternalV1_3(effect, strength, completionCallback);
     }
 
     ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
@@ -418,6 +463,13 @@
     return HalResult<Capabilities>::fromReturn(result, capabilities);
 }
 
+HalResult<milliseconds> HidlHalWrapperV1_3::performInternalV1_3(
+        Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+    V1_3::Effect e = static_cast<V1_3::Effect>(effect);
+    return performInternal(&V1_3::IVibrator::perform_1_3, mHandleV1_3, e, strength,
+                           completionCallback);
+}
+
 // -------------------------------------------------------------------------------------------------
 
 }; // namespace vibrator