Tăng cường bảo mật âm thanh nền

Kể từ Android 17, khung âm thanh sẽ thực thi các quy tắc hạn chế đối với hoạt động tương tác âm thanh ở chế độ nền, bao gồm cả việc phát âm thanh, yêu cầu lấy tiêu điểm âm thanh và các API thay đổi âm lượng để đảm bảo người dùng chủ ý bắt đầu những thay đổi này.

Tất cả ứng dụng chạy trên Android 17 có những hoạt động tương tác âm thanh ở chế độ nền này đều phải có một hoạt động hiển thị hoặc phải đang chạy một dịch vụ ở chế độ nền trước không thuộc loại SHORT_SERVICE. Điều này áp dụng cho dù ứng dụng có nhắm đến API cấp 37 hay không.

Nếu một ứng dụng nhắm đến Android 17 (cấp độ API 37), thì sẽ có thêm một hạn chế. Nếu đang chạy ở chế độ nền, ứng dụng phải chạy một dịch vụ nền trước có các chức năng trong khi sử dụng (WIU). (Dịch vụ trên nền trước được cấp các chức năng WIU nếu dịch vụ đó được khởi động để phản hồi một thao tác do người dùng khởi tạo hoặc trong khi người dùng nhìn thấy ứng dụng.) Tuy nhiên, yêu cầu về các chức năng WIU sẽ được miễn nếu ứng dụng đã được cấp quyền chuông báo chính xác và ứng dụng đó đang thực hiện các thay đổi đối với luồng âm thanh có thuộc tính USAGE_ALARM.

Nếu ứng dụng cố gắng gọi các API âm thanh khi ứng dụng không ở trong một vòng đời hợp lệ, thì các API phát âm thanh và thay đổi âm lượng sẽ âm thầm không hoạt động mà không đưa ra một ngoại lệ hoặc cung cấp thông báo lỗi. API quyền phát âm thanh không thành công với mã kết quả AUDIOFOCUS_REQUEST_FAILED.

Lý do có sự thay đổi này

Mục đích của việc áp dụng những quy tắc hạn chế này là giảm các trải nghiệm âm thanh nền không mong muốn do lỗi. Một số ví dụ bao gồm:

  • Các ứng dụng phát âm thanh mà không có dịch vụ nền trước có thể bị đóng băng. Khi ứng dụng được giải phóng, ứng dụng sẽ tiếp tục phát âm thanh một cách bất ngờ, có thể là vài giờ sau đó.
  • Các ứng dụng phát âm thanh mà không có dịch vụ trên nền trước phải đối mặt với nhiều hạn chế khi chạy, dẫn đến hiệu suất âm thanh bị giật.
  • Quá trình phát tách biệt với vòng đời của activity, điều này có thể dẫn đến rò rỉ phiên phát hoặc rò rỉ các sự kiện lấy tiêu điểm tiếp tục mà người dùng không có cách nào dừng phát.

Nhà phát triển nên kiểm thử ứng dụng của mình và gửi ý kiến phản hồi về thay đổi hành vi nếu có trường hợp sử dụng âm thanh có chủ đích nào bị ảnh hưởng tiêu cực. Vui lòng báo cáo mọi vấn đề bằng công cụ theo dõi vấn đề về khả năng tương thích của ứng dụng Android 17 này.

Xác định những trường hợp sử dụng âm thanh ở chế độ nền bị ảnh hưởng

Kiểm tra việc triển khai tính năng phát âm thanh và xác định xem ứng dụng của bạn có ý định cung cấp chức năng tương tác âm thanh ở chế độ nền hay không, ngay cả trong các trường hợp có điều kiện.

Nếu ứng dụng của bạn chỉ nhằm mục đích phát âm thanh hoặc sử dụng các API âm thanh trong khi đang hiển thị một hoạt động mà người dùng có thể thấy, bao gồm cả việc sử dụng chế độ Hình trong hình (PiP), thì ứng dụng đó sẽ không bị ảnh hưởng bởi bất kỳ thay đổi nào trong số này.

Nếu ứng dụng của bạn cung cấp chức năng VOIP, bao gồm cả ứng dụng gọi video, thì ứng dụng đó phải đáp ứng các yêu cầu được đưa ra đối với hoạt động phát (thường là thông qua việc sử dụng API viễn thông được đề xuất) để ghi lại âm thanh thành công. Do đó, ứng dụng của bạn khó có thể bị ảnh hưởng.

Nếu ứng dụng của bạn dự định tiếp tục phát âm thanh khi màn hình tắt hoặc khi hoạt động của bạn không hiển thị (thường thấy nhất trong các ứng dụng phát nhạc trực tuyến hoặc ứng dụng podcast), thì ứng dụng của bạn được coi là cung cấp chức năng âm thanh trong nền và phải đáp ứng các yêu cầu mới.

