Khắc phục sự cố về dịch vụ trên nền trước

Trang này thảo luận một số lý do phổ biến khiến dịch vụ trên nền trước có thể không hoạt động và giúp bạn xác định nguyên nhân gây ra vấn đề.

Tài liệu này thảo luận về các vấn đề sau:

Trước khi bạn khắc phục sự cố

Kiểm tra các thay đổi gần đây đối với dịch vụ trên nền trước

Nếu sử dụng không đúng cách, các dịch vụ trên nền trước có thể ảnh hưởng tiêu cực đến hiệu suất của thiết bị và thời lượng pin. Vì lý do này, các bản phát hành nền tảng Android thường thay đổi hành vi của dịch vụ trên nền trước để hạn chế những tác động xấu này.

Nếu gặp sự cố với dịch vụ trên nền trước, bạn nên kiểm tra tài liệu về các thay đổi đối với dịch vụ trên nền trước để xem có thay đổi nào gần đây có thể giải thích cho sự cố của bạn hay không. Bạn cần đặc biệt chú ý kiểm tra các thay đổi trong những trường hợp sau:

  • Mã dịch vụ trên nền trước từng hoạt động nhưng hiện không hoạt động
  • Bạn vừa bắt đầu kiểm thử trên một bản phát hành nền tảng mới hoặc bạn đã thay đổi cấp độ API mà ứng dụng nhắm đến

Ngoài ra, nếu bạn đang kiểm thử thiết bị trên bản dùng thử cho nhà phát triển của nền tảng, hãy nhớ kiểm tra phiên bản mới nhất của tài liệu bản dùng thử cho nhà phát triển.

Lỗi Ứng dụng không phản hồi (ANR)

Trong một số trường hợp, ứng dụng dự kiến sẽ tắt dịch vụ trên nền trước. Nếu ứng dụng không dừng dịch vụ, hệ thống sẽ dừng dịch vụ và kích hoạt lỗi Ứng dụng không phản hồi (ANR).

Dịch vụ ngắn chạy quá lâu gây ra lỗi ANR

Các dịch vụ trên nền trước sử dụng loại dịch vụ ngắn phải hoàn tất nhanh chóng, trong vòng khoảng ba phút. Khi hết thời gian, hệ thống sẽ gọi phương thức Service.onTimeout(int,int) của dịch vụ. Dịch vụ có vài giây để gọi stopSelf(). Nếu dịch vụ không tự dừng, hệ thống sẽ kích hoạt lỗi Ứng dụng không phản hồi.

Chẩn đoán:

Nếu lỗi ANR là do một dịch vụ trên nền trước không tự dừng được, thì hệ thống sẽ gửi một ngoại lệ nội bộ. Bạn có thể xác minh rằng đây là vấn đề bằng cách kiểm tra Logcat. Trong trường hợp này, nhật ký sẽ bao gồm thông báo sau:

Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type FOREGROUND_SERVICE_TYPE_SHORT_SERVICE did not stop within its timeout:
[component name]"

Cách khắc phục:

Đảm bảo rằng tất cả các dịch vụ trên nền trước có giới hạn thời gian đều hoàn tất công việc và gọi stopForeground(int) trong giới hạn thời gian của hệ thống.

Yêu cầu dịch vụ trên nền trước triển khai Service.onTimeout(int,int). Đảm bảo việc triển khai phương thức đó gọi stopSelf() ngay lập tức.

Trường hợp ngoại lệ về dịch vụ trên nền trước

Phần này mô tả một số vấn đề về dịch vụ trên nền trước có thể khiến hệ thống gửi một ngoại lệ. Nếu ứng dụng không phát hiện được ngoại lệ, người dùng sẽ thấy một hộp thoại thông báo rằng ứng dụng đã dừng.

Trong một số trường hợp, hệ thống sẽ gửi ra một ngoại lệ nội bộ. Bạn không thể phát hiện những ngoại lệ đó, nhưng có thể xem trong Logcat để biết ngoại lệ nào đã được gửi.

