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