ANR

Khi luồng giao diện người dùng của một ứng dụng Android bị chặn quá lâu, lỗi "Ứng dụng không phản hồi" (ANR) sẽ được kích hoạt. Android vitals theo dõi và báo cáo các chỉ số ANR trong Google Play Console để giúp bạn theo dõi độ ổn định và khả năng thích ứng của ứng dụng trên các thiết bị.

Các chỉ số và ngưỡng của Android vitals

Android vitals có thể giúp bạn theo dõi và cải thiện tỷ lệ ANR của ứng dụng. Android vitals đo lường một số tỷ lệ ANR:

  • Tỷ lệ ANR: Là tỷ lệ phần trăm số người dùng hoạt động hằng ngày gặp phải bất kỳ loại lỗi ANR nào.
  • Tỷ lệ lỗi ANR mà người dùng nhận thấy: Là tỷ lệ phần trăm số người dùng hoạt động hằng ngày gặp phải ít nhất 1 lỗi ANR mà người dùng nhận thấy. Hiện tại, chỉ những lỗi ANR thuộc loại Input dispatching timed out được coi là do người dùng nhận thấy.
  • Tỷ lệ ANR nhiều lần: Là tỷ lệ phần trăm người dùng hoạt động hằng ngày gặp phải ít nhất 2 lỗi ANR.

Số người dùng hoạt động hằng ngày là người dùng riêng biệt dùng ứng dụng của bạn trong một ngày trên một thiết bị, có thể có nhiều phiên hoạt động. Nếu một người dùng sử dụng ứng dụng của bạn trên nhiều thiết bị trong một ngày, thì từng thiết bị đó cũng sẽ đóng góp vào số lượng người dùng đang hoạt động trong ngày đó.

Tỷ lệ lỗi ANR mà người dùng nhận thấy là một chỉ số quan trọng chính, có nghĩa là tỷ lệ này ảnh hưởng đến khả năng người dùng phát hiện được ứng dụng của bạn trên Google Play. Đây là một chỉ số quan trọng vì các lỗi ANR mà chỉ số này tính đến luôn xảy ra khi người dùng tương tác với ứng dụng, do đó gây gián đoạn nhiều nhất.

Play đã xác định 2 ngưỡng hành vi xấu cho chỉ số này:

  • Ngưỡng hành vi xấu chung: Ít nhất 0,47% số người dùng hoạt động hằng ngày gặp phải lỗi ANR mà người dùng nhận thấy trên tất cả các kiểu máy.
  • Ngưỡng hành vi xấu trên mỗi thiết bị: Ít nhất 8% số người dùng hoạt động hằng ngày gặp phải lỗi ANR mà người dùng nhận thấy, đối với một kiểu máy duy nhất.

Nếu ứng dụng của bạn vượt quá ngưỡng hành vi xấu chung, thì ứng dụng đó có thể khó được phát hiện hơn trên tất cả các thiết bị. Nếu ứng dụng của bạn vượt quá ngưỡng hành vi xấu trên mỗi thiết bị ở một số thiết bị, thì ứng dụng đó có thể khó được phát hiện hơn trên các thiết bị đó và cảnh báo có thể sẽ xuất hiện trên trang thông tin của bạn trên Cửa hàng Play.

Android vitals có thể cảnh báo cho bạn qua Play Console khi ứng dụng gặp quá nhiều lỗi ANR.

Để biết thông tin về cách Google Play thu thập dữ liệu Android vitals, vui lòng xem tài liệu về Play Console.

Phát hiện vấn đề

Nếu ứng dụng chạy ở nền trước khi xảy ra lỗi ANR, hệ thống sẽ hiển thị hộp thoại cho người dùng như minh hoạ trong hình 1. Hộp thoại ANR cho phép người dùng buộc thoát khỏi ứng dụng.

Hộp thoại ANR hiển thị cho người dùng.
Hình 1. Hộp thoại ANR hiển thị cho người dùng

