Общее руководство по диагностике ANR

Есть много вопросов с файлом трассировки ANR, и ответ всегда «о, проблема в вашем потоке 76, исправить ваш HTTP-вызов» или что-то 🙂 Но я не смог найти никакого общего руководства или учебника о том, как читать эти следы, Шаг за шагом для любого ANR. Есть ли? У меня мало вопросов, в частности:

  1. Всегда ли можно увидеть проблему из трассировок потоков, которые я вижу для реальных ANR в консоли Google? Или возможно, что нет никакой соответствующей информации, и мне не повезло, если я не могу воспроизвести ANR локально?

  2. Какие темы включены в эту информацию? Я полагаю, что из моего процесса приложения есть все потоки, но как насчет остальных? Все ли они так важны для меня? (Например, потоки, которые некоторые из моих потоков ждут и т. Д.). Или есть также полностью несвязанные процессы?

  3. Как консоль воспроизведения Google определяет «место», где произошло ANR, которое затем отображается в списке ANR, например:

ANR keyDispatchingTimedOut

Miesto: com.sample.myapp / myapp.activities.SplashActivity

Поскольку SplashActivity нигде не видно в представленном тексте трасс потоков.

  1. Я знаю, что я должен искать потоки в состоянии WAIT для потенциальных взаимоблокировок и т. Д. Как насчет ситуации, когда поток «ждет сам по себе»?

"AsyncTask # 1" prio = 5 tid = 15 WAIT | Group = "main" sCount = 1 dsCount = 0 obj = 0x41bb50c0 self = 0x5529a868 | SysTid = 2448 nice = 0 sched = 0/0 cgrp = apps handle = 1429609576 | State = S schedstat = (18097077 39273309 41) utm = 1 stm = 0 core = 1 в java.lang.Object.wait (собственный метод) – ожидание <0x41bb5258> (java.lang.VMThread), хранящееся tid = 15 (AsyncTask # 1)

Это всегда нормально, и я могу предположить, что это не причина? Как насчет ситуации, когда у меня есть только куча нитей в NATIVE (включая основной поток) и кучу потоков в WAIT, ожидающих себя так? Как это может быть ANR?

Система отправляет различные события в ваше приложение, которые принимаются в потоке пользовательского интерфейса. Если этот поток не отвечает на события в течение определенного периода времени, система делает вывод о том, что приложение не отвечает и инициирует обработку ANR.

Обращаясь к вашему вопросу по пунктам:

  1. Не всегда можно увидеть проблему в трассировке стека. Процесс системного сервера обнаруживает, что существует проблема, а затем сигнализирует о проблемном процессе, чтобы сбрасывать трассировки стека. Если приложение восстановилось между обнаружением проблемы и сигналом дампа в стеке, то трассировки вам не расскажут.

  2. Вы должны увидеть все потоки из своего приложения и только вашего приложения. Механизм ANR не пытается определить набор «релевантных» потоков. Место для начала – поток пользовательского интерфейса, обычно «основной» поток приложения, чтобы увидеть, поймаете ли вы его в результате застревания. Иногда приложение работает медленно, не застревает, и причина медленности – это фактически другой процесс, который замачивает пропускную способность процессора или диска, но вы не можете видеть это в трассировке стека … и вы, скорее всего, получите стек След, который отражает выполнение за ту точку, где он «застревает».

  3. «Место» – это событие, на которое не ответили (в данном случае ключевое событие) и активность, с которой система пыталась взаимодействовать.

  4. Это нормально; Вы увидите, что когда поток «припаркован» через java.util.concurrent.locks.LockSupport.park() в Dalvik. Помните, что блокировка освобождается, пока поток ожидает, так что в этом случае он просто ждет, когда еще один поток появится и уведомит об этом.

Обращаясь к вопросу, поднятому в комментариях: возможно, что нативный сбой приведет к ANR, если (1) собственный сбой не полностью уничтожает приложение, что и должно быть сделано; И (2) поток, который умер, был потоком пользовательского интерфейса или содержал ресурс, который ожидал поток пользовательского интерфейса. Если у вас нет доступа к полному логарифму, вы можете проверить список потоков, чтобы подтвердить, что все ваши потоки живы.

Когда вы смотрите на ANR, первое, что вам нужно выяснить, это то, что оно постоянно застряло или просто временно замедлилось. Это должно быть очевидно для человека, использующего приложение. Постоянное зависание, как правило, проще всего решить, так как трассировка стека, как правило, приведет вас к тому, что пошло не так. Начните с потока пользовательского интерфейса и пройдитесь по трассе, пока не найдете немного кода, который вращается или застревает в обычном вызове. (Есть трюк с родными вызовами, хотя – если он говорит NATIVE, то он по-прежнему находится в собственном коде, но если он говорит SUSPENDED в потоке с нативным методом в верхней части стека, то он не застревает, а скорее действует Возврата из native в управляемый код.)

Переходные ANR могут быть сложнее, особенно если они происходят на клиентских устройствах, конфигурация которых неизвестна. Если они используют тесты CPU в фоновом режиме на устройстве, которое останавливается из-за сбоя флэш-части, ваше приложение будет иметь плохое время. Иногда трассировка стека указывает на общее направление проблемы (например, эта , где появляется медленная рендеринг и грубая блокировка, останавливает поток пользовательского интерфейса), в то время как трассировка сохраняется после того, как приложение возвращается к нормальной работе.

Вероятно, это не общий общий рецепт обнаружения ANR, который вы ищете, но хороший старт – это быстрый режим для вашего приложения.

Вы сможете проверить logcat, и система сообщит вам, когда вы делаете что-то неправильно.

Просто добавьте эти строки в метод onCreate () приложения или Activity:

 if (BuildConfig.DEBUG) { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectDiskReads() .detectDiskWrites() .detectAll() .penaltyLog() .build()); StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() .detectLeakedSqlLiteObjects() .detectLeakedClosableObjects() .penaltyLog() .build()); } 

Подробнее здесь: http://developer.android.com/reference/android/os/StrictMode.html