تتيح 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); }
ينفّذ الرمز الخطوات التالية:
- get the manager: يستردّ خدمة
ProfilingManager. - تحديد مشغّل: ينشئ
ProfilingTriggerلـTRIGGER_TYPE_APP_FULLY_DRAWN. يحدث هذا الحدث عندما يبلّغ التطبيق بأنّه انتهى من بدء التشغيل وأصبح تفاعليًا. - ضبط حدود المعدّل: يفرض هذا الإجراء حدًا للمعدّل يبلغ ساعة واحدة على هذا المشغّل المحدّد (
setRateLimitingPeriodHours(1))، ما يمنع التطبيق من تسجيل أكثر من ملف بدء تشغيل واحد في الساعة. - تسجيل أداة معالجة: يتم استدعاء
registerForAllProfilingResultsلتحديد دالة الرجوع التي تعالج النتيجة. يتلقّى هذا الإجراء مسار الملف الشخصي المحفوظ من خلالgetResultFilePath(). - إضافة مشغّلات: تسجّل هذه السمة قائمة المشغّلات باستخدام
ProfilingManageraddProfilingTriggers. - إطلاق الحدث: يتم استدعاء
reportFullyDrawn()، ما يؤدي إلى إرسال الحدثTRIGGER_TYPE_APP_FULLY_DRAWNإلى النظام، وبالتالي يتم تشغيل عملية جمع البيانات الشخصية، وذلك بافتراض أنّ عملية تتبُّع في الخلفية للنظام كانت قيد التشغيل وأنّ هناك حصة متاحة من أداة تحديد المعدّل. توضّح هذه الخطوة الاختيارية مسارًا كاملاً لأنّ تطبيقك يجب أن يستدعيreportFullyDrawn()لتنفيذ هذا المشغّل.
استرداد عملية التتبُّع
يحفظ النظام الملفات الشخصية المستندة إلى المشغّلات في الدليل نفسه الذي يتم فيه حفظ الملفات الشخصية الأخرى. يتّبع اسم ملف عمليات التتبُّع المشغَّلة التنسيق التالي:
profile_trigger_<profile_type_code>_<datetime>.<profile-type-name>
يمكنك سحب الملف باستخدام "أداة تصحيح أخطاء Android" (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().
للحدّ من التأثير في أداء الجهاز وعمر البطارية، لا يشغّل النظام عمليات التتبُّع في الخلفية بشكل مستمر. بدلاً من ذلك، تستخدم طريقة أخذ العيّنات. يبدأ النظام بشكل عشوائي عملية تتبُّع في الخلفية خلال إطار زمني محدّد (مع حد أدنى وأقصى للمدة). يؤدي تباعد هذه الآثار بشكل عشوائي إلى تحسين تغطية المشغّلات.
تتضمّن الملفات الشخصية التي يتم تشغيلها بواسطة النظام حدًا أقصى للحجم يحدّده النظام، لذا تستخدم مخزنًا مؤقتًا حلقيًا. بعد امتلاء المخزن المؤقت، تحلّ بيانات التتبُّع الجديدة محلّ البيانات الأقدم. كما هو موضّح في الشكل 1، قد لا يغطّي التتبُّع الذي تم تسجيله المدة الكاملة للتسجيل في الخلفية إذا تم ملء المخزن المؤقت، بل يمثّل النشاط الأخير الذي أدّى إلى بدء التسجيل.
تنفيذ الحدّ الأقصى لمعدّل الزحف الخاص بالمشغّلات
يمكن أن تؤدي المشغّلات العالية التردد إلى استهلاك حصة محدّد المعدّل في تطبيقك بسرعة. لفهم أداة تحديد المعدّل بشكل أفضل، ننصحك بالاطّلاع على طريقة عمل أداة تحديد المعدّل. لمنع نوع واحد من المشغّلات من استنفاد حصتك، يمكنك تنفيذ عملية تحديد معدّل الاستخدام خاصة بالمشغّل.
تتيح ProfilingManager وضع حدود قصوى لعدد مرات تشغيل المشغّلات المحدّدة في التطبيق. يتيح لك ذلك إضافة طبقة أخرى من الحدّ من عدد الطلبات المستند إلى الوقت، بالإضافة إلى أداة الحدّ من عدد الطلبات الحالية. استخدِم واجهة برمجة التطبيقات setRateLimitingPeriodHours لضبط وقت تهدئة محدّد لمشغّل. بعد انتهاء فترة الانتظار، يمكنك تفعيلها مرة أخرى.
تصحيح أخطاء المشغّلات على الجهاز
بما أنّ عمليات التتبُّع التي تتم في الخلفية تُنفَّذ في أوقات عشوائية، يصعب تصحيح الأخطاء التي تؤدي إلى تشغيلها على الجهاز. لفرض تتبُّع الخلفية بغرض الاختبار، استخدِم أمر ADB التالي:
adb shell device_config put profiling_testing system_triggered_profiling.testing_package_name <com.example.myapp>
يفرض هذا الأمر على النظام بدء تتبُّع مستمر في الخلفية للحزمة المحدّدة، ما يتيح لكل مشغّل إمكانية جمع ملف تعريف إذا سمح بذلك أداة تحديد المعدّل.
يمكنك أيضًا تفعيل خيارات تصحيح الأخطاء الأخرى، مثل إيقاف أداة تحديد المعدّل عند تصحيح الأخطاء محليًا. لمزيد من المعلومات، يُرجى الاطّلاع على أوامر تصحيح الأخطاء الخاصة بإنشاء الملفات الشخصية المحلية.