يتيح ProfilingManager تسجيل الملفات الشخصية استنادًا إلى مشغّلات النظام. يدير النظام عملية التسجيل ويوفّر الملف الشخصي الناتج لتطبيقك.
ترتبط المشغّلات بالأحداث المهمة للأداء. وتوفّر الملفات الشخصية التي يسجّلها النظام معلومات مفصّلة عن تصحيح الأخطاء لرحلات المستخدم الأساسية (CUJ) المرتبطة بمشغّلات الأداء هذه.
تسجيل البيانات السابقة
تتطلّب العديد من العوامل المحفّزة تحليل البيانات السابقة التي أدّت إلى الحدث. غالبًا ما يكون المحفّز نفسه نتيجة لمشكلة وليس السبب الأساسي. إذا بدأت ملفًا شخصيًا فقط بعد حدوث المشغّل، فقد يكون السبب الأساسي قد فُقد بالفعل.
على سبيل المثال، تؤدي عملية طويلة على سلسلة واجهة المستخدم إلى حدوث خطأ التطبيق لا يستجيب (ANR). وبحلول الوقت الذي يرصد فيه النظام خطأ ANR ويرسل إشارة إلى التطبيق، قد تكون العملية قد انتهت. وبدء ملف شخصي في تلك اللحظة يفوت عمل الحظر الفعلي.
من الصعب التنبؤ بدقة بموعد حدوث بعض العوامل، ما يجعل من المستحيل بدء ملف شخصي يدويًا مسبقًا.
لماذا يجب استخدام ميزة "الالتقاط المستند إلى عامل تشغيل"؟
السبب الأساسي لاستخدام عوامل تشغيل جمع البيانات هو تسجيل البيانات للأحداث غير المتوقعة التي يستحيل على التطبيق بدء تسجيلها يدويًا قبل وقوع هذه الأحداث. يمكن استخدام عوامل تشغيل جمع البيانات لإجراء ما يلي:
- تصحيح أخطاء الأداء: يمكنك تشخيص أخطاء ANR وتسرُّب الذاكرة ومشاكل الثبات الأخرى.
- تحسين رحلات المستخدمين الأساسية: يمكنك تحليل المسارات وتحسينها، مثل بدء تشغيل التطبيق.
- فهم سلوك المستخدمين: يمكنك الحصول على إحصاءات حول الأحداث، مثل عمليات الخروج من التطبيق التي يبدأها المستخدمون.
إعداد مشغِّل
يوضّح الرمز التالي كيفية التسجيل في مشغّل TRIGGER_TYPE_APP_FULLY_DRAWN وتطبيق حدّ معدّل عليه.
Kotlin
fun recordWithTrigger() { val profilingManager = applicationContext.getSystemService(ProfilingManager::class.java) val triggers = ArrayList<ProfilingTrigger>() val triggerBuilder = ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_APP_FULLY_DRAWN) .setRateLimitingPeriodHours(1) triggers.add(triggerBuilder.build()) val mainExecutor: Executor = Executors.newSingleThreadExecutor() val resultCallback = Consumer<ProfilingResult> { profilingResult -> if (profilingResult.errorCode == ProfilingResult.ERROR_NONE) { Log.d( "ProfileTest", "Received profiling result file=" + profilingResult.resultFilePath ) setupProfileUploadWorker(profilingResult.resultFilePath) } else { Log.e( "ProfileTest", "Profiling failed errorcode=" + profilingResult.errorCode + " errormsg=" + profilingResult.errorMessage ) } } profilingManager.registerForAllProfilingResults(mainExecutor, resultCallback) profilingManager.addProfilingTriggers(triggers) }
Java
public void recordWithTrigger() { ProfilingManager profilingManager = getApplicationContext().getSystemService( ProfilingManager.class); List<ProfilingTrigger> triggers = new ArrayList<>(); ProfilingTrigger.Builder triggerBuilder = new ProfilingTrigger.Builder( ProfilingTrigger.TRIGGER_TYPE_APP_FULLY_DRAWN); triggerBuilder.setRateLimitingPeriodHours(1); triggers.add(triggerBuilder.build()); 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()); } } }; profilingManager.registerForAllProfilingResults(mainExecutor, resultCallback); profilingManager.addProfilingTriggers(triggers); }
ينفّذ الرمز الخطوات التالية:
- الحصول على المدير: لاسترداد خدمة
ProfilingManager. - تحديد مشغّل: يتم إنشاء
ProfilingTriggerلـTRIGGER_TYPE_APP_FULLY_DRAWN. يحدث هذا الحدث عندما يبلغ التطبيق عن أنه انتهى من بدء التشغيل وأنه تفاعلي. - ضبط حدود المعدّل: يطبّق هذا الخيار حدًّا للمعدّل يبلغ ساعة واحدة على هذا العامل المشغِّل المحدّد (
setRateLimitingPeriodHours(1)). ويمنع ذلك التطبيق من تسجيل أكثر من ملف شخصي واحد لبدء التشغيل في الساعة. - تسجيل المستمع: يستدعي
registerForAllProfilingResultsلتحديد دالة الاستدعاء التي تعالج النتيجة. تتلقّى طريقة ردّ الاتصال هذه مسار الملف الشخصي المحفوظ من خلالgetResultFilePath(). - إضافة عوامل تشغيل: لتسجيل قائمة عوامل التشغيل في
ProfilingManagerباستخدامaddProfilingTriggers. - حدث Fire: يستدعي
reportFullyDrawn()، الذي يُصدر الحدثTRIGGER_TYPE_APP_FULLY_DRAWNإلى النظام لتشغيل مجموعة ملفات شخصية بافتراض أنّ تتبُّع خلفية النظام كان قيد التشغيل وأنّ هناك حصة محدِّد معدّل متاحة. توضّح هذه الخطوة الاختيارية عملية كاملة لأنّ تطبيقك يجب أن يستدعيreportFullyDrawn()لهذا المشغّل.
استرداد التتبُّع
يحفظ النظام الملفات الشخصية المستندة إلى المشغّلات في الدليل نفسه الذي يحفظ فيه الملفات الشخصية الأخرى. يتبع اسم ملف عمليات التتبُّع التي تم تشغيلها التنسيق التالي:
profile_trigger_<profile_type_code>_<datetime>.<profile-type-name>
يمكنك سحب الملف باستخدام ADB. على سبيل المثال، لسحب سجلّ تتبّع النظام الذي تم تسجيله باستخدام مثال الرمز البرمجي من خلال ADB، قد يبدو الأمر على النحو التالي:
adb pull /data/user/0/com.example.sampleapp/files/profiling/profile_trigger_1_2025-05-06-14-12-40.perfetto-trace
لمعرفة التفاصيل حول عرض هذه التتبّعات، يُرجى الاطّلاع على مقالة استرداد بيانات تحليل الأداء وتحليلها.
طريقة عمل ميزة "التتبُّع في الخلفية"
لالتقاط البيانات من قبل المشغّل، يبدأ نظام التشغيل بشكل دوري في تتبع الخلفية. إذا حدث مشغّل أثناء نشاط تتبُّع الخلفية هذا وكان تطبيقك مسجَّلاً له، يحفظ النظام ملف التتبُّع في دليل تطبيقك. سيتضمّن الملف الشخصي بعد ذلك المعلومات التي أدّت إلى ظهور المشغّل.
بعد حفظ الملف الشخصي، يُرسل النظام إشعارًا إلى تطبيقك باستخدام دالة الاستدعاء
المقدَّمة إلى registerForAllProfilingResults. يوفّر ردّ الاتصال هذا المسار إلى الملف الشخصي الذي تم تسجيله والذي يمكن الوصول إليه من خلال طلب ProfilingResult#getResultFilePath().
لتقليل التأثير على أداء الجهاز وعمر البطارية، لا يشغّل النظام عمليات تتبُّع في الخلفية بشكل مستمر. بدلاً من ذلك، تستخدم طريقة أخذ العينات. يبدأ النظام عشوائيًا تتبُّعًا في الخلفية خلال إطار زمني محدّد (بحدّ أدنى وأقصى للمدة). ويؤدي تباعد عمليات التتبُّع هذه بشكل عشوائي إلى تحسين تغطية المشغّلات.
تتضمّن الملفات الشخصية التي يشغّلها النظام حدًا أقصى للحجم يحدّده النظام، لذا فهي تستخدم مخزنًا مؤقتًا دائريًا. وعندما يمتلئ المخزن المؤقت، تحلّ بيانات التتبُّع الجديدة محلّ البيانات الأقدم. As shown in Figure 1, a captured trace might not cover the entire duration of the background recording if the buffer fills up; instead, it represents the most recent activity leading up to the trigger.
تنفيذ الحدّ من المعدّل الخاص بالمشغّلات
يمكن أن تستهلك عوامل التفعيل العالية التردد حصة محدّد معدّل تطبيقك بسرعة. لفهم محدِّد المعدّل بشكل أفضل، ننصحك بالاطّلاع على طريقة عمل محدِّد المعدّل. لمنع نوع واحد من المشغّلات من استنفاد حصتك، يمكنك تنفيذ حدّ معدّل خاص بالمشغّل.
يتيح ProfilingManager تحديد معدّل تكرار الإجراءات الخاصة بالمشغّلات التي يحدّدها التطبيق. يتيح لك ذلك إضافة طبقة أخرى من التقييد المستند إلى الوقت بالإضافة إلى محدّد المعدّل الحالي. استخدِم واجهة برمجة التطبيقات setRateLimitingPeriodHours لضبط فترة تهدئة محدّدة لمشغّل معيّن. بعد انتهاء فترة الانتظار، يمكنك تفعيلها
مرة أخرى.
تصحيح أخطاء المشغّلات محليًا
بما أنّ عمليات التتبُّع في الخلفية يتم تشغيلها في أوقات عشوائية، من الصعب تصحيح أخطاء المشغّلات على الجهاز. لفرض تتبُّع في الخلفية من أجل الاختبار، استخدِم أمر ADB التالي:
adb shell device_config put profiling_testing system_triggered_profiling.testing_package_name <com.example.myapp>
يفرض هذا الأمر على النظام بدء تتبُّع مستمر في الخلفية للحزمة المحدّدة، ما يسمح لكل عامل تشغيل بجمع ملف شخصي إذا كان محدِّد المعدّل يسمح بذلك.
يمكنك أيضًا تفعيل خيارات تصحيح الأخطاء الأخرى، مثل إيقاف محدّد المعدّل عند تصحيح الأخطاء محليًا. لمزيد من المعلومات، يُرجى الاطّلاع على أوامر تصحيح الأخطاء لإنشاء الملفات الشخصية المحلية.