ANR ทั่วไปสำหรับเกม Unity

ANR ของ Unity เกิดขึ้นด้วยเหตุผลหลายประการ ANR ที่พบบ่อยที่สุดเกิดจาก การใช้คอมโพเนนต์ Android และ Unity ในทางที่ผิด รวมถึงการสื่อสารที่ไม่ถูกต้อง

WebView

WebView คือคลาส Android ที่แสดงหน้าเว็บ บุคคลที่สาม SDK (เช่น โฆษณา) ใช้ WebView เพื่อแสดงเนื้อหาเว็บแบบไดนามิก ในกิจกรรมอื่นๆ นอกเหนือจาก UnityPlayerActivity ANR เกิดขึ้นเมื่อบุคคลที่สาม SDK ใช้ WebView ในทางที่ผิด

สแต็กเทรซ

สแต็กเทรซคือทรัพยากรแรกที่คุณใช้เพื่อทำความเข้าใจสาเหตุของ 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)

รูปที่ 1 สแต็กเทรซ ANR ที่เกิดจากการรอของ futex

สาเหตุ

ขณะนี้ยังไม่ทราบสาเหตุที่แท้จริงของปัญหานี้ สาเหตุที่เป็นไปได้บางอย่างอาจ รวมข้อมูลต่อไปนี้

  • การติดตั้งโฆษณาที่ไม่ดี
  • WebView เวอร์ชันเก่าเนื่องจากผู้ใช้อาจเลือกที่จะไม่อัปเดต แอปโดยอัตโนมัติ
  • มีการใช้ทรัพยากรระบบสูง (CPU, GPU ฯลฯ) ซึ่งอาจต้องใช้ทรัพยากรจำนวนมาก การสร้างโปรไฟล์
  • การคอมไพล์ Shader ขัดข้อง ซึ่งอาจชี้ให้เห็นว่า เนื้อหามีตัวปรับแสงเงาที่ใช้ร่วมกันไม่ได้ หรือผู้ใช้มี WebView แบบเก่า เวอร์ชันที่ติดตั้ง

โซลูชัน

  • หากต้องการจำกัดขอบเขตเนื้อหาที่ทําให้ WebView บล็อก เทรดหลัก เพิ่มบันทึกในเกม เมื่อมีการโหลดหน้าเว็บ แสดง หรือปิดไป
    • คุณสามารถใช้ Backtrace หรือ Crashlytics บริการรายงาน
    • จากนั้น เมื่อวิเคราะห์ข้อมูลและค้นหาปัญหาแล้ว ให้ลองปิดใช้ ผู้ให้บริการโฆษณาที่ไม่เหมาะสม
    • แนบบันทึกหน่วยความจำเพื่อให้แน่ใจว่าปัญหานั้นไม่เกี่ยวข้องกับหน่วยความจำ
  • แจ้งเตือนผู้ใช้ให้อัปเดต WebView จาก Google Play จาก Android 5.0 (API ระดับ 21) ขึ้นไป WebView ได้ย้ายไปยัง APK แล้ว ดังนั้นจึงอาจ และได้รับการอัปเดตแยกจากแพลตฟอร์ม Android หากต้องการดูเวอร์ชันของ WebView กำลังใช้งานอยู่บนอุปกรณ์ ให้ไปที่การตั้งค่า > แอป > ระบบ Android WebView และดูเวอร์ชันที่ด้านล่างของหน้า
หน้าจอข้อมูลแอปที่แสดงเวอร์ชัน WebView
รูปที่ 1 โปรดตรวจสอบเวอร์ชัน WebView

Unity หยุดชั่วคราว

