blob: 141b2440b87342593f369bf047a84b0ef272a410 [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>
Lais Andrade3f7ecc52020-03-25 23:57:08 +000022#include <gmock/gmock.h>
23#include <gtest/gtest.h>
Lais Andrade3f7ecc52020-03-25 23:57:08 +000024#include <powermanager/PowerHalController.h>
Lais Andradeb59a9b52020-05-07 17:23:42 +010025#include <utils/Log.h>
Lais Andrade3f7ecc52020-03-25 23:57:08 +000026
27#include <thread>
Lais Andrade3f7ecc52020-03-25 23:57:08 +000028
29using android::hardware::power::Boost;
30using android::hardware::power::Mode;
31using android::hardware::power::V1_0::Feature;
32using android::hardware::power::V1_0::IPower;
33using android::hardware::power::V1_0::PowerHint;
34
35using namespace android;
Lais Andradeb59a9b52020-05-07 17:23:42 +010036using namespace android::power;
Lais Andrade3f7ecc52020-03-25 23:57:08 +000037using namespace std::chrono_literals;
38using namespace testing;
39
40// -------------------------------------------------------------------------------------------------
41
42class MockIPowerV1_0 : public IPower {
43public:
44 MOCK_METHOD(hardware::Return<void>, setInteractive, (bool interactive), (override));
45 MOCK_METHOD(hardware::Return<void>, powerHint, (PowerHint hint, int32_t data), (override));
Lais Andradeb59a9b52020-05-07 17:23:42 +010046 MOCK_METHOD(hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
47 MOCK_METHOD(hardware::Return<void>, getPlatformLowPowerStats,
48 (getPlatformLowPowerStats_cb _hidl_cb), (override));
Lais Andrade3f7ecc52020-03-25 23:57:08 +000049};
50
Lais Andradeb59a9b52020-05-07 17:23:42 +010051class TestPowerHalConnector : public HalConnector {
Lais Andrade3f7ecc52020-03-25 23:57:08 +000052public:
53 TestPowerHalConnector(sp<IPower> powerHal) : mHal(std::move(powerHal)) {}
54 virtual ~TestPowerHalConnector() = default;
55
Lais Andradeb59a9b52020-05-07 17:23:42 +010056 virtual std::unique_ptr<HalWrapper> connect() override {
Lais Andrade3f7ecc52020-03-25 23:57:08 +000057 mCountMutex.lock();
58 ++mConnectedCount;
59 mCountMutex.unlock();
Lais Andradeb59a9b52020-05-07 17:23:42 +010060 return std::make_unique<HidlHalWrapperV1_0>(mHal);
Lais Andrade3f7ecc52020-03-25 23:57:08 +000061 }
62
63 void reset() override {
64 mCountMutex.lock();
65 ++mResetCount;
66 mCountMutex.unlock();
67 }
68
Lais Andradeb59a9b52020-05-07 17:23:42 +010069 int getConnectCount() { return mConnectedCount; }
Lais Andrade3f7ecc52020-03-25 23:57:08 +000070
Lais Andradeb59a9b52020-05-07 17:23:42 +010071 int getResetCount() { return mResetCount; }
Lais Andrade3f7ecc52020-03-25 23:57:08 +000072
73private:
74 sp<IPower> mHal = nullptr;
75 std::mutex mCountMutex;
76 int mConnectedCount = 0;
77 int mResetCount = 0;
78};
79
80class AlwaysFailingTestPowerHalConnector : public TestPowerHalConnector {
81public:
82 AlwaysFailingTestPowerHalConnector() : TestPowerHalConnector(nullptr) {}
83
Lais Andradeb59a9b52020-05-07 17:23:42 +010084 std::unique_ptr<HalWrapper> connect() override {
85 // Call parent to update counter, but ignore connected HalWrapper.
Lais Andrade3f7ecc52020-03-25 23:57:08 +000086 TestPowerHalConnector::connect();
87 return nullptr;
88 }
89};
90
91// -------------------------------------------------------------------------------------------------
92
93class PowerHalControllerTest : public Test {
94public:
95 void SetUp() override {
96 mMockHal = new StrictMock<MockIPowerV1_0>();
97 std::unique_ptr<TestPowerHalConnector> halConnector =
Lais Andradeb59a9b52020-05-07 17:23:42 +010098 std::make_unique<TestPowerHalConnector>(mMockHal);
Lais Andrade3f7ecc52020-03-25 23:57:08 +000099 mHalConnector = halConnector.get();
100 mHalController = std::make_unique<PowerHalController>(std::move(halConnector));
101 }
102
103protected:
104 sp<StrictMock<MockIPowerV1_0>> mMockHal = nullptr;
105 TestPowerHalConnector* mHalConnector = nullptr;
106 std::unique_ptr<PowerHalController> mHalController = nullptr;
107};
108
109// -------------------------------------------------------------------------------------------------
110
111TEST_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
125TEST_F(PowerHalControllerTest, TestUnableToConnectToPowerHalIgnoresAllApiCalls) {
126 std::unique_ptr<AlwaysFailingTestPowerHalConnector> halConnector =
Lais Andradeb59a9b52020-05-07 17:23:42 +0100127 std::make_unique<AlwaysFailingTestPowerHalConnector>();
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000128 AlwaysFailingTestPowerHalConnector* failingHalConnector = halConnector.get();
129 PowerHalController halController(std::move(halConnector));
130
131 int powerHalConnectCount = failingHalConnector->getConnectCount();
132 EXPECT_EQ(powerHalConnectCount, 0);
133
Lais Andradeb59a9b52020-05-07 17:23:42 +0100134 // Still works with EmptyPowerHalWrapper as fallback ignoring every api call
135 // and logging.
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000136 auto result = halController.setBoost(Boost::INTERACTION, 1000);
Lais Andradeb59a9b52020-05-07 17:23:42 +0100137 ASSERT_EQ(HalResult::UNSUPPORTED, result);
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000138 result = halController.setMode(Mode::LAUNCH, true);
Lais Andradeb59a9b52020-05-07 17:23:42 +0100139 ASSERT_EQ(HalResult::UNSUPPORTED, result);
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000140
Lais Andradeb59a9b52020-05-07 17:23:42 +0100141 // PowerHalConnector was called every time to attempt to reconnect with
142 // underlying service.
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000143 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
150TEST_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)))
Lais Andradeb59a9b52020-05-07 17:23:42 +0100157 .Times(Exactly(1));
158 EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), Eq(1))).Times(Exactly(1));
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000159 }
160
161 auto result = mHalController->setBoost(Boost::INTERACTION, 100);
Lais Andradeb59a9b52020-05-07 17:23:42 +0100162 ASSERT_EQ(HalResult::SUCCESSFUL, result);
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000163 result = mHalController->setMode(Mode::LAUNCH, true);
Lais Andradeb59a9b52020-05-07 17:23:42 +0100164 ASSERT_EQ(HalResult::SUCCESSFUL, result);
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000165
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
173TEST_F(PowerHalControllerTest, TestPowerHalRecoversFromFailureByRecreatingPowerHal) {
174 int powerHalConnectCount = mHalConnector->getConnectCount();
175 EXPECT_EQ(powerHalConnectCount, 0);
176
177 ON_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), _))
Lais Andradeb59a9b52020-05-07 17:23:42 +0100178 .WillByDefault([](PowerHint, int32_t) {
179 return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
180 });
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000181
Lais Andradeb59a9b52020-05-07 17:23:42 +0100182 EXPECT_CALL(*mMockHal.get(), powerHint(_, _)).Times(Exactly(4));
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000183
184 auto result = mHalController->setBoost(Boost::INTERACTION, 1000);
Lais Andradeb59a9b52020-05-07 17:23:42 +0100185 ASSERT_EQ(HalResult::SUCCESSFUL, result);
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000186 result = mHalController->setMode(Mode::LAUNCH, true);
Lais Andradeb59a9b52020-05-07 17:23:42 +0100187 ASSERT_EQ(HalResult::FAILED, result);
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000188 result = mHalController->setMode(Mode::VR, false);
Lais Andradeb59a9b52020-05-07 17:23:42 +0100189 ASSERT_EQ(HalResult::SUCCESSFUL, result);
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000190 result = mHalController->setMode(Mode::LOW_POWER, true);
Lais Andradeb59a9b52020-05-07 17:23:42 +0100191 ASSERT_EQ(HalResult::SUCCESSFUL, result);
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000192
Lais Andradeb59a9b52020-05-07 17:23:42 +0100193 // PowerHalConnector was called only twice: on first api call and after failed
194 // call.
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000195 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
202TEST_F(PowerHalControllerTest, TestPowerHalDoesNotTryToRecoverFromFailureOnUnsupportedCalls) {
203 int powerHalConnectCount = mHalConnector->getConnectCount();
204 EXPECT_EQ(powerHalConnectCount, 0);
205
206 auto result = mHalController->setBoost(Boost::CAMERA_LAUNCH, 1000);
Lais Andradeb59a9b52020-05-07 17:23:42 +0100207 ASSERT_EQ(HalResult::UNSUPPORTED, result);
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000208 result = mHalController->setMode(Mode::CAMERA_STREAMING_HIGH, true);
Lais Andradeb59a9b52020-05-07 17:23:42 +0100209 ASSERT_EQ(HalResult::UNSUPPORTED, result);
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000210
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
218TEST_F(PowerHalControllerTest, TestMultiThreadConnectsOnlyOnce) {
219 int powerHalConnectCount = mHalConnector->getConnectCount();
220 EXPECT_EQ(powerHalConnectCount, 0);
221
Lais Andradeb59a9b52020-05-07 17:23:42 +0100222 EXPECT_CALL(*mMockHal.get(), powerHint(_, _)).Times(Exactly(10));
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000223
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);
Lais Andradeb59a9b52020-05-07 17:23:42 +0100228 ASSERT_EQ(HalResult::SUCCESSFUL, result);
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000229 }));
230 }
231 std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
232
Lais Andradeb59a9b52020-05-07 17:23:42 +0100233 // PowerHalConnector was called only by the first thread to use the api and
234 // never reset.
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000235 powerHalConnectCount = mHalConnector->getConnectCount();
236 EXPECT_EQ(powerHalConnectCount, 1);
237 int powerHalResetCount = mHalConnector->getResetCount();
238 EXPECT_EQ(powerHalResetCount, 0);
239}
240
241TEST_F(PowerHalControllerTest, TestMultiThreadWithFailureReconnectIsThreadSafe) {
242 int powerHalConnectCount = mHalConnector->getConnectCount();
243 EXPECT_EQ(powerHalConnectCount, 0);
244
245 ON_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), _))
Lais Andradeb59a9b52020-05-07 17:23:42 +0100246 .WillByDefault([](PowerHint, int32_t) {
247 return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
248 });
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000249
Lais Andradeb59a9b52020-05-07 17:23:42 +0100250 EXPECT_CALL(*mMockHal.get(), powerHint(_, _)).Times(Exactly(40));
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000251
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);
Lais Andradeb59a9b52020-05-07 17:23:42 +0100256 ASSERT_EQ(HalResult::SUCCESSFUL, result);
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000257 }));
258 threads.push_back(std::thread([&]() {
259 auto result = mHalController->setMode(Mode::LAUNCH, true);
Lais Andradeb59a9b52020-05-07 17:23:42 +0100260 ASSERT_EQ(HalResult::FAILED, result);
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000261 }));
262 threads.push_back(std::thread([&]() {
263 auto result = mHalController->setMode(Mode::LOW_POWER, false);
Lais Andradeb59a9b52020-05-07 17:23:42 +0100264 ASSERT_EQ(HalResult::SUCCESSFUL, result);
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000265 }));
266 threads.push_back(std::thread([&]() {
267 auto result = mHalController->setMode(Mode::VR, true);
Lais Andradeb59a9b52020-05-07 17:23:42 +0100268 ASSERT_EQ(HalResult::SUCCESSFUL, result);
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000269 }));
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.
Lais Andradeb59a9b52020-05-07 17:23:42 +0100274 // Reset and reconnect calls were made at most 10 times, once after each
275 // failure.
Lais Andrade3f7ecc52020-03-25 23:57:08 +0000276 powerHalConnectCount = mHalConnector->getConnectCount();
277 EXPECT_THAT(powerHalConnectCount, AllOf(Ge(1), Le(11)));
278 int powerHalResetCount = mHalConnector->getResetCount();
279 EXPECT_THAT(powerHalResetCount, Le(10));
280}