ANR ها را تشخیص داده و اصلاح کنید

هنگامی که رشته رابط کاربری یک برنامه اندروید برای مدت طولانی مسدود می شود، سیستم خطای "Application Not Responding" (ANR) را ارسال می کند. در این صفحه انواع مختلف ANR، نحوه تشخیص آنها و پیشنهاداتی برای رفع آنها توضیح داده شده است. همه محدوده‌های زمانی پیش‌فرض فهرست‌شده برای دستگاه‌های AOSP و Pixel هستند. این زمان ها می تواند بر اساس OEM متفاوت باشد.

به خاطر داشته باشید که هنگام تعیین علت ANR، تمایز بین مشکلات سیستم و برنامه مفید است.

هنگامی که سیستم در وضعیت بدی قرار دارد، مشکلات زیر می تواند باعث ANR شود:

  • مشکلات گذرا در سرور سیستم باعث می‌شود که معمولاً تماس‌های بایندر سریع کند می‌شوند.
  • مشکلات مربوط به سرور سیستم و بار بالای دستگاه باعث می شود تا موضوعات برنامه برنامه ریزی نشود.

اگر در دسترس شما باشد، یک راه خوب برای تمایز بین مشکلات سیستم و برنامه، استفاده از Perfetto Traces است:

  • با نگاه کردن به مسیر وضعیت رشته در Perfetto، ببینید که آیا رشته اصلی برنامه برنامه ریزی شده است یا خیر.
  • به موضوعات system_server برای مسائلی مانند مناقشه قفل نگاه کنید.
  • برای تماس‌های آهسته کلاسور، در صورت وجود، به رشته پاسخ نگاه کنید تا ببینید چرا کند است.

مهلت زمانی ارسال ورودی

ANRهای ارسال ورودی زمانی اتفاق می‌افتند که رشته اصلی برنامه به یک رویداد ورودی، مانند کشیدن انگشت یا فشار دادن کلید، به موقع پاسخ نمی‌دهد. از آنجایی که برنامه زمانی که وقفه‌های ارسال ورودی رخ می‌دهد در پیش‌زمینه است، تقریباً همیشه برای کاربر قابل مشاهده است و کاهش آن بسیار مهم است.

مدت زمان پیش فرض : 5 ثانیه.

ANRهای ارسال ورودی معمولاً به دلیل مشکلات موجود در رشته اصلی ایجاد می شوند. اگر نخ اصلی در انتظار به دست آوردن قفل مسدود شده بود، نخ نگهدارنده نیز می تواند درگیر شود.

برای جلوگیری از ارسال ANR ورودی، بهترین روش‌ها را دنبال کنید:

  • از انجام عملیات مسدود کردن یا طولانی مدت روی نخ اصلی خودداری کنید. استفاده از StrictMode را برای مشاهده فعالیت تصادفی در رشته اصلی در نظر بگیرید.
  • اختلاف قفل بین نخ اصلی و رشته های دیگر را به حداقل برسانید.
  • کارهای غیر UI را روی رشته اصلی، مانند هنگام مدیریت پخش یا اجرای سرویس‌ها، به حداقل برسانید.

علل رایج

در اینجا چند علت رایج و راه‌حل‌های پیشنهادی برای ANR‌های ارسال ورودی آورده شده است.

علت چه اتفاقی می افتد راه حل های پیشنهادی
تماس آهسته کلاسور رشته اصلی یک تماس همزمان بایندر طولانی ایجاد می کند. اگر شما دارای API هستید، تماس را از رشته اصلی خارج کنید یا سعی کنید تماس را بهینه کنید.
بسیاری از تماس های متوالی کلاسور رشته اصلی بسیاری از تماس‌های بایندر همزمان متوالی را ایجاد می‌کند. تماس های کلاسور را در یک حلقه محکم انجام ندهید.
مسدود کردن I/O رشته اصلی باعث مسدود شدن تماس ورودی/خروجی می شود، مانند دسترسی به پایگاه داده یا شبکه. تمام IOهای مسدود کننده را از موضوع اصلی خارج کنید.
قفل جدال تاپیک اصلی مسدود شده است و در انتظار به دست آوردن قفل است. اختلاف قفل بین نخ اصلی و نخ دیگر را کاهش دهید. کدهای کند را در رشته دیگر بهینه کنید.
قاب گران قیمت رندر شدن بیش از حد در یک فریم، باعث انحراف شدید می شود. کار کمتری برای پاره کردن قاب انجام دهید. از الگوریتم های n 2 استفاده نکنید. از مؤلفه های کارآمد برای مواردی مانند پیمایش یا صفحه بندی استفاده کنید - برای مثال، کتابخانه جت پک.
توسط مؤلفه دیگر مسدود شده است یک مؤلفه متفاوت، مانند یک گیرنده پخش، در حال اجرا است و رشته اصلی را مسدود می کند. کارهای غیر UI را تا حد امکان از موضوع اصلی خارج کنید. گیرنده های پخش را روی یک رشته دیگر اجرا کنید.
GPU قطع است GPU hang یک مشکل سیستمی یا سخت افزاری است که باعث مسدود شدن رندر و در نتیجه ارسال ANR ورودی می شود. متأسفانه، معمولاً هیچ اصلاحی در سمت برنامه وجود ندارد. در صورت امکان برای عیب یابی با تیم سخت افزار تماس بگیرید.

