Trang này trình bày cách ghi lại dấu vết hệ thống bằng API ProfilingManager.
ProfilingManager cũng có thể ghi lại các loại hồ sơ khác. Quy trình này tương tự như quy trình ghi lại dấu vết hệ thống, nhưng mỗi loại sử dụng một trình tạo khác nhau. Sau đây là các hồ sơ được hỗ trợ và trình tạo tương ứng:
Dấu vết hệ thống: Được ghi lại bằng
SystemTraceRequestBuilder, rất hữu ích cho việc phân tích độ trễ và gỡ lỗi hiệu suất chung.Tệp báo lỗi: Được ghi bằng
JavaHeapDumpRequestBuilder, rất hữu ích cho việc phát hiện và tối ưu hoá tình trạng rò rỉ bộ nhớ.Hồ sơ vùng nhớ khối xếp: Được ghi lại bằng
HeapProfileRequestBuilder, rất hữu ích cho việc tối ưu hoá bộ nhớ.Hồ sơ ngăn xếp lệnh gọi: Được ghi lại bằng
StackSamplingRequestBuilder, rất hữu ích cho việc tìm hiểu quá trình thực thi mã và phân tích độ trễ.
Thêm phần phụ thuộc
Để có trải nghiệm tốt nhất với API ProfilingManager, hãy thêm các thư viện Jetpack sau vào tệp build.gradle.kts.
Kotlin
dependencies { implementation("androidx.tracing:tracing-ktx:2.0.1") implementation("androidx.core:core:1.19.0") }
Groovy
dependencies { implementation 'androidx.tracing:tracing:2.0.1' implementation 'androidx.core:core:1.19.0' }
Ghi lại dấu vết hệ thống
Sau khi thêm các phần phụ thuộc bắt buộc, hãy dùng mã sau để ghi lại dấu vết hệ thống. Ví dụ này cho thấy cách bắt đầu một phiên lập hồ sơ từ một thành phần kết hợp trong khi quản lý an toàn các thao tác nặng ngoài luồng chính.
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();
}
Mã mẫu thiết lập và quản lý phiên lập hồ sơ bằng cách thực hiện các bước sau:
Thiết lập trình thực thi. Tạo một
Executorđể xác định luồng sẽ nhận kết quả lập hồ sơ. Quá trình lập hồ sơ diễn ra ở chế độ nền. Việc sử dụng một trình thực thi luồng không phải giao diện người dùng sẽ giúp ngăn lỗi Ứng dụng không phản hồi (ANR) nếu sau này bạn thêm nhiều quy trình xử lý hơn vào lệnh gọi lại.Xử lý kết quả phân tích tài nguyên. Tạo đối tượng
Consumer<ProfilingResult>. Hệ thống sử dụng đối tượng này để gửi kết quả lập hồ sơ từProfilingManagertrở lại ứng dụng của bạn.Tạo yêu cầu lập hồ sơ. Tạo một
SystemTraceRequestBuilderđể thiết lập phiên lập hồ sơ. Trình tạo này cho phép bạn tuỳ chỉnh các chế độ cài đặt dấu vếtProfilingManager. Bạn không bắt buộc phải tuỳ chỉnh trình tạo; nếu không, hệ thống sẽ sử dụng các chế độ cài đặt mặc định.- Xác định thẻ. Sử dụng
setTag()để thêm thẻ vào tên dấu vết. Thẻ này giúp bạn xác định dấu vết. - Không bắt buộc: Đặt thời lượng. Sử dụng
setDurationMs()để chỉ định thời gian cần lập hồ sơ (tính bằng mili giây). Ví dụ:60000đặt một dấu vết 60 giây. Hoạt động theo dõi sẽ tự động kết thúc sau khoảng thời gian đã chỉ định nếuCancellationSignalkhông được kích hoạt trước đó. - Chọn chính sách về khoảng đệm. Sử dụng
setBufferFillPolicy()để xác định cách lưu trữ dữ liệu dấu vết.BufferFillPolicy.RING_BUFFERcó nghĩa là khi bộ nhớ đệm đầy, dữ liệu mới sẽ ghi đè dữ liệu cũ nhất, duy trì bản ghi liên tục về hoạt động gần đây. - Đặt dung lượng bộ nhớ đệm. Sử dụng
setBufferSizeKb()để chỉ định dung lượng bộ nhớ đệm cho hoạt động theo dõi. Bạn có thể dùng dung lượng này để kiểm soát kích thước của tệp dấu vết đầu ra.
- Xác định thẻ. Sử dụng
Không bắt buộc: Quản lý vòng đời của phiên. Tạo
CancellationSignal. Đối tượng này cho phép bạn dừng phiên lập hồ sơ bất cứ khi nào bạn muốn, giúp bạn kiểm soát chính xác độ dài của phiên.Bắt đầu và nhận kết quả. Khi bạn gọi
requestProfiling(),ProfilingManagersẽ bắt đầu một phiên lập hồ sơ ở chế độ nền. Sau khi lập hồ sơ xong, nó sẽ gửiProfilingResultđến phương thứcresultCallback#acceptcủa bạn. Nếu quá trình lập hồ sơ hoàn tất thành công,ProfilingResultsẽ cung cấp đường dẫn nơi dấu vết được lưu trên thiết bị của bạn thông quaProfilingResult#getResultFilePath. Bạn có thể lấy tệp này theo cách lập trình hoặc để lập hồ sơ cục bộ, bằng cách chạyadb pull <trace_path>trên máy tính.Thêm các điểm theo dõi tuỳ chỉnh. Bạn có thể thêm các điểm theo dõi tuỳ chỉnh vào mã của ứng dụng. Trong ví dụ về mã trước đó, khối
trace("MyApp:HeavyOperation") { ... }sẽ tạo một lát cắt tuỳ chỉnh trong hồ sơ đã tạo.