การเพิ่มความปลอดภัยของเสียงเบื้องหลัง

ตั้งแต่ Android 17 เป็นต้นไป เฟรมเวิร์กเสียงจะบังคับใช้ข้อจำกัดเกี่ยวกับการโต้ตอบกับเสียงในเบื้องหลัง ซึ่งรวมถึงการเล่นเสียง คำขอโฟกัสเสียง และ API การเปลี่ยนแปลงระดับเสียง เพื่อให้มั่นใจว่าการเปลี่ยนแปลงเหล่านี้เริ่มต้นโดยเจตนาของผู้ใช้

แอปทั้งหมดที่ทำงานบน Android 17 ซึ่งมีการโต้ตอบกับเสียงในเบื้องหลังเหล่านี้ต้องมีกิจกรรมที่มองเห็นได้หรือต้องเรียกใช้บริการที่ทำงานอยู่เบื้องหน้าที่ไม่ใช่ประเภท SHORT_SERVICE ซึ่งจะมีผลไม่ว่าแอปจะกำหนดเป้าหมายเป็น API ระดับ 37 หรือไม่ก็ตาม

หากแอปกำหนดเป้าหมายเป็น Android 17 (ระดับ API 37) จะมีข้อจำกัดเพิ่มเติม หากแอปทำงานในเบื้องหลัง แอปต้องใช้บริการที่ทำงานอยู่เบื้องหน้าซึ่งมีความสามารถขณะใช้งาน (WIU) (บริการที่ทำงานอยู่เบื้องหน้าจะได้รับความสามารถ WIU หากเริ่มทำงานเพื่อตอบสนองต่อการดำเนินการที่ผู้ใช้เริ่มหรือขณะที่ผู้ใช้มองเห็นแอป) อย่างไรก็ตาม ข้อกำหนดสำหรับความสามารถของ WIU จะได้รับการยกเว้นหากแอปได้รับสิทธิ์สัญญาณปลุกเจาะจง และกำลังทำการเปลี่ยนแปลงสตรีมเสียงที่มีแอตทริบิวต์ USAGE_ALARM

หากแอปพยายามเรียกใช้ Audio API ขณะที่แอปไม่ได้อยู่ในวงจรที่ถูกต้อง API การเล่นเสียงและการเปลี่ยนแปลงระดับเสียงจะไม่ทำงานโดยไม่มีการแสดงข้อยกเว้นหรือข้อความแสดงข้อผิดพลาด API โฟกัสเสียงไม่สำเร็จโดยมีรหัสผลลัพธ์ AUDIOFOCUS_REQUEST_FAILED

เหตุผลที่เราทำการเปลี่ยนแปลงนี้

จุดประสงค์ของการใช้ข้อจำกัดเหล่านี้คือเพื่อลดประสบการณ์การใช้งานที่เกิดข้อบกพร่องเกี่ยวกับเสียงในเบื้องหลังโดยไม่ตั้งใจ ตัวอย่างเช่น

  • แอปที่เล่นเสียงโดยไม่มีบริการที่ทำงานอยู่เบื้องหน้าอาจหยุดทำงานชั่วคราว เมื่อแอปกลับมาทำงานอีกครั้งในที่สุด แอปจะกลับมาเล่นเสียงต่อโดยไม่คาดคิด ซึ่งอาจเป็นเวลาหลายชั่วโมงต่อมา
  • แอปที่เล่นเสียงโดยไม่มีบริการที่ทำงานอยู่เบื้องหน้าจะพบข้อจำกัดในการเรียกใช้ที่แตกต่างกัน ซึ่งส่งผลให้ประสิทธิภาพของเสียงขาดๆ หายๆ
  • การเล่นแยกออกจากวงจรกิจกรรม ซึ่งอาจส่งผลให้เซสชันการเล่นรั่วไหลหรือเหตุการณ์โฟกัสรั่วไหล ซึ่งจะดำเนินต่อไปโดยที่ผู้ใช้ไม่มีวิธีหยุดการเล่น

เราขอแนะนำให้นักพัฒนาแอปทดสอบแอปและแสดงความคิดเห็นเกี่ยวกับการเปลี่ยนแปลงลักษณะการทำงาน หากมีกรณีการใช้งานเสียงโดยเจตนาที่ได้รับผลกระทบในทางลบ โปรดรายงานปัญหาโดยใช้เครื่องมือติดตามปัญหาความเข้ากันได้ของแอป Android 17

ระบุกรณีการใช้งานเสียงเบื้องหลังที่ได้รับผลกระทบ