Ngoại lệ nội bộ: Đã hết thời gian chờ

Hệ thống áp đặt giới hạn về thời lượng các dịch vụ trên nền trước xử lý chế độ đồng bộ hoá dữ liệu và nội dung đa phương tiện có thể chạy trong khi ứng dụng đang chạy ở chế độ nền. Nếu dịch vụ vượt quá giới hạn đó, hệ thống sẽ gọi phương thức Service.onTimeout(int,int) của dịch vụ. Dịch vụ có vài giây để gọi stopSelf(). Nếu dịch vụ không tự dừng, hệ thống sẽ tạo một ngoại lệ nội bộ khiến ứng dụng gặp sự cố.

Chẩn đoán:

Nếu nguyên nhân là hết thời gian chờ, thì Logcat sẽ đưa ra thông báo sau:

Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type [service type] did not stop within its timeout: [component name]"

Cách khắc phục:

Đảm bảo rằng tất cả các dịch vụ trên nền trước có giới hạn thời gian đều hoàn tất công việc và gọi stopForeground(int) trong giới hạn thời gian của hệ thống.

Yêu cầu dịch vụ trên nền trước triển khai Service.onTimeout(int,int). Hãy đảm bảo rằng việc triển khai phương thức đó sẽ gọi stopSelf() ngay lập tức.

Ngoại lệ nội bộ: ForegroundServiceDidNotStartInTimeException

Khi bạn khởi chạy một dịch vụ bằng cách gọi context.startForegroundService(), dịch vụ đó sẽ có vài giây để tự quảng bá thành dịch vụ trên nền trước bằng cách gọi ServiceCompat.startForeground(). Nếu dịch vụ không làm như vậy, hệ thống sẽ kích hoạt lỗi ANR.

Chẩn đoán:

Nếu một dịch vụ trên nền trước không khởi động kịp thời, ứng dụng sẽ gặp sự cố, khiến người dùng thấy hộp thoại Ứng dụng đã dừng. Trong trường hợp này, bạn có thể thấy thông báo sau trong Logcat:

android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException:
Context.startForegroundService() did not then call Service.startForeground()

Cách khắc phục:

Đảm bảo rằng tất cả dịch vụ trên nền trước mới tạo đều gọi ServiceCompat.startForeground() trong vòng vài giây.

ForegroundServiceStartNotAllowedException

Lỗi:

Hệ thống gửi ForegroundServiceStartNotAllowedException.

Nguyên nhân:

Điều này thường là do ứng dụng khởi chạy một dịch vụ trên nền trước từ chế độ nền khi không có trường hợp ngoại lệ hợp lệ.

Kể từ Android 12 (API cấp 31), các ứng dụng không được phép bắt đầu các dịch vụ trên nền trước trong khi ứng dụng đang chạy ở chế độ nền, ngoại trừ một số trường hợp ngoại lệ cụ thể. Nếu bạn cố gắng bắt đầu một dịch vụ trên nền trước từ chế độ nền và không đáp ứng yêu cầu của một trong các trường hợp miễn trừ, thì hệ thống sẽ gửi ForegroundServiceStartNotAllowedException. Hệ thống cũng thực hiện việc này nếu bạn không đáp ứng các yêu cầu của trường hợp miễn trừ.

Ví dụ: một ứng dụng có thể có một nút mà người dùng có thể nhấp vào, khiến ứng dụng thực hiện một số hoạt động xử lý rồi khởi chạy một dịch vụ trên nền trước. Trong trường hợp này, có nguy cơ người dùng có thể nhấp vào nút rồi ngay lập tức chuyển ứng dụng sang chế độ nền. Trong trường hợp này, ứng dụng sẽ cố gắng chạy dịch vụ từ chế độ nền. Nếu ứng dụng không đáp ứng một trong các trường hợp miễn trừ được chỉ định, thì hệ thống sẽ gửi một ForegroundServiceStartNotAllowedException.

