วินิจฉัยและแก้ไข 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 ใช้ ที่มีประสิทธิภาพสำหรับสิ่งต่างๆ อย่างเช่นการเลื่อนหรือการแบ่งหน้า ตัวอย่างเช่น จรวดสะพายหลัง ไลบรารีการแบ่งหน้า
ถูกบล็อกโดยคอมโพเนนต์อื่น คอมโพเนนต์อื่น เช่น 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 หากปัญหาทำให้โค้ด onReceive() ทำงานช้า
  • ชุดข้อความของผู้ปฏิบัติงานการประกาศ หากปัญหาทำให้รหัสการออกอากาศ goAsync() ทำงานช้า

โปรดทำตามแนวทางปฏิบัติแนะนำต่อไปนี้เพื่อหลีกเลี่ยง ANR จาก Broadcast Receiver

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

ระยะหมดเวลา

ระยะหมดเวลาของการรับการเผยแพร่จะขึ้นอยู่กับว่า Intent ที่ทำงานอยู่เบื้องหน้าหรือไม่ และเวอร์ชันของแพลตฟอร์ม

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

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

(FLAG_RECEIVER_FOREGROUND ตั้งค่า)

10 วินาที

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

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

(ไม่ได้ตั้งค่า 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 ดังนั้น การเริ่มต้นแอปช้าอาจส่งผลให้ Broadcast Receiver ANR

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

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

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

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

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

ต่อไปนี้คือสาเหตุที่พบบ่อยและการแก้ไขที่แนะนำสำหรับ ANR ของ Broadcast Receiver

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

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

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

โฟลว์ชาร์ตต่อไปนี้แสดงวิธีระบุสาเหตุของการออกอากาศ ANR ของผู้รับ

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

ค้นหารหัสผู้รับ

Google Play Console แสดงคลาสผู้รับและความตั้งใจในการออกอากาศใน 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 }

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

จากรหัสตัวรับสัญญาณ คุณจะเห็นได้ว่ากลุ่มเทรด "BG Thread [0,1,2,3]" จะเป็นงานหลักในการประมวลผลการออกอากาศนี้ กำลังดูกองซ้อน 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 รวมเวลาทั้งหมดที่จะเรียกใช้การค้นหาของผู้ให้บริการเนื้อหาระยะไกล รวมการเริ่มแอประยะไกลแบบ Cold Start หากไม่ได้ทำงานอยู่แล้ว

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

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

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

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

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

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

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

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

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

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

    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)
    

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

    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() โปรดโทรติดต่อหมายเลขนั้นโดยเร็วที่สุด อย่าทำงานหนักมากก่อนที่จะส่งการแจ้งเตือน

    ANR ลึกลับ

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

    ไม่มีความเคลื่อนไหวในคิวข้อความหรือ NativePollOne

    หากคุณเห็นเฟรม android.os.MessageQueue.nativePollOnce ใน ก็มักจะแสดงว่าชุดข้อความที่สงสัยว่าไม่ตอบสนองนั้น ไม่มีความเคลื่อนไหวและกำลังรอข้อความตัววนซ้ำ รายละเอียด ANR ใน Google Play Console ซึ่งจะมีลักษณะดังนี้

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

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

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

    • การนำกองซ้อนนี้ใช้เวลานานเกินไปและหมดเวลา
    • กระบวนการทำงานสิ้นสุดลงหรือถูกยกเลิกก่อนที่จะมีการนำไปใช้งาน
    [...]
    
    --- 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 แบบไม่พร้อมกัน