1 /*
2 * Copyright (C) 2021 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 "PerformanceHintNativeTest"
18
19 #include <android/os/IHintManager.h>
20 #include <android/os/IHintSession.h>
21 #include <android/performance_hint.h>
22 #include <binder/IBinder.h>
23 #include <gmock/gmock.h>
24 #include <gtest/gtest.h>
25 #include <performance_hint_private.h>
26
27 #include <memory>
28 #include <vector>
29
30 using android::binder::Status;
31 using android::os::IHintManager;
32 using android::os::IHintSession;
33
34 using namespace android;
35 using namespace testing;
36
37 class MockIHintManager : public IHintManager {
38 public:
39 MOCK_METHOD(Status, createHintSession,
40 (const sp<IBinder>& token, const ::std::vector<int32_t>& tids,
41 int64_t durationNanos, ::android::sp<IHintSession>* _aidl_return),
42 (override));
43 MOCK_METHOD(Status, getHintSessionPreferredRate, (int64_t * _aidl_return), (override));
44 MOCK_METHOD(Status, setHintSessionThreads,
45 (const sp<IHintSession>& hintSession, const ::std::vector<int32_t>& tids),
46 (override));
47 MOCK_METHOD(Status, getHintSessionThreadIds,
48 (const sp<IHintSession>& hintSession, ::std::vector<int32_t>* tids), (override));
49 MOCK_METHOD(IBinder*, onAsBinder, (), (override));
50 };
51
52 class MockIHintSession : public IHintSession {
53 public:
54 MOCK_METHOD(Status, updateTargetWorkDuration, (int64_t targetDurationNanos), (override));
55 MOCK_METHOD(Status, reportActualWorkDuration,
56 (const ::std::vector<int64_t>& actualDurationNanos,
57 const ::std::vector<int64_t>& timeStampNanos),
58 (override));
59 MOCK_METHOD(Status, sendHint, (int32_t hints), (override));
60 MOCK_METHOD(Status, close, (), (override));
61 MOCK_METHOD(IBinder*, onAsBinder, (), (override));
62 };
63
64 class PerformanceHintTest : public Test {
65 public:
SetUp()66 void SetUp() override {
67 mMockIHintManager = new StrictMock<MockIHintManager>();
68 APerformanceHint_setIHintManagerForTesting(mMockIHintManager);
69 }
70
TearDown()71 void TearDown() override {
72 mMockIHintManager = nullptr;
73 // Destroys MockIHintManager.
74 APerformanceHint_setIHintManagerForTesting(nullptr);
75 }
76
createManager()77 APerformanceHintManager* createManager() {
78 EXPECT_CALL(*mMockIHintManager, getHintSessionPreferredRate(_))
79 .Times(Exactly(1))
80 .WillRepeatedly(DoAll(SetArgPointee<0>(123L), Return(Status())));
81 return APerformanceHint_getManager();
82 }
83
84 StrictMock<MockIHintManager>* mMockIHintManager = nullptr;
85 };
86
TEST_F(PerformanceHintTest,TestGetPreferredUpdateRateNanos)87 TEST_F(PerformanceHintTest, TestGetPreferredUpdateRateNanos) {
88 APerformanceHintManager* manager = createManager();
89 int64_t preferredUpdateRateNanos = APerformanceHint_getPreferredUpdateRateNanos(manager);
90 EXPECT_EQ(123L, preferredUpdateRateNanos);
91 }
92
TEST_F(PerformanceHintTest,TestSession)93 TEST_F(PerformanceHintTest, TestSession) {
94 APerformanceHintManager* manager = createManager();
95
96 std::vector<int32_t> tids;
97 tids.push_back(1);
98 tids.push_back(2);
99 int64_t targetDuration = 56789L;
100
101 StrictMock<MockIHintSession>* iSession = new StrictMock<MockIHintSession>();
102 sp<IHintSession> session_sp(iSession);
103
104 EXPECT_CALL(*mMockIHintManager, createHintSession(_, Eq(tids), Eq(targetDuration), _))
105 .Times(Exactly(1))
106 .WillRepeatedly(DoAll(SetArgPointee<3>(std::move(session_sp)), Return(Status())));
107
108 APerformanceHintSession* session =
109 APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration);
110 ASSERT_TRUE(session);
111
112 int64_t targetDurationNanos = 10;
113 EXPECT_CALL(*iSession, updateTargetWorkDuration(Eq(targetDurationNanos))).Times(Exactly(1));
114 int result = APerformanceHint_updateTargetWorkDuration(session, targetDurationNanos);
115 EXPECT_EQ(0, result);
116
117 usleep(2); // Sleep for longer than preferredUpdateRateNanos.
118 int64_t actualDurationNanos = 20;
119 std::vector<int64_t> actualDurations;
120 actualDurations.push_back(20);
121 EXPECT_CALL(*iSession, reportActualWorkDuration(Eq(actualDurations), _)).Times(Exactly(1));
122 result = APerformanceHint_reportActualWorkDuration(session, actualDurationNanos);
123 EXPECT_EQ(0, result);
124
125 result = APerformanceHint_updateTargetWorkDuration(session, -1L);
126 EXPECT_EQ(EINVAL, result);
127 result = APerformanceHint_reportActualWorkDuration(session, -1L);
128 EXPECT_EQ(EINVAL, result);
129
130 SessionHint hintId = SessionHint::CPU_LOAD_RESET;
131 EXPECT_CALL(*iSession, sendHint(Eq(hintId))).Times(Exactly(1));
132 result = APerformanceHint_sendHint(session, hintId);
133 EXPECT_EQ(0, result);
134 usleep(110000); // Sleep for longer than the update timeout.
135 EXPECT_CALL(*iSession, sendHint(Eq(hintId))).Times(Exactly(1));
136 result = APerformanceHint_sendHint(session, hintId);
137 EXPECT_EQ(0, result);
138 // Expect to get rate limited if we try to send faster than the limiter allows
139 EXPECT_CALL(*iSession, sendHint(Eq(hintId))).Times(Exactly(0));
140 result = APerformanceHint_sendHint(session, hintId);
141 EXPECT_EQ(0, result);
142
143 result = APerformanceHint_sendHint(session, static_cast<SessionHint>(-1));
144 EXPECT_EQ(EINVAL, result);
145
146 EXPECT_CALL(*iSession, close()).Times(Exactly(1));
147 APerformanceHint_closeSession(session);
148 }
149
TEST_F(PerformanceHintTest,SetThreads)150 TEST_F(PerformanceHintTest, SetThreads) {
151 APerformanceHintManager* manager = createManager();
152
153 std::vector<int32_t> tids;
154 tids.push_back(1);
155 tids.push_back(2);
156 int64_t targetDuration = 56789L;
157
158 StrictMock<MockIHintSession>* iSession = new StrictMock<MockIHintSession>();
159 sp<IHintSession> session_sp(iSession);
160
161 EXPECT_CALL(*mMockIHintManager, createHintSession(_, Eq(tids), Eq(targetDuration), _))
162 .Times(Exactly(1))
163 .WillRepeatedly(DoAll(SetArgPointee<3>(std::move(session_sp)), Return(Status())));
164
165 APerformanceHintSession* session =
166 APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration);
167 ASSERT_TRUE(session);
168
169 std::vector<int32_t> emptyTids;
170 int result = APerformanceHint_setThreads(session, emptyTids.data(), emptyTids.size());
171 EXPECT_EQ(EINVAL, result);
172
173 std::vector<int32_t> newTids;
174 newTids.push_back(1);
175 newTids.push_back(3);
176 EXPECT_CALL(*mMockIHintManager, setHintSessionThreads(_, Eq(newTids)))
177 .Times(Exactly(1))
178 .WillOnce(Return(Status()));
179 result = APerformanceHint_setThreads(session, newTids.data(), newTids.size());
180 EXPECT_EQ(0, result);
181 }
182