تشخيص أخطاء ANR وإصلاحها

عند حظر سلسلة واجهة المستخدم في تطبيق Android لفترة طويلة جدًا، يرسل النظام رسالة "التطبيق لا يستجيب" (ANR). تصف هذه الصفحة الأنواع المختلفة أنواع أخطاء ANR وكيفية تشخيصها واقتراحات لإصلاحها. جميع النطاقات الزمنية التلقائية للمهلة المحدّدة هي تلك الخاصة بأجهزة AOSP وPixel. هذه الأوقات قد تختلف حسب المصنّع الأصلي للجهاز.

وتجدر الإشارة إلى أنه عند تحديد سبب أخطاء ANR، من المفيد التمييز بين مشاكل النظام والتطبيق.

عندما يكون النظام في حالة سيئة، يمكن أن تؤدي المشاكل التالية إلى حدوث أخطاء ANR:

  • تؤدي المشكلات المؤقتة في خادم النظام عادةً إلى حدوث اتصالات سريعة بطيء.
  • إنّ المشاكل المتعلّقة بخادم النظام والحِمل الزائد على الجهاز تؤدي إلى عدم تنفيذ سلاسل محادثات التطبيق. مجدول.

من الطرق الجيدة للتمييز بين مشاكل النظام والتطبيق، إذا كانت متاحة لك لاستخدام تتبُّعات Perfetto:

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

مهلة إرسال الإدخال

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

فترة المهلة التلقائية: 5 ثوانٍ.

تحدث أخطاء ANR في إرسال الإدخال عادةً بسبب مشاكل في سلسلة التعليمات الرئيسية. إذا تم تحديد إذا تم حظر سلسلة التعليمات في انتظار الحصول على قفل، فيمكن أيضًا حظر سلسلة التعليمات المشاركة.

لتجنُّب أخطاء ANR في إرسال الإدخالات، اتّبِع أفضل الممارسات التالية:

  • عدم تنفيذ عمليات حظر أو عمليات طويلة الأمد في سلسلة التعليمات الرئيسية ضع في اعتبارك استخدام StrictMode لرصد الأخطاء غير المقصودة النشاط في سلسلة التعليمات الرئيسية
  • يمكنك تقليل التضارب بين سلسلة التعليمات الرئيسية وسلاسل المحادثات الأخرى.
  • تقليل العمل غير المستند إلى واجهة المستخدم في سلسلة التعليمات الرئيسية، على سبيل المثال عند التعامل مع عمليات البث أو تشغيل الخدمات.

الأسباب الشائعة

في ما يلي بعض الأسباب الشائعة والإصلاحات المقترَحة لمشاكل ANR في إرسال الإدخالات.

السبب ماذا يحدث؟ الإصلاحات المقترَحة
طلب تثبيت بطيء تنشئ سلسلة التعليمات الرئيسية استدعاء أداة ربط متزامنة طويلة. يمكنك تحويل المكالمة خارج سلسلة المحادثات الرئيسية أو محاولة تحسين المكالمة إذا كنت امتلاك واجهة برمجة التطبيقات.
العديد من طلبات الربط المتتالية تُجري سلسلة التعليمات الرئيسية العديد من استدعاءات المجلِّد المتزامنة المتتالية. ويجب عدم إجراء طلبات الربط في حلقة مفرغة.
حظر وحدات الإدخال والإخراج تجعل سلسلة التعليمات الرئيسية حظر استدعاء الإدخال/الإخراج، مثل قاعدة البيانات أو الشبكة الوصول إليه. نقل كل عمليات الإدراج المحظورة خارج سلسلة التعليمات الرئيسية.
قفل الطلب تم حظر سلسلة التعليمات الرئيسية في انتظار التعرُّف على قفل. تقليل التضارب بين سلسلة التعليمات الرئيسية وسلسلة المحادثات الأخرى. حسِّن الرمز البطيء في سلسلة المحادثات الأخرى.
عرض لقطات باهظة الثمن يتم عرض عدد كبير جدًا من اللقطات في إطار واحد، ما يؤدي إلى تعطُّل شديد. أنصحك بتقليل الجهد المبذول في تعديل الإطار. لا تستخدِم خوارزميات n2. استخدام المكونات الفعالة لأشياء مثل التمرير أو التنقل - على سبيل المثال، الحقيبة النفاثة مكتبة الصفحات:
تم الحظر بواسطة مكوّن آخر هناك مكون آخر، مثل جهاز استقبال البث، قيد التشغيل يحظر سلسلة التعليمات الرئيسية. عليك نقل الأعمال غير المستندة إلى واجهة المستخدم من سلسلة التعليمات الرئيسية قدر الإمكان. تشغيل البث المستلِمين في سلسلة محادثات مختلفة.
تعليق وحدة معالجة الرسومات إن تعليق وحدة معالجة الرسومات هو مشكلة في النظام أو الأجهزة تتسبب في حظر العرض، وبالتالي يحدث خطأ ANR لإرسال الإدخال. للأسف، لا تكون هناك عادةً أي إصلاحات من جانب التطبيق. في حال حذف الاتصال بفريق الأجهزة لتحري الخلل وإصلاحه.