ตรวจสอบการติดตั้งใช้งานการเล่นเสียงและระบุว่าแอปของคุณตั้งใจที่จะให้ฟังก์ชันการโต้ตอบกับเสียงในเบื้องหลังแม้ในสถานการณ์แบบมีเงื่อนไขหรือไม่

หากแอปของคุณตั้งใจที่จะเล่นเสียงหรือใช้ API เสียงขณะแสดงกิจกรรมที่ผู้ใช้มองเห็นเท่านั้น ซึ่งรวมถึงการใช้โหมดการแสดงภาพซ้อนภาพ (PiP) แอปจะไม่ได้รับผลกระทบจากการเปลี่ยนแปลงเหล่านี้

หากแอปของคุณมีฟังก์ชันการทำงานของ VoIP ซึ่งรวมถึงแอปวิดีโอคอล แอปจะต้องเป็นไปตามข้อกำหนดที่แนะนำสำหรับการเล่นอยู่แล้ว (โดยปกติจะใช้ Telecom API ที่แนะนำ) เพื่อบันทึกเสียงได้สำเร็จ จึงไม่น่าจะได้รับผลกระทบ

หากแอปของคุณตั้งใจที่จะเล่นเสียงต่อขณะที่หน้าจอปิดอยู่หรือขณะที่กิจกรรมของคุณไม่ปรากฏ ซึ่งมักพบได้บ่อยที่สุดในแอปสตรีมมิงเพลงหรือแอปพอดแคสต์ แอปของคุณจะถือว่ามีฟังก์ชันการทำงานของเสียงในเบื้องหลังและต้องเป็นไปตามข้อกำหนดใหม่

สถานการณ์เสียงพื้นหลังที่มีแนวโน้มจะได้รับผลกระทบ

หากแอปไม่เป็นไปตามรูปแบบการโต้ตอบด้วยเสียงอย่างต่อเนื่องซึ่งเริ่มต้นขณะที่แอปเปิดอยู่ หรือเพื่อตอบสนองต่อทริกเกอร์ที่ผู้ใช้ระบุอย่างชัดเจน ก็มีแนวโน้มว่าฟังก์ชันการทำงานของแอปจะถูกระงับโดยไม่มีการแจ้งเตือน

ตัวอย่างเช่น หากแอปเริ่มบริการที่ทำงานอยู่เบื้องหน้าเพื่อตอบสนองต่อ BOOT_COMPLETE และพยายามโต้ตอบกับเสียง ระบบจะระงับบริการดังกล่าว

แนวทางปฏิบัติแนะนำสำหรับเสียงพื้นหลังเพื่อลดผลกระทบ

  • ใช้คอมโพเนนต์ MediaSessionService ของไลบรารี Jetpack media3 เพื่อจัดการการเล่นเสียงขณะล็อกหน้าจอหรือขณะใช้แอปอื่น

    หากทำเช่นนั้น แอปของคุณจะไม่ได้รับผลกระทบจากการเพิ่มความเข้มงวดในเบื้องหลังเนื่องจากไลบรารีจะช่วยจัดการวงจรการเล่น

  • หากไม่ได้ใช้ประโยชน์จากไลบรารี media3 คุณจะต้องเริ่ม mediaPlayback FGS ด้วยตนเอง เริ่มบริการที่ทำงานอยู่เบื้องหน้าเสมอขณะที่แอปอยู่เบื้องหน้าหากอาจมีเสียงเล่นอยู่เบื้องหลัง

    ตัวอย่างเช่น หากแอปของคุณเป็นแอปสตรีมมิงวิดีโอซึ่งโดยปกติจะทำงานอยู่เบื้องหน้าเท่านั้น แต่มีฟังก์ชันที่ผู้ใช้สามารถเล่นต่อได้ขณะที่หน้าจอปิดอยู่ เมื่อเกิดทริกเกอร์การเล่นที่ผู้ใช้เริ่มต้น แอปก็ควรเริ่มบริการที่ทำงานอยู่เบื้องหน้า

    การดำเนินการนี้ช่วยให้มั่นใจได้ว่าบริการที่ทำงานอยู่เบื้องหน้าจะเริ่มต้นด้วยความสามารถ WIU

  • เปิดใช้งาน mediaPlayback FGS ต่อไปในระหว่างที่เกิดความล้มเหลวชั่วคราวเป็นเวลาไม่เกิน 10 นาที

    หากแอปมีข้อผิดพลาดชั่วคราว เช่น ปัญหาเกี่ยวกับการบัฟเฟอร์เนื่องจากกิจกรรมเครือข่าย หรือมีการหยุดชะงักชั่วคราวที่คาดไว้ เช่น AUDIOFOCUS_LOSS_TRANSIENT ความตั้งใจที่จะเล่นควรดำเนินต่อไป ดังนั้น FGS ของคุณควรยังคงทำงานอยู่

  • หยุดบริการที่ทำงานอยู่เบื้องหน้าเมื่อสิ้นสุดการเล่น และเริ่มเล่นอีกครั้งเฉพาะในกรณีที่ผู้ใช้กลับมาเล่นอย่างชัดแจ้ง

    ในกรณีที่มีสัญญาณถาวรให้สิ้นสุดการเล่น (เช่น เนื้อหาเล่นจบแล้วโดยไม่มีการเล่นอัตโนมัติ, AUDIOFOCUS_LOSS, เหตุการณ์หยุดชั่วคราวจาก UMO หรือเหตุการณ์คีย์สื่อ) หรือความล้มเหลวที่กู้คืนไม่ได้ แอปควรหยุดการโต้ตอบด้วยเสียง หยุดบริการที่ทำงานอยู่เบื้องหน้า และสิ้นสุดเซสชันสื่อ การดำเนินการทั้งหมดนี้สอดคล้องกับแนวคิดของผู้ใช้เกี่ยวกับ "การสิ้นสุด" การโต้ตอบกับเสียงในเบื้องหลังที่ต้องการ หลังจากดำเนินการนี้แล้ว แอปของคุณจะไม่มีความสามารถในการโต้ตอบกับเสียงในเบื้องหลังอีกต่อไป

    ต่อมา หากผู้ใช้กลับมาเล่นต่ออย่างชัดแจ้ง เช่น ผ่าน UI ของแอปหรือผ่านปุ่มเล่นของ Universal Media Object ความตั้งใจที่จะเริ่มเล่นเสียงควรกลับมา ซึ่งส่งผลให้ FGS เริ่มทำงานใหม่

  • ทดสอบลักษณะการเล่นเสียงด้วยคำสั่ง adb shell

