ANR

เมื่อเธรด UI ของแอป Android ถูกบล็อกนานเกินไป ระบบจะทริกเกอร์ข้อผิดพลาด "แอปพลิเคชันไม่ตอบสนอง" (ANR) Android Vitals จะติดตามและรายงานเมตริก ANR ใน Google Play Console เพื่อช่วยคุณตรวจสอบความเสถียรและการตอบสนองของแอปในอุปกรณ์ต่างๆ

เมตริกและเกณฑ์ของ Android Vitals

Android Vitals ช่วยให้คุณตรวจสอบและปรับปรุงอัตรา ANR ของแอปได้ Android Vitals จะวัดอัตรา ANR หลายรายการ ดังนี้

  • อัตรา ANR: เปอร์เซ็นต์ของผู้ใช้ที่ใช้งานอยู่รายวันที่พบ ANR ประเภทใดก็ตาม
  • อัตรา ANR ที่ผู้ใช้รับรู้: เปอร์เซ็นต์ของผู้ใช้ที่ใช้งานอยู่รายวันที่พบ ANR ที่ผู้ใช้รับรู้อย่างน้อย 1 ครั้ง ปัจจุบันระบบจะพิจารณาเฉพาะ ANR ประเภท Input dispatching timed out ว่าเป็น ANR ที่ผู้ใช้รับรู้
  • อัตรา ANR หลายครั้ง: เปอร์เซ็นต์ของผู้ใช้ที่ใช้งานอยู่รายวันที่พบ ANR อย่างน้อย 2 ครั้ง

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

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

Play กำหนดเกณฑ์ลักษณะการทำงานที่ไม่ถูกต้องไว้ 2 เกณฑ์ในเมตริกนี้ ได้แก่

  • เกณฑ์ลักษณะการทำงานที่ไม่ถูกต้องโดยรวม: ผู้ใช้ที่ใช้งานอยู่รายวันอย่างน้อย 0.47% พบ ANR ที่ผู้ใช้รับรู้ในอุปกรณ์ทุกรุ่น
  • เกณฑ์ลักษณะการทำงานที่ไม่ถูกต้องในแต่ละอุปกรณ์: ผู้ใช้รายวันอย่างน้อย 8% พบ ANR ที่ผู้ใช้รับรู้ในอุปกรณ์รุ่นใดรุ่นหนึ่ง

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

Android Vitals จะแจ้งเตือนคุณผ่าน Play Console เมื่อแอปมี ANR มากเกินไป

ดูข้อมูลเกี่ยวกับวิธีที่ Google Play รวบรวมข้อมูล Android Vitals ได้ในเอกสารประกอบของ Play Console

ตรวจหาปัญหา

หากแอปอยู่ในเบื้องหน้าเมื่อเกิด ANR ระบบจะแสดงกล่องโต้ตอบแก่ผู้ใช้ ดังที่แสดงในรูปที่ 1 กล่องโต้ตอบ ANR จะให้โอกาสผู้ใช้ในการบังคับปิดแอป

