Trang này thảo luận về một số lý do phổ biến khiến dịch vụ 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 những thay đổi gần đây đối với dịch vụ nền trước
Nếu không được sử dụng đúng cách, dịch vụ nền trước có thể gây ảnh hưởng tiêu cực đến hiệu suất và thời lượng pin của thiết bị. 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 ảnh hưởng xấu này.
Nếu gặp sự cố với dịch vụ nền trước, bạn nên xem tài liệu về các thay đổi đối với dịch vụ nền trước và xem liệu 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ần đặc biệt lưu ý kiểm tra các thay đổi trong những trường hợp sau:
- Mã dịch vụ nền trước từng hoạt động được 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 thử nghiệm thiết bị trên bản dùng trước 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 trước 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ụ, thì 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ụ 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 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 lỗi ANR xảy ra do dịch vụ nền trước không tự dừng được, thì hệ thống sẽ gửi ra một ngoại lệ nội bộ. Bạn có thể xác minh xem đây có phải là vấn đề hay không 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ả dịch vụ 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ụ nền trước triển khai Service.onTimeout(int,int).
Hãy đảm bảo rằng phương thức triển khai của bạn gọi stopSelf() ngay lập tức.
Trường hợp ngoại lệ về dịch vụ nền trước
Phần này mô tả một số vấn đề về dịch vụ 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 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 ngoại lệ là gì bằng cách xem trong dấu vết ngăn xếp và 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ộ: Đã vượt quá thời gian chờ
Hệ thống áp đặt giới hạn về thời gian các dịch vụ nền trước xử lý nội dung nghe nhìn và đồng bộ hoá dữ liệu 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ụ 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 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 ngoại lệ đó là gì bằng cách xem trong dấu vết ngăn xếp và 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ả dịch vụ 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ụ nền trước triển khai Service.onTimeout(int,int).
Hãy đảm bảo rằng phương thức triển khai của bạn 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ự chuyển thành dịch vụ 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 ngoại lệ đó là gì bằng cách xem trong dấu vết ngăn xếp và 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ụ nền trước mới tạo đều gọi ServiceCompat.startForeground() trong vòng vài giây.
WorkManager:
Bạn cũng có thể thấy ngoại lệ này với các worker WorkManager thực thi một dịch vụ nền trước (gọi setForegound hoặc setForegroundAsync). Khi vòng đời của hai worker nền trước trùng lặp khi một worker cố gắng bắt đầu một dịch vụ nền trước trong khi một dịch vụ nền trước đang chạy trước đó cố gắng tắt, sự cố này sẽ đi kèm với nhật ký sau:
Re-initializing SystemForegroundService after a request to shut-down
Bản sửa lỗi cho sự cố này đã được ra mắt trong WorkManager phiên bản 2.10.5.
Nếu ứng dụng của bạn gặp phải ngoại lệ này, hãy cập nhật lên phiên bản WorkManager mới nhất và báo cáo mọi vấn đề còn tồn tại cho trình theo dõi sự cố của WorkManager.
ForegroundServiceStartNotAllowedException
Lỗi:
Hệ thống gửi ra ForegroundServiceStartNotAllowedException.
Nguyên nhân:
Điều này thường xảy ra 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 miễn trừ hợp lệ.
Kể từ Android 12 (cấp độ API 31), các ứng dụng không được phép khởi động dịch vụ nền trước 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ụ nền trước từ nền sau và không đáp ứng các yêu cầu của một trong những trường hợp miễn trừ, thì hệ thống sẽ gửi ForegroundServiceStartNotAllowedException. Hệ thống cũng làm điều 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ó 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ố quá trình xử lý rồi chạy một dịch vụ 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 đưa ứng dụng vào 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 ra 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 nếu ứng dụng của bạn chạy một dịch vụ trên nền trước để phản hồi 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 nghiêm ngặt hơn trong 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 đang nhắm đến, hãy xem 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 cho 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 dịch vụ 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 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 chạy một dịch vụ trên nền trước từ chế độ nền.
SecurityException
Lỗi:
Hệ thống gửi raSecurityException.
Nguyên nhân:
Ứng dụng của bạn đã cố khởi chạy một dịch vụ nền trước mà không có các quyền cần thiết.
- Nếu một ứng dụng nhắm đến Android 9 (cấp độ API 28) trở lên, thì ứng dụng đó phải có quyền
FOREGROUND_SERVICEđể chạy dịch vụ nền trước. - Nếu ứng dụng nhắm đến Android 14 (cấp độ API 34) trở lên, thì ứng dụng phải đáp ứng tất cả điều kiện tiên quyết cho loại dịch vụ nền trước của ứng dụng. 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ụ 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ụ nền trước yêu cầu quyền khi bắt đầu chạy cụ thể. Ví dụ: một dịch vụ 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ụ nền trước yêu cầu quyền khi bắt đầu chạy cụ thể. Ví dụ: một dịch vụ nền trước nhắn tin từ xa phải có quyền
- Trong một số trường hợp, có thêm các quy định hạn chế khi đang sử dụng đối với các quyền mà một số loại dịch vụ nền trước cần có. Các quyền này chỉ được cấp cho ứng dụng khi ứng dụng chạy ở 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 ứng dụng đang chạy ở chế độ nền, thì hệ thống sẽ gửi một
SecurityExceptionngay cả khi ứng dụng có quyền miễn trừ để 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 Các hạn chế khi khởi động dịch vụ nền trước cần có quyền khi đang dùng.- Bạn có thể nhận được
SecurityExceptionnếu đã yêu cầu các quyền cần thiết nhưng lại bắt đầu dịch vụ 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ụ 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ụ 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.