การทดสอบการเปลี่ยนแปลง

คุณทดสอบการปฏิบัติตามข้อกำหนดของแอปในแอปที่ใช้ Android 17 ขึ้นไป (เริ่มตั้งแต่เวอร์ชันเบต้า 3) ได้โดยเรียกใช้คำสั่ง ADB ต่อไปนี้

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

คำสั่งนี้มีตัวเลือกต่อไปนี้

  • enable: เปิดใช้ข้อจำกัดการเพิ่มความปลอดภัยของเสียงทั้งหมดสำหรับแอปทั้งหมด ข้อกำหนดสำหรับบริการที่ทำงานอยู่เบื้องหน้า WIU จะมีผลไม่ว่าแอปจะกำหนดเป้าหมายเป็น Android 17 (ระดับ API 37) หรือไม่ก็ตาม นอกจากนี้ ข้อกำหนดนี้ยังมีผลบังคับใช้แม้ว่าแอปจะทำการเปลี่ยนแปลงสตรีมสัญญาณปลุกและมีสิทธิ์สัญญาณปลุกเจาะจงก็ตาม

  • disable: ปิดใช้ข้อจำกัดการเพิ่มความปลอดภัยของเสียงทั้งหมด

  • throw: เปิดใช้ข้อจำกัดการเพิ่มความปลอดภัยของเสียงทั้งหมดสำหรับแอปทั้งหมด เช่น enable นอกจากนี้ แฟล็กนี้ยังเปิดใช้การแจ้งเตือนข้อผิดพลาดที่ชัดเจน โดยแสดง IllegalStateException สำหรับการโต้ตอบเกี่ยวกับระดับเสียงและโฟกัส สำหรับการเล่นเสียง เมธอดการเขียนจะแสดงรหัสข้อผิดพลาดอย่างต่อเนื่อง สำหรับโหมดการเล่นที่ไม่มีการเขียนอย่างชัดเจน แอปจะขัดข้อง

ใช้ adb dumpsys audio หรือ logcat เพื่อระบุว่าแอปพบข้อผิดพลาดแบบไม่แจ้งเตือนเนื่องจากการบังคับใช้การเพิ่มความปลอดภัยของเสียงหรือไม่ หากมี จะมีรายการที่ขึ้นต้นด้วย AudioHardening พร้อมชื่อแพ็กเกจของคุณ หากข้อความมี level: full แสดงว่าแอปของคุณกำลังเรียกใช้บริการที่ทำงานอยู่เบื้องหน้า แต่บริการดังกล่าวไม่มีความสามารถขณะใช้งาน หากข้อความมี level: partial แสดงว่าแอปไม่ได้เรียกใช้บริการที่ทำงานอยู่เบื้องหน้าเลย

ทำความเข้าใจ FGS ที่มีความสามารถขณะใช้งาน

