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