blob: ac1e19a2428778d55dbcc252780161e1045cea76 [file] [log] [blame]
Lais Andrade3f7ecc52020-03-25 23:57:08 +00001/*
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 "PowerHalControllerTest"
18
19#include <android/hardware/power/Boost.h>
20#include <android/hardware/power/IPower.h>
21#include <android/hardware/power/Mode.h>
22
23#include <gmock/gmock.h>
24#include <gtest/gtest.h>
25
26#include <powermanager/PowerHalWrapper.h>
27#include <powermanager/PowerHalController.h>
28
29#include <thread>
30#include <utils/Log.h>
31
32using android::hardware::power::Boost;
33using android::hardware::power::Mode;
34using android::hardware::power::V1_0::Feature;
35using android::hardware::power::V1_0::IPower;
36using android::hardware::power::V1_0::PowerHint;
37
38using namespace android;
39using namespace std::chrono_literals;
40using namespace testing;
41
42// -------------------------------------------------------------------------------------------------
43
44class MockIPowerV1_0 : public IPower {
45public:
46 MOCK_METHOD(hardware::Return<void>, setInteractive, (bool interactive), (override));
47 MOCK_METHOD(hardware::Return<void>, powerHint, (PowerHint hint, int32_t data), (override));
48 MOCK_METHOD(
49 hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
50 MOCK_METHOD(
51 hardware::Return<void>, getPlatformLowPowerStats,
52 (getPlatformLowPowerStats_cb _hidl_cb), (override));
53};
54
55class TestPowerHalConnector : public PowerHalConnector {
56public:
57 TestPowerHalConnector(sp<IPower> powerHal) : mHal(std::move(powerHal)) {}
58 virtual ~TestPowerHalConnector() = default;
59
60 virtual std::unique_ptr<PowerHalWrapper> connect() override {
61 mCountMutex.lock();
62 ++mConnectedCount;
63 mCountMutex.unlock();
64 return std::make_unique<HidlPowerHalWrapperV1_0>(mHal);
65 }
66
67 void reset() override {
68 mCountMutex.lock();
69 ++mResetCount;
70 mCountMutex.unlock();
71 }
72
73 int getConnectCount() {
74 return mConnectedCount;
75 }
76
77 int getResetCount() {
78 return mResetCount;
79 }
80
81private:
82 sp<IPower> mHal = nullptr;
83 std::mutex mCountMutex;
84 int mConnectedCount = 0;
85 int mResetCount = 0;
86};
87
88class AlwaysFailingTestPowerHalConnector : public TestPowerHalConnector {
89public:
90 AlwaysFailingTestPowerHalConnector() : TestPowerHalConnector(nullptr) {}
91
92 std::unique_ptr<PowerHalWrapper> connect() override {
93 // Call parent to update counter, but ignore connected PowerHalWrapper.
94 TestPowerHalConnector::connect();
95 return nullptr;
96 }
97};
98
99// -------------------------------------------------------------------------------------------------
100
101class PowerHalControllerTest : public Test {
102public:
103 void SetUp() override {
104 mMockHal = new StrictMock<MockIPowerV1_0>();
105 std::unique_ptr<TestPowerHalConnector> halConnector =
106 std::make_unique<TestPowerHalConnector>(mMockHal);
107 mHalConnector = halConnector.get();
108 mHalController = std::make_unique<PowerHalController>(std::move(halConnector));
109 }
110
111protected:
112 sp<StrictMock<MockIPowerV1_0>> mMockHal = nullptr;
113 TestPowerHalConnector* mHalConnector = nullptr;
114 std::unique_ptr<PowerHalController> mHalController = nullptr;
115};
116
117// -------------------------------------------------------------------------------------------------
118
119TEST_F(PowerHalControllerTest, TestInitConnectsToPowerHalOnlyOnce) {
120 int powerHalConnectCount = mHalConnector->getConnectCount();
121 EXPECT_EQ(powerHalConnectCount, 0);
122
123 mHalController->init();
124 mHalController->init();
125
126 // PowerHalConnector was called only once and never reset.
127 powerHalConnectCount = mHalConnector->getConnectCount();
128 EXPECT_EQ(powerHalConnectCount, 1);
129 int powerHalResetCount = mHalConnector->getResetCount();
130 EXPECT_EQ(powerHalResetCount, 0);
131}
132
133TEST_F(PowerHalControllerTest, TestUnableToConnectToPowerHalIgnoresAllApiCalls) {
134 std::unique_ptr<AlwaysFailingTestPowerHalConnector> halConnector =
135 std::make_unique<AlwaysFailingTestPowerHalConnector>();
136 AlwaysFailingTestPowerHalConnector* failingHalConnector = halConnector.get();
137 PowerHalController halController(std::move(halConnector));
138
139 int powerHalConnectCount = failingHalConnector->getConnectCount();
140 EXPECT_EQ(powerHalConnectCount, 0);
141
142 // Still works with EmptyPowerHalWrapper as fallback ignoring every api call and logging.
143 auto result = halController.setBoost(Boost::INTERACTION, 1000);
144 ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
145 result = halController.setMode(Mode::LAUNCH, true);
146 ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
147
148 // PowerHalConnector was called every time to attempt to reconnect with underlying service.
149 powerHalConnectCount = failingHalConnector->getConnectCount();
150 EXPECT_EQ(powerHalConnectCount, 2);
151 // PowerHalConnector was never reset.
152 int powerHalResetCount = mHalConnector->getResetCount();
153 EXPECT_EQ(powerHalResetCount, 0);
154}
155
156TEST_F(PowerHalControllerTest, TestAllApiCallsDelegatedToConnectedPowerHal) {
157 int powerHalConnectCount = mHalConnector->getConnectCount();
158 EXPECT_EQ(powerHalConnectCount, 0);
159
160 {
161 InSequence seg;
162 EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::INTERACTION), Eq(100)))
163 .Times(Exactly(1));
164 EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), Eq(1)))
165 .Times(Exactly(1));
166 }
167
168 auto result = mHalController->setBoost(Boost::INTERACTION, 100);
169 ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
170 result = mHalController->setMode(Mode::LAUNCH, true);
171 ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
172
173 // PowerHalConnector was called only once and never reset.
174 powerHalConnectCount = mHalConnector->getConnectCount();
175 EXPECT_EQ(powerHalConnectCount, 1);
176 int powerHalResetCount = mHalConnector->getResetCount();
177 EXPECT_EQ(powerHalResetCount, 0);
178}
179
180TEST_F(PowerHalControllerTest, TestPowerHalRecoversFromFailureByRecreatingPowerHal) {
181 int powerHalConnectCount = mHalConnector->getConnectCount();
182 EXPECT_EQ(powerHalConnectCount, 0);
183
184 ON_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), _))
185 .WillByDefault([](PowerHint, int32_t) {
186 return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
187 });
188
189 EXPECT_CALL(*mMockHal.get(), powerHint(_, _))
190 .Times(Exactly(4));
191
192 auto result = mHalController->setBoost(Boost::INTERACTION, 1000);
193 ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
194 result = mHalController->setMode(Mode::LAUNCH, true);
195 ASSERT_EQ(PowerHalResult::FAILED, result);
196 result = mHalController->setMode(Mode::VR, false);
197 ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
198 result = mHalController->setMode(Mode::LOW_POWER, true);
199 ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
200
201 // PowerHalConnector was called only twice: on first api call and after failed call.
202 powerHalConnectCount = mHalConnector->getConnectCount();
203 EXPECT_EQ(powerHalConnectCount, 2);
204 // PowerHalConnector was reset once after failed call.
205 int powerHalResetCount = mHalConnector->getResetCount();
206 EXPECT_EQ(powerHalResetCount, 1);
207}
208
209TEST_F(PowerHalControllerTest, TestPowerHalDoesNotTryToRecoverFromFailureOnUnsupportedCalls) {
210 int powerHalConnectCount = mHalConnector->getConnectCount();
211 EXPECT_EQ(powerHalConnectCount, 0);
212
213 auto result = mHalController->setBoost(Boost::CAMERA_LAUNCH, 1000);
214 ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
215 result = mHalController->setMode(Mode::CAMERA_STREAMING_HIGH, true);
216 ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
217
218 // PowerHalConnector was called only once and never reset.
219 powerHalConnectCount = mHalConnector->getConnectCount();
220 EXPECT_EQ(powerHalConnectCount, 1);
221 int powerHalResetCount = mHalConnector->getResetCount();
222 EXPECT_EQ(powerHalResetCount, 0);
223}
224
225TEST_F(PowerHalControllerTest, TestMultiThreadConnectsOnlyOnce) {
226 int powerHalConnectCount = mHalConnector->getConnectCount();
227 EXPECT_EQ(powerHalConnectCount, 0);
228
229 EXPECT_CALL(*mMockHal.get(), powerHint(_, _))
230 .Times(Exactly(10));
231
232 std::vector<std::thread> threads;
233 for (int i = 0; i < 10; i++) {
234 threads.push_back(std::thread([&]() {
235 auto result = mHalController->setBoost(Boost::INTERACTION, 1000);
236 ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
237 }));
238 }
239 std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
240
241 // PowerHalConnector was called only by the first thread to use the api and never reset.
242 powerHalConnectCount = mHalConnector->getConnectCount();
243 EXPECT_EQ(powerHalConnectCount, 1);
244 int powerHalResetCount = mHalConnector->getResetCount();
245 EXPECT_EQ(powerHalResetCount, 0);
246}
247
248TEST_F(PowerHalControllerTest, TestMultiThreadWithFailureReconnectIsThreadSafe) {
249 int powerHalConnectCount = mHalConnector->getConnectCount();
250 EXPECT_EQ(powerHalConnectCount, 0);
251
252 ON_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), _))
253 .WillByDefault([](PowerHint, int32_t) {
254 return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
255 });
256
257 EXPECT_CALL(*mMockHal.get(), powerHint(_, _))
258 .Times(Exactly(40));
259
260 std::vector<std::thread> threads;
261 for (int i = 0; i < 10; i++) {
262 threads.push_back(std::thread([&]() {
263 auto result = mHalController->setBoost(Boost::INTERACTION, 1000);
264 ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
265 }));
266 threads.push_back(std::thread([&]() {
267 auto result = mHalController->setMode(Mode::LAUNCH, true);
268 ASSERT_EQ(PowerHalResult::FAILED, result);
269 }));
270 threads.push_back(std::thread([&]() {
271 auto result = mHalController->setMode(Mode::LOW_POWER, false);
272 ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
273 }));
274 threads.push_back(std::thread([&]() {
275 auto result = mHalController->setMode(Mode::VR, true);
276 ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
277 }));
278 }
279 std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
280
281 // PowerHalConnector was called at least once by the first thread.
282 // Reset and reconnect calls were made at most 10 times, once after each failure.
283 powerHalConnectCount = mHalConnector->getConnectCount();
284 EXPECT_THAT(powerHalConnectCount, AllOf(Ge(1), Le(11)));
285 int powerHalResetCount = mHalConnector->getResetCount();
286 EXPECT_THAT(powerHalResetCount, Le(10));
287}