كيفية تصحيح الأخطاء

يمكنك بدء تصحيح الأخطاء من خلال الاطّلاع على توقيع مجموعة أخطاء ANR في Google Play Console أو Firebase Crashlytics. تحتوي المجموعة العنقودية عادةً على الجزء العلوي الإطارات التي يُشتبه في أنّها تسبب خطأ ANR.

يعرض الرسم البياني التالي طريقة تحديد سبب انتهاء مهلة الإدخال. إرسال ANR.

الشكل 1. كيفية تصحيح أخطاء ANR في إرسال الإدخال

يمكن أن ترصد ميزة "مؤشرات Play الحيوية" بعض أسباب أخطاء ANR الشائعة وتساعد في تصحيحها. بالنسبة مثلاً، إذا اكتشفت المؤشرات الحيوية حدوث خطأ ANR بسبب تزايد الطلب على القفل، فإنها تلخيص المشكلة والحلّ المقترَح في قسم إحصاءات أخطاء ANR.

الشكل 2. رصد أخطاء ANR في مؤشرات Play الحيوية

لم يتم التركيز على أي نافذة.

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

فترة المهلة التلقائية: 5 ثوانٍ.

الأسباب الشائعة

تحدث أخطاء ANR التي لا يتم التركيز عليها عادةً بسبب أي من المشاكل التالية:

  • يؤدي التطبيق الكثير من العمل وبطء للغاية لرسم الإطار الأول.
  • لا يمكن التركيز على النافذة الرئيسية. إذا تم وضع علامة على نافذة تفيد بأنها FLAG_NOT_FOCUSABLE، لا يمكن للمستخدم إرسال أحداث رئيسية أو أزرار إليه.

Kotlin

override fun onCreate(savedInstanceState: Bundle) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_main)
  window.addFlags(WindowManager.LayoutParams.FLAG_FLAG_NOT_FOCUSABLE)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
}

مهلة مستقبِل البث

يحدث خطأ ANR لمستقبِل البث عندما لا يتعامل مستقبل البث مع البث في الوقت المناسب. لأجهزة الاستقبال المتزامنة أو المستقبِلات التي لا تتصل goAsync()، تعني المهلة الزمنية أن onReceive() لم تكتمل خلال الوقت. بالنسبة إلى أجهزة الاستقبال غير المتزامنة أو المستلِمين الذين يتصلون بـ goAsync()، يعني انتهاء المهلة الذي لم يتم استدعاء PendingResult.finish() فيه في الوقت المناسب.

غالبًا ما تحدث أخطاء ANR لمستقبِل البث في سلاسل المحادثات التالية:

  • سلسلة التعليمات الرئيسية إذا كانت المشكلة تؤدي إلى بطء بدء تشغيل التطبيق
  • تعمل سلسلة المحادثات على تشغيل مستقبل البث، إذا كانت المشكلة بطيئة في رمز onReceive().
  • سلاسل المحادثات الخاصة بعاملي البث، إذا كانت المشكلة بطيئة في رمز البث goAsync()

