/* * Copyright (C) 2025 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 "VibratorController" #ifndef qDoWithRetries #define qDoWithRetries(op) doWithRetries(op, __FUNCTION__) #endif #include #include #include #include #include using ::aidl::android::hardware::vibrator::Effect; using ::aidl::android::hardware::vibrator::EffectStrength; using ::aidl::android::hardware::vibrator::IVibrator; using Status = ::ndk::ScopedAStatus; using namespace std::placeholders; namespace android { namespace vibrator { // ------------------------------------------------------------------------------------------------- inline bool isStatusUnsupported(const Status& status) { // STATUS_UNKNOWN_TRANSACTION means the HAL is an older version, so operation is unsupported. return status.getStatus() == STATUS_UNKNOWN_TRANSACTION || status.getExceptionCode() == EX_UNSUPPORTED_OPERATION; } inline bool isStatusTransactionFailed(const Status& status) { // STATUS_UNKNOWN_TRANSACTION means the HAL is an older version, so operation is unsupported. return status.getStatus() != STATUS_UNKNOWN_TRANSACTION && status.getExceptionCode() == EX_TRANSACTION_FAILED; } // ------------------------------------------------------------------------------------------------- bool VibratorProvider::isDeclared() { std::lock_guard lock(mMutex); if (mIsDeclared.has_value()) { return *mIsDeclared; } bool isDeclared = AServiceManager_isDeclared(mServiceName.c_str()); if (!isDeclared) { ALOGV("Vibrator HAL service not declared."); } mIsDeclared.emplace(isDeclared); return isDeclared; } std::shared_ptr VibratorProvider::waitForVibrator() { if (!isDeclared()) { return nullptr; } auto vibrator = IVibrator::fromBinder( ndk::SpAIBinder(AServiceManager_waitForService(mServiceName.c_str()))); if (vibrator) { ALOGV("Successfully connected to Vibrator HAL service."); } else { ALOGE("Error connecting to declared Vibrator HAL service."); } return vibrator; } std::shared_ptr VibratorProvider::checkForVibrator() { if (!isDeclared()) { return nullptr; } auto vibrator = IVibrator::fromBinder( ndk::SpAIBinder(AServiceManager_checkService(mServiceName.c_str()))); if (vibrator) { ALOGV("Successfully reconnected to Vibrator HAL service."); } else { ALOGE("Error reconnecting to declared Vibrator HAL service."); } return vibrator; } // ------------------------------------------------------------------------------------------------- bool VibratorController::init() { if (!mVibratorProvider->isDeclared()) { return false; } std::lock_guard lock(mMutex); if (mVibrator == nullptr) { mVibrator = mVibratorProvider->waitForVibrator(); } return mVibratorProvider->isDeclared(); } Status VibratorController::off() { return qDoWithRetries(std::bind(&IVibrator::off, _1)); } Status VibratorController::setAmplitude(float amplitude) { return qDoWithRetries(std::bind(&IVibrator::setAmplitude, _1, amplitude)); } Status VibratorController::setExternalControl(bool enabled) { return qDoWithRetries(std::bind(&IVibrator::setExternalControl, _1, enabled)); } Status VibratorController::alwaysOnEnable(int32_t id, const Effect& effect, const EffectStrength& strength) { return qDoWithRetries(std::bind(&IVibrator::alwaysOnEnable, _1, id, effect, strength)); } Status VibratorController::alwaysOnDisable(int32_t id) { return qDoWithRetries(std::bind(&IVibrator::alwaysOnDisable, _1, id)); } // ------------------------------------------------------------------------------------------------- std::shared_ptr VibratorController::reconnectToVibrator() { std::lock_guard lock(mMutex); mVibrator = mVibratorProvider->checkForVibrator(); return mVibrator; } Status VibratorController::doWithRetries(const VibratorController::VibratorOp& op, const char* logLabel) { if (!init()) { ALOGV("Skipped %s because Vibrator HAL is not declared", logLabel); return Status::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE, "IVibrator not declared"); } std::shared_ptr vibrator; { std::lock_guard lock(mMutex); vibrator = mVibrator; } if (!vibrator) { ALOGE("Skipped %s because Vibrator HAL is declared but failed to load", logLabel); return Status::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE, "IVibrator declared but failed to load"); } auto status = doOnce(vibrator.get(), op, logLabel); for (int i = 1; i < MAX_ATTEMPTS && isStatusTransactionFailed(status); i++) { vibrator = reconnectToVibrator(); if (!vibrator) { // Failed to reconnect to vibrator HAL after a transaction failed, skip retries. break; } status = doOnce(vibrator.get(), op, logLabel); } return status; } Status VibratorController::doOnce(IVibrator* vibrator, const VibratorController::VibratorOp& op, const char* logLabel) { auto status = op(vibrator); if (!status.isOk()) { if (isStatusUnsupported(status)) { ALOGV("Vibrator HAL %s is unsupported: %s", logLabel, status.getMessage()); } else { ALOGE("Vibrator HAL %s failed: %s", logLabel, status.getMessage()); } } return status; } // ------------------------------------------------------------------------------------------------- }; // namespace vibrator }; // namespace android