กล่องโต้ตอบ ANR ที่แสดงต่อผู้ใช้
รูปที่ 1 กล่องโต้ตอบ ANR ที่แสดงต่อผู้ใช้

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

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

  • การส่งอินพุตหมดเวลา: หากแอปไม่ตอบสนองต่อเหตุการณ์อินพุต (เช่น การกดแป้นหรือการแตะหน้าจอ) ภายใน 5 วินาที
  • การเรียกใช้บริการ: หากบริการที่แอปของคุณประกาศไม่สามารถเรียกใช้ Service.onCreate และ Service.onStartCommand หรือ Service.onBind ให้เสร็จภายในไม่กี่วินาที
  • ไม่ได้เรียกใช้ Service.startForeground: หากแอปใช้ Context.startForegroundService เพื่อเริ่มบริการใหม่ในเบื้องหน้า แต่บริการไม่เรียกใช้ startForeground ภายใน 5 วินาที
  • การประกาศ Intent: หาก BroadcastReceiver ทำงานไม่เสร็จภายในระยะเวลาที่กำหนด หากแอปมีกิจกรรมที่ทำงานอยู่เบื้องหน้า ระยะหมดเวลานี้จะเท่ากับ 10 วินาที
  • การโต้ตอบกับ JobScheduler: หาก JobService ไม่แสดงผลจาก JobService.onStartJob หรือ JobService.onStopJob ภายในไม่กี่วินาที หรือหากงานที่ผู้ใช้เริ่มเริ่มต้นขึ้นและแอปของคุณไม่เรียกใช้ JobService.setNotification ภายในไม่กี่วินาทีหลังจากที่มีการเรียกใช้ JobService.onStartJob สำหรับแอปที่กำหนดเป้าหมายเป็น Android 13 และต่ำกว่า ANR จะเกิดขึ้นโดยไม่มีการแจ้งเตือนและไม่มีการรายงานไปยังแอป สำหรับแอปที่กำหนดเป้าหมายเป็น Android 14 ขึ้นไป ANR จะเกิดขึ้นอย่างชัดเจนและมีการรายงานไปยังแอป

นอกจาก Android Vitals แล้ว คุณยังใช้เครื่องมืออื่นๆ เพื่อตรวจหา ANR ในภาคสนามได้ด้วย แม้ว่าเครื่องมือของบุคคลที่สามจะรายงาน ANR ใน Android 10 (ระดับ API 29) และต่ำกว่าไม่ได้ก็ตาม

วิเคราะห์ ANR

รูปแบบที่พบได้ทั่วไปซึ่งควรระวังเมื่อวินิจฉัย ANR มีดังนี้

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

เทคนิคต่อไปนี้จะช่วยคุณระบุสาเหตุของ ANR ได้

HealthStats

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

แก้ไขข้อบกพร่อง

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

ApplicationExitInfo

ApplicationExitInfo พร้อมใช้งานใน Android 11 (ระดับ API 30) ขึ้นไป และให้ข้อมูลเกี่ยวกับสาเหตุที่แอปพลิเคชันออก ซึ่งรวมถึง ANR, หน่วยความจำเหลือน้อย, แอปขัดข้อง, การใช้งาน CPU มากเกินไป, การรบกวนผู้ใช้, การรบกวนระบบ และการเปลี่ยนแปลงสิทธิ์รันไทม์

โหมดจำกัด

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

เปิดใช้กล่องโต้ตอบ ANR ในเบื้องหลัง

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

โปรไฟล์ CPU และการติดตามของระบบ

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

ดึงไฟล์การติดตาม

Android จะจัดเก็บข้อมูลการติดตามเมื่อพบ ANR ใน Android เวอร์ชันที่ต่ำกว่า จะมีไฟล์ /data/anr/traces.txt เพียงไฟล์เดียวในอุปกรณ์ ใน Android เวอร์ชันที่สูงกว่า จะมีไฟล์ /data/anr/anr_* หลายไฟล์ คุณเข้าถึงการติดตาม ANR จากอุปกรณ์หรือโปรแกรมจำลองได้โดยใช้ Android Debug Bridge (adb) เป็นรูท ดังนี้

adb root
adb shell ls /data/anr
adb pull /data/anr/<filename>

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

แก้ไขปัญหา

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

โค้ดที่ทำงานช้าในเทรดหลัก

ระบุตำแหน่งในโค้ดที่เทรดหลักของแอปไม่ว่างนานกว่า 5 วินาที มองหา Use Case ที่น่าสงสัยในเกมและพยายามจำลอง ANR

