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 sự cố.
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 xảy ra 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 báo cáo ANR. Nếu đây là vấn đề, báo cáo 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ộ. 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êm thông tin chi tiết về lỗ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 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êm thông tin chi tiết 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.
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.
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 không, dịch vụ 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êm thông tin chi tiết 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ụ 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 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. Sau đó, ứ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, 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 nhận biết được vòng đời để 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
.
- 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
- Trong một số trường hợp, có các quy định 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, thì 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.
- Bạn có thể nhận được
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ả 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.