Loading...
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <spawn.h>
#include <spawn_private.h>
#include <stdint.h>
#include <sys/sysctl.h>
#include <sys/spawn_internal.h>
#include <sys/kern_memorystatus.h>
#include <mach-o/dyld.h>

#include <darwintest.h>
#include <darwintest_utils.h>

#include "memorystatus_assertion_helpers.h"

T_GLOBAL_META(
	T_META_NAMESPACE("xnu.vm"),
	T_META_CHECK_LEAKS(false)
	);

extern char **environ;

/*
 * This test has multiple sub-tests that set and then verify jetsam priority transitions
 * as though they were driven by assertions. It uses the MEMORYSTATUS_CMD_SET_MEMLIMIT_PROPERTIES
 * version of the memorystatus_control() system call and specifically tests the use of the
 * MEMORYSTATUS_SET_PRIORITY_ASSERTION flag.
 *
 * The kernel will apply policy that chooses a maximum jetsam priority, resolving conflicts
 * between an assertion driven priority and clean/dirty transition policy.
 *
 * Processes that do not opt into dirty-tracking should behave as they always have.
 * This is the typical App transition behavior.
 *
 * Processes that do opt into dirty-tracking have more complex policy:
 * For example:
 * A MAX assertion priority will prevent a dirty process from transitioning to a clean
 * state if the process opts into idle-exit.
 *    See: memorystatus_schedule_idle_demotion_locked() where we note that
 *    the process isn't going to be making the trip to the lower bands.
 *
 * But a MAX assertion evaluation will not prevent a clean process from transition to dirty.
 * Assertion driven priorities should not change memory limits, they are expected to
 * just change a process's position in the jetsam priority bands.
 *
 * MEMORYSTATUS_CMD_xxx requires root (in the absence of entitlement).
 * Use T_META_ASROOT(true) to accomplish this.
 *
 * A note on test strategy.  It is not necessary to spawn a child to test these
 * assertion calls.   The test can act on itself, that is, it can make calls to
 * set and relinquish assertion state just like it can make calls to do dirty/clean
 * transitions.  Of course, in reality, we expect only runningboardd to manipulate
 * assertion based priorities.
 */

/*
 * New flag to tell kernel this is an assertion driven priority update.
 */
#ifndef MEMORYSTATUS_SET_PRIORITY_ASSERTION
#define MEMORYSTATUS_SET_PRIORITY_ASSERTION 0x1
#endif

static void
proc_will_set_clean(pid_t pid)
{
	proc_set_dirty(pid, false);
	T_LOG("pid[%d] --> now clean", pid);
	return;
}

static void
proc_will_set_dirty(pid_t pid)
{
	proc_set_dirty(pid, true);
	T_LOG("pid[%d] --> now dirty", pid);
	return;
}

#define kJetsamAgingPolicyNone                          (0)
#define kJetsamAgingPolicyLegacy                        (1)
#define kJetsamAgingPolicySysProcsReclaimedFirst        (2)
#define kJetsamAgingPolicyAppsReclaimedFirst            (3)
#define kJetsamAgingPolicyMax                           kJetsamAgingPolicyAppsReclaimedFirst

#ifndef kMemorystatusAssertion
#define kMemorystatusAssertion 0x40
#endif

/*
 * Make repetitive (eg: back-to-back) calls using MEMORYSTATUS_SET_PRIORITY_ASSERTION.
 * We know that runningboardd may try to relinquish its hold on an assertion priority
 * when it hasn't first set the assertion priority. The kernel must survive this
 * pattern even though it might be considered poor behavior on runningboardd's part.
 * When dirty tracking processes are involved, we are exercising the kernel's
 * idle-deferred paths. Only assertion state (whether or not assertion state is
 * set or relinquished) is verified in this round of tests.
 * Test is invoked three times:
 *	Scenario 1) as a non-dirty-tracking process  (like a typical app)
 *		relinquish assertion priority multiple times
 *		set same assertion priority multiple times.
 *	Scenario 2) setup a dirty-tracking process that is clean  (like a typical extension)
 *		relinquish assertion priority multiple times
 *		set same assertion priority multiple times.
 *	Scenario 3) setup dirty-tracking process that is dirty  (like a typical extension)
 *		relinquish assertion priority multiple times
 *		set same assertion priority multiple times.
 */

