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

Commit 921b6980 authored by Lais Andrade's avatar Lais Andrade
Browse files

Create vibrator controller for Vibrator HALs

Create vibrator::HalController, a vibrator::HalWrapper that manages
the connection to the underlying Vibrator HAL service available and is
responsible for reconnecting after any api call fails.

This controller also has a single vibrator::CallbackScheduler instance
that outlives the connection to the HAL and is responsible for
triggering the callbacks when the HAL does not support them. It makes
sure the callbacks will not be affected during reconnection with the HAL
service.

Bug: 153418251
Test: atest libvibratorservice_test
Change-Id: Ic6d9671468ee18d0aff4e8a80b501c7bb110477d
parent 10d9dc7a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ cc_library_shared {

    srcs: [
        "VibratorCallbackScheduler.cpp",
        "VibratorHalController.cpp",
        "VibratorHalWrapper.cpp",
    ],

+224 −0
Original line number Diff line number Diff line
/*
 * 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.
 */

#define LOG_TAG "VibratorHalController"

#include <android/hardware/vibrator/1.3/IVibrator.h>
#include <android/hardware/vibrator/IVibrator.h>
#include <binder/IServiceManager.h>
#include <hardware/vibrator.h>

#include <utils/Log.h>

#include <vibratorservice/VibratorCallbackScheduler.h>
#include <vibratorservice/VibratorHalController.h>
#include <vibratorservice/VibratorHalWrapper.h>

using android::hardware::vibrator::CompositeEffect;
using android::hardware::vibrator::Effect;
using android::hardware::vibrator::EffectStrength;

using std::chrono::milliseconds;

namespace V1_0 = android::hardware::vibrator::V1_0;
namespace V1_1 = android::hardware::vibrator::V1_1;
namespace V1_2 = android::hardware::vibrator::V1_2;
namespace V1_3 = android::hardware::vibrator::V1_3;
namespace Aidl = android::hardware::vibrator;

namespace android {

namespace vibrator {

// -------------------------------------------------------------------------------------------------

template <typename T>
using hal_connect_fn = std::function<sp<T>()>;

template <typename T>
sp<T> connectToHal(bool* halExists, const hal_connect_fn<T>& connectFn, const char* halName) {
    if (!*halExists) {
        return nullptr;
    }
    sp<T> hal = connectFn();
    if (hal) {
        ALOGV("Successfully connected to Vibrator HAL %s service.", halName);
    } else {
        ALOGV("Vibrator HAL %s service not available.", halName);
        *halExists = false;
    }
    return hal;
}

sp<Aidl::IVibrator> connectToAidl() {
    static bool gHalExists = true;
    static hal_connect_fn<Aidl::IVibrator> connectFn = []() {
        return waitForVintfService<Aidl::IVibrator>();
    };
    return connectToHal(&gHalExists, connectFn, "AIDL");
}

sp<V1_0::IVibrator> connectToHidl() {
    static bool gHalExists = true;
    static hal_connect_fn<V1_0::IVibrator> connectFn = []() {
        return V1_0::IVibrator::getService();
    };
    return connectToHal(&gHalExists, connectFn, "v1.0");
}

// -------------------------------------------------------------------------------------------------

std::shared_ptr<HalWrapper> HalConnector::connect(std::shared_ptr<CallbackScheduler> scheduler) {
    sp<Aidl::IVibrator> aidlHal = connectToAidl();
    if (aidlHal) {
        return std::make_shared<AidlHalWrapper>(std::move(scheduler), aidlHal);
    }
    sp<V1_0::IVibrator> halV1_0 = connectToHidl();
    if (halV1_0 == nullptr) {
        // No Vibrator HAL service available.
        return nullptr;
    }
    sp<V1_3::IVibrator> halV1_3 = V1_3::IVibrator::castFrom(halV1_0);
    if (halV1_3) {
        ALOGV("Successfully converted to Vibrator HAL v1.3 service.");
        return std::make_shared<HidlHalWrapperV1_3>(std::move(scheduler), halV1_3);
    }
    sp<V1_2::IVibrator> halV1_2 = V1_2::IVibrator::castFrom(halV1_0);
    if (halV1_2) {
        ALOGV("Successfully converted to Vibrator HAL v1.2 service.");
        return std::make_shared<HidlHalWrapperV1_2>(std::move(scheduler), halV1_2);
    }
    sp<V1_1::IVibrator> halV1_1 = V1_1::IVibrator::castFrom(halV1_0);
    if (halV1_1) {
        ALOGV("Successfully converted to Vibrator HAL v1.1 service.");
        return std::make_shared<HidlHalWrapperV1_1>(std::move(scheduler), halV1_1);
    }
    return std::make_shared<HidlHalWrapperV1_0>(std::move(scheduler), halV1_0);
}

// -------------------------------------------------------------------------------------------------

template <typename T>
HalResult<T> HalController::processHalResult(HalResult<T> result, const char* functionName) {
    if (result.isFailed()) {
        ALOGE("%s failed: Vibrator HAL not available", functionName);
        std::lock_guard<std::mutex> lock(mConnectedHalMutex);
        // Drop HAL handle. This will force future api calls to reconnect.
        mConnectedHal = nullptr;
    }
    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) {
            mConnectedHal = mHalConnector->connect(mCallbackScheduler);
        }
        hal = mConnectedHal;
    }
    if (hal) {
        return processHalResult(halFn(hal), functionName);
    }

    ALOGV("Skipped %s because Vibrator HAL is not available", functionName);
    return HalResult<T>::unsupported();
}

// -------------------------------------------------------------------------------------------------

HalResult<void> HalController::ping() {
    hal_fn<void> pingFn = [](std::shared_ptr<HalWrapper> hal) { return hal->ping(); };
    return apply(pingFn, "ping");
}

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(int32_t 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<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<void> HalController::performComposedEffect(
        const std::vector<CompositeEffect>& primitiveEffects,
        const std::function<void()>& completionCallback) {
    hal_fn<void> performComposedEffectFn = [&](std::shared_ptr<HalWrapper> hal) {
        return hal->performComposedEffect(primitiveEffects, completionCallback);
    };
    return apply(performComposedEffectFn, "performComposedEffect");
}

}; // namespace vibrator

}; // namespace android
+0 −27
Original line number Diff line number Diff line
@@ -67,21 +67,6 @@ bool isStaticCastValid(Effect effect) {

// -------------------------------------------------------------------------------------------------

template <typename T>
HalResult<T> HalResult<T>::ok(T value) {
    return HalResult(value);
}

template <typename T>
HalResult<T> HalResult<T>::failed() {
    return HalResult(/* unsupported= */ false);
}

template <typename T>
HalResult<T> HalResult<T>::unsupported() {
    return HalResult(/* unsupported= */ true);
}

template <typename T>
HalResult<T> HalResult<T>::fromStatus(binder::Status status, T data) {
    if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) {
@@ -119,18 +104,6 @@ HalResult<T> HalResult<T>::fromReturn(hardware::Return<R>& ret, V1_0::Status sta

// -------------------------------------------------------------------------------------------------

HalResult<void> HalResult<void>::ok() {
    return HalResult();
}

HalResult<void> HalResult<void>::failed() {
    return HalResult(/* failed= */ true);
}

HalResult<void> HalResult<void>::unsupported() {
    return HalResult(/* failed= */ false, /* unsupported= */ true);
}

HalResult<void> HalResult<void>::fromStatus(binder::Status status) {
    if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) {
        return HalResult<void>::unsupported();
+98 −0
Original line number Diff line number Diff line
/*
 * 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_VIBRATORHALCONTROLLER_H
#define ANDROID_OS_VIBRATORHALCONTROLLER_H

#include <android-base/thread_annotations.h>
#include <android/hardware/vibrator/IVibrator.h>

#include <vibratorservice/VibratorCallbackScheduler.h>
#include <vibratorservice/VibratorHalWrapper.h>

namespace android {

namespace vibrator {

// Handles the connection to he underlying HAL implementation available.
class HalConnector {
public:
    HalConnector() = default;
    virtual ~HalConnector() = default;

    virtual std::shared_ptr<HalWrapper> connect(std::shared_ptr<CallbackScheduler> scheduler);
};

// Controller for Vibrator HAL handle.
// This relies on HalConnector to connect to the underlying Vibrator HAL service and reconnects to
// it after each failed api call. This also ensures connecting to the service is thread-safe.
class HalController : public HalWrapper {
public:
    HalController()
          : HalController(std::make_unique<HalConnector>(), std::make_shared<CallbackScheduler>()) {
    }
    HalController(std::unique_ptr<HalConnector> halConnector,
                  std::shared_ptr<CallbackScheduler> callbackScheduler)
          : HalWrapper(std::move(callbackScheduler)),
            mHalConnector(std::move(halConnector)),
            mConnectedHal(nullptr) {}
    virtual ~HalController() = default;

    HalResult<void> ping() final override;

    HalResult<void> on(std::chrono::milliseconds timeout,
                       const std::function<void()>& completionCallback) final override;
    HalResult<void> off() final override;

    HalResult<void> setAmplitude(int32_t 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;

    HalResult<Capabilities> getCapabilities() final override;
    HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffects() final override;

    HalResult<std::chrono::milliseconds> performEffect(
            hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
            const std::function<void()>& completionCallback) final override;

    HalResult<void> performComposedEffect(
            const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
            const std::function<void()>& completionCallback) final override;

private:
    std::unique_ptr<HalConnector> mHalConnector;
    std::mutex mConnectedHalMutex;
    // Shared pointer to allow local copies to be used by different threads.
    std::shared_ptr<HalWrapper> mConnectedHal GUARDED_BY(mConnectedHalMutex);

    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);
};

}; // namespace vibrator

}; // namespace android

#endif // ANDROID_OS_VIBRATORHALCONTROLLER_H
+14 −15
Original line number Diff line number Diff line
@@ -33,9 +33,9 @@ namespace vibrator {
template <typename T>
class HalResult {
public:
    static HalResult<T> ok(T value);
    static HalResult<T> failed();
    static HalResult<T> unsupported();
    static HalResult<T> ok(T value) { return HalResult(value); }
    static HalResult<T> failed() { return HalResult(/* unsupported= */ false); }
    static HalResult<T> unsupported() { return HalResult(/* unsupported= */ true); }

    static HalResult<T> fromStatus(binder::Status status, T data);
    static HalResult<T> fromStatus(hardware::vibrator::V1_0::Status status, T data);
@@ -65,9 +65,11 @@ private:
template <>
class HalResult<void> {
public:
    static HalResult<void> ok();
    static HalResult<void> failed();
    static HalResult<void> unsupported();
    static HalResult<void> ok() { return HalResult(); }
    static HalResult<void> failed() { return HalResult(/* failed= */ true); }
    static HalResult<void> unsupported() {
        return HalResult(/* failed= */ false, /* unsupported= */ true);
    }

    static HalResult<void> fromStatus(binder::Status status);
    static HalResult<void> fromStatus(hardware::vibrator::V1_0::Status status);
@@ -262,9 +264,8 @@ protected:
class HidlHalWrapperV1_1 : public HidlHalWrapperV1_0 {
public:
    HidlHalWrapperV1_1(std::shared_ptr<CallbackScheduler> scheduler,
                       sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
          : HidlHalWrapperV1_0(std::move(scheduler), handleV1_0),
            mHandleV1_1(hardware::vibrator::V1_1::IVibrator::castFrom(handleV1_0)) {}
                       sp<hardware::vibrator::V1_1::IVibrator> handle)
          : HidlHalWrapperV1_0(std::move(scheduler), handle), mHandleV1_1(handle) {}
    virtual ~HidlHalWrapperV1_1() = default;

    virtual HalResult<std::chrono::milliseconds> performEffect(
@@ -283,9 +284,8 @@ protected:
class HidlHalWrapperV1_2 : public HidlHalWrapperV1_1 {
public:
    HidlHalWrapperV1_2(std::shared_ptr<CallbackScheduler> scheduler,
                       sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
          : HidlHalWrapperV1_1(std::move(scheduler), handleV1_0),
            mHandleV1_2(hardware::vibrator::V1_2::IVibrator::castFrom(handleV1_0)) {}
                       sp<hardware::vibrator::V1_2::IVibrator> handle)
          : HidlHalWrapperV1_1(std::move(scheduler), handle), mHandleV1_2(handle) {}
    virtual ~HidlHalWrapperV1_2() = default;

    virtual HalResult<std::chrono::milliseconds> performEffect(
@@ -304,9 +304,8 @@ protected:
class HidlHalWrapperV1_3 : public HidlHalWrapperV1_2 {
public:
    HidlHalWrapperV1_3(std::shared_ptr<CallbackScheduler> scheduler,
                       sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
          : HidlHalWrapperV1_2(std::move(scheduler), handleV1_0),
            mHandleV1_3(hardware::vibrator::V1_3::IVibrator::castFrom(handleV1_0)) {}
                       sp<hardware::vibrator::V1_3::IVibrator> handle)
          : HidlHalWrapperV1_2(std::move(scheduler), handle), mHandleV1_3(handle) {}
    virtual ~HidlHalWrapperV1_3() = default;

    virtual HalResult<void> setExternalControl(bool enabled) override;
Loading