วินิจฉัยและแก้ไข ANR

เมื่อเธรด UI ของแอป Android ถูกบล็อกนานเกินไป ระบบจะส่งข้อผิดพลาด "แอปพลิเคชันไม่ตอบสนอง" (ANR) หน้านี้จะอธิบาย ANR ประเภทต่างๆ วิธีวินิจฉัย และคำแนะนำในการแก้ไข ช่วงเวลาหมดเวลาเริ่มต้นทั้งหมดที่ระบุไว้มีไว้สำหรับอุปกรณ์ AOSP และ Pixel โดยเวลาเหล่านี้อาจแตกต่างกันไปตาม OEM

โปรดทราบว่าเมื่อพิจารณาสาเหตุของ ANR การแยกแยะปัญหาระหว่างระบบและแอปจะเป็นประโยชน์

เมื่อระบบอยู่ในสถานะที่ไม่ดี ปัญหาต่อไปนี้อาจทำให้เกิด ANR

  • ปัญหาชั่วคราวในเซิร์ฟเวอร์ของระบบมักทำให้การเรียก Binder ที่รวดเร็วช้าลง
  • ปัญหาเกี่ยวกับเซิร์ฟเวอร์ของระบบและโหลดของอุปกรณ์สูงทำให้ไม่สามารถกำหนดเวลาเธรดของแอปได้

หากมีให้ใช้งาน วิธีที่ดีในการแยกความแตกต่างระหว่างปัญหาของระบบและแอปคือ การใช้การติดตาม Perfetto

  • ดูว่ามีการกำหนดเวลาเธรดหลักของแอปหรือไม่โดยดูที่สถานะเธรด ใน Perfetto เพื่อดูว่าเธรดกำลังทำงานหรือพร้อมทำงาน
  • ดูsystem_serverเธรดเพื่อดูปัญหาต่างๆ เช่น การแย่งชิงล็อก
  • สำหรับการเรียก Binder ที่ช้า ให้ดูที่เธรดการตอบกลับ (หากมี) เพื่อดูว่าทำไมจึงช้า

การหมดเวลาการส่งอินพุต

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

ระยะหมดเวลาเริ่มต้น: 5 วินาที

โดยปกติแล้ว ANR การส่งอินพุตเกิดจากปัญหาในเทรดหลัก หากเทรดหลักถูกบล็อกโดยรอรับล็อก เทรดที่ถือล็อกก็อาจเกี่ยวข้องด้วย

หากต้องการหลีกเลี่ยง ANR ของการส่งอินพุต ให้ทำตามแนวทางปฏิบัติแนะนำต่อไปนี้

  • อย่าดำเนินการที่บล็อกหรือใช้เวลานานในเทรดหลัก พิจารณาใช้ StrictMode เพื่อตรวจหากิจกรรมที่เกิดขึ้นโดยไม่ตั้งใจในเทรดหลัก
  • ลดการแย่งชิงล็อกระหว่างเทรดหลักกับเทรดอื่นๆ
  • ลดงานที่ไม่ใช่ UI ในเทรดหลัก เช่น เมื่อจัดการการออกอากาศหรือเรียกใช้บริการ

สาเหตุที่พบบ่อย

สาเหตุที่พบบ่อยและวิธีแก้ไข ANR ในการส่งอินพุตมีดังนี้

สาเหตุ สิ่งที่เกิดขึ้น การแก้ไขที่แนะนำ
การเรียกใช้ Binder ที่ช้า เทรดหลักทำการเรียกใช้ Binder แบบซิงโครนัสที่ใช้เวลานาน ย้ายการเรียกออกจากเทรดหลักหรือลองเพิ่มประสิทธิภาพการเรียก หากคุณเป็นเจ้าของ API
การเรียก Binder ติดต่อกันหลายครั้ง เทรดหลักทำการเรียกใช้ Binder แบบซิงโครนัสหลายครั้งติดต่อกัน อย่าเรียกใช้ Binder ในลูปที่แน่น
การบล็อก I/O เทรดหลักทำการเรียก I/O ที่บล็อก เช่น ฐานข้อมูลหรือเครือข่าย การเข้าถึง ย้าย IO ที่บล็อกทั้งหมดออกจากเทรดหลัก
การช่วงชิงล็อก เทรดหลักถูกบล็อกเนื่องจากรอรับล็อก ลดการแย่งล็อกระหว่างเทรดหลักกับเทรดอื่นๆ เพิ่มประสิทธิภาพโค้ดที่ทำงานช้าในเธรดอื่น
เฟรมที่มีค่าใช้จ่ายสูง การแสดงผลมากเกินไปในเฟรมเดียว ซึ่งทำให้เกิดการกระตุกอย่างรุนแรง ลดการทำงานในการแสดงผลเฟรม อย่าใช้อัลกอริทึม n2 ใช้ คอมโพเนนต์ที่มีประสิทธิภาพสำหรับสิ่งต่างๆ เช่น การเลื่อนหรือการแบ่งหน้า เช่น Jetpack ไลบรารี Paging
ถูกบล็อกโดยคอมโพเนนต์อื่น คอมโพเนนต์อื่น เช่น Broadcast Receiver กำลังทำงานและ บล็อกเทรดหลัก ย้ายงานที่ไม่ใช่ UI ออกจากเทรดหลักให้มากที่สุด เรียกใช้ตัวรับสัญญาณ การออกอากาศในเธรดอื่น
GPU ค้าง การแฮงก์ของ GPU เป็นปัญหาระบบหรือฮาร์ดแวร์ที่ทำให้ การแสดงผลถูกบล็อกและทำให้เกิด ANR ในการส่งอินพุต แต่โดยปกติแล้วจะไม่มีการแก้ไขในฝั่งแอป หากเป็นไปได้ โปรดติดต่อทีมฮาร์ดแวร์เพื่อแก้ปัญหา

