Android - bagaimana cara saya menyelidiki ANR?

153

Apakah ada cara untuk mengetahui di mana aplikasi saya melemparkan PPA (Aplikasi Tidak Menanggapi). Saya melihat file traces.txt di / data dan saya melihat jejak untuk aplikasi saya. Inilah yang saya lihat di jejak.

DALVIK THREADS:
"main" prio=5 tid=3 TIMED_WAIT
  | group="main" sCount=1 dsCount=0 s=0 obj=0x400143a8
  | sysTid=691 nice=0 sched=0/0 handle=-1091117924
  at java.lang.Object.wait(Native Method)
  - waiting on <0x1cd570> (a android.os.MessageQueue)
  at java.lang.Object.wait(Object.java:195)
  at android.os.MessageQueue.next(MessageQueue.java:144)
  at android.os.Looper.loop(Looper.java:110)
  at android.app.ActivityThread.main(ActivityThread.java:3742)
  at java.lang.reflect.Method.invokeNative(Native Method)
  at java.lang.reflect.Method.invoke(Method.java:515)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
  at dalvik.system.NativeStart.main(Native Method)

"Binder Thread #3" prio=5 tid=15 NATIVE
  | group="main" sCount=1 dsCount=0 s=0 obj=0x434e7758
  | sysTid=734 nice=0 sched=0/0 handle=1733632
  at dalvik.system.NativeStart.run(Native Method)

"Binder Thread #2" prio=5 tid=13 NATIVE
  | group="main" sCount=1 dsCount=0 s=0 obj=0x433af808
  | sysTid=696 nice=0 sched=0/0 handle=1369840
  at dalvik.system.NativeStart.run(Native Method)

"Binder Thread #1" prio=5 tid=11 NATIVE
  | group="main" sCount=1 dsCount=0 s=0 obj=0x433aca10
  | sysTid=695 nice=0 sched=0/0 handle=1367448
  at dalvik.system.NativeStart.run(Native Method)

"JDWP" daemon prio=5 tid=9 VMWAIT
  | group="system" sCount=1 dsCount=0 s=0 obj=0x433ac2a0
  | sysTid=694 nice=0 sched=0/0 handle=1367136
  at dalvik.system.NativeStart.run(Native Method)

"Signal Catcher" daemon prio=5 tid=7 RUNNABLE
  | group="system" sCount=0 dsCount=0 s=0 obj=0x433ac1e8
  | sysTid=693 nice=0 sched=0/0 handle=1366712
  at dalvik.system.NativeStart.run(Native Method)

"HeapWorker" daemon prio=5 tid=5 VMWAIT
  | group="system" sCount=1 dsCount=0 s=0 obj=0x4253ef88
  | sysTid=692 nice=0 sched=0/0 handle=1366472
  at dalvik.system.NativeStart.run(Native Method)

----- end 691 -----

Bagaimana saya bisa mengetahui di mana masalahnya? Metode dalam penelusuran adalah semua metode SDK.

Terima kasih.

hilangInTransit
sumber
2
Saya punya satu laporan semacam ini, juga terjadi di android.os.MessageQueue.nativePollOnce(Native Method). Bisakah saya mengabaikannya dengan aman?
rds

Jawaban:

124

ANR terjadi ketika beberapa operasi lama berlangsung di utas "utama". Ini adalah utas loop acara, dan jika sibuk, Android tidak dapat memproses acara GUI lebih lanjut dalam aplikasi, dan karenanya memunculkan dialog PPA.

Sekarang, dalam jejak yang Anda posting, utas utama tampaknya baik-baik saja, tidak ada masalah. Itu idle di MessageQueue, menunggu pesan lain masuk. Dalam kasus Anda ANR kemungkinan operasi yang lebih lama, daripada sesuatu yang memblokir utas secara permanen, sehingga utas peristiwa pulih setelah operasi selesai, dan penelusuran Anda dilacak setelah PPA.

Mendeteksi di mana PPA terjadi mudah jika itu adalah blok permanen (kebuntuan mendapatkan beberapa kunci misalnya), tetapi lebih sulit jika itu hanya penundaan sementara. Pertama, periksalah kode Anda dan cari tempat-tempat yang vunerable dan operasi yang berjalan lama. Contohnya termasuk menggunakan soket, kunci, tidur ulir, dan operasi pemblokiran lainnya dari dalam utas acara. Anda harus memastikan ini semua terjadi di utas terpisah. Jika tidak ada masalah, gunakan DDMS dan aktifkan tampilan utas. Ini menunjukkan semua utas dalam aplikasi Anda mirip dengan jejak yang Anda miliki. Reproduksi ANR, dan segarkan utas utama secara bersamaan. Itu harus menunjukkan dengan tepat apa yang terjadi pada saat PPA