โดยทั่วไปแล้ว บริการที่ทำงานอยู่เบื้องหน้า (FGS) ต้องเปิดใช้งานขณะที่แอปทำงานอยู่เบื้องหน้าเพื่อขยายการดำเนินการที่ผู้ใช้เริ่มต้น ในบางกรณี แอปจะได้รับอนุญาตให้เปิดใช้บริการที่ทำงานอยู่เบื้องหน้าขณะที่แอปทำงานอยู่ในเบื้องหลัง อย่างไรก็ตาม บริการที่ทำงานอยู่เบื้องหน้าเหล่านี้มักไม่ได้รับความสามารถขณะใช้งาน (WIU)

WIU ทำหน้าที่เป็นประตูรักษาความปลอดภัย โดยจะป้องกันไม่ให้ FGS ที่เริ่มทำงานจากเบื้องหลังมีส่วนร่วมในพฤติกรรมที่ละเอียดอ่อนบางอย่างเมื่อผู้ใช้อาจไม่ทราบถึงกิจกรรมของแอป ซึ่งจะป้องกันไม่ให้แอปเข้าถึงข้อมูลที่ละเอียดอ่อน เช่น ตำแหน่ง กล้อง หรือไมโครโฟน และตั้งแต่ Android 17 เป็นต้นไป ระบบจะบล็อก API เสียงที่โดยปกติแล้วต้องใช้บริบท UI ที่มองเห็นได้ด้วย

ข้อมูลอ้างอิงที่มีประโยชน์มีดังนี้

  • FGS มาตรฐาน: บริการที่เริ่มต้นขณะที่แอปมองเห็นได้หรือได้รับความสามารถในการเปิดกิจกรรมในเบื้องหลังจะได้รับสิทธิ์เข้าถึง WIU
  • FGS ที่เริ่มทำงานในเบื้องหลัง (BFSL): ส่วนใหญ่ไม่ให้สิทธิ์เข้าถึง WIU ข้อยกเว้นหลักที่ให้สิทธิ์ WIU คือการโต้ตอบที่เกี่ยวข้องกับความตั้งใจของผู้ใช้อย่างชัดเจน เช่น การคลิกการแจ้งเตือน การโต้ตอบกับวิดเจ็ต หรือเหตุการณ์คีย์สื่อจากอุปกรณ์ภายนอก
  • FGS ที่ระบบเริ่มทำงาน: บริการที่ทำงานอยู่เบื้องหน้าจะได้รับสิทธิ์เข้าถึง WIU หากเริ่มทำงานโดยการมอบสิทธิ์ของเซิร์ฟเวอร์ระบบ (เช่น จากไลบรารี Telecom Jetpack) หรือโดยการเชื่อมโยงระบบที่แสดงถึงสถานะเบื้องหน้าที่ยกระดับเพื่อทำฟังก์ชันการทำงานเฉพาะ (เช่น สำหรับ VoiceInteractionService)

อ่านข้อมูลเพิ่มเติมได้ที่ข้อจำกัดในการเริ่มบริการที่ทำงานอยู่เบื้องหน้าจากเบื้องหลัง

รายการ Audio API ทั้งหมดที่ได้รับผลกระทบ

ฟังก์ชันเสียง

ผลลัพธ์

API ที่ได้รับผลกระทบ

การเล่นเสียง

ปิดเสียงการเล่นแล้ว

ไม่มีข้อยกเว้น ไม่มีข้อความแสดงข้อผิดพลาดจาก API ใดๆ

AudioTrack.write()

(NDK) AAudioStream_write

OpenSL ES สำหรับ Android

คลังสื่อฝั่งไคลเอ็นต์ที่จัดการการเล่น เช่น media3, Exoplayer และ Oboe อาจได้รับผลกระทบด้วย

คำขอโฟกัสเสียง

แสดงผล AUDIOFOCUS_REQUEST_FAILED

ไม่มีผลต่อการเล่นเสียงของแอปอื่นๆ ไม่มีการโฟกัส

AudioManager.requestAudioFocus()

API ระดับเสียงและโหมดเสียงเรียกเข้า

ไม่มีผลต่อโหมดหรือระดับเสียงของเสียงเรียกเข้า (ระบบจะละเว้นการเรียกใช้เมธอดโดยไม่แจ้งให้ทราบ)

ไม่มีข้อยกเว้น ไม่มีข้อความแสดงข้อผิดพลาดจาก API ใดๆ

AudioManager.setStreamVolume()

AudioManager.setStreamMute()

AudioManager.adjustStreamVolume()

AudioManager.adjustVolume()

AudioManager.adjustSuggestedStreamVolume()

AudioManager.setRingerMode()