Loading services/vr/performanced/cpu_set.cpp +1 −5 Original line number Diff line number Diff line Loading @@ -106,7 +106,7 @@ std::vector<CpuSet*> CpuSetManager::GetCpuSets() { return sets; } std::string CpuSetManager::DumpState() const { void CpuSetManager::DumpState(std::ostringstream& stream) const { size_t max_path = 0; std::vector<CpuSet*> sets; Loading @@ -119,8 +119,6 @@ std::string CpuSetManager::DumpState() const { return a->path() < b->path(); }); std::ostringstream stream; stream << std::left; stream << std::setw(max_path) << "Path"; stream << " "; Loading @@ -146,8 +144,6 @@ std::string CpuSetManager::DumpState() const { stream << std::setw(6) << set->GetTasks().size(); stream << std::endl; } return stream.str(); } void CpuSetManager::MoveUnboundTasks(const std::string& target_set) { Loading services/vr/performanced/cpu_set.h +2 −1 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ #include <memory> #include <mutex> #include <sstream> #include <string> #include <unordered_map> #include <vector> Loading Loading @@ -83,7 +84,7 @@ class CpuSetManager { // to shield the system from interference from unbound kernel threads. void MoveUnboundTasks(const std::string& target_set); std::string DumpState() const; void DumpState(std::ostringstream& stream) const; operator bool() const { return root_set_ != nullptr; } Loading services/vr/performanced/performance_service.cpp +75 −8 Original line number Diff line number Diff line #include "performance_service.h" #include <sstream> #include <sched.h> #include <sys/prctl.h> #include <unistd.h> Loading Loading @@ -31,6 +33,10 @@ const char kCpuSetBasePath[] = "/dev/cpuset"; const char kRootCpuSet[] = "/"; const char kVrAppRenderPolicy[] = "vr:app:render"; const bool kAllowAppsToRequestVrAppRenderPolicy = false; constexpr unsigned long kTimerSlackForegroundNs = 50000; constexpr unsigned long kTimerSlackBackgroundNs = 40000000; Loading Loading @@ -133,6 +139,17 @@ PerformanceService::PerformanceService() using AllowRootSystemTrusted = CheckOr<Trusted, UserId<AID_ROOT, AID_SYSTEM>, GroupId<AID_SYSTEM>>; auto vr_app_render_permission_check = []( const pdx::Message& sender, const Task& task) { // For vr:app:render, in addition to system/root apps and VrCore, we // also allow apps to request vr:app:render if // kAllowAppsToRequestVrAppRenderPolicy == true, but not for other // apps, only for themselves. return (task && task.thread_group_id() == sender.GetProcessId() && kAllowAppsToRequestVrAppRenderPolicy) || AllowRootSystemTrusted::Check(sender, task); }; partition_permission_check_ = AllowRootSystemTrusted::Check; // Setup the scheduler classes. Loading Loading @@ -184,11 +201,11 @@ PerformanceService::PerformanceService() .priority = fifo_medium + 2, .permission_check = AllowRootSystemTrusted::Check, "/system/performance"}}, {"vr:app:render", {kVrAppRenderPolicy, {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, .priority = fifo_medium + 1, .permission_check = AllowRootSystemTrusted::Check, .permission_check = vr_app_render_permission_check, "/application/performance"}}, {"normal", {.timer_slack = kTimerSlackForegroundNs, Loading @@ -215,7 +232,10 @@ bool PerformanceService::IsInitialized() const { } std::string PerformanceService::DumpState(size_t /*max_length*/) { return cpuset_.DumpState(); std::ostringstream stream; stream << "vr_app_render_thread: " << vr_app_render_thread_ << std::endl; cpuset_.DumpState(stream); return stream.str(); } Status<void> PerformanceService::OnSetSchedulerPolicy( Loading @@ -241,7 +261,12 @@ Status<void> PerformanceService::OnSetSchedulerPolicy( // Make sure the sending process is allowed to make the requested change to // this task. if (!config.IsAllowed(message, task)) return ErrorStatus(EINVAL); return ErrorStatus(EPERM); if (scheduler_policy == kVrAppRenderPolicy) { // We only allow one vr:app:render thread at a time SetVrAppRenderThread(task_id); } // Get the thread group's cpu set. Policies that do not specify a cpuset // should default to this cpuset. Loading Loading @@ -299,14 +324,16 @@ Status<void> PerformanceService::OnSetSchedulerPolicy( Status<void> PerformanceService::OnSetCpuPartition( Message& message, pid_t task_id, const std::string& partition) { Task task(task_id); if (!task || task.thread_group_id() != message.GetProcessId()) if (!task) return ErrorStatus(EINVAL); if (task.thread_group_id() != message.GetProcessId()) return ErrorStatus(EPERM); // Temporary permission check. // TODO(eieio): Replace this with a configuration file. if (partition_permission_check_ && !partition_permission_check_(message, task)) { return ErrorStatus(EINVAL); return ErrorStatus(EPERM); } auto target_set = cpuset_.Lookup(partition); Loading @@ -333,7 +360,12 @@ Status<void> PerformanceService::OnSetSchedulerClass( // Make sure the sending process is allowed to make the requested change to // this task. if (!config.IsAllowed(message, task)) return ErrorStatus(EINVAL); return ErrorStatus(EPERM); if (scheduler_class == kVrAppRenderPolicy) { // We only allow one vr:app:render thread at a time SetVrAppRenderThread(task_id); } struct sched_param param; param.sched_priority = config.priority; Loading @@ -356,8 +388,10 @@ Status<std::string> PerformanceService::OnGetCpuPartition(Message& message, pid_t task_id) { // Make sure the task id is valid and belongs to the sending process. Task task(task_id); if (!task || task.thread_group_id() != message.GetProcessId()) if (!task) return ErrorStatus(EINVAL); if (task.thread_group_id() != message.GetProcessId()) return ErrorStatus(EPERM); return task.GetCpuSetPath(); } Loading Loading @@ -390,5 +424,38 @@ Status<void> PerformanceService::HandleMessage(Message& message) { } } void PerformanceService::SetVrAppRenderThread(pid_t new_vr_app_render_thread) { ALOGI("SetVrAppRenderThread old=%d new=%d", vr_app_render_thread_, new_vr_app_render_thread); if (vr_app_render_thread_ >= 0 && vr_app_render_thread_ != new_vr_app_render_thread) { // Restore the default scheduler policy and priority on the previous // vr:app:render thread. struct sched_param param; param.sched_priority = 0; if (sched_setscheduler(vr_app_render_thread_, SCHED_NORMAL, ¶m) < 0) { if (errno == ESRCH) { ALOGI("Failed to revert %s scheduler policy. Couldn't find thread %d." " Was the app killed?", kVrAppRenderPolicy, vr_app_render_thread_); } else { ALOGE("Failed to revert %s scheduler policy: %s", kVrAppRenderPolicy, strerror(errno)); } } // Restore the default timer slack on the previous vr:app:render thread. prctl(PR_SET_TIMERSLACK_PID, kTimerSlackForegroundNs, vr_app_render_thread_); } // We could also reset the thread's cpuset here, but the cpuset is already // managed by Android. Better to let Android adjust the cpuset as the app // moves to the background, rather than adjust it ourselves here, and risk // stomping on the value set by Android. vr_app_render_thread_ = new_vr_app_render_thread; } } // namespace dvr } // namespace android services/vr/performanced/performance_service.h +10 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,14 @@ class PerformanceService : public pdx::ServiceBase<PerformanceService> { pdx::Status<std::string> OnGetCpuPartition(pdx::Message& message, pid_t task_id); // Set which thread gets the vr:app:render policy. Only one thread at a time // is allowed to have vr:app:render. If multiple threads are allowed // vr:app:render, and those threads busy loop, the system can freeze. When // SetVrAppRenderThread() is called, the thread which we had previously // assigned vr:app:render will have its scheduling policy reset to default // values. void SetVrAppRenderThread(pid_t new_vr_app_render_thread); CpuSetManager cpuset_; int sched_fifo_min_priority_; Loading Loading @@ -70,6 +78,8 @@ class PerformanceService : public pdx::ServiceBase<PerformanceService> { std::function<bool(const pdx::Message& message, const Task& task)> partition_permission_check_; pid_t vr_app_render_thread_ = -1; PerformanceService(const PerformanceService&) = delete; void operator=(const PerformanceService&) = delete; }; Loading Loading
services/vr/performanced/cpu_set.cpp +1 −5 Original line number Diff line number Diff line Loading @@ -106,7 +106,7 @@ std::vector<CpuSet*> CpuSetManager::GetCpuSets() { return sets; } std::string CpuSetManager::DumpState() const { void CpuSetManager::DumpState(std::ostringstream& stream) const { size_t max_path = 0; std::vector<CpuSet*> sets; Loading @@ -119,8 +119,6 @@ std::string CpuSetManager::DumpState() const { return a->path() < b->path(); }); std::ostringstream stream; stream << std::left; stream << std::setw(max_path) << "Path"; stream << " "; Loading @@ -146,8 +144,6 @@ std::string CpuSetManager::DumpState() const { stream << std::setw(6) << set->GetTasks().size(); stream << std::endl; } return stream.str(); } void CpuSetManager::MoveUnboundTasks(const std::string& target_set) { Loading
services/vr/performanced/cpu_set.h +2 −1 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ #include <memory> #include <mutex> #include <sstream> #include <string> #include <unordered_map> #include <vector> Loading Loading @@ -83,7 +84,7 @@ class CpuSetManager { // to shield the system from interference from unbound kernel threads. void MoveUnboundTasks(const std::string& target_set); std::string DumpState() const; void DumpState(std::ostringstream& stream) const; operator bool() const { return root_set_ != nullptr; } Loading
services/vr/performanced/performance_service.cpp +75 −8 Original line number Diff line number Diff line #include "performance_service.h" #include <sstream> #include <sched.h> #include <sys/prctl.h> #include <unistd.h> Loading Loading @@ -31,6 +33,10 @@ const char kCpuSetBasePath[] = "/dev/cpuset"; const char kRootCpuSet[] = "/"; const char kVrAppRenderPolicy[] = "vr:app:render"; const bool kAllowAppsToRequestVrAppRenderPolicy = false; constexpr unsigned long kTimerSlackForegroundNs = 50000; constexpr unsigned long kTimerSlackBackgroundNs = 40000000; Loading Loading @@ -133,6 +139,17 @@ PerformanceService::PerformanceService() using AllowRootSystemTrusted = CheckOr<Trusted, UserId<AID_ROOT, AID_SYSTEM>, GroupId<AID_SYSTEM>>; auto vr_app_render_permission_check = []( const pdx::Message& sender, const Task& task) { // For vr:app:render, in addition to system/root apps and VrCore, we // also allow apps to request vr:app:render if // kAllowAppsToRequestVrAppRenderPolicy == true, but not for other // apps, only for themselves. return (task && task.thread_group_id() == sender.GetProcessId() && kAllowAppsToRequestVrAppRenderPolicy) || AllowRootSystemTrusted::Check(sender, task); }; partition_permission_check_ = AllowRootSystemTrusted::Check; // Setup the scheduler classes. Loading Loading @@ -184,11 +201,11 @@ PerformanceService::PerformanceService() .priority = fifo_medium + 2, .permission_check = AllowRootSystemTrusted::Check, "/system/performance"}}, {"vr:app:render", {kVrAppRenderPolicy, {.timer_slack = kTimerSlackForegroundNs, .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK, .priority = fifo_medium + 1, .permission_check = AllowRootSystemTrusted::Check, .permission_check = vr_app_render_permission_check, "/application/performance"}}, {"normal", {.timer_slack = kTimerSlackForegroundNs, Loading @@ -215,7 +232,10 @@ bool PerformanceService::IsInitialized() const { } std::string PerformanceService::DumpState(size_t /*max_length*/) { return cpuset_.DumpState(); std::ostringstream stream; stream << "vr_app_render_thread: " << vr_app_render_thread_ << std::endl; cpuset_.DumpState(stream); return stream.str(); } Status<void> PerformanceService::OnSetSchedulerPolicy( Loading @@ -241,7 +261,12 @@ Status<void> PerformanceService::OnSetSchedulerPolicy( // Make sure the sending process is allowed to make the requested change to // this task. if (!config.IsAllowed(message, task)) return ErrorStatus(EINVAL); return ErrorStatus(EPERM); if (scheduler_policy == kVrAppRenderPolicy) { // We only allow one vr:app:render thread at a time SetVrAppRenderThread(task_id); } // Get the thread group's cpu set. Policies that do not specify a cpuset // should default to this cpuset. Loading Loading @@ -299,14 +324,16 @@ Status<void> PerformanceService::OnSetSchedulerPolicy( Status<void> PerformanceService::OnSetCpuPartition( Message& message, pid_t task_id, const std::string& partition) { Task task(task_id); if (!task || task.thread_group_id() != message.GetProcessId()) if (!task) return ErrorStatus(EINVAL); if (task.thread_group_id() != message.GetProcessId()) return ErrorStatus(EPERM); // Temporary permission check. // TODO(eieio): Replace this with a configuration file. if (partition_permission_check_ && !partition_permission_check_(message, task)) { return ErrorStatus(EINVAL); return ErrorStatus(EPERM); } auto target_set = cpuset_.Lookup(partition); Loading @@ -333,7 +360,12 @@ Status<void> PerformanceService::OnSetSchedulerClass( // Make sure the sending process is allowed to make the requested change to // this task. if (!config.IsAllowed(message, task)) return ErrorStatus(EINVAL); return ErrorStatus(EPERM); if (scheduler_class == kVrAppRenderPolicy) { // We only allow one vr:app:render thread at a time SetVrAppRenderThread(task_id); } struct sched_param param; param.sched_priority = config.priority; Loading @@ -356,8 +388,10 @@ Status<std::string> PerformanceService::OnGetCpuPartition(Message& message, pid_t task_id) { // Make sure the task id is valid and belongs to the sending process. Task task(task_id); if (!task || task.thread_group_id() != message.GetProcessId()) if (!task) return ErrorStatus(EINVAL); if (task.thread_group_id() != message.GetProcessId()) return ErrorStatus(EPERM); return task.GetCpuSetPath(); } Loading Loading @@ -390,5 +424,38 @@ Status<void> PerformanceService::HandleMessage(Message& message) { } } void PerformanceService::SetVrAppRenderThread(pid_t new_vr_app_render_thread) { ALOGI("SetVrAppRenderThread old=%d new=%d", vr_app_render_thread_, new_vr_app_render_thread); if (vr_app_render_thread_ >= 0 && vr_app_render_thread_ != new_vr_app_render_thread) { // Restore the default scheduler policy and priority on the previous // vr:app:render thread. struct sched_param param; param.sched_priority = 0; if (sched_setscheduler(vr_app_render_thread_, SCHED_NORMAL, ¶m) < 0) { if (errno == ESRCH) { ALOGI("Failed to revert %s scheduler policy. Couldn't find thread %d." " Was the app killed?", kVrAppRenderPolicy, vr_app_render_thread_); } else { ALOGE("Failed to revert %s scheduler policy: %s", kVrAppRenderPolicy, strerror(errno)); } } // Restore the default timer slack on the previous vr:app:render thread. prctl(PR_SET_TIMERSLACK_PID, kTimerSlackForegroundNs, vr_app_render_thread_); } // We could also reset the thread's cpuset here, but the cpuset is already // managed by Android. Better to let Android adjust the cpuset as the app // moves to the background, rather than adjust it ourselves here, and risk // stomping on the value set by Android. vr_app_render_thread_ = new_vr_app_render_thread; } } // namespace dvr } // namespace android
services/vr/performanced/performance_service.h +10 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,14 @@ class PerformanceService : public pdx::ServiceBase<PerformanceService> { pdx::Status<std::string> OnGetCpuPartition(pdx::Message& message, pid_t task_id); // Set which thread gets the vr:app:render policy. Only one thread at a time // is allowed to have vr:app:render. If multiple threads are allowed // vr:app:render, and those threads busy loop, the system can freeze. When // SetVrAppRenderThread() is called, the thread which we had previously // assigned vr:app:render will have its scheduling policy reset to default // values. void SetVrAppRenderThread(pid_t new_vr_app_render_thread); CpuSetManager cpuset_; int sched_fifo_min_priority_; Loading Loading @@ -70,6 +78,8 @@ class PerformanceService : public pdx::ServiceBase<PerformanceService> { std::function<bool(const pdx::Message& message, const Task& task)> partition_permission_check_; pid_t vr_app_render_thread_ = -1; PerformanceService(const PerformanceService&) = delete; void operator=(const PerformanceService&) = delete; }; Loading