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