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

Commit f20b1449 authored by Lais Andrade's avatar Lais Andrade
Browse files

Introduce controller for VibratorManager HAL

This controller will automatically reconnect to IVibratorManager when
HAL service fails, and also falls back to legacy VibratorManager when
the HAL service is not available on the device.

This change also simplifies the HalConnector logic in both vibrator
controllers.

Bug: 167946816
Test: atest libvibratorservice_test
Change-Id: I709227cbb2fb2e1a0fcac32676182d6c9baded88
parent 98c97036
Loading
Loading
Loading
Loading
+4 −4
Original line number Original line Diff line number Diff line
@@ -46,7 +46,7 @@ namespace vibrator {


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


std::shared_ptr<HalWrapper> HalConnector::connect(std::shared_ptr<CallbackScheduler> scheduler) {
std::shared_ptr<HalWrapper> connectHal(std::shared_ptr<CallbackScheduler> scheduler) {
    static bool gHalExists = true;
    static bool gHalExists = true;
    if (!gHalExists) {
    if (!gHalExists) {
        // We already tried to connect to all of the vibrator HAL versions and none was available.
        // We already tried to connect to all of the vibrator HAL versions and none was available.
@@ -106,7 +106,7 @@ HalResult<T> HalController::apply(HalController::hal_fn<T>& halFn, const char* f
        std::lock_guard<std::mutex> lock(mConnectedHalMutex);
        std::lock_guard<std::mutex> lock(mConnectedHalMutex);
        if (mConnectedHal == nullptr) {
        if (mConnectedHal == nullptr) {
            // Init was never called, so connect to HAL for the first time during this call.
            // Init was never called, so connect to HAL for the first time during this call.
            mConnectedHal = mHalConnector->connect(mCallbackScheduler);
            mConnectedHal = mConnector(mCallbackScheduler);


            if (mConnectedHal == nullptr) {
            if (mConnectedHal == nullptr) {
                ALOGV("Skipped %s because Vibrator HAL is not available", functionName);
                ALOGV("Skipped %s because Vibrator HAL is not available", functionName);
@@ -129,7 +129,7 @@ HalResult<T> HalController::apply(HalController::hal_fn<T>& halFn, const char* f
bool HalController::init() {
bool HalController::init() {
    std::lock_guard<std::mutex> lock(mConnectedHalMutex);
    std::lock_guard<std::mutex> lock(mConnectedHalMutex);
    if (mConnectedHal == nullptr) {
    if (mConnectedHal == nullptr) {
        mConnectedHal = mHalConnector->connect(mCallbackScheduler);
        mConnectedHal = mConnector(mCallbackScheduler);
    }
    }
    return mConnectedHal != nullptr;
    return mConnectedHal != nullptr;
}
}
@@ -142,7 +142,7 @@ HalResult<void> HalController::ping() {
void HalController::tryReconnect() {
void HalController::tryReconnect() {
    std::lock_guard<std::mutex> lock(mConnectedHalMutex);
    std::lock_guard<std::mutex> lock(mConnectedHalMutex);
    if (mConnectedHal == nullptr) {
    if (mConnectedHal == nullptr) {
        mConnectedHal = mHalConnector->connect(mCallbackScheduler);
        mConnectedHal = mConnector(mCallbackScheduler);
    } else {
    } else {
        mConnectedHal->tryReconnect();
        mConnectedHal->tryReconnect();
    }
    }
+149 −0
Original line number Original line 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 "VibratorManagerHalController"

#include <utils/Log.h>

#include <vibratorservice/VibratorManagerHalController.h>

namespace Aidl = android::hardware::vibrator;

namespace android {

namespace vibrator {

std::shared_ptr<ManagerHalWrapper> connectHal(std::shared_ptr<CallbackScheduler> scheduler) {
    static bool gHalExists = true;
    if (gHalExists) {
        sp<Aidl::IVibratorManager> hal = waitForVintfService<Aidl::IVibratorManager>();
        if (hal) {
            ALOGV("Successfully connected to VibratorManager HAL AIDL service.");
            return std::make_shared<AidlManagerHalWrapper>(std::move(scheduler), aidlHal);
        }
    }

    gHalExists = false;
    return std::make_shared<LegacyManagerHalWrapper>();
}

static constexpr int MAX_RETRIES = 1;

template <typename T>
HalResult<T> ManagerHalController::processHalResult(HalResult<T> result, const char* functionName) {
    if (result.isFailed()) {
        ALOGE("%s failed: %s", functionName, result.errorMessage());
        std::lock_guard<std::mutex> lock(mConnectedHalMutex);
        mConnectedHal->tryReconnect();
    }
    return result;
}

template <typename T>
HalResult<T> ManagerHalController::apply(ManagerHalController::hal_fn<T>& halFn,
                                         const char* functionName) {
    std::shared_ptr<ManagerHalWrapper> hal = nullptr;
    {
        std::lock_guard<std::mutex> lock(mConnectedHalMutex);
        if (mConnectedHal == nullptr) {
            // Init was never called, so connect to HAL for the first time during this call.
            mConnectedHal = mConnector(mCallbackScheduler);

            if (mConnectedHal == nullptr) {
                ALOGV("Skipped %s because VibratorManager HAL is not available", functionName);
                return HalResult<T>::unsupported();
            }
        }
        hal = mConnectedHal;
    }

    HalResult<T> ret = processHalResult(halFn(hal), functionName);
    for (int i = 0; i < MAX_RETRIES && ret.isFailed(); i++) {
        ret = processHalResult(halFn(hal), functionName);
    }

    return ret;
}

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

bool ManagerHalController::init() {
    std::lock_guard<std::mutex> lock(mConnectedHalMutex);
    if (mConnectedHal == nullptr) {
        mConnectedHal = mConnector(mCallbackScheduler);
    }
    return mConnectedHal != nullptr;
}

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

void ManagerHalController::tryReconnect() {
    std::lock_guard<std::mutex> lock(mConnectedHalMutex);
    if (mConnectedHal == nullptr) {
        mConnectedHal = mConnector(mCallbackScheduler);
    } else {
        mConnectedHal->tryReconnect();
    }
}

HalResult<ManagerCapabilities> ManagerHalController::getCapabilities() {
    hal_fn<ManagerCapabilities> getCapabilitiesFn = [](std::shared_ptr<ManagerHalWrapper> hal) {
        return hal->getCapabilities();
    };
    return apply(getCapabilitiesFn, "getCapabilities");
}

HalResult<std::vector<int32_t>> ManagerHalController::getVibratorIds() {
    hal_fn<std::vector<int32_t>> getVibratorIdsFn = [](std::shared_ptr<ManagerHalWrapper> hal) {
        return hal->getVibratorIds();
    };
    return apply(getVibratorIdsFn, "getVibratorIds");
}

HalResult<std::shared_ptr<HalController>> ManagerHalController::getVibrator(int32_t id) {
    hal_fn<std::shared_ptr<HalController>> getVibratorFn =
            [&](std::shared_ptr<ManagerHalWrapper> hal) { return hal->getVibrator(id); };
    return apply(getVibratorFn, "getVibrator");
}

HalResult<void> ManagerHalController::prepareSynced(const std::vector<int32_t>& ids) {
    hal_fn<void> prepareSyncedFn = [&](std::shared_ptr<ManagerHalWrapper> hal) {
        return hal->prepareSynced(ids);
    };
    return apply(prepareSyncedFn, "prepareSynced");
}

HalResult<void> ManagerHalController::triggerSynced(
        const std::function<void()>& completionCallback) {
    hal_fn<void> triggerSyncedFn = [&](std::shared_ptr<ManagerHalWrapper> hal) {
        return hal->triggerSynced(completionCallback);
    };
    return apply(triggerSyncedFn, "triggerSynced");
}

HalResult<void> ManagerHalController::cancelSynced() {
    hal_fn<void> cancelSyncedFn = [](std::shared_ptr<ManagerHalWrapper> hal) {
        return hal->cancelSynced();
    };
    return apply(cancelSyncedFn, "cancelSynced");
}

}; // namespace vibrator

}; // namespace android
+8 −7
Original line number Original line Diff line number Diff line
@@ -72,11 +72,11 @@ HalResult<void> LegacyManagerHalWrapper::cancelSynced() {


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


std::shared_ptr<HalWrapper> AidlManagerHalWrapper::ManagedHalConnector::connect(
std::shared_ptr<HalWrapper> AidlManagerHalWrapper::connectToVibrator(
        std::shared_ptr<CallbackScheduler> callbackScheduler) {
        int32_t vibratorId, std::shared_ptr<CallbackScheduler> callbackScheduler) {
    std::function<HalResult<sp<Aidl::IVibrator>>()> reconnectFn = [&]() {
    std::function<HalResult<sp<Aidl::IVibrator>>()> reconnectFn = [=]() {
        sp<Aidl::IVibrator> vibrator;
        sp<Aidl::IVibrator> vibrator;
        auto result = this->mManager->getHal()->getVibrator(this->mVibratorId, &vibrator);
        auto result = this->getHal()->getVibrator(vibratorId, &vibrator);
        return HalResult<sp<Aidl::IVibrator>>::fromStatus(result, vibrator);
        return HalResult<sp<Aidl::IVibrator>>::fromStatus(result, vibrator);
    };
    };
    auto result = reconnectFn();
    auto result = reconnectFn();
@@ -133,9 +133,10 @@ HalResult<std::vector<int32_t>> AidlManagerHalWrapper::getVibratorIds() {
        // Cache copy of returned value and the individual controllers.
        // Cache copy of returned value and the individual controllers.
        mVibratorIds.emplace(ret.value());
        mVibratorIds.emplace(ret.value());
        for (auto& id : ids) {
        for (auto& id : ids) {
            auto connector = std::make_unique<ManagedHalConnector>(this, id);
            HalController::Connector connector = [&, id](auto scheduler) {
            auto controller =
                return this->connectToVibrator(id, scheduler);
                    std::make_unique<HalController>(std::move(connector), mCallbackScheduler);
            };
            auto controller = std::make_unique<HalController>(mCallbackScheduler, connector);
            mVibrators[id] = std::move(controller);
            mVibrators[id] = std::move(controller);
        }
        }
    }
    }
+10 −17
Original line number Original line Diff line number Diff line
@@ -27,27 +27,20 @@ namespace android {


namespace vibrator {
namespace vibrator {


// Handles the connection to he underlying HAL implementation available.
std::shared_ptr<HalWrapper> connectHal(std::shared_ptr<CallbackScheduler> scheduler);
class HalConnector {
public:
    HalConnector() = default;
    virtual ~HalConnector() = default;

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


// Controller for Vibrator HAL handle.
// Controller for Vibrator HAL handle.
// This relies on HalConnector to connect to the underlying Vibrator HAL service and reconnects to
// This relies on a given Connector to connect to the underlying Vibrator HAL service and reconnects
// it after each failed api call. This also ensures connecting to the service is thread-safe.
// after each failed api call. This also ensures connecting to the service is thread-safe.
class HalController : public HalWrapper {
class HalController : public HalWrapper {
public:
public:
    HalController()
    using Connector =
          : HalController(std::make_unique<HalConnector>(), std::make_shared<CallbackScheduler>()) {
            std::function<std::shared_ptr<HalWrapper>(std::shared_ptr<CallbackScheduler>)>;
    }

    HalController(std::unique_ptr<HalConnector> halConnector,
    HalController() : HalController(std::make_shared<CallbackScheduler>(), &connectHal) {}
                  std::shared_ptr<CallbackScheduler> callbackScheduler)
    HalController(std::shared_ptr<CallbackScheduler> callbackScheduler, Connector connector)
          : HalWrapper(std::move(callbackScheduler)),
          : HalWrapper(std::move(callbackScheduler)),
            mHalConnector(std::move(halConnector)),
            mConnector(connector),
            mConnectedHal(nullptr) {}
            mConnectedHal(nullptr) {}
    virtual ~HalController() = default;
    virtual ~HalController() = default;


@@ -89,7 +82,7 @@ public:
            const std::function<void()>& completionCallback) final override;
            const std::function<void()>& completionCallback) final override;


private:
private:
    std::unique_ptr<HalConnector> mHalConnector;
    Connector mConnector;
    std::mutex mConnectedHalMutex;
    std::mutex mConnectedHalMutex;
    // Shared pointer to allow local copies to be used by different threads.
    // Shared pointer to allow local copies to be used by different threads.
    std::shared_ptr<HalWrapper> mConnectedHal GUARDED_BY(mConnectedHalMutex);
    std::shared_ptr<HalWrapper> mConnectedHal GUARDED_BY(mConnectedHalMutex);
+85 −0
Original line number Original line 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_VIBRATOR_MANAGER_HAL_CONTROLLER_H
#define ANDROID_OS_VIBRATOR_MANAGER_HAL_CONTROLLER_H

#include <android/hardware/vibrator/IVibratorManager.h>
#include <vibratorservice/VibratorHalController.h>
#include <unordered_map>

namespace android {

namespace vibrator {

std::shared_ptr<ManagerHalWrapper> connectManagerHal(std::shared_ptr<CallbackScheduler> scheduler);

// Controller for VibratorManager HAL handle.
class ManagerHalController : public ManagerHalWrapper {
public:
    using Connector =
            std::function<std::shared_ptr<ManagerHalWrapper>(std::shared_ptr<CallbackScheduler>)>;

    ManagerHalController()
          : ManagerHalController(std::make_shared<CallbackScheduler>(), &connectManagerHal) {}
    ManagerHalController(std::shared_ptr<CallbackScheduler> callbackScheduler, Connector connector)
          : mConnector(connector), mConnectedHal(nullptr) {}
    virtual ~ManagerHalController() = default;

    /* Connects to the HAL service, possibly waiting for the registered service to
     * become available. This will automatically be called at the first API usage if it was not
     * manually called beforehand. Calling this manually during the setup phase can avoid slowing
     * the first API call later on. This will fallback to a legacy manager implementation if the
     * service is not available.
     */
    virtual void init();

    /* reloads HAL service instance without waiting. This relies on the HAL found by init()
     * to rapidly reconnect to the specific HAL service, or defers to init() if it was never called.
     */
    void tryReconnect() override final;

    HalResult<void> ping() override final;

    HalResult<ManagerCapabilities> getCapabilities() override final;
    HalResult<std::vector<int32_t>> getVibratorIds() override final;
    HalResult<std::shared_ptr<HalController>> getVibrator(int32_t id) override final;

    HalResult<void> prepareSynced(const std::vector<int32_t>& ids) override final;
    HalResult<void> triggerSynced(const std::function<void()>& completionCallback) override final;
    HalResult<void> cancelSynced() override final;

private:
    Connector mConnector;
    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<ManagerHalWrapper>)>;

    template <typename T>
    HalResult<T> apply(hal_fn<T>& halFn, const char* functionName);
};

}; // namespace vibrator

}; // namespace android

#endif // ANDROID_OS_VIBRATOR_MANAGER_HAL_CONTROLLER_H
Loading