ANR Unity terjadi karena berbagai alasan. ANR yang paling umum disebabkan oleh penyalahgunaan komponen Android dan Unity dan miskomunikasinya.
WebView
WebView
adalah class Android yang menampilkan halaman web. Pihak ketiga
SDK (seperti iklan) menggunakan WebView
untuk menampilkan konten web dinamis
dalam aktivitas selain UnityPlayerActivity
. ANR terjadi saat pihak ketiga
SDK menyalahgunakan WebView
.
Pelacakan tumpukan
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 penyebab dapat termasuk:
- Penerapan iklan yang buruk.
- Versi
WebView
sudah tidak berlaku karena pengguna mungkin memilih untuk tidak mengupdate aplikasi secara otomatis. - Penggunaan resource sistem (CPU, GPU, dll. yang tinggi), yang mungkin memerlukan banyak pembuatan profil Anda.
- Kompilasi shader mengalami error, yang dapat menunjukkan bahwa
konten memiliki shader yang tidak kompatibel atau pengguna memiliki
WebView
lama versi yang diinstal.
Solusi
- Untuk mempersempit jenis konten yang menyebabkan
WebView
memblokir thread utama, menambahkan log ke game Anda setiap kali halaman web dimuat, ditampilkan, atau tertutup.- Anda dapat menggunakan Backtrace atau Crashlytics layanan pelaporan.
- Kemudian, setelah menganalisis data dan menemukan masalah, coba nonaktifkan penyedia iklan yang melakukan pelanggaran.
- Sertakan log memori untuk memastikan masalah tidak terkait dengan memori.
- Beri tahu pengguna untuk mengupdate
WebView
dari Google Play. Dari Android 5.0 (API level 21) dan yang lebih tinggi,WebView
telah dipindahkan ke APK. Oleh karena itu, dapat diupdate secara terpisah dari platform Android. Untuk melihat versiWebView
sedang digunakan di perangkat, buka Setelan > Aplikasi > Sistem Android WebView, lalu lihat versi di bagian bawah halaman.
Jeda Unity
Saat UnityPlayerActivity
menerima panggilan onPause()
, rantai 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 telusur sudah disinkronkan, UAP menunggu selama 4 detik hingga mesin berhenti. - Jika operasi tersebut memerlukan waktu lebih dari 5 detik, sistem akan memicu ANR.
Pelacakan tumpukan
"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 memakan waktu terlalu lama untuk menyelesaikan eksekusi selama menjeda atau melanjutkan peristiwa.
- Buat profil game Anda dan periksa apakah
OnApplicationPause
mahal operasi. Anda dapat menggunakanStopwatch
. - Hindari operasi I/O atau permintaan jaringan sinkron.
- Pindahkan operasi ke
Thread
lain menggunakanTask
Unity 2023.1 mendukung versi baru model pemrograman asinkron menggunakan C# Kata kunciasync
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 seperti mutex, yang menyebabkan ANR karena pertentangan kunci.
Pelacakan tumpukan
ANR pada gambar 4 disebabkan oleh operasi yang lama dalam kode C# yang dipanggil oleh Plugin Java. Mesin Unity menggunakan Non-Priority Inheritance mutex 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 beberapa pesan dikirim saat aplikasi akan dilanjutkan. Pesan dimasukkan ke dalam antrean karena tidak dapat dikirim saat game berjalan di latar belakang. Semua pesan dikirim bersamaan ketika aplikasi dilanjutkan.
Selama periode jeda, biasanya Anda menyimpan informasi game di server; misalnya, Anda merekam posisi pemain dalam game sehingga pemain tersebut dapat kembali ke tempat yang sama saat game dilanjutkan.
Workload ini, digabungkan dengan kode pihak ketiga lain yang menciptakan workload sendiri, dapat membebani sumber daya perangkat, terutama thread utama. Utama thread menjalankan antarmuka pengguna aplikasi dan sering kali merupakan lokasi utama ANR. Jadi, setiap 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 tersebut di luar periode jeda.
Beberapa pendekatan:
- Memindahkan 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 kirim status data terakhir ke game Anda jika hal ini tidak memengaruhi game Anda fungsionalitasnya.
Perujuk Instal
Perujuk Instal Play adalah string unik yang dikirim ke Play Store setiap kali pengguna mengklik iklan. ID pelacakan iklan khusus Android. Satu kali diinstal, aplikasi akan mengirimkan perujuk instal ke partner atribusi, yang mencocokkan sumber dengan penginstalan (mengatribusikan konversi).
Pelacakan tumpukan
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 penyebab tidak dapat ditentukan tanpa akses ke kode sumber SDK.
Solusi
Pemecahan jenis masalah ini melibatkan komunikasi dengan developer SDK atau melakukan pencarian {i>online<i} untuk menemukan solusi yang mungkin dilakukan, memeriksa apakah ada versi SDK ini memecahkan ANR untuk orang lain, atau bahkan bereksperimen dengan strategi peluncuran.
Google menyediakan halaman SDK Index yang menggabungkan data penggunaan dari aplikasi Google Play dengan informasi yang dikumpulkan melalui deteksi kode hingga menyediakan atribut dan sinyal yang dirancang untuk membantu Anda memutuskan apakah akan mengadopsi, menyimpan, atau menghapus SDK dari aplikasi Anda.
Referensi lainnya
Untuk mempelajari ANR lebih lanjut, lihat referensi berikut: