本页介绍了如何使用 ProfilingManager API 记录系统跟踪。
ProfilingManager 还可以记录其他类型的性能分析数据。此过程与记录系统跟踪记录类似,但每种类型都使用不同的构建器。支持的配置文件及其构建器如下:
系统跟踪记录:使用
SystemTraceRequestBuilder记录,可用于延迟时间分析和常规性能调试。堆转储:使用
JavaHeapDumpRequestBuilder记录,有助于检测和优化内存泄漏。堆分析报告:使用
HeapProfileRequestBuilder记录,可用于内存优化。调用堆栈配置文件:使用
StackSamplingRequestBuilder记录,有助于了解代码执行和延迟时间分析。
添加依赖项
为了在使用 ProfilingManager API 时获得最佳体验,请将以下 Jetpack 库添加到 build.gradle.kts 文件中。
Kotlin
dependencies { implementation("androidx.tracing:tracing-ktx:2.0.5") implementation("androidx.core:core:1.19.1") }
Groovy
dependencies { implementation 'androidx.tracing:tracing:2.0.5' implementation 'androidx.core:core:1.19.1' }
录制系统跟踪记录
添加所需的依赖项后,使用以下代码记录系统跟踪。此示例展示了如何从可组合项启动性能分析会话,同时在主线程之外安全地管理繁重的操作。
Kotlin
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@Composable
fun ProfiledScreen(modifier: Modifier = Modifier) {
// Use the application context: requestProfiling resolves the ProfilingManager
// system service from it, so there's no reason to hand it a short-lived Activity.
val appContext = LocalContext.current.applicationContext
val scope = rememberCoroutineScope()
Button(
onClick = {
// Run the orchestration off the main thread. Profiling a heavy operation
// on the UI thread would freeze the UI (ANR) and distort the very metrics
// you're trying to capture.
//
// Note: this scope is tied to composition. If the user leaves this screen
// mid-session, the coroutine is cancelled and stopSignal.cancel() might not
// run, but setDurationMs() acts as a safety net and ends the trace.
scope.launch(Dispatchers.Default) {
val callbackExecutor = Dispatchers.IO.asExecutor()
val resultCallback = Consumer<ProfilingResult> { profilingResult ->
if (profilingResult.errorCode == ProfilingResult.ERROR_NONE) {
Log.d("ProfileTest", "Result file: ${profilingResult.resultFilePath}")
} else {
// errorMessage explains the failure (e.g., rate limiting); keep it.
Log.e(
"ProfileTest",
"Profiling failed errorCode=${profilingResult.errorCode} " +
"errorMessage=${profilingResult.errorMessage}"
)
}
}
val stopSignal = CancellationSignal()
val requestBuilder = SystemTraceRequestBuilder().apply {
setCancellationSignal(stopSignal)
setTag("FOO") // Caller-supplied tag for identification.
setDurationMs(60000) // Hard cap: ends the session if cancel() never fires.
setBufferFillPolicy(BufferFillPolicy.RING_BUFFER)
setBufferSizeKb(32768)
}
// 1. Start the session. This is asynchronous system IPC. The tracing
// engine takes a moment to start and allocate buffers.
requestProfiling(appContext, requestBuilder.build(), callbackExecutor, resultCallback)
// 2. The API exposes no "profiling started" signal, so pad with a short,
// best-effort delay before running the code you care about. This is
// approximate. Increase it on slower or heavily loaded devices.
delay(STARTUP_PADDING_MS)
// 3. The session is already recording every thread in your app. This slice
// doesn't scope what's captured. It just labels this region of the
// timeline so heavyOperation() is easier to find. trace { } closes the
// section even if the block throws.
trace("MyApp:HeavyOperation") {
heavyOperation()
}
// 4. Stop recording. Until this fires or the setDurationMs() cap is
// reached (whichever comes first), the session keeps capturing app-wide
// activity.
stopSignal.cancel()
}
}
) {
Text("Run & Profile Heavy Operation")
}
}
// Best-effort wait for the system trace engine to initialize before profiling.
// There is no deterministic start callback; tune this for your target devices.
private const val STARTUP_PADDING_MS = 100L
fun heavyOperation() {
// Background computations 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(32768);
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();
}
示例代码通过以下步骤设置和管理性能分析会话:
设置执行器。创建一个
Executor来定义将接收性能分析结果的线程。性能分析在后台进行。如果您稍后向回调添加更多处理,使用非界面线程执行器有助于防止出现“应用无响应”(ANR) 错误。处理性能分析结果。创建一个
Consumer<ProfilingResult>对象。 系统会使用此对象将分析结果从ProfilingManager发送回您的应用。构建性能分析请求。创建
SystemTraceRequestBuilder以设置性能剖析会话。此构建器可让您自定义ProfilingManager跟踪设置。自定义构建器是可选的;如果您不进行自定义,系统将使用默认设置。- 定义代码。使用
setTag()向跟踪记录名称添加标记。此标记可帮助您识别跟踪记录。 - 可选:设置时长。使用
setDurationMs()指定性能分析时长(以毫秒为单位)。例如,60000会设置 60 秒的跟踪记录。如果在此之前未触发CancellationSignal,则跟踪会在指定时长后自动结束。 - 选择缓冲区政策。使用
setBufferFillPolicy()定义跟踪数据的存储方式。BufferFillPolicy.RING_BUFFER表示当缓冲区已满时,新数据会覆盖最旧的数据,从而持续记录近期活动。 - 设置缓冲区空间。使用
setBufferSizeKb()指定跟踪缓冲区空间,您可以使用该空间来控制输出跟踪文件的大小。
- 定义代码。使用
可选:管理会话生命周期。创建
CancellationSignal。 借助此对象,您可以随时停止性能分析会话,从而精确控制其时长。启动并接收结果。当您调用
requestProfiling()时,ProfilingManager会在后台启动性能剖析会话。分析完成后,它会将ProfilingResult发送到您的resultCallback#accept方法。如果性能分析成功完成,ProfilingResult会通过ProfilingResult#getResultFilePath提供跟踪记录在设备上的保存路径。您可以通过编程方式获取此文件,也可以通过从计算机运行adb pull <trace_path>来获取此文件(对于本地性能分析)。添加自定义跟踪点。您可以在应用代码中添加自定义跟踪点。在前面的代码示例中,
trace("MyApp:HeavyOperation") { ... }块在生成的配置文件中创建了一个自定义切片。