Các trường hợp âm thanh ở chế độ nền có khả năng bị ảnh hưởng

Nếu ứng dụng của bạn không tuân theo mô hình tiếp tục một hoạt động tương tác bằng âm thanh được bắt đầu khi ứng dụng của bạn đang mở hoặc để phản hồi một thao tác kích hoạt rõ ràng của người dùng, thì có thể chức năng của ứng dụng sẽ bị chặn âm thầm.

Ví dụ: nếu ứng dụng của bạn khởi động một dịch vụ trên nền trước để phản hồi BOOT_COMPLETE và cố gắng tương tác với âm thanh, thì dịch vụ đó sẽ bị chặn.

Các phương pháp hay nhất về âm thanh nền để giảm thiểu tác động

  • Sử dụng thành phần MediaSessionService trong thư viện jetpack media3 để quản lý hoạt động phát âm thanh trong nền.

    Nếu bạn làm như vậy, ứng dụng của bạn sẽ không bị ảnh hưởng bởi quá trình tăng cường bảo mật ở chế độ nền do thư viện hỗ trợ quản lý vòng đời phát.

  • Nếu không tận dụng thư viện media3, bạn sẽ cần phải tự khởi động một FGS mediaPlayback. Luôn khởi động một dịch vụ nền trước trong khi ứng dụng đang ở nền trước nếu có thể xảy ra âm thanh nền.

    Ví dụ: nếu ứng dụng của bạn là một ứng dụng phát trực tuyến video thường chỉ chạy ở nền trước nhưng có một thành phần tương tác để người dùng tiếp tục phát khi màn hình tắt, thì khi xảy ra sự kiện kích hoạt hoạt động phát do người dùng khởi tạo, ứng dụng của bạn vẫn phải bắt đầu một dịch vụ trên nền trước.

    Việc này giúp đảm bảo rằng dịch vụ nền trước được bắt đầu bằng các khả năng WIU.

  • Duy trì trạng thái hoạt động của mediaPlayback FGS trong thời gian xảy ra lỗi tạm thời dưới 10 phút.

    Nếu ứng dụng của bạn gặp lỗi tạm thời, chẳng hạn như vấn đề về việc lưu vào bộ nhớ đệm do hoạt động mạng hoặc có gián đoạn tạm thời dự kiến, chẳng hạn như AUDIOFOCUS_LOSS_TRANSIENT, thì ý định phát phải tiếp tục. Do đó, FGS của bạn phải luôn hoạt động.

  • Dừng dịch vụ nền trước khi kết thúc quá trình phát và chỉ khởi động lại quá trình phát nếu người dùng tiếp tục phát một cách rõ ràng.

    Trong trường hợp có tín hiệu cố định để kết thúc quá trình phát (ví dụ: nội dung đã hoàn tất mà không có chế độ tự động phát, AUDIOFOCUS_LOSS, sự kiện tạm dừng từ UMO hoặc sự kiện nhấn phím đa phương tiện) hoặc lỗi không thể khắc phục, ứng dụng của bạn phải dừng hoạt động tương tác âm thanh, dừng dịch vụ trên nền trước và kết thúc phiên phát nội dung nghe nhìn. Tất cả những việc này tương ứng với quan niệm của người dùng về việc "kết thúc" hoạt động tương tác âm thanh ở chế độ nền mong muốn. Sau khi thực hiện việc này, ứng dụng của bạn sẽ không còn khả năng tương tác với âm thanh ở chế độ nền nữa.

    Sau đó, nếu người dùng tiếp tục phát một cách rõ ràng, chẳng hạn như thông qua giao diện người dùng của ứng dụng hoặc thông qua nút phát của Universal Media Object, thì ý định bắt đầu phát âm thanh sẽ quay trở lại, dẫn đến việc FGS mới bắt đầu.

  • Kiểm thử hành vi phát âm thanh bằng các lệnh adb shell.

Kiểm thử các thay đổi

Bạn có thể kiểm thử mức độ tuân thủ của ứng dụng trên các ứng dụng chạy Android 17 trở lên (bắt đầu từ Beta 3) bằng cách chạy lệnh ADB sau:

adb shell cmd audio set-enable-hardening <enable|disable|throw>

Lệnh này có các lựa chọn sau:

  • enable: Cho phép tất cả các hạn chế về việc tăng cường bảo mật âm thanh cho tất cả các ứng dụng. Yêu cầu đối với dịch vụ nền trước WIU được áp dụng bất kể ứng dụng có nhắm đến Android 17 (cấp độ API 37) hay không. Ngoài ra, yêu cầu này được thực thi ngay cả khi ứng dụng đang thực hiện các thay đổi đối với luồng báo thức và có quyền chuông báo chính xác.

  • disable: Tắt tất cả các hạn chế về việc tăng cường bảo mật âm thanh.

  • throw: Cho phép tất cả các hạn chế tăng cường bảo mật âm thanh cho tất cả các ứng dụng, chẳng hạn như enable. Ngoài ra, cờ này cho phép các lỗi lớn, gửi IllegalStateException cho các lượt tương tác về âm lượng và tiêu điểm. Đối với việc phát âm thanh, phương thức ghi liên tục trả về mã lỗi. Đối với các chế độ phát không có thao tác ghi rõ ràng, ứng dụng sẽ gặp sự cố.