เมื่อ UnityPlayerActivity ได้รับการโทร onPause() สายต่อไปนี้ เริ่มดำเนินการ:

  1. UnityPlayerActivity แจ้งเครื่องมือรันไทม์ของ Unity ว่ากิจกรรมดังกล่าว หยุดชั่วคราวแล้ว
  2. Unity เรียกใช้ MonoBehaviour ทุกรายการที่ติดตั้งใช้งาน OnApplicationPause กิจกรรม
  3. Unity จะหยุดคอมโพเนนต์และโมดูล เช่น การเล่นเสียง การแสดงภาพ Game Loop และภาพเคลื่อนไหว
  4. เพื่อให้ทั้ง Unity Android Player (UAP) และเครื่องมือค้นหา ซิงค์แล้ว UAP จะรอ 4 วินาทีเพื่อให้เครื่องยนต์หยุด
  5. หากการดำเนินการดังกล่าวใช้เวลานานกว่า 5 วินาที ระบบจะทริกเกอร์ ANR

สแต็กเทรซ

"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)

รูปที่ 3 ANR เกิดจากการเกิดสัญญาณที่ไม่ปล่อยว่าง

โซลูชัน

ตรวจสอบให้แน่ใจว่าโค้ดเกม C# ของคุณไม่ใช้เวลานานเกินไปในการดำเนินการให้เสร็จสิ้นระหว่าง หยุดชั่วคราวหรือดำเนินเหตุการณ์ต่อ

  • ทำโปรไฟล์เกมของคุณและดูว่า OnApplicationPause เป็นราคาแพงหรือไม่ คุณสามารถใช้Stopwatch
  • หลีกเลี่ยงการดำเนินการ I/O หรือคำขอเครือข่ายแบบซิงโครนัส
  • ย้ายการดำเนินการไปที่ Thread อื่นโดยใช้ Task Unity 2023.1 รองรับ โมเดลการเขียนโปรแกรมแบบไม่พร้อมกันโดยใช้ C# คีย์เวิร์ด async และ await รายการ

UnitySendMessage ถูกบล็อก

ปลั๊กอินและ SDK ของ Java Unity จะส่งข้อมูลไปยังเลเยอร์เกม C# โดยใช้ JNI แต่การสื่อสารนี้อาจบล็อกเทรดหลักเนื่องจากโฆษณาเนทีฟ กิจวัตรการซิงค์ข้อมูล เช่น Mutex ที่ทําให้เกิด ANR เนื่องจากการช่วงชิงล็อก

สแต็กเทรซ

ANR ในรูปที่ 4 เกิดจากการทำงานที่ยาวนานในรหัส C# ที่ถูกเรียกโดย ปลั๊กอิน Java เครื่องมือ Unity ใช้การรับค่าที่ไม่สำคัญ hidex เพื่อให้แน่ใจว่ามีการเรียกใช้อย่างถูกต้อง

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)

รูปที่ 4 ANR เกิดจากการช่วงชิงล็อก

สาเหตุ

ปัญหาคือมีการส่งข้อความหลายข้อความเมื่อแอปพลิเคชัน ทำงานต่อ ข้อความอยู่ในคิวเนื่องจากไม่สามารถส่งขณะเล่นเกมได้ อยู่ในเบื้องหลัง ข้อความทั้งหมดจะถูกจัดส่งพร้อมกันเมื่อ ที่กลับมาทำงานอีกครั้ง

ในระหว่างช่วงการหยุดชั่วคราว โดยทั่วไปคุณจะจัดเก็บข้อมูลของเกมบน เซิร์ฟเวอร์; ตัวอย่างเช่น คุณบันทึกตำแหน่งของผู้เล่นในเกมเพื่อให้ผู้เล่นบันทึก จะสามารถกลับมาอยู่ในตำแหน่งเดิมเมื่อเกมกลับมาเล่นต่อ

