ANR Unity terjadi karena berbagai alasan. ANR yang paling umum disebabkan oleh penyalahgunaan komponen Android dan Unity serta miskomunikasinya.
WebView
WebView
adalah class Android yang menampilkan halaman web. SDK
pihak ketiga (seperti iklan) menggunakan WebView
untuk menampilkan konten web dinamis
dalam aktivitas selain UnityPlayerActivity
. ANR terjadi saat SDK pihak ketiga menyalahgunakan WebView
.
Stack trace
Stack trace adalah cara pertama Anda untuk memahami penyebab ANR.
/data/app/~~p-0ksfCD6bF6Sdq6kpVePg==/com.google.android.webview-5YQZOqKbbqp-uoLY6WYnTw==/base.apk!libmonochrome.so
at J.N.Mhc_M_H$ (Native method)
at org.chromium.components.viz.service.frame_sinks.ExternalBeginFrameSourceAndroid.doFrame (chromium-TrichromeWebViewGoogle.aab-stable-579013831:60)
at android.view.Choreographer$CallbackRecord.run (Choreographer.java:1054)
at android.view.Choreographer.doCallbacks (Choreographer.java:878)
at android.view.Choreographer.doFrame (Choreographer.java:807)
at android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:1041)
at android.os.Handler.handleCallback (Handler.java:938)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loop (Looper.java:223)
at android.app.ActivityThread.main (ActivityThread.java:7721)
at java.lang.reflect.Method.invoke (Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:952)
Gambar 1.Stack trace ANR yang disebabkan oleh waktu tunggu futex.
Penyebab
Sejauh ini, akar penyebab masalah ini belum jelas. Beberapa kemungkinan penyebabnya meliputi:
- Penerapan iklan yang buruk.
- Versi
WebView
yang sudah tidak berlaku karena pengguna mungkin telah memilih untuk tidak mengupdate aplikasi secara otomatis. - Penggunaan resource sistem (CPU, GPU, dll. yang tinggi), yang mungkin memerlukan banyak pembuatan profil.
- Kompilasi shader mengalami error, yang dapat menunjukkan bahwa
konten memiliki shader yang tidak kompatibel atau pengguna telah menginstal versi
WebView
lama.
Solusi
- Untuk mempersempit jenis konten yang menyebabkan
WebView
memblokir thread utama, tambahkan log ke game Anda setiap kali halaman web dimuat, ditampilkan, atau ditutup.- Anda dapat menggunakan layanan pelaporan Backtrace atau Crashlytics.
- Kemudian, setelah menganalisis data dan menemukan masalah, coba nonaktifkan penyedia iklan yang menyinggung.
- Sertakan log memori untuk memastikan masalah tidak terkait dengan memori.
- Beri tahu pengguna untuk mengupdate
WebView
dari Google Play. Dari Android 5.0 (level API 21) dan yang lebih tinggi,WebView
telah dipindahkan ke APK. Oleh karena itu, aplikasi dapat diupdate secara terpisah dari platform Android. Untuk melihat versiWebView
yang digunakan di perangkat, buka Setelan > Aplikasi > Android System WebView, lalu lihat versi di bagian bawah halaman.
WebView
.Jeda Unity
Saat UnityPlayerActivity
menerima panggilan onPause()
, rantai operasi berikut
akan dimulai:
UnityPlayerActivity
memberi tahu mesin runtime Unity bahwa aktivitas telah dijeda.- Unity memanggil setiap
MonoBehaviour
yang mengimplementasikan peristiwaOnApplicationPause
. - Unity menghentikan komponen dan modulnya, seperti pemutaran suara, rendering, game loop, dan animasi.
- Untuk memastikan
Unity Android Player
(UAP) dan mesin disinkronkan, UAP menunggu 4 detik hingga mesin berhenti. - Jika operasi tersebut memerlukan waktu lebih dari 5 detik, sistem akan memicu ANR.
Stack trace
"main" tid=1 Timed Waiting
jdk.internal.misc.Unsafe.park (Native method)
java.util.concurrent.locks.LockSupport.parkNanos (LockSupport.java:234)
java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedNanos (AbstractQueuedSynchronizer.java:1079)
java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireSharedNanos (AbstractQueuedSynchronizer.java:1369)
java.util.concurrent.Semaphore.tryAcquire (Semaphore.java:415)
com.unity3d.player.UnityPlayer.pauseUnity (UnityPlayer.java:833)
com.unity3d.player.UnityPlayer.pause (UnityPlayer.java:796)
com.unity3d.player.UnityPlayerActivity.onPause (UnityPlayerActivity.java:117)
android.app.Activity.performPause (Activity.java:8517)
android.app.Instrumentation.callActivityOnPause (Instrumentation.java:1618)
android.app.ActivityThread.performPauseActivityIfNeeded (ActivityThread.java:5061)
android.app.ActivityThread.performPauseActivity (ActivityThread.java:5022)
android.app.ActivityThread.handlePauseActivity (ActivityThread.java:4974)
android.app.servertransaction.PauseActivityItem.execute (PauseActivityItem.java:48)
android.app.servertransaction.ActivityTransactionItem.execute (ActivityTransactionItem.java:45)
android.app.servertransaction.TransactionExecutor.executeLifecycleState (TransactionExecutor.java:179)
android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:97)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:2303)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loopOnce (Looper.java:201)
android.os.Looper.loop (Looper.java:288)
android.app.ActivityThread.main (ActivityThread.java:7884)
java.lang.reflect.Method.invoke (Native method)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:548)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:936)
Gambar 3. ANR disebabkan oleh semafor yang tidak pernah dirilis.
Solusi
Pastikan kode game C# Anda tidak membutuhkan waktu yang terlalu lama untuk menyelesaikan eksekusi selama peristiwa jeda atau lanjutkan.
- Buat profil game Anda dan periksa apakah
OnApplicationPause
adalah operasi yang mahal. Anda dapat menggunakanStopwatch
. - Hindari operasi I/O atau permintaan jaringan sinkron.
- Pindahkan operasi ke
Thread
lain menggunakanTask
. Unity 2023.1 mendukung model pemrograman asinkron yang disederhanakan menggunakan kata kunci C#async
danawait
.
UnitySendMessage diblokir
Plugin dan SDK Java Unity mengirim data ke lapisan game C# menggunakan JNI. Namun, komunikasi ini mungkin memblokir thread utama karena rutinitas sinkronisasi native seperti mutex, menyebabkan ANR karena pertentangan kunci.
Stack trace
ANR pada gambar 4 disebabkan oleh operasi yang lama dalam kode C# yang dipanggil oleh plugin Java. Mesin Unity menggunakan mutex Non-Priority Inheritance untuk memastikan eksekusi yang benar.
libc.so NonPI::MutexLockWithTimeout(pthread_mutex_internal_t*, bool, timespec const*) + 604
com.unity3d.player.UnityPlayer.nativeUnitySendMessage (Native method)
com.unity3d.player.UnityPlayer.UnitySendMessage (UnityPlayer.java:665)
Gambar 4. ANR disebabkan oleh pertentangan kunci.
Penyebab
Masalahnya adalah ada beberapa pesan yang dikirim saat aplikasi dilanjutkan. Pesan dimasukkan ke dalam antrean karena tidak dapat dikirim saat game berada di latar belakang. Semua pesan dikirim secara bersamaan saat aplikasi dilanjutkan.
Selama periode jeda, biasanya Anda menyimpan informasi game di server. Misalnya, Anda merekam posisi pemain dalam game sehingga pemain dapat kembali ke tempat yang sama saat game dilanjutkan.
Workload ini, dikombinasikan dengan kode pihak ketiga lain yang membuat beban kerjanya sendiri, dapat membebani resource perangkat, terutama thread utama. Thread utama menjalankan antarmuka pengguna aplikasi dan sering kali merupakan lokasi utama ANR. Jadi, beban kerja tambahan di thread utama meningkatkan potensi ANR.
Solusi
Selama jeda aplikasi, pastikan semua tindakan kode diperlukan, atau coba simpan status pengguna di memori perangkat lokal Anda. Tentu saja, lihat apakah Anda juga dapat menyelesaikan tindakan ini di luar periode jeda.
Beberapa pendekatan:
- Pindahkan operasi C# yang menangani pesan ke thread
selain thread utama.
- Jika kode Anda tidak bergantung pada konteks thread utama Unity, gunakan
Task
untuk komunikasi, bukan pesan.
- Jika kode Anda tidak bergantung pada konteks thread utama Unity, gunakan
- Jangan kirim beberapa pesan dari plugin Anda saat game dijeda.
- Mesin game tidak dapat mengirim pesan saat game berjalan di latar belakang.
- Hanya kirimkan status data terakhir ke game Anda jika hal tersebut tidak memengaruhi fungsi game.
Perujuk Instal
Perujuk Instal Play adalah string unik yang dikirim ke Play Store setiap kali pengguna mengklik iklan. ID pelacakan iklan khusus Android. Setelah diinstal, aplikasi akan mengirimkan perujuk instal ke partner atribusi, yang mencocokkan sumber dengan penginstalan (mengatribusikan konversi).
Stack trace
Gambar 5 menunjukkan stack trace ANR dari game yang menggunakan Facebook SDK untuk mengambil atribusi penginstalan.
Penyebab
ANR disebabkan oleh panggilan binder yang lambat. Namun, akar masalahnya tidak dapat ditentukan tanpa akses ke kode sumber SDK.
Solusi
Memecahkan jenis masalah ini melibatkan komunikasi dengan developer SDK atau banyak penelusuran online untuk menemukan solusi potensial, memeriksa apakah versi SDK yang lebih baru menyelesaikan ANR untuk orang lain, atau bahkan bereksperimen dengan strategi peluncuran kecil.
Google menyediakan halaman SDK Index yang menggabungkan data penggunaan dari aplikasi Google Play dengan informasi yang dikumpulkan melalui deteksi kode untuk memberikan atribut dan sinyal yang dirancang untuk membantu Anda memutuskan apakah akan menggunakan, menyimpan, atau menghapus SDK dari aplikasi Anda.
Referensi tambahan
Untuk mempelajari ANR lebih lanjut, lihat referensi berikut: