1 /**
2 * Copyright (c) 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 "UidProcStatsCollector.h"
20
21 namespace android {
22 namespace automotive {
23 namespace watchdog {
24
25 namespace {
26
27 using ::aidl::android::automotive::watchdog::internal::ThreadPolicyWithPriority;
28 using ::android::base::Error;
29 using ::android::base::Result;
30
31 constexpr int PRIORITY_MIN = 1;
32 constexpr int PRIORITY_MAX = 99;
33
34 } // namespace
35
checkPidTidUid(pid_t pid,pid_t tid,uid_t uid)36 Result<void> ThreadPriorityController::checkPidTidUid(pid_t pid, pid_t tid, uid_t uid) {
37 auto tidStatus = mSystemCallsInterface->readPidStatusFileForPid(tid);
38 if (!tidStatus.ok()) {
39 return Error(EX_ILLEGAL_STATE) << "Invalid thread ID: " << tid;
40 }
41 uid_t uidForThread = std::get<0>(*tidStatus);
42 pid_t tgid = std::get<1>(*tidStatus);
43 if (pid != tgid) {
44 return Error(EX_ILLEGAL_STATE) << "Invalid process ID: " << pid;
45 }
46 if (uid != uidForThread) {
47 return Error(EX_ILLEGAL_STATE) << "Invalid user ID: " << uid;
48 }
49 return {};
50 }
51
setThreadPriority(int pid,int tid,int uid,int policy,int priority)52 Result<void> ThreadPriorityController::setThreadPriority(int pid, int tid, int uid, int policy,
53 int priority) {
54 pid_t tpid = static_cast<pid_t>(tid);
55 pid_t ppid = static_cast<pid_t>(pid);
56 uid_t uuid = static_cast<uid_t>(uid);
57 if (auto result = checkPidTidUid(ppid, tpid, uuid); !result.ok()) {
58 return result;
59 }
60
61 if (policy != SCHED_FIFO && policy != SCHED_RR && policy != SCHED_OTHER) {
62 return Error(EX_ILLEGAL_ARGUMENT)
63 << "Invalid policy: " << policy << ". Supported policies are SCHED_OTHER("
64 << SCHED_OTHER << ") , SCHED_FIFO(" << SCHED_FIFO << ") and SCHED_RR(" << SCHED_RR
65 << ")";
66 }
67
68 if (policy == SCHED_OTHER) {
69 priority = 0;
70 } else if (priority < PRIORITY_MIN || priority > PRIORITY_MAX) {
71 return Error(EX_ILLEGAL_ARGUMENT)
72 << "Invalid priority: " << priority << ". For policy: (" << policy
73 << "), priority must be within " << PRIORITY_MIN << " and " << PRIORITY_MAX;
74 }
75
76 sched_param param{.sched_priority = priority};
77 errno = 0;
78 if (mSystemCallsInterface->setScheduler(tpid, policy, ¶m) != 0) {
79 return Error(EX_SERVICE_SPECIFIC) << "sched_setscheduler failed, errno: " << errno;
80 }
81 return {};
82 }
83
getThreadPriority(int pid,int tid,int uid,ThreadPolicyWithPriority * result)84 Result<void> ThreadPriorityController::getThreadPriority(int pid, int tid, int uid,
85 ThreadPolicyWithPriority* result) {
86 pid_t tpid = static_cast<pid_t>(tid);
87 pid_t ppid = static_cast<pid_t>(pid);
88 uid_t uuid = static_cast<uid_t>(uid);
89 if (auto result = checkPidTidUid(ppid, tpid, uuid); !result.ok()) {
90 return result;
91 }
92
93 errno = 0;
94 int policy = mSystemCallsInterface->getScheduler(tpid);
95 if (policy < 0) {
96 return Error(EX_SERVICE_SPECIFIC) << "sched_getscheduler failed, errno: " << errno;
97 }
98
99 sched_param param = {};
100 errno = 0;
101 int callResult = mSystemCallsInterface->getParam(tpid, ¶m);
102 if (callResult != 0) {
103 return Error(EX_SERVICE_SPECIFIC) << "sched_getparam failed, errno: " << errno;
104 }
105
106 result->policy = policy;
107 result->priority = param.sched_priority;
108 return {};
109 }
110
setScheduler(pid_t tid,int policy,const sched_param * param)111 int ThreadPriorityController::SystemCalls::setScheduler(pid_t tid, int policy,
112 const sched_param* param) {
113 return sched_setscheduler(tid, policy, param);
114 }
115
getScheduler(pid_t tid)116 int ThreadPriorityController::SystemCalls::getScheduler(pid_t tid) {
117 return sched_getscheduler(tid);
118 }
119
getParam(pid_t tid,sched_param * param)120 int ThreadPriorityController::SystemCalls::getParam(pid_t tid, sched_param* param) {
121 return sched_getparam(tid, param);
122 }
123
readPidStatusFileForPid(pid_t pid)124 Result<std::tuple<uid_t, pid_t>> ThreadPriorityController::SystemCalls::readPidStatusFileForPid(
125 pid_t pid) {
126 return UidProcStatsCollector::readPidStatusFileForPid(pid);
127 }
128
129 } // namespace watchdog
130 } // namespace automotive
131 } // namespace android
132