ANR là một sự cố của luồng chính trong ứng dụng, vì luồng này chịu trách nhiệm cập nhật giao diện người dùng nhưng không thể xử lý các sự kiện đầu vào của người dùng hoặc vẽ khiến người dùng thất vọng. Để biết thêm thông tin về luồng chính của ứng dụng, vui lòng xem Tổng quan về quy trình và luồng.

ANR được kích hoạt cho ứng dụng của bạn khi một trong các điều kiện sau xảy ra:

  • Hết thời gian chờ điều phối đầu vào: Nếu ứng dụng của bạn chưa phản hồi sự kiện nhập (chẳng hạn như thao tác nhấn phím hoặc chạm vào màn hình) trong vòng 5 giây.
  • Thực thi dịch vụ: Nếu một dịch vụ do ứng dụng của bạn khai báo không thể hoàn tất quá trình thực thi Service.onCreate và Service.onStartCommand hoặc Service.onBind trong vòng vài giây.
  • Service.startForeground không được gọi: Nếu ứng dụng của bạn sử dụng Context.startForegroundService để bắt đầu một dịch vụ mới trên nền trước nhưng dịch vụ đó không gọi startForeground trong vòng 5 giây.
  • Truyền đi ý định: Nếu BroadcastReceiver chưa hoàn tất quá trình thực thi trong một khoảng thời gian nhất định. Nếu ứng dụng có bất cứ hoạt động nào trong nền trước, thời gian chờ này là 10 giây.
  • Tương tác với JobScheduler: Nếu JobService không trả về từ JobService.onStartJob hoặc JobService.onStopJob trong vòng vài giây, hoặc nếu lệnh do người dùng yêu cầu bắt đầu và ứng dụng của bạn không gọi JobService.setNotification trong vòng vài giây sau khi JobService.onStartJob được gọi. Đối với các ứng dụng nhắm đến Android 13 trở xuống, lỗi ANR không hoạt động và không được báo cáo cho ứng dụng. Đối với các ứng dụng nhắm đến Android 14 trở lên, lỗi ANR phải rõ ràng và được báo cáo cho ứng dụng.

Ngoài Android vitals, bạn có thể dùng các công cụ khác để phát hiện lỗi ANR trong trường này, mặc dù các công cụ bên thứ ba không thể báo cáo lỗi ANR trên Android 10 (cấp độ API 29) trở xuống.

Chẩn đoán lỗi ANR (Ứng dụng không phản hồi)

Có một vài mẫu phổ biến cần xem xét khi chẩn đoán lỗi ANR:

  • Ứng dụng đang thực hiện các thao tác chậm liên quan đến I/O trên luồng chính.
  • Ứng dụng đang thực hiện một phép tính mất nhiều thời gian trên luồng chính.
  • Luồng chính đang thực hiện một lệnh gọi liên kết đồng bộ tới một quy trình khác, và quy trình này sẽ mất nhiều thời gian để trả lệnh về lại.
  • Luồng chính bị chặn đang chờ một khối đồng bộ hoá cho hoạt động mất nhiều thời gian đang diễn ra trên luồng khác.
  • Luồng chính đang bị tắc nghẽn với một luồng khác, trong quá trình hoặc qua một lệnh gọi liên kết. Luồng chính không những đang đợi một hoạt động mất nhiều thời gian kết thúc mà còn đang gặp tình huống tắc nghẽn.

Các kỹ thuật sau có thể giúp bạn xác định nguyên nhân dẫn đến lỗi ANR.

HealthStats

HealthStats cung cấp các chỉ số về trạng thái của ứng dụng bằng cách ghi lại tổng thời gian người dùng và hệ thống, thời gian của CPU, số liệu thống kê về đài, mạng, thời gian bật/tắt màn hình và chuông báo thức. Thông tin này có thể giúp bạn đo lường mức sử dụng CPU tổng thể và mức tiêu hao pin.

Gỡ lỗi

Debug giúp bạn kiểm tra ứng dụng Android trong quá trình phát triển, bao gồm cả việc theo dõi và phân bổ số lượng để xác định hiện tượng giật và độ trễ trong ứng dụng. Bạn cũng có thể sử dụng Debug để xem bộ đếm thời gian chạy và bộ nhớ gốc, cũng như các chỉ số về bộ nhớ có thể giúp bạn xác định mức sử dụng bộ nhớ của một quy trình cụ thể.