لتجنُّب أخطاء ANR لمستقبِل البث، اتّبِع أفضل الممارسات التالية:

  • عليك التأكّد من أنّ بدء تشغيل التطبيق سريع، لأنّه يتم احتسابه ضمن مهلة خطأ ANR إذا بدء التطبيق بمعالجة البث.
  • في حال استخدام goAsync()، تأكَّد من طلب الرقم PendingResult.finish() بسرعة. يخضع ذلك لمهلة خطأ ANR نفسها التي تخضع لها أجهزة استقبال البث المتزامنة.
  • في حال استخدام goAsync()، تأكّد من عدم مشاركة سلاسل محادثات العامل مع. عمليات أخرى طويلة الأمد أو عمليات حظر.
  • يمكنك استخدام registerReceiver() لتشغيل أجهزة استقبال البث في سلسلة غير رئيسية، لتجنُّب حظر رمز واجهة المستخدم الذي يعمل في سلسلة التعليمات الرئيسية.

فترات المهلة

تعتمد فترات مهلة تلقّي البث على ما إذا كانت العلامة التي تعمل في المقدّمة وإصدار النظام الأساسي.

نوع الغرض الإصدار 13 من نظام التشغيل Android والإصدارات الأقدم الإصدار 14 من نظام التشغيل Android والإصدارات الأحدث

النية بالشراء التي تعمل في المقدّمة

(FLAG_RECEIVER_FOREGROUND) عينة)

10 ثوانٍ

من 10 إلى 20 ثانية، حسب ما إذا كانت العملية متوقّفة باستخدام وحدة المعالجة المركزية (CPU)

الغرض من أولوية الخلفية

(لم يتم ضبط FLAG_RECEIVER_FOREGROUND)

60 ثانية

من 60 إلى 120 ثانية، اعتمادًا على ما إذا كانت العملية متوقّفة باستخدام وحدة المعالجة المركزية (CPU)

لمعرفة ما إذا تم ضبط العلامة FLAG_RECEIVER_FOREGROUND، ابحث عن "flg=" في حدث خطأ ANR وتحقَّق من توفُّر 0x10000000. إذا تم تعيين هذا البت، تم ضبط FLAG_RECEIVER_FOREGROUND في الغرض، وبالتالي تكون المهلة أقصر.

مثال على موضوع ANR مع المهلة القصيرة للبث (من 10 إلى 20 ثانية):

Broadcast of Intent { act=android.inent.action.SCREEN_ON flg=0x50200010 }

مثال على موضوع ANR مع المهلة الطويلة للبث (من 60 إلى 120 ثانية):

Broadcast of Intent { act=android.intent.action.TIME_SET flg=0x25200010 }

كيفية قياس أوقات البث

يبدأ قياس مدة البث عندما يتم إرسال البث من system_server إلى التطبيق، وينتهي عند انتهاء التطبيق من معالجة البث. إذا لم تكن عملية التطبيق قيد التشغيل بالفعل، فستحتاج أيضًا إلى إجراء اختبار البدء خلال مهلة خطأ ANR. وبالتالي، يمكن أن يؤدي بطء بدء التطبيق إلى أخطاء ANR لمستقبِل البث

يوضِّح الشكل التالي أنّ المخطط الزمني لأخطاء ANR لمستقبِل البث يتوافق مع عمليات تطبيق معينة.

الشكل 3. المخطط الزمني لأخطاء ANR لمستقبِل البث

ينتهي قياس مهلة خطأ ANR عند انتهاء المُستلِم من معالجة البث: يعتمد الوقت الذي يحدث فيه هذا بالضبط على ما إذا كانت مزامنة مستلم غير متزامن.

  • بالنسبة إلى أجهزة الاستقبال المتزامنة، يتوقف القياس عند رجوع onReceive().
  • بالنسبة إلى أجهزة الاستقبال غير المتزامنة، يتوقف القياس عندما تم الاتصال بـ PendingResult.finish().
