• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &param) != 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, &param);
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