1 /*
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 #include "ThreadPriorityController.h"
18 
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21 
22 namespace android {
23 namespace automotive {
24 namespace watchdog {
25 namespace {
26 
27 using ::aidl::android::automotive::watchdog::internal::ThreadPolicyWithPriority;
28 using ::android::base::Result;
29 using ::testing::_;
30 using ::testing::Return;
31 
32 MATCHER_P(PriorityEq, priority, "") {
33     return (arg->sched_priority) == priority;
34 }
35 
36 class MockSystemCalls : public ThreadPriorityController::SystemCallsInterface {
37 public:
MockSystemCalls(int tid,int uid,int pid)38     MockSystemCalls(int tid, int uid, int pid) {
39         ON_CALL(*this, readPidStatusFileForPid(tid))
40                 .WillByDefault(Return(std::make_tuple(uid, pid)));
41     }
42 
43     MOCK_METHOD(int, setScheduler, (pid_t tid, int policy, const sched_param* param), (override));
44     MOCK_METHOD(int, getScheduler, (pid_t tid), (override));
45     MOCK_METHOD(int, getParam, (pid_t tid, sched_param* param), (override));
46     MOCK_METHOD((Result<std::tuple<uid_t, pid_t>>), readPidStatusFileForPid, (pid_t pid),
47                 (override));
48 };
49 
50 class ThreadPriorityControllerTest : public ::testing::Test {
51 public:
SetUp()52     virtual void SetUp() {
53         std::unique_ptr<MockSystemCalls> mockSystemCalls =
54                 std::make_unique<MockSystemCalls>(TEST_TID, TEST_UID, TEST_PID);
55         mMockSystemCalls = mockSystemCalls.get();
56         mController = std::make_unique<ThreadPriorityController>(std::move(mockSystemCalls));
57     }
58 
59 protected:
60     static constexpr pid_t TEST_PID = 1;
61     static constexpr pid_t TEST_TID = 2;
62     static constexpr uid_t TEST_UID = 3;
63 
64     std::unique_ptr<ThreadPriorityController> mController;
65     MockSystemCalls* mMockSystemCalls;
66 };
67 
TEST_F(ThreadPriorityControllerTest,TestSetThreadPriority)68 TEST_F(ThreadPriorityControllerTest, TestSetThreadPriority) {
69     int policy = SCHED_FIFO;
70     int priority = 1;
71     EXPECT_CALL(*mMockSystemCalls, setScheduler(TEST_TID, policy, PriorityEq(priority)))
72             .WillOnce(Return(0));
73 
74     auto result = mController->setThreadPriority(TEST_PID, TEST_TID, TEST_UID, policy, priority);
75 
76     ASSERT_TRUE(result.ok()) << result.error().message();
77 }
78 
TEST_F(ThreadPriorityControllerTest,TestSetThreadPriorityDefaultPolicy)79 TEST_F(ThreadPriorityControllerTest, TestSetThreadPriorityDefaultPolicy) {
80     int policy = SCHED_OTHER;
81     int setPriority = 1;
82     // Default policy should ignore the provided priority.
83     int expectedPriority = 0;
84     EXPECT_CALL(*mMockSystemCalls, setScheduler(TEST_TID, policy, PriorityEq(expectedPriority)))
85             .WillOnce(Return(0));
86 
87     auto result = mController->setThreadPriority(TEST_PID, TEST_TID, TEST_UID, policy, setPriority);
88 
89     ASSERT_TRUE(result.ok()) << result.error().message();
90 }
91 
TEST_F(ThreadPriorityControllerTest,TestSetThreadPriorityInvalidPid)92 TEST_F(ThreadPriorityControllerTest, TestSetThreadPriorityInvalidPid) {
93     auto result = mController->setThreadPriority(TEST_PID + 1, TEST_TID, TEST_UID, SCHED_FIFO, 1);
94 
95     EXPECT_FALSE(result.ok());
96     EXPECT_EQ(result.error().code(), EX_ILLEGAL_STATE);
97 }
98 
TEST_F(ThreadPriorityControllerTest,TestSetThreadPriorityInvalidTid)99 TEST_F(ThreadPriorityControllerTest, TestSetThreadPriorityInvalidTid) {
100     auto result = mController->setThreadPriority(TEST_PID, TEST_TID + 1, TEST_UID, SCHED_FIFO, 1);
101 
102     EXPECT_FALSE(result.ok());
103     EXPECT_EQ(result.error().code(), EX_ILLEGAL_STATE);
104 }
105 
TEST_F(ThreadPriorityControllerTest,TestSetThreadPriorityInvalidUid)106 TEST_F(ThreadPriorityControllerTest, TestSetThreadPriorityInvalidUid) {
107     auto result = mController->setThreadPriority(TEST_PID, TEST_TID, TEST_UID + 1, SCHED_FIFO, 1);
108 
109     EXPECT_FALSE(result.ok());
110     EXPECT_EQ(result.error().code(), EX_ILLEGAL_STATE);
111 }
112 
TEST_F(ThreadPriorityControllerTest,TestSetThreadPriorityInvalidPolicy)113 TEST_F(ThreadPriorityControllerTest, TestSetThreadPriorityInvalidPolicy) {
114     auto result = mController->setThreadPriority(TEST_PID, TEST_TID, TEST_UID, -1, 1);
115 
116     EXPECT_FALSE(result.ok());
117     EXPECT_EQ(result.error().code(), EX_ILLEGAL_ARGUMENT);
118 }
119 
TEST_F(ThreadPriorityControllerTest,TestSetThreadPriorityInvalidPriority)120 TEST_F(ThreadPriorityControllerTest, TestSetThreadPriorityInvalidPriority) {
121     auto result = mController->setThreadPriority(TEST_PID, TEST_TID, TEST_UID, SCHED_FIFO, 0);
122 
123     EXPECT_FALSE(result.ok());
124     EXPECT_EQ(result.error().code(), EX_ILLEGAL_ARGUMENT);
125 }
126 
TEST_F(ThreadPriorityControllerTest,TestSetThreadPriorityFailed)127 TEST_F(ThreadPriorityControllerTest, TestSetThreadPriorityFailed) {
128     int expectedPolicy = SCHED_FIFO;
129     int expectedPriority = 1;
130     EXPECT_CALL(*mMockSystemCalls,
131                 setScheduler(TEST_TID, expectedPolicy, PriorityEq(expectedPriority)))
132             .WillOnce(Return(-1));
133 
134     auto result = mController->setThreadPriority(TEST_PID, TEST_TID, TEST_UID, expectedPolicy,
135                                                  expectedPriority);
136 
137     EXPECT_FALSE(result.ok());
138     EXPECT_EQ(result.error().code(), EX_SERVICE_SPECIFIC);
139 }
140 
TEST_F(ThreadPriorityControllerTest,TestGetThreadPriority)141 TEST_F(ThreadPriorityControllerTest, TestGetThreadPriority) {
142     int expectedPolicy = SCHED_FIFO;
143     int expectedPriority = 1;
144     EXPECT_CALL(*mMockSystemCalls, getScheduler(TEST_TID)).WillOnce(Return(expectedPolicy));
145     EXPECT_CALL(*mMockSystemCalls, getParam(TEST_TID, _))
146             .WillOnce([expectedPriority](pid_t, sched_param* param) {
147                 param->sched_priority = expectedPriority;
148                 return 0;
149             });
150 
151     ThreadPolicyWithPriority actual;
152     auto result = mController->getThreadPriority(TEST_PID, TEST_TID, TEST_UID, &actual);
153 
154     ASSERT_TRUE(result.ok()) << result.error().message();
155     EXPECT_EQ(actual.policy, expectedPolicy);
156     EXPECT_EQ(actual.priority, expectedPriority);
157 }
158 
TEST_F(ThreadPriorityControllerTest,TestGetThreadPriorityInvalidPid)159 TEST_F(ThreadPriorityControllerTest, TestGetThreadPriorityInvalidPid) {
160     ThreadPolicyWithPriority actual;
161     auto result = mController->getThreadPriority(TEST_PID + 1, TEST_TID, TEST_UID, &actual);
162 
163     EXPECT_FALSE(result.ok());
164     EXPECT_EQ(result.error().code(), EX_ILLEGAL_STATE);
165 }
166 
TEST_F(ThreadPriorityControllerTest,TestGetThreadPriorityGetSchedulerFailed)167 TEST_F(ThreadPriorityControllerTest, TestGetThreadPriorityGetSchedulerFailed) {
168     EXPECT_CALL(*mMockSystemCalls, getScheduler(TEST_TID)).WillOnce(Return(-1));
169 
170     ThreadPolicyWithPriority actual;
171     auto result = mController->getThreadPriority(TEST_PID, TEST_TID, TEST_UID, &actual);
172 
173     EXPECT_FALSE(result.ok());
174     EXPECT_EQ(result.error().code(), EX_SERVICE_SPECIFIC);
175 }
176 
TEST_F(ThreadPriorityControllerTest,TestGetThreadPriorityGetParamFailed)177 TEST_F(ThreadPriorityControllerTest, TestGetThreadPriorityGetParamFailed) {
178     EXPECT_CALL(*mMockSystemCalls, getScheduler(TEST_TID)).WillOnce(Return(0));
179     EXPECT_CALL(*mMockSystemCalls, getParam(TEST_TID, _)).WillOnce(Return(-1));
180 
181     ThreadPolicyWithPriority actual;
182     auto result = mController->getThreadPriority(TEST_PID, TEST_TID, TEST_UID, &actual);
183 
184     EXPECT_FALSE(result.ok());
185     EXPECT_EQ(result.error().code(), EX_SERVICE_SPECIFIC);
186 }
187 
188 }  // namespace
189 }  // namespace watchdog
190 }  // namespace automotive
191 }  // namespace android
192