static void
memorystatus_assertion_test_repetitive(char *test, boolean_t turn_on_dirty_tracking, boolean_t start_clean)
{
	int count;
	int maxcount = 3;
	boolean_t verbose;
	uint32_t state;
	uint64_t user_data = 0;
	pid_t mypid = getpid();

	/* these values will remain fixed during testing */
	int             active_limit_mb = 35;   /* arbitrary */
	int             inactive_limit_mb = 25;  /* arbitrary */

	/* these values may vary during test */
	int             requestedpriority = 0;
	int             assertionpriority = 0;

	T_SETUPBEGIN;

	requestedpriority =  JETSAM_PRIORITY_UI_SUPPORT;
	assertionpriority =  JETSAM_PRIORITY_FOREGROUND;
	set_memlimits(mypid, active_limit_mb, inactive_limit_mb, true, true);
	set_priority(mypid, requestedpriority, 0, false);

	if (turn_on_dirty_tracking) {
		proc_track_dirty(mypid, (PROC_DIRTY_TRACK | PROC_DIRTY_ALLOW_IDLE_EXIT | PROC_DIRTY_DEFER));

		if (start_clean) {
			proc_will_set_clean(mypid);
		} else {
			proc_will_set_dirty(mypid);
		}
	} else {
		/*
		 * Do nothing.
		 * Acts like an app with no dirty tracking
		 * By default launches in the requested priority and is
		 * considered idle because it's below FG band.
		 */
	}


	verbose = false;
	(void)get_priority_props(mypid, verbose, NULL, NULL, NULL, NULL);

	/* log current setup state */
	T_LOG("SETUP STATE COMPLETE: Test %s", test);

	T_SETUPEND;

	int i;
	boolean_t ret;
	for (i = 0; i < 2; i++) {
		if (i == 1 && turn_on_dirty_tracking) {
			T_LOG("Avoid idle-deferred - sleeping for 20");
			sleep(20);

			if (start_clean) {
				proc_will_set_dirty(mypid);
			} else {
				proc_will_set_clean(mypid);
			}

			(void)get_priority_props(mypid, verbose, NULL, NULL, NULL, &state);
		}

		/*
		 * Relinquish assertion priority even though we don't
		 * currently hold an assertion priority.
		 */
		for (count = 0; count < maxcount; count++) {
			if (relinquish_assertion_priority(mypid, user_data)) {
				T_ASSERT_FAIL("relinquish_assertion_priority failed");
			}
		}

		/* Verify assertion state is relinquished */
		(void)get_priority_props(mypid, verbose, NULL, NULL, NULL, &state);

		ret = verify_assertion_state(state, ASSERTION_STATE_IS_RELINQUISHED);
		T_QUIET;
		T_ASSERT_TRUE(ret, "verify_assertion_state failed");



		/*
		 * Set an assertion priority multiple times in a row.
		 */
		for (count = 0; count < maxcount; count++) {
			if (set_assertion_priority(mypid, assertionpriority, user_data) != 0) {
				T_ASSERT_FAIL("set_assertion_priority failed");
			}
		}

		/* Verify state holds an assertion priority */
		(void)get_priority_props(mypid, verbose, NULL, NULL, NULL, &state);

		ret = verify_assertion_state(state, ASSERTION_STATE_IS_SET);
		T_QUIET;
		T_ASSERT_TRUE(ret, "verify_assertion_state failed");
	}
}

/*
 * Process is dirty tracking and opts into pressured exit.
 */
static void
memorystatus_assertion_test_allow_idle_exit()
{
	pid_t mypid = getpid();

	/* these values will remain fixed during testing */
	int active_limit_mb   = 35; /* arbitrary */
	int inactive_limit_mb = 25;  /* arbitrary */

	/* these values may vary during test */
	int requestedpriority = JETSAM_PRIORITY_UI_SUPPORT;

	T_SETUPBEGIN;

	set_memlimits(mypid, active_limit_mb, inactive_limit_mb, true, true);
	set_priority(mypid, requestedpriority, 0, false);

	proc_track_dirty(mypid, (PROC_DIRTY_TRACK | PROC_DIRTY_ALLOW_IDLE_EXIT | PROC_DIRTY_DEFER));

	proc_will_set_clean(mypid);

	(void)check_properties(mypid, JETSAM_PRIORITY_IDLE_DEFERRED, inactive_limit_mb, 0x0, ASSERTION_STATE_IS_RELINQUISHED, "Clean start");

	T_LOG("SETUP STATE COMPLETE");

	int g_jetsam_aging_policy = 0;
	/*
	 * Jetsam aging policy
	 * Failure to retrieve is not fatal.
	 */
	size_t size = sizeof(g_jetsam_aging_policy);
	if (sysctlbyname("kern.jetsam_aging_policy", &g_jetsam_aging_policy, &size, NULL, 0) != 0) {
		T_LOG(__func__, true, "Unable to retrieve jetsam aging policy (not fatal)");
	}

	T_SETUPEND;

	/*
	 * Relinquish assertion priority even though we don't hold it.  No change in state expected.
	 */
	T_LOG("********Test0 clean: no state change on relinquish");
	relinquish_assertion_priority(mypid, 0xF00D);
	(void)check_properties(mypid, JETSAM_PRIORITY_IDLE_DEFERRED, inactive_limit_mb, 0xF00D, ASSERTION_STATE_IS_RELINQUISHED, "Test0");

	T_LOG("********Test1 clean: deferred now assertion[10]");
	set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
	(void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, inactive_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test1");

	/* Test2 */
	T_LOG("********Test2 clean:  assertion[10 -> 3]");
	set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
	(void)check_properties(mypid, JETSAM_PRIORITY_BACKGROUND, inactive_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test2");

	/* Test3 */
	T_LOG("********Test3 clean: assertion[3 -> 0], but now deferred");
	relinquish_assertion_priority(mypid, 0xBEEF);
	(void)check_properties(mypid, JETSAM_PRIORITY_IDLE_DEFERRED, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test3");

	/* Test4 */
	T_LOG("********Test4 clean: deferred now assertion[10]");
	set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
	(void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, inactive_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test4");

	T_LOG("Avoid idle-deferred moving forward. Sleeping for 20");
	sleep(20);

	/* Test5 */
	T_LOG("********Test5 dirty: set dirty priority but assertion[10] prevails");
	proc_will_set_dirty(mypid);   /* active priority is less than FG*/
	(void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test5");

	/* Test6 */
	T_LOG("********Test6 dirty: assertion[10 -> 3] but dirty priority prevails");
	set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFEEB);  /* active priority is > BG */
	(void)check_properties(mypid, JETSAM_PRIORITY_UI_SUPPORT, active_limit_mb, 0xFEEB, ASSERTION_STATE_IS_SET, "Test6");

	/* Test7 */
	T_LOG("********Test7 dirty: assertion[3 -> 0] but dirty prevails");
	relinquish_assertion_priority(mypid, 0xBEEF);
	(void)check_properties(mypid, JETSAM_PRIORITY_UI_SUPPORT, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test7");


	/* Test8 */
	T_LOG("********Test8 dirty: assertion[0 -> 10] overrides dirty");
	set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
	(void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test8");

	/* Test9 */
	T_LOG("********Test9 dirty wants to go clean, but clean state is prevented as assertion[10] prevails");
	proc_will_set_clean(mypid);
	(void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test9");

	/* Test10 */
	T_LOG("********Test10 dirty goes dirty and stays dirty, and assertion[10] prevails again");
	proc_will_set_dirty(mypid);
	(void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test10");

	/* Test11 */
	T_LOG("********Test11 dirty: assertion[10 -> 3] but dirty prevails");
	set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
	(void)check_properties(mypid, JETSAM_PRIORITY_UI_SUPPORT, active_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test11");

	/* Test12 */
	T_LOG("********Test12 dirty: assertion[3 -> 0] but dirty prevails");
	relinquish_assertion_priority(mypid, 0xBEEF);
	(void)check_properties(mypid, JETSAM_PRIORITY_UI_SUPPORT, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test12");


	/* Test13 */
	T_LOG("********Test13 dirty goes clean: both assertion[0] and clean");
	proc_will_set_clean(mypid);
	if (g_jetsam_aging_policy == kJetsamAgingPolicySysProcsReclaimedFirst) {
		/* For sysproc aging policy the daemon should be at idle deferred and with an active memory limit */
		(void)check_properties(mypid, JETSAM_PRIORITY_IDLE_DEFERRED, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test13");
	} else {
		/* For the legacy aging policy, daemon should be at idle band with inactive memory limit */
		(void)check_properties(mypid, JETSAM_PRIORITY_IDLE, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test13");
	}
}

/*
 * Process is dirty tracking and does not opt into pressured exit.
 * This test lives above Foreground.  Assertions will have no affect
 * except where the assertion priority bumps it above the requested priority.
 */
static void
memorystatus_assertion_test_do_not_allow_idle_exit()
{
	pid_t mypid = getpid();

	/* these values will remain fixed during testing */
	int             active_limit_mb = 35;   /* arbitrary */
	int             inactive_limit_mb = 25;  /* arbitrary */
	int             requestedpriority = JETSAM_PRIORITY_AUDIO_AND_ACCESSORY;

	T_SETUPBEGIN;

	set_memlimits(mypid, active_limit_mb, inactive_limit_mb, true, true);
	set_priority(mypid, requestedpriority, 0, false);
	proc_track_dirty(mypid, (PROC_DIRTY_TRACK));

	proc_will_set_dirty(mypid);

	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0x0, ASSERTION_STATE_IS_RELINQUISHED, "Dirty start");

	proc_will_set_clean(mypid);

	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0x0, ASSERTION_STATE_IS_RELINQUISHED, "Clean transition");

	T_LOG("SETUP STATE COMPLETE");

	T_SETUPEND;

	/*
	 * Relinquish assertion priority even though we don't hold it.  No change in state expected.
	 */


	/* Test0 */
	T_LOG("********Test0 clean: no state change on relinquish");
	relinquish_assertion_priority(mypid, 0xF00D);
	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xF00D, ASSERTION_STATE_IS_RELINQUISHED, "Test0");

	/* Test1 */
	T_LOG("********Test1 clean: assertion[0 -> 10] but inactive priority prevails");
	set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test1");

	/* Test2 */
	T_LOG("********Test2 clean:  assertion[10 -> 3] but inactive priority prevails");
	set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test2");

	/* Test3 */
	T_LOG("********Test3 clean: assertion[3 -> 0], but inactive priority prevails");
	relinquish_assertion_priority(mypid, 0xBEEF);
	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test3");

	/* Test4 */
	T_LOG("********Test4 go dirty: assertion[0] has no affect, active priority prevails");
	proc_will_set_dirty(mypid);
	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test4");

	/* Test5 */
	T_LOG("********Test5 dirty: assertion[0 -> 10] active priority prevails");
	set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test5");

	/* Test6 */
	T_LOG("********Test6 dirty:  assertion[10 -> 3] active priority prevails");
	set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test6");

	/* Test 7 */
	T_LOG("********Test7 dirty: assertion[3 -> 0], active priority prevails");
	relinquish_assertion_priority(mypid, 0xBEEF);
	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test7");

	/* Test8 */
	T_LOG("********Test8 dirty: assertion[0 -> 19], dirty but now assertion[19] prevails");
	set_assertion_priority(mypid, JETSAM_PRIORITY_CRITICAL, 0xFEED);
	(void)check_properties(mypid, JETSAM_PRIORITY_CRITICAL, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test8");


	/* Test9 */
	T_LOG("********Test9 go clean: inactive priority but assertion[19] prevails");
	proc_will_set_clean(mypid);
	(void)check_properties(mypid, JETSAM_PRIORITY_CRITICAL, inactive_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test9");

	/* Test10 */
	T_LOG("********Test10 clean:  assertion[19 -> 3] inactive limit prevails");
	set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test10");


	/* Test11 */
	T_LOG("********Test11 clean:  assertion[3 -> 0] inactive priority still prevails");
	relinquish_assertion_priority(mypid, 0xBEEF);
	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test11");

	/* Test12 */
	T_LOG("********Test12 dirty goes clean: both assertion[0] and clean");
	proc_will_set_clean(mypid);
	(void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test12");
}

T_DECL(assertion_test_bad_flags, "verify bad flag returns an error", T_META_TIMEOUT(30), T_META_ASROOT(true)) {
	int err;
	uint32_t flag = 0;

	memorystatus_priority_properties_t mjp = { 0 };

	mjp.priority = JETSAM_PRIORITY_FOREGROUND;
	mjp.user_data = 0;

	/*
	 * init a bad flag
	 */

	flag = 0xf;

	err = memorystatus_control(MEMORYSTATUS_CMD_SET_PRIORITY_PROPERTIES, getpid(), flag, &mjp, sizeof(mjp));

	T_QUIET;
	T_ASSERT_POSIX_FAILURE(err, EINVAL, "MEMORYSTATUS_CMD_SET_PRIORITY_PROPERTIES should fail with bad flags (err=%d)", err);
}


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)) {
	/*
	 * Verify back-to-back assertion calls set assertion state as expected.
	 * false --> non-dirty-tracking process (like a typical app)
	 * false --> clean/dirty does not apply here
	 */

	memorystatus_assertion_test_repetitive("Scenario #1", false, false);
}

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)) {
	/*
	 * Verify back-to-back assertion calls set assertion state as expected.
	 * true --> dirty-tracking process (like a typical extension/widget)
	 * true --> start clean / inactive
	 * This will exercise idle-deferred paths.
	 */
	memorystatus_assertion_test_repetitive("Scenario #2", true, true);
}

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)) {
	/*
	 * Verify back-to-back assertion calls set assertion state as expected.
	 * true --> dirty-tracking process (like a typical extension/widget)
	 * false --> start dirty / active state
	 * This will exercise idle-deferred paths.
	 */
	memorystatus_assertion_test_repetitive("Scenario #3", true, false);
}


T_DECL(assertion_test_allow_idle_exit, "set assertion priorities on process supporting idle exit", T_META_TIMEOUT(360), T_META_ASROOT(true)) {
	memorystatus_assertion_test_allow_idle_exit();
}

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)) {
	memorystatus_assertion_test_do_not_allow_idle_exit();
}