• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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