1 /*
2 * Copyright (C) 2020 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 "VibratorHalControllerTest"
18
19 #include <android/hardware/vibrator/IVibrator.h>
20 #include <cutils/atomic.h>
21
22 #include <gmock/gmock.h>
23 #include <gtest/gtest.h>
24
25 #include <utils/Log.h>
26 #include <thread>
27
28 #include <vibratorservice/VibratorCallbackScheduler.h>
29 #include <vibratorservice/VibratorHalController.h>
30 #include <vibratorservice/VibratorHalWrapper.h>
31
32 #include "test_utils.h"
33
34 using android::hardware::vibrator::Effect;
35 using android::hardware::vibrator::EffectStrength;
36
37 using std::chrono::milliseconds;
38
39 using namespace android;
40 using namespace std::chrono_literals;
41 using namespace testing;
42
__anon4a8d81570102(vibrator::HalWrapper* hal) 43 static const auto ON_FN = [](vibrator::HalWrapper* hal) { return hal->on(10ms, []() {}); };
__anon4a8d81570302(vibrator::HalWrapper* hal) 44 static const auto OFF_FN = [](vibrator::HalWrapper* hal) { return hal->off(); };
__anon4a8d81570402(vibrator::HalWrapper* hal) 45 static const auto PING_FN = [](vibrator::HalWrapper* hal) { return hal->ping(); };
46
47 // -------------------------------------------------------------------------------------------------
48
49 class MockHalWrapper : public vibrator::HalWrapper {
50 public:
MockHalWrapper(std::shared_ptr<vibrator::CallbackScheduler> scheduler)51 MockHalWrapper(std::shared_ptr<vibrator::CallbackScheduler> scheduler)
52 : HalWrapper(scheduler) {}
53 virtual ~MockHalWrapper() = default;
54
55 MOCK_METHOD(vibrator::HalResult<void>, ping, (), (override));
56 MOCK_METHOD(void, tryReconnect, (), (override));
57 MOCK_METHOD(vibrator::HalResult<void>, on,
58 (milliseconds timeout, const std::function<void()>& completionCallback),
59 (override));
60 MOCK_METHOD(vibrator::HalResult<void>, off, (), (override));
61 MOCK_METHOD(vibrator::HalResult<void>, setAmplitude, (float amplitude), (override));
62 MOCK_METHOD(vibrator::HalResult<void>, setExternalControl, (bool enabled), (override));
63 MOCK_METHOD(vibrator::HalResult<void>, alwaysOnEnable,
64 (int32_t id, Effect effect, EffectStrength strength), (override));
65 MOCK_METHOD(vibrator::HalResult<void>, alwaysOnDisable, (int32_t id), (override));
66 MOCK_METHOD(vibrator::HalResult<milliseconds>, performEffect,
67 (Effect effect, EffectStrength strength,
68 const std::function<void()>& completionCallback),
69 (override));
70 MOCK_METHOD(vibrator::HalResult<vibrator::Capabilities>, getCapabilitiesInternal, (),
71 (override));
72
getCallbackScheduler()73 vibrator::CallbackScheduler* getCallbackScheduler() { return mCallbackScheduler.get(); }
74 };
75
76 // -------------------------------------------------------------------------------------------------
77
78 class VibratorHalControllerTest : public Test {
79 public:
SetUp()80 void SetUp() override {
81 mConnectCounter = 0;
82 auto callbackScheduler = std::make_shared<vibrator::CallbackScheduler>();
83 mMockHal = std::make_shared<StrictMock<MockHalWrapper>>(callbackScheduler);
84 mController = std::make_unique<
85 vibrator::HalController>(std::move(callbackScheduler),
86 [&](std::shared_ptr<vibrator::CallbackScheduler>) {
87 android_atomic_inc(&(this->mConnectCounter));
88 return this->mMockHal;
89 });
90 ASSERT_NE(mController, nullptr);
91 }
92
93 protected:
94 int32_t mConnectCounter;
95 std::shared_ptr<MockHalWrapper> mMockHal;
96 std::unique_ptr<vibrator::HalController> mController;
97 };
98
99 // -------------------------------------------------------------------------------------------------
100
TEST_F(VibratorHalControllerTest,TestInit)101 TEST_F(VibratorHalControllerTest, TestInit) {
102 ASSERT_TRUE(mController->init());
103 ASSERT_EQ(1, mConnectCounter);
104
105 // Noop when wrapper was already initialized.
106 ASSERT_TRUE(mController->init());
107 ASSERT_EQ(1, mConnectCounter);
108 }
109
TEST_F(VibratorHalControllerTest,TestGetInfoRetriesOnTransactionFailure)110 TEST_F(VibratorHalControllerTest, TestGetInfoRetriesOnTransactionFailure) {
111 EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(1));
112 EXPECT_CALL(*mMockHal.get(), getCapabilitiesInternal())
113 .Times(Exactly(2))
114 .WillOnce(Return(vibrator::HalResult<vibrator::Capabilities>::transactionFailed("msg")))
115 .WillRepeatedly(Return(vibrator::HalResult<vibrator::Capabilities>::ok(
116 vibrator::Capabilities::ON_CALLBACK)));
117
118 auto result = mController->getInfo();
119 ASSERT_TRUE(result.capabilities.isOk());
120 ASSERT_EQ(1, mConnectCounter);
121 }
122
TEST_F(VibratorHalControllerTest,TestGetInfoDoesNotRetryOnOperationFailure)123 TEST_F(VibratorHalControllerTest, TestGetInfoDoesNotRetryOnOperationFailure) {
124 EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(0));
125 EXPECT_CALL(*mMockHal.get(), getCapabilitiesInternal())
126 .Times(Exactly(1))
127 .WillRepeatedly(Return(vibrator::HalResult<vibrator::Capabilities>::failed("msg")));
128
129 auto result = mController->getInfo();
130 ASSERT_TRUE(result.capabilities.isFailed());
131 ASSERT_EQ(1, mConnectCounter);
132 }
133
TEST_F(VibratorHalControllerTest,TestGetInfoDoesNotRetryOnUnsupported)134 TEST_F(VibratorHalControllerTest, TestGetInfoDoesNotRetryOnUnsupported) {
135 EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(0));
136 EXPECT_CALL(*mMockHal.get(), getCapabilitiesInternal())
137 .Times(Exactly(1))
138 .WillRepeatedly(Return(vibrator::HalResult<vibrator::Capabilities>::unsupported()));
139
140 auto result = mController->getInfo();
141 ASSERT_TRUE(result.capabilities.isUnsupported());
142 ASSERT_EQ(1, mConnectCounter);
143 }
144
TEST_F(VibratorHalControllerTest,TestApiCallsAreForwardedToHal)145 TEST_F(VibratorHalControllerTest, TestApiCallsAreForwardedToHal) {
146 EXPECT_CALL(*mMockHal.get(), on(_, _))
147 .Times(Exactly(1))
148 .WillRepeatedly(Return(vibrator::HalResult<void>::ok()));
149
150 auto result = mController->doWithRetry<void>(ON_FN, "on");
151 ASSERT_TRUE(result.isOk());
152 ASSERT_EQ(1, mConnectCounter);
153 }
154
TEST_F(VibratorHalControllerTest,TestUnsupportedApiResultDoesNotResetHalConnection)155 TEST_F(VibratorHalControllerTest, TestUnsupportedApiResultDoesNotResetHalConnection) {
156 EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(0));
157 EXPECT_CALL(*mMockHal.get(), off())
158 .Times(Exactly(1))
159 .WillRepeatedly(Return(vibrator::HalResult<void>::unsupported()));
160
161 auto result = mController->doWithRetry<void>(OFF_FN, "off");
162 ASSERT_TRUE(result.isUnsupported());
163 ASSERT_EQ(1, mConnectCounter);
164 }
165
TEST_F(VibratorHalControllerTest,TestOperationFailedApiResultDoesNotResetHalConnection)166 TEST_F(VibratorHalControllerTest, TestOperationFailedApiResultDoesNotResetHalConnection) {
167 EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(0));
168 EXPECT_CALL(*mMockHal.get(), on(_, _))
169 .Times(Exactly(1))
170 .WillRepeatedly(Return(vibrator::HalResult<void>::failed("message")));
171
172 auto result = mController->doWithRetry<void>(ON_FN, "on");
173 ASSERT_TRUE(result.isFailed());
174 ASSERT_EQ(1, mConnectCounter);
175 }
176
TEST_F(VibratorHalControllerTest,TestTransactionFailedApiResultResetsHalConnection)177 TEST_F(VibratorHalControllerTest, TestTransactionFailedApiResultResetsHalConnection) {
178 EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(1));
179 EXPECT_CALL(*mMockHal.get(), on(_, _))
180 .Times(Exactly(2))
181 .WillRepeatedly(Return(vibrator::HalResult<void>::transactionFailed("message")));
182
183 auto result = mController->doWithRetry<void>(ON_FN, "on");
184 ASSERT_TRUE(result.isFailed());
185 ASSERT_EQ(1, mConnectCounter);
186 }
187
TEST_F(VibratorHalControllerTest,TestTransactionFailedApiResultReturnsSuccessAfterRetries)188 TEST_F(VibratorHalControllerTest, TestTransactionFailedApiResultReturnsSuccessAfterRetries) {
189 {
190 InSequence seq;
191 EXPECT_CALL(*mMockHal.get(), ping())
192 .Times(Exactly(1))
193 .WillRepeatedly(Return(vibrator::HalResult<void>::transactionFailed("message")));
194 EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(1));
195 EXPECT_CALL(*mMockHal.get(), ping())
196 .Times(Exactly(1))
197 .WillRepeatedly(Return(vibrator::HalResult<void>::ok()));
198 }
199
200 auto result = mController->doWithRetry<void>(PING_FN, "ping");
201 ASSERT_TRUE(result.isOk());
202 ASSERT_EQ(1, mConnectCounter);
203 }
204
TEST_F(VibratorHalControllerTest,TestMultiThreadConnectsOnlyOnce)205 TEST_F(VibratorHalControllerTest, TestMultiThreadConnectsOnlyOnce) {
206 ASSERT_EQ(0, mConnectCounter);
207
208 EXPECT_CALL(*mMockHal.get(), ping())
209 .Times(Exactly(10))
210 .WillRepeatedly(Return(vibrator::HalResult<void>::ok()));
211
212 std::vector<std::thread> threads;
213 for (int i = 0; i < 10; i++) {
214 threads.push_back(std::thread([&]() {
215 auto result = mController->doWithRetry<void>(PING_FN, "ping");
216 ASSERT_TRUE(result.isOk());
217 }));
218 }
219 std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
220
221 // Connector was called only by the first thread to use the api.
222 ASSERT_EQ(1, mConnectCounter);
223 }
224
TEST_F(VibratorHalControllerTest,TestNoVibratorReturnsUnsupportedAndAttemptsToReconnect)225 TEST_F(VibratorHalControllerTest, TestNoVibratorReturnsUnsupportedAndAttemptsToReconnect) {
226 mController = std::make_unique<
227 vibrator::HalController>(nullptr, [&](std::shared_ptr<vibrator::CallbackScheduler>) {
228 android_atomic_inc(&(this->mConnectCounter));
229 return nullptr;
230 });
231 ASSERT_EQ(0, mConnectCounter);
232
233 ASSERT_TRUE(mController->doWithRetry<void>(OFF_FN, "off").isUnsupported());
234 ASSERT_TRUE(mController->doWithRetry<void>(PING_FN, "ping").isUnsupported());
235
236 // One connection attempt per api call.
237 ASSERT_EQ(2, mConnectCounter);
238 }
239
TEST_F(VibratorHalControllerTest,TestScheduledCallbackSurvivesReconnection)240 TEST_F(VibratorHalControllerTest, TestScheduledCallbackSurvivesReconnection) {
241 {
242 InSequence seq;
243 EXPECT_CALL(*mMockHal.get(), on(_, _))
244 .Times(Exactly(1))
245 .WillRepeatedly([&](milliseconds timeout, std::function<void()> callback) {
246 mMockHal.get()->getCallbackScheduler()->schedule(callback, timeout);
247 return vibrator::HalResult<void>::ok();
248 });
249 EXPECT_CALL(*mMockHal.get(), ping())
250 .Times(Exactly(1))
251 .WillRepeatedly(Return(vibrator::HalResult<void>::transactionFailed("message")));
252 EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(1));
253 EXPECT_CALL(*mMockHal.get(), ping())
254 .Times(Exactly(1))
255 .WillRepeatedly(Return(vibrator::HalResult<void>::transactionFailed("message")));
256 }
257
258 auto counter = vibrator::TestCounter(0);
259
260 auto onFn = [&](vibrator::HalWrapper* hal) {
261 return hal->on(10ms, [&counter] { counter.increment(); });
262 };
263 ASSERT_TRUE(mController->doWithRetry<void>(onFn, "on").isOk());
264 ASSERT_TRUE(mController->doWithRetry<void>(PING_FN, "ping").isFailed());
265 mMockHal.reset();
266 ASSERT_EQ(0, counter.get());
267
268 // Callback triggered even after HalWrapper was reconnected.
269 counter.tryWaitUntilCountIsAtLeast(1, 500ms);
270 ASSERT_EQ(1, counter.get());
271 }
272