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

Commit 3c1c432b authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Create vibrator controller for Vibrator HALs"

parents c1c79d40 921b6980
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