blob: 21924e9f1394aa2b8fe186da432e86fcb21e667e [file]
/*
* 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 <aidl/android/hardware/vibrator/IVibrator.h>
#include <android/binder_manager.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <vibratorservice/VibratorController.h>
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<std::mutex> 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<IVibrator> 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<IVibrator> 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<std::mutex> 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<IVibrator> VibratorController::reconnectToVibrator() {
std::lock_guard<std::mutex> 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<IVibrator> vibrator;
{
std::lock_guard<std::mutex> 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