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