الشكل 4. نقاط نهاية قياس مهلة خطأ ANR والمستلمين غير المتزامنين.

الأسباب الشائعة

في ما يلي بعض الأسباب الشائعة والإصلاحات المقترَحة لمشاكل ANR لمستقبِل البث.

السبب ينطبق على تفاصيل المشكلة الحل المقترَح
مشكلة بطء التطبيق عند بدء تشغيله جميع المستلِمين استغرق التطبيق وقتًا طويلاً جدًا لبدء التشغيل على البارد. تحسين التشغيل البطيء للتطبيق
لم تتم جدولة onReceive(). جميع المستلِمين كانت سلسلة محادثات مستقبل البث مشغولة بإجراء أعمال أخرى ولم لبدء طريقة onReceive(). عدم التنفيذ المهام الطويلة الأمد في سلسلة محادثات المستلِم (أو نقل المُستلِم إلى سلسلة محادثات مخصّصة سلسلة التعليمات).
onReceive() بطيئة جميع المستلِمين، لكن بشكلٍ أساسي الناتجة المتزامنة بدأت طريقة onReceive() ولكن كانت ممنوعة أو بطيئة لذلك لم تكتمل في الوقت المناسب. بطء التحسين رمز جهاز الاستقبال.
لم تتم جدولة مهام المُستلِم غير المتزامنة goAsync() المستلِمون حاولت طريقة onReceive() تنفيذ العمل. في مجموعة محظورة لسلسلة محادثات العمال، وبالتالي لم يبدأ العمل أبدًا. حسِّن المكالمات البطيئة أو المحظورة أو استخدِم سلاسل محادثات مختلفة للبث العمال مقابل المهام الأخرى طويلة المدى.
العمال بطيء أو محظورون goAsync() مستلِم هناك عملية حظر أو عملية بطيئة في مكان ما في سلسلة التعليمات العاملة أثناء معالجة البث. إِذًا، PendingResult.finish لم يتم استدعاءها في الوقت المناسب. تحسين جهاز استقبال async البطيء الرمز.
نسيت الاتصال بـ PendingResult.finish goAsync() مستلِم الاستدعاء إلى finish() غير مضمّن في مسار الرمز. التأكّد من أن يتم الاتصال بـ "finish()" دائمًا.

كيفية تصحيح الأخطاء

استنادًا إلى توقيع المجموعة وتقرير ANR، يمكنك تحديد موقع سلسلة المحادثات التي تشغيل جهاز الاستقبال، ثم الرمز المحدد المفقود أو قيد التشغيل ببطء.

يعرض الرسم البياني التالي كيفية تحديد سبب البث. خطأ ANR للمستلم.

الشكل 5. كيفية تصحيح أخطاء ANR لمستقبِل البث

البحث عن رمز جهاز الاستقبال

تعرض أداة Google Play Console فئة المستلِم ونية البث في خطأ ANR. التوقيع. ابحث عما يلي:

  • cmp=<receiver class>
  • act=<broadcast_intent>

في ما يلي مثال على توقيع ANR لمتلقي البث:

com.example.app.MyClass.myMethod
Broadcast of Intent { act=android.accounts.LOGIN_ACCOUNTS_CHANGED
cmp=com.example.app/com.example.app.MyAccountReceiver }

البحث عن سلسلة المحادثات التي تستخدم طريقة onReceive()

إذا كنت تستخدم Context.registerReceiver لتحديد معالج مخصّص، إنه سلسلة التعليمات التي تشغّل هذا المعالج. وبخلاف ذلك، تكون سلسلة المحادثات الرئيسية.

مثال: مهام المُستلِم غير المتزامنة التي لم تتم جدولتها

يعرض هذا القسم مثالاً على كيفية تصحيح أخطاء ANR لمستقبِل البث.

لنفترض أنّ توقيع ANR يبدو كما يلي:

com.example.app.MyClass.myMethod
Broadcast of Intent {
act=android.accounts.LOG_ACCOUNTS_CHANGED cmp=com.example.app/com.example.app.MyReceiver }

