blob: e25a0aea245c1d00e74b3b3b9fa68174330b54b9 [file] [log] [blame]
Xiang Wange12b4fa2022-03-25 23:48:40 +00001/*
2 * Copyright 2022 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#undef LOG_TAG
18#define LOG_TAG "AidlPowerHalWrapperTest"
19
20#include <android/hardware/power/IPower.h>
21#include <android/hardware/power/IPowerHintSession.h>
22#include <gmock/gmock.h>
23#include <gtest/gtest.h>
24#include <algorithm>
25#include <chrono>
26#include <memory>
27#include "DisplayHardware/PowerAdvisor.h"
28#include "android/hardware/power/WorkDuration.h"
29#include "binder/Status.h"
30#include "log/log_main.h"
31#include "mock/DisplayHardware/MockIPower.h"
32#include "mock/DisplayHardware/MockIPowerHintSession.h"
33#include "utils/Timers.h"
34
35using namespace android;
36using namespace android::Hwc2::mock;
37using namespace android::hardware::power;
38using namespace std::chrono_literals;
39using namespace testing;
40
41namespace android::Hwc2::impl {
42
43class AidlPowerHalWrapperTest : public testing::Test {
44public:
45 void SetUp() override;
46
47protected:
48 std::unique_ptr<AidlPowerHalWrapper> mWrapper = nullptr;
49 sp<NiceMock<MockIPower>> mMockHal = nullptr;
50 sp<NiceMock<MockIPowerHintSession>> mMockSession = nullptr;
51 void verifyAndClearExpectations();
52 void sendActualWorkDurationGroup(std::vector<WorkDuration> durations,
53 std::chrono::nanoseconds sleepBeforeLastSend);
54};
55
56void AidlPowerHalWrapperTest::SetUp() {
57 mMockHal = new NiceMock<MockIPower>();
58 mMockSession = new NiceMock<MockIPowerHintSession>();
59 ON_CALL(*mMockHal.get(), getHintSessionPreferredRate(_)).WillByDefault(Return(Status::ok()));
60 mWrapper = std::make_unique<AidlPowerHalWrapper>(mMockHal);
61}
62
63void AidlPowerHalWrapperTest::verifyAndClearExpectations() {
64 Mock::VerifyAndClearExpectations(mMockHal.get());
65 Mock::VerifyAndClearExpectations(mMockSession.get());
66}
67
68void AidlPowerHalWrapperTest::sendActualWorkDurationGroup(
69 std::vector<WorkDuration> durations, std::chrono::nanoseconds sleepBeforeLastSend) {
70 for (size_t i = 0; i < durations.size(); i++) {
71 if (i == durations.size() - 1) {
72 std::this_thread::sleep_for(sleepBeforeLastSend);
73 }
74 auto duration = durations[i];
75 mWrapper->sendActualWorkDuration(duration.durationNanos, duration.timeStampNanos);
76 }
77}
78WorkDuration toWorkDuration(std::chrono::nanoseconds durationNanos, int64_t timeStampNanos) {
79 WorkDuration duration;
80 duration.durationNanos = durationNanos.count();
81 duration.timeStampNanos = timeStampNanos;
82 return duration;
83}
84
85namespace {
86TEST_F(AidlPowerHalWrapperTest, supportsPowerHintSession) {
87 ASSERT_TRUE(mWrapper->supportsPowerHintSession());
88 Mock::VerifyAndClearExpectations(mMockHal.get());
89 ON_CALL(*mMockHal.get(), getHintSessionPreferredRate(_))
90 .WillByDefault(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE)));
91 auto newWrapper = AidlPowerHalWrapper(mMockHal);
92 EXPECT_FALSE(newWrapper.supportsPowerHintSession());
93}
94
95TEST_F(AidlPowerHalWrapperTest, startPowerHintSession) {
96 ASSERT_TRUE(mWrapper->supportsPowerHintSession());
97 std::vector<int32_t> threadIds = {1, 2};
98 mWrapper->setPowerHintSessionThreadIds(threadIds);
99 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
100 .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
101 EXPECT_TRUE(mWrapper->startPowerHintSession());
102 EXPECT_FALSE(mWrapper->startPowerHintSession());
103}
104
105TEST_F(AidlPowerHalWrapperTest, restartNewPoserHintSessionWithNewThreadIds) {
106 ASSERT_TRUE(mWrapper->supportsPowerHintSession());
107
108 std::vector<int32_t> threadIds = {1, 2};
109 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
110 .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
111 mWrapper->setPowerHintSessionThreadIds(threadIds);
112 EXPECT_EQ(mWrapper->getPowerHintSessionThreadIds(), threadIds);
113 ASSERT_TRUE(mWrapper->startPowerHintSession());
114 verifyAndClearExpectations();
115
116 threadIds = {2, 3};
117 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
118 .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
119 EXPECT_CALL(*mMockSession.get(), close()).Times(1);
120 mWrapper->setPowerHintSessionThreadIds(threadIds);
121 EXPECT_EQ(mWrapper->getPowerHintSessionThreadIds(), threadIds);
122 verifyAndClearExpectations();
123
124 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)).Times(0);
125 EXPECT_CALL(*mMockSession.get(), close()).Times(0);
126 mWrapper->setPowerHintSessionThreadIds(threadIds);
127 verifyAndClearExpectations();
128}
129
130TEST_F(AidlPowerHalWrapperTest, setTargetWorkDuration) {
131 ASSERT_TRUE(mWrapper->supportsPowerHintSession());
132
133 std::vector<int32_t> threadIds = {1, 2};
134 mWrapper->setPowerHintSessionThreadIds(threadIds);
135 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
136 .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
137 ASSERT_TRUE(mWrapper->startPowerHintSession());
138 verifyAndClearExpectations();
139
140 std::chrono::nanoseconds base = 100ms;
141 // test cases with target work duration and whether it should update hint against baseline 100ms
142 const std::vector<std::pair<std::chrono::nanoseconds, bool>> testCases = {{0ms, false},
143 {-1ms, false},
144 {200ms, true},
145 {2ms, true},
146 {96ms, false},
147 {104ms, false}};
148
149 for (const auto& test : testCases) {
150 // reset to 100ms baseline
151 mWrapper->setTargetWorkDuration(1);
152 mWrapper->setTargetWorkDuration(base.count());
153
154 auto target = test.first;
155 EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(target.count()))
156 .Times(test.second ? 1 : 0);
157 mWrapper->setTargetWorkDuration(target.count());
158 verifyAndClearExpectations();
159 }
160}
161
162TEST_F(AidlPowerHalWrapperTest, setTargetWorkDuration_shouldReconnectOnError) {
163 ASSERT_TRUE(mWrapper->supportsPowerHintSession());
164
165 std::vector<int32_t> threadIds = {1, 2};
166 mWrapper->setPowerHintSessionThreadIds(threadIds);
167 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
168 .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
169 ASSERT_TRUE(mWrapper->startPowerHintSession());
170 verifyAndClearExpectations();
171
172 EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(1))
173 .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE)));
174 mWrapper->setTargetWorkDuration(1);
175 EXPECT_TRUE(mWrapper->shouldReconnectHAL());
176}
177
178TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration) {
179 ASSERT_TRUE(mWrapper->supportsPowerHintSession());
180
181 std::vector<int32_t> threadIds = {1, 2};
182 mWrapper->setPowerHintSessionThreadIds(threadIds);
183 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
184 .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
185 ASSERT_TRUE(mWrapper->startPowerHintSession());
186 verifyAndClearExpectations();
187
188 auto base = toWorkDuration(100ms, 0);
189 // test cases with actual work durations and whether it should update hint against baseline
190 // 100ms
191 const std::vector<std::pair<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>, bool>>
192 testCases = {{{{-1ms, 100}}, false},
193 {{{91ms, 100}}, false},
194 {{{109ms, 100}}, false},
195 {{{100ms, 100}, {200ms, 200}}, true},
196 {{{100ms, 500}, {100ms, 600}, {3ms, 600}}, true}};
197
198 for (const auto& test : testCases) {
199 // reset actual duration
200 sendActualWorkDurationGroup({base}, 80ms);
201
202 auto raw = test.first;
203 std::vector<WorkDuration> durations(raw.size());
204 std::transform(raw.begin(), raw.end(), durations.begin(),
205 [](std::pair<std::chrono::nanoseconds, nsecs_t> d) {
206 return toWorkDuration(d.first, d.second);
207 });
208 EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(durations))
209 .Times(test.second ? 1 : 0);
210 sendActualWorkDurationGroup(durations, 0ms);
211 verifyAndClearExpectations();
212 }
213}
214
215TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration_exceedsStaleTime) {
216 ASSERT_TRUE(mWrapper->supportsPowerHintSession());
217
218 std::vector<int32_t> threadIds = {1, 2};
219 mWrapper->setPowerHintSessionThreadIds(threadIds);
220 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
221 .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
222 ASSERT_TRUE(mWrapper->startPowerHintSession());
223 verifyAndClearExpectations();
224
225 auto base = toWorkDuration(100ms, 0);
226 // test cases with actual work durations and whether it should update hint against baseline
227 // 100ms
228 const std::vector<std::pair<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>, bool>>
229 testCases = {{{{91ms, 100}}, true}, {{{109ms, 100}}, true}};
230
231 for (const auto& test : testCases) {
232 // reset actual duration
233 sendActualWorkDurationGroup({base}, 80ms);
234
235 auto raw = test.first;
236 std::vector<WorkDuration> durations(raw.size());
237 std::transform(raw.begin(), raw.end(), durations.begin(),
238 [](std::pair<std::chrono::nanoseconds, nsecs_t> d) {
239 return toWorkDuration(d.first, d.second);
240 });
241 EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(durations))
242 .Times(test.second ? 1 : 0);
243 sendActualWorkDurationGroup(durations, 80ms);
244 verifyAndClearExpectations();
245 }
246}
247
248TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration_shouldReconnectOnError) {
249 ASSERT_TRUE(mWrapper->supportsPowerHintSession());
250
251 std::vector<int32_t> threadIds = {1, 2};
252 mWrapper->setPowerHintSessionThreadIds(threadIds);
253 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
254 .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
255 ASSERT_TRUE(mWrapper->startPowerHintSession());
256 verifyAndClearExpectations();
257 WorkDuration duration;
258 duration.durationNanos = 1;
259 EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(_))
260 .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE)));
261 sendActualWorkDurationGroup({duration}, 0ms);
262 EXPECT_TRUE(mWrapper->shouldReconnectHAL());
263}
264
265} // namespace
266} // namespace android::Hwc2::impl