Trang này thảo luận về một số lý do phổ biến khiến dịch vụ trên nền trước có thể gặp lỗi 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 được 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 có những thay đổi về 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 vấn đề với dịch vụ trên nền trước, bạn nên kiểm tra các thay đổi đối với dịch vụ trên nền trước và xem có thay đổi nào gần đây có thể giải thích cho vấn đề của bạn hay không. Bạn đặc biệt cần 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 giờ không hoạt động nữa
- 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 của bạn nhắm đến
Ngoài ra, nếu đ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 về 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 thành nhanh chóng, trong vòng khoảng 3 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ụ này 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 ANR xảy ra do một dịch vụ trên nền trước không tự dừng, hệ thống sẽ gửi ra 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 báo cáo ANR. Nếu đây là vấn đề, báo cáo sẽ có 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.
Các dịch vụ trên nền trước của bạn phải triển khai Service.onTimeout(int,int)
.
Đảm bảo rằng quá trình triển khai phương thức đó gọi stopSelf()
ngay lập tức.
Trường hợp ngoại lệ đối với 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 đưa ra một ngoại lệ. Nếu ứng dụng không bắt được ngoại lệ, người dùng sẽ thấy một hộp thoại cho biết ứ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ộ. Trong những trường hợp đó, bạn có thể tìm hiểu xem ngoại lệ là gì bằng cách xem trong dấu vết ngăn xếp và bạn có thể kiểm tra Logcat để biết thông tin lỗi chi tiết hơn.
Ngoại lệ nội bộ: Đã hết thời gian chờ
Hệ thống áp đặt giới hạn về thời gian mà các dịch vụ đồng bộ hoá dữ liệu và xử lý nội dung nghe nhìn ở nền trước có thể chạy trong khi ứng dụng ở 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ụ này có vài giây để gọi stopSelf()
. Nếu dịch vụ không tự dừng, hệ thống sẽ tạo ra một RemoteServiceException
nội bộ khiến ứng dụng gặp sự cố.
Chẩn đoán:
Bạn có thể tìm hiểu xem ngoại lệ là gì bằng cách xem trong dấu vết ngăn xếp và bạn có thể kiểm tra Logcat để biết thông tin chi tiết hơn về lỗi. Trong trường hợp này, Logcat có thông báo lỗi 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.
Các dịch vụ trên nền trước của bạn phải triển khai Service.onTimeout(int,int)
.
Đảm bảo rằng quá trình triển khai phương thức đó gọi stopSelf()
ngay lập tức.
Ngoại lệ nội bộ: ForegroundServiceDidNotStartInTimeException
Khi bạn chạy một dịch vụ bằng cách gọi context.startForegroundService()
, dịch vụ đó có vài giây để tự quảng bá thành một 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, thì sẽ gửi một ForegroundServiceDidNotStartInTimeException
nội bộ.
Chẩn đoán:
Bạn có thể tìm hiểu xem ngoại lệ là gì bằng cách xem trong dấu vết ngăn xếp và bạn có thể kiểm tra Logcat để biết thông tin chi tiết hơn về lỗi. Trong trường hợp này, Logcat có thông báo lỗi sau:
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ụ mới tạo trên nền trước đều gọi ServiceCompat.startForeground()
trong vòng vài giây.
ForegroundServiceStartNotAllowedException
Lỗi:
Hệ thống sẽ gửi ForegroundServiceStartNotAllowedException
.
Nguyên nhân:
Điều này thường xảy ra do ứng dụng khởi chạy một dịch vụ trên nền trước từ 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 dịch vụ trên nền trước trong khi ứng dụng đang chạy ở chế độ nền, với một số trường hợp miễn trừ cụ thể.
Nếu bạn cố gắng bắt đầu một dịch vụ trên nền trước từ nền và không đáp ứng các 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 sẽ làm như vậ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. Nút này khiến ứng dụng thực hiện một số quy trình 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 chuyển ngay ứng dụng sang chế độ nền. Sau đó, ứng dụng sẽ cố gắng chạy dịch vụ ở chế độ nền. Nếu ứng dụng không đáp ứng một trong các trường hợp ngoại lệ được chỉ định, thì hệ thống sẽ gửi ra một ForegroundServiceStartNotAllowedException
.
Ngoài ra, một số trường hợp miễn trừ có giới hạn thời gian ngắn. Ví dụ: có một trường hợp miễn trừ ngắ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, bạn sẽ nhận được một 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 bạn nhắm đến, hãy xem tài liệu 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 ngoại lệ được phép.
Cách khắc phục:
Thay đổi quy trình của ứng dụng để ứng dụng không cần khởi chạy các dịch vụ trên nền trước khi ở 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 ngoại lệ.
Bạn có thể sử dụng các thành phần nhận biết vòng đời để quản lý vòng đời của ứng dụng, nhờ đó bạn không vô tình tìm cách khởi chạy một dịch vụ trên nền trước từ nền.
SecurityException
Lỗi:
Hệ thống gửi SecurityException
.
Nguyên nhân:
Ứng dụng của bạn đã tìm cách khởi 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, ứng dụng phải có quyền
FOREGROUND_SERVICE
để chạy một dịch vụ trên nền trước. - Nếu một ứng dụng 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 cho loại dịch vụ trên nền trước. Các điều kiện tiên quyết này được trình bày chi tiết trong tài liệu về các loại dịch vụ trên nền trước. Đặc biệt, 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ụ nhắn tin từ xa trên nền trước phải có quyền
FOREGROUND_SERVICE_REMOTE_MESSAGING
.
- 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ụ nhắn tin từ xa trên nền trước phải có quyền
- Trong một số trường hợp, có những hạn chế bổ sung 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. Những quyền này chỉ được cấp cho ứng dụng khi ứng dụng ở chế độ nền trước (ngoại trừ một số trường hợp 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 ứng dụng ở chế độ nền, thì hệ thống sẽ gửi một
SecurityException
ngay cả khi ứng dụng có trường hợp ngoại lệ để chạy dịch vụ trên nền trước từ chế độ nền. Để biết thêm thông tin, hãy xem bài viết Các hạn chế khi khởi động dịch vụ trên nền trước cần có quyền sử dụng khi đang dùng.- Bạn có thể gặp phải lỗi
SecurityException
nếu yêu cầu các quyền cần thiết nhưng lại bắt đầu dịch vụ trên nền trước trước khi xác nhận rằng bạn đã được cấp các quyền bắt buộc.
- Bạn có thể gặp phải lỗi
Cách khắc phục:
Trước khi chạy dịch vụ trên nền trước, hãy yêu cầu tất cả các quyền thích hợp đối với 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 khi chạy.