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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

البحث عن سلسلة التعليمات التي تُشغّل طريقة onSubmit()

إذا كنت تستخدم 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 في سلسلة الصنف Binder. تحسين طلب بحث موفّر المحتوى تعرَّف على العنصر الذي يتسبّب في حظر سلسلة تعليمات الصنف Binder.
    مشكلة بطء التطبيق عند بدء تشغيله يستغرق بدء تشغيل تطبيق موفر المحتوى وقتًا طويلاً. ويتم إدراج إطار ActivityThread.handleBindApplication في سلسلة التعليمات الرئيسية. تحسين بدء تشغيل التطبيقات
    نفاذ سلاسل الصنف 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 قابلاً للتنفيذ.

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

    إذا رأيت الإطار 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 وتفريغ الحزم. يبلغ وقت الاستجابة في وحدات البكسل على نظام التشغيل 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.