خطاهای «برنامه پاسخ نمیدهد» (ANR) زمانی راهاندازی میشوند که رشته میانای کاربر
برنامه برای بیشاز ۵ ثانیه پاسخ ندهد. میتوانید در
اسناد Android درباره خطاهای ANR و تشخیص خطاهای ANR
بیشتر بخوانید.
علاوهبراین، Crashlytics میتواند به شناسایی رشتههای مشکلساز خاص کمک کند. ما خطاهای ANR را تحلیل میکنیم و سپس در داشبورد DevOps و تعامل > Crashlytics، رشتههای مربوطه را برچسبگذاری میکنیم تا نکاتی درباره نحوه اشکالزدایی خطای ANR ارائه دهیم.
بخشهای زیر در این صفحه توضیح میدهند که هر برچسب ANR چه معنایی دارد،
نمونهای از ANR با آن برچسب را نشان میدهند، و راهحل توصیهشدهای برای اشکالزدایی ANR ارائه میدهند.
Triggered ANR
رشتهای که برای مدت طولانی مسدود شده و باعث ایجاد خطای ANR شده است با این برچسب Triggered ANR حاشیهنویسی میشود.
رشته مشکلدار میتواند رشته اصلی برنامه یا هر رشتهای باشد که
پاسخگو نیست. بااینحال، رشتهای که با برچسب
Triggered ANR مشخص شده است ممکن است علت واقعی
خطای ANR باشد یا نباشد. برای ارائه اطلاعات آماری برای اشکالزدایی و رفع این خطاهای ANR،
Crashlytics همچنین هر رشته دیگری را که در خطای ANR دخیل است برچسبگذاری میکند. در
بخشهای بعدی این صفحه، با برچسبهای دیگری که میتوانند
به رشته اعمال شوند آشنا شوید.
Deadlocked
هر رشتهای که مشخص شود در بنبستی که منجر به ANR شده است دخیل بوده است، با این برچسب Deadlocked حاشیهنویسی میشود.
بنبست زمانی رخ میدهد که رشتهای وارد حالت انتظار میشود زیرا منبع موردنیاز توسط رشته دیگری نگهداشته شده است، که آن رشته نیز منتظر منبعی است که توسط رشته اول نگهداشته شده است. اگر رشته اصلی برنامه در این وضعیت باشد، احتمالاً خطای ANR رخ میدهد.
مشاهده نمونه
در اینجا دو رشته درگیر در بنبست آورده شده است:
main (unknown): tid=1 systid=1568
com.android.server.pm.PackageManagerService$PackageManagerInternalImpl.getPackage(PackageManagerService.java:22701)
com.android.server.pm.PackageManagerService$PackageManagerInternalImpl.filterOnlySystemPackages(PackageManagerService.java:22787)
...
com.android.server.SystemServer.main(SystemServer.java:368)
java.lang.reflect.Method.invoke(Native method)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:517)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:934)
ActivityManager (unknown): tid=21 systid=1902
com.android.server.pm.PackageManagerService.getPackageSetting(PackageManagerService.java:23618)
com.android.server.pm.PackageManagerService.getPackageUid(PackageManagerService.java:4542)
...
android.os.Handler.handleCallback(Handler.java:907)
android.os.Handler.dispatchMessage(Handler.java:99)
android.os.Looper.loop(Looper.java:216)
android.os.HandlerThread.run(HandlerThread.java:67)
com.android.server.ServiceThread.run(ServiceThread.java:44)
توصیه
رشتههای درگیر در بنبست را بررسی کنید و منابع/قفلهای بهدستآمده توسط آن رشتهها را بررسی کنید. برای راهحلهای احتمالی، به
بنبست و
الگوریتمهای جلوگیری از بنبست
مراجعه کنید.
IO Root blocking
هر رشتهای که درحال اجرای عملیات ورودی/خروجی کند بوده و رشته
Triggered ANR را مسدود کرده است با برچسب
IO Root blocking حاشیهنویسی میشود. اگر رشته
Triggered ANR توسط رشتههای دیگر مسدود نشده باشد،
رشته IO Root blocking نیز رشته
Root blocking است.
مشاهده نمونهها
Thread main(THREAD_STATE_TIMED_WAITING)
sun.misc.Unsafe.park( Unsafe.java:0 )
java.util.concurrent.locks.LockSupport.parkNanos( LockSupport.java:230 )
android.database.sqlite.SQLiteConnectionPool.waitForConnection( SQLiteConnectionPool.java:756 )
...
android.app.ActivityThread.main( ActivityThread.java:8192 )
Thread main(THREAD_STATE_NATIVE_WAITING)
Syscall
art::ConditionVariable::WaitHoldingLocks(art::Thread*)
art::GoToRunnable(art::Thread*)
art::JniMethodEnd(unsigned int, art::Thread*)
libcore.io.Linux.fdatasync( Linux.java:0 )
libcore.io.ForwardingOs.fdatasync( ForwardingOs.java:105 )
...
java.io.RandomAccessFile.write( RandomAccessFile.java:559 )
...
android.app.ActivityThread.main( ActivityThread.java:8192 )
توصیه
بهطور کلی، برنامهتان نباید عملیات ورودی/خروجی پرهزینه را در رشته اصلی اجرا کند. درصورتیکه رشته اصلی
IO Root blocking باشد، میتوانید از
حالت سختگیرانه
نیز برای شناسایی عملیات ورودی/خروجی ناخواستهای که در رشته اصلی
اتفاق میافتد استفاده کنید.
Root blocking
هر رشتهای که رشته برچسبگذاریشده بهعنوان
Triggered ANR را مسدود کرده باشد، با برچسب
Root blocking حاشیهنویسی میشود. اگر رشتهای هم با
Root blocking و هم با
Triggered ANR برچسبگذاری شده باشد، رشته دیگری وجود ندارد که
آن رشته را مسدود کند.
اگر هر رشته Triggered ANR (شاید بهصورت متعدی) منتظر رشتههای دیگر باشد،
Root blocking است. دلایل مختلفی میتواند وجود داشته باشد که چرا یک
رشته علت ریشهای ANR است.
مشاهده نمونهها
در اینجا چند نمونه براساس وضعیت رشته آورده شده است:
Thread main(THREAD_STATE_RUNNABLE)
android.os.Parcel.createTypedArray( Parcel.java:3086 )
android.content.pm.PackageInfo.<init>( PackageInfo.java:546 )
...
android.app.ActivityThread$H.handleMessage( ActivityThread.java:2166 )
android.os.Handler.dispatchMessage( Handler.java:106 )
android.os.Looper.loop( Looper.java:246 )
android.app.ActivityThread.main( ActivityThread.java:8633 )
Thread main(THREAD_STATE_BLOCKED)
DBHelper.runOnDB( DBHelper.java:97 )
DBHelper.runDb( DBHelper.java:125 )
...
java.lang.reflect.Method.invoke( Method.java:0 )
EventBus.invokeSubscriber( EventBus.java:510 )
postToSubscription( EventBus.java:437 )
...
android.os.Handler.handleCallback( Handler.java:938 )
android.os.Handler.dispatchMessage( Handler.java:99 )
android.os.Looper.loop( Looper.java:268 )
android.app.ActivityThread.main( ActivityThread.java:7904 )
توصیه
کارهای سنگین برای واحد پردازش مرکزی را در رشته اصلی به حداقل برسانید. از رشتههای کارگر یا پسزمینه
برای انجام کارهای سنگین CPU استفاده کنید.
کارهای سنگین ورودی/خروجی، مثل بار کردن از پایگاه داده، را در رشته اصلی به حداقل برسانید.
Unknown root cause
رشتهای با برچسب Unknown root cause برچسبگذاری میشود اگر
رشتهای باشد که خطای ANR را راهاندازی کرده است اما هنگام وقوع خطای ANR در فرایند غیرفعال بوده است. Crashlytics اطلاعات کافی برای تعیین علت ریشهای ندارد. دلیل مشخصی برای وقوع این ANR وجود ندارد.
مشاهده نمونه
Thread main(THREAD_STATE_NATIVE_WAITING) __epoll_pwait
android::Looper::pollInner(int)
android::Looper::pollOnce(int, int*, int*, void**)
android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)
android.os.MessageQueue.nativePollOnce( MessageQueue.java:0 )
android.os.MessageQueue.next( MessageQueue.java:335 )
android.os.Looper.loop( Looper.java:193 )
android.app.ActivityThread.main( ActivityThread.java:8019 )
توصیه
توصیههای عمومی درباره نحوه جلوگیری از ANR را دنبال کنید. برای مثال، جاهایی را در کدتان شناسایی کنید که رشته اصلی برنامه میتواند برای بیشاز ۵ ثانیه مشغول باشد.
Waiting for binder call
هر رشتهای که منتظر فراخوانی binder بوده و رشته
Triggered ANR را مسدود کرده است با برچسب
Waiting for binder call حاشیهنویسی میشود. اگر رشته
Triggered ANR توسط رشتههای دیگر مسدود نشده باشد،
رشته Waiting for binder call نیز
رشته Root blocking است.
مشاهده نمونه
Thread main(THREAD_STATE_NATIVE_WAITING)
syscall
android::IPCThreadState::talkWithDriver(bool)
android::IPCThreadState::waitForResponse(android::Parcel*, int*)
android::IPCThreadState::transact(int, unsigned int, android::Parcel const&, android::Parcel*, unsigned int)
android::BpBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)
android_os_BinderProxy_transact(_JNIEnv*, _jobject*, int, _jobject*, _jobject*, int)
android.os.BinderProxy.transactNative( BinderProxy.java:0 )
android.os.BinderProxy.transact( BinderProxy.java:540 )
android.app.IActivityManager$Stub$Proxy.getContentProvider( IActivityManager.java:5945 )
android.app.ActivityThread.acquireProvider( ActivityThread.java:7138 )
android.app.ActivityThread$H.handleMessage( ActivityThread.java:1982 )
android.os.Handler.dispatchMessage( Handler.java:106 )
android.os.Looper.loop( Looper.java:236 )
android.app.ActivityThread.main( ActivityThread.java:8037 )
توصیه
چون تأخیر فراخوانی binder میتواند غیرقابلپیشبینی باشد، با فراخوانیهای binder مثل عملیات ورودی/خروجی رفتار کنید و درصورت امکان، آنها را در رشته اصلی انجام ندهید. کدی را که موجب فراخوانیهای Binder میشود (ازجمله فراخوانیهای میانای برنامهسازی کاربردی پلاتفرم که منجر به تراکنشهای Binder میشود) به رشته پسزمینه منتقل کنید، یا اگر فراخوانی از رشته اصلی اجتنابناپذیر است، نتایج را ذخیره کنید.