Sử dụng adb dumpsys audio hoặc logcat để xác định xem ứng dụng có gặp phải lỗi âm thầm do việc thực thi biện pháp tăng cường bảo mật âm thanh hay không. Nếu có, sẽ có một mục có tiền tố AudioHardening kèm theo tên gói của bạn. Nếu thông báo chứa level: full, thì ứng dụng của bạn đang chạy một dịch vụ nền trước, nhưng dịch vụ đó không có khả năng khi đang sử dụng. Nếu thông báo chứa level: partial, thì ứng dụng của bạn hoàn toàn không chạy dịch vụ nền trước.

Tìm hiểu về FGS có khả năng sử dụng trong khi đang dùng

Thông thường, dịch vụ trên nền trước (FGS) phải được khởi chạy trong khi ứng dụng ở nền trước để mở rộng các thao tác do người dùng thực hiện. Trong một số trường hợp cụ thể, các ứng dụng được phép chạy một dịch vụ nền trước trong khi ứng dụng đang ở chế độ nền. Tuy nhiên, các dịch vụ trên nền trước này thường không được cấp các chức năng Khi đang sử dụng (WIU).

WIU đóng vai trò là một cổng bảo mật – ngăn FGS bắt đầu từ nền tham gia vào một số hành vi nhạy cảm khi người dùng có thể không biết về hoạt động của ứng dụng. Quyền này ngăn ứng dụng truy cập vào dữ liệu nhạy cảm như vị trí, camera hoặc micrô. Kể từ Android 17, quyền này cũng chặn các API âm thanh thường yêu cầu một ngữ cảnh giao diện người dùng hiển thị.

Sau đây là thông tin tham khảo hữu ích:

  • FGS tiêu chuẩn: Các dịch vụ được bắt đầu trong khi ứng dụng hiển thị hoặc được cấp khả năng khởi chạy hoạt động ở chế độ nền sẽ được cấp quyền truy cập WIU.
  • Dịch vụ ở nền trước bắt đầu từ nền (BFSL): Hầu hết không cấp quyền truy cập WIU. Các trường hợp ngoại lệ chính cho phép WIU là những lượt tương tác liên quan đến ý định rõ ràng của người dùng, chẳng hạn như lượt nhấp vào thông báo, lượt tương tác với tiện ích hoặc sự kiện khoá đa phương tiện từ một thiết bị bên ngoài.
  • Hệ thống đã bắt đầu FGS: Các dịch vụ trên nền trước được cấp quyền truy cập WIU nếu được uỷ quyền bắt đầu bởi máy chủ hệ thống (ví dụ: từ thư viện Telecom jetpack) hoặc bằng các liên kết hệ thống đại diện cho trạng thái nền trước được nâng cao để thực hiện chức năng chuyên dụng (chẳng hạn như đối với VoiceInteractionService).

Đọc thêm trong phần Các hạn chế khi khởi động dịch vụ trên nền trước từ nền.

Danh sách đầy đủ các API âm thanh bị ảnh hưởng

Chức năng âm thanh

Kết quả

Các API bị ảnh hưởng

Phát âm thanh

Đã tắt tiếng phát

Không có trường hợp ngoại lệ, không có thông báo lỗi nào do API cung cấp

AudioTrack.write()

(NDK) AAudioStream_write

OpenSL ES dành cho Android

Mọi thư viện nội dung đa phương tiện phía máy khách quản lý hoạt động phát (chẳng hạn như media3, Exoplayer và Oboe) cũng có thể bị ảnh hưởng.

Yêu cầu quyền phát âm thanh

Trả về AUDIOFOCUS_REQUEST_FAILED

Không ảnh hưởng đến việc phát âm thanh của các ứng dụng khác, không có quyền phát âm thanh

AudioManager.requestAudioFocus()

API âm lượng và chế độ chuông

Không ảnh hưởng đến chế độ chuông hoặc âm lượng (lệnh gọi phương thức sẽ bị bỏ qua một cách âm thầm)

Không có trường hợp ngoại lệ, không có thông báo lỗi nào do API cung cấp

AudioManager.setStreamVolume()

AudioManager.setStreamMute()

AudioManager.adjustStreamVolume()

AudioManager.adjustVolume()

AudioManager.adjustSuggestedStreamVolume()

AudioManager.setRingerMode()