تحديد المواصفات الشخصية استنادًا إلى تفاعلات الجمهور

تتيح ProfilingManager إمكانية تسجيل الملفات الشخصية استنادًا إلى مشغّلات النظام. يدير النظام عملية التسجيل ويقدّم الملف الشخصي الناتج إلى تطبيقك.

ترتبط المشغّلات بالأحداث المهمة للأداء. تقدّم الملفات الشخصية التي يسجّلها النظام معلومات مفصّلة عن تصحيح الأخطاء لرحلات المستخدمين الأساسية (CUJs) المرتبطة بهذه المشغّلات.

تسجيل البيانات السابقة

تتطلّب العديد من المشغّلات تحليل البيانات السابقة التي أدّت إلى وقوع الحدث. وغالبًا ما يكون المشغّل نفسه نتيجة لمشكلة معيّنة وليس السبب الجذري. إذا بدأت ملفًا شخصيًا بعد وقوع المشغّل فقط، قد يكون السبب الجذري قد فُقد.

على سبيل المثال، تؤدي عملية طويلة الأمد على سلسلة واجهة المستخدم الرئيسية إلى ظهور الخطأ "التطبيق لا يستجيب (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);

}

ينفّذ الرمز الخطوات التالية:

  1. الحصول على المدير: يسترد خدمة ProfilingManager.
  2. تحديد مشغّل: ينشئ ProfilingTrigger لـ TRIGGER_TYPE_APP_FULLY_DRAWN. يحدث هذا الحدث عندما يبلّغ التطبيق عن اكتمال بدء التشغيل وإمكانية التفاعل معه.
  3. ضبط حدود المعدّل: يطبّق حدًا للمعدّل لمدة ساعة واحدة على هذا المشغّل تحديدًا (setRateLimitingPeriodHours(1)). ويمنع ذلك التطبيق من تسجيل أكثر من ملف شخصي واحد لبدء التشغيل في الساعة.
  4. تسجيل المستمع: يستدعي registerForAllProfilingResults لتحديد معاودة الاتصال التي تعالج النتيجة. تتلقّى معاودة الاتصال هذه مسار الملف الشخصي المحفوظ من خلال getResultFilePath().
  5. إضافة المشغّلات: يسجّل قائمة المشغّلات باستخدام ProfilingManager من خلال addProfilingTriggers.
  6. تفعيل الحدث: يستدعي 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().

مخطّط يوضّح طريقة عمل لقطات تتبُّع الخلفية، مع مخزن مؤقت حلقي يسجّل البيانات قبل وقوع حدث مشغِّل.
الشكل 1: آلية عمل لقطات التتبُّع في الخلفية.

للحدّ من التأثير على أداء الجهاز وعمر البطارية، لا يشغّل النظام عمليات التتبُّع في الخلفية باستمرار. بدلاً من ذلك، يستخدم طريقة أخذ العينات. يبدأ النظام بشكلٍ عشوائي عملية تتبُّع في الخلفية خلال إطار زمني محدّد (بحد أدنى وأقصى للمدة). يؤدي توزيع عمليات التتبُّع هذه بشكلٍ عشوائي إلى تحسين تغطية المشغّلات.

تتضمّن الملفات الشخصية التي يتم تفعيلها من قِبل النظام حدًا أقصى للحجم محدّدًا من قِبل النظام، لذا تستخدم مخزنًا مؤقتًا حلقيًا. عندما يمتلئ المخزن المؤقت، تحلّ بيانات التتبُّع الجديدة محل البيانات الأقدم. كما هو موضّح في الشكل 1، قد لا تغطي عملية التتبُّع المسجّلة المدة الكاملة للتسجيل في الخلفية إذا امتلأ المخزن المؤقت، بل تمثّل الأنشطة الحديثة التي أدّت إلى وقوع المشغّل.

تنفيذ الحدّ من المعدّل الخاص بالمشغّل

يمكن أن تستهلك المشغّلات عالية التردد بسرعة حصة الحدّ من المعدّل في تطبيقك. لفهم أداة الحدّ من المعدّل بشكلٍ أفضل، ننصحك بالاطّلاع على مقالة آلية عمل أداة الحدّ من المعدّل. لمنع نوع مشغّل واحد من استنفاد حصتك، يمكنك تنفيذ الحدّ من المعدّل الخاص بالمشغّل.

تتيح ProfilingManager إمكانية الحدّ من المعدّل الخاص بالمشغّل الذي يحدّده التطبيق. يتيح لك ذلك إضافة طبقة أخرى من التقييد المستند إلى الوقت بالإضافة إلى أداة الحدّ من المعدّل الحالية. استخدِم واجهة برمجة التطبيقات setRateLimitingPeriodHours لضبط فترة استراحة معيّنة لمشغّل. بعد انتهاء فترة الاستراحة، يمكنك تفعيله مرة أخرى.

تصحيح أخطاء المشغّلات محليًا

بما أنّ عمليات التتبُّع في الخلفية يتم تشغيلها في أوقات عشوائية، يصعب تصحيح أخطاء المشغّلات محليًا. لفرض عملية تتبُّع في الخلفية لأغراض الاختبار، استخدِم أمر ADB التالي:

adb shell device_config put profiling_testing system_triggered_profiling.testing_package_name <com.example.myapp>

يفرض هذا الأمر على النظام بدء عملية تتبُّع مستمرة في الخلفية للحزمة المحدّدة، ما يسمح لكل مشغّل بجمع ملف شخصي إذا كانت حصة الحدّ من المعدّل متاحة.

يمكنك أيضًا تفعيل خيارات تصحيح الأخطاء الأخرى، على سبيل المثال، إيقاف أداة الحدّ من المعدّل عند تصحيح الأخطاء محليًا. لمزيد من المعلومات، يُرجى الاطّلاع على مقالة أوامر تصحيح الأخطاء للتسجيل المحلي للتسجيل المحلي.