sooniln
sumber
6
satu-satunya masalah adalah "mereproduksi ANR" :-). bisa tolong jelaskan bagaimana acara jejak stack itu adalah utas 'idling', itu akan bagus.
Blundell
20
Jejak tumpukan menunjukkan bahwa utas utama ada di Looper (implementasi loop pesan) dan melakukan menunggu waktunya melalui Object.wait. Ini berarti loop pesan saat ini tidak memiliki pesan untuk dikirim, dan sedang menunggu pesan baru untuk masuk. ANR terjadi ketika sistem menyadari loop pesan menghabiskan banyak waktu untuk memproses pesan, dan tidak memproses pesan lain di antre. Jika loop menunggu pesan, jelas ini tidak terjadi.
sooniln
3
@Soonil Hai, tahukah Anda apa arti bagian-bagian lain seperti Binder thread 3, Binder thread 2 JDWP demon prio 5. apa itu sCount, dsCount, obj, sysTid, nice sched means. juga memiliki informasi seperti VMWAIT, RUNNABLE, NATIVE
minhaz
1
Aplikasi saya berbasis NDK, saya melihat ANR yang sama. Juga, utas utama baik-baik saja. Saya mencoba DDMS dan menyegarkan utas pekerja saya ketika membeku. Sayangnya yang saya dapatkan hanyalah satu baris NativeStart :: run. Apakah tampilan ulir DDMS bahkan mampu memeriksa utas NDK asli? Juga: StrictMode tidak menemukan apa pun.
Bram
6
Lihat elliotth.blogspot.com/2012/08/... untuk penjelasan yang baik tentang hasilnya.
sooniln
96

Anda dapat mengaktifkan StrictMode di API level 9 ke atas.

StrictMode paling umum digunakan untuk menangkap disk yang tidak disengaja atau akses jaringan pada utas utama aplikasi, tempat operasi UI diterima dan animasi dilakukan. Dengan menjaga utas utas aplikasi Anda responsif, Anda juga mencegah dialog PPA ditampilkan kepada pengguna.

public void onCreate() {
    StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                           .detectAll()
                           .penaltyLog()
                           .penaltyDeath()
                           .build());
    super.onCreate();
}

menggunakan penaltyLog()Anda dapat menonton output dari adb logcat saat Anda menggunakan aplikasi Anda untuk melihat pelanggaran yang terjadi.

Dheeraj Vepakomma
sumber
StrictMode tidak bisa diselesaikan ke suatu jenis. Apakah ada yang perlu saya impor terlebih dahulu? Menekan CTRL + SHIFT + O tidak membantu.
kuchi
23
tip kecil - gunakan if (BuildConfig.DEBUG) ... untuk mencegah inklusi dalam produksi
Amir Uval
@uval apa yang Anda maksud dengan "untuk mencegah dimasukkannya dalam produksi"? !!
Muhammed Refaat
2
@MuhammedRefaat tidak mencegah PPA apa pun. Ini akan crash aplikasi segera, bukan setelah 5 detik. Misalnya, jika Anda mengakses database di utas utama dan butuh 2 detik, Anda tidak akan mendapatkan ANR, tetapi StrictMode akan membuat aplikasi mogok. StrictMode hanya untuk fase debugging Anda, bukan produksi.
Amir Uval
1
@MuhammedRefaat menambahkan balasan saya ke pertanyaan Anda.
Amir Uval
80

Anda bertanya-tanya tugas mana yang memegang Thread UI. File jejak memberi Anda petunjuk untuk menemukan tugas. Anda perlu menyelidiki keadaan setiap utas

Keadaan utas

  • menjalankan - mengeksekusi kode aplikasi
  • sedang tidur - bernama Thread.sleep ()
  • monitor - menunggu untuk mendapatkan kunci monitor
  • tunggu - di Object.wait ()
  • asli - mengeksekusi kode asli
  • vmwait - menunggu sumber daya VM
  • zombie - thread sedang dalam proses kematian
  • init - utas menginisialisasi (Anda seharusnya tidak melihat ini)
  • starting - utas akan segera dimulai (Anda juga tidak akan melihat ini)

Fokus pada SUSPENDED, MONITOR state. Status monitor mengindikasikan thread mana yang diselidiki dan status thread yang DITANGGUNG mungkin merupakan alasan utama kebuntuan.

Langkah-langkah investigasi dasar

  1. Temukan "menunggu untuk mengunci"
    • Anda dapat menemukan status monitor "Binder Thread # 15" prio = 5 tid = 75 MONITOR
    • Anda beruntung jika menemukan "menunggu untuk mengunci"
    • contoh: menunggu untuk mengunci <0xblahblah> (a com.foo.A) yang dipegang oleh threadid = 74
  2. Anda dapat melihat bahwa "tid = 74" memegang tugas sekarang. Jadi buka tid = 74
  3. tid = 74 negara mungkin TERGANTUNG! temukan alasan utama!

trace tidak selalu mengandung "waiting to lock". dalam hal ini sulit untuk menemukan alasan utama.

Horyun Lee
sumber
1
Penjelasan yang bagus. Sekarang lebih mudah bagi saya untuk memahami log PPA. Tetapi saya masih memiliki masalah untuk dipahami karena pada langkah 1 saya dapat dengan mudah menemukan id utas tetapi ketika, pada langkah 2, saya mencoba untuk pergi ke tempat itu, untuk memeriksa keadaan, saya tidak dapat menemukannya. . Adakah yang tahu bagaimana melanjutkannya?
THZ
1
Saya punya - waiting to lock an unknown objectdi dalam "HeapTaskDaemon" daemon prio=5 tid=8 Blocked . Apa artinya seseorang dapat membantu?
Hilal
13

Saya sudah belajar android selama beberapa bulan terakhir, jadi saya jauh dari ahli, tapi saya benar-benar kecewa dengan dokumentasi ANR.

Sebagian besar saran tampaknya diarahkan untuk menghindari mereka atau memperbaikinya dengan melihat secara membabi buta melalui kode Anda, yang bagus, tetapi saya tidak dapat menemukan apa pun dalam menganalisis jejak.

Ada tiga hal yang benar-benar perlu Anda cari dengan log ANR.

1) Deadlock: Ketika sebuah thread berada dalam status WAIT, Anda dapat melihat rincian untuk menemukan siapa itu "dipegang =". Sebagian besar waktu, itu akan dipegang dengan sendirinya, tetapi jika dipegang oleh utas lain, itu mungkin merupakan tanda bahaya. Pergi melihat utas itu dan lihat apa yang dipegangnya. Anda mungkin menemukan lingkaran, yang merupakan pertanda jelas bahwa ada sesuatu yang salah. Ini sangat jarang, tetapi ini adalah poin pertama karena ketika itu terjadi, itu adalah mimpi buruk

2) Utas utama Menunggu: Jika utas utama Anda dalam status TUNGGU, periksa apakah utas dimiliki oleh utas lainnya. Ini seharusnya tidak terjadi, karena utas UI Anda seharusnya tidak dipegang oleh utas latar belakang.

Kedua skenario ini, berarti Anda perlu mengolah kode Anda secara signifikan.

3) Operasi berat pada utas utama: Ini adalah penyebab paling umum dari PPA, tetapi terkadang salah satu yang lebih sulit ditemukan dan diperbaiki. Lihatlah detail utas utama. Gulir ke bawah jejak tumpukan dan sampai Anda melihat kelas yang Anda kenali (dari aplikasi Anda). Lihatlah metode dalam penelusuran dan cari tahu apakah Anda melakukan panggilan jaringan, panggilan db, dll di tempat-tempat ini.

Akhirnya, dan saya minta maaf karena tanpa malu memasukkan kode saya sendiri, Anda dapat menggunakan penganalisis log python yang saya tulis di https://github.com/HarshEvilGeek/Android-Log-Analyzer Ini akan melalui file log Anda, buka file ANR, cari kebuntuan, temukan utas utama yang menunggu, temukan pengecualian yang tidak tertangkap dalam log agen Anda dan cetak semuanya di layar dengan cara yang relatif mudah dibaca. Baca file ReadMe (yang akan saya tambahkan) untuk mempelajari cara menggunakannya. Ini membantu saya satu ton di minggu terakhir!

Akhil Cherian Verghese
sumber
4

Setiap kali Anda menganalisis masalah waktu, debugging sering kali tidak membantu, karena membekukan aplikasi di breakpoint akan membuat masalah hilang.

Taruhan terbaik Anda adalah memasukkan banyak panggilan logging (Log.XXX ()) ke utas dan panggilan balik aplikasi yang berbeda dan lihat di mana penundaannya. Jika Anda membutuhkan stacktrace, buat Exception baru (cukup instantiate) dan catat.

