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