From a92c154d3e0f09d56df47e9d5f08ed0a0b249100 Mon Sep 17 00:00:00 2001 From: Tri Vo Date: Sat, 17 Jun 2017 14:58:44 -0700 Subject: [PATCH] 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 --- .../com_android_server_VibratorService.cpp | 154 ++++++++++-------- 1 file changed, 84 insertions(+), 70 deletions(-) diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp index 804cd17fc27c7..cb8416b36be5c 100644 --- a/services/core/jni/com_android_server_VibratorService.cpp +++ b/services/core/jni/com_android_server_VibratorService.cpp @@ -42,107 +42,121 @@ using IVibrator_1_1 = android::hardware::vibrator::V1_1::IVibrator; namespace android { -static sp mHal; +static constexpr int NUM_TRIES = 2; + +// Creates a Return with STATUS::EX_NULL_POINTER. +template +inline Return NullptrStatus() { + using ::android::hardware::Status; + return Return{Status::fromExceptionCode(Status::EX_NULL_POINTER)}; +} + +// Helper used to transparently deal with the vibrator HAL becoming unavailable. +template +Return halCall(Return (I::* fn)(Args0...), Args1&&... args1) { + // Assume that if getService returns a nullptr, HAL is not available on the + // device. + static sp sHal = I::getService(); + static bool sAvailable = sHal != nullptr; + + if (!sAvailable) { + return NullptrStatus(); + } + + // Return doesn't have a default constructor, so make a Return with + // STATUS::EX_NONE. + using ::android::hardware::Status; + Return 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() + : (*sHal.*fn)(std::forward(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); - if (retStatus != Status::OK) { - ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast(retStatus)); - } - } else { - ALOGW("Tried to vibrate but there is no vibrator device."); + Status retStatus = halCall(&IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR); + if (retStatus != Status::OK) { + ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast(retStatus)); } } static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */) { - if (mHal != nullptr) { - Status retStatus = mHal->off(); - if (retStatus != Status::OK) { - ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast(retStatus)); - } - } else { - ALOGW("Tried to stop vibrating but there is no vibrator device."); + Status retStatus = halCall(&IVibrator::off).withDefault(Status::UNKNOWN_ERROR); + if (retStatus != Status::OK) { + ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast(retStatus)); } } 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(amplitude)); - if (status != Status::OK) { - ALOGE("Failed to set vibrator amplitude (%" PRIu32 ").", - static_cast(status)); - } - } else { - ALOGW("Unable to set vibration amplitude, there is no vibrator device."); + Status status = halCall(&IVibrator::setAmplitude, static_cast(amplitude)) + .withDefault(Status::UNKNOWN_ERROR); + if (status != Status::OK) { + ALOGE("Failed to set vibrator amplitude (%" PRIu32 ").", + static_cast(status)); } } 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) { - status = retStatus; - lengthMs = retLengthMs; - }; - EffectStrength effectStrength(static_cast(strength)); + Status status; + uint32_t lengthMs; + auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) { + status = retStatus; + lengthMs = retLengthMs; + }; + EffectStrength effectStrength(static_cast(strength)); - if (effect < 0 || effect > static_cast(Effect_1_1::TICK)) { - ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")", + if (effect < 0 || effect > static_cast(Effect_1_1::TICK)) { + ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")", + static_cast(effect)); + } else if (effect == static_cast(Effect_1_1::TICK)) { + auto ret = halCall(&IVibrator_1_1::perform_1_1, static_cast(effect), + effectStrength, callback); + if (!ret.isOk()) { + ALOGW("Failed to perform effect (%" PRId32 "), insufficient HAL version", static_cast(effect)); - } else if (effect == static_cast(Effect_1_1::TICK)) { - sp hal_1_1 = IVibrator_1_1::castFrom(mHal); - if (hal_1_1 != nullptr) { - hal_1_1->perform_1_1(static_cast(effect), effectStrength, callback); - } else { - ALOGW("Failed to perform effect (%" PRId32 "), insufficient HAL version", - static_cast(effect)); - } - } else { - mHal->perform(static_cast(effect), effectStrength, callback); - } - if (status == Status::OK) { - return lengthMs; - } else if (status != Status::UNSUPPORTED_OPERATION) { - // Don't warn on UNSUPPORTED_OPERATION, that's a normal even and just means the motor - // doesn't have a pre-defined waveform to perform for it, so we should just fall back - // to the framework waveforms. - ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32 - ", error=%" PRIu32 ").", static_cast(effect), - static_cast(strength), static_cast(status)); } } else { - ALOGW("Unable to perform haptic effect, there is no vibrator device."); + auto ret = halCall(&IVibrator::perform, static_cast(effect), effectStrength, + callback); + if (!ret.isOk()) { + ALOGW("Failed to perform effect (%" PRId32 ")", static_cast(effect)); + } + } + + if (status == Status::OK) { + return lengthMs; + } else if (status != Status::UNSUPPORTED_OPERATION) { + // Don't warn on UNSUPPORTED_OPERATION, that's a normal even and just means the motor + // doesn't have a pre-defined waveform to perform for it, so we should just fall back + // to the framework waveforms. + ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32 + ", error=%" PRIu32 ").", static_cast(effect), + static_cast(strength), static_cast(status)); } return -1; }