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