Menemukan rangkaian pesan yang tidak responsif

Dokumen ini menunjukkan cara mengidentifikasi thread yang tidak responsif dalam stack dump ANR. Thread yang tidak responsif berbeda-beda menurut jenis ANR, seperti yang ditunjukkan dalam tabel berikut.

Jenis ANR Thread yang tidak responsif
Pengiriman input Thread utama
Pengiriman input tanpa jendela yang difokuskan Thread utama. Jenis ANR ini biasanya tidak disebabkan oleh thread yang diblokir.
Penerima siaran (sinkron) Thread menjalankan onReceive(). Ini adalah thread utama, kecuali jika pengendali kustom pada thread non-utama ditentukan menggunakan Context.registerReceiver.
Penerima siaran (asinkron) Periksa kode untuk melihat thread atau kumpulan thread yang bertanggung jawab melakukan tugas untuk memproses siaran setelah goAsync dipanggil.
Mengeksekusi waktu tunggu layanan Thread utama
Layanan latar depan dimulai Thread utama
Penyedia konten tidak merespons Atau:
  • Thread binder jika ANR disebabkan oleh kueri penyedia konten yang lambat.
  • Thread utama jika ANR disebabkan oleh startup aplikasi yang lama.
Tidak ada respons untuk onStartJob atau onStopJob Thread utama

Terkadang thread tidak responsif karena akar masalah dalam thread atau proses yang berbeda. Thread tidak dapat merespons karena menunggu hal berikut:

  • Kunci yang dipegang oleh thread lain.
  • Panggilan binder lambat ke proses yang berbeda.

Penyebab umum thread yang tidak responsif

Berikut adalah penyebab umum thread yang tidak responsif.

Panggilan binder lambat

Meskipun sebagian besar panggilan binder berlangsung dengan cepat, longtail-nya bisa sangat lambat. Hal ini lebih mungkin terjadi jika perangkat dimuat atau thread balasan binder lambat, seperti dari pertentangan kunci, banyak panggilan binder yang masuk, atau waktu tunggu hardware abstraction layer (HAL).

Anda dapat mengatasi hal ini dengan memindahkan panggilan binder sinkron ke thread latar belakang jika memungkinkan. Jika panggilan harus terjadi pada thread utama, cari tahu penyebab panggilan lambat. Cara terbaik untuk melakukannya adalah dari rekaman aktivitas Perfetto.

Cari BinderProxy.transactNative atau Binderproxy.transact di stack. Hal ini berarti panggilan binder sedang berlangsung. Dengan mengikuti dua baris ini, Anda dapat melihat API binder yang dipanggil. Pada contoh berikut, panggilannya adalah ke IAccessibilityManager.addClient.

main tid=123

...
android.os.BinderProxy.transactNative (Native method)
android.os.BinderProxy.transact (BinderProxy.java:568)
android.view.accessibility.IAccessibilityManager$Stub$Proxy.addClient (IAccessibilityManager.java:599)
...

Banyak panggilan binder berturut-turut

Melakukan banyak panggilan binder berturut-turut dalam loop padat dapat memblokir thread dalam jangka waktu yang lama.

Pemblokiran I/O

Jangan pernah memblokir I/O di thread utama. Hal ini adalah antipola.

Pertentangan kunci

Jika thread diblokir saat mendapatkan kunci, hal ini dapat menyebabkan ANR.

Contoh berikut menunjukkan thread utama diblokir saat mencoba mendapatkan kunci:

main (tid=1) Blocked

Waiting for com.example.android.apps.foo.BarCache (0x07d657b7) held by
ptz-rcs-28-EDITOR_REMOTE_VIDEO_DOWNLOAD
[...]
at android.app.ActivityThread.handleStopActivity(ActivityThread.java:5412)
[...]

Thread yang diblokir membuat permintaan HTTP untuk mendownload video:

ptz-rcs-28-EDITOR_REMOTE_VIDEO_DOWNLOAD (tid=110) Waiting

at jdk.internal.misc.Unsafe.park(Native method:0)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:211)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:715)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1047)
at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:230)
at com.example.android.apps.foo.HttpRequest.execute(HttpRequest:136)
at com.example.android.apps.foo$Task$VideoLoadTask.downloadVideoToFile(RequestExecutor:711)
[...]

Frame mahal

Merender terlalu banyak hal dalam satu frame dapat menyebabkan thread utama tidak responsif selama durasi frame, seperti berikut:

  • Merender banyak item di luar layar yang tidak perlu.
  • Menggunakan algoritma yang tidak efisien, seperti O(n^2), saat merender banyak elemen UI.

Diblokir oleh komponen lain

Jika komponen lain, seperti penerima siaran, memblokir thread utama selama lebih dari lima detik, hal ini dapat menyebabkan ANR pada pengiriman input dan jank serius.

Hindari melakukan tugas berat pada thread utama dalam komponen aplikasi. Jalankan penerima siaran di thread lain jika memungkinkan.