]> git.saurik.com Git - apple/xnu.git/blob - libsyscall/wrappers/libproc/libproc.c
xnu-4903.270.47.tar.gz
[apple/xnu.git] / libsyscall / wrappers / libproc / libproc.c
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 __private_extern__ int proc_setthreadname(void * buffer, int buffersize);
41 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);
42 int proc_rlimit_control(pid_t pid, int flavor, void *arg);
43
44 int
45 proc_listpids(uint32_t type, uint32_t typeinfo, void *buffer, int buffersize)
46 {
47 int retval;
48
49 if ((type >= PROC_ALL_PIDS) || (type <= PROC_PPID_ONLY)) {
50 if ((retval = __proc_info(PROC_INFO_CALL_LISTPIDS, type, typeinfo, (uint64_t)0, buffer, buffersize)) == -1) {
51 return 0;
52 }
53 } else {
54 errno = EINVAL;
55 retval = 0;
56 }
57 return retval;
58 }
59
60
61 int
62 proc_listallpids(void * buffer, int buffersize)
63 {
64 int numpids;
65 numpids = proc_listpids(PROC_ALL_PIDS, (uint32_t)0, buffer, buffersize);
66
67 if (numpids == -1) {
68 return -1;
69 } else {
70 return numpids / sizeof(int);
71 }
72 }
73
74 int
75 proc_listpgrppids(pid_t pgrpid, void * buffer, int buffersize)
76 {
77 int numpids;
78 numpids = proc_listpids(PROC_PGRP_ONLY, (uint32_t)pgrpid, buffer, buffersize);
79 if (numpids == -1) {
80 return -1;
81 } else {
82 return numpids / sizeof(int);
83 }
84 }
85
86 int
87 proc_listchildpids(pid_t ppid, void * buffer, int buffersize)
88 {
89 int numpids;
90 numpids = proc_listpids(PROC_PPID_ONLY, (uint32_t)ppid, buffer, buffersize);
91 if (numpids == -1) {
92 return -1;
93 } else {
94 return numpids / sizeof(int);
95 }
96 }
97
98
99 int
100 proc_pidinfo(int pid, int flavor, uint64_t arg, void *buffer, int buffersize)
101 {
102 int retval;
103
104 if ((retval = __proc_info(PROC_INFO_CALL_PIDINFO, pid, flavor, arg, buffer, buffersize)) == -1) {
105 return 0;
106 }
107
108 return retval;
109 }
110
111
112 int
113 proc_pidoriginatorinfo(int flavor, void *buffer, int buffersize)
114 {
115 int retval;
116
117 if ((retval = __proc_info(PROC_INFO_CALL_PIDORIGINATORINFO, getpid(), flavor, 0, buffer, buffersize)) == -1) {
118 return 0;
119 }
120
121 return retval;
122 }
123
124 int
125 proc_listcoalitions(int flavor, int coaltype, void *buffer, int buffersize)
126 {
127 int retval;
128
129 if ((retval = __proc_info(PROC_INFO_CALL_LISTCOALITIONS, flavor, coaltype, 0, buffer, buffersize)) == -1) {
130 return 0;
131 }
132
133 return retval;
134 }
135
136 int
137 proc_pid_rusage(int pid, int flavor, rusage_info_t *buffer)
138 {
139 return __proc_info(PROC_INFO_CALL_PIDRUSAGE, pid, flavor, 0, buffer, 0);
140 }
141
142 int
143 proc_setthread_cpupercent(uint8_t percentage, uint32_t ms_refill)
144 {
145 uint32_t arg = 0;
146
147 /* Pack percentage and refill into a 32-bit number to match existing kernel implementation */
148 if ((percentage >= 100) || (ms_refill & ~0xffffffU)) {
149 errno = EINVAL;
150 return -1;
151 }
152
153 arg = ((ms_refill << 8) | percentage);
154
155 return proc_rlimit_control(-1, RLIMIT_THREAD_CPULIMITS, (void *)(uintptr_t)arg);
156 }
157
158 int
159 proc_pidfdinfo(int pid, int fd, int flavor, void * buffer, int buffersize)
160 {
161 int retval;
162
163 if ((retval = __proc_info(PROC_INFO_CALL_PIDFDINFO, pid, flavor, (uint64_t)fd, buffer, buffersize)) == -1) {
164 return 0;
165 }
166
167 return retval;
168 }
169
170
171 int
172 proc_pidfileportinfo(int pid, uint32_t fileport, int flavor, void *buffer, int buffersize)
173 {
174 int retval;
175
176 if ((retval = __proc_info(PROC_INFO_CALL_PIDFILEPORTINFO, pid, flavor, (uint64_t)fileport, buffer, buffersize)) == -1) {
177 return 0;
178 }
179 return retval;
180 }
181
182 int
183 proc_piddynkqueueinfo(int pid, int flavor, kqueue_id_t kq_id, void *buffer, int buffersize)
184 {
185 int ret;
186
187 if ((ret = __proc_info(PROC_INFO_CALL_PIDDYNKQUEUEINFO, pid, flavor, (uint64_t)kq_id, buffer, buffersize)) == -1) {
188 return 0;
189 }
190
191 return ret;
192 }
193
194 int
195 proc_udata_info(int pid, int flavor, void *buffer, int buffersize)
196 {
197 return __proc_info(PROC_INFO_CALL_UDATA_INFO, pid, flavor, 0, buffer, buffersize);
198 }
199
200 int
201 proc_name(int pid, void * buffer, uint32_t buffersize)
202 {
203 int retval = 0, len;
204 struct proc_bsdinfo pbsd;
205
206
207 if (buffersize < sizeof(pbsd.pbi_name)) {
208 errno = ENOMEM;
209 return 0;
210 }
211
212 retval = proc_pidinfo(pid, PROC_PIDTBSDINFO, (uint64_t)0, &pbsd, sizeof(struct proc_bsdinfo));
213 if (retval != 0) {
214 if (pbsd.pbi_name[0]) {
215 bcopy(&pbsd.pbi_name, buffer, sizeof(pbsd.pbi_name));
216 } else {
217 bcopy(&pbsd.pbi_comm, buffer, sizeof(pbsd.pbi_comm));
218 }
219 len = (int)strlen(buffer);
220 return len;
221 }
222 return 0;
223 }
224
225 int
226 proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersize)
227 {
228 int retval;
229 struct proc_regionwithpathinfo reginfo;
230
231 if (buffersize < MAXPATHLEN) {
232 errno = ENOMEM;
233 return 0;
234 }
235
236 retval = proc_pidinfo(pid, PROC_PIDREGIONPATHINFO2, (uint64_t)address, &reginfo, sizeof(struct proc_regionwithpathinfo));
237 if (retval != -1) {
238 return (int)(strlcpy(buffer, reginfo.prp_vip.vip_path, MAXPATHLEN));
239 }
240 return 0;
241 }
242
243 int
244 proc_kmsgbuf(void * buffer, uint32_t buffersize)
245 {
246 int retval;
247
248 if ((retval = __proc_info(PROC_INFO_CALL_KERNMSGBUF, 0, 0, (uint64_t)0, buffer, buffersize)) == -1) {
249 return 0;
250 }
251 return retval;
252 }
253
254 int
255 proc_pidpath(int pid, void * buffer, uint32_t buffersize)
256 {
257 int retval, len;
258
259 if (buffersize < PROC_PIDPATHINFO_SIZE) {
260 errno = ENOMEM;
261 return 0;
262 }
263 if (buffersize > PROC_PIDPATHINFO_MAXSIZE) {
264 errno = EOVERFLOW;
265 return 0;
266 }
267
268 retval = __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDPATHINFO, (uint64_t)0, buffer, buffersize);
269 if (retval != -1) {
270 len = (int)strlen(buffer);
271 return len;
272 }
273 return 0;
274 }
275
276
277 int
278 proc_libversion(int *major, int * minor)
279 {
280 if (major != NULL) {
281 *major = 1;
282 }
283 if (minor != NULL) {
284 *minor = 1;
285 }
286 return 0;
287 }
288
289 int
290 proc_setpcontrol(const int control)
291 {
292 int retval;
293
294 if (control < PROC_SETPC_NONE || control > PROC_SETPC_TERMINATE) {
295 return EINVAL;
296 }
297
298 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_PCONTROL, (uint64_t)control, NULL, 0)) == -1) {
299 return errno;
300 }
301
302 return 0;
303 }
304
305
306 __private_extern__ int
307 proc_setthreadname(void * buffer, int buffersize)
308 {
309 int retval;
310
311 retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_THREADNAME, (uint64_t)0, buffer, buffersize);
312
313 if (retval == -1) {
314 return errno;
315 } else {
316 return 0;
317 }
318 }
319
320 int
321 proc_track_dirty(pid_t pid, uint32_t flags)
322 {
323 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_TRACK, flags, NULL, 0) == -1) {
324 return errno;
325 }
326
327 return 0;
328 }
329
330 int
331 proc_set_dirty(pid_t pid, bool dirty)
332 {
333 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_SET, dirty, NULL, 0) == -1) {
334 return errno;
335 }
336
337 return 0;
338 }
339
340 int
341 proc_get_dirty(pid_t pid, uint32_t *flags)
342 {
343 int retval;
344
345 if (!flags) {
346 return EINVAL;
347 }
348
349 retval = __proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_GET, 0, NULL, 0);
350 if (retval == -1) {
351 return errno;
352 }
353
354 *flags = retval;
355
356 return 0;
357 }
358
359 int
360 proc_clear_dirty(pid_t pid, uint32_t flags)
361 {
362 if (__proc_info(PROC_INFO_CALL_DIRTYCONTROL, pid, PROC_DIRTYCONTROL_CLEAR, flags, NULL, 0) == -1) {
363 return errno;
364 }
365
366 return 0;
367 }
368
369 int
370 proc_terminate(pid_t pid, int *sig)
371 {
372 int retval;
373
374 if (!sig) {
375 return EINVAL;
376 }
377
378 retval = __proc_info(PROC_INFO_CALL_TERMINATE, pid, 0, 0, NULL, 0);
379 if (retval == -1) {
380 return errno;
381 }
382
383 *sig = retval;
384
385 return 0;
386 }
387
388 /*
389 * XXX the _fatal() variant both checks for an existing monitor
390 * (with important policy effects on first party background apps)
391 * and validates inputs.
392 */
393 int
394 proc_set_cpumon_params(pid_t pid, int percentage, int interval)
395 {
396 proc_policy_cpuusage_attr_t attr;
397
398 /* no argument validation ...
399 * task_set_cpuusage() ignores 0 values and squashes negative
400 * values into uint32_t.
401 */
402
403 attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
404 attr.ppattr_cpu_percentage = percentage;
405 attr.ppattr_cpu_attr_interval = (uint64_t)interval;
406 attr.ppattr_cpu_attr_deadline = 0;
407
408 return __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
409 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
410 }
411
412 int
413 proc_get_cpumon_params(pid_t pid, int *percentage, int *interval)
414 {
415 proc_policy_cpuusage_attr_t attr;
416 int ret;
417
418 ret = __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_GET, PROC_POLICY_RESOURCE_USAGE,
419 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
420
421 if ((ret == 0) && (attr.ppattr_cpu_attr == PROC_POLICY_RSRCACT_NOTIFY_EXC)) {
422 *percentage = attr.ppattr_cpu_percentage;
423 *interval = (int)attr.ppattr_cpu_attr_interval;
424 } else {
425 *percentage = 0;
426 *interval = 0;
427 }
428
429 return ret;
430 }
431
432 int
433 proc_set_cpumon_defaults(pid_t pid)
434 {
435 proc_policy_cpuusage_attr_t attr;
436
437 attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
438 attr.ppattr_cpu_percentage = PROC_POLICY_CPUMON_DEFAULTS;
439 attr.ppattr_cpu_attr_interval = 0;
440 attr.ppattr_cpu_attr_deadline = 0;
441
442 return __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
443 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
444 }
445
446 int
447 proc_resume_cpumon(pid_t pid)
448 {
449 return __process_policy(PROC_POLICY_SCOPE_PROCESS,
450 PROC_POLICY_ACTION_ENABLE,
451 PROC_POLICY_RESOURCE_USAGE,
452 PROC_POLICY_RUSAGE_CPU,
453 NULL, pid, 0);
454 }
455
456 int
457 proc_disable_cpumon(pid_t pid)
458 {
459 proc_policy_cpuusage_attr_t attr;
460
461 attr.ppattr_cpu_attr = PROC_POLICY_RSRCACT_NOTIFY_EXC;
462 attr.ppattr_cpu_percentage = PROC_POLICY_CPUMON_DISABLE;
463 attr.ppattr_cpu_attr_interval = 0;
464 attr.ppattr_cpu_attr_deadline = 0;
465
466 return __process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_SET, PROC_POLICY_RESOURCE_USAGE,
467 PROC_POLICY_RUSAGE_CPU, (proc_policy_attribute_t*)&attr, pid, 0);
468 }
469
470
471 /*
472 * Turn on the CPU usage monitor using the supplied parameters, and make
473 * violations of the monitor fatal.
474 *
475 * Returns: 0 on success;
476 * -1 on failure and sets errno
477 */
478 int
479 proc_set_cpumon_params_fatal(pid_t pid, int percentage, int interval)
480 {
481 int current_percentage = 0;
482 int current_interval = 0; /* intervals are in seconds */
483 int ret = 0;
484
485 if ((percentage <= 0) || (interval <= 0)) {
486 errno = EINVAL;
487 return -1;
488 }
489
490 /*
491 * Do a simple query to see if CPU monitoring is
492 * already active. If either the percentage or the
493 * interval is nonzero, then CPU monitoring is
494 * already in use for this process.
495 *
496 * XXX: need set...() and set..fatal() to behave similarly.
497 * Currently, this check prevents 1st party apps (which get a
498 * default non-fatal monitor) not to get a fatal monitor.
499 */
500 (void)proc_get_cpumon_params(pid, &current_percentage, &current_interval);
501 if (current_percentage || current_interval) {
502 /*
503 * The CPU monitor appears to be active.
504 * We choose not to disturb those settings.
505 */
506 errno = EBUSY;
507 return -1;
508 }
509
510 if ((ret = proc_set_cpumon_params(pid, percentage, interval)) != 0) {
511 /* Failed to activate the CPU monitor */
512 return ret;
513 }
514
515 if ((ret = proc_rlimit_control(pid, RLIMIT_CPU_USAGE_MONITOR, (void *)(uintptr_t)CPUMON_MAKE_FATAL)) != 0) {
516 /* Failed to set termination, back out the CPU monitor settings. */
517 (void)proc_disable_cpumon(pid);
518 }
519
520 return ret;
521 }
522
523 int
524 proc_set_wakemon_params(pid_t pid, int rate_hz, int flags __unused)
525 {
526 struct proc_rlimit_control_wakeupmon params;
527
528 params.wm_flags = WAKEMON_ENABLE;
529 params.wm_rate = rate_hz;
530
531 return proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params);
532 }
533
534 #ifndef WAKEMON_GET_PARAMS
535 #define WAKEMON_GET_PARAMS 0x4
536 #define WAKEMON_SET_DEFAULTS 0x8
537 #endif
538
539 int
540 proc_get_wakemon_params(pid_t pid, int *rate_hz, int *flags)
541 {
542 struct proc_rlimit_control_wakeupmon params;
543 int error;
544
545 params.wm_flags = WAKEMON_GET_PARAMS;
546
547 if ((error = proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params)) != 0) {
548 return error;
549 }
550
551 *rate_hz = params.wm_rate;
552 *flags = params.wm_flags;
553
554 return 0;
555 }
556
557 int
558 proc_set_wakemon_defaults(pid_t pid)
559 {
560 struct proc_rlimit_control_wakeupmon params;
561
562 params.wm_flags = WAKEMON_ENABLE | WAKEMON_SET_DEFAULTS;
563 params.wm_rate = -1;
564
565 return proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params);
566 }
567
568 int
569 proc_disable_wakemon(pid_t pid)
570 {
571 struct proc_rlimit_control_wakeupmon params;
572
573 params.wm_flags = WAKEMON_DISABLE;
574 params.wm_rate = -1;
575
576 return proc_rlimit_control(pid, RLIMIT_WAKEUPS_MONITOR, &params);
577 }
578
579 int
580 proc_list_uptrs(int pid, uint64_t *buf, uint32_t bufsz)
581 {
582 return __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDLISTUPTRS, 0,
583 buf, bufsz);
584 }
585
586 int
587 proc_list_dynkqueueids(int pid, kqueue_id_t *buf, uint32_t bufsz)
588 {
589 return __proc_info(PROC_INFO_CALL_PIDINFO, pid, PROC_PIDLISTDYNKQUEUES, 0,
590 buf, bufsz);
591 }
592
593
594 int
595 proc_setcpu_percentage(pid_t pid, int action, int percentage)
596 {
597 proc_policy_cpuusage_attr_t attr;
598
599 bzero(&attr, sizeof(proc_policy_cpuusage_attr_t));
600 attr.ppattr_cpu_attr = action;
601 attr.ppattr_cpu_percentage = percentage;
602 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) {
603 return 0;
604 } else {
605 return errno;
606 }
607 }
608
609 int
610 proc_reset_footprint_interval(pid_t pid)
611 {
612 return proc_rlimit_control(pid, RLIMIT_FOOTPRINT_INTERVAL, (void *)(uintptr_t)FOOTPRINT_INTERVAL_RESET);
613 }
614
615 int
616 proc_clear_cpulimits(pid_t pid)
617 {
618 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) {
619 return 0;
620 } else {
621 return errno;
622 }
623 }
624
625 #if TARGET_OS_EMBEDDED
626
627 int
628 proc_setcpu_deadline(pid_t pid, int action, uint64_t deadline)
629 {
630 proc_policy_cpuusage_attr_t attr;
631
632 bzero(&attr, sizeof(proc_policy_cpuusage_attr_t));
633 attr.ppattr_cpu_attr = action;
634 attr.ppattr_cpu_attr_deadline = deadline;
635 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) {
636 return 0;
637 } else {
638 return errno;
639 }
640 }
641
642 int
643 proc_setcpu_percentage_withdeadline(pid_t pid, int action, int percentage, uint64_t deadline)
644 {
645 proc_policy_cpuusage_attr_t attr;
646
647 bzero(&attr, sizeof(proc_policy_cpuusage_attr_t));
648 attr.ppattr_cpu_attr = action;
649 attr.ppattr_cpu_percentage = percentage;
650 attr.ppattr_cpu_attr_deadline = deadline;
651 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) {
652 return 0;
653 } else {
654 return errno;
655 }
656 }
657
658 int
659 proc_appstate(int pid, int * appstatep)
660 {
661 int state;
662
663 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) {
664 if (appstatep != NULL) {
665 *appstatep = state;
666 }
667 return 0;
668 } else {
669 return errno;
670 }
671 }
672
673 int
674 proc_setappstate(int pid, int appstate)
675 {
676 int state = appstate;
677
678 switch (state) {
679 case PROC_APPSTATE_NONE:
680 case PROC_APPSTATE_ACTIVE:
681 case PROC_APPSTATE_INACTIVE:
682 case PROC_APPSTATE_BACKGROUND:
683 case PROC_APPSTATE_NONUI:
684 break;
685 default:
686 return EINVAL;
687 }
688 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) {
689 return 0;
690 } else {
691 return errno;
692 }
693 }
694
695 int
696 proc_devstatusnotify(int devicestatus)
697 {
698 int state = devicestatus;
699
700 switch (devicestatus) {
701 case PROC_DEVSTATUS_SHORTTERM:
702 case PROC_DEVSTATUS_LONGTERM:
703 break;
704 default:
705 return EINVAL;
706 }
707
708 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) {
709 return 0;
710 } else {
711 return errno;
712 }
713 }
714
715 int
716 proc_pidbind(int pid, uint64_t threadid, int bind)
717 {
718 int state = bind;
719 pid_t passpid = pid;
720
721 switch (bind) {
722 case PROC_PIDBIND_CLEAR:
723 passpid = getpid(); /* ignore pid on clear */
724 break;
725 case PROC_PIDBIND_SET:
726 break;
727 default:
728 return EINVAL;
729 }
730 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) {
731 return 0;
732 } else {
733 return errno;
734 }
735 }
736
737 int
738 proc_can_use_foreground_hw(int pid, uint32_t *reason)
739 {
740 return __proc_info(PROC_INFO_CALL_CANUSEFGHW, pid, 0, 0, reason, sizeof(*reason));
741 }
742 #endif /* TARGET_OS_EMBEDDED */
743
744
745 /* Donate importance to adaptive processes from this process */
746 int
747 proc_donate_importance_boost()
748 {
749 int rval;
750
751 #if TARGET_OS_EMBEDDED
752 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
753 PROC_POLICY_ACTION_ENABLE,
754 PROC_POLICY_APPTYPE,
755 PROC_POLICY_IOS_DONATEIMP,
756 NULL, getpid(), (uint64_t)0);
757 #else /* TARGET_OS_EMBEDDED */
758 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
759 PROC_POLICY_ACTION_SET,
760 PROC_POLICY_BOOST,
761 PROC_POLICY_IMP_DONATION,
762 NULL, getpid(), 0);
763 #endif /* TARGET_OS_EMBEDDED */
764
765 if (rval == 0) {
766 return 0;
767 } else {
768 return errno;
769 }
770 }
771
772 static __attribute__((noinline)) void
773 proc_importance_bad_assertion(char *reason)
774 {
775 (void)reason;
776 }
777
778 /*
779 * Use the address of these variables as the token. This way, they can be
780 * printed in the debugger as useful names.
781 */
782 uint64_t important_boost_assertion_token = 0xfafafafafafafafa;
783 uint64_t normal_boost_assertion_token = 0xfbfbfbfbfbfbfbfb;
784 uint64_t non_boost_assertion_token = 0xfcfcfcfcfcfcfcfc;
785 uint64_t denap_boost_assertion_token = 0xfdfdfdfdfdfdfdfd;
786
787 /*
788 * Accept the boost on a message, or request another boost assertion
789 * if we have already accepted the implicit boost for this message.
790 *
791 * Returns EOVERFLOW if an attempt is made to take an extra assertion when not boosted.
792 *
793 * Returns EIO if the message was not a boosting message.
794 * TODO: Return a 'non-boost' token instead.
795 */
796 int
797 proc_importance_assertion_begin_with_msg(mach_msg_header_t *msg,
798 __unused mach_msg_trailer_t *trailer,
799 uint64_t *assertion_token)
800 {
801 int rval = 0;
802
803 if (assertion_token == NULL) {
804 return EINVAL;
805 }
806
807 #define LEGACYBOOSTMASK (MACH_MSGH_BITS_VOUCHER_MASK | MACH_MSGH_BITS_RAISEIMP)
808 #define LEGACYBOOSTED(m) (((m)->msgh_bits & LEGACYBOOSTMASK) == MACH_MSGH_BITS_RAISEIMP)
809
810 /* Is this a legacy boosted message? */
811 if (LEGACYBOOSTED(msg)) {
812 /*
813 * Have we accepted the implicit boost for this message yet?
814 * If we haven't accepted it yet, no need to call into kernel.
815 */
816 if ((msg->msgh_bits & MACH_MSGH_BITS_IMPHOLDASRT) == 0) {
817 msg->msgh_bits |= MACH_MSGH_BITS_IMPHOLDASRT;
818 *assertion_token = (uint64_t) &important_boost_assertion_token;
819 return 0;
820 }
821
822 /* Request an additional boost count */
823 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
824 PROC_POLICY_ACTION_HOLD,
825 PROC_POLICY_BOOST,
826 PROC_POLICY_IMP_IMPORTANT,
827 NULL, getpid(), 0);
828 if (rval == 0) {
829 *assertion_token = (uint64_t) &important_boost_assertion_token;
830 return 0;
831 } else if (errno == EOVERFLOW) {
832 proc_importance_bad_assertion("Attempted to take assertion while not boosted");
833 return errno;
834 } else {
835 return errno;
836 }
837 }
838
839 return EIO;
840 }
841
842
843 /*
844 * Drop a boost assertion.
845 * Returns EOVERFLOW on boost assertion underflow.
846 */
847 int
848 proc_importance_assertion_complete(uint64_t assertion_token)
849 {
850 int rval = 0;
851
852 if (assertion_token == 0) {
853 return 0;
854 }
855
856 if (assertion_token == (uint64_t) &important_boost_assertion_token) {
857 rval = __process_policy(PROC_POLICY_SCOPE_PROCESS,
858 PROC_POLICY_ACTION_DROP,
859 PROC_POLICY_BOOST,
860 PROC_POLICY_IMP_IMPORTANT,
861 NULL, getpid(), 0);
862 if (rval == 0) {
863 return 0;
864 } else if (errno == EOVERFLOW) {
865 proc_importance_bad_assertion("Attempted to drop too many assertions");
866 return errno;
867 } else {
868 return errno;
869 }
870 } else {
871 proc_importance_bad_assertion("Attempted to drop assertion with invalid token");
872 return EIO;
873 }
874 }
875
876 /*
877 * Accept the De-Nap boost on a message, or request another boost assertion
878 * if we have already accepted the implicit boost for this message.
879 *
880 * Interface is deprecated before it really got started - just as synonym
881 * for proc_importance_assertion_begin_with_msg() now.
882 */
883 int
884 proc_denap_assertion_begin_with_msg(mach_msg_header_t *msg,
885 uint64_t *assertion_token)
886 {
887 #pragma clang diagnostic push
888 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
889 return proc_importance_assertion_begin_with_msg(msg, NULL, assertion_token);
890 #pragma clang diagnostic pop
891 }
892
893
894 /*
895 * Drop a denap boost assertion.
896 *
897 * Interface is deprecated before it really got started - just a synonym
898 * for proc_importance_assertion_complete() now.
899 */
900 int
901 proc_denap_assertion_complete(uint64_t assertion_token)
902 {
903 return proc_importance_assertion_complete(assertion_token);
904 }
905
906 #if !TARGET_OS_EMBEDDED
907
908 int
909 proc_clear_vmpressure(pid_t pid)
910 {
911 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) {
912 return 0;
913 } else {
914 return errno;
915 }
916 }
917
918 /* set the current process as one who can resume suspended processes due to low virtual memory. Need to be root */
919 int
920 proc_set_owner_vmpressure(void)
921 {
922 int retval;
923
924 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_VMRSRCOWNER, (uint64_t)0, NULL, 0)) == -1) {
925 return errno;
926 }
927
928 return 0;
929 }
930
931 /* mark yourself to delay idle sleep on disk IO */
932 int
933 proc_set_delayidlesleep(void)
934 {
935 int retval;
936
937 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_DELAYIDLESLEEP, (uint64_t)1, NULL, 0)) == -1) {
938 return errno;
939 }
940
941 return 0;
942 }
943
944 /* Reset yourself to delay idle sleep on disk IO, if already set */
945 int
946 proc_clear_delayidlesleep(void)
947 {
948 int retval;
949
950 if ((retval = __proc_info(PROC_INFO_CALL_SETCONTROL, getpid(), PROC_SELFSET_DELAYIDLESLEEP, (uint64_t)0, NULL, 0)) == -1) {
951 return errno;
952 }
953
954 return 0;
955 }
956
957 /* disable the launch time backgroudn policy and restore the process to default group */
958 int
959 proc_disable_apptype(pid_t pid, int apptype)
960 {
961 switch (apptype) {
962 case PROC_POLICY_OSX_APPTYPE_TAL:
963 case PROC_POLICY_OSX_APPTYPE_DASHCLIENT:
964 break;
965 default:
966 return EINVAL;
967 }
968
969 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_DISABLE, PROC_POLICY_APPTYPE, apptype, NULL, pid, (uint64_t)0) != -1) {
970 return 0;
971 } else {
972 return errno;
973 }
974 }
975
976 /* re-enable the launch time background policy if it had been disabled. */
977 int
978 proc_enable_apptype(pid_t pid, int apptype)
979 {
980 switch (apptype) {
981 case PROC_POLICY_OSX_APPTYPE_TAL:
982 case PROC_POLICY_OSX_APPTYPE_DASHCLIENT:
983 break;
984 default:
985 return EINVAL;
986 }
987
988 if (__process_policy(PROC_POLICY_SCOPE_PROCESS, PROC_POLICY_ACTION_ENABLE, PROC_POLICY_APPTYPE, apptype, NULL, pid, (uint64_t)0) != -1) {
989 return 0;
990 } else {
991 return errno;
992 }
993 }
994
995 #if !TARGET_IPHONE_SIMULATOR
996
997 int
998 proc_suppress(__unused pid_t pid, __unused uint64_t *generation)
999 {
1000 return 0;
1001 }
1002
1003 #endif /* !TARGET_IPHONE_SIMULATOR */
1004
1005 #endif /* !TARGET_OS_EMBEDDED */