xref: /xnu-12377.81.4/tests/memorystatus_is_assertion.c (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <errno.h>
5 #include <string.h>
6 #include <assert.h>
7 #include <signal.h>
8 #include <spawn.h>
9 #include <spawn_private.h>
10 #include <stdint.h>
11 #include <sys/sysctl.h>
12 #include <sys/spawn_internal.h>
13 #include <sys/kern_memorystatus.h>
14 #include <mach-o/dyld.h>
15 #include <os/voucher_private.h>
16 
17 #include <darwintest.h>
18 #include <darwintest_multiprocess.h>
19 #include <darwintest_utils.h>
20 
21 #include "memorystatus_assertion_helpers.h"
22 
23 T_GLOBAL_META(
24 	T_META_NAMESPACE("xnu.memorystatus"),
25 	T_META_RADAR_COMPONENT_NAME("xnu"),
26 	T_META_RADAR_COMPONENT_VERSION("VM"),
27 	T_META_CHECK_LEAKS(false),
28 	T_META_RUN_CONCURRENTLY(true),
29 	T_META_TAG_VM_PREFERRED,
30 	T_META_BOOTARGS_SET("memstat_no_task_limit_increase=1")
31 	);
32 
33 #define IDLE_AGEOUT_S 30
34 #define AGEOUT_STUCK_S 35
35 
36 /*
37  * This test has multiple sub-tests that set and then verify jetsam priority transitions
38  * as though they were driven by assertions. It uses the MEMORYSTATUS_CMD_SET_MEMLIMIT_PROPERTIES
39  * version of the memorystatus_control() system call and specifically tests the use of the
40  * MEMORYSTATUS_SET_PRIORITY_ASSERTION flag.
41  *
42  * The kernel will apply policy that chooses a maximum jetsam priority, resolving conflicts
43  * between an assertion driven priority and clean/dirty transition policy.
44  *
45  * Processes that do not opt into dirty-tracking should behave as they always have.
46  * This is the typical App transition behavior.
47  *
48  * Processes that do opt into dirty-tracking have more complex policy:
49  * For example:
50  * A MAX assertion priority will prevent a dirty process from transitioning to a clean
51  * state if the process opts into idle-exit.
52  *    See: memorystatus_schedule_idle_demotion_locked() where we note that
53  *    the process isn't going to be making the trip to the lower bands.
54  *
55  * But a MAX assertion evaluation will not prevent a clean process from transition to dirty.
56  * Assertion driven priorities should not change memory limits, they are expected to
57  * just change a process's position in the jetsam priority bands.
58  *
59  * MEMORYSTATUS_CMD_xxx requires root (in the absence of entitlement).
60  * Use T_META_ASROOT(true) to accomplish this.
61  *
62  * A note on test strategy.  It is not necessary to spawn a child to test these
63  * assertion calls.   The test can act on itself, that is, it can make calls to
64  * set and relinquish assertion state just like it can make calls to do dirty/clean
65  * transitions.  Of course, in reality, we expect only runningboardd to manipulate
66  * assertion based priorities.
67  */
68 
69 static void
proc_will_set_clean(pid_t pid)70 proc_will_set_clean(pid_t pid)
71 {
72 	proc_set_dirty(pid, false);
73 	T_LOG("pid[%d] --> now clean", pid);
74 	return;
75 }
76 
77 static void
proc_will_set_dirty(pid_t pid)78 proc_will_set_dirty(pid_t pid)
79 {
80 	proc_set_dirty(pid, true);
81 	T_LOG("pid[%d] --> now dirty", pid);
82 	return;
83 }
84 
85 static void
proc_set_managed(pid_t pid,bool managed)86 proc_set_managed(pid_t pid, bool managed)
87 {
88 	int err;
89 	err = memorystatus_control(MEMORYSTATUS_CMD_SET_PROCESS_IS_MANAGED, pid,
90 	    managed, NULL, 0);
91 	T_QUIET; T_ASSERT_POSIX_SUCCESS(err,
92 	    "memorystatus_control(MEMORYSTATUS_CMD_SET_PROCESS_IS_MANAGED)");
93 }
94 
95 /*
96  * Make repetitive (eg: back-to-back) calls using MEMORYSTATUS_SET_PRIORITY_ASSERTION.
97  * We know that runningboardd may try to relinquish its hold on an assertion priority
98  * when it hasn't first set the assertion priority. The kernel must survive this
99  * pattern even though it might be considered poor behavior on runningboardd's part.
100  * When dirty tracking processes are involved, we are exercising the kernel's
101  * idle-deferred paths. Only assertion state (whether or not assertion state is
102  * set or relinquished) is verified in this round of tests.
103  * Test is invoked three times:
104  *	Scenario 1) as a non-dirty-tracking process  (like a typical app)
105  *		relinquish assertion priority multiple times
106  *		set same assertion priority multiple times.
107  *	Scenario 2) setup a dirty-tracking process that is clean  (like a typical extension)
108  *		relinquish assertion priority multiple times
109  *		set same assertion priority multiple times.
110  *	Scenario 3) setup dirty-tracking process that is dirty  (like a typical extension)
111  *		relinquish assertion priority multiple times
112  *		set same assertion priority multiple times.
113  */
114 
115 static void
memorystatus_assertion_test_repetitive(char * test,boolean_t turn_on_dirty_tracking,boolean_t start_clean)116 memorystatus_assertion_test_repetitive(char *test, boolean_t turn_on_dirty_tracking, boolean_t start_clean)
117 {
118 	int count;
119 	int maxcount = 3;
120 	boolean_t verbose;
121 	uint32_t state;
122 	uint64_t user_data = 0;
123 	pid_t mypid = getpid();
124 
125 	/* these values will remain fixed during testing */
126 	int             active_limit_mb = 35;   /* arbitrary */
127 	int             inactive_limit_mb = 25;  /* arbitrary */
128 
129 	/* these values may vary during test */
130 	int             requestedpriority = 0;
131 	int             assertionpriority = 0;
132 
133 	T_SETUPBEGIN;
134 
135 	requestedpriority =  JETSAM_PRIORITY_UI_SUPPORT;
136 	assertionpriority =  JETSAM_PRIORITY_FOREGROUND;
137 	set_memlimits(mypid, active_limit_mb, inactive_limit_mb, true, true);
138 	set_priority(mypid, requestedpriority, 0, false);
139 
140 	if (turn_on_dirty_tracking) {
141 		proc_track_dirty(mypid, (PROC_DIRTY_TRACK | PROC_DIRTY_ALLOW_IDLE_EXIT | PROC_DIRTY_DEFER));
142 
143 		if (start_clean) {
144 			proc_will_set_clean(mypid);
145 		} else {
146 			proc_will_set_dirty(mypid);
147 		}
148 	} else {
149 		/*
150 		 * Do nothing.
151 		 * Acts like an app with no dirty tracking
152 		 * By default launches in the requested priority and is
153 		 * considered idle because it's below FG band.
154 		 */
155 	}
156 
157 	proc_set_managed(mypid, true);
158 
159 	verbose = false;
160 	(void)get_priority_props(mypid, verbose, NULL, NULL, NULL, NULL);
161 
162 	/* log current setup state */
163 	T_LOG("SETUP STATE COMPLETE: Test %s", test);
164 
165 	T_SETUPEND;
166 
167 	int i;
168 	boolean_t ret;
169 	for (i = 0; i < 2; i++) {
170 		if (i == 1 && turn_on_dirty_tracking) {
171 			T_LOG("Avoid idle-deferred - sleeping for %d s", IDLE_AGEOUT_S);
172 			sleep(IDLE_AGEOUT_S);
173 
174 			if (start_clean) {
175 				proc_will_set_dirty(mypid);
176 			} else {
177 				proc_will_set_clean(mypid);
178 			}
179 
180 			(void)get_priority_props(mypid, verbose, NULL, NULL, NULL, &state);
181 		}
182 
183 		/*
184 		 * Relinquish assertion priority even though we don't
185 		 * currently hold an assertion priority.
186 		 */
187 		for (count = 0; count < maxcount; count++) {
188 			if (relinquish_assertion_priority(mypid, user_data)) {
189 				T_ASSERT_FAIL("relinquish_assertion_priority failed");
190 			}
191 		}
192 
193 		/* Verify assertion state is relinquished */
194 		(void)get_priority_props(mypid, verbose, NULL, NULL, NULL, &state);
195 
196 		ret = verify_assertion_state(state, ASSERTION_STATE_IS_RELINQUISHED);
197 		T_QUIET;
198 		T_ASSERT_TRUE(ret, "verify_assertion_state failed");
199 
200 
201 
202 		/*
203 		 * Set an assertion priority multiple times in a row.
204 		 */
205 		for (count = 0; count < maxcount; count++) {
206 			if (set_assertion_priority(mypid, assertionpriority, user_data) != 0) {
207 				T_ASSERT_FAIL("set_assertion_priority failed");
208 			}
209 		}
210 
211 		/* Verify state holds an assertion priority */
212 		(void)get_priority_props(mypid, verbose, NULL, NULL, NULL, &state);
213 
214 		ret = verify_assertion_state(state, ASSERTION_STATE_IS_SET);
215 		T_QUIET;
216 		T_ASSERT_TRUE(ret, "verify_assertion_state failed");
217 	}
218 }
219 
220 /*
221  * Process is dirty tracking and opts into pressured exit.
222  */
223 static void
memorystatus_assertion_test_allow_idle_exit(void)224 memorystatus_assertion_test_allow_idle_exit(void)
225 {
226 	pid_t mypid = getpid();
227 
228 	/* these values will remain fixed during testing */
229 	int active_limit_mb   = 35; /* arbitrary */
230 	int inactive_limit_mb = 25;  /* arbitrary */
231 
232 	/* these values may vary during test */
233 	int requestedpriority = JETSAM_PRIORITY_UI_SUPPORT;
234 
235 	T_SETUPBEGIN;
236 
237 	set_memlimits(mypid, active_limit_mb, inactive_limit_mb, true, true);
238 	set_priority(mypid, requestedpriority, 0, false);
239 
240 	proc_track_dirty(mypid, (PROC_DIRTY_TRACK | PROC_DIRTY_ALLOW_IDLE_EXIT | PROC_DIRTY_DEFER));
241 	proc_set_managed(mypid, true);
242 
243 	proc_will_set_clean(mypid);
244 
245 	(void)check_properties(mypid, JETSAM_PRIORITY_IDLE_DEFERRED, active_limit_mb, 0x0, ASSERTION_STATE_IS_RELINQUISHED, "Clean start");
246 
247 	T_LOG("SETUP STATE COMPLETE");
248 
249 	int g_jetsam_aging_policy = 0;
250 	/*
251 	 * Jetsam aging policy
252 	 * Failure to retrieve is not fatal.
253 	 */
254 	size_t size = sizeof(g_jetsam_aging_policy);
255 	if (sysctlbyname("kern.jetsam_aging_policy", &g_jetsam_aging_policy, &size, NULL, 0) != 0) {
256 		T_LOG(__func__, true, "Unable to retrieve jetsam aging policy (not fatal)");
257 	}
258 
259 	T_SETUPEND;
260 
261 	/*
262 	 * Relinquish assertion priority even though we don't hold it.  No change in state expected.
263 	 */
264 	T_LOG("********Test0 clean: no state change on relinquish");
265 	relinquish_assertion_priority(mypid, 0xF00D);
266 	(void)check_properties(mypid, JETSAM_PRIORITY_IDLE_DEFERRED, active_limit_mb, 0xF00D, ASSERTION_STATE_IS_RELINQUISHED, "Test0");
267 
268 	T_LOG("********Test1 clean: deferred now assertion[10]");
269 	set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
270 	(void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test1");
271 
272 	/* Test2 */
273 	T_LOG("********Test2 clean:  assertion[10 -> 3]");
274 	set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
275 	(void)check_properties(mypid, JETSAM_PRIORITY_BACKGROUND, active_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test2");
276 
277 	/* Test3 */
278 	T_LOG("********Test3 clean: assertion[3 -> 0], but now deferred");
279 	relinquish_assertion_priority(mypid, 0xBEEF);
280 	(void)check_properties(mypid, JETSAM_PRIORITY_IDLE_DEFERRED, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test3");
281 
282 	T_LOG("Avoid idle-deferred moving forward. Sleeping for %d s", IDLE_AGEOUT_S);
283 	sleep(IDLE_AGEOUT_S);
284 
285 	(void)check_properties(mypid, JETSAM_PRIORITY_IDLE, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test3");
286 
287 	/* Test4 */
288 	T_LOG("********Test4 clean: deferred now assertion[10]");
289 	set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
290 	(void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test4");
291 
292 
293 	/* Test5 */
294 	T_LOG("********Test5 dirty: set dirty priority but assertion[10] prevails");
295 	proc_will_set_dirty(mypid);   /* active priority is less than FG*/
296 	(void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test5");
297 
298 	/* Test6 */
299 	T_LOG("********Test6 dirty: assertion[10 -> 3] but dirty priority prevails");
300 	set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFEEB);  /* active priority is > BG */
301 	(void)check_properties(mypid, JETSAM_PRIORITY_UI_SUPPORT, active_limit_mb, 0xFEEB, ASSERTION_STATE_IS_SET, "Test6");
302 
303 	/* Test7 */
304 	T_LOG("********Test7 dirty: assertion[3 -> 0] but dirty prevails");
305 	relinquish_assertion_priority(mypid, 0xBEEF);
306 	(void)check_properties(mypid, JETSAM_PRIORITY_UI_SUPPORT, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test7");
307 
308 
309 	/* Test8 */
310 	T_LOG("********Test8 dirty: assertion[0 -> 10] overrides dirty");
311 	set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
312 	(void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test8");
313 
314 	/* Test9 */
315 	T_LOG("********Test9 dirty wants to go clean, but clean state is prevented as assertion[10] prevails");
316 	proc_will_set_clean(mypid);
317 	(void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test9");
318 
319 	/* Test10 */
320 	T_LOG("********Test10 dirty goes dirty and stays dirty, and assertion[10] prevails again");
321 	proc_will_set_dirty(mypid);
322 	(void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test10");
323 
324 	/* Test11 */
325 	T_LOG("********Test11 dirty: assertion[10 -> 3] but dirty prevails");
326 	set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
327 	(void)check_properties(mypid, JETSAM_PRIORITY_UI_SUPPORT, active_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test11");
328 
329 	/* Test12 */
330 	T_LOG("********Test12 dirty: assertion[3 -> 0] but dirty prevails");
331 	relinquish_assertion_priority(mypid, 0xBEEF);
332 	(void)check_properties(mypid, JETSAM_PRIORITY_UI_SUPPORT, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test12");
333 
334 
335 	/* Test13 */
336 	T_LOG("********Test13 dirty goes clean: both assertion[0] and clean");
337 	proc_will_set_clean(mypid);
338 	/* For sysproc aging policy the daemon should be at idle deferred and with an active memory limit */
339 	(void)check_properties(mypid, JETSAM_PRIORITY_IDLE_DEFERRED, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test13");
340 }
341 
342 /*
343  * Process is dirty tracking and does not opt into pressured exit.
344  * This test lives above Foreground.  Assertions will have no affect
345  * except where the assertion priority bumps it above the requested priority.
346  */
347 static void
memorystatus_assertion_test_do_not_allow_idle_exit(void)348 memorystatus_assertion_test_do_not_allow_idle_exit(void)
349 {
350 	pid_t mypid = getpid();
351 
352 	/* these values will remain fixed during testing */
353 	int             active_limit_mb = 35;   /* arbitrary */
354 	int             inactive_limit_mb = 25;  /* arbitrary */
355 	int             requestedpriority = JETSAM_PRIORITY_AUDIO_AND_ACCESSORY;
356 
357 	T_SETUPBEGIN;
358 
359 	set_memlimits(mypid, active_limit_mb, inactive_limit_mb, true, true);
360 	set_priority(mypid, requestedpriority, 0, false);
361 	proc_track_dirty(mypid, (PROC_DIRTY_TRACK));
362 	proc_set_managed(mypid, true);
363 
364 	proc_will_set_dirty(mypid);
365 
366 	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0x0, ASSERTION_STATE_IS_RELINQUISHED, "Dirty start");
367 
368 	proc_will_set_clean(mypid);
369 
370 	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0x0, ASSERTION_STATE_IS_RELINQUISHED, "Clean transition");
371 
372 	T_LOG("SETUP STATE COMPLETE");
373 
374 	T_SETUPEND;
375 
376 	/*
377 	 * Relinquish assertion priority even though we don't hold it.  No change in state expected.
378 	 */
379 
380 
381 	/* Test0 */
382 	T_LOG("********Test0 clean: no state change on relinquish");
383 	relinquish_assertion_priority(mypid, 0xF00D);
384 	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xF00D, ASSERTION_STATE_IS_RELINQUISHED, "Test0");
385 
386 	/* Test1 */
387 	T_LOG("********Test1 clean: assertion[0 -> 10] but inactive priority prevails");
388 	set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
389 	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test1");
390 
391 	/* Test2 */
392 	T_LOG("********Test2 clean:  assertion[10 -> 3] but inactive priority prevails");
393 	set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
394 	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test2");
395 
396 	/* Test3 */
397 	T_LOG("********Test3 clean: assertion[3 -> 0], but inactive priority prevails");
398 	relinquish_assertion_priority(mypid, 0xBEEF);
399 	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test3");
400 
401 	/* Test4 */
402 	T_LOG("********Test4 go dirty: assertion[0] has no affect, active priority prevails");
403 	proc_will_set_dirty(mypid);
404 	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test4");
405 
406 	/* Test5 */
407 	T_LOG("********Test5 dirty: assertion[0 -> 10] active priority prevails");
408 	set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
409 	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test5");
410 
411 	/* Test6 */
412 	T_LOG("********Test6 dirty:  assertion[10 -> 3] active priority prevails");
413 	set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
414 	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test6");
415 
416 	/* Test 7 */
417 	T_LOG("********Test7 dirty: assertion[3 -> 0], active priority prevails");
418 	relinquish_assertion_priority(mypid, 0xBEEF);
419 	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test7");
420 
421 	/* Test8 */
422 	T_LOG("********Test8 dirty: assertion[0 -> 19], dirty but now assertion[19] prevails");
423 	set_assertion_priority(mypid, JETSAM_PRIORITY_CRITICAL, 0xFEED);
424 	(void)check_properties(mypid, JETSAM_PRIORITY_CRITICAL, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test8");
425 
426 
427 	/* Test9 */
428 	T_LOG("********Test9 go clean: inactive priority but assertion[19] prevails");
429 	proc_will_set_clean(mypid);
430 	(void)check_properties(mypid, JETSAM_PRIORITY_CRITICAL, inactive_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test9");
431 
432 	/* Test10 */
433 	T_LOG("********Test10 clean:  assertion[19 -> 3] inactive limit prevails");
434 	set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
435 	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test10");
436 
437 
438 	/* Test11 */
439 	T_LOG("********Test11 clean:  assertion[3 -> 0] inactive priority still prevails");
440 	relinquish_assertion_priority(mypid, 0xBEEF);
441 	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test11");
442 
443 	/* Test12 */
444 	T_LOG("********Test12 dirty goes clean: both assertion[0] and clean");
445 	proc_will_set_clean(mypid);
446 	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test12");
447 }
448 
449 T_DECL(assertion_test_bad_flags, "verify bad flag returns an error", T_META_TIMEOUT(30), T_META_ASROOT(true)) {
450 	int err;
451 	uint32_t flag = 0;
452 
453 	memorystatus_priority_properties_t mjp = { 0 };
454 
455 	mjp.priority = JETSAM_PRIORITY_FOREGROUND;
456 	mjp.user_data = 0;
457 
458 	/*
459 	 * init a bad flag
460 	 */
461 
462 	flag = 0xf;
463 
464 	err = memorystatus_control(MEMORYSTATUS_CMD_SET_PRIORITY_PROPERTIES, getpid(), flag, &mjp, sizeof(mjp));
465 
466 	T_QUIET;
467 	T_ASSERT_POSIX_FAILURE(err, EINVAL, "MEMORYSTATUS_CMD_SET_PRIORITY_PROPERTIES should fail with bad flags (err=%d)", err);
468 }
469 
470 T_DECL(set_assertion_pri_unmanaged,
471     "verify that an unmanaged process cannot have assertion-driven priority set")
472 {
473 	int err;
474 	memorystatus_priority_properties_t mjp = {
475 		.priority = JETSAM_PRIORITY_FOREGROUND,
476 		.user_data = 0x0
477 	};
478 	err = memorystatus_control(MEMORYSTATUS_CMD_SET_PRIORITY_PROPERTIES,
479 	    getpid(), MEMORYSTATUS_SET_PRIORITY_ASSERTION, &mjp, sizeof(mjp));
480 
481 	T_EXPECT_POSIX_FAILURE(err, EPERM,
482 	    "Should not be able to set assertion-driven priority of unmanaged process.");
483 }
484 
485 
486 #if TARGET_OS_OSX
487 /*
488  * Idle band deferral, aka aging band/demotion, has been disabled on macOS till
489  * we do the daemon hygiene work on macOS to make sure that processes don't change
490  * their role after spawn e.g. apps opting into dirty-tracking/idle-exit.
491  * The following set of tests rely on PROC_DIRTY_DEFER, aka aging bands, for the tests.
492  */
493 #else /* TARGET_OS_OSX */
494 
495 T_HELPER_DECL(idle_age_as_app_then_sysproc,
496     "Launch as managed, begin idle aging, then enroll in ActivityTracking")
497 {
498 	pid_t my_pid = getpid();
499 	int32_t priority;
500 
501 	// Set self as managed and begin idle aging
502 	proc_set_managed(my_pid, true);
503 	set_priority(my_pid, JETSAM_PRIORITY_IDLE, 0, false);
504 	// process must have a fatal memlimit to enroll in dirtytracking while
505 	// managed
506 	set_memlimits(my_pid, 100, 100, true, true);
507 
508 	get_priority_props(my_pid, FALSE, &priority, NULL, NULL, NULL);
509 	T_EXPECT_EQ(priority, JETSAM_PRIORITY_AGING_BAND2, "Process is placed in App aging band");
510 
511 	// Enroll in dirty tracking
512 	proc_track_dirty(my_pid,
513 	    (PROC_DIRTY_TRACK | PROC_DIRTY_ALLOW_IDLE_EXIT | PROC_DIRTY_DEFER));
514 
515 	get_priority_props(my_pid, FALSE, &priority, NULL, NULL, NULL);
516 	T_EXPECT_EQ(priority, JETSAM_PRIORITY_AGING_BAND1, "Process is placed in SysProc aging band");
517 
518 	T_LOG("Sleeping for %d sec...", IDLE_AGEOUT_S);
519 	sleep(IDLE_AGEOUT_S);
520 
521 	get_priority_props(my_pid, FALSE, &priority, NULL, NULL, NULL);
522 	T_EXPECT_EQ(priority, JETSAM_PRIORITY_IDLE, "Process ages to IDLE");
523 }
524 
525 T_DECL(idle_aging_app_to_sysproc,
526     "Processes that transition from App -> SysProc while aging are deferred properly")
527 {
528 	dt_helper_t helper = dt_child_helper("idle_age_as_app_then_sysproc");
529 
530 	dt_run_helpers(&helper, 1, 90);
531 }
532 
533 T_HELPER_DECL(idle_age_timeout_importance_boost,
534     "Enroll in ActivityTracking, idle age with held assertion")
535 {
536 	pid_t my_pid = getpid();
537 	int32_t priority, ret;
538 
539 	// Set managed, enroll in dirty tracking, and pretend we have an importance assertion voucher
540 	proc_set_managed(my_pid, true);
541 	set_memlimits(my_pid, 100, 100, true, true);
542 	proc_track_dirty(my_pid,
543 	    (PROC_DIRTY_TRACK | PROC_DIRTY_ALLOW_IDLE_EXIT | PROC_DIRTY_DEFER));
544 	ret = memorystatus_control(MEMORYSTATUS_CMD_SET_TESTING_PID, getpid(), MEMORYSTATUS_FLAGS_SET_IMP_TESTING_PID, NULL, 0);
545 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "MEMORYSTATUS_CMD_SET_TESTING_PID");
546 
547 	get_priority_props(my_pid, FALSE, &priority, NULL, NULL, NULL);
548 	T_EXPECT_EQ(priority, JETSAM_PRIORITY_AGING_BAND1, "Process is placed in SysProc aging band");
549 
550 	T_LOG("Sleeping for %d sec...", IDLE_AGEOUT_S);
551 	sleep(IDLE_AGEOUT_S);
552 
553 	get_priority_props(my_pid, FALSE, &priority, NULL, NULL, NULL);
554 	T_EXPECT_EQ(priority, JETSAM_PRIORITY_AGING_BAND1_STUCK, "Process ages to JETSAM_PRIORITY_AGING_BAND1_STUCK");
555 
556 	T_LOG("Sleeping for %d sec...", AGEOUT_STUCK_S);
557 	sleep(AGEOUT_STUCK_S);
558 
559 	get_priority_props(my_pid, FALSE, &priority, NULL, NULL, NULL);
560 	T_EXPECT_EQ(priority, JETSAM_PRIORITY_IDLE, "Process ages to JETSAM_PRIORITY_IDLE");
561 }
562 
563 T_DECL(idle_aging_leaked_importance_boost,
564     "Idle aging with leaked importance boost")
565 {
566 	dt_helper_t helper = dt_child_helper("idle_age_timeout_importance_boost");
567 
568 	dt_run_helpers(&helper, 1, 80);
569 }
570 T_DECL(assertion_test_repetitive_non_dirty_tracking, "Scenario #1 - repetitive assertion priority on non-dirty-tracking process", T_META_TIMEOUT(60), T_META_ASROOT(true)) {
571 	/*
572 	 * Verify back-to-back assertion calls set assertion state as expected.
573 	 * false --> non-dirty-tracking process (like a typical app)
574 	 * false --> clean/dirty does not apply here
575 	 */
576 
577 	memorystatus_assertion_test_repetitive("Scenario #1", false, false);
578 }
579 
580 T_DECL(assertion_test_repetitive_dirty_tracking_clean, "Scenario #2 - repetitive assertion priority on clean dirty-tracking process", T_META_TIMEOUT(60), T_META_ASROOT(true)) {
581 	/*
582 	 * Verify back-to-back assertion calls set assertion state as expected.
583 	 * true --> dirty-tracking process (like a typical extension/widget)
584 	 * true --> start clean / inactive
585 	 * This will exercise idle-deferred paths.
586 	 */
587 	memorystatus_assertion_test_repetitive("Scenario #2", true, true);
588 }
589 
590 T_DECL(assertion_test_repetitive_dirty_tracking_dirty, "Scenario #3 - repetitive assertion priority on dirty dirty-tracking processes", T_META_TIMEOUT(60), T_META_ASROOT(true)) {
591 	/*
592 	 * Verify back-to-back assertion calls set assertion state as expected.
593 	 * true --> dirty-tracking process (like a typical extension/widget)
594 	 * false --> start dirty / active state
595 	 * This will exercise idle-deferred paths.
596 	 */
597 	memorystatus_assertion_test_repetitive("Scenario #3", true, false);
598 }
599 
600 
601 T_DECL(assertion_test_allow_idle_exit, "set assertion priorities on process supporting idle exit", T_META_TIMEOUT(360), T_META_ASROOT(true)) {
602 	memorystatus_assertion_test_allow_idle_exit();
603 }
604 
605 T_DECL(assertion_test_do_not_allow_idle_exit, "set assertion priorities on process no idle exit allowed", T_META_TIMEOUT(360), T_META_ASROOT(true)) {
606 	memorystatus_assertion_test_do_not_allow_idle_exit();
607 }
608 #endif /* TARGET_OS_OSX */
609 
610 T_DECL(daemon_memlimits,
611     "test that daemons have their memlimits set correctly according to dirtiness",
612     T_META_ENABLED(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR))
613 {
614 	int ret;
615 	const uint32_t memlimit_active = 6; /* 6 MB */
616 	const uint32_t memlimit_inactive = 4; /* 4 MB */
617 	pid_t pid = getpid();
618 
619 	set_priority(pid, JETSAM_PRIORITY_UI_SUPPORT, 0, false);
620 	set_memlimits(pid, memlimit_active, memlimit_inactive, true, true);
621 
622 	ret = proc_track_dirty(pid, PROC_DIRTY_TRACK | PROC_DIRTY_ALLOW_IDLE_EXIT | PROC_DIRTY_DEFER);
623 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "proc_track_dirty()");
624 
625 	check_properties(pid, JETSAM_PRIORITY_IDLE_DEFERRED, memlimit_active, 0x0,
626 	    false, "jetsam_test_daemon_memlimit - #1 post-track-dirty");
627 
628 	T_LOG("Sleeping for %d to allow idle-ageout.", IDLE_AGEOUT_S);
629 	sleep(IDLE_AGEOUT_S);
630 
631 	check_properties(pid, JETSAM_PRIORITY_IDLE, memlimit_inactive, 0x0, false,
632 	    "jetsam_test_daemon_memlimit - #4 post-sleep");
633 
634 	proc_set_dirty(pid, true);
635 
636 	check_properties(pid, JETSAM_PRIORITY_UI_SUPPORT, memlimit_active, 0x0,
637 	    false, "jetsam_test_daemon_memlimit - #2 post-set-dirty");
638 
639 	proc_set_dirty(pid, false);
640 
641 	check_properties(pid, JETSAM_PRIORITY_IDLE_DEFERRED, memlimit_active, 0x0,
642 	    false, "jetsam_test_daemon_memlimit - #3 post-clear-dirty");
643 
644 	T_LOG("Sleeping for %d s to allow idle-ageout.", IDLE_AGEOUT_S);
645 	sleep(IDLE_AGEOUT_S);
646 
647 	check_properties(pid, JETSAM_PRIORITY_IDLE, memlimit_inactive, 0x0, false,
648 	    "jetsam_test_daemon_memlimit - #4 post-sleep");
649 
650 	proc_set_dirty(pid, true);
651 
652 	check_properties(pid, JETSAM_PRIORITY_UI_SUPPORT, memlimit_active, 0x0,
653 	    false, "jetsam_test_daemon_memlimit - #5 post-set-dirty-2");
654 
655 	proc_set_dirty(pid, false);
656 
657 	check_properties(pid, JETSAM_PRIORITY_IDLE_DEFERRED, memlimit_active, 0x0, false,
658 	    "jetsam_test_daemon_memlimit - #6 post-clear-dirty-2");
659 }
660