שגיאות יישום לא מגיב (ANR) מופעלות כאשר שרשור ממשק המשתמש של היישום אינו מגיב במשך יותר מ -5 שניות . תוכל לקרוא עוד על ANRs ואבחון ANR בתיעוד של Android .
בנוסף, Crashlytics יכול לעזור באיתור שרשורים בעייתיים ספציפיים. אנו מנתחים מקרי ANR, ולאחר מכן, בלוח המחוונים של 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)
המלצה
תסתכל על שרשורים המעורבים במבוי סתום ובדוק את המשאבים/מנעולים שנרכשו על ידי השרשורים האלה. עיין באלגוריתמים למניעת Deadlock ו-Deadlock לפתרונות אפשריים.
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 )
המלצה
באופן כללי, האפליקציה שלך לא אמורה לבצע פעולות I/O יקרות בשרשור הראשי. במקרה של הוויית החוט הראשי 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 )
המלצה
צמצם עבודה אינטנסיבית של מעבד בשרשור הראשי. השתמש בשרשורי עובדים או רקע לביצוע משימות אינטנסיביות של מעבד.
צמצם עבודה אינטנסיבית של קלט/פלט, כמו טעינה ממסד נתונים, על השרשור הראשי.
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 )
המלצה
עקוב אחר העצה הכללית כיצד למנוע ANRs. לדוגמה, זהה את המקומות בקוד שלך שבהם השרשור הראשי של האפליקציה יכול להיות תפוס במשך יותר מ -5 שניות .