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
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index 804cd17..cb8416b 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -42,107 +42,121 @@
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);
- 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.");
+ 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));
}
}
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<uint32_t>(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<uint32_t>(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<uint32_t>(amplitude));
- 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.");
+ 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));
}
}
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<EffectStrength>(strength));
+ Status status;
+ uint32_t lengthMs;
+ auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) {
+ status = retStatus;
+ lengthMs = retLengthMs;
+ };
+ EffectStrength effectStrength(static_cast<EffectStrength>(strength));
- if (effect < 0 || effect > static_cast<uint32_t>(Effect_1_1::TICK)) {
- ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")",
+ if (effect < 0 || effect > static_cast<uint32_t>(Effect_1_1::TICK)) {
+ 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)) {
+ 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 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 {
- ALOGW("Failed to perform effect (%" PRId32 "), insufficient HAL version",
- static_cast<int32_t>(effect));
- }
- } else {
- mHal->perform(static_cast<Effect>(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<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.");
+ 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) {
+ // 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<int64_t>(effect),
+ static_cast<int32_t>(strength), static_cast<uint32_t>(status));
}
return -1;
}