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