1 /*
2 * Copyright (c) 2006-2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <sys/cdefs.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <strings.h>
29 #include <stdlib.h>
30 #include <sys/errno.h>
31 #include <sys/msgbuf.h>
32 #include <sys/resource.h>
33 #include <sys/process_policy.h>
34 #include <sys/event.h>
35 #include <mach/message.h>
36
37 #include "libproc_internal.h"
38
39 int __proc_info(int callnum, int pid, int flavor, uint64_t arg, void * buffer, int buffersize);
40 int __proc_info_extended_id(int32_t callnum, int32_t pid, uint32_t flavor, uint32_t flags, uint64_t ext_id, uint64_t arg, user_addr_t buffer, int32_t buffersize);
41 __private_extern__ int proc_setthreadname(void * buffer, int buffersize);
42 int __process_policy(int scope, int action, int policy, int policy_subtype, proc_policy_attribute_t * attrp, pid_t target_pid, uint64_t target_threadid);
43 int proc_rlimit_control(pid_t pid, int flavor, void *arg);
44
45 int
proc_listpids(uint32_t type,uint32_t typeinfo,void * buffer,int buffersize)46 proc_listpids(uint32_t type, uint32_t typeinfo, void *buffer, int buffersize)
47 {
48 int retval;
49
50 if ((type >= PROC_ALL_PIDS) || (type <= PROC_PPID_ONLY)) {
51 if ((retval = __proc_info(PROC_INFO_CALL_LISTPIDS, type, typeinfo, (uint64_t)0, buffer, buffersize)) == -1) {
52 return 0;
53 }
54 } else {
55 errno = EINVAL;
56 retval = 0;
57 }
58 return retval;
59 }
60
61
62 int
proc_listallpids(void * buffer,int buffersize)63 proc_listallpids(void * buffer, int buffersize)
64 {
65 int numpids;
66 numpids = proc_listpids(PROC_ALL_PIDS, (uint32_t)0, buffer, buffersize);
67
68 if (numpids == -1) {
69 return -1;
70 } else {
71 return numpids / sizeof(int);
72 }
73 }
74
75 int
proc_listpgrppids(pid_t pgrpid,void * buffer,int buffersize)76 proc_listpgrppids(pid_t pgrpid, void * buffer, int buffersize)
77 {
78 int numpids;
79 numpids = proc_listpids(PROC_PGRP_ONLY, (uint32_t)pgrpid, buffer, buffersize);
80 if (numpids == -1) {
81 return -1;
82 } else {
83 return numpids / sizeof(int);
84 }
85 }
86
87 int
proc_listchildpids(pid_t ppid,void * buffer,int buffersize)88 proc_listchildpids(pid_t ppid, void * buffer, int buffersize)
89 {
90 int numpids;
91 numpids = proc_listpids(PROC_PPID_ONLY, (uint32_t)ppid, buffer, buffersize);
92 if (numpids == -1) {
93 return -1;
94 } else {
95 return numpids / sizeof(int);
96 }
97 }
98
99
100 int
proc_pidinfo(int pid,int flavor,uint64_t arg,void * buffer,int buffersize)101 proc_pidinfo(int pid, int flavor, uint64_t arg, void *buffer, int buffersize)
102 {
103 int retval;
104
105 if ((retval = __proc_info(PROC_INFO_CALL_PIDINFO, pid, flavor, arg, buffer, buffersize)) == -1) {
106 return 0;
107 }
108
109 return retval;
110 }
111
112
113 int
proc_pidoriginatorinfo(int flavor,void * buffer,int buffersize)114 proc_pidoriginatorinfo(int flavor, void *buffer, int buffersize)
115 {
116 int retval;
117
118 if ((retval = __proc_info(PROC_INFO_CALL_PIDORIGINATORINFO, getpid(), flavor, 0, buffer, buffersize)) == -1) {
119 return 0;
120 }
121
122 return retval;
123 }
124
125 int
proc_listcoalitions(int flavor,int coaltype,void * buffer,int buffersize)126 proc_listcoalitions(int flavor, int coaltype, void *buffer, int buffersize)
127 {
128 int retval;
129
130 if ((retval = __proc_info(PROC_INFO_CALL_LISTCOALITIONS, flavor, coaltype, 0, buffer, buffersize)) == -1) {
131 return 0;
132 }
133
134 return retval;
135 }
136
137 int
proc_pid_rusage(int pid,int flavor,rusage_info_t * buffer)138 proc_pid_rusage(int pid, int flavor, rusage_info_t *buffer)
139 {
140 return __proc_info(PROC_INFO_CALL_PIDRUSAGE, pid, flavor, 0, buffer, 0);
141 }
142
143 int
proc_setthread_cpupercent(uint8_t percentage,uint32_t ms_refill)144 proc_setthread_cpupercent(uint8_t percentage, uint32_t ms_refill)
145 {
146 uint32_t arg = 0;
147
148 /* Pack percentage and refill into a 32-bit number to match existing kernel implementation */
149 if ((percentage >= 100) || (ms_refill & ~0xffffffU)) {
150 errno = EINVAL;
151 return -1;
152 }
153
154 arg = ((ms_refill << 8) | percentage);
155
156 return proc_rlimit_control(-1, RLIMIT_THREAD_CPULIMITS, (void *)(uintptr_t)arg);
157 }
158
159 int
proc_pidfdinfo(int pid,int fd,int flavor,void * buffer,int buffersize)160 proc_pidfdinfo(int pid, int fd, int flavor, void * buffer, int buffersize)
161 {
162 int retval;
163
164 if ((retval = __proc_info(PROC_INFO_CALL_PIDFDINFO, pid, flavor, (uint64_t)fd, buffer, buffersize)) == -1) {
165 return 0;
166 }
167
168 return retval;
169 }
170
171
172 int
proc_pidfileportinfo(int pid,uint32_t fileport,int flavor,void * buffer,int buffersize)173 proc_pidfileportinfo(int pid, uint32_t fileport, int flavor, void *buffer, int buffersize)
174 {
175 int retval;
176
177 if ((retval = __proc_info(PROC_INFO_CALL_PIDFILEPORTINFO, pid, flavor, (uint64_t)fileport, buffer, buffersize)) == -1) {
178 return 0;
179 }
180 return retval;
181 }
182
183 int
proc_piddynkqueueinfo(int pid,int flavor,kqueue_id_t kq_id,void * buffer,int buffersize)184 proc_piddynkqueueinfo(int pid, int flavor, kqueue_id_t kq_id, void *buffer, int buffersize)
185 {
186 int ret;
187
188 if ((ret = __proc_info(PROC_INFO_CALL_PIDDYNKQUEUEINFO, pid, flavor, (uint64_t)kq_id, buffer, buffersize)) == -1) {
189 return 0;
190 }
191
192 return ret;
193 }
194
195 int
proc_udata_info(int pid,int flavor,void * buffer,int buffersize)196 proc_udata_info(int pid, int flavor, void *buffer, int buffersize)
197 {
198 return __proc_info(PROC_INFO_CALL_UDATA_INFO, pid, flavor, 0, buffer, buffersize);
199 }
200
201 /* only used by dyld which links with libsystem_kernel.a */
202 __private_extern__ int
proc_set_dyld_all_image_info(void * buffer,int buffersize)203 proc_set_dyld_all_image_info(void *buffer, int buffersize)
204 {
205 return __proc_info(PROC_INFO_CALL_SET_DYLD_IMAGES, getpid(), 0, 0, buffer, buffersize);
206 }
207
208
209 int
proc_name(int pid,void * buffer,uint32_t buffersize)210 proc_name(int pid, void * buffer, uint32_t buffersize)
211 {
212 int retval = 0, len;
213 struct proc_bsdinfo pbsd;
214
215
216 if (buffersize < sizeof(pbsd.pbi_name)) {
217 errno = ENOMEM;
218 return 0;
219 }
220
221 retval = proc_pidinfo(pid, PROC_PIDTBSDINFO, (uint64_t)0, &pbsd, sizeof(struct proc_bsdinfo));
222 if (retval != 0) {
223 if (pbsd.pbi_name[0]) {
224 bcopy(&pbsd.pbi_name, buffer, sizeof(pbsd.pbi_name));
225 } else {
226 bcopy(&pbsd.pbi_comm, buffer, sizeof(pbsd.pbi_comm));
227 }
228 len = (int)strlen(buffer);
229 return len;
230 }
231 return 0;
232 }
233
234 int
proc_regionfilename(int pid,uint64_t address,void * buffer,uint32_t buffersize)235 proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersize)
236 {
237 int retval;
238 struct proc_regionpath path;
239
240 if (buffersize < MAXPATHLEN) {
241 errno = ENOMEM;
242 return 0;
243 }
244
245 retval = proc_pidinfo(pid, PROC_PIDREGIONPATH, (uint64_t)address, &path, sizeof(struct proc_regionpath));
246 if (retval != 0) {
247 return (int)(strlcpy(buffer, path.prpo_path, buffersize));
248 }
249 return 0;
250 }
251
252 int
proc_kmsgbuf(void * buffer,uint32_t buffersize)253 proc_kmsgbuf(void * buffer, uint32_t buffersize)
254 {
255 int retval;
256
257 if ((retval = __proc_info(PROC_INFO_CALL_KERNMSGBUF, 0, 0, (uint64_t)0, buffer, buffersize)) == -1) {
258 return 0;
259 }
260 return retval;
261 }
262
263 int
proc_pidpath(int pid,void * buffer,uint32_t buffersize)264 proc_pidpath(int pid, void * buffer, uint32_t buffersize)
265 {
266 int retval, len;
267
268 if (buffersize < PROC_PIDPATHINFO_SIZE) {
269 errno = ENOMEM;
270 return 0;
271 }
272 if (buffersize > PROC_PIDPATHINFO_MAXSIZE) {
273 errno = EOVERFLOW;
274 return 0;
275 }
276
277 retval = __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDPATHINFO, (uint64_t)0, buffer, buffersize);
278 if (retval != -1) {
279 len = (int)strlen(buffer);
280 return len;
281 }
282 return 0;
283 }
284
285 int
proc_pidpath_audittoken(audit_token_t * audittoken,void * buffer,uint32_t buffersize)286 proc_pidpath_audittoken(audit_token_t *audittoken, void * buffer, uint32_t buffersize)
287 {
288 int retval, len;
289
290 if (buffersize < PROC_PIDPATHINFO_SIZE) {
291 errno = ENOMEM;
292 return 0;
293 }
294 if (buffersize > PROC_PIDPATHINFO_MAXSIZE) {
295 errno = EOVERFLOW;
296 return 0;
297 }
298
299 int pid = audittoken->val[5];
300 int idversion = audittoken->val[7];
301
302 retval = __proc_info_extended_id(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDPATHINFO, PIF_COMPARE_IDVERSION, (uint64_t)idversion,
303 (uint64_t)0, buffer, buffersize);
304 if (retval != -1) {
305 len = (int)strlen(buffer);
306 return len;
307 }
308 return 0;
309 }
310
311 int
proc_current_thread_schedinfo(void * buffer,size_t buffersize)312 proc_current_thread_schedinfo(void *buffer, size_t buffersize)
313 {
314 extern uint64_t __thread_selfid(void);
315
316 int retval;
317
318 if (buffersize < PROC_PIDTHREADSCHEDINFO_SIZE) {
319 errno = ENOMEM;
320 return errno;
321 }
322 if (buffersize > PROC_PIDTHREADSCHEDINFO_SIZE) {
323 errno = EOVERFLOW;
324 return errno;
325 }
326
327 pid_t pid = getpid();
328 uint64_t threadid = __thread_selfid();
329
330 retval = __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDTHREADSCHEDINFO, threadid, buffer, buffersize);
331
332 if (retval == -1) {
333 return errno;
334 }
335 return 0;
336 }
337
338 int
proc_libversion(int * major,int * minor)339 proc_libversion(int *major, int * minor)
340 {
341 if (major != NULL) {
342 *major = 1;
343 }
344 if (minor != NULL) {
345 *minor = 1;
346 }
347 return 0;
348 }
349
350 int
proc_setpcontrol(const int control)351 proc_setpcontrol(const int control)
352 {
353 int retval;
354
355 if (control < PROC_SETPC_NONE || control > PROC_SETPC_TERMINATE) {
356 return EINVAL;
357 }
358
359 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_PCONTROL, (uint64_t)control, NULL, 0)) == -1) {
360 return errno;
361 }
362
363 return 0;
364 }
365
366
367 __private_extern__ int
proc_setthreadname(void * buffer,int buffersize)368 proc_setthreadname(void * buffer, int buffersize)
369 {
370 int retval;
371
372 retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_THREADNAME, (uint64_t)0, buffer, buffersize);
373
374 if (retval == -1) {
375 return errno;
376 } else {
377 return 0;
378 }
379 }
380
381 int
proc_track_dirty(pid_t pid,uint32_t flags)382 proc_track_dirty(pid_t pid, uint32_t flags)
383 {
384 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_TRACK, flags, NULL, 0) == -1) {
385 return errno;
386 }
387
388 return 0;
389 }
390
391 int
proc_set_dirty(pid_t pid,bool dirty)392 proc_set_dirty(pid_t pid, bool dirty)
393 {
394 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_SET, dirty, NULL, 0) == -1) {
395 return errno;
396 }
397
398 return 0;
399 }
400
401 int
proc_get_dirty(pid_t pid,uint32_t * flags)402 proc_get_dirty(pid_t pid, uint32_t *flags)
403 {
404 int retval;
405
406 if (!flags) {
407 return EINVAL;
408 }
409
410 retval = __proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_GET, 0, NULL, 0);
411 if (retval == -1) {
412 return errno;
413 }
414
415 *flags = retval;
416
417 return 0;
418 }
419
420 int
proc_clear_dirty(pid_t pid,uint32_t flags)421 proc_clear_dirty(pid_t pid, uint32_t flags)
422 {
423 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_CLEAR, flags, NULL, 0) == -1) {
424 return errno;
425 }
426
427 return 0;
428 }
429
430 int
proc_terminate(pid_t pid,int * sig)431 proc_terminate(pid_t pid, int *sig)
432 {
433 int retval;
434
435 if (!sig) {
436 return EINVAL;
437 }
438
439 retval = __proc_info(PROC_INFO_CALL_TERMINATE, pid, 0, 0, NULL, 0);
440 if (retval == -1) {
441 return errno;
442 }
443
444 *sig = retval;
445
446 return 0;
447 }
448
449 int
proc_signal_with_audittoken(audit_token_t * audittoken,int sig)450 proc_signal_with_audittoken(audit_token_t *audittoken, int sig)
451 {
452 int retval = __proc_info(PROC_INFO_CALL_SIGNAL_AUDITTOKEN, 0, sig, 0, audittoken, 0);
453 if (retval == -1) {
454 return errno;
455 }
456
457 return 0;
458 }
459
460 int
proc_terminate_all_rsr(int sig)461 proc_terminate_all_rsr(int sig)
462 {
463 int retval = 0;
464
465 if (sig != SIGKILL && sig != SIGTERM) {
466 return EINVAL;
467 }
468
469 retval = __proc_info(PROC_INFO_CALL_TERMINATE_RSR, 0, 0, sig, NULL, 0);
470 if (retval == -1) {
471 return errno;
472 }
473
474 return 0;
475 }
476
477 /*
478 * XXX the _fatal() variant both checks for an existing monitor
479 * (with important policy effects on first party background apps)
480 * and validates inputs.
481 */
482 int
proc_set_cpumon_params(pid_t pid,int percentage,int interval)483 proc_set_cpumon_params(pid_t pid, int percentage, int interval)
484 {
485 proc_policy_cpuusage_attr_t attr;
486
487 /* no argument validation ...
488 * task_set_cpuusage() ignores 0 values and squashes negative
489 * values into uint32_t.
490 */
491
492 attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
493 attr.ppattr_cpu_percentage = percentage;
494 attr.ppattr_cpu_attr_interval = (uint64_t)interval;
495 attr.ppattr_cpu_attr_deadline = 0;
496
497 return __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
498 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
499 }
500
501 int
proc_get_cpumon_params(pid_t pid,int * percentage,int * interval)502 proc_get_cpumon_params(pid_t pid, int *percentage, int *interval)
503 {
504 proc_policy_cpuusage_attr_t attr;
505 int ret;
506
507 ret = __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_GET, PROC_POLICY_RESOURCE_USAGE,
508 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
509
510 if ((ret == 0) && (attr.ppattr_cpu_attr == PROC_POLICY_RSRCACT_NOTIFY_EXC)) {
511 *percentage = attr.ppattr_cpu_percentage;
512 *interval = (int)attr.ppattr_cpu_attr_interval;
513 } else {
514 *percentage = 0;
515 *interval = 0;
516 }
517
518 return ret;
519 }
520
521 int
proc_set_cpumon_defaults(pid_t pid)522 proc_set_cpumon_defaults(pid_t pid)
523 {
524 proc_policy_cpuusage_attr_t attr;
525
526 attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
527 attr.ppattr_cpu_percentage = PROC_POLICY_CPUMON_DEFAULTS;
528 attr.ppattr_cpu_attr_interval = 0;
529 attr.ppattr_cpu_attr_deadline = 0;
530
531 return __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
532 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
533 }
534
535 int
proc_resume_cpumon(pid_t pid)536 proc_resume_cpumon(pid_t pid)
537 {
538 return __process_policy(PROC_POLICY_SCOPE_PROCESS,
539 PROC_POLICY_ACTION_ENABLE,
540 PROC_POLICY_RESOURCE_USAGE,
541 PROC_POLICY_RUSAGE_CPU,
542 NULL, pid, 0);
543 }
544
545 int
proc_disable_cpumon(pid_t pid)546 proc_disable_cpumon(pid_t pid)
547 {
548 proc_policy_cpuusage_attr_t attr;
549
550 attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
551 attr.ppattr_cpu_percentage = PROC_POLICY_CPUMON_DISABLE;
552 attr.ppattr_cpu_attr_interval = 0;
553 attr.ppattr_cpu_attr_deadline = 0;
554
555 return __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
556 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
557 }
558
559
560 /*
561 * Turn on the CPU usage monitor using the supplied parameters, and make
562 * violations of the monitor fatal.
563 *
564 * Returns: 0 on success;
565 * -1 on failure and sets errno
566 */
567 int
proc_set_cpumon_params_fatal(pid_t pid,int percentage,int interval)568 proc_set_cpumon_params_fatal(pid_t pid, int percentage, int interval)
569 {
570 int current_percentage = 0;
571 int current_interval = 0; /* intervals are in seconds */
572 int ret = 0;
573
574 if ((percentage <= 0) || (interval <= 0)) {
575 errno = EINVAL;
576 return -1;
577 }
578
579 /*
580 * Do a simple query to see if CPU monitoring is
581 * already active. If either the percentage or the
582 * interval is nonzero, then CPU monitoring is
583 * already in use for this process.
584 *
585 * XXX: need set...() and set..fatal() to behave similarly.
586 * Currently, this check prevents 1st party apps (which get a
587 * default non-fatal monitor) not to get a fatal monitor.
588 */
589 (void)proc_get_cpumon_params(pid, ¤t_percentage, ¤t_interval);
590 if (current_percentage || current_interval) {
591 /*
592 * The CPU monitor appears to be active.
593 * We choose not to disturb those settings.
594 */
595 errno = EBUSY;
596 return -1;
597 }
598
599 if ((ret = proc_set_cpumon_params(pid, percentage, interval)) != 0) {
600 /* Failed to activate the CPU monitor */
601 return ret;
602 }
603
604 if ((ret = proc_rlimit_control(pid, RLIMIT_CPU_USAGE_MONITOR, (void *)(uintptr_t)CPUMON_MAKE_FATAL)) != 0) {
605 /* Failed to set termination, back out the CPU monitor settings. */
606 (void)proc_disable_cpumon(pid);
607 }
608
609 return ret;
610 }
611
612 int
proc_set_wakemon_params(pid_t pid,int rate_hz,int flags __unused)613 proc_set_wakemon_params(pid_t pid, int rate_hz, int flags __unused)
614 {
615 struct proc_rlimit_control_wakeupmon params;
616
617 params.wm_flags = WAKEMON_ENABLE;
618 params.wm_rate = rate_hz;
619
620 return proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, ¶ms);
621 }
622
623 #ifndef WAKEMON_GET_PARAMS
624 #define WAKEMON_GET_PARAMS 0x4
625 #define WAKEMON_SET_DEFAULTS 0x8
626 #endif
627
628 int
proc_get_wakemon_params(pid_t pid,int * rate_hz,int * flags)629 proc_get_wakemon_params(pid_t pid, int *rate_hz, int *flags)
630 {
631 struct proc_rlimit_control_wakeupmon params;
632 int error;
633
634 params.wm_flags = WAKEMON_GET_PARAMS;
635
636 if ((error = proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, ¶ms)) != 0) {
637 return error;
638 }
639
640 *rate_hz = params.wm_rate;
641 *flags = params.wm_flags;
642
643 return 0;
644 }
645
646 int
proc_set_wakemon_defaults(pid_t pid)647 proc_set_wakemon_defaults(pid_t pid)
648 {
649 struct proc_rlimit_control_wakeupmon params;
650
651 params.wm_flags = WAKEMON_ENABLE | WAKEMON_SET_DEFAULTS;
652 params.wm_rate = -1;
653
654 return proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, ¶ms);
655 }
656
657 int
proc_disable_wakemon(pid_t pid)658 proc_disable_wakemon(pid_t pid)
659 {
660 struct proc_rlimit_control_wakeupmon params;
661
662 params.wm_flags = WAKEMON_DISABLE;
663 params.wm_rate = -1;
664
665 return proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, ¶ms);
666 }
667
668 int
proc_list_uptrs(int pid,uint64_t * buf,uint32_t bufsz)669 proc_list_uptrs(int pid, uint64_t *buf, uint32_t bufsz)
670 {
671 return __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDLISTUPTRS, 0,
672 buf, bufsz);
673 }
674
675 int
proc_list_dynkqueueids(int pid,kqueue_id_t * buf,uint32_t bufsz)676 proc_list_dynkqueueids(int pid, kqueue_id_t *buf, uint32_t bufsz)
677 {
678 return __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDLISTDYNKQUEUES, 0,
679 buf, bufsz);
680 }
681
682
683 int
proc_setcpu_percentage(pid_t pid,int action,int percentage)684 proc_setcpu_percentage(pid_t pid, int action, int percentage)
685 {
686 proc_policy_cpuusage_attr_t attr;
687
688 bzero(&attr, sizeof(proc_policy_cpuusage_attr_t));
689 attr.ppattr_cpu_attr = action;
690 attr.ppattr_cpu_percentage = percentage;
691 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_RESOURCE_USAGE, PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, (uint64_t)0) != -1) {
692 return 0;
693 } else {
694 return errno;
695 }
696 }
697
698 int
proc_reset_footprint_interval(pid_t pid)699 proc_reset_footprint_interval(pid_t pid)
700 {
701 return proc_rlimit_control(pid, RLIMIT_FOOTPRINT_INTERVAL, (void *)(uintptr_t)FOOTPRINT_INTERVAL_RESET);
702 }
703
704 int
proc_clear_cpulimits(pid_t pid)705 proc_clear_cpulimits(pid_t pid)
706 {
707 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_RESTORE, PROC_POLICY_RESOURCE_USAGE, PROC_POLICY_RUSAGE_CPU, NULL, pid, (uint64_t)0) != -1) {
708 return 0;
709 } else {
710 return errno;
711 }
712 }
713
714 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
715
716 int
proc_setcpu_deadline(pid_t pid,int action,uint64_t deadline)717 proc_setcpu_deadline(pid_t pid, int action, uint64_t deadline)
718 {
719 proc_policy_cpuusage_attr_t attr;
720
721 bzero(&attr, sizeof(proc_policy_cpuusage_attr_t));
722 attr.ppattr_cpu_attr = action;
723 attr.ppattr_cpu_attr_deadline = deadline;
724 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_RESOURCE_USAGE, PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, (uint64_t)0) != -1) {
725 return 0;
726 } else {
727 return errno;
728 }
729 }
730
731 int
proc_setcpu_percentage_withdeadline(pid_t pid,int action,int percentage,uint64_t deadline)732 proc_setcpu_percentage_withdeadline(pid_t pid, int action, int percentage, uint64_t deadline)
733 {
734 proc_policy_cpuusage_attr_t attr;
735
736 bzero(&attr, sizeof(proc_policy_cpuusage_attr_t));
737 attr.ppattr_cpu_attr = action;
738 attr.ppattr_cpu_percentage = percentage;
739 attr.ppattr_cpu_attr_deadline = deadline;
740 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_RESOURCE_USAGE, PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, (uint64_t)0) != -1) {
741 return 0;
742 } else {
743 return errno;
744 }
745 }
746
747 int
proc_appstate(int pid,int * appstatep)748 proc_appstate(int pid, int * appstatep)
749 {
750 int state;
751
752 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_GET, PROC_POLICY_APP_LIFECYCLE, PROC_POLICY_APPLIFE_STATE, (proc_policy_attribute_t*)&state, pid, (uint64_t)0) != -1) {
753 if (appstatep != NULL) {
754 *appstatep = state;
755 }
756 return 0;
757 } else {
758 return errno;
759 }
760 }
761
762 int
proc_setappstate(int pid,int appstate)763 proc_setappstate(int pid, int appstate)
764 {
765 int state = appstate;
766
767 switch (state) {
768 case PROC_APPSTATE_NONE:
769 case PROC_APPSTATE_ACTIVE:
770 case PROC_APPSTATE_INACTIVE:
771 case PROC_APPSTATE_BACKGROUND:
772 case PROC_APPSTATE_NONUI:
773 break;
774 default:
775 return EINVAL;
776 }
777 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_APP_LIFECYCLE, PROC_POLICY_APPLIFE_STATE, (proc_policy_attribute_t*)&state, pid, (uint64_t)0) != -1) {
778 return 0;
779 } else {
780 return errno;
781 }
782 }
783
784 int
proc_devstatusnotify(int devicestatus)785 proc_devstatusnotify(int devicestatus)
786 {
787 int state = devicestatus;
788
789 switch (devicestatus) {
790 case PROC_DEVSTATUS_SHORTTERM:
791 case PROC_DEVSTATUS_LONGTERM:
792 break;
793 default:
794 return EINVAL;
795 }
796
797 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_APP_LIFECYCLE, PROC_POLICY_APPLIFE_DEVSTATUS, (proc_policy_attribute_t*)&state, getpid(), (uint64_t)0) != -1) {
798 return 0;
799 } else {
800 return errno;
801 }
802 }
803
804 int
proc_pidbind(int pid,uint64_t threadid,int bind)805 proc_pidbind(int pid, uint64_t threadid, int bind)
806 {
807 int state = bind;
808 pid_t passpid = pid;
809
810 switch (bind) {
811 case PROC_PIDBIND_CLEAR:
812 passpid = getpid(); /* ignore pid on clear */
813 break;
814 case PROC_PIDBIND_SET:
815 break;
816 default:
817 return EINVAL;
818 }
819 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_APP_LIFECYCLE, PROC_POLICY_APPLIFE_PIDBIND, (proc_policy_attribute_t*)&state, passpid, threadid) != -1) {
820 return 0;
821 } else {
822 return errno;
823 }
824 }
825
826 int
proc_can_use_foreground_hw(int pid,uint32_t * reason)827 proc_can_use_foreground_hw(int pid, uint32_t *reason)
828 {
829 return __proc_info(PROC_INFO_CALL_CANUSEFGHW, pid, 0, 0, reason, sizeof(*reason));
830 }
831 #endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
832
833
834 /* Donate importance to adaptive processes from this process */
835 int
proc_donate_importance_boost(void)836 proc_donate_importance_boost(void)
837 {
838 int rval;
839
840 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
841 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
842 PROC_POLICY_ACTION_ENABLE,
843 PROC_POLICY_APPTYPE,
844 PROC_POLICY_IOS_DONATEIMP,
845 NULL, getpid(), (uint64_t)0);
846 #else /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
847 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
848 PROC_POLICY_ACTION_SET,
849 PROC_POLICY_BOOST,
850 PROC_POLICY_IMP_DONATION,
851 NULL, getpid(), 0);
852 #endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
853
854 if (rval == 0) {
855 return 0;
856 } else {
857 return errno;
858 }
859 }
860
861 static __attribute__((noinline)) void
proc_importance_bad_assertion(char * reason)862 proc_importance_bad_assertion(char *reason)
863 {
864 (void)reason;
865 }
866
867 /*
868 * Use the address of these variables as the token. This way, they can be
869 * printed in the debugger as useful names.
870 */
871 uint64_t important_boost_assertion_token = 0xfafafafafafafafa;
872 uint64_t normal_boost_assertion_token = 0xfbfbfbfbfbfbfbfb;
873 uint64_t non_boost_assertion_token = 0xfcfcfcfcfcfcfcfc;
874 uint64_t denap_boost_assertion_token = 0xfdfdfdfdfdfdfdfd;
875
876 /*
877 * Accept the boost on a message, or request another boost assertion
878 * if we have already accepted the implicit boost for this message.
879 *
880 * Returns EOVERFLOW if an attempt is made to take an extra assertion when not boosted.
881 *
882 * Returns EIO if the message was not a boosting message.
883 * TODO: Return a 'non-boost' token instead.
884 */
885 int
proc_importance_assertion_begin_with_msg(mach_msg_header_t * msg,__unused mach_msg_trailer_t * trailer,uint64_t * assertion_token)886 proc_importance_assertion_begin_with_msg(mach_msg_header_t *msg,
887 __unused mach_msg_trailer_t *trailer,
888 uint64_t *assertion_token)
889 {
890 int rval = 0;
891
892 if (assertion_token == NULL) {
893 return EINVAL;
894 }
895
896 #define LEGACYBOOSTMASK (MACH_MSGH_BITS_VOUCHER_MASK | MACH_MSGH_BITS_RAISEIMP)
897 #define LEGACYBOOSTED(m) (((m)->msgh_bits & LEGACYBOOSTMASK) == MACH_MSGH_BITS_RAISEIMP)
898
899 /* Is this a legacy boosted message? */
900 if (LEGACYBOOSTED(msg)) {
901 /*
902 * Have we accepted the implicit boost for this message yet?
903 * If we haven't accepted it yet, no need to call into kernel.
904 */
905 if ((msg->msgh_bits & MACH_MSGH_BITS_IMPHOLDASRT) == 0) {
906 msg->msgh_bits |= MACH_MSGH_BITS_IMPHOLDASRT;
907 *assertion_token = (uint64_t) &important_boost_assertion_token;
908 return 0;
909 }
910
911 /* Request an additional boost count */
912 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
913 PROC_POLICY_ACTION_HOLD,
914 PROC_POLICY_BOOST,
915 PROC_POLICY_IMP_IMPORTANT,
916 NULL, getpid(), 0);
917 if (rval == 0) {
918 *assertion_token = (uint64_t) &important_boost_assertion_token;
919 return 0;
920 } else if (errno == EOVERFLOW) {
921 proc_importance_bad_assertion("Attempted to take assertion while not boosted");
922 return errno;
923 } else {
924 return errno;
925 }
926 }
927
928 return EIO;
929 }
930
931
932 /*
933 * Drop a boost assertion.
934 * Returns EOVERFLOW on boost assertion underflow.
935 */
936 int
proc_importance_assertion_complete(uint64_t assertion_token)937 proc_importance_assertion_complete(uint64_t assertion_token)
938 {
939 int rval = 0;
940
941 if (assertion_token == 0) {
942 return 0;
943 }
944
945 if (assertion_token == (uint64_t) &important_boost_assertion_token) {
946 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
947 PROC_POLICY_ACTION_DROP,
948 PROC_POLICY_BOOST,
949 PROC_POLICY_IMP_IMPORTANT,
950 NULL, getpid(), 0);
951 if (rval == 0) {
952 return 0;
953 } else if (errno == EOVERFLOW) {
954 proc_importance_bad_assertion("Attempted to drop too many assertions");
955 return errno;
956 } else {
957 return errno;
958 }
959 } else {
960 proc_importance_bad_assertion("Attempted to drop assertion with invalid token");
961 return EIO;
962 }
963 }
964
965 /*
966 * Accept the De-Nap boost on a message, or request another boost assertion
967 * if we have already accepted the implicit boost for this message.
968 *
969 * Interface is deprecated before it really got started - just as synonym
970 * for proc_importance_assertion_begin_with_msg() now.
971 */
972 int
proc_denap_assertion_begin_with_msg(mach_msg_header_t * msg,uint64_t * assertion_token)973 proc_denap_assertion_begin_with_msg(mach_msg_header_t *msg,
974 uint64_t *assertion_token)
975 {
976 #pragma clang diagnostic push
977 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
978 return proc_importance_assertion_begin_with_msg(msg, NULL, assertion_token);
979 #pragma clang diagnostic pop
980 }
981
982
983 /*
984 * Drop a denap boost assertion.
985 *
986 * Interface is deprecated before it really got started - just a synonym
987 * for proc_importance_assertion_complete() now.
988 */
989 int
proc_denap_assertion_complete(uint64_t assertion_token)990 proc_denap_assertion_complete(uint64_t assertion_token)
991 {
992 return proc_importance_assertion_complete(assertion_token);
993 }
994
995 #if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
996
997 int
proc_clear_vmpressure(pid_t pid)998 proc_clear_vmpressure(pid_t pid)
999 {
1000 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_RESTORE, PROC_POLICY_RESOURCE_STARVATION, PROC_POLICY_RS_VIRTUALMEM, NULL, pid, (uint64_t)0) != -1) {
1001 return 0;
1002 } else {
1003 return errno;
1004 }
1005 }
1006
1007 /* set the current process as one who can resume suspended processes due to low virtual memory. Need to be root */
1008 int
proc_set_owner_vmpressure(void)1009 proc_set_owner_vmpressure(void)
1010 {
1011 int retval;
1012
1013 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_VMRSRCOWNER, (uint64_t)0, NULL, 0)) == -1) {
1014 return errno;
1015 }
1016
1017 return 0;
1018 }
1019
1020 /* mark yourself to delay idle sleep on disk IO */
1021 int
proc_set_delayidlesleep(void)1022 proc_set_delayidlesleep(void)
1023 {
1024 int retval;
1025
1026 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_DELAYIDLESLEEP, (uint64_t)1, NULL, 0)) == -1) {
1027 return errno;
1028 }
1029
1030 return 0;
1031 }
1032
1033 /* Reset yourself to delay idle sleep on disk IO, if already set */
1034 int
proc_clear_delayidlesleep(void)1035 proc_clear_delayidlesleep(void)
1036 {
1037 int retval;
1038
1039 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_DELAYIDLESLEEP, (uint64_t)0, NULL, 0)) == -1) {
1040 return errno;
1041 }
1042
1043 return 0;
1044 }
1045
1046 /* disable the launch time backgroudn policy and restore the process to default group */
1047 int
proc_disable_apptype(pid_t pid,int apptype)1048 proc_disable_apptype(pid_t pid, int apptype)
1049 {
1050 switch (apptype) {
1051 case PROC_POLICY_OSX_APPTYPE_TAL:
1052 case PROC_POLICY_OSX_APPTYPE_DASHCLIENT:
1053 break;
1054 default:
1055 return EINVAL;
1056 }
1057
1058 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_DISABLE, PROC_POLICY_APPTYPE, apptype, NULL, pid, (uint64_t)0) != -1) {
1059 return 0;
1060 } else {
1061 return errno;
1062 }
1063 }
1064
1065 /* re-enable the launch time background policy if it had been disabled. */
1066 int
proc_enable_apptype(pid_t pid,int apptype)1067 proc_enable_apptype(pid_t pid, int apptype)
1068 {
1069 switch (apptype) {
1070 case PROC_POLICY_OSX_APPTYPE_TAL:
1071 case PROC_POLICY_OSX_APPTYPE_DASHCLIENT:
1072 break;
1073 default:
1074 return EINVAL;
1075 }
1076
1077 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_ENABLE, PROC_POLICY_APPTYPE, apptype, NULL, pid, (uint64_t)0) != -1) {
1078 return 0;
1079 } else {
1080 return errno;
1081 }
1082 }
1083
1084 #if !TARGET_OS_SIMULATOR
1085
1086 int
proc_suppress(__unused pid_t pid,__unused uint64_t * generation)1087 proc_suppress(__unused pid_t pid, __unused uint64_t *generation)
1088 {
1089 return 0;
1090 }
1091
1092 #endif /* !TARGET_OS_SIMULATOR */
1093
1094 #endif /* !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
1095
1096 int
proc_set_no_smt(void)1097 proc_set_no_smt(void)
1098 {
1099 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_NO_SMT, 0, NULL, getpid(), (uint64_t)0) == -1) {
1100 return errno;
1101 }
1102 return 0;
1103 }
1104
1105 int
proc_setthread_no_smt(void)1106 proc_setthread_no_smt(void)
1107 {
1108 extern uint64_t __thread_selfid(void);
1109 if (__process_policy(PROC_POLICY_SCOPE_THREAD, PROC_POLICY_ACTION_APPLY, PROC_POLICY_NO_SMT, 0, NULL, 0, __thread_selfid()) == -1) {
1110 return errno;
1111 }
1112 return 0;
1113 }
1114
1115 int
proc_set_csm(uint32_t flags)1116 proc_set_csm(uint32_t flags)
1117 {
1118 const uint32_t mask = PROC_CSM_ALL | PROC_CSM_TECS | PROC_CSM_NOSMT;
1119 if ((flags & ~mask) != 0) {
1120 return EINVAL;
1121 }
1122
1123 if (flags & (PROC_CSM_NOSMT | PROC_CSM_ALL)) {
1124 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_NO_SMT, 0, NULL, getpid(), (uint64_t)0) == -1) {
1125 return errno;
1126 }
1127 }
1128
1129 if (flags & (PROC_CSM_TECS | PROC_CSM_ALL)) {
1130 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_TECS, 0, NULL, getpid(), (uint64_t)0) == -1) {
1131 return errno;
1132 }
1133 }
1134
1135 return 0;
1136 }
1137
1138 int
proc_setthread_csm(uint32_t flags)1139 proc_setthread_csm(uint32_t flags)
1140 {
1141 extern uint64_t __thread_selfid(void);
1142 const uint32_t mask = PROC_CSM_ALL | PROC_CSM_TECS | PROC_CSM_NOSMT;
1143 if ((flags & ~mask) != 0) {
1144 return EINVAL;
1145 }
1146
1147 if (flags & (PROC_CSM_NOSMT | PROC_CSM_ALL)) {
1148 if (__process_policy(PROC_POLICY_SCOPE_THREAD, PROC_POLICY_ACTION_APPLY, PROC_POLICY_NO_SMT, 0, NULL, 0, __thread_selfid()) == -1) {
1149 return errno;
1150 }
1151 }
1152
1153 if (flags & (PROC_CSM_TECS | PROC_CSM_ALL)) {
1154 if (__process_policy(PROC_POLICY_SCOPE_THREAD, PROC_POLICY_ACTION_APPLY, PROC_POLICY_TECS, 0, NULL, 0, __thread_selfid()) == -1) {
1155 return errno;
1156 }
1157 }
1158
1159 return 0;
1160 }
1161