ApplicationExitInfo

ApplicationExitInfo có trên Android 11 (cấp độ API 30) trở lên và cung cấp thông tin về lý do thoát khỏi ứng dụng. Lý do bao gồm lỗi ANR, sắp hết bộ nhớ, ứng dụng gặp sự cố, sử dụng CPU quá mức, tình trạng gián đoạn do người dùng, gián đoạn do hệ thống hoặc các thay đổi quyền khi bắt đầu chạy.

Chế độ nghiêm ngặt

Việc sử dụng StrictMode sẽ giúp bạn tìm thấy các hoạt động I/O ngẫu nhiên trên luồng chính khi đang phát triển ứng dụng của mình. Bạn có thể dùng StrictMode ở cấp ứng dụng hoặc hoạt động.

Bật hộp thoại lỗi ANR trong nền

Android sẽ hiển thị hộp thoại lỗi ANR cho các ứng dụng mất quá nhiều thời gian để xử lý thông báo phát đi với điều kiện mục Hiển thị tất cả các lỗi ANR được bật trong phần Tuỳ chọn cho nhà phát triển trên thiết bị. Vì lý do này, hộp thoại lỗi ANR trong nền không phải lúc nào cũng hiển thị cho người dùng, ngay cả khi ứng dụng gặp vấn đề về hiệu suất.

Lập hồ sơ CPU và dấu vết hệ thống

Sử dụng Trình phân tích CPU Android Studio để ghi lại dấu vết hệ thống và hoạt động của CPU trong khi trò chơi chạy. Việc kiểm tra luồng Activity chính cùng với các luồng kết xuất, âm thanh và luồng worker của công cụ phát triển trò chơi giúp bạn phát hiện các khung hình dài, tải thành phần đồng bộ và tranh chấp luồng trước khi chúng kích hoạt lỗi ANR.

Kéo tệp theo dõi

Android lưu trữ thông tin theo dõi khi gặp lỗi ANR. Trên các phiên bản Android thấp hơn, chỉ có một tệp /data/anr/traces.txt trên thiết bị. Trên các phiên bản Android cao hơn, có nhiều tệp /data/anr/anr_*. Bạn có thể truy cập các dấu vết của lỗi ANR từ một thiết bị hoặc trình mô phỏng bằng cách sử dụng Cầu gỡ lỗi Android (adb) làm thư mục gốc:

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

Bạn có thể ghi lại báo cáo lỗi từ thiết bị thực bằng cách sử dụng tùy chọn cho nhà phát triển Tạo báo cáo lỗi trên thiết bị hoặc lệnh adb bugreport trên máy phát triển của mình. Để biết thêm thông tin, hãy xem bài viết Ghi lại và đọc báo cáo lỗi.

Khắc phục sự cố

Sau khi đã xác định sự cố, bạn có thể sử dụng các mẹo trong phần này để khắc phục các sự cố thường gặp.

Mã chậm trên luồng chính

Xác định các vị trí trong mã của bạn nơi luồng chính của ứng dụng bận trong hơn 5 giây. Tìm các trường hợp sử dụng đáng ngờ trong trò chơi của bạn và cố gắng mô phỏng lỗi ANR.

Trong trò chơi, tình trạng gián đoạn luồng chính thường xảy ra khi quá trình giải nén tài sản đồng bộ, biên dịch chương trình đổ bóng hoặc khởi chạy trạng thái trò chơi nặng chạy trên luồng Activity chính của Android (chẳng hạn như bên trong onCreate, onResume hoặc lệnh gọi lại JNI được gọi từ luồng giao diện người dùng). Di chuyển quá trình thực thi vòng lặp trò chơi, xử lý thành phần và khởi động cảnh sang các luồng worker chuyên dụng của công cụ, kết xuất hoặc nền để luồng chính vẫn có thể xử lý các sự kiện đầu vào và sự kiện trong vòng đời.

I/O trên luồng chính