วิธีแก้ไขข้อบกพร่อง

เริ่มแก้ไขข้อบกพร่องโดยดูที่ลายเซ็นคลัสเตอร์ ANR ใน Google Play Console หรือ Firebase Crashlytics โดยปกติแล้วคลัสเตอร์จะมีเฟรมบนสุดที่น่าสงสัยว่าทำให้เกิด ANR

โฟลว์ชาร์ตต่อไปนี้แสดงวิธีระบุสาเหตุของ ANR ที่เกิดจากการหมดเวลาอินพุต การเรียกใช้

รูปที่ 1 วิธีแก้ไขข้อบกพร่องของ ANR ที่เกิดจากการส่งอินพุต

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

รูปที่ 2 การตรวจหา ANR ของ Play Vitals

ไม่มีหน้าต่างที่โฟกัส

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

ระยะหมดเวลาเริ่มต้น: 5 วินาที

สาเหตุที่พบบ่อย

โดยปกติแล้ว ANR ที่ไม่มีหน้าต่างที่โฟกัสเกิดจากปัญหาใดปัญหาหนึ่งต่อไปนี้

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

Kotlin

override fun onCreate(savedInstanceState: Bundle) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_main)
  window.addFlags(WindowManager.LayoutParams.FLAG_FLAG_NOT_FOCUSABLE)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
}

หมดเวลาของ Broadcast Receiver

ANR ของ Broadcast Receiver จะเกิดขึ้นเมื่อ Broadcast Receiver ไม่จัดการ การออกอากาศได้ทันเวลา สำหรับผู้รับแบบซิงโครนัสหรือผู้รับที่ไม่เรียกใช้ goAsync() การหมดเวลาหมายความว่า onReceive() ไม่เสร็จสมบูรณ์ภายในเวลาที่กำหนด สำหรับผู้รับแบบไม่พร้อมกันหรือผู้รับที่เรียกใช้ goAsync() การหมดเวลาหมายความว่า ไม่ได้เรียกใช้ PendingResult.finish() ตามเวลาที่กำหนด

ANR ของ Broadcast Receiver มักเกิดขึ้นในเทรดต่อไปนี้

  • เทรดหลัก หากปัญหาคือการเริ่มต้นแอปช้า
  • เธรดที่เรียกใช้ Broadcast Receiver หากปัญหาเกิดจากonReceive()โค้ดที่ทำงานช้า
  • Broadcast worker threads หากปัญหาคือโค้ดการออกอากาศ goAsync() ช้า

หากต้องการหลีกเลี่ยง ANR ของ Broadcast Receiver ให้ทําตามแนวทางปฏิบัติแนะนําต่อไปนี้

  • ตรวจสอบว่าการเริ่มต้นแอปเป็นไปอย่างรวดเร็ว เนื่องจากระบบจะนับรวมการเริ่มต้นแอปในระยะหมดเวลา ANR หากมีการเริ่มแอปเพื่อจัดการการออกอากาศ
  • หากใช้ goAsync() ให้ตรวจสอบว่าได้เรียกใช้ PendingResult.finish() อย่างรวดเร็ว ซึ่งจะขึ้นอยู่กับระยะหมดเวลา ANR เดียวกันกับเครื่องรับการออกอากาศแบบซิงโครนัส
  • หากใช้ goAsync() ให้ตรวจสอบว่าไม่ได้แชร์เทรดผู้ปฏิบัติงานกับ การดำเนินการที่ใช้เวลานานหรือการดำเนินการที่บล็อกอื่นๆ
  • ลองใช้ registerReceiver() เพื่อเรียกใช้ BroadcastReceiver ใน เทรดที่ไม่ใช่เทรดหลัก เพื่อหลีกเลี่ยงการบล็อกโค้ด UI ที่ทํางานในเทรดหลัก

ระยะหมดเวลา

ระยะหมดเวลาในการรับการออกอากาศจะขึ้นอยู่กับว่ามีการตั้งค่าแฟล็กเจตนาเบื้องหน้า หรือไม่ และขึ้นอยู่กับเวอร์ชันของแพลตฟอร์ม

ประเภท Intent Android 13 และต่ำกว่า Android 14 ขึ้นไป

Intent ที่มีลำดับความสำคัญเบื้องหน้า

(FLAG_RECEIVER_FOREGROUND ชุด)

10 วินาที

10-20 วินาที ขึ้นอยู่กับว่ากระบวนการนี้ใช้ CPU มากเกินไปหรือไม่

Intent ที่มีลำดับความสำคัญในเบื้องหลัง

(ไม่ได้ตั้งค่า FLAG_RECEIVER_FOREGROUND)

60 วินาที

60-120 วินาที ขึ้นอยู่กับว่ากระบวนการขาดแคลน CPU หรือไม่

หากต้องการดูว่ามีการตั้งค่าแฟล็ก FLAG_RECEIVER_FOREGROUND หรือไม่ ให้มองหา "flg=" ใน หัวเรื่อง ANR และตรวจสอบว่ามี 0x10000000 หรือไม่ หากตั้งค่าบิตนี้ แสดงว่า Intent มีการตั้งค่า FLAG_RECEIVER_FOREGROUND และไทม์เอาต์จึงสั้นลง

ตัวอย่างเรื่อง ANR ที่มีระยะหมดเวลาในการออกอากาศสั้น (10-20 วินาที)

Broadcast of Intent { act=android.inent.action.SCREEN_ON flg=0x50200010 }

ตัวอย่างเรื่อง ANR ที่มีระยะหมดเวลาในการออกอากาศนาน (60-120 วินาที)

