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
__anon0a7ef88a0202() 43 static const auto ON_FN = [](vibrator::HalWrapper* hal) { return hal->on(10ms, []() {}); };
__anon0a7ef88a0302(vibrator::HalWrapper* hal) 44 static const auto OFF_FN = [](vibrator::HalWrapper* hal) { return hal->off(); };
__anon0a7ef88a0402(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,TestGetInfoRetriesOnAnyFailure)110 TEST_F(VibratorHalControllerTest, TestGetInfoRetriesOnAnyFailure) {
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>::failed("message")))
115 .WillRepeatedly(Return(vibrator::HalResult<vibrator::Capabilities>::ok(
116 vibrator::Capabilities::ON_CALLBACK)));
117
118 auto result = mController->getInfo();
119 ASSERT_FALSE(result.capabilities.isFailed());
120
121 ASSERT_EQ(1, mConnectCounter);
122 }
123
TEST_F(VibratorHalControllerTest,TestApiCallsAreForwardedToHal)124 TEST_F(VibratorHalControllerTest, TestApiCallsAreForwardedToHal) {
125 EXPECT_CALL(*mMockHal.get(), on(_, _))
126 .Times(Exactly(1))
127 .WillRepeatedly(Return(vibrator::HalResult<void>::ok()));
128
129 auto result = mController->doWithRetry<void>(ON_FN, "on");
130 ASSERT_TRUE(result.isOk());
131
132 ASSERT_EQ(1, mConnectCounter);
133 }
134
TEST_F(VibratorHalControllerTest,TestUnsupportedApiResultDoNotResetHalConnection)135 TEST_F(VibratorHalControllerTest, TestUnsupportedApiResultDoNotResetHalConnection) {
136 EXPECT_CALL(*mMockHal.get(), off())
137 .Times(Exactly(1))
138 .WillRepeatedly(Return(vibrator::HalResult<void>::unsupported()));
139
140 ASSERT_EQ(0, mConnectCounter);
141 auto result = mController->doWithRetry<void>(OFF_FN, "off");
142 ASSERT_TRUE(result.isUnsupported());
143 ASSERT_EQ(1, mConnectCounter);
144 }
145
TEST_F(VibratorHalControllerTest,TestFailedApiResultResetsHalConnection)146 TEST_F(VibratorHalControllerTest, TestFailedApiResultResetsHalConnection) {
147 EXPECT_CALL(*mMockHal.get(), on(_, _))
148 .Times(Exactly(2))
149 .WillRepeatedly(Return(vibrator::HalResult<void>::failed("message")));
150 EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(1));
151
152 ASSERT_EQ(0, mConnectCounter);
153
154 auto result = mController->doWithRetry<void>(ON_FN, "on");
155 ASSERT_TRUE(result.isFailed());
156 ASSERT_EQ(1, mConnectCounter);
157 }
158
TEST_F(VibratorHalControllerTest,TestFailedApiResultReturnsSuccessAfterRetries)159 TEST_F(VibratorHalControllerTest, TestFailedApiResultReturnsSuccessAfterRetries) {
160 {
161 InSequence seq;
162 EXPECT_CALL(*mMockHal.get(), ping())
163 .Times(Exactly(1))
164 .WillRepeatedly(Return(vibrator::HalResult<void>::failed("message")));
165 EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(1));
166 EXPECT_CALL(*mMockHal.get(), ping())
167 .Times(Exactly(1))
168 .WillRepeatedly(Return(vibrator::HalResult<void>::ok()));
169 }
170
171 ASSERT_EQ(0, mConnectCounter);
172
173 auto result = mController->doWithRetry<void>(PING_FN, "ping");
174 ASSERT_TRUE(result.isOk());
175 ASSERT_EQ(1, mConnectCounter);
176 }
177
TEST_F(VibratorHalControllerTest,TestMultiThreadConnectsOnlyOnce)178 TEST_F(VibratorHalControllerTest, TestMultiThreadConnectsOnlyOnce) {
179 ASSERT_EQ(0, mConnectCounter);
180
181 EXPECT_CALL(*mMockHal.get(), ping())
182 .Times(Exactly(10))
183 .WillRepeatedly(Return(vibrator::HalResult<void>::ok()));
184
185 std::vector<std::thread> threads;
186 for (int i = 0; i < 10; i++) {
187 threads.push_back(std::thread([&]() {
188 auto result = mController->doWithRetry<void>(PING_FN, "ping");
189 ASSERT_TRUE(result.isOk());
190 }));
191 }
192 std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
193
194 // Connector was called only by the first thread to use the api.
195 ASSERT_EQ(1, mConnectCounter);
196 }
197
TEST_F(VibratorHalControllerTest,TestNoVibratorReturnsUnsupportedAndAttemptsToReconnect)198 TEST_F(VibratorHalControllerTest, TestNoVibratorReturnsUnsupportedAndAttemptsToReconnect) {
199 mController = std::make_unique<
200 vibrator::HalController>(nullptr, [&](std::shared_ptr<vibrator::CallbackScheduler>) {
201 android_atomic_inc(&(this->mConnectCounter));
202 return nullptr;
203 });
204 ASSERT_EQ(0, mConnectCounter);
205
206 ASSERT_TRUE(mController->doWithRetry<void>(OFF_FN, "off").isUnsupported());
207 ASSERT_TRUE(mController->doWithRetry<void>(PING_FN, "ping").isUnsupported());
208
209 // One connection attempt per api call.
210 ASSERT_EQ(2, mConnectCounter);
211 }
212
TEST_F(VibratorHalControllerTest,TestScheduledCallbackSurvivesReconnection)213 TEST_F(VibratorHalControllerTest, TestScheduledCallbackSurvivesReconnection) {
214 {
215 InSequence seq;
216 EXPECT_CALL(*mMockHal.get(), on(_, _))
217 .Times(Exactly(1))
218 .WillRepeatedly([&](milliseconds timeout, std::function<void()> callback) {
219 mMockHal.get()->getCallbackScheduler()->schedule(callback, timeout);
220 return vibrator::HalResult<void>::ok();
221 });
222 EXPECT_CALL(*mMockHal.get(), ping())
223 .Times(Exactly(1))
224 .WillRepeatedly(Return(vibrator::HalResult<void>::failed("message")));
225 EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(1));
226 EXPECT_CALL(*mMockHal.get(), ping())
227 .Times(Exactly(1))
228 .WillRepeatedly(Return(vibrator::HalResult<void>::failed("message")));
229 }
230
231 std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
232 auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
233
234 auto onFn = [&](vibrator::HalWrapper* hal) { return hal->on(10ms, callback); };
235 ASSERT_TRUE(mController->doWithRetry<void>(onFn, "on").isOk());
236 ASSERT_TRUE(mController->doWithRetry<void>(PING_FN, "ping").isFailed());
237 mMockHal.reset();
238 ASSERT_EQ(0, *callbackCounter.get());
239
240 // Callback triggered even after HalWrapper was reconnected.
241 std::this_thread::sleep_for(15ms);
242 ASSERT_EQ(1, *callbackCounter.get());
243 }
244