1 /*
2 * Copyright (C) 2024 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 #include <aidl/android/hardware/power/BnPower.h>
18 #include <fmq/AidlMessageQueue.h>
19 #include <fmq/EventFlag.h>
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22
23 #include <future>
24
25 #include "aidl/AdpfTypes.h"
26 #include "aidl/ChannelGroup.h"
27 #include "aidl/ChannelManager.h"
28 #include "aidl/android/hardware/power/ChannelMessage.h"
29 #include "aidl/android/hardware/power/WorkDurationFixedV1.h"
30 #include "android/binder_auto_utils.h"
31 #include "gmock/gmock.h"
32 #include "mocks/MockPowerHintSession.h"
33 #include "mocks/MockPowerSessionManager.h"
34
35 namespace aidl::google::hardware::power::impl::pixel {
36
37 using namespace std::chrono_literals;
38 using namespace testing;
39 using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
40 using ::android::AidlMessageQueue;
41 using ::android::hardware::EventFlag;
42 using android::hardware::power::ChannelMessage;
43
44 using SessionMessageQueue = AidlMessageQueue<ChannelMessage, SynchronizedReadWrite>;
45 using FlagMessageQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
46
47 constexpr int kChannelId = 1;
48
49 class ChannelGroupTest : public Test {
50 public:
SetUp()51 virtual void SetUp() {
52 mManager = NiceMock<mock::pixel::MockPowerSessionManager>::getInstance();
53 Mock::VerifyAndClear(mManager);
54 }
55
56 protected:
57 NiceMock<mock::pixel::MockPowerSessionManager> *mManager;
58 ChannelGroup<NiceMock<mock::pixel::MockPowerSessionManager>,
59 NiceMock<mock::pixel::MockPowerHintSession>>
60 mChannelGroup{1};
61 };
62
63 class FMQTest : public ChannelGroupTest {
64 public:
SetUp()65 void SetUp() override {
66 ChannelGroupTest::SetUp();
67 std::optional<FlagQueueDesc> flagDesc;
68 mChannelGroup.getFlagDesc(&flagDesc);
69 mBackendChannel = mChannelGroup.createChannel(mTestTgid, mTestUid);
70 ChannelQueueDesc channelDesc;
71 mBackendChannel->getDesc(&channelDesc);
72 mChannel = std::make_shared<SessionMessageQueue>(channelDesc, true);
73 mReadFlag = mBackendChannel->getReadBitmask();
74 mWriteFlag = mBackendChannel->getWriteBitmask();
75 ASSERT_TRUE(mChannel->isValid());
76
77 if (flagDesc.has_value()) {
78 mFlagChannel = std::make_shared<FlagMessageQueue>(*flagDesc, true);
79 ASSERT_EQ(EventFlag::createEventFlag(mFlagChannel->getEventFlagWord(), &mEventFlag),
80 ::android::OK);
81 } else {
82 ASSERT_EQ(EventFlag::createEventFlag(mChannel->getEventFlagWord(), &mEventFlag),
83 ::android::OK);
84 }
85
86 ASSERT_NE(mEventFlag, nullptr);
87
88 mMockPowerHintSession = std::make_shared<NiceMock<mock::pixel::MockPowerHintSession>>();
89 ON_CALL(*mMockPowerHintSession, getSessionConfig)
90 .WillByDefault(DoAll(SetArgPointee<0>(SessionConfig{.id = mSessionId}),
91 Return(ByMove(ndk::ScopedAStatus::ok()))));
92
93 ON_CALL(*mManager, getSession(Eq(mSessionId))).WillByDefault(Return(mMockPowerHintSession));
94 }
TearDown()95 void TearDown() {}
96
97 protected:
98 int mTestTgid = 123;
99 int mTestUid = 234;
100 int mSessionId = 4;
101 uint32_t mReadFlag;
102 uint32_t mWriteFlag;
103 std::shared_ptr<IPowerHintSession> mSession;
104 std::shared_ptr<SessionMessageQueue> mChannel;
105 std::shared_ptr<FlagMessageQueue> mFlagChannel;
106 std::shared_ptr<SessionChannel> mBackendChannel;
107 ::android::hardware::EventFlag *mEventFlag;
108 // SessionConfig mSessionConfig{.id=mSessionId};
109 std::shared_ptr<NiceMock<mock::pixel::MockPowerHintSession>> mMockPowerHintSession;
110 };
111
WorkDurationsAreSame(WorkDuration a,WorkDuration b)112 bool WorkDurationsAreSame(WorkDuration a, WorkDuration b) {
113 return a.timeStampNanos == b.timeStampNanos && a.cpuDurationNanos,
114 b.cpuDurationNanos && a.gpuDurationNanos == b.gpuDurationNanos &&
115 a.workPeriodStartTimestampNanos == b.workPeriodStartTimestampNanos &&
116 a.durationNanos == b.durationNanos;
117 }
118
TEST_F(ChannelGroupTest,testCreateAndDestroyChannelGroup)119 TEST_F(ChannelGroupTest, testCreateAndDestroyChannelGroup) {}
120
TEST_F(ChannelGroupTest,testCreateChannel)121 TEST_F(ChannelGroupTest, testCreateChannel) {
122 int tgid = 234;
123 int uid = 123;
124 int count1 = mChannelGroup.getChannelCount();
125 auto out = mChannelGroup.createChannel(tgid, uid);
126
127 EXPECT_EQ(mChannelGroup.getChannelCount(), count1 + 1);
128 EXPECT_EQ(out->getUid(), uid);
129 EXPECT_EQ(out->getTgid(), tgid);
130 }
131
TEST_F(ChannelGroupTest,testGetChannel)132 TEST_F(ChannelGroupTest, testGetChannel) {
133 int tgid = 234;
134 int uid = 123;
135 int count1 = mChannelGroup.getChannelCount();
136 auto out1 = mChannelGroup.createChannel(tgid, uid);
137 auto out2 = mChannelGroup.getChannel(
138 ChannelManager<>::ChannelMapValue{.value = out1->getId()}.offset);
139
140 EXPECT_EQ(mChannelGroup.getChannelCount(), count1 + 1);
141 EXPECT_EQ(out1->getId(), out2->getId());
142 EXPECT_EQ(out1->getTgid(), out2->getTgid());
143 EXPECT_EQ(out1->getId(), out2->getId());
144 }
145
TEST_F(ChannelGroupTest,testRemoveChannel)146 TEST_F(ChannelGroupTest, testRemoveChannel) {
147 int tgid = 234;
148 int uid = 123;
149 int count1 = mChannelGroup.getChannelCount();
150 auto out1 = mChannelGroup.createChannel(tgid, uid);
151
152 EXPECT_EQ(mChannelGroup.getChannelCount(), count1 + 1);
153
154 mChannelGroup.removeChannel(ChannelManager<>::ChannelMapValue{.value = out1->getId()}.offset);
155
156 EXPECT_EQ(mChannelGroup.getChannelCount(), count1);
157 }
158
TEST_F(ChannelGroupTest,testGetFlagDesc)159 TEST_F(ChannelGroupTest, testGetFlagDesc) {
160 std::optional<FlagQueueDesc> desc;
161 mChannelGroup.getFlagDesc(&desc);
162
163 EXPECT_EQ(desc.has_value(), true);
164 }
165
TEST_F(FMQTest,testSendingHint)166 TEST_F(FMQTest, testSendingHint) {
167 std::promise<SessionHint> sentHint;
168 EXPECT_CALL(*mMockPowerHintSession, sendHint).Times(1).WillOnce([&](SessionHint hint) {
169 sentHint.set_value(hint);
170 return ndk::ScopedAStatus::ok();
171 });
172
173 ChannelMessage in{.timeStampNanos = 1L,
174 .sessionID = mSessionId,
175 .data = ChannelMessage::ChannelMessageContents::make<
176 ChannelMessage::ChannelMessageContents::Tag::hint>(
177 SessionHint::GPU_LOAD_RESET)};
178 mChannel->writeBlocking(&in, 1, mReadFlag, mWriteFlag, 0, mEventFlag);
179
180 auto future = sentHint.get_future();
181 auto status = future.wait_for(1s);
182 EXPECT_EQ(status, std::future_status::ready);
183 SessionHint out = future.get();
184
185 EXPECT_EQ(out, SessionHint::GPU_LOAD_RESET);
186 }
187
fromWorkDuration(WorkDuration in,int32_t sessionId)188 ChannelMessage fromWorkDuration(WorkDuration in, int32_t sessionId) {
189 return ChannelMessage{
190 .timeStampNanos = in.timeStampNanos,
191 .sessionID = sessionId,
192 .data = ChannelMessage::ChannelMessageContents::make<
193 ChannelMessage::ChannelMessageContents::Tag::workDuration>(WorkDurationFixedV1{
194 .durationNanos = in.durationNanos,
195 .workPeriodStartTimestampNanos = in.workPeriodStartTimestampNanos,
196 .cpuDurationNanos = in.cpuDurationNanos,
197 .gpuDurationNanos = in.gpuDurationNanos})};
198 }
199
TEST_F(FMQTest,testSendingReportActualMessage)200 TEST_F(FMQTest, testSendingReportActualMessage) {
201 std::promise<WorkDuration> reportedDuration;
202 EXPECT_CALL(*mMockPowerHintSession, reportActualWorkDuration)
203 .Times(1)
204 .WillOnce([&](const std::vector<WorkDuration> &actualDurations) {
205 reportedDuration.set_value(actualDurations[0]);
206 return ndk::ScopedAStatus::ok();
207 });
208
209 WorkDuration expected{.timeStampNanos = 1L,
210 .durationNanos = 5L,
211 .workPeriodStartTimestampNanos = 3L,
212 .cpuDurationNanos = 4L,
213 .gpuDurationNanos = 5L};
214
215 ChannelMessage in = fromWorkDuration(expected, mSessionId);
216
217 mChannel->writeBlocking(&in, 1, mReadFlag, mWriteFlag, 0, mEventFlag);
218
219 auto future = reportedDuration.get_future();
220 auto status = future.wait_for(1s);
221 EXPECT_EQ(status, std::future_status::ready);
222 WorkDuration out = future.get();
223
224 EXPECT_EQ(WorkDurationsAreSame(expected, out), true);
225 }
226
TEST_F(FMQTest,testSendingManyReportActualMessages)227 TEST_F(FMQTest, testSendingManyReportActualMessages) {
228 std::promise<std::vector<WorkDuration>> reportedDurations;
229 EXPECT_CALL(*mMockPowerHintSession, reportActualWorkDuration)
230 .Times(1)
231 .WillOnce([&](const std::vector<WorkDuration> &actualDurations) {
232 reportedDurations.set_value(actualDurations);
233 return ndk::ScopedAStatus::ok();
234 });
235
236 WorkDuration expectedBase{.timeStampNanos = 10L,
237 .durationNanos = 50L,
238 .workPeriodStartTimestampNanos = 30L,
239 .cpuDurationNanos = 40L,
240 .gpuDurationNanos = 50L};
241
242 std::vector<WorkDuration> in;
243 std::vector<ChannelMessage> messagesIn;
244 for (int i = 0; i < 20; i++) {
245 in.emplace_back(expectedBase.timeStampNanos + i, expectedBase.durationNanos + i,
246 expectedBase.workPeriodStartTimestampNanos + i,
247 expectedBase.cpuDurationNanos + i, expectedBase.gpuDurationNanos + i);
248 messagesIn.emplace_back(fromWorkDuration(in[i], mSessionId));
249 }
250
251 mChannel->writeBlocking(messagesIn.data(), 20, mReadFlag, mWriteFlag, 0, mEventFlag);
252
253 auto future = reportedDurations.get_future();
254 auto status = future.wait_for(1s);
255 EXPECT_EQ(status, std::future_status::ready);
256 std::vector<WorkDuration> out = future.get();
257 EXPECT_EQ(out.size(), 20);
258
259 for (int i = 0; i < 20; i++) {
260 EXPECT_EQ(WorkDurationsAreSame(in[i], out[i]), true);
261 }
262 }
263
264 } // namespace aidl::google::hardware::power::impl::pixel
265