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 ::android::automotive::watchdog::internal::ThreadPolicyWithPriority;
28 using ::android::base::Result;
29 using ::android::binder::Status;
30
fromExceptionCode(int32_t exceptionCode,const std::string & message)31 Status fromExceptionCode(int32_t exceptionCode, const std::string& message) {
32 ALOGW("%s", message.c_str());
33 return Status::fromExceptionCode(exceptionCode, message.c_str());
34 }
35
fromServiceSpecificError(const std::string & message)36 Status fromServiceSpecificError(const std::string& message) {
37 ALOGW("%s", message.c_str());
38 return Status::fromServiceSpecificError(/*exceptionCode=*/0, message.c_str());
39 }
40
41 constexpr int PRIORITY_MIN = 1;
42 constexpr int PRIORITY_MAX = 99;
43
44 } // namespace
45
checkPidTidUid(pid_t pid,pid_t tid,uid_t uid)46 Status ThreadPriorityController::checkPidTidUid(pid_t pid, pid_t tid, uid_t uid) {
47 auto tidStatus = mSystemCallsInterface->readPidStatusFileForPid(tid);
48 if (!tidStatus.ok()) {
49 return fromExceptionCode(Status::EX_ILLEGAL_STATE,
50 StringPrintf("invalid thread ID: %d", tid));
51 }
52 uid_t uidForThread = std::get<0>(*tidStatus);
53 pid_t tgid = std::get<1>(*tidStatus);
54 if (pid != tgid) {
55 return fromExceptionCode(Status::EX_ILLEGAL_STATE,
56 StringPrintf("invalid process ID: %d", pid));
57 }
58 if (uid != uidForThread) {
59 return fromExceptionCode(Status::EX_ILLEGAL_STATE,
60 StringPrintf("invalid user ID: %d", uid));
61 }
62 return Status::ok();
63 }
64
setThreadPriority(int pid,int tid,int uid,int policy,int priority)65 Status ThreadPriorityController::setThreadPriority(int pid, int tid, int uid, int policy,
66 int priority) {
67 pid_t tpid = static_cast<pid_t>(tid);
68 pid_t ppid = static_cast<pid_t>(pid);
69 uid_t uuid = static_cast<uid_t>(uid);
70 Status status = checkPidTidUid(ppid, tpid, uuid);
71 if (!status.isOk()) {
72 return status;
73 }
74
75 if (policy != SCHED_FIFO && policy != SCHED_RR && policy != SCHED_OTHER) {
76 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
77 StringPrintf("invalid policy: %d, only support SCHED_OTHER(%d)"
78 ", SCHED_FIFO(%d) and SCHED_RR(%d)",
79 policy, SCHED_OTHER, SCHED_FIFO, SCHED_RR));
80 }
81
82 if (policy == SCHED_OTHER) {
83 priority = 0;
84 } else if (priority < PRIORITY_MIN || priority > PRIORITY_MAX) {
85 return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
86 StringPrintf("invalid priority: %d for policy: (%d), "
87 "must be within %d and %d",
88 priority, policy, PRIORITY_MIN, PRIORITY_MAX));
89 }
90
91 sched_param param{.sched_priority = priority};
92 errno = 0;
93 if (mSystemCallsInterface->setScheduler(tpid, policy, ¶m) != 0) {
94 return fromServiceSpecificError(
95 StringPrintf("sched_setscheduler failed, errno: %d", errno));
96 }
97 return Status::ok();
98 }
99
getThreadPriority(int pid,int tid,int uid,ThreadPolicyWithPriority * result)100 Status ThreadPriorityController::getThreadPriority(int pid, int tid, int uid,
101 ThreadPolicyWithPriority* result) {
102 pid_t tpid = static_cast<pid_t>(tid);
103 pid_t ppid = static_cast<pid_t>(pid);
104 uid_t uuid = static_cast<uid_t>(uid);
105 Status status = checkPidTidUid(ppid, tpid, uuid);
106 if (!status.isOk()) {
107 return status;
108 }
109
110 errno = 0;
111 int policy = mSystemCallsInterface->getScheduler(tpid);
112 if (policy < 0) {
113 return fromServiceSpecificError(
114 StringPrintf("sched_getscheduler failed, errno: %d", errno));
115 }
116
117 sched_param param = {};
118 errno = 0;
119 int callResult = mSystemCallsInterface->getParam(tpid, ¶m);
120 if (callResult != 0) {
121 return fromServiceSpecificError(StringPrintf("sched_getparam failed, errno: %d", errno));
122 }
123
124 result->policy = policy;
125 result->priority = param.sched_priority;
126 return Status::ok();
127 }
128
setScheduler(pid_t tid,int policy,const sched_param * param)129 int ThreadPriorityController::SystemCalls::setScheduler(pid_t tid, int policy,
130 const sched_param* param) {
131 return sched_setscheduler(tid, policy, param);
132 }
133
getScheduler(pid_t tid)134 int ThreadPriorityController::SystemCalls::getScheduler(pid_t tid) {
135 return sched_getscheduler(tid);
136 }
137
getParam(pid_t tid,sched_param * param)138 int ThreadPriorityController::SystemCalls::getParam(pid_t tid, sched_param* param) {
139 return sched_getparam(tid, param);
140 }
141
readPidStatusFileForPid(pid_t pid)142 Result<std::tuple<uid_t, pid_t>> ThreadPriorityController::SystemCalls::readPidStatusFileForPid(
143 pid_t pid) {
144 return UidProcStatsCollector::readPidStatusFileForPid(pid);
145 }
146
147 } // namespace watchdog
148 } // namespace automotive
149 } // namespace android
150