Skip to content

Commit bb68497

Browse files
Treehugger RobotAndroid (Google) Code Review
authored andcommitted
Merge "Simplify libvibratorservice after HIDL support removal" into main
2 parents ac86c3e + 1d71443 commit bb68497

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)