Ngoài ra, một số trường hợp miễn trừ có thời hạn ngắn. Ví dụ: có một trường hợp miễn trừ ngắn hạn nếu ứng dụng của bạn khởi chạy một dịch vụ trên nền trước để phản hồi một thông báo FCM có mức độ ưu tiên cao. Nếu không khởi chạy dịch vụ nhanh chóng, bạn sẽ nhận được ForegroundServiceStartNotAllowedException.

Đôi khi, các trường hợp miễn trừ cụ thể sẽ trở nên hạn chế hơn với các bản phát hành Android mới. Nếu bạn đã thay đổi phiên bản Android mà ứng dụng của mình nhắm đến, hãy kiểm tra tài liệu về các thay đổi đối với dịch vụ trên nền trước và xác nhận rằng ứng dụng của bạn vẫn đáp ứng một trong các trường hợp miễn trừ được phép.

Cách khắc phục:

Thay đổi quy trình làm việc của ứng dụng để ứng dụng không cần chạy các dịch vụ trên nền trước khi ứng dụng đang chạy ở chế độ nền hoặc xác nhận rằng ứng dụng của bạn đáp ứng một trong các trường hợp miễn trừ.

Bạn có thể sử dụng các thành phần vòng đời như LiveData để quản lý vòng đời của ứng dụng, nhờ đó bạn không vô tình cố gắng chạy một dịch vụ trên nền trước từ chế độ nền.

SecurityException

Lỗi:

Hệ thống gửiSecurityException.

Nguyên nhân:

Ứng dụng của bạn đã cố gắng chạy một dịch vụ trên nền trước mà không có các quyền cần thiết.

  • Nếu nhắm đến Android 9 (API cấp 28) trở lên, thì ứng dụng phải có quyền FOREGROUND_SERVICE để chạy dịch vụ trên nền trước.
  • Nếu nhắm đến Android 14 (API cấp 34) trở lên, thì ứng dụng phải đáp ứng tất cả các điều kiện tiên quyết đối với loại dịch vụ trên nền trước. Các điều kiện tiên quyết này được nêu chi tiết trong tài liệu về các loại dịch vụ trên nền trước. Cụ thể, hãy lưu ý các yêu cầu sau:
    • Một số loại dịch vụ trên nền trước yêu cầu các quyền cụ thể trong thời gian chạy. Ví dụ: dịch vụ trên nền trước nhắn tin từ xa phải có quyền FOREGROUND_SERVICE_REMOTE_MESSAGING.
  • Trong một số trường hợp, có các hạn chế bổ sung trong khi sử dụng đối với các quyền mà một số loại dịch vụ trên nền trước cần. Các quyền này chỉ được cấp cho ứng dụng khi ứng dụng đang chạy ở chế độ nền trước (ngoại trừ một số trường hợp ngoại lệ cụ thể). Điều này có nghĩa là ngay cả khi ứng dụng của bạn đã yêu cầu và được cấp một trong các quyền này, nếu ứng dụng cố gắng chạy dịch vụ trên nền trước trong khi đang chạy ở chế độ nền, hệ thống sẽ gửi SecurityException ngay cả khi ứng dụng có trường hợp ngoại lệ để bắt đầu dịch vụ trên nền trước từ chế độ nền. Để biết thêm thông tin, hãy xem phần Hạn chế khi khởi động các dịch vụ trên nền trước cần quyền khi đang sử dụng.
    • Bạn có thể nhận được SecurityException nếu đã yêu cầu các quyền cần thiết nhưng bắt đầu dịch vụ trên nền trước trước khi xác nhận rằng các quyền cần thiết đã được cấp.

Cách khắc phục:

Trước khi khởi chạy dịch vụ trên nền trước, hãy yêu cầu tất cả quyền thích hợp cho dịch vụ trên nền trước và xác nhận rằng bạn đã đáp ứng tất cả các điều kiện tiên quyết khác về thời gian chạy.