This page shows how to record a system trace using the ProfilingManager API.
ProfilingManager can also record other types of profiles. This process is
similar to recording a system trace. The key difference is that you'll use a
specific builder from the following list, depending on the profile type you
need:
- Heap dumps: Recorded using
JavaHeapDumpRequestBuilder, which are helpful for memory leak detection and optimization. - Heap profiles: Recorded using
HeapProfileRequestBuilder, which are useful for memory optimization. - Call stack profiles: Recorded using
StackSamplingRequestBuilder, which are useful for understanding and latency analysis.
Add dependencies
For the best experience with the ProfilingManager API, add the following
Jetpack libraries to your build.gradle.kts file.
Kotlin
dependencies { implementation("androidx.tracing:tracing:1.3.0") implementation("androidx.core:core:1.17.0") }
Groovy
dependencies { implementation 'androidx.tracing:tracing:1.3.0' implementation 'androidx.core:core:1.17.0' }
Record a system trace
After adding the required dependencies, use the following code to record a
system trace. This example shows a basic setup within an Activity to start and
manage a profiling session.
Kotlin
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) fun sampleRecordSystemTrace() { val mainExecutor: Executor = Dispatchers.IO.asExecutor() // Your choice of executor for the callback to occur on. val resultCallback = Consumer<ProfilingResult> { profilingResult -> if (profilingResult.errorCode == ProfilingResult.ERROR_NONE) { Log.d( "ProfileTest", "Received profiling result file=" + profilingResult.resultFilePath ) } else { Log.e( "ProfileTest", "Profiling failed errorcode=" + profilingResult.errorCode + " errormsg=" + profilingResult.errorMessage ) } } val stopSignal = CancellationSignal() val requestBuilder = SystemTraceRequestBuilder() requestBuilder.setCancellationSignal(stopSignal) requestBuilder.setTag("FOO") // Caller supplied tag for identification requestBuilder.setDurationMs(60000) requestBuilder.setBufferFillPolicy(BufferFillPolicy.RING_BUFFER) requestBuilder.setBufferSizeKb(20971520) requestProfiling(applicationContext, requestBuilder.build(), mainExecutor, resultCallback) // Wait some time for profiling to start. Trace.beginSection("MyApp:HeavyOperation") heavyOperation() Trace.endSection() // Once the interesting code section is profiled, stop profile stopSignal.cancel() } fun heavyOperation() { // Computations you want to profile }
Java
void heavyOperation() { // Computations you want to profile } void sampleRecordSystemTrace() { Executor mainExecutor = Executors.newSingleThreadExecutor(); Consumer<ProfilingResult> resultCallback = new Consumer<ProfilingResult>() { @Override public void accept(ProfilingResult profilingResult) { if (profilingResult.getErrorCode() == ProfilingResult.ERROR_NONE) { Log.d( "ProfileTest", "Received profiling result file=" + profilingResult.getResultFilePath()); setupProfileUploadWorker(profilingResult.getResultFilePath()); } else { Log.e( "ProfileTest", "Profiling failed errorcode=" + profilingResult.getErrorCode() + " errormsg=" + profilingResult.getErrorMessage()); } } }; CancellationSignal stopSignal = new CancellationSignal(); SystemTraceRequestBuilder requestBuilder = new SystemTraceRequestBuilder(); requestBuilder.setCancellationSignal(stopSignal); requestBuilder.setTag("FOO"); requestBuilder.setDurationMs(60000); requestBuilder.setBufferFillPolicy(BufferFillPolicy.RING_BUFFER); requestBuilder.setBufferSizeKb(20971520); Profiling.requestProfiling(getApplicationContext(), requestBuilder.build(), mainExecutor, resultCallback); // Wait some time for profiling to start. Trace.beginSection("MyApp:HeavyOperation"); heavyOperation(); Trace.endSection(); // Once the interesting code section is profiled, stop profile stopSignal.cancel(); }
The sample code sets up and manages the profiling session by going through the following steps:
Set up the executor. Create an
Executorto define the thread that will receive the profiling results. Profiling happens in the background. Using a non-UI thread executor helps prevent Application Not Responding (ANR) errors if you add more processing to the callback later.Handle profiling results. Create a
Consumer<ProfilingResult>object. The system uses this object to send profiling results fromProfilingManagerback to your app.Build the profiling request. Create a
SystemTraceRequestBuilderto set up your profiling session. This builder lets you customizeProfilingManagertrace settings. Customizing the builder is optional; if you don't, the system uses default settings.- Define a tag. Use
setTag()to add a tag to the trace name. This tag helps you identify the trace. - Optional: Set the duration. Use
setDurationMs()to specify how long to profile in milliseconds. For example,60000sets a 60-second trace. The trace automatically ends after the specified duration ifCancellationSignalisn't triggered before that. - Choose a buffer policy. Use
setBufferFillPolicy()to define how trace data is stored.BufferFillPolicy.RING_BUFFERmeans that when the buffer is full, new data overwrites the oldest data, keeping a continuous record of recent activity. - Set a buffer size. Use
setBufferSizeKb()to specify a buffer size for tracing which you can use to control the size of the output trace file.
- Define a tag. Use
Optional: Manage the session lifecycle. Create a
CancellationSignal. This object lets you stop the profiling session whenever you want, giving you precise control over its length.Start and receive results. When you call
requestProfiling(),ProfilingManagerstarts a profiling session in the background. Once profiling is done, it sends theProfilingResultto yourresultCallback#acceptmethod. If profiling finishes successfully, theProfilingResultprovides the path where the trace was saved on your device throughProfilingResult#getResultFilePath. You can get this file programmatically or, for local profiling, by runningadb pull <trace_path>from your computer.Add custom trace points. You can add custom trace points in your app's code. In the previous code example, a trace slice named
MyApp:HeavyOperationis added usingTrace.beginSection()andTrace.endSection(). This custom slice appears in the generated profile, highlighting specific operations within your app.