چگونه اشکال زدایی کنیم

اشکال زدایی را با نگاه کردن به امضای خوشه ANR در Google Play Console یا Firebase Crashlytics شروع کنید. این خوشه معمولاً شامل فریم های بالایی است که مشکوک به ایجاد ANR هستند.

نمودار جریان زیر نحوه تعیین علت ANR ارسال وقفه ورودی را نشان می دهد.

شکل 1. نحوه اشکال زدایی یک ANR ارسال ورودی.

بازی حیاتی می تواند برخی از این علل رایج ANR را شناسایی کرده و به رفع اشکال کمک کند. برای مثال، اگر Vitals تشخیص دهد که یک ANR به دلیل اختلاف قفل رخ داده است، می‌تواند مشکل را خلاصه کرده و در بخش اطلاعات ANR اصلاح کند.

شکل 2. تشخیص ANR حیاتی را پخش کنید.

بدون پنجره متمرکز

در حالی که رویدادهایی مانند لمس مستقیماً بر اساس آزمایش ضربه به پنجره مربوطه ارسال می شوند، رویدادهایی مانند کلیدها به یک هدف نیاز دارند. این هدف به عنوان پنجره متمرکز شناخته می شود. در هر نمایشگر فقط یک پنجره متمرکز وجود دارد و معمولاً پنجره ای است که کاربر در حال حاضر با آن تعامل دارد. اگر یک پنجره متمرکز پیدا نشد، ورودی یک ANR بدون فوکوس پنجره را افزایش می دهد. یک ANR بدون فوکوس پنجره نوعی ANR ارسال ورودی است.

مدت زمان پیش فرض : 5 ثانیه.

علل رایج

ANR های بدون پنجره معمولاً به دلیل یکی از مشکلات زیر ایجاد می شوند:

  • برنامه کار زیادی انجام می دهد و برای ترسیم فریم اول بسیار کند است.
  • پنجره اصلی قابل فوکوس نیست. اگر پنجره ای با FLAG_NOT_FOCUSABLE پرچم گذاری شده باشد، کاربر نمی تواند رویدادهای کلید یا دکمه را برای آن ارسال کند.

کاتلین

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

جاوا

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

مهلت زمانی گیرنده پخش

ANR گیرنده پخش زمانی اتفاق می‌افتد که گیرنده پخش پخش را به موقع انجام ندهد. برای گیرنده‌های همزمان، یا گیرنده‌هایی که goAsync() را فراخوانی نمی‌کنند، مهلت زمانی به این معنی است که onReceive() به موقع کامل نشده است. برای گیرنده‌های async یا گیرنده‌هایی که goAsync() را فراخوانی می‌کنند، مهلت زمانی به این معنی است که PendingResult.finish() به موقع فراخوانی نشده است.

ANR های گیرنده پخش اغلب در این رشته ها اتفاق می افتد:

  • موضوع اصلی، اگر مشکل شروع کند برنامه باشد.
  • اگر مشکل در کد onReceive() کند است، گیرنده پخش را در حال اجرا قرار دهید.
  • اگر مشکل از کد پخش کند goAsync() باشد، thread های کارگر را پخش کنید.

برای جلوگیری از ANR گیرنده پخش، بهترین روش‌ها را دنبال کنید:

  • مطمئن شوید که راه‌اندازی برنامه سریع است، زیرا اگر برنامه شروع به پخش پخش کند، در مهلت زمانی ANR محاسبه می‌شود.
  • اگر از goAsync() استفاده می شود، مطمئن شوید که PendingResult.finish() به سرعت فراخوانی شده است. این موضوع مشمول همان زمان ANR مانند گیرنده های پخش همزمان است.
  • اگر از goAsync() استفاده می شود، مطمئن شوید که رشته(های) کارگر با سایر عملیات های طولانی مدت یا مسدود کننده به اشتراک گذاشته نشده است.
  • استفاده از registerReceiver() برای اجرای گیرنده های پخش در یک رشته غیر اصلی، برای جلوگیری از مسدود کردن کد UI در حال اجرا در رشته اصلی.

دوره های وقفه

دوره های وقفه دریافت پخش به تنظیم پرچم قصد پیش زمینه و نسخه پلت فرم بستگی دارد.

نوع قصد اندروید 13 و پایین تر اندروید 14 و بالاتر

هدف اولویت پیش زمینه

