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