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

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

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

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

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

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

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

انتهاء مهلة إرسال الإدخال

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

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

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

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

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

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

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

السبب ماذا يحدث؟ الحلول المقترَحة
طلب الصنف Binder بطيء تُجري سلسلة التعليمات الرئيسية استدعاء أداة ربط متزامن طويل. انقل الطلب من سلسلة المحادثات الرئيسية أو حاوِل تحسين الطلب إذا كنت مالك واجهة برمجة التطبيقات.
العديد من طلبات الصنف المتتالية تُجري سلسلة التعليمات الرئيسية العديد من طلبات الصنف المتزامن المتتالية. ويُرجى عدم تنفيذ طلبات الصنف Binder في حلقة مرتبطة.
حظر وحدات الإدخال والإخراج تُجري سلسلة التعليمات الرئيسية حظر طلب وحدات الإدخال والإخراج، مثل الوصول إلى قاعدة البيانات أو الشبكة. نقل كل طلبات الإدراج المحظورة خارج سلسلة التعليمات الرئيسية
تزايد الطلب على دالة الاستبعاد المتبادل تم حظر سلسلة التعليمات الرئيسية إلى حين وصول قفلها. يمكنك تقليل تزايد الطلب على دالة الاستبعاد المتبادل بين سلسلة التعليمات الرئيسية وسلسلة التعليمات الأخرى. حسِّن الرمز البطيء في سلسلة المحادثات الأخرى.
إطار مكلف عرض عدد كبير جدًا من اللقطات في إطار واحد، ما يؤدي إلى إيقاف مؤقت شديد يمكنك بذل مجهود أقل عند تحريك الإطار. ولا تستخدِم الخوارزميات n2. استخدِم مكونات فعالة لعناصر مثل التمرير أو الصفحات، على سبيل المثال مكتبة الصفحات في Jetpack.
تم الحظر بواسطة مكوّن آخر ثمة مكوّن مختلف، مثل جهاز استقبال البث، قيد التشغيل ويحظر سلسلة التعليمات الرئيسية. نقل الأعمال التي لا تتبع واجهة المستخدم خارج سلسلة التعليمات الرئيسية قدر الإمكان تشغيل أجهزة استقبال البث على سلسلة محادثات مختلفة
تعليق وحدة معالجة الرسومات تعطُّل وحدة معالجة الرسومات هو مشكلة في النظام أو في الجهاز تؤدي إلى حظر العرض، ما يؤدي إلى حدوث خطأ 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 التي تحدث في جهاز استقبال البث عندما لا يتمكن جهاز استقبال البث من إجراء عملية بث في الوقت المناسب. بالنسبة إلى أجهزة الاستقبال المتزامنة أو أجهزة الاستقبال التي لا تستدعي goAync()، تعني المهلة أنّ 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 }

البحث عن سلسلة المحادثات التي تقوم بتشغيل طريقة onReceived()

إذا كنت تستخدم 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 إذا تم بدء تشغيل التطبيق في وضع "موفِّر المحتوى".
    • تأكَّد من أنّ طلبات بحث موفر المحتوى سريعة.
    • لا تُنفّذ الكثير من استدعاءات الصنف Binder المتزامنة التي قد تحظر جميع سلاسل محادثات الصنف Binder التطبيق.

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

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

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

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

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

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

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

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

    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 قابلاً للتنفيذ أم لا.

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

    إذا رأيت الإطار 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 على الإصدار 13 من نظام التشغيل Android 100 ملي ثانية تقريبًا، ولكن يمكن أن يتجاوز ثانية واحدة. وعادةً ما يكون وقت الاستجابة في هواتف Pixel على الإصدار 14 من نظام التشغيل Android أقل من 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.