xref: /aosp_15_r20/external/cronet/base/process/process_mac.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2016 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/process/process.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <mach/mach.h>
8*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
9*6777b538SAndroid Build Coastguard Worker #include <sys/resource.h>
10*6777b538SAndroid Build Coastguard Worker #include <sys/sysctl.h>
11*6777b538SAndroid Build Coastguard Worker #include <sys/time.h>
12*6777b538SAndroid Build Coastguard Worker #include <unistd.h>
13*6777b538SAndroid Build Coastguard Worker 
14*6777b538SAndroid Build Coastguard Worker #include <iterator>
15*6777b538SAndroid Build Coastguard Worker #include <memory>
16*6777b538SAndroid Build Coastguard Worker #include <optional>
17*6777b538SAndroid Build Coastguard Worker #include <utility>
18*6777b538SAndroid Build Coastguard Worker 
19*6777b538SAndroid Build Coastguard Worker #include "base/apple/mach_logging.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/feature_list.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/memory/free_deleter.h"
22*6777b538SAndroid Build Coastguard Worker 
23*6777b538SAndroid Build Coastguard Worker namespace base {
24*6777b538SAndroid Build Coastguard Worker 
25*6777b538SAndroid Build Coastguard Worker namespace {
26*6777b538SAndroid Build Coastguard Worker 
27*6777b538SAndroid Build Coastguard Worker // Enables setting the task role of every child process to
28*6777b538SAndroid Build Coastguard Worker // TASK_DEFAULT_APPLICATION.
29*6777b538SAndroid Build Coastguard Worker BASE_FEATURE(kMacSetDefaultTaskRole,
30*6777b538SAndroid Build Coastguard Worker              "MacSetDefaultTaskRole",
31*6777b538SAndroid Build Coastguard Worker              FEATURE_ENABLED_BY_DEFAULT);
32*6777b538SAndroid Build Coastguard Worker 
33*6777b538SAndroid Build Coastguard Worker // Returns the `task_role_t` of the process whose task port is `task_port`.
GetTaskCategoryPolicyRole(mach_port_t task_port)34*6777b538SAndroid Build Coastguard Worker std::optional<task_role_t> GetTaskCategoryPolicyRole(mach_port_t task_port) {
35*6777b538SAndroid Build Coastguard Worker   task_category_policy_data_t category_policy;
36*6777b538SAndroid Build Coastguard Worker   mach_msg_type_number_t task_info_count = TASK_CATEGORY_POLICY_COUNT;
37*6777b538SAndroid Build Coastguard Worker   boolean_t get_default = FALSE;
38*6777b538SAndroid Build Coastguard Worker 
39*6777b538SAndroid Build Coastguard Worker   kern_return_t result =
40*6777b538SAndroid Build Coastguard Worker       task_policy_get(task_port, TASK_CATEGORY_POLICY,
41*6777b538SAndroid Build Coastguard Worker                       reinterpret_cast<task_policy_t>(&category_policy),
42*6777b538SAndroid Build Coastguard Worker                       &task_info_count, &get_default);
43*6777b538SAndroid Build Coastguard Worker   if (result != KERN_SUCCESS) {
44*6777b538SAndroid Build Coastguard Worker     MACH_LOG(ERROR, result) << "task_policy_get TASK_CATEGORY_POLICY";
45*6777b538SAndroid Build Coastguard Worker     return std::nullopt;
46*6777b538SAndroid Build Coastguard Worker   }
47*6777b538SAndroid Build Coastguard Worker   CHECK(!get_default);
48*6777b538SAndroid Build Coastguard Worker   return category_policy.role;
49*6777b538SAndroid Build Coastguard Worker }
50*6777b538SAndroid Build Coastguard Worker 
51*6777b538SAndroid Build Coastguard Worker // Sets the task role for `task_port`.
SetTaskCategoryPolicy(mach_port_t task_port,task_role_t task_role)52*6777b538SAndroid Build Coastguard Worker bool SetTaskCategoryPolicy(mach_port_t task_port, task_role_t task_role) {
53*6777b538SAndroid Build Coastguard Worker   task_category_policy task_category_policy{.role = task_role};
54*6777b538SAndroid Build Coastguard Worker   kern_return_t result =
55*6777b538SAndroid Build Coastguard Worker       task_policy_set(task_port, TASK_CATEGORY_POLICY,
56*6777b538SAndroid Build Coastguard Worker                       reinterpret_cast<task_policy_t>(&task_category_policy),
57*6777b538SAndroid Build Coastguard Worker                       TASK_CATEGORY_POLICY_COUNT);
58*6777b538SAndroid Build Coastguard Worker   if (result != KERN_SUCCESS) {
59*6777b538SAndroid Build Coastguard Worker     MACH_LOG(ERROR, result) << "task_policy_set TASK_CATEGORY_POLICY";
60*6777b538SAndroid Build Coastguard Worker     return false;
61*6777b538SAndroid Build Coastguard Worker   }
62*6777b538SAndroid Build Coastguard Worker   return true;
63*6777b538SAndroid Build Coastguard Worker }
64*6777b538SAndroid Build Coastguard Worker 
65*6777b538SAndroid Build Coastguard Worker // Taken from task_policy_private.h.
66*6777b538SAndroid Build Coastguard Worker struct task_suppression_policy {
67*6777b538SAndroid Build Coastguard Worker   integer_t active;
68*6777b538SAndroid Build Coastguard Worker   integer_t lowpri_cpu;
69*6777b538SAndroid Build Coastguard Worker   integer_t timer_throttle;
70*6777b538SAndroid Build Coastguard Worker   integer_t disk_throttle;
71*6777b538SAndroid Build Coastguard Worker   integer_t cpu_limit;
72*6777b538SAndroid Build Coastguard Worker   integer_t suspend;
73*6777b538SAndroid Build Coastguard Worker   integer_t throughput_qos;
74*6777b538SAndroid Build Coastguard Worker   integer_t suppressed_cpu;
75*6777b538SAndroid Build Coastguard Worker   integer_t background_sockets;
76*6777b538SAndroid Build Coastguard Worker   integer_t reserved[7];
77*6777b538SAndroid Build Coastguard Worker };
78*6777b538SAndroid Build Coastguard Worker 
79*6777b538SAndroid Build Coastguard Worker // Taken from task_policy_private.h.
80*6777b538SAndroid Build Coastguard Worker #define TASK_SUPPRESSION_POLICY_COUNT                                \
81*6777b538SAndroid Build Coastguard Worker   ((mach_msg_type_number_t)(sizeof(struct task_suppression_policy) / \
82*6777b538SAndroid Build Coastguard Worker                             sizeof(integer_t)))
83*6777b538SAndroid Build Coastguard Worker 
84*6777b538SAndroid Build Coastguard Worker // Activates or deactivates the suppression policy to match the effect of App
85*6777b538SAndroid Build Coastguard Worker // Nap.
SetTaskSuppressionPolicy(mach_port_t task_port,bool activate)86*6777b538SAndroid Build Coastguard Worker bool SetTaskSuppressionPolicy(mach_port_t task_port, bool activate) {
87*6777b538SAndroid Build Coastguard Worker   task_suppression_policy suppression_policy = {
88*6777b538SAndroid Build Coastguard Worker       .active = activate,
89*6777b538SAndroid Build Coastguard Worker       .lowpri_cpu = activate,
90*6777b538SAndroid Build Coastguard Worker       .timer_throttle =
91*6777b538SAndroid Build Coastguard Worker           activate ? LATENCY_QOS_TIER_5 : LATENCY_QOS_TIER_UNSPECIFIED,
92*6777b538SAndroid Build Coastguard Worker       .disk_throttle = activate,
93*6777b538SAndroid Build Coastguard Worker       .cpu_limit = 0,                                    /* unused */
94*6777b538SAndroid Build Coastguard Worker       .suspend = false,                                  /* unused */
95*6777b538SAndroid Build Coastguard Worker       .throughput_qos = THROUGHPUT_QOS_TIER_UNSPECIFIED, /* unused */
96*6777b538SAndroid Build Coastguard Worker       .suppressed_cpu = activate,
97*6777b538SAndroid Build Coastguard Worker       .background_sockets = activate,
98*6777b538SAndroid Build Coastguard Worker   };
99*6777b538SAndroid Build Coastguard Worker   kern_return_t result =
100*6777b538SAndroid Build Coastguard Worker       task_policy_set(task_port, TASK_SUPPRESSION_POLICY,
101*6777b538SAndroid Build Coastguard Worker                       reinterpret_cast<task_policy_t>(&suppression_policy),
102*6777b538SAndroid Build Coastguard Worker                       TASK_SUPPRESSION_POLICY_COUNT);
103*6777b538SAndroid Build Coastguard Worker   if (result != KERN_SUCCESS) {
104*6777b538SAndroid Build Coastguard Worker     MACH_LOG(ERROR, result) << "task_policy_set TASK_SUPPRESSION_POLICY";
105*6777b538SAndroid Build Coastguard Worker     return false;
106*6777b538SAndroid Build Coastguard Worker   }
107*6777b538SAndroid Build Coastguard Worker   return true;
108*6777b538SAndroid Build Coastguard Worker }
109*6777b538SAndroid Build Coastguard Worker 
110*6777b538SAndroid Build Coastguard Worker // Returns true if the task suppression policy is active for `task_port`.
IsTaskSuppressionPolicyActive(mach_port_t task_port)111*6777b538SAndroid Build Coastguard Worker bool IsTaskSuppressionPolicyActive(mach_port_t task_port) {
112*6777b538SAndroid Build Coastguard Worker   task_suppression_policy suppression_policy = {
113*6777b538SAndroid Build Coastguard Worker       .active = false,
114*6777b538SAndroid Build Coastguard Worker   };
115*6777b538SAndroid Build Coastguard Worker 
116*6777b538SAndroid Build Coastguard Worker   mach_msg_type_number_t task_info_count = TASK_SUPPRESSION_POLICY_COUNT;
117*6777b538SAndroid Build Coastguard Worker   boolean_t get_default = FALSE;
118*6777b538SAndroid Build Coastguard Worker 
119*6777b538SAndroid Build Coastguard Worker   kern_return_t result =
120*6777b538SAndroid Build Coastguard Worker       task_policy_get(task_port, TASK_SUPPRESSION_POLICY,
121*6777b538SAndroid Build Coastguard Worker                       reinterpret_cast<task_policy_t>(&suppression_policy),
122*6777b538SAndroid Build Coastguard Worker                       &task_info_count, &get_default);
123*6777b538SAndroid Build Coastguard Worker   if (result != KERN_SUCCESS) {
124*6777b538SAndroid Build Coastguard Worker     MACH_LOG(ERROR, result) << "task_policy_get TASK_SUPPRESSION_POLICY";
125*6777b538SAndroid Build Coastguard Worker     return false;
126*6777b538SAndroid Build Coastguard Worker   }
127*6777b538SAndroid Build Coastguard Worker   CHECK(!get_default);
128*6777b538SAndroid Build Coastguard Worker 
129*6777b538SAndroid Build Coastguard Worker   // Only check the `active` property as it is sufficient to discern the state,
130*6777b538SAndroid Build Coastguard Worker   // even though other properties could be used.
131*6777b538SAndroid Build Coastguard Worker   return suppression_policy.active;
132*6777b538SAndroid Build Coastguard Worker }
133*6777b538SAndroid Build Coastguard Worker 
134*6777b538SAndroid Build Coastguard Worker // Sets the task role and the suppression policy for `task_port`.
SetPriorityImpl(mach_port_t task_port,task_role_t task_role,bool activate_suppression_policy)135*6777b538SAndroid Build Coastguard Worker bool SetPriorityImpl(mach_port_t task_port,
136*6777b538SAndroid Build Coastguard Worker                      task_role_t task_role,
137*6777b538SAndroid Build Coastguard Worker                      bool activate_suppression_policy) {
138*6777b538SAndroid Build Coastguard Worker   // Do both operations, even if the first one fails.
139*6777b538SAndroid Build Coastguard Worker   bool succeeded = SetTaskCategoryPolicy(task_port, task_role);
140*6777b538SAndroid Build Coastguard Worker   succeeded &= SetTaskSuppressionPolicy(task_port, activate_suppression_policy);
141*6777b538SAndroid Build Coastguard Worker   return succeeded;
142*6777b538SAndroid Build Coastguard Worker }
143*6777b538SAndroid Build Coastguard Worker 
144*6777b538SAndroid Build Coastguard Worker }  // namespace
145*6777b538SAndroid Build Coastguard Worker 
CreationTime() const146*6777b538SAndroid Build Coastguard Worker Time Process::CreationTime() const {
147*6777b538SAndroid Build Coastguard Worker   int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, Pid()};
148*6777b538SAndroid Build Coastguard Worker   size_t len = 0;
149*6777b538SAndroid Build Coastguard Worker   if (sysctl(mib, std::size(mib), NULL, &len, NULL, 0) < 0)
150*6777b538SAndroid Build Coastguard Worker     return Time();
151*6777b538SAndroid Build Coastguard Worker 
152*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<struct kinfo_proc, base::FreeDeleter> proc(
153*6777b538SAndroid Build Coastguard Worker       static_cast<struct kinfo_proc*>(malloc(len)));
154*6777b538SAndroid Build Coastguard Worker   if (sysctl(mib, std::size(mib), proc.get(), &len, NULL, 0) < 0)
155*6777b538SAndroid Build Coastguard Worker     return Time();
156*6777b538SAndroid Build Coastguard Worker   return Time::FromTimeVal(proc->kp_proc.p_un.__p_starttime);
157*6777b538SAndroid Build Coastguard Worker }
158*6777b538SAndroid Build Coastguard Worker 
CanSetPriority()159*6777b538SAndroid Build Coastguard Worker bool Process::CanSetPriority() {
160*6777b538SAndroid Build Coastguard Worker   return true;
161*6777b538SAndroid Build Coastguard Worker }
162*6777b538SAndroid Build Coastguard Worker 
GetPriority(PortProvider * port_provider) const163*6777b538SAndroid Build Coastguard Worker Process::Priority Process::GetPriority(PortProvider* port_provider) const {
164*6777b538SAndroid Build Coastguard Worker   CHECK(IsValid());
165*6777b538SAndroid Build Coastguard Worker   CHECK(port_provider);
166*6777b538SAndroid Build Coastguard Worker 
167*6777b538SAndroid Build Coastguard Worker   mach_port_t task_port = port_provider->TaskForHandle(Handle());
168*6777b538SAndroid Build Coastguard Worker   if (task_port == TASK_NULL) {
169*6777b538SAndroid Build Coastguard Worker     // Upon failure, return the default value.
170*6777b538SAndroid Build Coastguard Worker     return Priority::kUserBlocking;
171*6777b538SAndroid Build Coastguard Worker   }
172*6777b538SAndroid Build Coastguard Worker 
173*6777b538SAndroid Build Coastguard Worker   std::optional<task_role_t> task_role = GetTaskCategoryPolicyRole(task_port);
174*6777b538SAndroid Build Coastguard Worker   if (!task_role) {
175*6777b538SAndroid Build Coastguard Worker     // Upon failure, return the default value.
176*6777b538SAndroid Build Coastguard Worker     return Priority::kUserBlocking;
177*6777b538SAndroid Build Coastguard Worker   }
178*6777b538SAndroid Build Coastguard Worker   bool is_suppression_policy_active = IsTaskSuppressionPolicyActive(task_port);
179*6777b538SAndroid Build Coastguard Worker   if (*task_role == TASK_BACKGROUND_APPLICATION &&
180*6777b538SAndroid Build Coastguard Worker       is_suppression_policy_active) {
181*6777b538SAndroid Build Coastguard Worker     return Priority::kBestEffort;
182*6777b538SAndroid Build Coastguard Worker   } else if (*task_role == TASK_BACKGROUND_APPLICATION &&
183*6777b538SAndroid Build Coastguard Worker              !is_suppression_policy_active) {
184*6777b538SAndroid Build Coastguard Worker     return Priority::kUserVisible;
185*6777b538SAndroid Build Coastguard Worker   } else if (*task_role == TASK_FOREGROUND_APPLICATION &&
186*6777b538SAndroid Build Coastguard Worker              !is_suppression_policy_active) {
187*6777b538SAndroid Build Coastguard Worker     return Priority::kUserBlocking;
188*6777b538SAndroid Build Coastguard Worker   }
189*6777b538SAndroid Build Coastguard Worker 
190*6777b538SAndroid Build Coastguard Worker   // It is possible to get a different state very early in the process lifetime,
191*6777b538SAndroid Build Coastguard Worker   // before SetCurrentTaskDefaultRole() has been invoked. Assume highest
192*6777b538SAndroid Build Coastguard Worker   // priority then.
193*6777b538SAndroid Build Coastguard Worker   return Priority::kUserBlocking;
194*6777b538SAndroid Build Coastguard Worker }
195*6777b538SAndroid Build Coastguard Worker 
SetPriority(PortProvider * port_provider,Priority priority)196*6777b538SAndroid Build Coastguard Worker bool Process::SetPriority(PortProvider* port_provider, Priority priority) {
197*6777b538SAndroid Build Coastguard Worker   CHECK(IsValid());
198*6777b538SAndroid Build Coastguard Worker   CHECK(port_provider);
199*6777b538SAndroid Build Coastguard Worker 
200*6777b538SAndroid Build Coastguard Worker   if (!CanSetPriority()) {
201*6777b538SAndroid Build Coastguard Worker     return false;
202*6777b538SAndroid Build Coastguard Worker   }
203*6777b538SAndroid Build Coastguard Worker 
204*6777b538SAndroid Build Coastguard Worker   mach_port_t task_port = port_provider->TaskForHandle(Handle());
205*6777b538SAndroid Build Coastguard Worker   if (task_port == TASK_NULL) {
206*6777b538SAndroid Build Coastguard Worker     return false;
207*6777b538SAndroid Build Coastguard Worker   }
208*6777b538SAndroid Build Coastguard Worker 
209*6777b538SAndroid Build Coastguard Worker   switch (priority) {
210*6777b538SAndroid Build Coastguard Worker     case Priority::kBestEffort:
211*6777b538SAndroid Build Coastguard Worker       // Activate the suppression policy.
212*6777b538SAndroid Build Coastguard Worker       // Note:
213*6777b538SAndroid Build Coastguard Worker       // App Nap keeps the task role to TASK_FOREGROUND_APPLICATION when it
214*6777b538SAndroid Build Coastguard Worker       // activates the suppression policy. Here TASK_BACKGROUND_APPLICATION is
215*6777b538SAndroid Build Coastguard Worker       // used instead to keep the kBestEffort role consistent with the value for
216*6777b538SAndroid Build Coastguard Worker       // kUserVisible (so that its is not greater than kUserVisible). This
217*6777b538SAndroid Build Coastguard Worker       // difference is unlikely to matter.
218*6777b538SAndroid Build Coastguard Worker       return SetPriorityImpl(task_port, TASK_BACKGROUND_APPLICATION, true);
219*6777b538SAndroid Build Coastguard Worker     case Priority::kUserVisible:
220*6777b538SAndroid Build Coastguard Worker       // Set a task role with a lower priority than kUserBlocking, but do not
221*6777b538SAndroid Build Coastguard Worker       // activate the suppression policy.
222*6777b538SAndroid Build Coastguard Worker       return SetPriorityImpl(task_port, TASK_BACKGROUND_APPLICATION, false);
223*6777b538SAndroid Build Coastguard Worker     case Priority::kUserBlocking:
224*6777b538SAndroid Build Coastguard Worker     default:
225*6777b538SAndroid Build Coastguard Worker       // Set the highest priority with the suppression policy inactive.
226*6777b538SAndroid Build Coastguard Worker       return SetPriorityImpl(task_port, TASK_FOREGROUND_APPLICATION, false);
227*6777b538SAndroid Build Coastguard Worker   }
228*6777b538SAndroid Build Coastguard Worker }
229*6777b538SAndroid Build Coastguard Worker 
230*6777b538SAndroid Build Coastguard Worker // static
SetCurrentTaskDefaultRole()231*6777b538SAndroid Build Coastguard Worker void Process::SetCurrentTaskDefaultRole() {
232*6777b538SAndroid Build Coastguard Worker   if (!base::FeatureList::IsEnabled(kMacSetDefaultTaskRole)) {
233*6777b538SAndroid Build Coastguard Worker     return;
234*6777b538SAndroid Build Coastguard Worker   }
235*6777b538SAndroid Build Coastguard Worker 
236*6777b538SAndroid Build Coastguard Worker   SetTaskCategoryPolicy(mach_task_self(), TASK_FOREGROUND_APPLICATION);
237*6777b538SAndroid Build Coastguard Worker 
238*6777b538SAndroid Build Coastguard Worker   // Set the QoS settings to tier 0, to match the default value given to App Nap
239*6777b538SAndroid Build Coastguard Worker   // enabled applications.
240*6777b538SAndroid Build Coastguard Worker   task_qos_policy task_qos_policy = {
241*6777b538SAndroid Build Coastguard Worker       .task_latency_qos_tier = LATENCY_QOS_TIER_0,
242*6777b538SAndroid Build Coastguard Worker       .task_throughput_qos_tier = THROUGHPUT_QOS_TIER_0,
243*6777b538SAndroid Build Coastguard Worker   };
244*6777b538SAndroid Build Coastguard Worker   task_policy_set(mach_task_self(), TASK_BASE_QOS_POLICY,
245*6777b538SAndroid Build Coastguard Worker                   reinterpret_cast<task_policy_t>(&task_qos_policy),
246*6777b538SAndroid Build Coastguard Worker                   TASK_QOS_POLICY_COUNT);
247*6777b538SAndroid Build Coastguard Worker }
248*6777b538SAndroid Build Coastguard Worker 
249*6777b538SAndroid Build Coastguard Worker }  // namespace base
250