Broadcast of Intent { act=android.intent.action.TIME_SET flg=0x25200010 }

วิธีวัดเวลาออกอากาศ

การวัดระยะเวลาการออกอากาศจะเริ่มขึ้นเมื่อมีการส่งการออกอากาศจาก system_server ไปยังแอป และสิ้นสุดเมื่อแอปประมวลผลการออกอากาศ เสร็จสิ้น หากกระบวนการของแอปยังไม่ได้ทำงาน ก็จะต้องเริ่มแบบเย็นภายในระยะหมดเวลา ANR ด้วย ดังนั้น การเริ่มต้นแอปที่ช้าอาจทำให้เกิด ANR ของ Broadcast Receiver

รูปภาพต่อไปนี้แสดงไทม์ไลน์ ANR ของ Broadcast Receiver ที่สอดคล้องกับ กระบวนการของแอปบางอย่าง

รูปที่ 3 ไทม์ไลน์ ANR ของ Broadcast Receiver

การวัดระยะหมดเวลาของ ANR จะสิ้นสุดเมื่อตัวรับสัญญาณประมวลผลการออกอากาศเสร็จสิ้น ซึ่งเวลาที่แน่นอนจะขึ้นอยู่กับว่าตัวรับสัญญาณเป็นแบบซิงโครนัสหรือแบบอะซิงโครนัส

  • สำหรับผู้รับแบบซิงโครนัส การวัดจะหยุดเมื่อ onReceive() แสดงผล
  • สำหรับผู้รับแบบไม่พร้อมกัน การวัดจะหยุดเมื่อมีการเรียกใช้ PendingResult.finish()
รูปที่ 4 ปลายทางการวัดการหมดเวลาของ ANR สำหรับตัวรับแบบซิงโครนัส และอะซิงโครนัส

สาเหตุที่พบบ่อย

สาเหตุที่พบบ่อยและวิธีแก้ไข ANR ของ Broadcast Receiver มีดังนี้

สาเหตุ ใช้กับ สิ่งที่เกิดขึ้น การแก้ไขที่แนะนํา
การเริ่มต้นแอปช้า ผู้รับทั้งหมด แอปใช้เวลาในการทำ Cold Start นานเกินไป เพิ่มประสิทธิภาพการเริ่มต้นแอปที่ช้า
ไม่ได้กำหนดเวลา onReceive() ผู้รับทั้งหมด เธรด Broadcast Receiver กำลังทำงานอื่นอยู่และไม่สามารถ เริ่มเมธอด onReceive() ได้ อย่าเรียกใช้ งานที่ใช้เวลานานในเธรดตัวรับ (หรือย้ายตัวรับไปยังเธรดเฉพาะ )
onReceive() ทำงานช้า ตัวรับทั้งหมด แต่ส่วนใหญ่เป็นตัวรับแบบ ซิงโครนัส onReceive() เริ่มวิธีการแล้ว แต่ ถูกบล็อกหรือช้า จึงไม่เสร็จตามเวลา เพิ่มประสิทธิภาพโค้ดตัวรับสัญญาณที่ช้า
ไม่ได้กำหนดเวลางานตัวรับที่ไม่พร้อมกัน goAsync() ผู้รับ onReceive() วิธีพยายามดำเนินการ ในพูลเทรดผู้ปฏิบัติงานที่ถูกบล็อก งานจึงไม่เคยเริ่มต้น เพิ่มประสิทธิภาพการเรียกที่ช้าหรือบล็อก หรือใช้เธรดที่แตกต่างกันสำหรับ Broadcast Worker กับงานอื่นๆ ที่ใช้เวลานาน
Worker ทำงานช้าหรือถูกบล็อก ผู้รับ goAsync() คน มีการบล็อกหรือการดำเนินการที่ช้าในที่ใดที่หนึ่งในพูลของเทรดผู้ปฏิบัติงานขณะประมวลผลการออกอากาศ ดังนั้น PendingResult.finish จึงไม่ได้รับการเรียกใช้ตามเวลาที่กำหนด เพิ่มประสิทธิภาพโค้ดของasyncตัวรับสัญญาณที่ช้า
ลืมโทรหา PendingResult.finish ผู้รับ goAsync() คน ไม่มีการเรียกไปยัง finish() ในเส้นทางโค้ด ตรวจสอบว่ามีการเรียกใช้ finish() เสมอ

วิธีแก้ไขข้อบกพร่อง

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

แผนผังต่อไปนี้แสดงวิธีระบุสาเหตุของ ANR ของ BroadcastReceiver

รูปที่ 5 วิธีแก้ไขข้อบกพร่องของ ANR ของ Broadcast Receiver

ค้นหารหัสตัวรับสัญญาณ

Google Play Console จะแสดงคลาสตัวรับและ Intent การออกอากาศในลายเซ็น ANR มองหาสิ่งต่อไปนี้

  • cmp=<receiver class>
  • act=<broadcast_intent>

ตัวอย่างลายเซ็น ANR ของ Broadcast Receiver มีดังนี้

com.example.app.MyClass.myMethod
Broadcast of Intent { act=android.accounts.LOGIN_ACCOUNTS_CHANGED
cmp=com.example.app/com.example.app.MyAccountReceiver }

ค้นหาเธรดที่เรียกใช้เมธอด onReceive()

หากคุณใช้ Context.registerReceiver เพื่อระบุตัวแฮนเดิลที่กำหนดเอง จะเป็นเทรดที่เรียกใช้ตัวแฮนเดิลนี้ มิเช่นนั้นจะเป็นเธรดหลัก

ตัวอย่าง: งานตัวรับสัญญาณแบบไม่พร้อมกันที่ไม่ได้กำหนดเวลา

ส่วนนี้จะอธิบายตัวอย่างวิธีแก้ไขข้อบกพร่องของ ANR ของ Broadcast Receiver