ภาระงานนี้รวมกับโค้ดของบุคคลที่สามอื่นๆ ที่สร้างภาระงานของตัวเอง ทำให้ทรัพยากรของอุปกรณ์มากเกินไป โดยเฉพาะเทรดหลัก องค์ประกอบหลัก เทรดเรียกใช้อินเทอร์เฟซผู้ใช้ของแอปและมักเป็นตำแหน่งหลักของ ANR ดังนั้น ภาระงานที่เพิ่มขึ้นในเทรดหลักจะเพิ่มโอกาสในการเกิด ANR

โซลูชัน

ในระหว่างที่หยุดแอปพลิเคชันชั่วคราว ให้ตรวจดูว่าการดำเนินการโค้ดทั้งหมดเป็นสิ่งจำเป็น หรือ ให้ลองบันทึกสถานะของผู้ใช้ในหน่วยความจำของอุปกรณ์ และแน่นอนว่าจะเห็น คุณสามารถดำเนินการเหล่านี้ให้เสร็จสมบูรณ์นอกระยะเวลาหยุดชั่วคราวได้หรือไม่

วิธีการมีดังนี้

  • ย้ายการดำเนินการ C# ที่จัดการข้อความไปยังชุดข้อความ นอกเหนือจากเทรดหลัก
    • หากโค้ดของคุณไม่ขึ้นอยู่กับบริบทเทรดหลักของ Unity ให้ใช้ Task สำหรับการสื่อสารแทนการส่งข้อความ
  • อย่าส่งหลายข้อความจากปลั๊กอินเมื่อเกมหยุดชั่วคราว
    • โปรแกรมไม่สามารถส่งข้อความในขณะที่เกมอยู่ในเบื้องหลัง
    • ส่งสถานะข้อมูลล่าสุดให้เกมเฉพาะเมื่อไม่ส่งผลต่อเกมเท่านั้น

ติดตั้งผู้อ้างอิง

URL สำหรับการติดตั้ง Play คือสตริงที่ไม่ซ้ำกันซึ่งส่งไปยัง Play Store เมื่อใดก็ตามที่ ผู้ใช้คลิกโฆษณา เป็นตัวระบุการติดตามโฆษณาเฉพาะของ Android ครั้งเดียว ติดตั้งแล้ว แอปจะส่ง URL ที่มาการติดตั้งไปยังพาร์ทเนอร์ระบุแหล่งที่มา จับคู่แหล่งที่มาที่มีการติดตั้ง (ที่ระบุแหล่งที่มาของ Conversion)

สแต็กเทรซ

รูปที่ 5 แสดงสแต็กเทรซ ANR จากเกมที่ใช้ Facebook SDK เพื่อ ดึงข้อมูลการระบุแหล่งที่มาของการติดตั้ง

วันที่
รูปที่ 5 รายงาน Android Vitals ที่มีการเรียกใช้ Binder

สาเหตุ

ANR เกิดจากการเรียกใช้ Binder ที่ช้า แต่สาเหตุที่แท้จริงไม่สามารถ ถูกกำหนดโดยไม่มีการเข้าถึงซอร์สโค้ด SDK

โซลูชัน

การแก้ไขปัญหาประเภทนี้ต้องสื่อสารกับนักพัฒนาซอฟต์แวร์ SDK หรือ ทางออนไลน์ได้มากมาย เพื่อหาทางแก้ไข การตรวจสอบว่าไซต์ ของ SDK แก้ไข ANR สำหรับผู้อื่น หรือแม้แต่ทดสอบกับ กลยุทธ์การเปิดตัว

Google มีหน้าดัชนี SDK ที่รวมข้อมูลการใช้งาน จากแอป Google Play ที่มีข้อมูลที่รวบรวมผ่านการตรวจหาโค้ดไปยัง ระบุแอตทริบิวต์และสัญญาณที่ออกแบบมาเพื่อช่วยคุณตัดสินใจว่าจะนำไปใช้หรือไม่ เก็บหรือนำ SDK ออกจากแอป

แหล่งข้อมูลเพิ่มเติม

หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับ ANR โปรดดูแหล่งข้อมูลต่อไปนี้