1*d8b80295SApple OSS Distributions #include <stdio.h>
2*d8b80295SApple OSS Distributions #include <unistd.h>
3*d8b80295SApple OSS Distributions #include <stdlib.h>
4*d8b80295SApple OSS Distributions #include <errno.h>
5*d8b80295SApple OSS Distributions #include <string.h>
6*d8b80295SApple OSS Distributions #include <assert.h>
7*d8b80295SApple OSS Distributions #include <signal.h>
8*d8b80295SApple OSS Distributions #include <spawn.h>
9*d8b80295SApple OSS Distributions #include <spawn_private.h>
10*d8b80295SApple OSS Distributions #include <stdint.h>
11*d8b80295SApple OSS Distributions #include <sys/sysctl.h>
12*d8b80295SApple OSS Distributions #include <sys/spawn_internal.h>
13*d8b80295SApple OSS Distributions #include <sys/kern_memorystatus.h>
14*d8b80295SApple OSS Distributions #include <mach-o/dyld.h>
15*d8b80295SApple OSS Distributions
16*d8b80295SApple OSS Distributions #include <darwintest.h>
17*d8b80295SApple OSS Distributions #include <darwintest_utils.h>
18*d8b80295SApple OSS Distributions
19*d8b80295SApple OSS Distributions #include "memorystatus_assertion_helpers.h"
20*d8b80295SApple OSS Distributions
21*d8b80295SApple OSS Distributions T_GLOBAL_META(
22*d8b80295SApple OSS Distributions T_META_NAMESPACE("xnu.vm"),
23*d8b80295SApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"),
24*d8b80295SApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("VM"),
25*d8b80295SApple OSS Distributions T_META_CHECK_LEAKS(false)
26*d8b80295SApple OSS Distributions );
27*d8b80295SApple OSS Distributions
28*d8b80295SApple OSS Distributions extern char **environ;
29*d8b80295SApple OSS Distributions
30*d8b80295SApple OSS Distributions /*
31*d8b80295SApple OSS Distributions * This test has multiple sub-tests that set and then verify jetsam priority transitions
32*d8b80295SApple OSS Distributions * as though they were driven by assertions. It uses the MEMORYSTATUS_CMD_SET_MEMLIMIT_PROPERTIES
33*d8b80295SApple OSS Distributions * version of the memorystatus_control() system call and specifically tests the use of the
34*d8b80295SApple OSS Distributions * MEMORYSTATUS_SET_PRIORITY_ASSERTION flag.
35*d8b80295SApple OSS Distributions *
36*d8b80295SApple OSS Distributions * The kernel will apply policy that chooses a maximum jetsam priority, resolving conflicts
37*d8b80295SApple OSS Distributions * between an assertion driven priority and clean/dirty transition policy.
38*d8b80295SApple OSS Distributions *
39*d8b80295SApple OSS Distributions * Processes that do not opt into dirty-tracking should behave as they always have.
40*d8b80295SApple OSS Distributions * This is the typical App transition behavior.
41*d8b80295SApple OSS Distributions *
42*d8b80295SApple OSS Distributions * Processes that do opt into dirty-tracking have more complex policy:
43*d8b80295SApple OSS Distributions * For example:
44*d8b80295SApple OSS Distributions * A MAX assertion priority will prevent a dirty process from transitioning to a clean
45*d8b80295SApple OSS Distributions * state if the process opts into idle-exit.
46*d8b80295SApple OSS Distributions * See: memorystatus_schedule_idle_demotion_locked() where we note that
47*d8b80295SApple OSS Distributions * the process isn't going to be making the trip to the lower bands.
48*d8b80295SApple OSS Distributions *
49*d8b80295SApple OSS Distributions * But a MAX assertion evaluation will not prevent a clean process from transition to dirty.
50*d8b80295SApple OSS Distributions * Assertion driven priorities should not change memory limits, they are expected to
51*d8b80295SApple OSS Distributions * just change a process's position in the jetsam priority bands.
52*d8b80295SApple OSS Distributions *
53*d8b80295SApple OSS Distributions * MEMORYSTATUS_CMD_xxx requires root (in the absence of entitlement).
54*d8b80295SApple OSS Distributions * Use T_META_ASROOT(true) to accomplish this.
55*d8b80295SApple OSS Distributions *
56*d8b80295SApple OSS Distributions * A note on test strategy. It is not necessary to spawn a child to test these
57*d8b80295SApple OSS Distributions * assertion calls. The test can act on itself, that is, it can make calls to
58*d8b80295SApple OSS Distributions * set and relinquish assertion state just like it can make calls to do dirty/clean
59*d8b80295SApple OSS Distributions * transitions. Of course, in reality, we expect only runningboardd to manipulate
60*d8b80295SApple OSS Distributions * assertion based priorities.
61*d8b80295SApple OSS Distributions */
62*d8b80295SApple OSS Distributions
63*d8b80295SApple OSS Distributions /*
64*d8b80295SApple OSS Distributions * New flag to tell kernel this is an assertion driven priority update.
65*d8b80295SApple OSS Distributions */
66*d8b80295SApple OSS Distributions #ifndef MEMORYSTATUS_SET_PRIORITY_ASSERTION
67*d8b80295SApple OSS Distributions #define MEMORYSTATUS_SET_PRIORITY_ASSERTION 0x1
68*d8b80295SApple OSS Distributions #endif
69*d8b80295SApple OSS Distributions
70*d8b80295SApple OSS Distributions static void
proc_will_set_clean(pid_t pid)71*d8b80295SApple OSS Distributions proc_will_set_clean(pid_t pid)
72*d8b80295SApple OSS Distributions {
73*d8b80295SApple OSS Distributions proc_set_dirty(pid, false);
74*d8b80295SApple OSS Distributions T_LOG("pid[%d] --> now clean", pid);
75*d8b80295SApple OSS Distributions return;
76*d8b80295SApple OSS Distributions }
77*d8b80295SApple OSS Distributions
78*d8b80295SApple OSS Distributions static void
proc_will_set_dirty(pid_t pid)79*d8b80295SApple OSS Distributions proc_will_set_dirty(pid_t pid)
80*d8b80295SApple OSS Distributions {
81*d8b80295SApple OSS Distributions proc_set_dirty(pid, true);
82*d8b80295SApple OSS Distributions T_LOG("pid[%d] --> now dirty", pid);
83*d8b80295SApple OSS Distributions return;
84*d8b80295SApple OSS Distributions }
85*d8b80295SApple OSS Distributions
86*d8b80295SApple OSS Distributions #define kJetsamAgingPolicyNone (0)
87*d8b80295SApple OSS Distributions #define kJetsamAgingPolicyLegacy (1)
88*d8b80295SApple OSS Distributions #define kJetsamAgingPolicySysProcsReclaimedFirst (2)
89*d8b80295SApple OSS Distributions #define kJetsamAgingPolicyAppsReclaimedFirst (3)
90*d8b80295SApple OSS Distributions #define kJetsamAgingPolicyMax kJetsamAgingPolicyAppsReclaimedFirst
91*d8b80295SApple OSS Distributions
92*d8b80295SApple OSS Distributions #ifndef kMemorystatusAssertion
93*d8b80295SApple OSS Distributions #define kMemorystatusAssertion 0x40
94*d8b80295SApple OSS Distributions #endif
95*d8b80295SApple OSS Distributions
96*d8b80295SApple OSS Distributions /*
97*d8b80295SApple OSS Distributions * Make repetitive (eg: back-to-back) calls using MEMORYSTATUS_SET_PRIORITY_ASSERTION.
98*d8b80295SApple OSS Distributions * We know that runningboardd may try to relinquish its hold on an assertion priority
99*d8b80295SApple OSS Distributions * when it hasn't first set the assertion priority. The kernel must survive this
100*d8b80295SApple OSS Distributions * pattern even though it might be considered poor behavior on runningboardd's part.
101*d8b80295SApple OSS Distributions * When dirty tracking processes are involved, we are exercising the kernel's
102*d8b80295SApple OSS Distributions * idle-deferred paths. Only assertion state (whether or not assertion state is
103*d8b80295SApple OSS Distributions * set or relinquished) is verified in this round of tests.
104*d8b80295SApple OSS Distributions * Test is invoked three times:
105*d8b80295SApple OSS Distributions * Scenario 1) as a non-dirty-tracking process (like a typical app)
106*d8b80295SApple OSS Distributions * relinquish assertion priority multiple times
107*d8b80295SApple OSS Distributions * set same assertion priority multiple times.
108*d8b80295SApple OSS Distributions * Scenario 2) setup a dirty-tracking process that is clean (like a typical extension)
109*d8b80295SApple OSS Distributions * relinquish assertion priority multiple times
110*d8b80295SApple OSS Distributions * set same assertion priority multiple times.
111*d8b80295SApple OSS Distributions * Scenario 3) setup dirty-tracking process that is dirty (like a typical extension)
112*d8b80295SApple OSS Distributions * relinquish assertion priority multiple times
113*d8b80295SApple OSS Distributions * set same assertion priority multiple times.
114*d8b80295SApple OSS Distributions */
115*d8b80295SApple OSS Distributions
116*d8b80295SApple OSS Distributions static void
memorystatus_assertion_test_repetitive(char * test,boolean_t turn_on_dirty_tracking,boolean_t start_clean)117*d8b80295SApple OSS Distributions memorystatus_assertion_test_repetitive(char *test, boolean_t turn_on_dirty_tracking, boolean_t start_clean)
118*d8b80295SApple OSS Distributions {
119*d8b80295SApple OSS Distributions int count;
120*d8b80295SApple OSS Distributions int maxcount = 3;
121*d8b80295SApple OSS Distributions boolean_t verbose;
122*d8b80295SApple OSS Distributions uint32_t state;
123*d8b80295SApple OSS Distributions uint64_t user_data = 0;
124*d8b80295SApple OSS Distributions pid_t mypid = getpid();
125*d8b80295SApple OSS Distributions
126*d8b80295SApple OSS Distributions /* these values will remain fixed during testing */
127*d8b80295SApple OSS Distributions int active_limit_mb = 35; /* arbitrary */
128*d8b80295SApple OSS Distributions int inactive_limit_mb = 25; /* arbitrary */
129*d8b80295SApple OSS Distributions
130*d8b80295SApple OSS Distributions /* these values may vary during test */
131*d8b80295SApple OSS Distributions int requestedpriority = 0;
132*d8b80295SApple OSS Distributions int assertionpriority = 0;
133*d8b80295SApple OSS Distributions
134*d8b80295SApple OSS Distributions T_SETUPBEGIN;
135*d8b80295SApple OSS Distributions
136*d8b80295SApple OSS Distributions requestedpriority = JETSAM_PRIORITY_UI_SUPPORT;
137*d8b80295SApple OSS Distributions assertionpriority = JETSAM_PRIORITY_FOREGROUND;
138*d8b80295SApple OSS Distributions set_memlimits(mypid, active_limit_mb, inactive_limit_mb, true, true);
139*d8b80295SApple OSS Distributions set_priority(mypid, requestedpriority, 0, false);
140*d8b80295SApple OSS Distributions
141*d8b80295SApple OSS Distributions if (turn_on_dirty_tracking) {
142*d8b80295SApple OSS Distributions proc_track_dirty(mypid, (PROC_DIRTY_TRACK | PROC_DIRTY_ALLOW_IDLE_EXIT | PROC_DIRTY_DEFER));
143*d8b80295SApple OSS Distributions
144*d8b80295SApple OSS Distributions if (start_clean) {
145*d8b80295SApple OSS Distributions proc_will_set_clean(mypid);
146*d8b80295SApple OSS Distributions } else {
147*d8b80295SApple OSS Distributions proc_will_set_dirty(mypid);
148*d8b80295SApple OSS Distributions }
149*d8b80295SApple OSS Distributions } else {
150*d8b80295SApple OSS Distributions /*
151*d8b80295SApple OSS Distributions * Do nothing.
152*d8b80295SApple OSS Distributions * Acts like an app with no dirty tracking
153*d8b80295SApple OSS Distributions * By default launches in the requested priority and is
154*d8b80295SApple OSS Distributions * considered idle because it's below FG band.
155*d8b80295SApple OSS Distributions */
156*d8b80295SApple OSS Distributions }
157*d8b80295SApple OSS Distributions
158*d8b80295SApple OSS Distributions
159*d8b80295SApple OSS Distributions verbose = false;
160*d8b80295SApple OSS Distributions (void)get_priority_props(mypid, verbose, NULL, NULL, NULL, NULL);
161*d8b80295SApple OSS Distributions
162*d8b80295SApple OSS Distributions /* log current setup state */
163*d8b80295SApple OSS Distributions T_LOG("SETUP STATE COMPLETE: Test %s", test);
164*d8b80295SApple OSS Distributions
165*d8b80295SApple OSS Distributions T_SETUPEND;
166*d8b80295SApple OSS Distributions
167*d8b80295SApple OSS Distributions int i;
168*d8b80295SApple OSS Distributions boolean_t ret;
169*d8b80295SApple OSS Distributions for (i = 0; i < 2; i++) {
170*d8b80295SApple OSS Distributions if (i == 1 && turn_on_dirty_tracking) {
171*d8b80295SApple OSS Distributions T_LOG("Avoid idle-deferred - sleeping for 20");
172*d8b80295SApple OSS Distributions sleep(20);
173*d8b80295SApple OSS Distributions
174*d8b80295SApple OSS Distributions if (start_clean) {
175*d8b80295SApple OSS Distributions proc_will_set_dirty(mypid);
176*d8b80295SApple OSS Distributions } else {
177*d8b80295SApple OSS Distributions proc_will_set_clean(mypid);
178*d8b80295SApple OSS Distributions }
179*d8b80295SApple OSS Distributions
180*d8b80295SApple OSS Distributions (void)get_priority_props(mypid, verbose, NULL, NULL, NULL, &state);
181*d8b80295SApple OSS Distributions }
182*d8b80295SApple OSS Distributions
183*d8b80295SApple OSS Distributions /*
184*d8b80295SApple OSS Distributions * Relinquish assertion priority even though we don't
185*d8b80295SApple OSS Distributions * currently hold an assertion priority.
186*d8b80295SApple OSS Distributions */
187*d8b80295SApple OSS Distributions for (count = 0; count < maxcount; count++) {
188*d8b80295SApple OSS Distributions if (relinquish_assertion_priority(mypid, user_data)) {
189*d8b80295SApple OSS Distributions T_ASSERT_FAIL("relinquish_assertion_priority failed");
190*d8b80295SApple OSS Distributions }
191*d8b80295SApple OSS Distributions }
192*d8b80295SApple OSS Distributions
193*d8b80295SApple OSS Distributions /* Verify assertion state is relinquished */
194*d8b80295SApple OSS Distributions (void)get_priority_props(mypid, verbose, NULL, NULL, NULL, &state);
195*d8b80295SApple OSS Distributions
196*d8b80295SApple OSS Distributions ret = verify_assertion_state(state, ASSERTION_STATE_IS_RELINQUISHED);
197*d8b80295SApple OSS Distributions T_QUIET;
198*d8b80295SApple OSS Distributions T_ASSERT_TRUE(ret, "verify_assertion_state failed");
199*d8b80295SApple OSS Distributions
200*d8b80295SApple OSS Distributions
201*d8b80295SApple OSS Distributions
202*d8b80295SApple OSS Distributions /*
203*d8b80295SApple OSS Distributions * Set an assertion priority multiple times in a row.
204*d8b80295SApple OSS Distributions */
205*d8b80295SApple OSS Distributions for (count = 0; count < maxcount; count++) {
206*d8b80295SApple OSS Distributions if (set_assertion_priority(mypid, assertionpriority, user_data) != 0) {
207*d8b80295SApple OSS Distributions T_ASSERT_FAIL("set_assertion_priority failed");
208*d8b80295SApple OSS Distributions }
209*d8b80295SApple OSS Distributions }
210*d8b80295SApple OSS Distributions
211*d8b80295SApple OSS Distributions /* Verify state holds an assertion priority */
212*d8b80295SApple OSS Distributions (void)get_priority_props(mypid, verbose, NULL, NULL, NULL, &state);
213*d8b80295SApple OSS Distributions
214*d8b80295SApple OSS Distributions ret = verify_assertion_state(state, ASSERTION_STATE_IS_SET);
215*d8b80295SApple OSS Distributions T_QUIET;
216*d8b80295SApple OSS Distributions T_ASSERT_TRUE(ret, "verify_assertion_state failed");
217*d8b80295SApple OSS Distributions }
218*d8b80295SApple OSS Distributions }
219*d8b80295SApple OSS Distributions
220*d8b80295SApple OSS Distributions /*
221*d8b80295SApple OSS Distributions * Process is dirty tracking and opts into pressured exit.
222*d8b80295SApple OSS Distributions */
223*d8b80295SApple OSS Distributions static void
memorystatus_assertion_test_allow_idle_exit()224*d8b80295SApple OSS Distributions memorystatus_assertion_test_allow_idle_exit()
225*d8b80295SApple OSS Distributions {
226*d8b80295SApple OSS Distributions pid_t mypid = getpid();
227*d8b80295SApple OSS Distributions
228*d8b80295SApple OSS Distributions /* these values will remain fixed during testing */
229*d8b80295SApple OSS Distributions int active_limit_mb = 35; /* arbitrary */
230*d8b80295SApple OSS Distributions int inactive_limit_mb = 25; /* arbitrary */
231*d8b80295SApple OSS Distributions
232*d8b80295SApple OSS Distributions /* these values may vary during test */
233*d8b80295SApple OSS Distributions int requestedpriority = JETSAM_PRIORITY_UI_SUPPORT;
234*d8b80295SApple OSS Distributions
235*d8b80295SApple OSS Distributions T_SETUPBEGIN;
236*d8b80295SApple OSS Distributions
237*d8b80295SApple OSS Distributions set_memlimits(mypid, active_limit_mb, inactive_limit_mb, true, true);
238*d8b80295SApple OSS Distributions set_priority(mypid, requestedpriority, 0, false);
239*d8b80295SApple OSS Distributions
240*d8b80295SApple OSS Distributions proc_track_dirty(mypid, (PROC_DIRTY_TRACK | PROC_DIRTY_ALLOW_IDLE_EXIT | PROC_DIRTY_DEFER));
241*d8b80295SApple OSS Distributions
242*d8b80295SApple OSS Distributions proc_will_set_clean(mypid);
243*d8b80295SApple OSS Distributions
244*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_IDLE_DEFERRED, inactive_limit_mb, 0x0, ASSERTION_STATE_IS_RELINQUISHED, "Clean start");
245*d8b80295SApple OSS Distributions
246*d8b80295SApple OSS Distributions T_LOG("SETUP STATE COMPLETE");
247*d8b80295SApple OSS Distributions
248*d8b80295SApple OSS Distributions int g_jetsam_aging_policy = 0;
249*d8b80295SApple OSS Distributions /*
250*d8b80295SApple OSS Distributions * Jetsam aging policy
251*d8b80295SApple OSS Distributions * Failure to retrieve is not fatal.
252*d8b80295SApple OSS Distributions */
253*d8b80295SApple OSS Distributions size_t size = sizeof(g_jetsam_aging_policy);
254*d8b80295SApple OSS Distributions if (sysctlbyname("kern.jetsam_aging_policy", &g_jetsam_aging_policy, &size, NULL, 0) != 0) {
255*d8b80295SApple OSS Distributions T_LOG(__func__, true, "Unable to retrieve jetsam aging policy (not fatal)");
256*d8b80295SApple OSS Distributions }
257*d8b80295SApple OSS Distributions
258*d8b80295SApple OSS Distributions T_SETUPEND;
259*d8b80295SApple OSS Distributions
260*d8b80295SApple OSS Distributions /*
261*d8b80295SApple OSS Distributions * Relinquish assertion priority even though we don't hold it. No change in state expected.
262*d8b80295SApple OSS Distributions */
263*d8b80295SApple OSS Distributions T_LOG("********Test0 clean: no state change on relinquish");
264*d8b80295SApple OSS Distributions relinquish_assertion_priority(mypid, 0xF00D);
265*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_IDLE_DEFERRED, inactive_limit_mb, 0xF00D, ASSERTION_STATE_IS_RELINQUISHED, "Test0");
266*d8b80295SApple OSS Distributions
267*d8b80295SApple OSS Distributions T_LOG("********Test1 clean: deferred now assertion[10]");
268*d8b80295SApple OSS Distributions set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
269*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, inactive_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test1");
270*d8b80295SApple OSS Distributions
271*d8b80295SApple OSS Distributions /* Test2 */
272*d8b80295SApple OSS Distributions T_LOG("********Test2 clean: assertion[10 -> 3]");
273*d8b80295SApple OSS Distributions set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
274*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_BACKGROUND, inactive_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test2");
275*d8b80295SApple OSS Distributions
276*d8b80295SApple OSS Distributions /* Test3 */
277*d8b80295SApple OSS Distributions T_LOG("********Test3 clean: assertion[3 -> 0], but now deferred");
278*d8b80295SApple OSS Distributions relinquish_assertion_priority(mypid, 0xBEEF);
279*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_IDLE_DEFERRED, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test3");
280*d8b80295SApple OSS Distributions
281*d8b80295SApple OSS Distributions /* Test4 */
282*d8b80295SApple OSS Distributions T_LOG("********Test4 clean: deferred now assertion[10]");
283*d8b80295SApple OSS Distributions set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
284*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, inactive_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test4");
285*d8b80295SApple OSS Distributions
286*d8b80295SApple OSS Distributions T_LOG("Avoid idle-deferred moving forward. Sleeping for 20");
287*d8b80295SApple OSS Distributions sleep(20);
288*d8b80295SApple OSS Distributions
289*d8b80295SApple OSS Distributions /* Test5 */
290*d8b80295SApple OSS Distributions T_LOG("********Test5 dirty: set dirty priority but assertion[10] prevails");
291*d8b80295SApple OSS Distributions proc_will_set_dirty(mypid); /* active priority is less than FG*/
292*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test5");
293*d8b80295SApple OSS Distributions
294*d8b80295SApple OSS Distributions /* Test6 */
295*d8b80295SApple OSS Distributions T_LOG("********Test6 dirty: assertion[10 -> 3] but dirty priority prevails");
296*d8b80295SApple OSS Distributions set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFEEB); /* active priority is > BG */
297*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_UI_SUPPORT, active_limit_mb, 0xFEEB, ASSERTION_STATE_IS_SET, "Test6");
298*d8b80295SApple OSS Distributions
299*d8b80295SApple OSS Distributions /* Test7 */
300*d8b80295SApple OSS Distributions T_LOG("********Test7 dirty: assertion[3 -> 0] but dirty prevails");
301*d8b80295SApple OSS Distributions relinquish_assertion_priority(mypid, 0xBEEF);
302*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_UI_SUPPORT, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test7");
303*d8b80295SApple OSS Distributions
304*d8b80295SApple OSS Distributions
305*d8b80295SApple OSS Distributions /* Test8 */
306*d8b80295SApple OSS Distributions T_LOG("********Test8 dirty: assertion[0 -> 10] overrides dirty");
307*d8b80295SApple OSS Distributions set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
308*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test8");
309*d8b80295SApple OSS Distributions
310*d8b80295SApple OSS Distributions /* Test9 */
311*d8b80295SApple OSS Distributions T_LOG("********Test9 dirty wants to go clean, but clean state is prevented as assertion[10] prevails");
312*d8b80295SApple OSS Distributions proc_will_set_clean(mypid);
313*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test9");
314*d8b80295SApple OSS Distributions
315*d8b80295SApple OSS Distributions /* Test10 */
316*d8b80295SApple OSS Distributions T_LOG("********Test10 dirty goes dirty and stays dirty, and assertion[10] prevails again");
317*d8b80295SApple OSS Distributions proc_will_set_dirty(mypid);
318*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test10");
319*d8b80295SApple OSS Distributions
320*d8b80295SApple OSS Distributions /* Test11 */
321*d8b80295SApple OSS Distributions T_LOG("********Test11 dirty: assertion[10 -> 3] but dirty prevails");
322*d8b80295SApple OSS Distributions set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
323*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_UI_SUPPORT, active_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test11");
324*d8b80295SApple OSS Distributions
325*d8b80295SApple OSS Distributions /* Test12 */
326*d8b80295SApple OSS Distributions T_LOG("********Test12 dirty: assertion[3 -> 0] but dirty prevails");
327*d8b80295SApple OSS Distributions relinquish_assertion_priority(mypid, 0xBEEF);
328*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_UI_SUPPORT, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test12");
329*d8b80295SApple OSS Distributions
330*d8b80295SApple OSS Distributions
331*d8b80295SApple OSS Distributions /* Test13 */
332*d8b80295SApple OSS Distributions T_LOG("********Test13 dirty goes clean: both assertion[0] and clean");
333*d8b80295SApple OSS Distributions proc_will_set_clean(mypid);
334*d8b80295SApple OSS Distributions if (g_jetsam_aging_policy == kJetsamAgingPolicySysProcsReclaimedFirst) {
335*d8b80295SApple OSS Distributions /* For sysproc aging policy the daemon should be at idle deferred and with an active memory limit */
336*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_IDLE_DEFERRED, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test13");
337*d8b80295SApple OSS Distributions } else {
338*d8b80295SApple OSS Distributions /* For the legacy aging policy, daemon should be at idle band with inactive memory limit */
339*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_IDLE, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test13");
340*d8b80295SApple OSS Distributions }
341*d8b80295SApple OSS Distributions }
342*d8b80295SApple OSS Distributions
343*d8b80295SApple OSS Distributions /*
344*d8b80295SApple OSS Distributions * Process is dirty tracking and does not opt into pressured exit.
345*d8b80295SApple OSS Distributions * This test lives above Foreground. Assertions will have no affect
346*d8b80295SApple OSS Distributions * except where the assertion priority bumps it above the requested priority.
347*d8b80295SApple OSS Distributions */
348*d8b80295SApple OSS Distributions static void
memorystatus_assertion_test_do_not_allow_idle_exit()349*d8b80295SApple OSS Distributions memorystatus_assertion_test_do_not_allow_idle_exit()
350*d8b80295SApple OSS Distributions {
351*d8b80295SApple OSS Distributions pid_t mypid = getpid();
352*d8b80295SApple OSS Distributions
353*d8b80295SApple OSS Distributions /* these values will remain fixed during testing */
354*d8b80295SApple OSS Distributions int active_limit_mb = 35; /* arbitrary */
355*d8b80295SApple OSS Distributions int inactive_limit_mb = 25; /* arbitrary */
356*d8b80295SApple OSS Distributions int requestedpriority = JETSAM_PRIORITY_AUDIO_AND_ACCESSORY;
357*d8b80295SApple OSS Distributions
358*d8b80295SApple OSS Distributions T_SETUPBEGIN;
359*d8b80295SApple OSS Distributions
360*d8b80295SApple OSS Distributions set_memlimits(mypid, active_limit_mb, inactive_limit_mb, true, true);
361*d8b80295SApple OSS Distributions set_priority(mypid, requestedpriority, 0, false);
362*d8b80295SApple OSS Distributions proc_track_dirty(mypid, (PROC_DIRTY_TRACK));
363*d8b80295SApple OSS Distributions
364*d8b80295SApple OSS Distributions proc_will_set_dirty(mypid);
365*d8b80295SApple OSS Distributions
366*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0x0, ASSERTION_STATE_IS_RELINQUISHED, "Dirty start");
367*d8b80295SApple OSS Distributions
368*d8b80295SApple OSS Distributions proc_will_set_clean(mypid);
369*d8b80295SApple OSS Distributions
370*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0x0, ASSERTION_STATE_IS_RELINQUISHED, "Clean transition");
371*d8b80295SApple OSS Distributions
372*d8b80295SApple OSS Distributions T_LOG("SETUP STATE COMPLETE");
373*d8b80295SApple OSS Distributions
374*d8b80295SApple OSS Distributions T_SETUPEND;
375*d8b80295SApple OSS Distributions
376*d8b80295SApple OSS Distributions /*
377*d8b80295SApple OSS Distributions * Relinquish assertion priority even though we don't hold it. No change in state expected.
378*d8b80295SApple OSS Distributions */
379*d8b80295SApple OSS Distributions
380*d8b80295SApple OSS Distributions
381*d8b80295SApple OSS Distributions /* Test0 */
382*d8b80295SApple OSS Distributions T_LOG("********Test0 clean: no state change on relinquish");
383*d8b80295SApple OSS Distributions relinquish_assertion_priority(mypid, 0xF00D);
384*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xF00D, ASSERTION_STATE_IS_RELINQUISHED, "Test0");
385*d8b80295SApple OSS Distributions
386*d8b80295SApple OSS Distributions /* Test1 */
387*d8b80295SApple OSS Distributions T_LOG("********Test1 clean: assertion[0 -> 10] but inactive priority prevails");
388*d8b80295SApple OSS Distributions set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
389*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test1");
390*d8b80295SApple OSS Distributions
391*d8b80295SApple OSS Distributions /* Test2 */
392*d8b80295SApple OSS Distributions T_LOG("********Test2 clean: assertion[10 -> 3] but inactive priority prevails");
393*d8b80295SApple OSS Distributions set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
394*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test2");
395*d8b80295SApple OSS Distributions
396*d8b80295SApple OSS Distributions /* Test3 */
397*d8b80295SApple OSS Distributions T_LOG("********Test3 clean: assertion[3 -> 0], but inactive priority prevails");
398*d8b80295SApple OSS Distributions relinquish_assertion_priority(mypid, 0xBEEF);
399*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test3");
400*d8b80295SApple OSS Distributions
401*d8b80295SApple OSS Distributions /* Test4 */
402*d8b80295SApple OSS Distributions T_LOG("********Test4 go dirty: assertion[0] has no affect, active priority prevails");
403*d8b80295SApple OSS Distributions proc_will_set_dirty(mypid);
404*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test4");
405*d8b80295SApple OSS Distributions
406*d8b80295SApple OSS Distributions /* Test5 */
407*d8b80295SApple OSS Distributions T_LOG("********Test5 dirty: assertion[0 -> 10] active priority prevails");
408*d8b80295SApple OSS Distributions set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
409*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test5");
410*d8b80295SApple OSS Distributions
411*d8b80295SApple OSS Distributions /* Test6 */
412*d8b80295SApple OSS Distributions T_LOG("********Test6 dirty: assertion[10 -> 3] active priority prevails");
413*d8b80295SApple OSS Distributions set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
414*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test6");
415*d8b80295SApple OSS Distributions
416*d8b80295SApple OSS Distributions /* Test 7 */
417*d8b80295SApple OSS Distributions T_LOG("********Test7 dirty: assertion[3 -> 0], active priority prevails");
418*d8b80295SApple OSS Distributions relinquish_assertion_priority(mypid, 0xBEEF);
419*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test7");
420*d8b80295SApple OSS Distributions
421*d8b80295SApple OSS Distributions /* Test8 */
422*d8b80295SApple OSS Distributions T_LOG("********Test8 dirty: assertion[0 -> 19], dirty but now assertion[19] prevails");
423*d8b80295SApple OSS Distributions set_assertion_priority(mypid, JETSAM_PRIORITY_CRITICAL, 0xFEED);
424*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_CRITICAL, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test8");
425*d8b80295SApple OSS Distributions
426*d8b80295SApple OSS Distributions
427*d8b80295SApple OSS Distributions /* Test9 */
428*d8b80295SApple OSS Distributions T_LOG("********Test9 go clean: inactive priority but assertion[19] prevails");
429*d8b80295SApple OSS Distributions proc_will_set_clean(mypid);
430*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_CRITICAL, inactive_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test9");
431*d8b80295SApple OSS Distributions
432*d8b80295SApple OSS Distributions /* Test10 */
433*d8b80295SApple OSS Distributions T_LOG("********Test10 clean: assertion[19 -> 3] inactive limit prevails");
434*d8b80295SApple OSS Distributions set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
435*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test10");
436*d8b80295SApple OSS Distributions
437*d8b80295SApple OSS Distributions
438*d8b80295SApple OSS Distributions /* Test11 */
439*d8b80295SApple OSS Distributions T_LOG("********Test11 clean: assertion[3 -> 0] inactive priority still prevails");
440*d8b80295SApple OSS Distributions relinquish_assertion_priority(mypid, 0xBEEF);
441*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test11");
442*d8b80295SApple OSS Distributions
443*d8b80295SApple OSS Distributions /* Test12 */
444*d8b80295SApple OSS Distributions T_LOG("********Test12 dirty goes clean: both assertion[0] and clean");
445*d8b80295SApple OSS Distributions proc_will_set_clean(mypid);
446*d8b80295SApple OSS Distributions (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test12");
447*d8b80295SApple OSS Distributions }
448*d8b80295SApple OSS Distributions
449*d8b80295SApple OSS Distributions T_DECL(assertion_test_bad_flags, "verify bad flag returns an error", T_META_TIMEOUT(30), T_META_ASROOT(true)) {
450*d8b80295SApple OSS Distributions int err;
451*d8b80295SApple OSS Distributions uint32_t flag = 0;
452*d8b80295SApple OSS Distributions
453*d8b80295SApple OSS Distributions memorystatus_priority_properties_t mjp = { 0 };
454*d8b80295SApple OSS Distributions
455*d8b80295SApple OSS Distributions mjp.priority = JETSAM_PRIORITY_FOREGROUND;
456*d8b80295SApple OSS Distributions mjp.user_data = 0;
457*d8b80295SApple OSS Distributions
458*d8b80295SApple OSS Distributions /*
459*d8b80295SApple OSS Distributions * init a bad flag
460*d8b80295SApple OSS Distributions */
461*d8b80295SApple OSS Distributions
462*d8b80295SApple OSS Distributions flag = 0xf;
463*d8b80295SApple OSS Distributions
464*d8b80295SApple OSS Distributions err = memorystatus_control(MEMORYSTATUS_CMD_SET_PRIORITY_PROPERTIES, getpid(), flag, &mjp, sizeof(mjp));
465*d8b80295SApple OSS Distributions
466*d8b80295SApple OSS Distributions T_QUIET;
467*d8b80295SApple OSS Distributions T_ASSERT_POSIX_FAILURE(err, EINVAL, "MEMORYSTATUS_CMD_SET_PRIORITY_PROPERTIES should fail with bad flags (err=%d)", err);
468*d8b80295SApple OSS Distributions }
469*d8b80295SApple OSS Distributions
470*d8b80295SApple OSS Distributions #if TARGET_OS_OSX
471*d8b80295SApple OSS Distributions /*
472*d8b80295SApple OSS Distributions * Idle band deferral, aka aging band/demotion, has been disabled on macOS till
473*d8b80295SApple OSS Distributions * we do the daemon hygiene work on macOS to make sure that processes don't change
474*d8b80295SApple OSS Distributions * their role after spawn e.g. apps opting into dirty-tracking/idle-exit.
475*d8b80295SApple OSS Distributions * The following set of tests rely on PROC_DIRTY_DEFER, aka aging bands, for the tests.
476*d8b80295SApple OSS Distributions */
477*d8b80295SApple OSS Distributions #else /* TARGET_OS_OSX */
478*d8b80295SApple OSS Distributions
479*d8b80295SApple OSS Distributions 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)) {
480*d8b80295SApple OSS Distributions /*
481*d8b80295SApple OSS Distributions * Verify back-to-back assertion calls set assertion state as expected.
482*d8b80295SApple OSS Distributions * false --> non-dirty-tracking process (like a typical app)
483*d8b80295SApple OSS Distributions * false --> clean/dirty does not apply here
484*d8b80295SApple OSS Distributions */
485*d8b80295SApple OSS Distributions
486*d8b80295SApple OSS Distributions memorystatus_assertion_test_repetitive("Scenario #1", false, false);
487*d8b80295SApple OSS Distributions }
488*d8b80295SApple OSS Distributions
489*d8b80295SApple OSS Distributions 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)) {
490*d8b80295SApple OSS Distributions /*
491*d8b80295SApple OSS Distributions * Verify back-to-back assertion calls set assertion state as expected.
492*d8b80295SApple OSS Distributions * true --> dirty-tracking process (like a typical extension/widget)
493*d8b80295SApple OSS Distributions * true --> start clean / inactive
494*d8b80295SApple OSS Distributions * This will exercise idle-deferred paths.
495*d8b80295SApple OSS Distributions */
496*d8b80295SApple OSS Distributions memorystatus_assertion_test_repetitive("Scenario #2", true, true);
497*d8b80295SApple OSS Distributions }
498*d8b80295SApple OSS Distributions
499*d8b80295SApple OSS Distributions 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)) {
500*d8b80295SApple OSS Distributions /*
501*d8b80295SApple OSS Distributions * Verify back-to-back assertion calls set assertion state as expected.
502*d8b80295SApple OSS Distributions * true --> dirty-tracking process (like a typical extension/widget)
503*d8b80295SApple OSS Distributions * false --> start dirty / active state
504*d8b80295SApple OSS Distributions * This will exercise idle-deferred paths.
505*d8b80295SApple OSS Distributions */
506*d8b80295SApple OSS Distributions memorystatus_assertion_test_repetitive("Scenario #3", true, false);
507*d8b80295SApple OSS Distributions }
508*d8b80295SApple OSS Distributions
509*d8b80295SApple OSS Distributions
510*d8b80295SApple OSS Distributions T_DECL(assertion_test_allow_idle_exit, "set assertion priorities on process supporting idle exit", T_META_TIMEOUT(360), T_META_ASROOT(true)) {
511*d8b80295SApple OSS Distributions memorystatus_assertion_test_allow_idle_exit();
512*d8b80295SApple OSS Distributions }
513*d8b80295SApple OSS Distributions
514*d8b80295SApple OSS Distributions 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)) {
515*d8b80295SApple OSS Distributions memorystatus_assertion_test_do_not_allow_idle_exit();
516*d8b80295SApple OSS Distributions }
517*d8b80295SApple OSS Distributions #endif /* TARGET_OS_OSX */
518