توضّح هذه الصفحة كيفية تسجيل تتبُّع النظام باستخدام واجهة برمجة التطبيقات ProfilingManager.
يمكن لحساب ProfilingManager أيضًا تسجيل أنواع أخرى من الملفات الشخصية. تشبه هذه العملية تسجيل تتبُّع النظام، ولكن يستخدم كل نوع أداة إنشاء مختلفة. في ما يلي الملفات الشخصية المتوافقة وأدوات الإنشاء الخاصة بها:
عمليات تتبُّع النظام: يتم تسجيلها باستخدام
SystemTraceRequestBuilder، وهي مفيدة لتحليل وقت الاستجابة وتصحيح الأخطاء العامة في الأداء.لقطات أجزاء من الذاكرة: يتم تسجيلها باستخدام
JavaHeapDumpRequestBuilder، وهي مفيدة في رصد تسرُّب الذاكرة وتحسينها.ملفات تعريف الذاكرة المخصّصة لأخذ لقطات لعناصر متعدّدة: يتم تسجيلها باستخدام
HeapProfileRequestBuilder، وهي مفيدة لتحسين استخدام الذاكرة.الملفات الشخصية لحزمة التنفيذ: يتم تسجيلها باستخدام
StackSamplingRequestBuilder، وهي مفيدة لفهم تنفيذ الرمز البرمجي وتحليل وقت الاستجابة.
إضافة التبعيات
للحصول على أفضل تجربة مع واجهة برمجة التطبيقات ProfilingManager، أضِف مكتبات Jetpack التالية إلى ملف build.gradle.kts.
Kotlin
dependencies { implementation("androidx.tracing:tracing-ktx:2.0.2") implementation("androidx.core:core:1.19.0") }
أنيق
dependencies { implementation 'androidx.tracing:tracing:2.0.2' implementation 'androidx.core:core:1.19.0' }
تسجيل عملية تتبُّع النظام
بعد إضافة التبعيات المطلوبة، استخدِم الرمز التالي لتسجيل تتبُّع النظام. يوضّح هذا المثال كيفية بدء جلسة قياس الأداء من عنصر قابل للإنشاء مع إدارة العمليات المعقّدة بأمان خارج سلسلة المحادثات الرئيسية.
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") { ... }شريحة مخصّصة في الملف الشخصي الذي تم إنشاؤه.