Việc thực thi các hoạt động I/O trên luồng chính là nguyên nhân phổ biến gây ra các thao tác chậm trên luồng chính, điều này dẫn đến các lỗi ANR.

Di chuyển tất cả các lượt đọc gói tài sản, chuyển đổi tuần tự trò chơi đã lưu, SharedPreferences quyền truy cập và yêu cầu mạng ra khỏi luồng Activity chính sang các luồng worker trong nền để độ trễ của bộ nhớ hoặc mạng không thể chặn việc gửi dữ liệu đầu vào.

Tình trạng tắc nghẽn

Tình trạng tắc nghẽn sẽ xảy ra khi một luồng chuyển sang trạng thái chờ vì một tài nguyên cần thiết được giữ lại trong một luồng khác, đồng thời đang chờ tài nguyên do luồng đầu tiên lưu giữ. Nếu luồng chính của ứng dụng rơi vào trường hợp này, thì nhiều khả năng lỗi ANR sẽ xảy ra.

Trong trò chơi, tình trạng tắc nghẽn và tranh chấp khoá thường xảy ra giữa luồng Activity chính của Android (xử lý vòng đời, nền tảng hoặc lệnh gọi lại đầu vào) và các luồng kết xuất, logic hoặc âm thanh C hoặc C++ gốc. Tránh chờ đồng bộ trên luồng chính đối với khoá công cụ gốc, đồng thời sử dụng thứ tự khoá nhất quán hoặc hàng đợi thông báo không khoá khi giao tiếp giữa JNI và luồng công cụ.

Tắc nghẽn là một hiện tượng được nghiên cứu kỹ lưỡng trong khoa học máy tính và có các thuật toán ngăn chặn cụ thể mà bạn có thể sử dụng để tránh tình trạng này.

Để biết thêm thông tin chi tiết, vui lòng xem bài viết về Thuật toán tắc nghẽn và Thuật toán ngăn ngừa tắc nghẽn trên Wikipedia.

Broadcast receiver (bộ thu phát sóng) chậm

Các ứng dụng có thể phản hồi thông báo phát đi, chẳng hạn như bật hoặc tắt chế độ trên máy bay hoặc sự thay đổi trạng thái kết nối bằng broadcast receiver. ANR xảy ra khi ứng dụng mất quá nhiều thời gian để xử lý thông báo phát đi.

Lỗi ANR xảy ra trong các trường hợp sau:

  • Một bộ nhận tín hiệu truyền tin vẫn chưa hoàn tất việc thực thi phương thức onReceive trong khoảng thời gian đáng kể.
  • Bộ nhận tín hiệu truyền tin gọi goAsync nhưng không gọi được finish trên đối tượng PendingResult.

Ứng dụng của bạn chỉ được thực hiện các thao tác ngắn trong phương thức onReceive của BroadcastReceiver. Tuy nhiên, nếu ứng dụng của bạn yêu cầu xử lý phức tạp hơn do có thông báo phát đi, bạn nên chuyển nhiệm vụ đó cho một luồng worker trong nền nếu nhiệm vụ đó dự kiến mất tối đa vài giây, hoặc cho WorkManager đối với các nhiệm vụ dự kiến mất hơn vài giây.

GameActivity

Thư viện GameActivity đã giảm lỗi ANR trong các nghiên cứu điển hình về trò chơi và ứng dụng được viết bằng C hoặc C++. Nếu thay thế hoạt động gốc hiện có bằng GameActivity, bạn có thể giảm tình trạng chặn luồng giao diện người dùng và ngăn chặn một số lỗi ANR xảy ra.

Nếu bạn đang xây dựng trò chơi bằng Unity, hãy xem bài viết Gỡ lỗi ANR cho trò chơi Unity, Lỗi ANR thường gặp trong trò chơi Unity và Thay thế sự cố và lỗi ANR trên Android bằng biểu tượng cho trò chơi Unity.

Để biết thêm thông tin về lỗi ANR, hãy xem bài viết Duy trì khả năng thích ứng của ứng dụng. Để biết thêm thông tin chi tiết về luồng, vui lòng xem phần Hiệu suất tốt hơn thông qua luồng.