Ulrich
sumber
2
Terima kasih atas sarannya membuat pengecualian baru jika Anda membutuhkan stacktrace. Itu sangat membantu saat
men-
3

Apa yang Memicu ANR?

Secara umum, sistem menampilkan PPA jika aplikasi tidak dapat menanggapi input pengguna.

Dalam situasi apa pun di mana aplikasi Anda melakukan operasi yang berpotensi panjang, Anda tidak boleh melakukan pekerjaan pada utas UI, melainkan membuat utas pekerja dan melakukan sebagian besar pekerjaan di sana. Ini membuat utas UI (yang menggerakkan loop peristiwa antarmuka pengguna) berjalan dan mencegah sistem menyimpulkan bahwa kode Anda telah dibekukan.

Cara Menghindari ANR

Aplikasi Android biasanya berjalan seluruhnya pada satu utas secara default "utas UI" atau "utas utama"). Ini berarti apa pun yang dilakukan aplikasi Anda di utas UI yang membutuhkan waktu lama untuk diselesaikan dapat memicu dialog PPA karena aplikasi Anda tidak memberikan kesempatan kepada dirinya sendiri untuk menangani acara masukan atau siaran maksud.

Oleh karena itu, metode apa pun yang berjalan di utas UI harus melakukan pekerjaan sesedikit mungkin pada utas itu. Secara khusus, kegiatan harus dilakukan sesedikit mungkin untuk mengatur dalam metode siklus hidup utama seperti onCreate () dan onResume (). Operasi yang berpotensi berjalan lama seperti operasi jaringan atau basis data, atau perhitungan yang mahal secara komputasi seperti mengubah ukuran bitmap harus dilakukan dalam utas pekerja (atau dalam kasus operasi basis data, melalui permintaan asinkron).

Kode: Utas pekerja dengan kelas AsyncTask

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
    // Do the long-running work in here
    protected Long doInBackground(URL... urls) {
        int count = urls.length;
        long totalSize = 0;
        for (int i = 0; i < count; i++) {
            totalSize += Downloader.downloadFile(urls[i]);
            publishProgress((int) ((i / (float) count) * 100));
            // Escape early if cancel() is called
            if (isCancelled()) break;
        }
        return totalSize;
    }

    // This is called each time you call publishProgress()
    protected void onProgressUpdate(Integer... progress) {
        setProgressPercent(progress[0]);
    }

    // This is called when doInBackground() is finished
    protected void onPostExecute(Long result) {
        showNotification("Downloaded " + result + " bytes");
    }
}

Kode: Jalankan utas Pekerja

Untuk mengeksekusi utas pekerja ini, cukup buat sebuah instance dan panggil execute ():

new DownloadFilesTask().execute(url1, url2, url3);

Sumber

http://developer.android.com/training/articles/perf-anr.html

Mendongkrak
sumber
1

masalah saya dengan PPA, setelah banyak pekerjaan saya menemukan bahwa utas memanggil sumber daya yang tidak ada dalam tata letak, alih-alih mengembalikan pengecualian, saya mendapat P ...

yaniv
sumber
itu sangat aneh
Nilabja
0

Dasar pada @Horyun Lee menjawab, saya menulis skrip python kecil untuk membantu menyelidiki ANR dari traces.txt.

ANRs akan ditampilkan sebagai grafik graphvizjika Anda telah menginstal grapvhvizpada sistem Anda.

$ ./anr.py --format png ./traces.txt

Sebuah png akan menampilkan seperti di bawah ini jika ada PPA terdeteksi dalam file traces.txt. Ini lebih intuitif.

masukkan deskripsi gambar di sini

File sampel yang traces.txtdigunakan di atas didapat dari sini .

alijandro
sumber
0

Pertimbangkan untuk menggunakan perpustakaan ANR-Watchdog untuk secara akurat melacak dan menangkap jejak tumpukan ANR dalam detail tingkat tinggi. Anda kemudian dapat mengirimnya ke perpustakaan pelaporan kerusakan Anda. Saya sarankan menggunakan setReportMainThreadOnly()dalam skenario ini. Anda dapat membuat aplikasi melemparkan pengecualian non-fatal dari titik beku, atau membuat kekuatan aplikasi berhenti ketika ANR terjadi.

Perhatikan bahwa laporan PPA standar yang dikirim ke konsol Pengembang Google Play Anda seringkali tidak cukup akurat untuk menunjukkan masalah yang sebenarnya. Itu sebabnya perpustakaan pihak ketiga diperlukan.

Tuan-IDE
sumber