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

Commit a92c154d authored by Tri Vo's avatar Tri Vo
Browse files

Fwk vibrator server handles vibrator hal dying.

Bug: 35729206
Test: 1. on device: pkill -f vibrator
2. trigger vibrator
3. runtime survives
Change-Id: Ic2d98e36635151029e3dda78c3a58f481e273936
parent d20db5a0
Loading
Loading
Loading
Loading
+85 −71
Original line number Diff line number Diff line
@@ -42,73 +42,86 @@ using IVibrator_1_1 = android::hardware::vibrator::V1_1::IVibrator;
namespace android
{

static sp<IVibrator> mHal;
static constexpr int NUM_TRIES = 2;

// Creates a Return<R> with STATUS::EX_NULL_POINTER.
template<class R>
inline Return<R> NullptrStatus() {
    using ::android::hardware::Status;
    return Return<R>{Status::fromExceptionCode(Status::EX_NULL_POINTER)};
}

// Helper used to transparently deal with the vibrator HAL becoming unavailable.
template<class R, class I, class... Args0, class... Args1>
Return<R> halCall(Return<R> (I::* fn)(Args0...), Args1&&... args1) {
    // Assume that if getService returns a nullptr, HAL is not available on the
    // device.
    static sp<I> sHal = I::getService();
    static bool sAvailable = sHal != nullptr;

    if (!sAvailable) {
        return NullptrStatus<R>();
    }

    // Return<R> doesn't have a default constructor, so make a Return<R> with
    // STATUS::EX_NONE.
    using ::android::hardware::Status;
    Return<R> ret{Status::fromExceptionCode(Status::EX_NONE)};

    // Note that ret is guaranteed to be changed after this loop.
    for (int i = 0; i < NUM_TRIES; ++i) {
        ret = (sHal == nullptr) ? NullptrStatus<R>()
                : (*sHal.*fn)(std::forward<Args1>(args1)...);

        if (!ret.isOk()) {
            ALOGE("Failed to issue command to vibrator HAL. Retrying.");
            // Restoring connection to the HAL.
            sHal = I::tryGetService();
        }
    }
    return ret;
}

static void vibratorInit(JNIEnv /* env */, jobject /* clazz */)
{
    /* TODO(b/31632518) */
    if (mHal != nullptr) {
        return;
    }
    mHal = IVibrator::getService();
    halCall(&IVibrator::ping).isOk();
}

static jboolean vibratorExists(JNIEnv* /* env */, jobject /* clazz */)
{
    if (mHal != nullptr) {
        return JNI_TRUE;
    } else {
        return JNI_FALSE;
    }
    return halCall(&IVibrator::ping).isOk() ? JNI_TRUE : JNI_FALSE;
}

static void vibratorOn(JNIEnv* /* env */, jobject /* clazz */, jlong timeout_ms)
{
    if (mHal != nullptr) {
        Status retStatus = mHal->on(timeout_ms);
    Status retStatus = halCall(&IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR);
    if (retStatus != Status::OK) {
        ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
    }
    } else {
        ALOGW("Tried to vibrate but there is no vibrator device.");
    }
}

static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */)
{
    if (mHal != nullptr) {
        Status retStatus = mHal->off();
    Status retStatus = halCall(&IVibrator::off).withDefault(Status::UNKNOWN_ERROR);
    if (retStatus != Status::OK) {
        ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
    }
    } else {
        ALOGW("Tried to stop vibrating but there is no vibrator device.");
    }
}

static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jobject) {
    if (mHal != nullptr) {
        return mHal->supportsAmplitudeControl();
    } else {
        ALOGW("Unable to get max vibration amplitude, there is no vibrator device.");
    }
    return false;
    return halCall(&IVibrator::supportsAmplitudeControl).withDefault(false);
}

static void vibratorSetAmplitude(JNIEnv*, jobject, jint amplitude) {
    if (mHal != nullptr) {
        Status status = mHal->setAmplitude(static_cast<uint32_t>(amplitude));
    Status status = halCall(&IVibrator::setAmplitude, static_cast<uint32_t>(amplitude))
        .withDefault(Status::UNKNOWN_ERROR);
    if (status != Status::OK) {
      ALOGE("Failed to set vibrator amplitude (%" PRIu32 ").",
            static_cast<uint32_t>(status));
    }
    } else {
        ALOGW("Unable to set vibration amplitude, there is no vibrator device.");
    }
}

static jlong vibratorPerformEffect(JNIEnv*, jobject, jlong effect, jint strength) {
    if (mHal != nullptr) {
    Status status;
    uint32_t lengthMs;
    auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) {
@@ -121,16 +134,20 @@ static jlong vibratorPerformEffect(JNIEnv*, jobject, jlong effect, jint strength
        ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")",
                static_cast<int32_t>(effect));
    } else if (effect == static_cast<uint32_t>(Effect_1_1::TICK)) {
            sp<IVibrator_1_1> hal_1_1 = IVibrator_1_1::castFrom(mHal);
            if (hal_1_1 != nullptr) {
                hal_1_1->perform_1_1(static_cast<Effect_1_1>(effect), effectStrength, callback);
            } else {
        auto ret = halCall(&IVibrator_1_1::perform_1_1, static_cast<Effect_1_1>(effect),
                           effectStrength, callback);
        if (!ret.isOk()) {
            ALOGW("Failed to perform effect (%" PRId32 "), insufficient HAL version",
                    static_cast<int32_t>(effect));
        }
    } else {
            mHal->perform(static_cast<Effect>(effect), effectStrength, callback);
        auto ret = halCall(&IVibrator::perform, static_cast<Effect>(effect), effectStrength,
                           callback);
        if (!ret.isOk()) {
            ALOGW("Failed to perform effect (%" PRId32 ")", static_cast<int32_t>(effect));
        }
    }

    if (status == Status::OK) {
        return lengthMs;
    } else if (status != Status::UNSUPPORTED_OPERATION) {
@@ -141,9 +158,6 @@ static jlong vibratorPerformEffect(JNIEnv*, jobject, jlong effect, jint strength
                ", error=%" PRIu32 ").", static_cast<int64_t>(effect),
                static_cast<int32_t>(strength), static_cast<uint32_t>(status));
    }
    } else {
        ALOGW("Unable to perform haptic effect, there is no vibrator device.");
    }
    return -1;
}