Skip to content

Commit 1d71443

Browse files
committed
Simplify libvibratorservice after HIDL support removal
Introduce a simplified VibratorController class to the libvibratorservice module that only handles AIDL vibrator HAL versions and reuse the binder ndk objects. This removes all wrapper classes introduced to handle both AIDL and HIDL objects seamlesly, reducing complexity for the library. The connect/reconnect logic on transcation falure remains, with most HAL operations working with a retry logic. This first change introduced the core for the VibratorController with basic APIs like off / setAmplitude / setExternalControl. Following changes will introduce the remaining IVibrator API support. Bug: 308452413 Test: libvibratorservice_test Flag: android.os.vibrator.remove_hidl_support Change-Id: Ie76168eaf9fd5cd0ce9719499d4ef9b086b2fca6
1 parent b0f3016 commit 1d71443

7 files changed

Lines changed: 572 additions & 4 deletions

File tree

services/vibratorservice/Android.bp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ cc_library_shared {
2626

2727
srcs: [
2828
"VibratorCallbackScheduler.cpp",
29+
"VibratorController.cpp",
2930
"VibratorHalController.cpp",
3031
"VibratorHalWrapper.cpp",
3132
"VibratorManagerHalController.cpp",
@@ -41,17 +42,17 @@ cc_library_shared {
4142
},
4243

4344
shared_libs: [
45+
"android.hardware.vibrator-V3-ndk",
4446
"libbinder_ndk",
4547
"liblog",
4648
"libutils",
47-
"android.hardware.vibrator-V3-ndk",
4849
],
4950

5051
cflags: [
5152
"-Wall",
5253
"-Werror",
53-
"-Wunused",
5454
"-Wunreachable-code",
55+
"-Wunused",
5556
],
5657

5758
local_include_dirs: ["include"],
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/*
2+
* Copyright (C) 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#define LOG_TAG "VibratorController"
18+
19+
#ifndef qDoWithRetries
20+
#define qDoWithRetries(op) doWithRetries(op, __FUNCTION__)
21+
#endif
22+
23+
#include <aidl/android/hardware/vibrator/IVibrator.h>
24+
#include <android/binder_manager.h>
25+
#include <binder/IServiceManager.h>
26+
27+
#include <utils/Log.h>
28+
29+
#include <vibratorservice/VibratorController.h>
30+
31+
using ::aidl::android::hardware::vibrator::Effect;
32+
using ::aidl::android::hardware::vibrator::EffectStrength;
33+
using ::aidl::android::hardware::vibrator::IVibrator;
34+
35+
using Status = ::ndk::ScopedAStatus;
36+
37+
using namespace std::placeholders;
38+
39+
namespace android {
40+
41+
namespace vibrator {
42+
43+
// -------------------------------------------------------------------------------------------------
44+
45+
inline bool isStatusUnsupported(const Status& status) {
46+
// STATUS_UNKNOWN_TRANSACTION means the HAL is an older version, so operation is unsupported.
47+
return status.getStatus() == STATUS_UNKNOWN_TRANSACTION ||
48+
status.getExceptionCode() == EX_UNSUPPORTED_OPERATION;
49+
}
50+
51+
inline bool isStatusTransactionFailed(const Status& status) {
52+
// STATUS_UNKNOWN_TRANSACTION means the HAL is an older version, so operation is unsupported.
53+
return status.getStatus() != STATUS_UNKNOWN_TRANSACTION &&
54+
status.getExceptionCode() == EX_TRANSACTION_FAILED;
55+
}
56+
57+
// -------------------------------------------------------------------------------------------------
58+
59+
bool VibratorProvider::isDeclared() {
60+
std::lock_guard<std::mutex> lock(mMutex);
61+
if (mIsDeclared.has_value()) {
62+
return *mIsDeclared;
63+
}
64+
65+
bool isDeclared = AServiceManager_isDeclared(mServiceName.c_str());
66+
if (!isDeclared) {
67+
ALOGV("Vibrator HAL service not declared.");
68+
}
69+
70+
mIsDeclared.emplace(isDeclared);
71+
return isDeclared;
72+
}
73+
74+
std::shared_ptr<IVibrator> VibratorProvider::waitForVibrator() {
75+
if (!isDeclared()) {
76+
return nullptr;
77+
}
78+
79+
auto vibrator = IVibrator::fromBinder(
80+
ndk::SpAIBinder(AServiceManager_waitForService(mServiceName.c_str())));
81+
if (vibrator) {
82+
ALOGV("Successfully connected to Vibrator HAL service.");
83+
} else {
84+
ALOGE("Error connecting to declared Vibrator HAL service.");
85+
}
86+
87+
return vibrator;
88+
}
89+
90+
std::shared_ptr<IVibrator> VibratorProvider::checkForVibrator() {
91+
if (!isDeclared()) {
92+
return nullptr;
93+
}
94+
95+
auto vibrator = IVibrator::fromBinder(
96+
ndk::SpAIBinder(AServiceManager_checkService(mServiceName.c_str())));
97+
if (vibrator) {
98+
ALOGV("Successfully reconnected to Vibrator HAL service.");
99+
} else {
100+
ALOGE("Error reconnecting to declared Vibrator HAL service.");
101+
}
102+
103+
return vibrator;
104+
}
105+
106+
// -------------------------------------------------------------------------------------------------
107+
108+
bool VibratorController::init() {
109+
if (!mVibratorProvider->isDeclared()) {
110+
return false;
111+
}
112+
std::lock_guard<std::mutex> lock(mMutex);
113+
if (mVibrator == nullptr) {
114+
mVibrator = mVibratorProvider->waitForVibrator();
115+
}
116+
return mVibratorProvider->isDeclared();
117+
}
118+
119+
Status VibratorController::off() {
120+
return qDoWithRetries(std::bind(&IVibrator::off, _1));
121+
}
122+
123+
Status VibratorController::setAmplitude(float amplitude) {
124+
return qDoWithRetries(std::bind(&IVibrator::setAmplitude, _1, amplitude));
125+
}
126+
127+
Status VibratorController::setExternalControl(bool enabled) {
128+
return qDoWithRetries(std::bind(&IVibrator::setExternalControl, _1, enabled));
129+
}
130+
131+
Status VibratorController::alwaysOnEnable(int32_t id, const Effect& effect,
132+
const EffectStrength& strength) {
133+
return qDoWithRetries(std::bind(&IVibrator::alwaysOnEnable, _1, id, effect, strength));
134+
}
135+
136+
Status VibratorController::alwaysOnDisable(int32_t id) {
137+
return qDoWithRetries(std::bind(&IVibrator::alwaysOnDisable, _1, id));
138+
}
139+
140+
// -------------------------------------------------------------------------------------------------
141+
142+
std::shared_ptr<IVibrator> VibratorController::reconnectToVibrator() {
143+
std::lock_guard<std::mutex> lock(mMutex);
144+
mVibrator = mVibratorProvider->checkForVibrator();
145+
return mVibrator;
146+
}
147+
148+
Status VibratorController::doWithRetries(const VibratorController::VibratorOp& op,
149+
const char* logLabel) {
150+
if (!init()) {
151+
ALOGV("Skipped %s because Vibrator HAL is not declared", logLabel);
152+
return Status::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE, "IVibrator not declared");
153+
}
154+
std::shared_ptr<IVibrator> vibrator;
155+
{
156+
std::lock_guard<std::mutex> lock(mMutex);
157+
vibrator = mVibrator;
158+
}
159+
160+
if (!vibrator) {
161+
ALOGE("Skipped %s because Vibrator HAL is declared but failed to load", logLabel);
162+
return Status::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
163+
"IVibrator declared but failed to load");
164+
}
165+
166+
auto status = doOnce(vibrator.get(), op, logLabel);
167+
for (int i = 1; i < MAX_ATTEMPTS && isStatusTransactionFailed(status); i++) {
168+
vibrator = reconnectToVibrator();
169+
if (!vibrator) {
170+
// Failed to reconnect to vibrator HAL after a transaction failed, skip retries.
171+
break;
172+
}
173+
status = doOnce(vibrator.get(), op, logLabel);
174+
}
175+
176+
return status;
177+
}
178+
179+
Status VibratorController::doOnce(IVibrator* vibrator, const VibratorController::VibratorOp& op,
180+
const char* logLabel) {
181+
auto status = op(vibrator);
182+
if (!status.isOk()) {
183+
if (isStatusUnsupported(status)) {
184+
ALOGV("Vibrator HAL %s is unsupported: %s", logLabel, status.getMessage());
185+
} else {
186+
ALOGE("Vibrator HAL %s failed: %s", logLabel, status.getMessage());
187+
}
188+
}
189+
return status;
190+
}
191+
192+
// -------------------------------------------------------------------------------------------------
193+
194+
}; // namespace vibrator
195+
196+
}; // namespace android
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
* Copyright (C) 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef ANDROID_OS_VIBRATOR_CONTROLLER_H
18+
#define ANDROID_OS_VIBRATOR_CONTROLLER_H
19+
20+
#include <aidl/android/hardware/vibrator/IVibrator.h>
21+
22+
#include <android-base/thread_annotations.h>
23+
24+
namespace android {
25+
26+
namespace vibrator {
27+
28+
// -------------------------------------------------------------------------------------------------
29+
30+
/* Provider for IVibrator HAL service instances. */
31+
class VibratorProvider {
32+
public:
33+
using IVibrator = ::aidl::android::hardware::vibrator::IVibrator;
34+
35+
VibratorProvider() : mServiceName(std::string(IVibrator::descriptor) + "/default") {}
36+
virtual ~VibratorProvider() = default;
37+
38+
/* Returns true if vibrator HAL service is declared in the device, false otherwise. */
39+
virtual bool isDeclared();
40+
41+
/* Connects to vibrator HAL, possibly waiting for the declared service to become available. */
42+
virtual std::shared_ptr<IVibrator> waitForVibrator();
43+
44+
/* Connects to vibrator HAL if declared and available, without waiting. */
45+
virtual std::shared_ptr<IVibrator> checkForVibrator();
46+
47+
private:
48+
std::mutex mMutex;
49+
const std::string mServiceName;
50+
std::optional<bool> mIsDeclared GUARDED_BY(mMutex);
51+
};
52+
53+
// -------------------------------------------------------------------------------------------------
54+
55+
/* Controller for Vibrator HAL handle.
56+
* This relies on VibratorProvider to connect to the underlying Vibrator HAL service and reconnects
57+
* after each transaction failed call. This also ensures connecting to the service is thread-safe.
58+
*/
59+
class VibratorController {
60+
public:
61+
using Effect = ::aidl::android::hardware::vibrator::Effect;
62+
using EffectStrength = ::aidl::android::hardware::vibrator::EffectStrength;
63+
using IVibrator = ::aidl::android::hardware::vibrator::IVibrator;
64+
using Status = ::ndk::ScopedAStatus;
65+
using VibratorOp = std::function<Status(IVibrator*)>;
66+
67+
VibratorController() : VibratorController(std::make_shared<VibratorProvider>()) {}
68+
VibratorController(std::shared_ptr<VibratorProvider> vibratorProvider)
69+
: mVibratorProvider(std::move(vibratorProvider)), mVibrator(nullptr) {}
70+
virtual ~VibratorController() = default;
71+
72+
/* Connects HAL service, possibly waiting for the declared service to become available.
73+
* This will automatically be called at the first API usage if it was not manually called
74+
* beforehand. Call this manually during the setup phase to avoid slowing the first API call.
75+
* Returns true if HAL service is declared, false otherwise.
76+
*/
77+
bool init();
78+
79+
/* Turn vibrator off. */
80+
Status off();
81+
82+
/* Set vibration amplitude in [0,1]. */
83+
Status setAmplitude(float amplitude);
84+
85+
/* Enable/disable external control. */
86+
Status setExternalControl(bool enabled);
87+
88+
/* Enable always-on for given id, with given effect and strength. */
89+
Status alwaysOnEnable(int32_t id, const Effect& effect, const EffectStrength& strength);
90+
91+
/* Disable always-on for given id. */
92+
Status alwaysOnDisable(int32_t id);
93+
94+
private:
95+
/* Max number of attempts to perform an operation when it fails with transaction error. */
96+
static constexpr int MAX_ATTEMPTS = 2;
97+
98+
std::mutex mMutex;
99+
std::shared_ptr<VibratorProvider> mVibratorProvider;
100+
std::shared_ptr<IVibrator> mVibrator GUARDED_BY(mMutex);
101+
102+
/* Reconnects HAL service without waiting for the service to become available. */
103+
std::shared_ptr<IVibrator> reconnectToVibrator();
104+
105+
/* Perform given operation on HAL with retries on transaction failures. */
106+
Status doWithRetries(const VibratorOp& op, const char* logLabel);
107+
108+
/* Perform given operation on HAL with logs for error/unsupported results. */
109+
static Status doOnce(IVibrator* vibrator, const VibratorOp& op, const char* logLabel);
110+
};
111+
112+
// -------------------------------------------------------------------------------------------------
113+
114+
}; // namespace vibrator
115+
116+
}; // namespace android
117+
118+
#endif // ANDROID_OS_VIBRATOR_CONTROLLER_H