สมมติว่าลายเซ็น ANR มีลักษณะดังนี้

com.example.app.MyClass.myMethod
Broadcast of Intent {
act=android.accounts.LOG_ACCOUNTS_CHANGED cmp=com.example.app/com.example.app.MyReceiver }

จากลายเซ็น ดูเหมือนว่า Intent การออกอากาศคือ android.accounts.LOG_ACCOUNTS_CHANGED และคลาสตัวรับคือ com.example.app.MyReceiver

จากโค้ดตัวรับ คุณจะเห็นว่า Thread Pool "BG Thread [0,1,2,3]" ทำงานหลักในการประมวลผลการออกอากาศนี้ เมื่อดู Stack Dumps คุณจะเห็นว่าเธรดพื้นหลัง (BG) ทั้ง 4 รายการมีรูปแบบเดียวกัน คือเรียกใช้การเรียกที่บล็อก getDataSync เนื่องจากเธรด BG ทั้งหมดทำงานอยู่ ระบบจึงประมวลผล การออกอากาศไม่ทันเวลา ซึ่งทำให้เกิด ANR

BG Thread #0 (tid=26) Waiting

at jdk.internal.misc.Unsafe.park(Native method:0)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:211)
at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture:563)
at com.google.common.util.concurrent.ForwardingFuture.get(ForwardingFuture:68)
at com.example.app.getDataSync(<MyClass>:152)

...

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at com.google.android.libraries.concurrent.AndroidExecutorsModule.lambda$withStrictMode$5(AndroidExecutorsModule:451)
at com.google.android.libraries.concurrent.AndroidExecutorsModule$$ExternalSyntheticLambda8.run(AndroidExecutorsModule:1)
at java.lang.Thread.run(Thread.java:1012)
at com.google.android.libraries.concurrent.ManagedPriorityThread.run(ManagedPriorityThread:34)

There are several approaches to fix the issue:

  • Find out why getDataSync is slow and optimize.
  • Don't run getDataSync on all four BG threads.
  • More generally, ensure that the BG thread pool isn't saturated with long-running operations.
  • Use a dedicated thread pool for goAsync worker tasks.
  • Use an unbounded thread pool instead of the bounded BG thread pool

Example: slow app startup

A slow app startup can cause several types of ANRs, especially broadcast receiver and execute service ANRs. The cause of an ANR is likely slow app startup if you see ActivityThread.handleBindApplication in the main thread stacks.

Execute service timeout

An execute service ANR happens when the app's main thread doesn't start a service in time. Specifically, a service doesn't finish executing onCreate() and onStartCommand() or onBind() within the timeout period.

Default timeout period: 20 seconds for foreground service; 200 seconds for background service. The ANR timeout period includes the app cold start, if necessary, and calls to onCreate(), onBind(), or onStartCommand().

To avoid execute service ANRs, follow these general best practices:

  • Make sure that app startup is fast, since it's counted in the ANR timeout if the app is started to run the service component.
  • Make sure that the service's onCreate(), onStartCommand(), and onBind() methods are fast.
  • Avoid running any slow or blocking operations on the main thread from other components; these operations can prevent a service from starting quickly.

Common causes

The following table lists common causes of execute service ANRs and suggested fixes.

Cause What Suggested fix
Slow app startup The app takes too long to perform a cold start. Optimize slow app start.
Slow onCreate(), onStartCommand(), or onBind() The service component's onCreate(), onStartCommand(), or onBind() method takes too long to execute on the main thread. Optimize slow code. Move slow operations off the critical path where possible.
Not scheduled (main thread blocked before onStart()) The app's main thread is blocked by another component before the service can be started. Move other component's work off the main thread. Optimize other component's blocking code.

How to debug

From the cluster signature and ANR report in Google Play Console or Firebase Crashlytics, you can often determine the cause of the ANR based on what the main thread is doing.

The following flow chart describes how to debug an execute service ANR.

Figure 6. How to debug an execute service ANR.

