1 #include "performance_service.h" 2 3 #include <sched.h> 4 #include <sys/prctl.h> 5 #include <unistd.h> 6 7 #include <pdx/default_transport/service_endpoint.h> 8 #include <pdx/rpc/argument_encoder.h> 9 #include <pdx/rpc/message_buffer.h> 10 #include <pdx/rpc/remote_method.h> 11 #include <private/dvr/performance_rpc.h> 12 13 #include "task.h" 14 15 // This prctl is only available in Android kernels. 16 #define PR_SET_TIMERSLACK_PID 41 17 18 using android::pdx::Message; 19 using android::pdx::rpc::DispatchRemoteMethod; 20 using android::pdx::default_transport::Endpoint; 21 22 namespace { 23 24 const char kCpuSetBasePath[] = "/dev/cpuset"; 25 26 constexpr unsigned long kTimerSlackForegroundNs = 50000; 27 constexpr unsigned long kTimerSlackBackgroundNs = 40000000; 28 29 } // anonymous namespace 30 31 namespace android { 32 namespace dvr { 33 34 PerformanceService::PerformanceService() 35 : BASE("PerformanceService", 36 Endpoint::Create(PerformanceRPC::kClientPath)) { 37 cpuset_.Load(kCpuSetBasePath); 38 39 Task task(getpid()); 40 ALOGI("Running in cpuset=%s uid=%d gid=%d", task.GetCpuSetPath().c_str(), 41 task.user_id()[Task::kUidReal], task.group_id()[Task::kUidReal]); 42 43 // Errors here are checked in IsInitialized(). 44 sched_fifo_min_priority_ = sched_get_priority_min(SCHED_FIFO); 45 sched_fifo_max_priority_ = sched_get_priority_max(SCHED_FIFO); 46 47 const int fifo_range = sched_fifo_max_priority_ - sched_fifo_min_priority_; 48 const int fifo_low = sched_fifo_min_priority_; 49 const int fifo_medium = sched_fifo_min_priority_ + fifo_range / 5; 50 51 // TODO(eieio): Make this configurable on the command line. 52 cpuset_.MoveUnboundTasks("/kernel"); 53 54 // Setup the scheduler classes. 55 scheduler_classes_ = { 56 {"audio:low", 57 {.timer_slack = kTimerSlackForegroundNs, 58 .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, 59 .priority = fifo_medium}}, 60 {"audio:high", 61 {.timer_slack = kTimerSlackForegroundNs, 62 .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, 63 .priority = fifo_medium + 3}}, 64 {"graphics", 65 {.timer_slack = kTimerSlackForegroundNs, 66 .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, 67 .priority = fifo_medium}}, 68 {"graphics:low", 69 {.timer_slack = kTimerSlackForegroundNs, 70 .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, 71 .priority = fifo_medium}}, 72 {"graphics:high", 73 {.timer_slack = kTimerSlackForegroundNs, 74 .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, 75 .priority = fifo_medium + 2}}, 76 {"sensors", 77 {.timer_slack = kTimerSlackForegroundNs, 78 .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, 79 .priority = fifo_low}}, 80 {"sensors:low", 81 {.timer_slack = kTimerSlackForegroundNs, 82 .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, 83 .priority = fifo_low}}, 84 {"sensors:high", 85 {.timer_slack = kTimerSlackForegroundNs, 86 .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, 87 .priority = fifo_low + 1}}, 88 {"normal", 89 {.timer_slack = kTimerSlackForegroundNs, 90 .scheduler_policy = SCHED_NORMAL, 91 .priority = 0}}, 92 {"foreground", 93 {.timer_slack = kTimerSlackForegroundNs, 94 .scheduler_policy = SCHED_NORMAL, 95 .priority = 0}}, 96 {"background", 97 {.timer_slack = kTimerSlackBackgroundNs, 98 .scheduler_policy = SCHED_BATCH, 99 .priority = 0}}, 100 {"batch", 101 {.timer_slack = kTimerSlackBackgroundNs, 102 .scheduler_policy = SCHED_BATCH, 103 .priority = 0}}, 104 }; 105 } 106 107 bool PerformanceService::IsInitialized() const { 108 return BASE::IsInitialized() && cpuset_ && sched_fifo_min_priority_ >= 0 && 109 sched_fifo_max_priority_ >= 0; 110 } 111 112 std::string PerformanceService::DumpState(size_t /*max_length*/) { 113 return cpuset_.DumpState(); 114 } 115 116 int PerformanceService::OnSetCpuPartition(Message& message, pid_t task_id, 117 const std::string& partition) { 118 Task task(task_id); 119 if (!task || task.thread_group_id() != message.GetProcessId()) 120 return -EINVAL; 121 122 auto target_set = cpuset_.Lookup(partition); 123 if (!target_set) 124 return -ENOENT; 125 126 const auto attach_error = target_set->AttachTask(task_id); 127 if (attach_error) 128 return attach_error; 129 130 return 0; 131 } 132 133 int PerformanceService::OnSetSchedulerClass( 134 Message& message, pid_t task_id, const std::string& scheduler_class) { 135 // Make sure the task id is valid and belongs to the sending process. 136 Task task(task_id); 137 if (!task || task.thread_group_id() != message.GetProcessId()) 138 return -EINVAL; 139 140 struct sched_param param; 141 142 // TODO(eieio): Apply rules based on the requesting process. Applications are 143 // only allowed one audio thread that runs at SCHED_FIFO. System services can 144 // have more than one. 145 auto search = scheduler_classes_.find(scheduler_class); 146 if (search != scheduler_classes_.end()) { 147 auto config = search->second; 148 param.sched_priority = config.priority; 149 sched_setscheduler(task_id, config.scheduler_policy, ¶m); 150 prctl(PR_SET_TIMERSLACK_PID, config.timer_slack, task_id); 151 ALOGI("PerformanceService::OnSetSchedulerClass: Set task=%d to class=%s.", 152 task_id, scheduler_class.c_str()); 153 return 0; 154 } else { 155 ALOGE( 156 "PerformanceService::OnSetSchedulerClass: Invalid class=%s requested " 157 "by task=%d.", 158 scheduler_class.c_str(), task_id); 159 return -EINVAL; 160 } 161 } 162 163 std::string PerformanceService::OnGetCpuPartition(Message& message, 164 pid_t task_id) { 165 // Make sure the task id is valid and belongs to the sending process. 166 Task task(task_id); 167 if (!task || task.thread_group_id() != message.GetProcessId()) 168 REPLY_ERROR_RETURN(message, EINVAL, ""); 169 170 return task.GetCpuSetPath(); 171 } 172 173 pdx::Status<void> PerformanceService::HandleMessage(Message& message) { 174 switch (message.GetOp()) { 175 case PerformanceRPC::SetCpuPartition::Opcode: 176 DispatchRemoteMethod<PerformanceRPC::SetSchedulerClass>( 177 *this, &PerformanceService::OnSetCpuPartition, message); 178 return {}; 179 180 case PerformanceRPC::SetSchedulerClass::Opcode: 181 DispatchRemoteMethod<PerformanceRPC::SetSchedulerClass>( 182 *this, &PerformanceService::OnSetSchedulerClass, message); 183 return {}; 184 185 case PerformanceRPC::GetCpuPartition::Opcode: 186 DispatchRemoteMethod<PerformanceRPC::GetCpuPartition>( 187 *this, &PerformanceService::OnGetCpuPartition, message); 188 return {}; 189 190 default: 191 return Service::HandleMessage(message); 192 } 193 } 194 195 } // namespace dvr 196 } // namespace android 197