services/vibratorservice/include/vibratorservice/VibratorHalController.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
* limitations under the License.
1515
*/
1616

17+
// TODO(b/308452413): remove this file once android.os.vibrator.remove_hidl_support is removed
18+
1719
#ifndef ANDROID_OS_VIBRATORHALCONTROLLER_H
1820
#define ANDROID_OS_VIBRATORHALCONTROLLER_H
1921

services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
* limitations under the License.
1515
*/
1616

17+
// TODO(b/308452413): remove this file once android.os.vibrator.remove_hidl_support is removed
18+
1719
#ifndef ANDROID_OS_VIBRATORHALWRAPPER_H
1820
#define ANDROID_OS_VIBRATORHALWRAPPER_H
1921

services/vibratorservice/test/Android.bp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ cc_test {
2727
test_suites: ["device-tests"],
2828
srcs: [
2929
"VibratorCallbackSchedulerTest.cpp",
30+
"VibratorControllerTest.cpp",
3031
"VibratorHalControllerTest.cpp",
3132
"VibratorHalWrapperAidlTest.cpp",
3233
"VibratorManagerHalControllerTest.cpp",
@@ -39,12 +40,12 @@ cc_test {
3940
"-Wextra",
4041
],
4142
shared_libs: [
43+
"android.hardware.vibrator-V3-ndk",
4244
"libbase",
4345
"libbinder_ndk",
4446
"liblog",
45-
"libvibratorservice",
4647
"libutils",
47-
"android.hardware.vibrator-V3-ndk",
48+
"libvibratorservice",
4849
],
4950
static_libs: [
5051
"libgmock",

0 commit comments

Comments
 (0)