• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.profiling.cts;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertNull;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assert.fail;
25 import static org.mockito.ArgumentMatchers.any;
26 import static org.mockito.ArgumentMatchers.anyBoolean;
27 import static org.mockito.Mockito.spy;
28 import static org.mockito.Mockito.times;
29 import static org.mockito.Mockito.verify;
30 
31 import android.app.Instrumentation;
32 import android.content.Context;
33 import android.os.Binder;
34 import android.os.Bundle;
35 import android.os.CancellationSignal;
36 import android.os.Parcel;
37 import android.os.ProfilingManager;
38 import android.os.ProfilingResult;
39 import android.os.ProfilingServiceHelper;
40 import android.os.ProfilingTrigger;
41 import android.os.profiling.DeviceConfigHelper;
42 import android.os.profiling.Flags;
43 import android.os.profiling.ProfilingService;
44 import android.platform.test.annotations.RequiresFlagsEnabled;
45 import android.platform.test.flag.junit.CheckFlagsRule;
46 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
47 
48 import androidx.test.core.app.ApplicationProvider;
49 import androidx.test.filters.LargeTest;
50 import androidx.test.platform.app.InstrumentationRegistry;
51 import androidx.test.runner.AndroidJUnit4;
52 
53 import com.android.compatibility.common.util.SystemUtil;
54 
55 import com.google.errorprone.annotations.FormatMethod;
56 
57 import org.junit.After;
58 import org.junit.Before;
59 import org.junit.Rule;
60 import org.junit.Test;
61 import org.junit.rules.TestName;
62 import org.junit.runner.RunWith;
63 import org.testng.TestException;
64 
65 import java.io.File;
66 import java.io.IOException;
67 import java.nio.file.FileSystems;
68 import java.nio.file.Files;
69 import java.nio.file.Path;
70 import java.nio.file.Paths;
71 import java.util.List;
72 import java.util.concurrent.atomic.AtomicBoolean;
73 import java.util.function.Consumer;
74 
75 /**
76  *
77  * Tests defined in this class are expected to test the API implementation.  All tests below require
78  * the android.os.profiling.telemetry_apis flag to be enabled, otherwise you will receive an
79  * assumed failure for any tests has the @RequiresFlagsEnabled annotation.
80  *
81  */
82 
83 @RunWith(AndroidJUnit4.class)
84 public final class ProfilingFrameworkTests {
85 
86     // Wait for callback for 5 seconds at a time for up to 60 increments totalling 5 minutes.
87     private static final int CALLBACK_WAIT_TIME_INCREMENT_MS = 5 * 1000;
88     private static final int CALLBACK_WAIT_TIME_INCREMENTS_COUNT = 60;
89 
90     // Smaller number of increments for cancel case - wait for callback for 5 seconds at a time for
91     // up to 4 increments totalling 20 seconds.
92     private static final int CALLBACK_CANCEL_WAIT_TIME_INCREMENTS_COUNT = 4;
93 
94     // Wait for rate limiter config to update for 250 milliseconds at a time for up to 12 increments
95     // totalling 3 seconds.
96     private static final int RATE_LIMITER_WAIT_TIME_INCREMENT_MS = 250;
97     private static final int RATE_LIMITER_WAIT_TIME_INCREMENTS_COUNT = 12;
98 
99     // Wait 2 seconds for profiling to get started before attempting to cancel it.
100     // TODO: b/376440094 - change to query perfetto and confirm profiling is running.
101     private static final int WAIT_TIME_FOR_PROFILING_START_MS = 2 * 1000;
102 
103     // Wait 10 seconds for profiling to potentially clone, process, and return result to confirm it
104     // did not occur.
105     private static final int WAIT_TIME_FOR_TRIGGERED_PROFILING_NO_RESULT = 10 * 1000;
106 
107     // Keep in sync with {@link ProfilingService} because we can't access it.
108     private static final String OUTPUT_FILE_JAVA_HEAP_DUMP_SUFFIX = ".perfetto-java-heap-dump";
109     private static final String OUTPUT_FILE_HEAP_PROFILE_SUFFIX = ".perfetto-heap-profile";
110     private static final String OUTPUT_FILE_STACK_SAMPLING_SUFFIX = ".perfetto-stack-sample";
111     private static final String OUTPUT_FILE_TRACE_SUFFIX = ".perfetto-trace";
112 
113     public static final Path DUMP_PATH = FileSystems.getDefault()
114             .getPath("/sdcard/ProfilesCollected/");
115 
116     private static final String COMMAND_OVERRIDE_DEVICE_CONFIG_INT = "device_config put %s %s %d";
117     private static final String COMMAND_OVERRIDE_DEVICE_CONFIG_BOOL = "device_config put %s %s %b";
118     private static final String COMMAND_OVERRIDE_DEVICE_CONFIG_STRING =
119             "device_config put %s %s %s";
120     private static final String COMMAND_DELETE_DEVICE_CONFIG_STRING = "device_config delete %s %s";
121     private static final String RESET_NAMESPACE = "device_config reset trusted_defaults %s";
122 
123     private static final String REAL_PACKAGE_NAME = "com.android.profiling.tests";
124 
125     private static final int ONE_SECOND_MS = 1 * 1000;
126     private static final int FIVE_SECONDS_MS = 5 * 1000;
127     private static final int TEN_SECONDS_MS = 10 * 1000;
128     private static final int ONE_MINUTE_MS = 60 * 1000;
129     private static final int FIVE_MINUTES_MS = 5 * 60 * 1000;
130     private static final int TEN_MINUTES_MS = 10 * 60 * 1000;
131 
132     private ProfilingManager mProfilingManager = null;
133     private Context mContext = null;
134     private Instrumentation mInstrumentation;
135 
136     static {
137         System.loadLibrary("cts_profiling_module_test_native");
138     }
139 
140     @Rule
141     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
142 
143     @Rule
144     public final TestName mTestName = new TestName();
145 
146     @Before
setup()147     public void setup() throws Exception {
148         mContext = ApplicationProvider.getApplicationContext();
149         mProfilingManager = mContext.getSystemService(ProfilingManager.class);
150         mInstrumentation = InstrumentationRegistry.getInstrumentation();
151 
152         executeShellCmd(RESET_NAMESPACE, DeviceConfigHelper.NAMESPACE);
153         executeShellCmd(RESET_NAMESPACE, DeviceConfigHelper.NAMESPACE_TESTING);
154 
155         // This permission is required for Headless (HSUM) tests, including Auto.
156         mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(
157                 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
158     }
159 
160     @SuppressWarnings("GuardedBy") // Suppress warning for mProfilingManager.mProfilingService lock.
161     @After
cleanup()162     public void cleanup() throws Exception {
163         mProfilingManager.mProfilingService = null;
164         executeShellCmd(COMMAND_DELETE_DEVICE_CONFIG_STRING, DeviceConfigHelper.NAMESPACE_TESTING,
165                 DeviceConfigHelper.SYSTEM_TRIGGERED_TEST_PACKAGE_NAME);
166     }
167 
168     /** Check and see if we can get a reference to the ProfilingManager service. */
169     @Test
170     @RequiresFlagsEnabled(Flags.FLAG_TELEMETRY_APIS)
createServiceTest()171     public void createServiceTest() {
172         assertNotNull(mProfilingManager);
173     }
174 
175     /** Test that request with invalid profiling type fails with correct error output. */
176     @Test
177     @RequiresFlagsEnabled(Flags.FLAG_TELEMETRY_APIS)
testInvalidProfilingType()178     public void testInvalidProfilingType() throws Exception {
179         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
180 
181         disableRateLimiter();
182 
183         AppCallback callback = new AppCallback();
184 
185         // This call is passing an invalid profiling request type and should result in an error.
186         mProfilingManager.requestProfiling(
187                 -1,
188                 null,
189                 null,
190                 null,
191                 new ProfilingTestUtils.ImmediateExecutor(),
192                 callback);
193 
194         // Wait until callback#onAccept is triggered so we can confirm the result.
195         waitForCallback(callback);
196 
197         assertEquals(ProfilingResult.ERROR_FAILED_INVALID_REQUEST, callback.mResult.getErrorCode());
198     }
199 
200     /** Test that request with invalid profiling params fails with correct error output. */
201     @Test
202     @RequiresFlagsEnabled(Flags.FLAG_TELEMETRY_APIS)
testInvalidProfilingParams()203     public void testInvalidProfilingParams() throws Exception {
204         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
205 
206         disableRateLimiter();
207 
208         AppCallback callback = new AppCallback();
209 
210         Bundle params = new Bundle();
211         params.putBoolean("bypass_rate_limiter", true);
212 
213         // This call is passing a parameters bundle with an invalid parameter and should result in
214         // an error.
215         mProfilingManager.requestProfiling(
216                 ProfilingManager.PROFILING_TYPE_STACK_SAMPLING,
217                 params,
218                 null,
219                 null,
220                 new ProfilingTestUtils.ImmediateExecutor(),
221                 callback);
222 
223         // Wait until callback#onAccept is triggered so we can confirm the result.
224         waitForCallback(callback);
225 
226         assertEquals(ProfilingResult.ERROR_FAILED_INVALID_REQUEST, callback.mResult.getErrorCode());
227     }
228 
229     /** Test that profiling request for java heap dump succeeds and returns a non-empty file. */
230     @Test
231     @LargeTest
232     @RequiresFlagsEnabled(Flags.FLAG_TELEMETRY_APIS)
testRequestJavaHeapDumpSuccess()233     public void testRequestJavaHeapDumpSuccess() throws Exception {
234         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
235 
236         disableRateLimiter();
237 
238         overrideJavaHeapDumpDeviceConfigValues(false, ONE_SECOND_MS, TEN_SECONDS_MS);
239 
240         AppCallback callback = new AppCallback();
241 
242         // Now kick off the request.
243         mProfilingManager.requestProfiling(
244                 ProfilingManager.PROFILING_TYPE_JAVA_HEAP_DUMP,
245                 null,
246                 null,
247                 null,
248                 new ProfilingTestUtils.ImmediateExecutor(),
249                 callback);
250 
251         // Wait until callback#onAccept is triggered so we can confirm the result.
252         waitForCallback(callback);
253 
254         // Assert that result matches assumptions for success.
255         confirmCollectionSuccess(callback.mResult, OUTPUT_FILE_JAVA_HEAP_DUMP_SUFFIX);
256         dumpTrace(callback.mResult);
257     }
258 
259     /** Test that profiling request for heap profile succeeds and returns a non-empty file. */
260     @Test
261     @RequiresFlagsEnabled(Flags.FLAG_TELEMETRY_APIS)
testRequestHeapProfileSuccess()262     public void testRequestHeapProfileSuccess() throws Exception {
263         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
264 
265         disableRateLimiter();
266 
267         overrideHeapProfileDeviceConfigValues(false, ONE_SECOND_MS, ONE_SECOND_MS, FIVE_SECONDS_MS);
268 
269         AppCallback callback = new AppCallback();
270 
271         // Add sampling interval param to test because it is currently the only long param.
272         Bundle params = ProfilingTestUtils.getOneSecondDurationParamBundle();
273         params.putLong(ProfilingManager.KEY_SAMPLING_INTERVAL_BYTES, 4096L);
274 
275         // Now kick off the request.
276         mProfilingManager.requestProfiling(
277                 ProfilingManager.PROFILING_TYPE_HEAP_PROFILE,
278                 params,
279                 null,
280                 null,
281                 new ProfilingTestUtils.ImmediateExecutor(),
282                 callback);
283 
284         MallocLoopThread mallocThread = new MallocLoopThread();
285 
286         // Wait until callback#onAccept is triggered so we can confirm the result.
287         waitForCallback(callback);
288 
289         mallocThread.stop();
290 
291         // Assert that result matches assumptions for success.
292         confirmCollectionSuccess(callback.mResult, OUTPUT_FILE_HEAP_PROFILE_SUFFIX);
293         dumpTrace(callback.mResult);
294     }
295 
296     /** Test that profiling request for stack sampling succeeds and returns a non-empty file. */
297     @Test
298     @RequiresFlagsEnabled(Flags.FLAG_TELEMETRY_APIS)
testRequestStackSamplingSuccess()299     public void testRequestStackSamplingSuccess() throws Exception {
300         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
301 
302         disableRateLimiter();
303 
304         overrideStackSamplingDeviceConfigValues(false, ONE_SECOND_MS, ONE_SECOND_MS,
305                 FIVE_SECONDS_MS);
306 
307         AppCallback callback = new AppCallback();
308 
309         // Now kick off the request.
310         mProfilingManager.requestProfiling(
311                 ProfilingManager.PROFILING_TYPE_STACK_SAMPLING,
312                 ProfilingTestUtils.getOneSecondDurationParamBundle(),
313                 null,
314                 null,
315                 new ProfilingTestUtils.ImmediateExecutor(),
316                 callback);
317 
318         BusyLoopThread busy = new BusyLoopThread();
319 
320         // Wait until callback#onAccept is triggered so we can confirm the result.
321         waitForCallback(callback);
322 
323         busy.stop();
324 
325         // Assert that result matches assumptions for success.
326         confirmCollectionSuccess(callback.mResult, OUTPUT_FILE_STACK_SAMPLING_SUFFIX);
327         dumpTrace(callback.mResult);
328     }
329 
330     /**
331      * Test that profiling request for system trace fails as it's disabled until redaction
332      * is in place.
333      */
334     @Test
335     @RequiresFlagsEnabled({Flags.FLAG_TELEMETRY_APIS, Flags.FLAG_REDACTION_ENABLED})
testRequestSystemTraceSuccess()336     public void testRequestSystemTraceSuccess() throws Exception {
337         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
338 
339         disableRateLimiter();
340 
341         overrideSystemTraceDeviceConfigValues(false, ONE_SECOND_MS, ONE_SECOND_MS, FIVE_SECONDS_MS);
342 
343         AppCallback callback = new AppCallback();
344 
345         // Now kick off the request.
346         mProfilingManager.requestProfiling(
347                 ProfilingManager.PROFILING_TYPE_SYSTEM_TRACE,
348                 ProfilingTestUtils.getOneSecondDurationParamBundle(),
349                 null,
350                 null,
351                 new ProfilingTestUtils.ImmediateExecutor(),
352                 callback);
353 
354         // Wait until callback#onAccept is triggered so we can confirm the result.
355         waitForCallback(callback);
356 
357         // Assert trace has succeeded.
358         confirmCollectionSuccess(callback.mResult, OUTPUT_FILE_TRACE_SUFFIX);
359         dumpTrace(callback.mResult);
360     }
361 
362     /** Test that cancelling java heap dump stops collection and still receives correct result. */
363     @Test
364     @RequiresFlagsEnabled(Flags.FLAG_TELEMETRY_APIS)
testRequestJavaHeapDumpCancel()365     public void testRequestJavaHeapDumpCancel() throws Exception {
366         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
367 
368         disableRateLimiter();
369 
370         // Set override duration and timeout to 10 minutes so we can ensure it finishes early when
371         // canceled.
372         overrideJavaHeapDumpDeviceConfigValues(false, TEN_MINUTES_MS, TEN_MINUTES_MS);
373 
374         AppCallback callback = new AppCallback();
375         CancellationSignal cancellationSignal = new CancellationSignal();
376 
377         // Now kick off the request.
378         mProfilingManager.requestProfiling(
379                 ProfilingManager.PROFILING_TYPE_JAVA_HEAP_DUMP,
380                 null,    // Use default parameters since we will cancel quickly
381                 null,
382                 cancellationSignal,
383                 new ProfilingTestUtils.ImmediateExecutor(),
384                 callback);
385 
386         // Wait a bit for collection to get started.
387         sleep(WAIT_TIME_FOR_PROFILING_START_MS);
388 
389         // Now request cancellation.
390         cancellationSignal.cancel();
391 
392         // Wait until callback#onAccept is triggered so we can confirm the result.
393         waitForCancelCallback(callback);
394 
395         // Assert that result matches assumptions for success.
396         confirmCollectionSuccess(callback.mResult, OUTPUT_FILE_JAVA_HEAP_DUMP_SUFFIX);
397     }
398 
399     /** Test that cancelling heap profile stops collection and still receives correct result. */
400     @Test
401     @RequiresFlagsEnabled(Flags.FLAG_TELEMETRY_APIS)
testRequestHeapProfileCancel()402     public void testRequestHeapProfileCancel() throws Exception {
403         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
404 
405         disableRateLimiter();
406 
407         // Set override durations to 10 minutes so we can ensure it finishes early when canceled.
408         overrideHeapProfileDeviceConfigValues(false, TEN_MINUTES_MS, TEN_MINUTES_MS,
409                 TEN_MINUTES_MS);
410 
411         AppCallback callback = new AppCallback();
412         CancellationSignal cancellationSignal = new CancellationSignal();
413 
414         // Now kick off the request.
415         mProfilingManager.requestProfiling(
416                 ProfilingManager.PROFILING_TYPE_HEAP_PROFILE,
417                 null,    // Use default parameters since we will cancel quickly
418                 null,
419                 cancellationSignal,
420                 new ProfilingTestUtils.ImmediateExecutor(),
421                 callback);
422 
423         // Wait a bit for collection to get started.
424         sleep(WAIT_TIME_FOR_PROFILING_START_MS);
425 
426         // Now request cancellation.
427         cancellationSignal.cancel();
428 
429         // Wait until callback#onAccept is triggered so we can confirm the result.
430         waitForCancelCallback(callback);
431 
432         // Assert that result matches assumptions for success.
433         confirmCollectionSuccess(callback.mResult, OUTPUT_FILE_HEAP_PROFILE_SUFFIX);
434     }
435 
436     /** Test that cancelling stack sampling stops collection and still receives correct result. */
437     @Test
438     @RequiresFlagsEnabled(Flags.FLAG_TELEMETRY_APIS)
testRequestStackSamplingCancel()439     public void testRequestStackSamplingCancel() throws Exception {
440         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
441 
442         disableRateLimiter();
443 
444         // Set override durations to 10 minutes so we can ensure it finishes early when canceled.
445         overrideStackSamplingDeviceConfigValues(false, TEN_MINUTES_MS, TEN_MINUTES_MS,
446                 TEN_MINUTES_MS);
447 
448         AppCallback callback = new AppCallback();
449         CancellationSignal cancellationSignal = new CancellationSignal();
450 
451         // Now kick off the request.
452         mProfilingManager.requestProfiling(
453                 ProfilingManager.PROFILING_TYPE_STACK_SAMPLING,
454                 null,    // Use default parameters since we will cancel quickly
455                 null,
456                 cancellationSignal,
457                 new ProfilingTestUtils.ImmediateExecutor(),
458                 callback);
459 
460         // Wait a bit for collection to get started.
461         sleep(WAIT_TIME_FOR_PROFILING_START_MS);
462 
463         // Now request cancellation.
464         cancellationSignal.cancel();
465 
466         // Wait until callback#onAccept is triggered so we can confirm the result.
467         waitForCancelCallback(callback);
468 
469         // Assert that result matches assumptions for success.
470         confirmCollectionSuccess(callback.mResult, OUTPUT_FILE_STACK_SAMPLING_SUFFIX);
471     }
472 
473     /** Test that cancelling stack sampling stops collection and still receives correct result. */
474     @Test
475     @RequiresFlagsEnabled({Flags.FLAG_TELEMETRY_APIS, Flags.FLAG_REDACTION_ENABLED})
testRequestSystemTraceCancel()476     public void testRequestSystemTraceCancel() throws Exception {
477         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
478 
479         disableRateLimiter();
480 
481         // Set override durations to 10 minutes so we can ensure it finishes early when canceled.
482         overrideSystemTraceDeviceConfigValues(false, TEN_MINUTES_MS, TEN_MINUTES_MS,
483                 TEN_MINUTES_MS);
484 
485         AppCallback callback = new AppCallback();
486         CancellationSignal cancellationSignal = new CancellationSignal();
487 
488         // Now kick off the request.
489         mProfilingManager.requestProfiling(
490                 ProfilingManager.PROFILING_TYPE_SYSTEM_TRACE,
491                 null,    // Use default parameters since we will cancel quickly
492                 null,
493                 cancellationSignal,
494                 new ProfilingTestUtils.ImmediateExecutor(),
495                 callback);
496 
497         // Wait a bit for collection to get started.
498         sleep(WAIT_TIME_FOR_PROFILING_START_MS);
499 
500         // Now request cancellation.
501         cancellationSignal.cancel();
502 
503         // Wait until callback#onAccept is triggered so we can confirm the result.
504         waitForCancelCallback(callback);
505 
506         // Assert that result matches assumptions for success.
507         confirmCollectionSuccess(callback.mResult, OUTPUT_FILE_TRACE_SUFFIX);
508     }
509 
510     /** Test that unregistering a global listener works and that listener does not get called. */
511     @Test
512     @SuppressWarnings("GuardedBy") // Suppress warning for mProfilingManager.mCallbacks lock.
513     @RequiresFlagsEnabled(Flags.FLAG_TELEMETRY_APIS)
testUnregisterGeneralListener()514     public void testUnregisterGeneralListener() throws Exception {
515         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
516 
517         disableRateLimiter();
518 
519         overrideStackSamplingDeviceConfigValues(false, ONE_SECOND_MS, ONE_SECOND_MS,
520                 FIVE_SECONDS_MS);
521 
522         // Clear all existing callbacks.
523         mProfilingManager.mCallbacks.clear();
524 
525         // Create 2 callbacks.
526         AppCallback callbackSpecific = new AppCallback();
527         AppCallback callbackGeneral = new AppCallback();
528 
529         // Register the general callback.
530         mProfilingManager.registerForAllProfilingResults(
531                 new ProfilingTestUtils.ImmediateExecutor(), callbackGeneral);
532 
533         // Confirm callback is properly registered by checking for size of 1.
534         assertTrue(mProfilingManager.mCallbacks.size() == 1);
535 
536         // Now unregister the general callback.
537         mProfilingManager.unregisterForAllProfilingResults(callbackGeneral);
538 
539         // Now kick off the request.
540         mProfilingManager.requestProfiling(
541                 ProfilingManager.PROFILING_TYPE_STACK_SAMPLING,
542                 ProfilingTestUtils.getOneSecondDurationParamBundle(),
543                 null,
544                 null,
545                 new ProfilingTestUtils.ImmediateExecutor(),
546                 callbackSpecific);
547 
548         // Wait until callback#onAccept is triggered so we can confirm the result.
549         waitForCallback(callbackSpecific);
550 
551         // Assert that the unregistered callback was not triggered.
552         assertNull(callbackGeneral.mResult);
553     }
554 
555     /** Test that unregistering all global listeners works and that listeners do not get called. */
556     @Test
557     @SuppressWarnings("GuardedBy") // Suppress warning for mProfilingManager.mCallbacks lock.
558     @RequiresFlagsEnabled(Flags.FLAG_TELEMETRY_APIS)
testUnregisterAllGeneralListeners()559     public void testUnregisterAllGeneralListeners() throws Exception {
560         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
561 
562         disableRateLimiter();
563 
564         overrideStackSamplingDeviceConfigValues(false, ONE_SECOND_MS, ONE_SECOND_MS,
565                 FIVE_SECONDS_MS);
566 
567         // Clear all existing callbacks.
568         mProfilingManager.mCallbacks.clear();
569 
570         // Create 3 callbacks, 2 general and 1 specific.
571         AppCallback callbackSpecific = new AppCallback();
572         AppCallback callbackGeneral1 = new AppCallback();
573         AppCallback callbackGeneral2 = new AppCallback();
574 
575         // Register both general callbacks.
576         mProfilingManager.registerForAllProfilingResults(
577                 new ProfilingTestUtils.ImmediateExecutor(), callbackGeneral1);
578         mProfilingManager.registerForAllProfilingResults(
579                 new ProfilingTestUtils.ImmediateExecutor(), callbackGeneral2);
580 
581         // Confirm callbacks are properly registered by checking for size of 2.
582         assertTrue(mProfilingManager.mCallbacks.size() == 2);
583 
584         // Now unregister the general callbacks.
585         mProfilingManager.unregisterForAllProfilingResults(null);
586 
587         // Now kick off the request.
588         mProfilingManager.requestProfiling(
589                 ProfilingManager.PROFILING_TYPE_STACK_SAMPLING,
590                 ProfilingTestUtils.getOneSecondDurationParamBundle(),
591                 null,
592                 null,
593                 new ProfilingTestUtils.ImmediateExecutor(),
594                 callbackSpecific);
595 
596         // Wait until callback#onAccept is triggered so we can confirm the result.
597         waitForCallback(callbackSpecific);
598 
599         // Assert that the unregistered callbacks were not triggered.
600         assertNull(callbackGeneral1.mResult);
601         assertNull(callbackGeneral2.mResult);
602     }
603 
604     /** Test that a globally registered listener is triggered along with the specific one. */
605     @Test
606     @RequiresFlagsEnabled(Flags.FLAG_TELEMETRY_APIS)
testTriggerAllListeners()607     public void testTriggerAllListeners() throws Exception {
608         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
609 
610         disableRateLimiter();
611 
612         overrideStackSamplingDeviceConfigValues(false, ONE_SECOND_MS, ONE_SECOND_MS,
613                 FIVE_SECONDS_MS);
614 
615         // Create 3 callbacks.
616         AppCallback callbackSpecific = new AppCallback();
617         AppCallback callbackGeneral1 = new AppCallback();
618         AppCallback callbackGeneral2 = new AppCallback();
619 
620         // Register the first general callback before kicking off request.
621         mProfilingManager.registerForAllProfilingResults(
622                 new ProfilingTestUtils.ImmediateExecutor(), callbackGeneral1);
623 
624         // Now kick off the request.
625         mProfilingManager.requestProfiling(
626                 ProfilingManager.PROFILING_TYPE_STACK_SAMPLING,
627                 ProfilingTestUtils.getOneSecondDurationParamBundle(),
628                 null,
629                 null,
630                 new ProfilingTestUtils.ImmediateExecutor(),
631                 callbackSpecific);
632 
633         // Register the 2nd general callback after kicking off request, but before result is ready.
634         mProfilingManager.registerForAllProfilingResults(
635                 new ProfilingTestUtils.ImmediateExecutor(), callbackGeneral2);
636 
637         // Wait until callback#onAccept is triggered so we can confirm the result.
638         waitForCallback(callbackSpecific);
639 
640         // Assert that result matches assumptions for success in all callbacks.
641         confirmCollectionSuccess(callbackSpecific.mResult, OUTPUT_FILE_STACK_SAMPLING_SUFFIX);
642         confirmCollectionSuccess(callbackGeneral1.mResult, OUTPUT_FILE_STACK_SAMPLING_SUFFIX);
643         confirmCollectionSuccess(callbackGeneral2.mResult, OUTPUT_FILE_STACK_SAMPLING_SUFFIX);
644     }
645 
646     /** Test that listeners registered to the same UID from different contexts are all triggered. */
647     @Test
648     @RequiresFlagsEnabled(Flags.FLAG_TELEMETRY_APIS)
testTriggerAllListenersDifferentContexts()649     public void testTriggerAllListenersDifferentContexts() throws Exception {
650         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
651 
652         disableRateLimiter();
653 
654         overrideStackSamplingDeviceConfigValues(false, ONE_SECOND_MS, ONE_SECOND_MS,
655                 FIVE_SECONDS_MS);
656 
657         // Obtain another ProfilingManager instance from a different context.
658         Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
659         // Confirm the 2 contexts are of a different class. This check is broader than is a strictly
660         // required, but guarantees these contexts cannot be the same.
661         assertFalse(mContext.getClass().equals(context.getClass()));
662         ProfilingManager profilingManager = context.getSystemService(ProfilingManager.class);
663 
664         // Create 3 callbacks.
665         AppCallback callbackSpecific = new AppCallback();
666         AppCallback callbackGeneral1 = new AppCallback();
667         AppCallback callbackGeneral2 = new AppCallback();
668 
669         // Register the general callbacks, one to each context.
670         profilingManager.registerForAllProfilingResults(
671                 new ProfilingTestUtils.ImmediateExecutor(), callbackGeneral1);
672         mProfilingManager.registerForAllProfilingResults(
673                 new ProfilingTestUtils.ImmediateExecutor(), callbackGeneral2);
674 
675         // Now kick off the request.
676         mProfilingManager.requestProfiling(
677                 ProfilingManager.PROFILING_TYPE_STACK_SAMPLING,
678                 ProfilingTestUtils.getOneSecondDurationParamBundle(),
679                 null,
680                 null,
681                 new ProfilingTestUtils.ImmediateExecutor(),
682                 callbackSpecific);
683 
684 
685         // Wait until callback#onAccept is triggered so we can confirm the result.
686         waitForCallback(callbackSpecific);
687 
688         // Assert that result matches assumptions for success in all callbacks.
689         confirmCollectionSuccess(callbackSpecific.mResult, OUTPUT_FILE_STACK_SAMPLING_SUFFIX);
690         confirmCollectionSuccess(callbackGeneral1.mResult, OUTPUT_FILE_STACK_SAMPLING_SUFFIX);
691         confirmCollectionSuccess(callbackGeneral2.mResult, OUTPUT_FILE_STACK_SAMPLING_SUFFIX);
692     }
693 
694     /** Test that profiling request result file name contains the correct tag. */
695     @Test
696     @RequiresFlagsEnabled(Flags.FLAG_TELEMETRY_APIS)
testRequestTagInFilename()697     public void testRequestTagInFilename() throws Exception {
698         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
699 
700         disableRateLimiter();
701 
702         overrideStackSamplingDeviceConfigValues(false, ONE_SECOND_MS, ONE_SECOND_MS,
703                 FIVE_SECONDS_MS);
704 
705         AppCallback callback = new AppCallback();
706 
707         // Setup tag to use with invalid chars and length, and expected cleaned up version.
708         String fullTag = "TestTag-_-_-12345678901234567890\\\"&:|<>";
709         String tagForFilename = "testtag---1234567890";
710 
711         // Now kick off the request.
712         mProfilingManager.requestProfiling(
713                 ProfilingManager.PROFILING_TYPE_STACK_SAMPLING,
714                 ProfilingTestUtils.getOneSecondDurationParamBundle(),
715                 fullTag,
716                 null,
717                 new ProfilingTestUtils.ImmediateExecutor(),
718                 callback);
719 
720         // Wait until callback#onAccept is triggered so we can confirm the result.
721         waitForCallback(callback);
722 
723         // Assert that used tag matches returned tag.
724         assertTrue(fullTag.equals(callback.mResult.getTag()));
725 
726         // Split the path to obtain the filename.
727         String[] pathArray = callback.mResult.getResultFilePath().split("/");
728         // Then split the filename to obtain the tag section.
729         String[] nameArray = pathArray[pathArray.length - 1].split("_");
730 
731         // Assert that the file name section containing the tag matches the expected filename tag.
732         assertTrue(nameArray[1].equals(tagForFilename));
733     }
734 
735     /** Test that java heap dump killswitch disables collection. */
736     @Test
737     @RequiresFlagsEnabled(Flags.FLAG_TELEMETRY_APIS)
testJavaHeapDumpKillswitchEnabled()738     public void testJavaHeapDumpKillswitchEnabled() throws Exception {
739         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
740 
741         disableRateLimiter();
742 
743         overrideJavaHeapDumpDeviceConfigValues(true, ONE_SECOND_MS, TEN_SECONDS_MS);
744 
745         AppCallback callback = new AppCallback();
746 
747         // Now kick off the request.
748         mProfilingManager.requestProfiling(
749                 ProfilingManager.PROFILING_TYPE_JAVA_HEAP_DUMP,
750                 null,
751                 null,
752                 null,
753                 new ProfilingTestUtils.ImmediateExecutor(),
754                 callback);
755 
756         // Wait until callback#onAccept is triggered so we can confirm the result.
757         waitForCallback(callback);
758 
759         // Assert that request failed with correct error code.
760         assertEquals(ProfilingResult.ERROR_FAILED_INVALID_REQUEST, callback.mResult.getErrorCode());
761     }
762 
763     /** Test that heap profile killswitch disables collection. */
764     @Test
765     @RequiresFlagsEnabled(Flags.FLAG_TELEMETRY_APIS)
testHeapProfileKillswitchEnabled()766     public void testHeapProfileKillswitchEnabled() throws Exception {
767         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
768 
769         disableRateLimiter();
770 
771         overrideHeapProfileDeviceConfigValues(true, ONE_SECOND_MS, FIVE_SECONDS_MS, TEN_SECONDS_MS);
772 
773         AppCallback callback = new AppCallback();
774 
775         // Now kick off the request.
776         mProfilingManager.requestProfiling(
777                 ProfilingManager.PROFILING_TYPE_HEAP_PROFILE,
778                 null,
779                 null,
780                 null,
781                 new ProfilingTestUtils.ImmediateExecutor(),
782                 callback);
783 
784         // Wait until callback#onAccept is triggered so we can confirm the result.
785         waitForCallback(callback);
786 
787         // Assert that request failed with correct error code.
788         assertEquals(ProfilingResult.ERROR_FAILED_INVALID_REQUEST, callback.mResult.getErrorCode());
789     }
790 
791     /** Test that stack sampling killswitch disables collection. */
792     @Test
793     @RequiresFlagsEnabled(Flags.FLAG_TELEMETRY_APIS)
testStackSamplingKillswitchEnabled()794     public void testStackSamplingKillswitchEnabled() throws Exception {
795         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
796 
797         disableRateLimiter();
798 
799         overrideStackSamplingDeviceConfigValues(true, ONE_SECOND_MS, FIVE_SECONDS_MS,
800                 TEN_SECONDS_MS);
801 
802         AppCallback callback = new AppCallback();
803 
804         // Now kick off the request.
805         mProfilingManager.requestProfiling(
806                 ProfilingManager.PROFILING_TYPE_STACK_SAMPLING,
807                 null,
808                 null,
809                 null,
810                 new ProfilingTestUtils.ImmediateExecutor(),
811                 callback);
812 
813         // Wait until callback#onAccept is triggered so we can confirm the result.
814         waitForCallback(callback);
815 
816         // Assert that request failed with correct error code.
817         assertEquals(ProfilingResult.ERROR_FAILED_INVALID_REQUEST, callback.mResult.getErrorCode());
818     }
819 
820     /** Test that system trace killswitch disables collection. */
821     @Test
822     @RequiresFlagsEnabled({Flags.FLAG_TELEMETRY_APIS, Flags.FLAG_REDACTION_ENABLED})
testSystemTraceKillswitchEnabled()823     public void testSystemTraceKillswitchEnabled() throws Exception {
824         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
825 
826         disableRateLimiter();
827 
828         overrideSystemTraceDeviceConfigValues(true, ONE_SECOND_MS, FIVE_SECONDS_MS, TEN_SECONDS_MS);
829 
830         AppCallback callback = new AppCallback();
831 
832         // Now kick off the request.
833         mProfilingManager.requestProfiling(
834                 ProfilingManager.PROFILING_TYPE_SYSTEM_TRACE,
835                 null,
836                 null,
837                 null,
838                 new ProfilingTestUtils.ImmediateExecutor(),
839                 callback);
840 
841         // Wait until callback#onAccept is triggered so we can confirm the result.
842         waitForCallback(callback);
843 
844         // Assert that request failed with correct error code.
845         assertEquals(ProfilingResult.ERROR_FAILED_INVALID_REQUEST, callback.mResult.getErrorCode());
846     }
847 
848     /**
849      * Test that adding a new general listener when no listeners have been added to that instance
850      * works correctly, that is: that mProfilingService has been initialized.
851      *
852      * The flow should result in registerResultsCallback being triggered with isGeneralListener true
853      * and generalListenerAdded not being triggered, but we cannot confirm this specifically here.
854      */
855     @SuppressWarnings("GuardedBy") // Suppress warning for mProfilingManager lock.
856     @Test
857     @RequiresFlagsEnabled({Flags.FLAG_TELEMETRY_APIS})
testAddGeneralListenerNoCurrentListeners()858     public void testAddGeneralListenerNoCurrentListeners() throws Exception {
859         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
860 
861         disableRateLimiter();
862 
863         // Setup for no current listener - mProfilingService should be null and mCallbacks empty.
864         mProfilingManager.mProfilingService = null;
865         mProfilingManager.mCallbacks.clear();
866 
867         AppCallback callback = new AppCallback();
868 
869         // Register the general callback.
870         mProfilingManager.registerForAllProfilingResults(new ProfilingTestUtils.ImmediateExecutor(),
871                 callback);
872 
873         // Confirm that mProfilingService has been initialized.
874         assertNotNull(mProfilingManager.mProfilingService);
875     }
876 
877     /**
878      * Test that adding a new profiling instance specific listener when no listeners have been
879      * added to that instance works correctly, that is: that mProfilingService has been initialized.
880      *
881      * The flow should result in registerResultsCallback being triggered with isGeneralListener
882      * false and generalListenerAdded not being triggered, but we cannot confirm this specifically
883      * here.
884      */
885     @SuppressWarnings("GuardedBy") // Suppress warning for mProfilingManager lock.
886     @Test
887     @RequiresFlagsEnabled({Flags.FLAG_TELEMETRY_APIS})
testAddSpecificListenerNoCurrentListeners()888     public void testAddSpecificListenerNoCurrentListeners() throws Exception {
889         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
890 
891         disableRateLimiter();
892 
893         overrideStackSamplingDeviceConfigValues(false, ONE_SECOND_MS, ONE_SECOND_MS,
894                 FIVE_SECONDS_MS);
895 
896         // Setup for no current listener - mProfilingService should be null and mCallbacks empty.
897         mProfilingManager.mProfilingService = null;
898         mProfilingManager.mCallbacks.clear();
899 
900         AppCallback callback = new AppCallback();
901 
902         mProfilingManager.requestProfiling(
903                 ProfilingManager.PROFILING_TYPE_STACK_SAMPLING,
904                 null,
905                 null,
906                 null,
907                 new ProfilingTestUtils.ImmediateExecutor(),
908                 callback);
909 
910         // Confirm that mProfilingService has been initialized.
911         assertNotNull(mProfilingManager.mProfilingService);
912     }
913 
914     /**
915      * Test that adding a new general listener when a listener has already been added to that
916      * instance works correctly, that is: generalListenerAdded is triggered, but
917      * registerResultsCallback is not.
918      */
919     @SuppressWarnings("GuardedBy") // Suppress warning for mProfilingManager lock.
920     @Test
921     @RequiresFlagsEnabled({Flags.FLAG_TELEMETRY_APIS})
testAddGeneralListenerWithCurrentListener()922     public void testAddGeneralListenerWithCurrentListener() throws Exception {
923         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
924 
925         disableRateLimiter();
926 
927         mProfilingManager.mProfilingService = spy(new ProfilingService(mContext));
928 
929         AppCallback callback = new AppCallback();
930 
931         // Register the general callback.
932         mProfilingManager.registerForAllProfilingResults(new ProfilingTestUtils.ImmediateExecutor(),
933                 callback);
934 
935         // Confirm that generalListenerAdded was triggered and registerResultsCallback was not.
936         verify(mProfilingManager.mProfilingService, times(0)).registerResultsCallback(anyBoolean(),
937                 any());
938         verify(mProfilingManager.mProfilingService, times(1)).generalListenerAdded();
939     }
940 
941     /**
942      * Test that adding a new profiling instance specific listener when a listener has already been
943      * added to that instance works correctly, that is: neither registerResultsCallback nor
944      * generalListenerAdded are triggered.
945      */
946     @SuppressWarnings("GuardedBy") // Suppress warning for mProfilingManager lock.
947     @Test
948     @RequiresFlagsEnabled({Flags.FLAG_TELEMETRY_APIS})
testAddSpecificListenerWithCurrentListener()949     public void testAddSpecificListenerWithCurrentListener() throws Exception {
950         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
951 
952         disableRateLimiter();
953 
954         overrideStackSamplingDeviceConfigValues(false, ONE_SECOND_MS, ONE_SECOND_MS,
955                 FIVE_SECONDS_MS);
956 
957         mProfilingManager.mProfilingService = spy(new ProfilingService(mContext));
958 
959         AppCallback callback = new AppCallback();
960 
961         mProfilingManager.requestProfiling(
962                 ProfilingManager.PROFILING_TYPE_STACK_SAMPLING,
963                 null,
964                 null,
965                 null,
966                 new ProfilingTestUtils.ImmediateExecutor(),
967                 callback);
968 
969         // Confirm that neither generalListenerAdded nor registerResultsCallback were triggered.
970         verify(mProfilingManager.mProfilingService, times(0)).registerResultsCallback(anyBoolean(),
971                 any());
972         verify(mProfilingManager.mProfilingService, times(0)).generalListenerAdded();
973     }
974 
975     /**
976      * Test adding a profiling trigger and receiving a result works correctly.
977      *
978      * This is done by: adding the trigger through the public api, force starting a system triggered
979      * trace, sending a fake trigger as if from the system, and then confirming the result is
980      * received.
981      */
982     @SuppressWarnings("GuardedBy") // Suppress warning for mProfilingManager lock.
983     @Test
984     @RequiresFlagsEnabled(android.os.profiling.Flags.FLAG_SYSTEM_TRIGGERED_PROFILING_NEW)
testSystemTriggeredProfiling()985     public void testSystemTriggeredProfiling() throws Exception {
986         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
987 
988         disableRateLimiter();
989 
990         // First add a trigger
991         ProfilingTrigger trigger = new ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_ANR)
992                 .setRateLimitingPeriodHours(1)
993                 .build();
994         mProfilingManager.addProfilingTriggers(List.of(trigger));
995 
996         // Verify the trigger and rate limiting period.
997         assertEquals(ProfilingTrigger.TRIGGER_TYPE_ANR, trigger.getTriggerType());
998         assertEquals(1, trigger.getRateLimitingPeriodHours());
999 
1000         // And add a global listener
1001         AppCallback callbackGeneral = new AppCallback();
1002         mProfilingManager.registerForAllProfilingResults(
1003                 new ProfilingTestUtils.ImmediateExecutor(), callbackGeneral);
1004 
1005         // Then start the system triggered trace for testing.
1006         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_STRING,
1007                 DeviceConfigHelper.NAMESPACE_TESTING,
1008                 DeviceConfigHelper.SYSTEM_TRIGGERED_TEST_PACKAGE_NAME,
1009                 REAL_PACKAGE_NAME);
1010 
1011         // Wait a bit so the trace can get started and actually collect something.
1012         sleep(WAIT_TIME_FOR_PROFILING_START_MS);
1013 
1014         // Now fake a system trigger.
1015         ProfilingServiceHelper.getInstance().onProfilingTriggerOccurred(Binder.getCallingUid(),
1016                 REAL_PACKAGE_NAME,
1017                 ProfilingTrigger.TRIGGER_TYPE_ANR);
1018 
1019         // Wait for the trace to process.
1020         waitForCallback(callbackGeneral);
1021 
1022         // Finally, confirm that a result was received.
1023         confirmCollectionSuccess(callbackGeneral.mResult, OUTPUT_FILE_TRACE_SUFFIX,
1024                 ProfilingTrigger.TRIGGER_TYPE_ANR);
1025     }
1026 
1027     /**
1028      * Test removing profiling trigger.
1029      *
1030      * There is no way to check the data structure from this context and that specifically is tested
1031      * in {@link ProfilingServiceTests}, so this test just ensures that a result is not received.
1032      */
1033     @SuppressWarnings("GuardedBy") // Suppress warning for mProfilingManager lock.
1034     @Test
1035     @RequiresFlagsEnabled(android.os.profiling.Flags.FLAG_SYSTEM_TRIGGERED_PROFILING_NEW)
testSystemTriggeredProfilingRemove()1036     public void testSystemTriggeredProfilingRemove() throws Exception {
1037         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
1038 
1039         disableRateLimiter();
1040 
1041         // First add a trigger
1042         ProfilingTrigger trigger = new ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_ANR)
1043                 .setRateLimitingPeriodHours(1)
1044                 .build();
1045         mProfilingManager.addProfilingTriggers(List.of(trigger));
1046 
1047         // And add a global listener
1048         AppCallback callbackGeneral = new AppCallback();
1049         mProfilingManager.registerForAllProfilingResults(
1050                 new ProfilingTestUtils.ImmediateExecutor(), callbackGeneral);
1051 
1052         // Then start the system triggered trace for testing.
1053         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_STRING,
1054                 DeviceConfigHelper.NAMESPACE_TESTING,
1055                 DeviceConfigHelper.SYSTEM_TRIGGERED_TEST_PACKAGE_NAME,
1056                 REAL_PACKAGE_NAME);
1057 
1058         // Wait a bit so the trace can get started and actually collect something.
1059         sleep(WAIT_TIME_FOR_PROFILING_START_MS);
1060 
1061         // Remove the trigger.
1062         mProfilingManager.removeProfilingTriggersByType(
1063                 new int[]{ProfilingTrigger.TRIGGER_TYPE_ANR});
1064 
1065         // Now fake a system trigger.
1066         ProfilingServiceHelper.getInstance().onProfilingTriggerOccurred(Binder.getCallingUid(),
1067                 REAL_PACKAGE_NAME,
1068                 ProfilingTrigger.TRIGGER_TYPE_ANR);
1069 
1070         // We can't wait for nothing to happen, so wait 10 seconds which should be long enough.
1071         sleep(WAIT_TIME_FOR_TRIGGERED_PROFILING_NO_RESULT);
1072 
1073         // Finally, confirm that no callback was received.
1074         assertNull(callbackGeneral.mResult);
1075     }
1076 
1077     /**
1078      * Test clearing all profiling triggers.
1079      *
1080      * There is no way to check the data structure from this context and that specifically is tested
1081      * in {@link ProfilingServiceTests}, so this test just ensures that a result is not received.
1082      */
1083     @SuppressWarnings("GuardedBy") // Suppress warning for mProfilingManager lock.
1084     @Test
1085     @RequiresFlagsEnabled(android.os.profiling.Flags.FLAG_SYSTEM_TRIGGERED_PROFILING_NEW)
testSystemTriggeredProfilingClear()1086     public void testSystemTriggeredProfilingClear() throws Exception {
1087         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
1088 
1089         disableRateLimiter();
1090 
1091         // First add a trigger
1092         ProfilingTrigger trigger = new ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_ANR)
1093                 .setRateLimitingPeriodHours(1)
1094                 .build();
1095         mProfilingManager.addProfilingTriggers(List.of(trigger));
1096 
1097         // And add a global listener
1098         AppCallback callbackGeneral = new AppCallback();
1099         mProfilingManager.registerForAllProfilingResults(
1100                 new ProfilingTestUtils.ImmediateExecutor(), callbackGeneral);
1101 
1102         // Then start the system triggered trace for testing.
1103         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_STRING,
1104                 DeviceConfigHelper.NAMESPACE_TESTING,
1105                 DeviceConfigHelper.SYSTEM_TRIGGERED_TEST_PACKAGE_NAME,
1106                 REAL_PACKAGE_NAME);
1107 
1108         // Wait a bit so the trace can get started and actually collect something.
1109         sleep(WAIT_TIME_FOR_PROFILING_START_MS);
1110 
1111         // Clear all triggers for this process.
1112         mProfilingManager.clearProfilingTriggers();
1113 
1114         // Now fake a system trigger.
1115         ProfilingServiceHelper.getInstance().onProfilingTriggerOccurred(Binder.getCallingUid(),
1116                 REAL_PACKAGE_NAME,
1117                 ProfilingTrigger.TRIGGER_TYPE_ANR);
1118 
1119         // We can't wait for nothing to happen, so wait 10 seconds which should be long enough.
1120         sleep(WAIT_TIME_FOR_TRIGGERED_PROFILING_NO_RESULT);
1121 
1122         // Finally, confirm that no callback was received.
1123         assertNull(callbackGeneral.mResult);
1124     }
1125 
1126     /**
1127      * Test {@link ProfilingResult} parcel read and write implementations match, correctly loading
1128      * result with the same values and leaving no data unread.
1129      */
1130     @Test
1131     @RequiresFlagsEnabled(Flags.FLAG_TELEMETRY_APIS)
testProfilingResultParcelReadWriteMatch()1132     public void testProfilingResultParcelReadWriteMatch() throws Exception {
1133         // Create a fake ProfilingResult with all fields set.
1134         ProfilingResult result = new ProfilingResult(
1135                 ProfilingResult.ERROR_FAILED_RATE_LIMIT_SYSTEM,
1136                 "/path/to/file.type",
1137                 "some_tag",
1138                 "This is an error message.",
1139                 ProfilingTrigger.TRIGGER_TYPE_APP_FULLY_DRAWN);
1140 
1141         // Write to parcel.
1142         Parcel parcel = Parcel.obtain();
1143         result.writeToParcel(parcel, 0 /* flags */);
1144 
1145         // Set the data position back to 0 so it's ready to be read.
1146         parcel.setDataPosition(0);
1147 
1148         // Now load from the parcel.
1149         ProfilingResult resultFromParcel = new ProfilingResult(parcel);
1150 
1151         // Make sure there is no unread data remaining in the parcel, and confirm that the loaded
1152         // object is equal to the one it was written from. Check dataAvail first as if that check
1153         // fails then the next check will fail too, but knowing the status of this check will tell
1154         // us that we're missing a read or write. Check the objects are equals second as  if the
1155         // avail check passes and equals fails, then we know we're reading all the data just not to
1156         // the correct fields.
1157         assertEquals(0, parcel.dataAvail());
1158         assertTrue(result.equals(resultFromParcel));
1159     }
1160 
1161     /**
1162      * Test that profiling request fails system rate limiter when cost exceeds max.
1163      *
1164      * This test in particular will fail the hour bucket just to verify end to end a system deny.
1165      * Testing for each time bucket is covered in service side tests.
1166      */
1167     @Test
1168     @RequiresFlagsEnabled({Flags.FLAG_TELEMETRY_APIS, Flags.FLAG_REDACTION_ENABLED})
testRateLimiterDenySystem()1169     public void testRateLimiterDenySystem() throws Exception {
1170         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
1171 
1172         enableRateLimiter();
1173 
1174         // Override rate limiter values such that the system trace cost is more than the system
1175         // limits but less than the process limits.
1176         overrideSystemTraceDeviceConfigValues(false, ONE_SECOND_MS, ONE_SECOND_MS, FIVE_SECONDS_MS);
1177         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1178                 DeviceConfigHelper.MAX_COST_SYSTEM_1_HOUR, 10);
1179         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1180                 DeviceConfigHelper.MAX_COST_SYSTEM_24_HOUR, 10);
1181         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1182                 DeviceConfigHelper.MAX_COST_SYSTEM_7_DAY, 10);
1183         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1184                 DeviceConfigHelper.MAX_COST_PROCESS_1_HOUR, 1000);
1185         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1186                 DeviceConfigHelper.MAX_COST_PROCESS_24_HOUR, 1000);
1187         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1188                 DeviceConfigHelper.MAX_COST_PROCESS_7_DAY, 1000);
1189         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1190                 DeviceConfigHelper.COST_SYSTEM_TRACE, 100);
1191 
1192         AppCallback callback = new AppCallback();
1193 
1194         // Now kick off the request.
1195         mProfilingManager.requestProfiling(
1196                 ProfilingManager.PROFILING_TYPE_SYSTEM_TRACE,
1197                 ProfilingTestUtils.getOneSecondDurationParamBundle(),
1198                 null,
1199                 null,
1200                 new ProfilingTestUtils.ImmediateExecutor(),
1201                 callback);
1202 
1203         // Wait until callback#onAccept is triggered so we can confirm the result.
1204         waitForCallback(callback);
1205 
1206         // Assert request failed with system rate limiting error.
1207         assertEquals(ProfilingResult.ERROR_FAILED_RATE_LIMIT_SYSTEM,
1208                 callback.mResult.getErrorCode());
1209     }
1210 
1211     /**
1212      * Test that profiling request fails process rate limiter when cost exceeds max.
1213      *
1214      * This test in particular will fail the hour bucket just to verify end to end a process deny.
1215      * Testing for each time bucket is covered in service side tests.
1216      */
1217     @Test
1218     @RequiresFlagsEnabled({Flags.FLAG_TELEMETRY_APIS, Flags.FLAG_REDACTION_ENABLED})
testRateLimiterDenyProcess()1219     public void testRateLimiterDenyProcess() throws Exception {
1220         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
1221 
1222         enableRateLimiter();
1223 
1224         // Override rate limiter values such that the system trace cost is more than the process
1225         // limits but less than the system limits.
1226         overrideSystemTraceDeviceConfigValues(false, ONE_SECOND_MS, ONE_SECOND_MS, FIVE_SECONDS_MS);
1227         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1228                 DeviceConfigHelper.MAX_COST_SYSTEM_1_HOUR, 1000);
1229         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1230                 DeviceConfigHelper.MAX_COST_SYSTEM_24_HOUR, 1000);
1231         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1232                 DeviceConfigHelper.MAX_COST_SYSTEM_7_DAY, 1000);
1233         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1234                 DeviceConfigHelper.MAX_COST_PROCESS_1_HOUR, 10);
1235         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1236                 DeviceConfigHelper.MAX_COST_PROCESS_24_HOUR, 10);
1237         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1238                 DeviceConfigHelper.MAX_COST_PROCESS_7_DAY, 10);
1239         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1240                 DeviceConfigHelper.COST_SYSTEM_TRACE, 100);
1241 
1242         AppCallback callback = new AppCallback();
1243 
1244         // Now kick off the request.
1245         mProfilingManager.requestProfiling(
1246                 ProfilingManager.PROFILING_TYPE_SYSTEM_TRACE,
1247                 ProfilingTestUtils.getOneSecondDurationParamBundle(),
1248                 null,
1249                 null,
1250                 new ProfilingTestUtils.ImmediateExecutor(),
1251                 callback);
1252 
1253         // Wait until callback#onAccept is triggered so we can confirm the result.
1254         waitForCallback(callback);
1255 
1256         // Assert request failed with process rate limiting error.
1257         assertEquals(ProfilingResult.ERROR_FAILED_RATE_LIMIT_PROCESS,
1258                 callback.mResult.getErrorCode());
1259     }
1260 
1261     /** Test that profiling request passes system rate limiter. */
1262     @Test
1263     @RequiresFlagsEnabled({Flags.FLAG_TELEMETRY_APIS, Flags.FLAG_REDACTION_ENABLED})
testRateLimiterAllow()1264     public void testRateLimiterAllow() throws Exception {
1265         if (mProfilingManager == null) throw new TestException("mProfilingManager can not be null");
1266 
1267         enableRateLimiter();
1268 
1269         // Override rate limiter values such that the system trace cost is less than both the system
1270         // and process limits.
1271         overrideSystemTraceDeviceConfigValues(false, ONE_SECOND_MS, ONE_SECOND_MS, FIVE_SECONDS_MS);
1272         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1273                 DeviceConfigHelper.MAX_COST_SYSTEM_1_HOUR, 1000);
1274         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1275                 DeviceConfigHelper.MAX_COST_SYSTEM_24_HOUR, 1000);
1276         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1277                 DeviceConfigHelper.MAX_COST_SYSTEM_7_DAY, 1000);
1278         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1279                 DeviceConfigHelper.MAX_COST_PROCESS_1_HOUR, 1000);
1280         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1281                 DeviceConfigHelper.MAX_COST_PROCESS_24_HOUR, 1000);
1282         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1283                 DeviceConfigHelper.MAX_COST_PROCESS_7_DAY, 1000);
1284         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1285                 DeviceConfigHelper.COST_SYSTEM_TRACE, 100);
1286 
1287         AppCallback callback = new AppCallback();
1288 
1289         // Now kick off the request.
1290         mProfilingManager.requestProfiling(
1291                 ProfilingManager.PROFILING_TYPE_SYSTEM_TRACE,
1292                 ProfilingTestUtils.getOneSecondDurationParamBundle(),
1293                 null,
1294                 null,
1295                 new ProfilingTestUtils.ImmediateExecutor(),
1296                 callback);
1297 
1298         // Wait until callback#onAccept is triggered so we can confirm the result.
1299         waitForCallback(callback);
1300 
1301         // Assert request returned with no error indicating that the rate limiter allowed the run.
1302         assertEquals(ProfilingResult.ERROR_NONE, callback.mResult.getErrorCode());
1303     }
1304 
1305     /** Disable the rate limiter and wait long enough for the update to be picked up. */
disableRateLimiter()1306     private void disableRateLimiter() throws Exception {
1307         overrideRateLimiter(true);
1308     }
1309 
1310     /** Enable the rate limiter and wait long enough for the update to be picked up. */
enableRateLimiter()1311     private void enableRateLimiter() throws Exception {
1312         overrideRateLimiter(false);
1313     }
1314 
1315     /**
1316      * Override the rate limiter to the provided value and wait long enough for the update to be
1317      * picked up.
1318      */
overrideRateLimiter(boolean disable)1319     private void overrideRateLimiter(boolean disable) throws Exception {
1320         executeShellCmd(
1321                 "device_config put profiling_testing rate_limiter.disabled %s", disable);
1322         for (int i = 0; i < RATE_LIMITER_WAIT_TIME_INCREMENTS_COUNT; i++) {
1323             sleep(RATE_LIMITER_WAIT_TIME_INCREMENT_MS);
1324             String output = executeShellCmd(
1325                     "device_config get profiling_testing rate_limiter.disabled");
1326             if (Boolean.parseBoolean(output.trim()) == disable) {
1327                 return;
1328             }
1329         }
1330     }
1331 
1332     /** Wait for callback to be triggered. Waits for up to 5 minutes, checking every 5 seconds. */
waitForCallback(AppCallback callback)1333     private void waitForCallback(AppCallback callback) {
1334         waitForCallback(callback, CALLBACK_WAIT_TIME_INCREMENT_MS,
1335                 CALLBACK_WAIT_TIME_INCREMENTS_COUNT);
1336     }
1337 
1338     /**
1339      * Wait for callback to be triggered after cancellation. Waits for up to 20 seconds, checking
1340      * every 5 seconds.
1341      */
waitForCancelCallback(AppCallback callback)1342     private void waitForCancelCallback(AppCallback callback) {
1343         waitForCallback(callback, CALLBACK_WAIT_TIME_INCREMENT_MS,
1344                 CALLBACK_CANCEL_WAIT_TIME_INCREMENTS_COUNT);
1345     }
1346 
1347     /**
1348      * Wait for callback to be triggered. Waits up to incrementMs * count, checking every
1349      * incrementMs milliseconds.
1350      */
waitForCallback(AppCallback callback, int incrementMs, int count)1351     private void waitForCallback(AppCallback callback, int incrementMs, int count) {
1352         for (int i = 0; i < count; i++) {
1353             sleep(incrementMs);
1354             if (callback.mResult != null) {
1355                 return;
1356             }
1357         }
1358         fail("Test timed out waiting for callback");
1359     }
1360 
1361     /** Assert that result matches a success case, specifically: contains a path and no errors. */
confirmCollectionSuccess(ProfilingResult result, String suffix)1362     private void confirmCollectionSuccess(ProfilingResult result, String suffix) {
1363         confirmCollectionSuccess(result, suffix, 0);
1364     }
1365 
1366     /** Assert that result matches a success case, specifically: contains a path and no errors. */
confirmCollectionSuccess(ProfilingResult result, String suffix, int triggerType)1367     private void confirmCollectionSuccess(ProfilingResult result, String suffix, int triggerType) {
1368         assertNotNull(result);
1369         assertEquals(ProfilingResult.ERROR_NONE, result.getErrorCode());
1370         assertNotNull(result.getResultFilePath());
1371         assertTrue(result.getResultFilePath().contains(suffix));
1372         assertNull(result.getErrorMessage());
1373         assertEquals(triggerType, result.getTriggerType());
1374 
1375         // Confirm output file exists and is not empty.
1376         File file = new File(result.getResultFilePath());
1377         assertTrue(file.exists());
1378         assertFalse(file.length() == 0);
1379     }
1380 
1381     /** Copies the trace to an /sdcard directory that will be collected by the test runner. */
dumpTrace(ProfilingResult result)1382     private void dumpTrace(ProfilingResult result) {
1383         assertNotNull(result);
1384         assertEquals(ProfilingResult.ERROR_NONE, result.getErrorCode());
1385         assertNotNull(result.getResultFilePath());
1386         assertNull(result.getErrorMessage());
1387 
1388         // Copy to dump directory
1389         Path path = Paths.get(result.getResultFilePath());
1390         try {
1391             Files.createDirectories(DUMP_PATH);
1392             String filename = mTestName.getMethodName() + "_" + path.getFileName()
1393                     + ".perfetto-trace";
1394             Files.copy(path, Paths.get(DUMP_PATH.toString(), filename));
1395         } catch (IOException e) {
1396             throw new AssertionError("Failed to copy to DUMP_PATH", e);
1397         }
1398     }
1399 
overrideJavaHeapDumpDeviceConfigValues(boolean killswitchEnabled, int durationMs, int dataSourceTimeoutMs)1400     private void overrideJavaHeapDumpDeviceConfigValues(boolean killswitchEnabled, int durationMs,
1401             int dataSourceTimeoutMs) throws Exception {
1402         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_BOOL, DeviceConfigHelper.NAMESPACE,
1403                 DeviceConfigHelper.KILLSWITCH_JAVA_HEAP_DUMP, killswitchEnabled);
1404         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1405                 DeviceConfigHelper.JAVA_HEAP_DUMP_DURATION_MS_DEFAULT, durationMs);
1406         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1407                 DeviceConfigHelper.JAVA_HEAP_DUMP_DATA_SOURCE_STOP_TIMEOUT_MS_DEFAULT,
1408                 dataSourceTimeoutMs);
1409     }
1410 
overrideHeapProfileDeviceConfigValues(boolean killswitchEnabled, int durationDefaultMs, int durationMinMs, int durationMaxMs)1411     private void overrideHeapProfileDeviceConfigValues(boolean killswitchEnabled,
1412             int durationDefaultMs, int durationMinMs, int durationMaxMs) throws Exception {
1413         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_BOOL, DeviceConfigHelper.NAMESPACE,
1414                 DeviceConfigHelper.KILLSWITCH_HEAP_PROFILE, killswitchEnabled);
1415         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1416                 DeviceConfigHelper.HEAP_PROFILE_DURATION_MS_DEFAULT, durationDefaultMs);
1417         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1418                 DeviceConfigHelper.HEAP_PROFILE_DURATION_MS_MIN, durationMinMs);
1419         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1420                 DeviceConfigHelper.HEAP_PROFILE_DURATION_MS_MAX, durationMaxMs);
1421     }
1422 
overrideStackSamplingDeviceConfigValues(boolean killswitchEnabled, int durationDefaultMs, int durationMinMs, int durationMaxMs)1423     private void overrideStackSamplingDeviceConfigValues(boolean killswitchEnabled,
1424             int durationDefaultMs, int durationMinMs, int durationMaxMs) throws Exception {
1425         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_BOOL, DeviceConfigHelper.NAMESPACE,
1426                 DeviceConfigHelper.KILLSWITCH_STACK_SAMPLING, killswitchEnabled);
1427         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1428                 DeviceConfigHelper.STACK_SAMPLING_DURATION_MS_DEFAULT, durationDefaultMs);
1429         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1430                 DeviceConfigHelper.STACK_SAMPLING_DURATION_MS_MIN, durationMinMs);
1431         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1432                 DeviceConfigHelper.STACK_SAMPLING_DURATION_MS_MAX, durationMaxMs);
1433     }
1434 
overrideSystemTraceDeviceConfigValues(boolean killswitchEnabled, int durationDefaultMs, int durationMinMs, int durationMaxMs)1435     private void overrideSystemTraceDeviceConfigValues(boolean killswitchEnabled,
1436             int durationDefaultMs, int durationMinMs, int durationMaxMs) throws Exception {
1437         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_BOOL, DeviceConfigHelper.NAMESPACE,
1438                 DeviceConfigHelper.KILLSWITCH_SYSTEM_TRACE, killswitchEnabled);
1439         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1440                 DeviceConfigHelper.SYSTEM_TRACE_DURATION_MS_DEFAULT, durationDefaultMs);
1441         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1442                 DeviceConfigHelper.SYSTEM_TRACE_DURATION_MS_MIN, durationMinMs);
1443         executeShellCmd(COMMAND_OVERRIDE_DEVICE_CONFIG_INT, DeviceConfigHelper.NAMESPACE,
1444                 DeviceConfigHelper.SYSTEM_TRACE_DURATION_MS_MAX, durationMaxMs);
1445     }
1446 
1447     @FormatMethod
executeShellCmd(String cmdFormat, Object... args)1448     private String executeShellCmd(String cmdFormat, Object... args) throws Exception {
1449         String cmd = String.format(cmdFormat, args);
1450         return SystemUtil.runShellCommand(mInstrumentation, cmd);
1451     }
1452 
sleep(long ms)1453     private static void sleep(long ms) {
1454         try {
1455             Thread.sleep(ms);
1456         } catch (InterruptedException e) {
1457             // Do nothing.
1458         }
1459     }
1460 
doMallocAndFree()1461     private static native void doMallocAndFree();
1462 
1463     public static class AppCallback implements Consumer<ProfilingResult> {
1464 
1465         public ProfilingResult mResult;
1466 
1467         @Override
accept(ProfilingResult result)1468         public void accept(ProfilingResult result) {
1469             mResult = result;
1470         }
1471     }
1472 
1473     // Starts a thread that keeps a CPU busy.
1474     private static class BusyLoopThread {
1475         private Thread mThread;
1476         private AtomicBoolean mDone = new AtomicBoolean(false);
1477 
BusyLoopThread()1478         BusyLoopThread() {
1479             mDone.set(false);
1480             mThread = new Thread(() -> {
1481                 while (!mDone.get()) {
1482                   // Keep spinning!
1483                 }
1484             });
1485             mThread.start();
1486         }
1487 
stop()1488         public void stop() {
1489             mDone.set(true);
1490             try {
1491                 mThread.join();
1492             } catch (InterruptedException e) {
1493                 throw new AssertionError("InterruptedException", e);
1494             }
1495         }
1496     }
1497 
1498     // Starts a thread that repeatedly issues malloc() and free().
1499     private static class MallocLoopThread {
1500         private Thread mThread;
1501         private AtomicBoolean mDone = new AtomicBoolean(false);
1502 
MallocLoopThread()1503         MallocLoopThread() {
1504             mDone.set(false);
1505             mThread = new Thread(() -> {
1506                 while (!mDone.get()) {
1507                     doMallocAndFree();
1508                     sleep(10);
1509                 }
1510             });
1511             mThread.start();
1512         }
1513 
stop()1514         public void stop() {
1515             mDone.set(true);
1516             try {
1517                 mThread.join();
1518             } catch (InterruptedException e) {
1519                 throw new AssertionError("InterruptedException", e);
1520             }
1521         }
1522     }
1523 }
1524