• 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 
__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