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 int
proc_name(int pid,void * buffer,uint32_t buffersize)202 proc_name(int pid, void * buffer, uint32_t buffersize)
203 {
204 int retval = 0, len;
205 struct proc_bsdinfo pbsd;
206
207
208 if (buffersize < sizeof(pbsd.pbi_name)) {
209 errno = ENOMEM;
210 return 0;
211 }
212
213 retval = proc_pidinfo(pid, PROC_PIDTBSDINFO, (uint64_t)0, &pbsd, sizeof(struct proc_bsdinfo));
214 if (retval != 0) {
215 if (pbsd.pbi_name[0]) {
216 bcopy(&pbsd.pbi_name, buffer, sizeof(pbsd.pbi_name));
217 } else {
218 bcopy(&pbsd.pbi_comm, buffer, sizeof(pbsd.pbi_comm));
219 }
220 len = (int)strlen(buffer);
221 return len;
222 }
223 return 0;
224 }
225
226 int
proc_regionfilename(int pid,uint64_t address,void * buffer,uint32_t buffersize)227 proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersize)
228 {
229 int retval;
230 struct proc_regionpath path;
231
232 if (buffersize < MAXPATHLEN) {
233 errno = ENOMEM;
234 return 0;
235 }
236
237 retval = proc_pidinfo(pid, PROC_PIDREGIONPATH, (uint64_t)address, &path, sizeof(struct proc_regionpath));
238 if (retval != 0) {
239 return (int)(strlcpy(buffer, path.prpo_path, buffersize));
240 }
241 return 0;
242 }
243
244 int
proc_kmsgbuf(void * buffer,uint32_t buffersize)245 proc_kmsgbuf(void * buffer, uint32_t buffersize)
246 {
247 int retval;
248
249 if ((retval = __proc_info(PROC_INFO_CALL_KERNMSGBUF, 0, 0, (uint64_t)0, buffer, buffersize)) == -1) {
250 return 0;
251 }
252 return retval;
253 }
254
255 int
proc_pidpath(int pid,void * buffer,uint32_t buffersize)256 proc_pidpath(int pid, void * buffer, uint32_t buffersize)
257 {
258 int retval, len;
259
260 if (buffersize < PROC_PIDPATHINFO_SIZE) {
261 errno = ENOMEM;
262 return 0;
263 }
264 if (buffersize > PROC_PIDPATHINFO_MAXSIZE) {
265 errno = EOVERFLOW;
266 return 0;
267 }
268
269 retval = __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDPATHINFO, (uint64_t)0, buffer, buffersize);
270 if (retval != -1) {
271 len = (int)strlen(buffer);
272 return len;
273 }
274 return 0;
275 }
276
277 int
proc_pidpath_audittoken(audit_token_t * audittoken,void * buffer,uint32_t buffersize)278 proc_pidpath_audittoken(audit_token_t *audittoken, void * buffer, uint32_t buffersize)
279 {
280 int retval, len;
281
282 if (buffersize < PROC_PIDPATHINFO_SIZE) {
283 errno = ENOMEM;
284 return 0;
285 }
286 if (buffersize > PROC_PIDPATHINFO_MAXSIZE) {
287 errno = EOVERFLOW;
288 return 0;
289 }
290
291 int pid = audittoken->val[5];
292 int idversion = audittoken->val[7];
293
294 retval = __proc_info_extended_id(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDPATHINFO, PIF_COMPARE_IDVERSION, (uint64_t)idversion,
295 (uint64_t)0, buffer, buffersize);
296 if (retval != -1) {
297 len = (int)strlen(buffer);
298 return len;
299 }
300 return 0;
301 }
302
303 int
proc_current_thread_schedinfo(void * buffer,size_t buffersize)304 proc_current_thread_schedinfo(void *buffer, size_t buffersize)
305 {
306 extern uint64_t __thread_selfid(void);
307
308 int retval;
309
310 if (buffersize < PROC_PIDTHREADSCHEDINFO_SIZE) {
311 errno = ENOMEM;
312 return errno;
313 }
314 if (buffersize > PROC_PIDTHREADSCHEDINFO_SIZE) {
315 errno = EOVERFLOW;
316 return errno;
317 }
318
319 pid_t pid = getpid();
320 uint64_t threadid = __thread_selfid();
321
322 retval = __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDTHREADSCHEDINFO, threadid, buffer, buffersize);
323
324 if (retval == -1) {
325 return errno;
326 }
327 return 0;
328 }
329
330 int
proc_libversion(int * major,int * minor)331 proc_libversion(int *major, int * minor)
332 {
333 if (major != NULL) {
334 *major = 1;
335 }
336 if (minor != NULL) {
337 *minor = 1;
338 }
339 return 0;
340 }
341
342 int
proc_setpcontrol(const int control)343 proc_setpcontrol(const int control)
344 {
345 int retval;
346
347 if (control < PROC_SETPC_NONE || control > PROC_SETPC_TERMINATE) {
348 return EINVAL;
349 }
350
351 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_PCONTROL, (uint64_t)control, NULL, 0)) == -1) {
352 return errno;
353 }
354
355 return 0;
356 }
357
358
359 __private_extern__ int
proc_setthreadname(void * buffer,int buffersize)360 proc_setthreadname(void * buffer, int buffersize)
361 {
362 int retval;
363
364 retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_THREADNAME, (uint64_t)0, buffer, buffersize);
365
366 if (retval == -1) {
367 return errno;
368 } else {
369 return 0;
370 }
371 }
372
373 int
proc_track_dirty(pid_t pid,uint32_t flags)374 proc_track_dirty(pid_t pid, uint32_t flags)
375 {
376 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_TRACK, flags, NULL, 0) == -1) {
377 return errno;
378 }
379
380 return 0;
381 }
382
383 int
proc_set_dirty(pid_t pid,bool dirty)384 proc_set_dirty(pid_t pid, bool dirty)
385 {
386 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_SET, dirty, NULL, 0) == -1) {
387 return errno;
388 }
389
390 return 0;
391 }
392
393 int
proc_get_dirty(pid_t pid,uint32_t * flags)394 proc_get_dirty(pid_t pid, uint32_t *flags)
395 {
396 int retval;
397
398 if (!flags) {
399 return EINVAL;
400 }
401
402 retval = __proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_GET, 0, NULL, 0);
403 if (retval == -1) {
404 return errno;
405 }
406
407 *flags = retval;
408
409 return 0;
410 }
411
412 int
proc_clear_dirty(pid_t pid,uint32_t flags)413 proc_clear_dirty(pid_t pid, uint32_t flags)
414 {
415 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_CLEAR, flags, NULL, 0) == -1) {
416 return errno;
417 }
418
419 return 0;
420 }
421
422 int
proc_terminate(pid_t pid,int * sig)423 proc_terminate(pid_t pid, int *sig)
424 {
425 int retval;
426
427 if (!sig) {
428 return EINVAL;
429 }
430
431 retval = __proc_info(PROC_INFO_CALL_TERMINATE, pid, 0, 0, NULL, 0);
432 if (retval == -1) {
433 return errno;
434 }
435
436 *sig = retval;
437
438 return 0;
439 }
440
441 /*
442 * XXX the _fatal() variant both checks for an existing monitor
443 * (with important policy effects on first party background apps)
444 * and validates inputs.
445 */
446 int
proc_set_cpumon_params(pid_t pid,int percentage,int interval)447 proc_set_cpumon_params(pid_t pid, int percentage, int interval)
448 {
449 proc_policy_cpuusage_attr_t attr;
450
451 /* no argument validation ...
452 * task_set_cpuusage() ignores 0 values and squashes negative
453 * values into uint32_t.
454 */
455
456 attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
457 attr.ppattr_cpu_percentage = percentage;
458 attr.ppattr_cpu_attr_interval = (uint64_t)interval;
459 attr.ppattr_cpu_attr_deadline = 0;
460
461 return __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
462 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
463 }
464
465 int
proc_get_cpumon_params(pid_t pid,int * percentage,int * interval)466 proc_get_cpumon_params(pid_t pid, int *percentage, int *interval)
467 {
468 proc_policy_cpuusage_attr_t attr;
469 int ret;
470
471 ret = __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_GET, PROC_POLICY_RESOURCE_USAGE,
472 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
473
474 if ((ret == 0) && (attr.ppattr_cpu_attr == PROC_POLICY_RSRCACT_NOTIFY_EXC)) {
475 *percentage = attr.ppattr_cpu_percentage;
476 *interval = (int)attr.ppattr_cpu_attr_interval;
477 } else {
478 *percentage = 0;
479 *interval = 0;
480 }
481
482 return ret;
483 }
484
485 int
proc_set_cpumon_defaults(pid_t pid)486 proc_set_cpumon_defaults(pid_t pid)
487 {
488 proc_policy_cpuusage_attr_t attr;
489
490 attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
491 attr.ppattr_cpu_percentage = PROC_POLICY_CPUMON_DEFAULTS;
492 attr.ppattr_cpu_attr_interval = 0;
493 attr.ppattr_cpu_attr_deadline = 0;
494
495 return __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
496 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
497 }
498
499 int
proc_resume_cpumon(pid_t pid)500 proc_resume_cpumon(pid_t pid)
501 {
502 return __process_policy(PROC_POLICY_SCOPE_PROCESS,
503 PROC_POLICY_ACTION_ENABLE,
504 PROC_POLICY_RESOURCE_USAGE,
505 PROC_POLICY_RUSAGE_CPU,
506 NULL, pid, 0);
507 }
508
509 int
proc_disable_cpumon(pid_t pid)510 proc_disable_cpumon(pid_t pid)
511 {
512 proc_policy_cpuusage_attr_t attr;
513
514 attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
515 attr.ppattr_cpu_percentage = PROC_POLICY_CPUMON_DISABLE;
516 attr.ppattr_cpu_attr_interval = 0;
517 attr.ppattr_cpu_attr_deadline = 0;
518
519 return __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
520 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
521 }
522
523
524 /*
525 * Turn on the CPU usage monitor using the supplied parameters, and make
526 * violations of the monitor fatal.
527 *
528 * Returns: 0 on success;
529 * -1 on failure and sets errno
530 */
531 int
proc_set_cpumon_params_fatal(pid_t pid,int percentage,int interval)532 proc_set_cpumon_params_fatal(pid_t pid, int percentage, int interval)
533 {
534 int current_percentage = 0;
535 int current_interval = 0; /* intervals are in seconds */
536 int ret = 0;
537
538 if ((percentage <= 0) || (interval <= 0)) {
539 errno = EINVAL;
540 return -1;
541 }
542
543 /*
544 * Do a simple query to see if CPU monitoring is
545 * already active. If either the percentage or the
546 * interval is nonzero, then CPU monitoring is
547 * already in use for this process.
548 *
549 * XXX: need set...() and set..fatal() to behave similarly.
550 * Currently, this check prevents 1st party apps (which get a
551 * default non-fatal monitor) not to get a fatal monitor.
552 */
553 (void)proc_get_cpumon_params(pid, ¤t_percentage, ¤t_interval);
554 if (current_percentage || current_interval) {
555 /*
556 * The CPU monitor appears to be active.
557 * We choose not to disturb those settings.
558 */
559 errno = EBUSY;
560 return -1;
561 }
562
563 if ((ret = proc_set_cpumon_params(pid, percentage, interval)) != 0) {
564 /* Failed to activate the CPU monitor */
565 return ret;
566 }
567
568 if ((ret = proc_rlimit_control(pid, RLIMIT_CPU_USAGE_MONITOR, (void *)(uintptr_t)CPUMON_MAKE_FATAL)) != 0) {
569 /* Failed to set termination, back out the CPU monitor settings. */
570 (void)proc_disable_cpumon(pid);
571 }
572
573 return ret;
574 }
575
576 int
proc_set_wakemon_params(pid_t pid,int rate_hz,int flags __unused)577 proc_set_wakemon_params(pid_t pid, int rate_hz, int flags __unused)
578 {
579 struct proc_rlimit_control_wakeupmon params;
580
581 params.wm_flags = WAKEMON_ENABLE;
582 params.wm_rate = rate_hz;
583
584 return proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, ¶ms);
585 }
586
587 #ifndef WAKEMON_GET_PARAMS
588 #define WAKEMON_GET_PARAMS 0x4
589 #define WAKEMON_SET_DEFAULTS 0x8
590 #endif
591
592 int
proc_get_wakemon_params(pid_t pid,int * rate_hz,int * flags)593 proc_get_wakemon_params(pid_t pid, int *rate_hz, int *flags)
594 {
595 struct proc_rlimit_control_wakeupmon params;
596 int error;
597
598 params.wm_flags = WAKEMON_GET_PARAMS;
599
600 if ((error = proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, ¶ms)) != 0) {
601 return error;
602 }
603
604 *rate_hz = params.wm_rate;
605 *flags = params.wm_flags;
606
607 return 0;
608 }
609
610 int
proc_set_wakemon_defaults(pid_t pid)611 proc_set_wakemon_defaults(pid_t pid)
612 {
613 struct proc_rlimit_control_wakeupmon params;
614
615 params.wm_flags = WAKEMON_ENABLE | WAKEMON_SET_DEFAULTS;
616 params.wm_rate = -1;
617
618 return proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, ¶ms);
619 }
620
621 int
proc_disable_wakemon(pid_t pid)622 proc_disable_wakemon(pid_t pid)
623 {
624 struct proc_rlimit_control_wakeupmon params;
625
626 params.wm_flags = WAKEMON_DISABLE;
627 params.wm_rate = -1;
628
629 return proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, ¶ms);
630 }
631
632 int
proc_list_uptrs(int pid,uint64_t * buf,uint32_t bufsz)633 proc_list_uptrs(int pid, uint64_t *buf, uint32_t bufsz)
634 {
635 return __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDLISTUPTRS, 0,
636 buf, bufsz);
637 }
638
639 int
proc_list_dynkqueueids(int pid,kqueue_id_t * buf,uint32_t bufsz)640 proc_list_dynkqueueids(int pid, kqueue_id_t *buf, uint32_t bufsz)
641 {
642 return __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDLISTDYNKQUEUES, 0,
643 buf, bufsz);
644 }
645
646
647 int
proc_setcpu_percentage(pid_t pid,int action,int percentage)648 proc_setcpu_percentage(pid_t pid, int action, int percentage)
649 {
650 proc_policy_cpuusage_attr_t attr;
651
652 bzero(&attr, sizeof(proc_policy_cpuusage_attr_t));
653 attr.ppattr_cpu_attr = action;
654 attr.ppattr_cpu_percentage = percentage;
655 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) {
656 return 0;
657 } else {
658 return errno;
659 }
660 }
661
662 int
proc_reset_footprint_interval(pid_t pid)663 proc_reset_footprint_interval(pid_t pid)
664 {
665 return proc_rlimit_control(pid, RLIMIT_FOOTPRINT_INTERVAL, (void *)(uintptr_t)FOOTPRINT_INTERVAL_RESET);
666 }
667
668 int
proc_clear_cpulimits(pid_t pid)669 proc_clear_cpulimits(pid_t pid)
670 {
671 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) {
672 return 0;
673 } else {
674 return errno;
675 }
676 }
677
678 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
679
680 int
proc_setcpu_deadline(pid_t pid,int action,uint64_t deadline)681 proc_setcpu_deadline(pid_t pid, int action, uint64_t deadline)
682 {
683 proc_policy_cpuusage_attr_t attr;
684
685 bzero(&attr, sizeof(proc_policy_cpuusage_attr_t));
686 attr.ppattr_cpu_attr = action;
687 attr.ppattr_cpu_attr_deadline = deadline;
688 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) {
689 return 0;
690 } else {
691 return errno;
692 }
693 }
694
695 int
proc_setcpu_percentage_withdeadline(pid_t pid,int action,int percentage,uint64_t deadline)696 proc_setcpu_percentage_withdeadline(pid_t pid, int action, int percentage, uint64_t deadline)
697 {
698 proc_policy_cpuusage_attr_t attr;
699
700 bzero(&attr, sizeof(proc_policy_cpuusage_attr_t));
701 attr.ppattr_cpu_attr = action;
702 attr.ppattr_cpu_percentage = percentage;
703 attr.ppattr_cpu_attr_deadline = deadline;
704 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) {
705 return 0;
706 } else {
707 return errno;
708 }
709 }
710
711 int
proc_appstate(int pid,int * appstatep)712 proc_appstate(int pid, int * appstatep)
713 {
714 int state;
715
716 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) {
717 if (appstatep != NULL) {
718 *appstatep = state;
719 }
720 return 0;
721 } else {
722 return errno;
723 }
724 }
725
726 int
proc_setappstate(int pid,int appstate)727 proc_setappstate(int pid, int appstate)
728 {
729 int state = appstate;
730
731 switch (state) {
732 case PROC_APPSTATE_NONE:
733 case PROC_APPSTATE_ACTIVE:
734 case PROC_APPSTATE_INACTIVE:
735 case PROC_APPSTATE_BACKGROUND:
736 case PROC_APPSTATE_NONUI:
737 break;
738 default:
739 return EINVAL;
740 }
741 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) {
742 return 0;
743 } else {
744 return errno;
745 }
746 }
747
748 int
proc_devstatusnotify(int devicestatus)749 proc_devstatusnotify(int devicestatus)
750 {
751 int state = devicestatus;
752
753 switch (devicestatus) {
754 case PROC_DEVSTATUS_SHORTTERM:
755 case PROC_DEVSTATUS_LONGTERM:
756 break;
757 default:
758 return EINVAL;
759 }
760
761 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) {
762 return 0;
763 } else {
764 return errno;
765 }
766 }
767
768 int
proc_pidbind(int pid,uint64_t threadid,int bind)769 proc_pidbind(int pid, uint64_t threadid, int bind)
770 {
771 int state = bind;
772 pid_t passpid = pid;
773
774 switch (bind) {
775 case PROC_PIDBIND_CLEAR:
776 passpid = getpid(); /* ignore pid on clear */
777 break;
778 case PROC_PIDBIND_SET:
779 break;
780 default:
781 return EINVAL;
782 }
783 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) {
784 return 0;
785 } else {
786 return errno;
787 }
788 }
789
790 int
proc_can_use_foreground_hw(int pid,uint32_t * reason)791 proc_can_use_foreground_hw(int pid, uint32_t *reason)
792 {
793 return __proc_info(PROC_INFO_CALL_CANUSEFGHW, pid, 0, 0, reason, sizeof(*reason));
794 }
795 #endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
796
797
798 /* Donate importance to adaptive processes from this process */
799 int
proc_donate_importance_boost()800 proc_donate_importance_boost()
801 {
802 int rval;
803
804 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
805 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
806 PROC_POLICY_ACTION_ENABLE,
807 PROC_POLICY_APPTYPE,
808 PROC_POLICY_IOS_DONATEIMP,
809 NULL, getpid(), (uint64_t)0);
810 #else /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
811 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
812 PROC_POLICY_ACTION_SET,
813 PROC_POLICY_BOOST,
814 PROC_POLICY_IMP_DONATION,
815 NULL, getpid(), 0);
816 #endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
817
818 if (rval == 0) {
819 return 0;
820 } else {
821 return errno;
822 }
823 }
824
825 static __attribute__((noinline)) void
proc_importance_bad_assertion(char * reason)826 proc_importance_bad_assertion(char *reason)
827 {
828 (void)reason;
829 }
830
831 /*
832 * Use the address of these variables as the token. This way, they can be
833 * printed in the debugger as useful names.
834 */
835 uint64_t important_boost_assertion_token = 0xfafafafafafafafa;
836 uint64_t normal_boost_assertion_token = 0xfbfbfbfbfbfbfbfb;
837 uint64_t non_boost_assertion_token = 0xfcfcfcfcfcfcfcfc;
838 uint64_t denap_boost_assertion_token = 0xfdfdfdfdfdfdfdfd;
839
840 /*
841 * Accept the boost on a message, or request another boost assertion
842 * if we have already accepted the implicit boost for this message.
843 *
844 * Returns EOVERFLOW if an attempt is made to take an extra assertion when not boosted.
845 *
846 * Returns EIO if the message was not a boosting message.
847 * TODO: Return a 'non-boost' token instead.
848 */
849 int
proc_importance_assertion_begin_with_msg(mach_msg_header_t * msg,__unused mach_msg_trailer_t * trailer,uint64_t * assertion_token)850 proc_importance_assertion_begin_with_msg(mach_msg_header_t *msg,
851 __unused mach_msg_trailer_t *trailer,
852 uint64_t *assertion_token)
853 {
854 int rval = 0;
855
856 if (assertion_token == NULL) {
857 return EINVAL;
858 }
859
860 #define LEGACYBOOSTMASK (MACH_MSGH_BITS_VOUCHER_MASK | MACH_MSGH_BITS_RAISEIMP)
861 #define LEGACYBOOSTED(m) (((m)->msgh_bits & LEGACYBOOSTMASK) == MACH_MSGH_BITS_RAISEIMP)
862
863 /* Is this a legacy boosted message? */
864 if (LEGACYBOOSTED(msg)) {
865 /*
866 * Have we accepted the implicit boost for this message yet?
867 * If we haven't accepted it yet, no need to call into kernel.
868 */
869 if ((msg->msgh_bits & MACH_MSGH_BITS_IMPHOLDASRT) == 0) {
870 msg->msgh_bits |= MACH_MSGH_BITS_IMPHOLDASRT;
871 *assertion_token = (uint64_t) &important_boost_assertion_token;
872 return 0;
873 }
874
875 /* Request an additional boost count */
876 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
877 PROC_POLICY_ACTION_HOLD,
878 PROC_POLICY_BOOST,
879 PROC_POLICY_IMP_IMPORTANT,
880 NULL, getpid(), 0);
881 if (rval == 0) {
882 *assertion_token = (uint64_t) &important_boost_assertion_token;
883 return 0;
884 } else if (errno == EOVERFLOW) {
885 proc_importance_bad_assertion("Attempted to take assertion while not boosted");
886 return errno;
887 } else {
888 return errno;
889 }
890 }
891
892 return EIO;
893 }
894
895
896 /*
897 * Drop a boost assertion.
898 * Returns EOVERFLOW on boost assertion underflow.
899 */
900 int
proc_importance_assertion_complete(uint64_t assertion_token)901 proc_importance_assertion_complete(uint64_t assertion_token)
902 {
903 int rval = 0;
904
905 if (assertion_token == 0) {
906 return 0;
907 }
908
909 if (assertion_token == (uint64_t) &important_boost_assertion_token) {
910 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
911 PROC_POLICY_ACTION_DROP,
912 PROC_POLICY_BOOST,
913 PROC_POLICY_IMP_IMPORTANT,
914 NULL, getpid(), 0);
915 if (rval == 0) {
916 return 0;
917 } else if (errno == EOVERFLOW) {
918 proc_importance_bad_assertion("Attempted to drop too many assertions");
919 return errno;
920 } else {
921 return errno;
922 }
923 } else {
924 proc_importance_bad_assertion("Attempted to drop assertion with invalid token");
925 return EIO;
926 }
927 }
928
929 /*
930 * Accept the De-Nap boost on a message, or request another boost assertion
931 * if we have already accepted the implicit boost for this message.
932 *
933 * Interface is deprecated before it really got started - just as synonym
934 * for proc_importance_assertion_begin_with_msg() now.
935 */
936 int
proc_denap_assertion_begin_with_msg(mach_msg_header_t * msg,uint64_t * assertion_token)937 proc_denap_assertion_begin_with_msg(mach_msg_header_t *msg,
938 uint64_t *assertion_token)
939 {
940 #pragma clang diagnostic push
941 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
942 return proc_importance_assertion_begin_with_msg(msg, NULL, assertion_token);
943 #pragma clang diagnostic pop
944 }
945
946
947 /*
948 * Drop a denap boost assertion.
949 *
950 * Interface is deprecated before it really got started - just a synonym
951 * for proc_importance_assertion_complete() now.
952 */
953 int
proc_denap_assertion_complete(uint64_t assertion_token)954 proc_denap_assertion_complete(uint64_t assertion_token)
955 {
956 return proc_importance_assertion_complete(assertion_token);
957 }
958
959 #if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
960
961 int
proc_clear_vmpressure(pid_t pid)962 proc_clear_vmpressure(pid_t pid)
963 {
964 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) {
965 return 0;
966 } else {
967 return errno;
968 }
969 }
970
971 /* set the current process as one who can resume suspended processes due to low virtual memory. Need to be root */
972 int
proc_set_owner_vmpressure(void)973 proc_set_owner_vmpressure(void)
974 {
975 int retval;
976
977 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_VMRSRCOWNER, (uint64_t)0, NULL, 0)) == -1) {
978 return errno;
979 }
980
981 return 0;
982 }
983
984 /* mark yourself to delay idle sleep on disk IO */
985 int
proc_set_delayidlesleep(void)986 proc_set_delayidlesleep(void)
987 {
988 int retval;
989
990 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_DELAYIDLESLEEP, (uint64_t)1, NULL, 0)) == -1) {
991 return errno;
992 }
993
994 return 0;
995 }
996
997 /* Reset yourself to delay idle sleep on disk IO, if already set */
998 int
proc_clear_delayidlesleep(void)999 proc_clear_delayidlesleep(void)
1000 {
1001 int retval;
1002
1003 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_DELAYIDLESLEEP, (uint64_t)0, NULL, 0)) == -1) {
1004 return errno;
1005 }
1006
1007 return 0;
1008 }
1009
1010 /* disable the launch time backgroudn policy and restore the process to default group */
1011 int
proc_disable_apptype(pid_t pid,int apptype)1012 proc_disable_apptype(pid_t pid, int apptype)
1013 {
1014 switch (apptype) {
1015 case PROC_POLICY_OSX_APPTYPE_TAL:
1016 case PROC_POLICY_OSX_APPTYPE_DASHCLIENT:
1017 break;
1018 default:
1019 return EINVAL;
1020 }
1021
1022 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_DISABLE, PROC_POLICY_APPTYPE, apptype, NULL, pid, (uint64_t)0) != -1) {
1023 return 0;
1024 } else {
1025 return errno;
1026 }
1027 }
1028
1029 /* re-enable the launch time background policy if it had been disabled. */
1030 int
proc_enable_apptype(pid_t pid,int apptype)1031 proc_enable_apptype(pid_t pid, int apptype)
1032 {
1033 switch (apptype) {
1034 case PROC_POLICY_OSX_APPTYPE_TAL:
1035 case PROC_POLICY_OSX_APPTYPE_DASHCLIENT:
1036 break;
1037 default:
1038 return EINVAL;
1039 }
1040
1041 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_ENABLE, PROC_POLICY_APPTYPE, apptype, NULL, pid, (uint64_t)0) != -1) {
1042 return 0;
1043 } else {
1044 return errno;
1045 }
1046 }
1047
1048 #if !TARGET_OS_SIMULATOR
1049
1050 int
proc_suppress(__unused pid_t pid,__unused uint64_t * generation)1051 proc_suppress(__unused pid_t pid, __unused uint64_t *generation)
1052 {
1053 return 0;
1054 }
1055
1056 #endif /* !TARGET_OS_SIMULATOR */
1057
1058 #endif /* !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
1059
1060 int
proc_set_no_smt(void)1061 proc_set_no_smt(void)
1062 {
1063 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_NO_SMT, 0, NULL, getpid(), (uint64_t)0) == -1) {
1064 return errno;
1065 }
1066 return 0;
1067 }
1068
1069 int
proc_setthread_no_smt(void)1070 proc_setthread_no_smt(void)
1071 {
1072 extern uint64_t __thread_selfid(void);
1073 if (__process_policy(PROC_POLICY_SCOPE_THREAD, PROC_POLICY_ACTION_APPLY, PROC_POLICY_NO_SMT, 0, NULL, 0, __thread_selfid()) == -1) {
1074 return errno;
1075 }
1076 return 0;
1077 }
1078
1079 int
proc_set_csm(uint32_t flags)1080 proc_set_csm(uint32_t flags)
1081 {
1082 const uint32_t mask = PROC_CSM_ALL | PROC_CSM_TECS | PROC_CSM_NOSMT;
1083 if ((flags & ~mask) != 0) {
1084 return EINVAL;
1085 }
1086
1087 if (flags & (PROC_CSM_NOSMT | PROC_CSM_ALL)) {
1088 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_NO_SMT, 0, NULL, getpid(), (uint64_t)0) == -1) {
1089 return errno;
1090 }
1091 }
1092
1093 if (flags & (PROC_CSM_TECS | PROC_CSM_ALL)) {
1094 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_APPLY, PROC_POLICY_TECS, 0, NULL, getpid(), (uint64_t)0) == -1) {
1095 return errno;
1096 }
1097 }
1098
1099 return 0;
1100 }
1101
1102 int
proc_setthread_csm(uint32_t flags)1103 proc_setthread_csm(uint32_t flags)
1104 {
1105 extern uint64_t __thread_selfid(void);
1106 const uint32_t mask = PROC_CSM_ALL | PROC_CSM_TECS | PROC_CSM_NOSMT;
1107 if ((flags & ~mask) != 0) {
1108 return EINVAL;
1109 }
1110
1111 if (flags & (PROC_CSM_NOSMT | PROC_CSM_ALL)) {
1112 if (__process_policy(PROC_POLICY_SCOPE_THREAD, PROC_POLICY_ACTION_APPLY, PROC_POLICY_NO_SMT, 0, NULL, 0, __thread_selfid()) == -1) {
1113 return errno;
1114 }
1115 }
1116
1117 if (flags & (PROC_CSM_TECS | PROC_CSM_ALL)) {
1118 if (__process_policy(PROC_POLICY_SCOPE_THREAD, PROC_POLICY_ACTION_APPLY, PROC_POLICY_TECS, 0, NULL, 0, __thread_selfid()) == -1) {
1119 return errno;
1120 }
1121 }
1122
1123 return 0;
1124 }
1125