استنادًا إلى التوقيع، يبدو أنّ الهدف من البث هو android.accounts.LOG_ACCOUNTS_CHANGED وفئة المستلِم هي com.example.app.MyReceiver

من رمز المستلِم، يمكنك تحديد أنّ مجموعة سلاسل المحادثات "BG Thread [0,1,2,3]" يقوم بالعمل الرئيسي لمعالجة هذا البث. الاطّلاع على الحزمة ، يمكنك رؤية أن سلاسل الخلفية (BG) الأربع لها النمط ذاته: طلب حظر "getDataSync" نظرًا لأن جميع سلاسل محادثات BG كانت مشغولة، فإن تعذّرت معالجة البث في الوقت المناسب، ما أدّى إلى حدوث خطأ ANR.

BG Thread #0 (tid=26) Waiting

at jdk.internal.misc.Unsafe.park(Native method:0)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:211)
at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture:563)
at com.google.common.util.concurrent.ForwardingFuture.get(ForwardingFuture:68)
at com.example.app.getDataSync(<MyClass>:152)

...

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at com.google.android.libraries.concurrent.AndroidExecutorsModule.lambda$withStrictMode$5(AndroidExecutorsModule:451)
at com.google.android.libraries.concurrent.AndroidExecutorsModule$$ExternalSyntheticLambda8.run(AndroidExecutorsModule:1)
at java.lang.Thread.run(Thread.java:1012)
at com.google.android.libraries.concurrent.ManagedPriorityThread.run(ManagedPriorityThread:34)

There are several approaches to fix the issue:

  • Find out why getDataSync is slow and optimize.
  • Don't run getDataSync on all four BG threads.
  • More generally, ensure that the BG thread pool isn't saturated with long-running operations.
  • Use a dedicated thread pool for goAsync worker tasks.
  • Use an unbounded thread pool instead of the bounded BG thread pool

Example: slow app startup

A slow app startup can cause several types of ANRs, especially broadcast receiver and execute service ANRs. The cause of an ANR is likely slow app startup if you see ActivityThread.handleBindApplication in the main thread stacks.

Execute service timeout

An execute service ANR happens when the app's main thread doesn't start a service in time. Specifically, a service doesn't finish executing onCreate() and onStartCommand() or onBind() within the timeout period.

Default timeout period: 20 seconds for foreground service; 200 seconds for background service. The ANR timeout period includes the app cold start, if necessary, and calls to onCreate(), onBind(), or onStartCommand().

To avoid execute service ANRs, follow these general best practices:

  • Make sure that app startup is fast, since it's counted in the ANR timeout if the app is started to run the service component.
  • Make sure that the service's onCreate(), onStartCommand(), and onBind() methods are fast.
  • Avoid running any slow or blocking operations on the main thread from other components; these operations can prevent a service from starting quickly.

Common causes

The following table lists common causes of execute service ANRs and suggested fixes.

Cause What Suggested fix
Slow app startup The app takes too long to perform a cold start. Optimize slow app start.
Slow onCreate(), onStartCommand(), or onBind() The service component's onCreate(), onStartCommand(), or onBind() method takes too long to execute on the main thread. Optimize slow code. Move slow operations off the critical path where possible.
Not scheduled (main thread blocked before onStart()) The app's main thread is blocked by another component before the service can be started. Move other component's work off the main thread. Optimize other component's blocking code.

How to debug

From the cluster signature and ANR report in Google Play Console or Firebase Crashlytics, you can often determine the cause of the ANR based on what the main thread is doing.

The following flow chart describes how to debug an execute service ANR.

Figure 6. How to debug an execute service ANR.

