• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/process/process.h"
6 
7 #include <mach/mach.h>
8 #include <stddef.h>
9 #include <sys/resource.h>
10 #include <sys/sysctl.h>
11 #include <sys/time.h>
12 #include <unistd.h>
13 
14 #include <iterator>
15 #include <memory>
16 
17 #include "base/cxx17_backports.h"
18 #include "base/feature_list.h"
19 #include "base/mac/mach_logging.h"
20 #include "base/memory/free_deleter.h"
21 #include "third_party/abseil-cpp/absl/types/optional.h"
22 
23 namespace base {
24 
25 namespace {
26 
27 // Enables setting the task role of every child process to
28 // TASK_DEFAULT_APPLICATION.
29 BASE_FEATURE(kMacSetDefaultTaskRole,
30              "MacSetDefaultTaskRole",
31              FEATURE_DISABLED_BY_DEFAULT);
32 
33 // Returns the `task_role_t` of the process whose process ID is `pid`.
GetTaskCategoryPolicyRole(PortProvider * port_provider,ProcessId pid)34 absl::optional<task_role_t> GetTaskCategoryPolicyRole(
35     PortProvider* port_provider,
36     ProcessId pid) {
37   DCHECK(port_provider);
38 
39   mach_port_t task_port = port_provider->TaskForPid(pid);
40   if (task_port == TASK_NULL) {
41     return absl::nullopt;
42   }
43 
44   task_category_policy_data_t category_policy;
45   mach_msg_type_number_t task_info_count = TASK_CATEGORY_POLICY_COUNT;
46   boolean_t get_default = FALSE;
47 
48   kern_return_t result =
49       task_policy_get(task_port, TASK_CATEGORY_POLICY,
50                       reinterpret_cast<task_policy_t>(&category_policy),
51                       &task_info_count, &get_default);
52   if (result != KERN_SUCCESS) {
53     MACH_LOG(ERROR, result) << "task_policy_get TASK_CATEGORY_POLICY";
54     return absl::nullopt;
55   }
56   DCHECK(!get_default);
57   return category_policy.role;
58 }
59 
60 }  // namespace
61 
CreationTime() const62 Time Process::CreationTime() const {
63   int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, Pid()};
64   size_t len = 0;
65   if (sysctl(mib, std::size(mib), NULL, &len, NULL, 0) < 0)
66     return Time();
67 
68   std::unique_ptr<struct kinfo_proc, base::FreeDeleter> proc(
69       static_cast<struct kinfo_proc*>(malloc(len)));
70   if (sysctl(mib, std::size(mib), proc.get(), &len, NULL, 0) < 0)
71     return Time();
72   return Time::FromTimeVal(proc->kp_proc.p_un.__p_starttime);
73 }
74 
CanBackgroundProcesses()75 bool Process::CanBackgroundProcesses() {
76   return true;
77 }
78 
IsProcessBackgrounded(PortProvider * port_provider) const79 bool Process::IsProcessBackgrounded(PortProvider* port_provider) const {
80   DCHECK(IsValid());
81   DCHECK(port_provider);
82 
83   // A process is backgrounded if the role is explicitly
84   // TASK_BACKGROUND_APPLICATION (as opposed to not being
85   // TASK_FOREGROUND_APPLICATION).
86   absl::optional<task_role_t> task_role =
87       GetTaskCategoryPolicyRole(port_provider, Pid());
88   return task_role && *task_role == TASK_BACKGROUND_APPLICATION;
89 }
90 
SetProcessBackgrounded(PortProvider * port_provider,bool background)91 bool Process::SetProcessBackgrounded(PortProvider* port_provider,
92                                      bool background) {
93   DCHECK(IsValid());
94   DCHECK(port_provider);
95 
96   if (!CanBackgroundProcesses()) {
97     return false;
98   }
99 
100   mach_port_t task_port = port_provider->TaskForPid(Pid());
101   if (task_port == TASK_NULL)
102     return false;
103 
104   absl::optional<task_role_t> current_role =
105       GetTaskCategoryPolicyRole(port_provider, Pid());
106   if (!current_role) {
107     return false;
108   }
109 
110   if ((background && *current_role == TASK_BACKGROUND_APPLICATION) ||
111       (!background && *current_role == TASK_FOREGROUND_APPLICATION)) {
112     return true;
113   }
114 
115   task_category_policy category_policy;
116   category_policy.role =
117       background ? TASK_BACKGROUND_APPLICATION : TASK_FOREGROUND_APPLICATION;
118   kern_return_t result =
119       task_policy_set(task_port, TASK_CATEGORY_POLICY,
120                       reinterpret_cast<task_policy_t>(&category_policy),
121                       TASK_CATEGORY_POLICY_COUNT);
122 
123   if (result != KERN_SUCCESS) {
124     MACH_LOG(ERROR, result) << "task_policy_set TASK_CATEGORY_POLICY";
125     return false;
126   }
127 
128   return true;
129 }
130 
131 // static
SetCurrentTaskDefaultRole()132 void Process::SetCurrentTaskDefaultRole() {
133   if (!base::FeatureList::IsEnabled(kMacSetDefaultTaskRole)) {
134     return;
135   }
136 
137   task_category_policy category_policy;
138   category_policy.role = TASK_DEFAULT_APPLICATION;
139   task_policy_set(mach_task_self(), TASK_CATEGORY_POLICY,
140                   reinterpret_cast<task_policy_t>(&category_policy),
141                   TASK_CATEGORY_POLICY_COUNT);
142 }
143 
144 }  // namespace base
145