( مجموعه 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() Call to finish() در مسیر کد وجود ندارد. اطمینان حاصل کنید که finish() همیشه فراخوانی شود.

چگونه اشکال زدایی کنیم

بر اساس امضای خوشه و گزارش ANR، می‌توانید رشته‌ای را که گیرنده روی آن اجرا می‌کند، و سپس کد خاصی را که گم شده یا به کندی اجرا می‌شود، پیدا کنید.

نمودار جریان زیر نحوه تعیین علت ANR گیرنده پخش را نشان می دهد.

شکل 5. نحوه اشکال زدایی ANR گیرنده پخش.

کد گیرنده را پیدا کنید

کنسول Google Play کلاس گیرنده و هدف پخش را در امضای 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 به طور کلی کجا اتفاق می‌افتد، بقیه پشته‌های رشته اصلی را بررسی کنید تا عملکرد کند را پیدا کنید و آن را بهینه کنید یا از مسیر بحرانی خارج کنید.

برای اطلاعات بیشتر در مورد خدمات، به صفحات زیر مراجعه کنید:

ارائه دهنده محتوا پاسخ نمی دهد

یک ANR ارائه‌دهنده محتوا زمانی اتفاق می‌افتد که یک ارائه‌دهنده محتوای راه دور بیشتر از مدت زمان وقفه برای پاسخ به یک درخواست طول بکشد و کشته شود.

بازه زمانی پیش‌فرض : توسط ارائه‌دهنده محتوا با استفاده از ContentProviderClient.setDetectNotResponding مشخص شده است. دوره وقفه ANR کل زمان اجرای درخواست ارائه‌دهنده محتوای راه دور را شامل می‌شود، که شامل راه‌اندازی سرد برنامه از راه دور در صورتی که قبلاً اجرا نشده بود، می‌شود.

برای جلوگیری از ANR ارائه‌دهنده محتوا، بهترین روش‌ها را دنبال کنید:

  • مطمئن شوید که راه‌اندازی برنامه سریع است، زیرا اگر برنامه برای اجرای ارائه‌دهنده محتوا شروع به کار کند، در مهلت زمانی ANR محاسبه می‌شود.
  • مطمئن شوید که درخواست های ارائه دهنده محتوا سریع هستند.
  • بسیاری از تماس‌های مسدودکننده بایندر را که می‌توانند همه رشته‌های کلاسور برنامه را مسدود کنند، انجام ندهید.

علل رایج

جدول زیر علل رایج ANR های ارائه دهنده محتوا و راه حل های پیشنهادی را فهرست می کند.

علت چه اتفاقی می افتد سیگنال راه حل پیشنهادی
پرس و جو ارائه دهنده محتوا کند اجرای ارائه دهنده محتوا خیلی طول می کشد یا مسدود شده است. قاب android.content.ContentProvider$Transport.query در رشته کلاسور قرار دارد. بهینه سازی درخواست ارائه دهنده محتوا پیدا کنید چه چیزی باعث مسدود شدن نخ کلاسور شده است.
راه اندازی آهسته برنامه راه اندازی برنامه ارائه دهنده محتوا خیلی طول می کشد. قاب ActivityThread.handleBindApplication در رشته اصلی قرار دارد. بهینه سازی راه اندازی اپلیکیشن
اتمام نخ کلاسور - همه رزوه های کلاسور مشغول هستند همه رشته‌های کلاسور مشغول ارائه درخواست‌های همزمان دیگر هستند، بنابراین تماس بایندر ارائه‌دهنده محتوا نمی‌تواند اجرا شود. برنامه شروع نمی شود، همه رشته های کلاسور مشغول هستند و ارائه دهنده محتوا در حال اجرا نیست. بار روی رزوه های کلاسور را کاهش دهید. یعنی تماس‌های همزمان خروجی بایندر کمتری برقرار کنید یا هنگام رسیدگی به تماس‌های ورودی، کار کمتری انجام دهید.

چگونه اشکال زدایی کنیم

برای اشکال‌زدایی 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 قابل اجرا است یا خیر، بردارید.

صف پیام بیکار یا nativePollOnce

اگر قاب 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 و ریختن پشته‌ها بازیابی شد. تأخیر در پیکسل‌ها در اندروید 13 حدود 100 میلی‌ثانیه است، اما می‌تواند از 1 ثانیه نیز فراتر رود. تاخیر در پیکسل ها در اندروید 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 قابل اجرا نیستند. برای اشکال‌زدایی، به کلاسترهای دیگر برنامه نگاه کنید، زیرا اگر مشکلی به اندازه کافی بزرگ باشد، معمولاً کلاستر مخصوص به خود را خواهد داشت که در آن فریم‌های پشته وجود دارد. گزینه دیگر این است که به Traces Perfetto نگاه کنید.

مسائل شناخته شده

نگه‌داشتن تایمر در فرآیند برنامه‌تان به‌منظور تکمیل مدیریت پخش قبل از راه‌اندازی ANR ممکن است به‌دلیل روش ناهمزمان نظارت بر ANR‌ها، به درستی کار نکند.