• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
isStatusUnsupported(const Status & status)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 
isStatusTransactionFailed(const Status & status)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 
isDeclared()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 
waitForVibrator()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 
checkForVibrator()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 
init()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 
off()119 Status VibratorController::off() {
120     return qDoWithRetries(std::bind(&IVibrator::off, _1));
121 }
122 
setAmplitude(float amplitude)123 Status VibratorController::setAmplitude(float amplitude) {
124     return qDoWithRetries(std::bind(&IVibrator::setAmplitude, _1, amplitude));
125 }
126 
setExternalControl(bool enabled)127 Status VibratorController::setExternalControl(bool enabled) {
128     return qDoWithRetries(std::bind(&IVibrator::setExternalControl, _1, enabled));
129 }
130 
alwaysOnEnable(int32_t id,const Effect & effect,const EffectStrength & strength)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 
alwaysOnDisable(int32_t id)136 Status VibratorController::alwaysOnDisable(int32_t id) {
137     return qDoWithRetries(std::bind(&IVibrator::alwaysOnDisable, _1, id));
138 }
139 
140 // -------------------------------------------------------------------------------------------------
141 
reconnectToVibrator()142 std::shared_ptr<IVibrator> VibratorController::reconnectToVibrator() {
143     std::lock_guard<std::mutex> lock(mMutex);
144     mVibrator = mVibratorProvider->checkForVibrator();
145     return mVibrator;
146 }
147 
doWithRetries(const VibratorController::VibratorOp & op,const char * logLabel)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 
doOnce(IVibrator * vibrator,const VibratorController::VibratorOp & op,const char * logLabel)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
197