If you've determined that the execute service ANR is actionable, follow these steps to help resolve the issue:

  1. Find the service component class in the ANR signature. In Google Play Console, the service component class is shown in the ANR signature. In the following example ANR details, it's com.example.app/MyService.

    com.google.common.util.concurrent.Uninterruptibles.awaitUninterruptibly
    Executing service com.example.app/com.example.app.MyService
    
  2. Determine whether the slow or block operation is part of app startup, the service component, or elsewhere by checking for the following important function call(s) in the main threads.

    Function call(s) in main thread stacks What it means
    android.app.ActivityThread.handleBindApplication App was starting up, so the ANR was caused by slow app start.

    <ServiceClass>.onCreate()

    [...]

    android.app.ActivityThread.handleCreateService

    Service was being created, so the ANR was likely caused by slow onCreate() code.

    <ServiceClass>.onBind()

    [...]

    android.app.ActivityThread.handleBindService

    Service was being bound, so the ANR was likely caused by slow onBind() code.

    <ServiceClass>.onStartCommand()

    [...]

    android.app.ActivityThread.handleServiceArgs

    Service was being started, so the ANR was likely caused by slow onStartCommand() code.

    For example, if the onStartCommand() method in the MyService class is slow, the main threads will look like this:

    at com.example.app.MyService.onStartCommand(FooService.java:25)
    at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4820)
    at android.app.ActivityThread.-$$Nest$mhandleServiceArgs(unavailable:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2289)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loopOnce(Looper.java:205)
    at android.os.Looper.loop(Looper.java:294)
    at android.app.ActivityThread.main(ActivityThread.java:8176)
    at java.lang.reflect.Method.invoke(Native method:0)
    

    หากไม่เห็นการเรียกใช้ฟังก์ชันที่สำคัญใดๆ อาจเป็นไปได้ว่า

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

  4. ดูข้อมูลเพิ่มเติมเกี่ยวกับบริการได้ที่หน้าต่อไปนี้

    ผู้ให้บริการเนื้อหาไม่ตอบสนอง

    ANR ของผู้ให้บริการเนื้อหาจะเกิดขึ้นเมื่อผู้ให้บริการเนื้อหาระยะไกลใช้เวลานานกว่า ระยะหมดเวลาในการตอบคำค้นหาและถูกปิด

    ระยะหมดเวลาเริ่มต้น: ผู้ให้บริการเนื้อหาเป็นผู้ระบุโดยใช้ ContentProviderClient.setDetectNotResponding ระยะหมดเวลาของ ANR รวมถึงเวลาทั้งหมดที่ใช้ในการเรียกใช้การค้นหาผู้ให้บริการเนื้อหาระยะไกล ซึ่ง รวมถึงการเริ่มแอปจากระยะไกลแบบเย็นหากแอปยังไม่ได้ทำงาน

    หากต้องการหลีกเลี่ยง ANR ของผู้ให้บริการเนื้อหา ให้ทำตามแนวทางปฏิบัติแนะนำต่อไปนี้

    • ตรวจสอบว่าการเริ่มต้นแอปนั้นรวดเร็ว เนื่องจากระบบจะนับรวมการเริ่มต้นแอปในระยะหมดเวลาของ ANR หากมีการเริ่มแอปเพื่อเรียกใช้ Content Provider
    • ตรวจสอบว่าการค้นหาของผู้ให้บริการเนื้อหานั้นรวดเร็ว
    • อย่าทำการเรียกใช้ Binder ที่บล็อกพร้อมกันจำนวนมากซึ่งอาจบล็อกเธรด Binder ทั้งหมดของแอป

    สาเหตุที่พบบ่อย

    ตารางต่อไปนี้แสดงสาเหตุที่พบบ่อยของ ANR ของผู้ให้บริการเนื้อหาและวิธีแก้ไขที่แนะนำ

    สาเหตุ สิ่งที่เกิดขึ้น สัญญาณ การแก้ไขที่แนะนํา
    การค้นหาผู้ให้บริการเนื้อหาที่ช้า ผู้ให้บริการเนื้อหาใช้เวลานานเกินไปในการดำเนินการหรือถูกบล็อก เฟรม android.content.ContentProvider$Transport.query อยู่ในเธรดของ Binder เพิ่มประสิทธิภาพการค้นหาผู้ให้บริการเนื้อหา ค้นหาว่ามีอะไรบล็อกเธรดของ Binder อยู่
    การเริ่มต้นแอปช้า แอปของผู้ให้บริการเนื้อหาใช้เวลานานเกินไปในการเริ่มต้น เฟรม ActivityThread.handleBindApplication อยู่ใน เทรดหลัก เพิ่มประสิทธิภาพการเริ่มต้นแอป
    Binder thread exhaustion - Binder thread ทั้งหมดไม่ว่าง เธรด Binder ทั้งหมดกำลังประมวลผลคำขอแบบซิงโครนัสอื่นๆ อยู่ จึงไม่สามารถเรียกใช้การเรียก Binder ของ Content Provider ได้ แอปไม่เริ่มทำงาน เธรด Binder ทั้งหมดไม่ว่าง และ Content Provider ไม่ทำงาน ลดภาระของเธรด Binder กล่าวคือ ลดการเรียก Binder แบบซิงโครนัสขาออก หรือทำงานน้อยลงเมื่อจัดการการเรียกเข้า

    วิธีแก้ไขข้อบกพร่อง

    หากต้องการแก้ไขข้อบกพร่องของ ANR ของ Content Provider โดยใช้ลายเซ็นคลัสเตอร์และรายงาน ANR ใน Google Play Console หรือ Firebase Crashlytics ให้ดูว่าเทรดหลักและ เทรด Binder กำลังทำอะไรอยู่

    โฟลว์ชาร์ตต่อไปนี้อธิบายวิธีแก้ไขข้อบกพร่องของ ANR ของผู้ให้บริการเนื้อหา

    รูปที่ 7 วิธีแก้ไขข้อบกพร่องของ ANR ของผู้ให้บริการเนื้อหา

    ข้อมูลโค้ดต่อไปนี้แสดงลักษณะของเธรด Binder เมื่อถูกบล็อกเนื่องจากการค้นหา Content Provider ช้า ในกรณีนี้ ผู้ให้บริการเนื้อหา จะรอการล็อกเมื่อเปิดฐานข้อมูล

    binder:11300_2 (tid=13) Blocked
    
    Waiting for osm (0x01ab5df9) held by at com.google.common.base.Suppliers$NonSerializableMemoizingSupplier.get(Suppliers:182)
    at com.example.app.MyClass.blockingGetOpenDatabase(FooClass:171)
    [...]
    at com.example.app.MyContentProvider.query(MyContentProvider.java:915)
    at android.content.ContentProvider$Transport.query(ContentProvider.java:292)
    at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:107)
    at android.os.Binder.execTransactInternal(Binder.java:1339)
    at android.os.Binder.execTransact(Binder.java:1275)
    

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

    main (tid=1) Blocked
    
    [...]
    at dagger.internal.DoubleCheck.get(DoubleCheck:51)
    - locked 0x0e33cd2c (a qsn)at dagger.internal.SetFactory.get(SetFactory:126)
    at com.myapp.Bar_Factory.get(Bar_Factory:38)
    [...]
    at com.example.app.MyApplication.onCreate(DocsApplication:203)
    at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1316)
    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6991)
    at android.app.ActivityThread.-$$Nest$mhandleBindApplication(unavailable:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2235)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loopOnce(Looper.java:205)
    at android.os.Looper.loop(Looper.java:294)
    at android.app.ActivityThread.main(ActivityThread.java:8170)
    at java.lang.reflect.Method.invoke(Native method:0)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
    

    การตอบสนองงานช้า

    ANR การตอบกลับงานที่ช้าเกิดขึ้นเมื่อแอปใช้เวลานานเกินไปในการตอบกลับ JobService.onStartJob() หรือ JobService.onStopJob() หรือใช้เวลานานเกินไปในการ แสดงการแจ้งเตือนโดยใช้ JobService.setNotification() ซึ่งแสดงว่าเทรดหลักของแอปถูกบล็อกเนื่องจากกำลังทำอย่างอื่น

    หากเป็นปัญหาเกี่ยวกับ JobService.onStartJob() หรือ JobService.onStopJob() ให้ตรวจสอบสิ่งที่เกิดขึ้นในเทรดหลัก หากเป็นปัญหาเกี่ยวกับ JobService.setNotification() โปรดโทรหาโดยเร็วที่สุด อย่าทำงานมากเกินไปก่อนที่จะแสดงการแจ้งเตือน

    ดูการละเมิดการแยกชุดข้อความ

    ลองใช้วิธีแบบ Compose
    Jetpack Compose เป็นชุดเครื่องมือ UI ที่แนะนำสำหรับ Android

    หากแอปแก้ไขมุมมองในเธรดเบื้องหลัง อาจทำให้เกิดสภาวะแข่งขันในสถานะภายในของลำดับชั้นของมุมมอง การละเมิดนี้อาจบล็อกไม่ให้ เธรดหลัก (UI) ดำเนินการข้อความแบบซิงโครนัสใดๆ ซึ่งจะทำให้เกิดปัญหาด้านความเสถียรที่ร้ายแรง

    • UI ค้างโดยไม่มีข้อความแจ้ง: UI ของแอปหยุดตอบสนองต่อข้อมูลจากผู้ใช้
    • การขัดข้อง: แอปอาจขัดข้องพร้อมกับ illegalStateException
    • ANR: ระบบอาจทริกเกอร์การหมดเวลาของ ANR

    การละเมิดการใช้เทรดนี้เป็นสาเหตุหลักอย่างหนึ่งที่อยู่เบื้องหลังสแต็กเทรซของ ANR ซึ่งเทรดหลักดูเหมือนจะไม่มีการใช้งาน (เช่น บันทึกใน "nativePollOnce" หรือ "เทรดหลักไม่มีการใช้งาน")

    การรั่วไหลของ Barrier Sync

    คุณสามารถลบล้างการดูได้ทั้งโดยอ้อมด้วยการเปลี่ยนสถานะ (เช่น การเรียก TextView.setText, View.setVisibility) หรือโดยตรงด้วยการเรียก View.invalidate หรือ View.requestLayout เมื่อมุมมองไม่ถูกต้อง ViewRootImpl จะกำหนดเวลาการข้ามเพื่อทำการวัดผล เลย์เอาต์ และการวาด เพื่ออัปเดตสถานะ UI

    1. การกำหนดเวลาการส่งผ่าน: ViewRootImpl กำหนดเวลาการส่งผ่าน ซึ่งเป็นการส่งเลย์เอาต์และ การวาดภาพโดยการโพสต์แบริเออร์การซิงโครไนซ์ไปยัง MessageQueue ของเธรด UI แบริเออร์นี้จะหยุดการประมวลผลข้อความตามปกติชั่วคราวเพื่อให้เลย์เอาต์ UI มีลำดับความสำคัญ
    2. Race Condition: เมื่อหลายเธรดพยายามทำให้มุมมองไม่ถูกต้องพร้อมกัน เธรดเหล่านั้นจะแข่งกันเพื่อกำหนดเวลาการข้ามนี้ ทั้ง 2 เธรดอาจแทรกแบริเออร์การซิงค์ได้สำเร็จ แต่เฟรมเวิร์กจะจัดเก็บโทเค็นสำหรับเธรดใดเธรดหนึ่งเท่านั้น
    3. UI หยุดทำงาน: เมื่อการข้ามดำเนินการ ระบบจะนำเฉพาะอุปสรรคที่บันทึกไว้รายการเดียวออก ส่วนแบริเออร์รองที่ "รั่วไหล" จะยังคงอยู่ในคิวต่อไปเรื่อยๆ ซึ่งจะบล็อกเธรด UI ไม่ให้ประมวลผลข้อความแบบซิงโครนัสอย่างถาวร

    จึงทำให้ UI ค้าง เนื่องจาก MessageQueue ประมวลผลข้อความแบบไม่พร้อมกันที่ผ่านขีดจำกัดที่รั่วไหลไม่ได้ ชุดข้อความหลักจึงเข้าสู่สถานะว่าง ปัญหานี้มักจะปรากฏเป็น ANR ที่มี nativePollOnce ใน สแต็กเทรซ

    หากต้องการหลีกเลี่ยงการละเมิดการแสดงผลแบบเธรด ให้ทำตามแนวทางปฏิบัติแนะนำต่อไปนี้

    • โต้ตอบกับViewออบเจ็กต์เท่านั้น รวมถึงอ่านพร็อพเพอร์ตี้ เช่น width หรือ height หรือตั้งค่าพร็อพเพอร์ตี้ เช่น TextView's text ในเทรด ที่คุณสร้างลำดับชั้นการแสดงผล ซึ่งมักจะเป็นเทรดหลักหรือเทรด UI เสมอ
    • หากไม่สามารถรับประกันได้ว่าคุณกำลังทำงานในเธรด UI เมื่อเข้าถึงมุมมอง ให้ถือว่าการดำเนินการดังกล่าวไม่ปลอดภัย เช่น หากคุณใช้ Coroutines สำหรับงานเบื้องหลัง คุณต้องเปลี่ยนไปใช้ตัวจัดส่งหลักก่อนที่จะจัดการออบเจ็กต์ View

    lifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
        val data = myRepository.getData()
        withContext(Dispatchers.Main) { // Switch context to Main
            myTextView.text = data.title
        }
    }

    Android มีวิธีเข้าถึง UI thread จากเธรดอื่นๆ หลายวิธีเพื่อช่วยให้คุณปฏิบัติตามแนวทางปฏิบัติแนะนำได้

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

    วิธีแก้ไขข้อบกพร่อง

    Android 17 เปิดตัวเครื่องมือใหม่ที่จะช่วยคุณระบุ ติดตาม และแก้ไขการละเมิดการทำงานของ View ในเธรดระหว่างการพัฒนา

    1. เครื่องมือเฟรมเวิร์กความเข้ากันได้

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

    1. ติดตั้งแอปเวอร์ชันที่แก้ไขข้อบกพร่องได้ในอุปกรณ์ที่ใช้ Android 17 ขึ้นไป
    2. เปิดแอปการตั้งค่าของอุปกรณ์ แล้วไปที่ระบบ > ขั้นสูง > ตัวเลือกสำหรับนักพัฒนาแอป > การเปลี่ยนแปลงความเข้ากันได้ของแอป
    3. เลือกแอปจากรายการ
    4. จากรายการการเปลี่ยนแปลง ให้ค้นหาและเปิดสวิตช์ ENFORCE_THREAD_CHECKS_ON_VIEW_ROOT_IMPL_APIS

    นอกจากนี้ คุณยังเปิดหรือปิดค่าสถานะได้โดยใช้ ADB ดังนี้

    $ adb shell am compat enable ENFORCE_THREAD_CHECKS_ON_VIEW_ROOT_IMPL_APIS <your.package.name>
    $ adb shell am compat disable ENFORCE_THREAD_CHECKS_ON_VIEW_ROOT_IMPL_APIS <your.package.name>
    

    การเปิดใช้ฟีเจอร์นี้จะบังคับให้แอปส่งข้อยกเว้นและหยุดทำงานทุกครั้งที่มีการเรียกใช้ View API จากเธรดที่ไม่ถูกต้อง ซึ่งจะช่วยให้คุณตรวจหาและแก้ไขปัญหาการละเมิดการทำงานของเธรดใน View ได้

    2. CalledFromWrongThreadListener API

    นอกจากนี้ คุณยังใช้ View#registerCalledFromWrongThreadListener API ทั่วโลกเพื่อตรวจหาการเข้าถึงเธรดที่ไม่เหมาะสมโดยใช้โปรแกรมได้ด้วย

    • การส่งข้อมูลการใช้งานและการติดตาม: Listener นี้ช่วยให้แอปได้รับการเรียกกลับ เมื่อมีการเรียกใช้ View API จากเธรดที่ไม่ถูกต้อง ซึ่งจะช่วยให้บันทึก การส่งข้อมูลการใช้งานและติดตามข้อบกพร่องได้ง่ายขึ้น
    • การดำเนินการในบรรทัด: ระบบจะเรียกใช้ Listener ในบรรทัด ซึ่งช่วยให้คุณบันทึก และตรวจสอบสแต็กเทรซที่แน่นอนได้ในขณะที่เกิดการละเมิด
    android {
       //...
       compileSdk = 37
    }
    

    val listener = object : View.CalledFromWrongThreadListener {
        override fun onCalledFromWrongThread() {
            // Handle the issue, e.g. crash if this is a dev build, or log an event
            // e.g. Log.d(TAG, "CalledFromWrongThread: ${Exception().stackTraceToString()}")
            // Unregister the listener to avoid redundant notifications for the same issue
            View.unregisterCalledFromWrongThreadListener(this)
        }
    }
    View.registerCalledFromWrongThreadListener(listener)

    nativePollOnce

    หากคุณเห็นเฟรม "nativePollOnce" หรือ "message queue idle" ในสแต็ก ANR มักจะบ่งบอกว่าเธรดที่น่าสงสัยว่าไม่ตอบสนองนั้นไม่ได้ทำงาน และรอข้อความ Looper อยู่ ใน Google Play Console รายละเอียด ANR จะมีลักษณะดังนี้

    Native method - android.os.MessageQueue.nativePollOnce
    Executing service com.example.app/com.example.app.MyService
    

    เช่น หากเทรดหลักไม่มีการใช้งาน สแต็กจะมีลักษณะดังนี้

    "main" tid=1 NativeMain threadIdle
    
    #00  pc 0x00000000000d8b38  /apex/com.android.runtime/lib64/bionic/libc.so (__epoll_pwait+8)
    #01  pc 0x0000000000019d88  /system/lib64/libutils.so (android::Looper::pollInner(int)+184)
    #02  pc 0x0000000000019c68  /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+112)
    #03  pc 0x000000000011409c  /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)+44)
    at android.os.MessageQueue.nativePollOnce (Native method)
    at android.os.MessageQueue.next (MessageQueue.java:339)  at android.os.Looper.loop (Looper.java:208)
    at android.app.ActivityThread.main (ActivityThread.java:8192)
    at java.lang.reflect.Method.invoke (Native method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:626)
    at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1015)
    

    มีสาเหตุหลายประการที่ทำให้เธรดที่สงสัยว่าไม่ตอบสนองอาจไม่ได้ใช้งาน ได้แก่

    • ปัญหาทั้งระบบ ระบบไม่ได้กำหนดเวลากระบวนการเนื่องจากระบบมีการโหลดข้อมูลจำนวนมาก หรือมีปัญหาในเซิร์ฟเวอร์ของระบบ
    • การทิ้งข้อมูลสแต็กที่ล่าช้า เธรดที่กู้คืนในช่วงเวลาสั้นๆ ระหว่างการทริกเกอร์ ANR กับการทิ้งสแต็ก เวลาในการตอบสนองใน Pixel บน Android 13 อยู่ที่ประมาณ 100 มิลลิวินาที แต่อาจเกิน 1 วินาทีได้ โดยปกติแล้ว เวลาในการตอบสนองใน Pixel ที่ใช้ Android 14 จะน้อยกว่า 10 มิลลิวินาที
    • การระบุชุดข้อความที่ไม่ถูกต้อง เธรดที่ใช้สร้างลายเซ็น ANR ไม่ใช่ เธรดที่ไม่ตอบสนองจริงซึ่งทำให้เกิด ANR
    • ดูการละเมิดการสนทนา หากแอป แก้ไขมุมมองในเธรดเบื้องหลัง อาจทำให้เกิดสภาวะแข่งขันภายใน มุมมองที่บล็อกไม่ให้งานของเธรด UI ทำงาน

    เนื่องจากทริกเกอร์พื้นฐานของ ANR ประเภท "nativePollOnce" จะแตกต่างกันไปตามประเภท ANR การวินิจฉัยหมวดหมู่ ANR ที่เฉพาะเจาะจงจะช่วยระบุขั้นตอนที่นำไปใช้ได้จริงเพื่อ แก้ไขปัญหาภายในแอป

    หมวดหมู่ สาเหตุ การแก้ไขที่แนะนํา
    การหมดเวลาการส่งอินพุต ปัญหาในระบบ
    การดัมพ์สแต็กที่ล่าช้า
    ไม่ต้องดำเนินการใดๆ
    ไม่มีหน้าต่างที่โฟกัส ปัญหาทั่วทั้งระบบ
    การดัมพ์สแต็กที่ล่าช้า
    ดูการละเมิดการทำงานแบบหลายเทรด
    ตรวจสอบฐานโค้ดเพื่อหาการละเมิดการทำงานของ View ในหลายเธรด
    หมดเวลาของ Broadcast Receiver การทิ้งสแต็กที่ล่าช้า
    ปัญหาระดับระบบ
    การระบุเธรดที่ไม่ถูกต้อง
    ดูการละเมิดการแยกเธรด
    ตรวจสอบเธรดที่เกี่ยวข้องในการดัมพ์สแต็ก
    ตรวจสอบฐานของโค้ดเพื่อหาการละเมิดการทำงานของ View ในหลายเธรด
    หมดเวลาในการดำเนินการบริการ การทิ้งสแต็กที่ล่าช้า
    ปัญหาระดับระบบ
    ดูการละเมิดการทำงานแบบหลายเธรด
    ตรวจสอบฐานโค้ดเพื่อหาการละเมิดการทำงานของ View ในหลายเธรด
    ผู้ให้บริการเนื้อหาไม่ตอบสนอง การทิ้งข้อมูลสแต็กที่ล่าช้า
    ปัญหาระดับระบบ
    การระบุเธรดที่ไม่ถูกต้อง
    ตรวจสอบเธรดที่เกี่ยวข้องในการดัมพ์สแต็ก

    ขั้นตอนที่แนะนำในการวิเคราะห์ ANR ของ nativePollOnce มีดังนี้

    1. การใช้งานระบบอย่างหนัก: ประเมินแรงกดดันด้านทรัพยากรโดยรวมของอุปกรณ์ เช่น CPU, หน่วยความจำ หรือ I/O ที่ขาดแคลนทั่วทั้งระบบ ซึ่งเป็นสาเหตุหลักที่ทำให้ ไม่ตอบสนอง
    2. การระบุแหล่งที่มาของเธรดไม่ถูกต้อง: ตรวจสอบเธรดของ Worker และ Binder เพื่อหาการหยุดชะงัก การแย่งชิงล็อกที่ส่งผลต่อเธรดหลักหรือเธรดพื้นหลังที่ค้างอยู่ ซึ่งประมวลผลคอมโพเนนต์แบบอะซิงโครนัส (เช่น goAsync())
    3. ดูการละเมิดการแยกเธรด: สแกนเธรดเบื้องหลังเพื่อหาการแก้ไขลำดับชั้นของมุมมอง UI ที่ผิดกฎหมาย ซึ่งอาจทำให้แบริเออร์การซิงค์ใน MessageQueue ไม่สามารถใช้งานได้และบล็อกข้อความแบบซิงโครนัสทั้งหมดอย่างถาวร

    ไม่มีสแตกเฟรม

    รายงาน ANR บางรายการไม่มีสแต็กที่มี ANR ซึ่งหมายความว่าการทิ้งสแต็กไม่สำเร็จเมื่อสร้างรายงาน ANR สาเหตุที่เป็นไปได้บางประการที่ทำให้ไม่มีเฟรมสแต็กมีดังนี้

    • การดึงข้อมูลสแต็กใช้เวลานานเกินไปและหมดเวลา
    • กระบวนการสิ้นสุดหรือถูกหยุดก่อนที่จะมีการบันทึกสแต็ก
    [...]
    
    --- CriticalEventLog ---
    capacity: 20
    timestamp_ms: 1666030897753
    window_ms: 300000
    
    libdebuggerd_client: failed to read status response from tombstoned: timeout reached?
    
    ----- Waiting Channels: pid 7068 at 2022-10-18 02:21:37.<US_SOCIAL_SECURITY_NUMBER>+0800 -----
    
    [...]
    

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

    ปัญหาที่ทราบแล้ว

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