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, &param) != 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, &param);
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