If you've determined that the execute service ANR is actionable, follow these steps to help resolve the issue:

  1. Find the service component class in the ANR signature. In Google Play Console, the service component class is shown in the ANR signature. In the following example ANR details, it's com.example.app/MyService.

    com.google.common.util.concurrent.Uninterruptibles.awaitUninterruptibly
    Executing service com.example.app/com.example.app.MyService
    
  2. Determine whether the slow or block operation is part of app startup, the service component, or elsewhere by checking for the following important function call(s) in the main threads.

    Function call(s) in main thread stacks What it means
    android.app.ActivityThread.handleBindApplication App was starting up, so the ANR was caused by slow app start.

    <ServiceClass>.onCreate()

    [...]

    android.app.ActivityThread.handleCreateService

    Service was being created, so the ANR was likely caused by slow onCreate() code.

    <ServiceClass>.onBind()

    [...]

    android.app.ActivityThread.handleBindService

    Service was being bound, so the ANR was likely caused by slow onBind() code.

    <ServiceClass>.onStartCommand()

    [...]

    android.app.ActivityThread.handleServiceArgs

    Service was being started, so the ANR was likely caused by slow onStartCommand() code.

    For example, if the onStartCommand() method in the MyService class is slow, the main threads will look like this:

    at com.example.app.MyService.onStartCommand(FooService.java:25)
    at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4820)
    at android.app.ActivityThread.-$$Nest$mhandleServiceArgs(unavailable:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2289)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loopOnce(Looper.java:205)
    at android.os.Looper.loop(Looper.java:294)
    at android.app.ActivityThread.main(ActivityThread.java:8176)
    at java.lang.reflect.Method.invoke(Native method:0)
    

    إذا لم تتمكن من رؤية أي من استدعاءات الدوال المهمة، فهناك سببان آخران الاحتمالات:

    • فالخدمة قيد التشغيل أو يتم إيقافها، مما يعني أن الحزم غير مفعّلة يستغرق ظهورها وقت متأخر. في هذه الحالة، يمكنك تجاهل خطأ ANR باعتباره موجبًا خاطئًا.
    • هناك مكوِّن تطبيق آخر قيد التشغيل، مثل جهاز استقبال البث. في هذه الدورة، إذا كان من المحتمل أن تكون سلسلة التعليمات الرئيسية محظورة في هذا المكوِّن، ما يمنع الخدمة منذ بدء تشغيلها.
  3. إذا ظهر لك استدعاء وظيفة رئيسية وكان بإمكانك تحديد مكان خطأ ANR بشكل عام، فتحقق من باقي حزم سلاسل المحادثات الرئيسية للعثور على البيانات البطيئة تشغيله وتحسينه أو نقله خارج المسار الحرج.

  4. لمزيد من المعلومات عن الخدمات، يُرجى الاطّلاع على الصفحات التالية:

    موفّر المحتوى لا يستجيب

    يحدث خطأ ANR لموفّر المحتوى عندما يستغرق موفّر المحتوى البعيد وقتًا أطول من المهلة للرد على استعلام، ويتم إنهاؤها.

    فترة المهلة التلقائية: يحددها موفّر المحتوى باستخدام ContentProviderClient.setDetectNotResponding فترة مهلة خطأ ANR الوقت الإجمالي اللازم لتشغيل استعلام موفر المحتوى البعيد، تشغيل التطبيق البعيد على البارد إذا لم يكن قيد التشغيل بالفعل.

    لتجنُّب أخطاء ANR التي يوفّرها موفّر المحتوى، اتّبِع أفضل الممارسات التالية:

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

    الأسباب الشائعة

    يعرض الجدول التالي الأسباب الشائعة لمشاكل ANR وموفّر المحتوى المقترَحة إصلاحات الأخطاء.

    السبب ماذا يحدث؟ الإشارة الحل المقترَح
    طلب بحث من مقدِّم محتوى بطيء يستغرق موفّر المحتوى وقتًا طويلاً جدًا لتنفيذه أو تم حظره. إطار android.content.ContentProvider$Transport.query في سلسلة الربط. تحسين طلب بحث موفّر المحتوى التعرّف على سبب حجب مادة الحافظ .
    مشكلة بطء التطبيق عند بدء تشغيله يستغرق تطبيق موفّر المحتوى وقتًا طويلاً للبدء. يقع إطار ActivityThread.handleBindApplication في السلسلة الرئيسية. تحسين بدء تشغيل التطبيق:
    استنفاد سلسلة التعليمات: جميع سلاسل مجلد الربط مشغولة. جميع سلاسل المرابط مشغولة بخدمة طلبات متزامنة أخرى، وبالتالي يتعذر تشغيل طلب binder موفّر المحتوى. التطبيق لا يبدأ، وجميع سلاسل المجلدات مشغولة، والمحتوى مقدم الخدمة لا يعمل. تقليل الحمل على سلاسل الربط. أي تقليل عدد الرسائل الصادرة المتزامنة بيندر أو تنجز عملاً أقل عند التعامل مع المكالمات الواردة.

    كيفية تصحيح الأخطاء

    لتصحيح أخطاء ANR لموفّر المحتوى باستخدام توقيع المجموعة وتقرير ANR في Google Play Console أو Firebase Crashlytics، فابحث عن موضوع تقوم بها سلسلة(سلاسل) البيندر.

    يوضِّح رسم التدفّق البياني التالي كيفية تصحيح أخطاء ANR لموفّر المحتوى:

    الشكل 7. كيفية تصحيح أخطاء ANR لموفّر المحتوى

    يوضح مقتطف الرمز التالي الشكل الذي تبدو عليه سلسلة الربط عند تم الحظر بسبب بطء طلب موفّر المحتوى. في هذه الحالة، يستخدم موفر المحتوى الاستعلام في انتظار القفل عند فتح قاعدة بيانات.

    binder:11300_2 (tid=13) Blocked
    
    Waiting for osm (0x01ab5df9) held by at com.google.common.base.Suppliers$NonSerializableMemoizingSupplier.get(Suppliers:182)
    at com.example.app.MyClass.blockingGetOpenDatabase(FooClass:171)
    [...]
    at com.example.app.MyContentProvider.query(MyContentProvider.java:915)
    at android.content.ContentProvider$Transport.query(ContentProvider.java:292)
    at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:107)
    at android.os.Binder.execTransactInternal(Binder.java:1339)
    at android.os.Binder.execTransact(Binder.java:1275)
    

    يوضح مقتطف الرمز التالي شكل سلسلة المحادثات الرئيسية تم حظره بسبب بطء بدء تشغيل التطبيق. في هذه الحالة، يكون بدء تشغيل التطبيق بطيئًا بسبب قفل الخلاف أثناء تهيئة الخنجر.

    main (tid=1) Blocked
    
    [...]
    at dagger.internal.DoubleCheck.get(DoubleCheck:51)
    - locked 0x0e33cd2c (a qsn)at dagger.internal.SetFactory.get(SetFactory:126)
    at com.myapp.Bar_Factory.get(Bar_Factory:38)
    [...]
    at com.example.app.MyApplication.onCreate(DocsApplication:203)
    at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1316)
    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6991)
    at android.app.ActivityThread.-$$Nest$mhandleBindApplication(unavailable:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2235)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loopOnce(Looper.java:205)
    at android.os.Looper.loop(Looper.java:294)
    at android.app.ActivityThread.main(ActivityThread.java:8170)
    at java.lang.reflect.Method.invoke(Native method:0)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
    

    استجابة وظيفية بطيئة

    يحدث خطأ ANR للاستجابة البطيئة للوظيفة عندما يستغرق التطبيق وقتًا طويلاً جدًا للاستجابة إلى JobService.onStartJob() أو JobService.onStopJob()، أو يستغرق وقتًا طويلاً جدًا إرسال إشعار باستخدام JobService.setNotification() يشير هذا إلى أن تم حظر سلسلة التعليمات الرئيسية للتطبيق من تنفيذ إجراء آخر.

    إذا كانت المشكلة في JobService.onStartJob() أو JobService.onStopJob()، تحقَّق مما يحدث في سلسلة المحادثات الرئيسية إذا كانت المشكلة في JobService.setNotification()، احرص على الاتصال به في أسرع وقت ممكن. ولا تقوم بالكثير من العمل قبل تقديم الإشعار.

    أخطاء ANR الغامضة

    في بعض الأحيان، يكون سبب حدوث خطأ ANR غير واضح أو قد لا يكون معلومات لتصحيح الأخطاء في توقيع المجموعة وتقرير أخطاء ANR. في هذه الحالات، لا يزال هناك بعض الخطوات التي يمكنك اتخاذها لتحديد ما إذا كان خطأ ANR قابلة للتنفيذ.

    قائمة انتظار الرسائل غير نشِطة أو localPollOnce

    إذا رأيت الإطار android.os.MessageQueue.nativePollOnce في غالبًا ما يشير ذلك إلى أن سلسلة التعليمات التي يُشتبه بأنّها غير مستجيبة خاملاً وفي انتظار رسائل التكرار. في Google Play Console، ستظهر تفاصيل خطأ ANR تبدو كما يلي:

    Native method - android.os.MessageQueue.nativePollOnce
    Executing service com.example.app/com.example.app.MyService
    

    على سبيل المثال، إذا كانت سلسلة المحادثات الرئيسية غير نشطة، ستبدو الحزم على النحو التالي:

    "main" tid=1 NativeMain threadIdle
    
    #00  pc 0x00000000000d8b38  /apex/com.android.runtime/lib64/bionic/libc.so (__epoll_pwait+8)
    #01  pc 0x0000000000019d88  /system/lib64/libutils.so (android::Looper::pollInner(int)+184)
    #02  pc 0x0000000000019c68  /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+112)
    #03  pc 0x000000000011409c  /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)+44)
    at android.os.MessageQueue.nativePollOnce (Native method)
    at android.os.MessageQueue.next (MessageQueue.java:339)  at android.os.Looper.loop (Looper.java:208)
    at android.app.ActivityThread.main (ActivityThread.java:8192)
    at java.lang.reflect.Method.invoke (Native method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:626)
    at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1015)
    

    هناك عدة أسباب قد تؤدي إلى عدم نشاط سلسلة المحادثات التي يُشتبه بأنّها غير مستجيبة:

    • تفريغ تسلسل استدعاء الدوال البرمجية في وقت متأخر: تم استرداد سلسلة المحادثات خلال الفترة الزمنية القصيرة بين حدث خطأ ANR وتفريغ الحزم وقت الاستجابة في هواتف Pixel على نظام التشغيل Android 13 حوالي 100 ملي ثانية، ولكن يمكن أن تتجاوز ثانية واحدة. وقت الاستجابة في هواتف Pixel على نظام التشغيل Android 14 عادة أقل من 10 ملّي ثانية.
    • إساءة تحديد مصدر سلسلة المحادثات: لم تكن سلسلة المحادثات المُستخدَمة لإنشاء توقيع ANR سلسلة التعليمات الفعلية التي لا تستجيب والتي تسببت في حدوث خطأ ANR. في هذه الحالة، حاول عليك تحديد ما إذا كان خطأ ANR أحد الأنواع التالية:
    • مشكلة على مستوى النظام لم تتم جدولة العملية بسبب الحِمل الزائد على النظام. أو مشكلة في خادم النظام.

    بدون إطارات تكديس

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

    • يستغرق نقل الحزمة وقتًا طويلاً جدًا وتنتهي المهلة.
    • انتهت العملية أو قتلت قبل أخذ المكدسات.
    [...]
    
    --- CriticalEventLog ---
    capacity: 20
    timestamp_ms: 1666030897753
    window_ms: 300000
    
    libdebuggerd_client: failed to read status response from tombstoned: timeout reached?
    
    ----- Waiting Channels: pid 7068 at 2022-10-18 02:21:37.<US_SOCIAL_SECURITY_NUMBER>+0800 -----
    
    [...]
    

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

    المشاكل المعروفة

    الاحتفاظ بموقت في عملية التطبيق لغرض إنهاء العملية قد لا تعمل معالجة البث بشكل صحيح قبل تشغيل خطأ ANR بشكل صحيح بسبب الطريقة غير المتزامنة التي يراقب بها النظام أخطاء ANR.