/*
- * Copyright (c) 2005, 2010 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2016 Apple Computer, Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <mach/mach_types.h>
#include <mach/vm_param.h>
#include <kern/task.h>
-#include <kern/lock.h>
#include <kern/kalloc.h>
#include <kern/assert.h>
+#include <kern/policy_internal.h>
+
#include <vm/vm_kern.h>
#include <vm/vm_map.h>
#include <mach/host_info.h>
#include <vm/vm_protos.h>
static int handle_lowresource(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
-static int handle_resourceuse(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
+static int handle_cpuuse(int action, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
static int handle_apptype(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
static int handle_boost(int scope, int action, int policy, int policy_subtype, user_addr_t attrp, proc_t proc, uint64_t target_threadid);
error = handle_lowresource(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
break;
case PROC_POLICY_RESOURCE_USAGE:
- error = handle_resourceuse(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
+ switch(policy_subtype) {
+ case PROC_POLICY_RUSAGE_NONE:
+ case PROC_POLICY_RUSAGE_WIREDMEM:
+ case PROC_POLICY_RUSAGE_VIRTMEM:
+ case PROC_POLICY_RUSAGE_DISK:
+ case PROC_POLICY_RUSAGE_NETWORK:
+ case PROC_POLICY_RUSAGE_POWER:
+ error = ENOTSUP;
+ goto out;
+ default:
+ error = EINVAL;
+ goto out;
+ case PROC_POLICY_RUSAGE_CPU:
+ break;
+ }
+
+ error = handle_cpuuse(action, attrp, target_proc, target_threadid);
break;
case PROC_POLICY_APPTYPE:
error = handle_apptype(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
static int
-handle_resourceuse(__unused int scope, __unused int action, __unused int policy, int policy_subtype, user_addr_t attrp, proc_t proc, __unused uint64_t target_threadid)
+handle_cpuuse(int action, user_addr_t attrp, proc_t proc, __unused uint64_t target_threadid)
{
proc_policy_cpuusage_attr_t cpuattr;
#if CONFIG_MACF
proc_t curp = current_proc();
#endif
- int entitled = TRUE;
+ int entitled = FALSE;
+ Boolean canEnable = FALSE;
uint64_t interval = -1ULL;
int error = 0;
-
- switch(policy_subtype) {
- case PROC_POLICY_RUSAGE_NONE:
- case PROC_POLICY_RUSAGE_WIREDMEM:
- case PROC_POLICY_RUSAGE_VIRTMEM:
- case PROC_POLICY_RUSAGE_DISK:
- case PROC_POLICY_RUSAGE_NETWORK:
- case PROC_POLICY_RUSAGE_POWER:
- return(ENOTSUP);
- break;
- default:
- return(EINVAL);
- case PROC_POLICY_RUSAGE_CPU:
- break;
- }
+ uint8_t percentage;
#if CONFIG_MACF
- if (curp != proc) {
- /* the cpumon entitlement manages messing with CPU limits on self */
- error = mac_proc_check_sched(curp, proc);
- if (error)
- return error;
- }
-
/*
- * Allow a process to change CPU usage monitor parameters, unless a MAC policy
- * overrides it with an entitlement check.
+ * iOS only allows processes to override their own CPU usage monitor
+ * parameters if they have com.apple.private.kernel.override-cpumon.
+ *
+ * Until rdar://24799462 improves our scheme, we are also using the
+ * same entitlement to indicate which processes can resume monitoring
+ * when they otherwise wouldn't be able to.
*/
entitled = (mac_proc_check_cpumon(curp) == 0) ? TRUE : FALSE;
+ canEnable = (entitled && action == PROC_POLICY_ACTION_ENABLE);
+
+ if (!canEnable && curp != proc) {
+ /* can the current process change scheduling parameters? */
+ error = mac_proc_check_sched(curp, proc);
+ if (error) return error;
+ }
#endif
- switch (action) {
- uint8_t percentage;
+ // on macOS tasks can only set and clear their own CPU limits
+ if ((action == PROC_POLICY_ACTION_APPLY || action == PROC_POLICY_ACTION_RESTORE)
+ && proc != current_proc()) {
+ return (EPERM);
+ }
+ switch (action) {
case PROC_POLICY_ACTION_GET:
error = proc_get_task_ruse_cpu(proc->task, &cpuattr.ppattr_cpu_attr,
&percentage,
entitled);
break;
+ /* restore process to prior state */
case PROC_POLICY_ACTION_RESTORE:
error = proc_clear_task_ruse_cpu(proc->task, entitled);
break;
+ /* re-enable suspended monitor */
+ case PROC_POLICY_ACTION_ENABLE:
+ error = task_resume_cpumon(proc->task);
+ break;
+
+ case PROC_POLICY_ACTION_REMOVE:
+
default:
error = EINVAL;
break;
return (EINVAL);
/* PROCESS ENABLE APPTYPE HOLDIMP */
- error = task_importance_hold_external_assertion(current_task(), 1);
+ error = task_importance_hold_legacy_external_assertion(current_task(), 1);
return(error);
return (EINVAL);
/* PROCESS ENABLE APPTYPE DROPIMP */
- error = task_importance_drop_external_assertion(current_task(), 1);
+ error = task_importance_drop_legacy_external_assertion(current_task(), 1);
return(error);
switch (action) {
case PROC_POLICY_ACTION_ENABLE:
/* PROCESS ENABLE APPTYPE TAL */
- proc_set_task_policy(target_proc->task, THREAD_NULL,
- TASK_POLICY_ATTRIBUTE, TASK_POLICY_TAL,
- TASK_POLICY_ENABLE);
+ proc_set_task_policy(target_proc->task,
+ TASK_POLICY_ATTRIBUTE, TASK_POLICY_TAL,
+ TASK_POLICY_ENABLE);
break;
case PROC_POLICY_ACTION_DISABLE:
/* PROCESS DISABLE APPTYPE TAL */
- proc_set_task_policy(target_proc->task, THREAD_NULL,
- TASK_POLICY_ATTRIBUTE, TASK_POLICY_TAL,
- TASK_POLICY_DISABLE);
+ proc_set_task_policy(target_proc->task,
+ TASK_POLICY_ATTRIBUTE, TASK_POLICY_TAL,
+ TASK_POLICY_DISABLE);
break;
default:
return (EINVAL);
- break;
}
return(0);
switch(policy_subtype) {
case PROC_POLICY_IMP_IMPORTANT:
- if (task_is_importance_receiver(target_proc->task) == FALSE)
+ if (task_is_importance_receiver_type(target_proc->task) == FALSE)
return (EINVAL);
switch (action) {
case PROC_POLICY_ACTION_HOLD:
/* PROCESS HOLD BOOST IMPORTANT */
- error = task_importance_hold_external_assertion(current_task(), 1);
+ error = task_importance_hold_legacy_external_assertion(current_task(), 1);
break;
case PROC_POLICY_ACTION_DROP:
/* PROCESS DROP BOOST IMPORTANT */
- error = task_importance_drop_external_assertion(current_task(), 1);
+ error = task_importance_drop_legacy_external_assertion(current_task(), 1);
break;
default:
error = (EINVAL);
return (0);
}
+/*
+ * Get the darwin background state of the originator. If the current
+ * process app type is App, then it is the originator, else if it is
+ * a Daemon, then creator of the Resource Accounting attribute of
+ * the current thread voucher is the originator of the work.
+ */
+int
+proc_get_originatorbgstate(uint32_t *is_backgrounded)
+{
+ uint32_t bgstate;
+ proc_t p = current_proc();
+ uint32_t flagsp;
+ kern_return_t kr;
+ pid_t pid;
+ int ret;
+ thread_t thread = current_thread();
+
+ bgstate = proc_get_effective_thread_policy(thread, TASK_POLICY_DARWIN_BG);
+
+ /* If current thread or task backgrounded, return background */
+ if (bgstate) {
+ *is_backgrounded = 1;
+ return 0;
+ }
+
+ /* Check if current process app type is App, then return foreground */
+ proc_get_darwinbgstate(p->task, &flagsp);
+ if ((flagsp & PROC_FLAG_APPLICATION) == PROC_FLAG_APPLICATION) {
+ *is_backgrounded = 0;
+ return 0;
+ }
+
+ /*
+ * Get the current voucher origin pid and it's bgstate.The pid
+ * returned here might not be valid or may have been recycled.
+ */
+ kr = thread_get_current_voucher_origin_pid(&pid);
+ if (kr != KERN_SUCCESS) {
+ if (kr == KERN_INVALID_TASK)
+ return ESRCH;
+ else if (kr == KERN_INVALID_VALUE)
+ return ENOATTR;
+ else
+ return EINVAL;
+ }
+
+ ret = proc_pidbackgrounded(pid, is_backgrounded);
+ return ret;
+}
+
int
proc_apply_resource_actions(void * bsdinfo, __unused int type, int action)
{
return(0);
}
-
int
proc_restore_resource_actions(void * bsdinfo, __unused int type, int action)
{