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 "PowerHalWrapperAidlTest"
18
19 #include <aidl/android/hardware/power/Boost.h>
20 #include <aidl/android/hardware/power/IPowerHintSession.h>
21 #include <aidl/android/hardware/power/Mode.h>
22 #include <binder/IServiceManager.h>
23 #include <gmock/gmock.h>
24 #include <gtest/gtest.h>
25 #include <powermanager/PowerHalWrapper.h>
26 #include <utils/Log.h>
27
28 #include <unistd.h>
29 #include <thread>
30
31 using aidl::android::hardware::power::Boost;
32 using aidl::android::hardware::power::ChannelConfig;
33 using aidl::android::hardware::power::IPower;
34 using aidl::android::hardware::power::IPowerHintSession;
35 using aidl::android::hardware::power::Mode;
36 using aidl::android::hardware::power::SessionConfig;
37 using aidl::android::hardware::power::SessionTag;
38 using android::binder::Status;
39
40 using namespace android;
41 using namespace android::power;
42 using namespace std::chrono_literals;
43 using namespace testing;
44
45 // -------------------------------------------------------------------------------------------------
46
47 class MockIPower : public IPower {
48 public:
49 MockIPower() = default;
50
51 MOCK_METHOD(ndk::ScopedAStatus, isBoostSupported, (Boost boost, bool* ret), (override));
52 MOCK_METHOD(ndk::ScopedAStatus, setBoost, (Boost boost, int32_t durationMs), (override));
53 MOCK_METHOD(ndk::ScopedAStatus, isModeSupported, (Mode mode, bool* ret), (override));
54 MOCK_METHOD(ndk::ScopedAStatus, setMode, (Mode mode, bool enabled), (override));
55 MOCK_METHOD(ndk::ScopedAStatus, createHintSession,
56 (int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds,
57 int64_t durationNanos, std::shared_ptr<IPowerHintSession>* session),
58 (override));
59 MOCK_METHOD(ndk::ScopedAStatus, createHintSessionWithConfig,
60 (int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds,
61 int64_t durationNanos, SessionTag tag, SessionConfig* config,
62 std::shared_ptr<IPowerHintSession>* _aidl_return),
63 (override));
64 MOCK_METHOD(ndk::ScopedAStatus, getSessionChannel,
65 (int32_t tgid, int32_t uid, ChannelConfig* _aidl_return), (override));
66 MOCK_METHOD(ndk::ScopedAStatus, closeSessionChannel, (int32_t tgid, int32_t uid), (override));
67 MOCK_METHOD(ndk::ScopedAStatus, getHintSessionPreferredRate, (int64_t * rate), (override));
68 MOCK_METHOD(ndk::ScopedAStatus, getInterfaceVersion, (int32_t * version), (override));
69 MOCK_METHOD(ndk::ScopedAStatus, getInterfaceHash, (std::string * hash), (override));
70 MOCK_METHOD(ndk::SpAIBinder, asBinder, (), (override));
71 MOCK_METHOD(bool, isRemote, (), (override));
72 };
73
74 // -------------------------------------------------------------------------------------------------
75
76 class PowerHalWrapperAidlTest : public Test {
77 public:
78 void SetUp() override;
79
80 protected:
81 std::unique_ptr<HalWrapper> mWrapper = nullptr;
82 std::shared_ptr<StrictMock<MockIPower>> mMockHal = nullptr;
83 };
84
85 // -------------------------------------------------------------------------------------------------
86
SetUp()87 void PowerHalWrapperAidlTest::SetUp() {
88 mMockHal = ndk::SharedRefBase::make<StrictMock<MockIPower>>();
89 EXPECT_CALL(*mMockHal, getInterfaceVersion(_)).WillRepeatedly(([](int32_t* ret) {
90 *ret = 5;
91 return ndk::ScopedAStatus::ok();
92 }));
93 mWrapper = std::make_unique<AidlHalWrapper>(mMockHal);
94 ASSERT_NE(nullptr, mWrapper);
95 }
96
97 // -------------------------------------------------------------------------------------------------
98
TEST_F(PowerHalWrapperAidlTest,TestSetBoostSuccessful)99 TEST_F(PowerHalWrapperAidlTest, TestSetBoostSuccessful) {
100 {
101 InSequence seq;
102 EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::DISPLAY_UPDATE_IMMINENT), _))
103 .Times(Exactly(1))
104 .WillOnce(DoAll(SetArgPointee<1>(true),
105 Return(testing::ByMove(ndk::ScopedAStatus::ok()))));
106 EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::DISPLAY_UPDATE_IMMINENT), Eq(100)))
107 .Times(Exactly(1))
108 .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok())));
109 }
110
111 auto result = mWrapper->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 100);
112 ASSERT_TRUE(result.isOk());
113 }
114
TEST_F(PowerHalWrapperAidlTest,TestSetBoostFailed)115 TEST_F(PowerHalWrapperAidlTest, TestSetBoostFailed) {
116 {
117 InSequence seq;
118 EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::INTERACTION), _))
119 .Times(Exactly(1))
120 .WillOnce(DoAll(SetArgPointee<1>(true),
121 Return(testing::ByMove(ndk::ScopedAStatus::ok()))));
122 EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::INTERACTION), Eq(100)))
123 .Times(Exactly(1))
124 .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::fromExceptionCode(-1))));
125 EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::DISPLAY_UPDATE_IMMINENT), _))
126 .Times(Exactly(1))
127 .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::fromExceptionCode(-1))));
128 }
129
130 auto result = mWrapper->setBoost(Boost::INTERACTION, 100);
131 ASSERT_TRUE(result.isFailed());
132 result = mWrapper->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 1000);
133 ASSERT_TRUE(result.isFailed());
134 }
135
TEST_F(PowerHalWrapperAidlTest,TestSetBoostUnsupported)136 TEST_F(PowerHalWrapperAidlTest, TestSetBoostUnsupported) {
137 EXPECT_CALL(*mMockHal.get(), isBoostSupported(_, _))
138 .Times(Exactly(2))
139 .WillRepeatedly([](Boost, bool* ret) {
140 *ret = false;
141 return ndk::ScopedAStatus::ok();
142 });
143
144 auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
145 ASSERT_TRUE(result.isUnsupported());
146 result = mWrapper->setBoost(Boost::CAMERA_SHOT, 10);
147 ASSERT_TRUE(result.isUnsupported());
148 }
149
TEST_F(PowerHalWrapperAidlTest,TestSetBoostMultiThreadCheckSupportedOnlyOnce)150 TEST_F(PowerHalWrapperAidlTest, TestSetBoostMultiThreadCheckSupportedOnlyOnce) {
151 {
152 InSequence seq;
153 EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::INTERACTION), _))
154 .Times(Exactly(1))
155 .WillOnce(DoAll(SetArgPointee<1>(true),
156 Return(testing::ByMove(ndk::ScopedAStatus::ok()))));
157 auto& exp = EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::INTERACTION), Eq(100)))
158 .Times(Exactly(10));
159 for (int i = 0; i < 10; i++) {
160 exp.WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok())));
161 }
162 }
163
164 std::vector<std::thread> threads;
165 for (int i = 0; i < 10; i++) {
166 threads.push_back(std::thread([&]() {
167 auto result = mWrapper->setBoost(Boost::INTERACTION, 100);
168 ASSERT_TRUE(result.isOk());
169 }));
170 }
171 std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
172 }
173
TEST_F(PowerHalWrapperAidlTest,TestSetModeSuccessful)174 TEST_F(PowerHalWrapperAidlTest, TestSetModeSuccessful) {
175 {
176 InSequence seq;
177 EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::DISPLAY_INACTIVE), _))
178 .Times(Exactly(1))
179 .WillOnce(DoAll(SetArgPointee<1>(true),
180 Return(testing::ByMove(ndk::ScopedAStatus::ok()))));
181 EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::DISPLAY_INACTIVE), Eq(false)))
182 .Times(Exactly(1))
183 .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok())));
184 }
185
186 auto result = mWrapper->setMode(Mode::DISPLAY_INACTIVE, false);
187 ASSERT_TRUE(result.isOk());
188 }
189
TEST_F(PowerHalWrapperAidlTest,TestSetModeFailed)190 TEST_F(PowerHalWrapperAidlTest, TestSetModeFailed) {
191 {
192 InSequence seq;
193 EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::LAUNCH), _))
194 .Times(Exactly(1))
195 .WillOnce(DoAll(SetArgPointee<1>(true),
196 Return(testing::ByMove(ndk::ScopedAStatus::ok()))));
197 EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::LAUNCH), Eq(true)))
198 .Times(Exactly(1))
199 .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::fromExceptionCode(-1))));
200 EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::DISPLAY_INACTIVE), _))
201 .Times(Exactly(1))
202 .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::fromExceptionCode(-1))));
203 }
204
205 auto result = mWrapper->setMode(Mode::LAUNCH, true);
206 ASSERT_TRUE(result.isFailed());
207 result = mWrapper->setMode(Mode::DISPLAY_INACTIVE, false);
208 ASSERT_TRUE(result.isFailed());
209 }
210
TEST_F(PowerHalWrapperAidlTest,TestSetModeUnsupported)211 TEST_F(PowerHalWrapperAidlTest, TestSetModeUnsupported) {
212 EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::LAUNCH), _))
213 .Times(Exactly(1))
214 .WillOnce(DoAll(SetArgPointee<1>(false),
215 Return(testing::ByMove(ndk::ScopedAStatus::ok()))));
216
217 auto result = mWrapper->setMode(Mode::LAUNCH, true);
218 ASSERT_TRUE(result.isUnsupported());
219
220 EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::CAMERA_STREAMING_HIGH), _))
221 .Times(Exactly(1))
222 .WillOnce(DoAll(SetArgPointee<1>(false),
223 Return(testing::ByMove(ndk::ScopedAStatus::ok()))));
224 result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true);
225 ASSERT_TRUE(result.isUnsupported());
226 }
227
TEST_F(PowerHalWrapperAidlTest,TestSetModeMultiThreadCheckSupportedOnlyOnce)228 TEST_F(PowerHalWrapperAidlTest, TestSetModeMultiThreadCheckSupportedOnlyOnce) {
229 {
230 InSequence seq;
231 EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::LAUNCH), _))
232 .Times(Exactly(1))
233 .WillOnce(DoAll(SetArgPointee<1>(true),
234 Return(testing::ByMove(ndk::ScopedAStatus::ok()))));
235 auto& exp = EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::LAUNCH), Eq(false)))
236 .Times(Exactly(10));
237 for (int i = 0; i < 10; i++) {
238 exp.WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok())));
239 }
240 }
241
242 std::vector<std::thread> threads;
243 for (int i = 0; i < 10; i++) {
244 threads.push_back(std::thread([&]() {
245 auto result = mWrapper->setMode(Mode::LAUNCH, false);
246 ASSERT_TRUE(result.isOk());
247 }));
248 }
249 std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
250 }
251
TEST_F(PowerHalWrapperAidlTest,TestCreateHintSessionSuccessful)252 TEST_F(PowerHalWrapperAidlTest, TestCreateHintSessionSuccessful) {
253 std::vector<int> threadIds{gettid()};
254 int32_t tgid = 999;
255 int32_t uid = 1001;
256 int64_t durationNanos = 16666666L;
257 EXPECT_CALL(*mMockHal.get(),
258 createHintSession(Eq(tgid), Eq(uid), Eq(threadIds), Eq(durationNanos), _))
259 .Times(Exactly(1))
260 .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok())));
261 auto result = mWrapper->createHintSession(tgid, uid, threadIds, durationNanos);
262 ASSERT_TRUE(result.isOk());
263 }
264
TEST_F(PowerHalWrapperAidlTest,TestCreateHintSessionWithConfigSuccessful)265 TEST_F(PowerHalWrapperAidlTest, TestCreateHintSessionWithConfigSuccessful) {
266 std::vector<int> threadIds{gettid()};
267 int32_t tgid = 999;
268 int32_t uid = 1001;
269 int64_t durationNanos = 16666666L;
270 SessionTag tag = SessionTag::OTHER;
271 SessionConfig out;
272 EXPECT_CALL(*mMockHal.get(),
273 createHintSessionWithConfig(Eq(tgid), Eq(uid), Eq(threadIds), Eq(durationNanos),
274 Eq(tag), _, _))
275 .Times(Exactly(1))
276 .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok())));
277 auto result =
278 mWrapper->createHintSessionWithConfig(tgid, uid, threadIds, durationNanos, tag, &out);
279 ASSERT_TRUE(result.isOk());
280 }
281
TEST_F(PowerHalWrapperAidlTest,TestCreateHintSessionFailed)282 TEST_F(PowerHalWrapperAidlTest, TestCreateHintSessionFailed) {
283 int32_t tgid = 999;
284 int32_t uid = 1001;
285 std::vector<int> threadIds{};
286 int64_t durationNanos = 16666666L;
287 EXPECT_CALL(*mMockHal.get(),
288 createHintSession(Eq(tgid), Eq(uid), Eq(threadIds), Eq(durationNanos), _))
289 .Times(Exactly(1))
290 .WillOnce(Return(testing::ByMove(
291 ndk::ScopedAStatus::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT))));
292 auto result = mWrapper->createHintSession(tgid, uid, threadIds, durationNanos);
293 ASSERT_TRUE(result.isFailed());
294 }
295
TEST_F(PowerHalWrapperAidlTest,TestGetHintSessionPreferredRate)296 TEST_F(PowerHalWrapperAidlTest, TestGetHintSessionPreferredRate) {
297 EXPECT_CALL(*mMockHal.get(), getHintSessionPreferredRate(_))
298 .Times(Exactly(1))
299 .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok())));
300 auto result = mWrapper->getHintSessionPreferredRate();
301 ASSERT_TRUE(result.isOk());
302 int64_t rate = result.value();
303 ASSERT_GE(0, rate);
304 }
305
TEST_F(PowerHalWrapperAidlTest,TestSessionChannel)306 TEST_F(PowerHalWrapperAidlTest, TestSessionChannel) {
307 int32_t tgid = 999;
308 int32_t uid = 1001;
309 EXPECT_CALL(*mMockHal.get(), getSessionChannel(Eq(tgid), Eq(uid), _))
310 .Times(Exactly(1))
311 .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok())));
312 EXPECT_CALL(*mMockHal.get(), closeSessionChannel(Eq(tgid), Eq(uid)))
313 .Times(Exactly(1))
314 .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok())));
315 auto createResult = mWrapper->getSessionChannel(tgid, uid);
316 ASSERT_TRUE(createResult.isOk());
317 auto closeResult = mWrapper->closeSessionChannel(tgid, uid);
318 ASSERT_TRUE(closeResult.isOk());
319 }
320
TEST_F(PowerHalWrapperAidlTest,TestCreateHintSessionWithConfigUnsupported)321 TEST_F(PowerHalWrapperAidlTest, TestCreateHintSessionWithConfigUnsupported) {
322 std::vector<int> threadIds{gettid()};
323 int32_t tgid = 999;
324 int32_t uid = 1001;
325 int64_t durationNanos = 16666666L;
326 SessionTag tag = SessionTag::OTHER;
327 SessionConfig out;
328 EXPECT_CALL(*mMockHal.get(),
329 createHintSessionWithConfig(Eq(tgid), Eq(uid), Eq(threadIds), Eq(durationNanos),
330 Eq(tag), _, _))
331 .Times(1)
332 .WillOnce(Return(testing::ByMove(
333 ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION))));
334 auto result =
335 mWrapper->createHintSessionWithConfig(tgid, uid, threadIds, durationNanos, tag, &out);
336 ASSERT_TRUE(result.isUnsupported());
337 Mock::VerifyAndClearExpectations(mMockHal.get());
338 EXPECT_CALL(*mMockHal.get(),
339 createHintSessionWithConfig(Eq(tgid), Eq(uid), Eq(threadIds), Eq(durationNanos),
340 Eq(tag), _, _))
341 .WillOnce(Return(
342 testing::ByMove(ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION))));
343 result = mWrapper->createHintSessionWithConfig(tgid, uid, threadIds, durationNanos, tag, &out);
344 ASSERT_TRUE(result.isUnsupported());
345 }
346