ในเกม การหยุดชะงักของเธรดหลักมักเกิดขึ้นเมื่อการคลายการบีบอัดเนื้อหาแบบซิงโครนัส การคอมไพล์ตัวปรับเฉดสี หรือการเริ่มต้นสถานะเกมที่หนักหน่วงทำงานในเธรด Activity หลักของ Android (เช่น ภายใน onCreate, onResume หรือ Callback ของ JNI ที่เรียกใช้จากเธรด UI) ย้ายการดำเนินการ Game Loop, การประมวลผลเนื้อหา และการเริ่มต้นฉากไปยังเทรดเครื่องมือ เทรดการแสดงผล หรือเทรดผู้ปฏิบัติงานในเบื้องหลังโดยเฉพาะ เพื่อให้เทรดหลักยังคงว่างสำหรับการประมวลผลอินพุตและเหตุการณ์ในวงจร

I/O ในเทรดหลัก

การดําเนินการ I/O ในเทรดหลักเป็นสาเหตุที่พบบ่อยของการทํางานที่ช้าในเทรดหลัก ซึ่งอาจทําให้เกิด ANR

ย้ายการอ่าน Asset Bundle, การจัดลำดับเกมที่บันทึกไว้, SharedPreferences การเข้าถึง และคำขอเครือข่ายทั้งหมดออกจากเทรด Activity หลักไปยังเทรดผู้ปฏิบัติงานในเบื้องหลัง เพื่อให้เวลาในการตอบสนองของพื้นที่เก็บข้อมูลหรือเครือข่ายไม่บล็อกการส่งอินพุต

Deadlock

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

ในเกม ภาวะติดตายและการแย่งชิงล็อกมักเกิดขึ้นระหว่างเทรด Activity หลักของ Android (จัดการวงจร, Surface หรือ Callback ของอินพุต) กับเทรดการแสดงผล ตรรกะ หรือเสียงของ C หรือ C++ แบบเนทีฟ หลีกเลี่ยงการรอแบบซิงโครนัสในเทรดหลักสำหรับการล็อกเอนจินแบบเนทีฟ และใช้การจัดลำดับการล็อกที่สอดคล้องกันหรือคิวข้อความที่ไม่มีการล็อกเมื่อสื่อสารผ่าน JNI และเทรดเอนจิน

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

ดูข้อมูลเพิ่มเติมได้ที่ภาวะติดตายและอัลกอริทึมการป้องกันภาวะติดตายใน Wikipedia

Broadcast Receiver ที่ทำงานช้า

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

ANR จะเกิดขึ้นในกรณีต่อไปนี้

  • Broadcast Receiver ยังดำเนินการตามเมธอด onReceive ไม่เสร็จภายในระยะเวลาที่เหมาะสม
  • Broadcast Receiver เรียกใช้ goAsync และเรียกใช้ finish ในออบเจ็กต์ PendingResult ไม่สำเร็จ

แอปควรดำเนินการสั้นๆ ในเมธอด onReceive ของ BroadcastReceiver เท่านั้น อย่างไรก็ตาม หากแอปของคุณต้องการการประมวลผลที่ซับซ้อนมากขึ้นอันเป็นผลมาจากข้อความประกาศ คุณควรเลื่อนงานไปยังเทรดผู้ปฏิบัติงานในเบื้องหลังหากคาดว่างานจะใช้เวลาไม่เกิน 2-3 วินาที หรือเลื่อนไปยัง WorkManager สำหรับงานที่คาดว่าจะใช้เวลานานกว่า 2-3 วินาที

GameActivity

ไลบรารี GameActivity ช่วยลด ANR ในกรณีศึกษาของเกมและแอปที่เขียนด้วย C หรือ C++ หากคุณแทนที่กิจกรรมแบบเนทีฟที่มีอยู่ด้วย GameActivity คุณจะลดการบล็อกเธรด UI และป้องกันไม่ให้เกิด ANR บางรายการได้

หากคุณสร้างเกมด้วย Unity โปรดดูแก้ไขข้อบกพร่อง ANR สำหรับเกม Unity, ANR ที่พบบ่อยในเกม Unity และสร้างสัญลักษณ์สำหรับข้อขัดข้องของ Android และ ANR สำหรับเกม Unity

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