Tombol fitur dan mode Canary

Media3 memperkenalkan pengoptimalan baru, peningkatan perilaku, dan peningkatan arsitektur di seluruh library-nya. Meskipun perubahan ini diuji dan diverifikasi secara menyeluruh sebelum dirilis, Media3 menyertakan infrastruktur tombol fitur terpusat (androidx.media3.common.Flags) yang berpusat pada mode Canary untuk memberi aplikasi kontrol atas cara dan waktu perilaku baru diterapkan.

Halaman ini menjelaskan cara kerja mode Canary dan tombol fitur, serta cara menggunakannya dalam aplikasi untuk mengurangi risiko upgrade di seluruh rilis, menjalankan peluncuran terkontrol, dan mengonfigurasi rollback darurat.

Ringkasan

Mode Canary mengelompokkan peningkatan library yang baru diperkenalkan dan diverifikasi di bawah tombol global terpadu:

  • Diaktifkan secara default: Dalam rilis Media3 standar, mode Canary diaktifkan secara default (true). Hal ini memastikan aplikasi Anda otomatis mendapatkan manfaat dari peningkatan performa, pengoptimalan, dan kemampuan baru yang aman.
  • Kemampuan memilih tidak ikut dan melakukan rollback: Aplikasi dapat menonaktifkan mode Canary secara global atau mengganti tombol fitur tertentu satu per satu saat runtime.
  • Tanpa kompleksitas pengaitan: Flag dikelola melalui class Flags pusat dalam modul common, sehingga tidak memerlukan setter atau objek konfigurasi khusus di berbagai komponen.

Mengapa menggunakan Flag di aplikasi Anda?

Meskipun mode Canary aktif secara default, mengintegrasikan Flags dengan framework konfigurasi atau eksperimen aplikasi Anda memberikan beberapa manfaat:

1. Memitigasi risiko upgrade versi

Mengupgrade versi library utama atau minor dalam produksi dapat menyebabkan interaksi yang tidak terduga pada perangkat OEM tertentu atau pipeline media kustom. Saat mengupdate Media3, Anda dapat menggunakan mode Canary dan konfigurasi jarak jauh untuk alur upgrade yang lebih aman di seluruh rilis:

  1. Mengirimkan update dengan mode Canary dinonaktifkan: Merilis versi Media3 baru dengan mode Canary dinonaktifkan akan mempertahankan set fitur rilis sebelumnya (dengan Canary diaktifkan), sehingga Anda dapat memverifikasi stabilitas library dasar dan perbaikan bug umum dalam produksi sebelum mengadopsi perilaku baru.
  2. Aktifkan mode Canary secara progresif: Gunakan konfigurasi jarak jauh untuk mengaktifkan mode Canary secara bertahap di seluruh kelompok pengguna (misalnya, 5% → 25% → 100%) atau jalankan eksperimen A/B untuk mengukur dampak metrik.
  3. Roll back jika diperlukan: Jika terjadi regresi pada perangkat tertentu, nonaktifkan mode Canary atau ID tanda tertentu dari jarak jauh tanpa memerlukan rilis aplikasi darurat.
  4. Adopsi sebagai default: Setelah diverifikasi, biarkan mode Canary diaktifkan secara default hingga upgrade versi berikutnya, saat fitur Canary yang diverifikasi sebelumnya menjadi permanen.

Kotlin

// Enable or disable Canary mode globally (defaults to true).
Flags.setCanaryModeEnabled(false)

Java

// Enable or disable Canary mode globally (defaults to true).
Flags.setCanaryModeEnabled(false);

2. Rilis bertahap yang terkontrol dan pengujian A/B

Daripada mengekspos 100% pengguna Anda ke perilaku library baru sekaligus, Anda dapat menghubungkan Flags ke konfigurasi jarak jauh atau sistem eksperimen.

Anda dapat mengaktifkan mode Canary secara bertahap (misalnya, 5% pengguna → 25% → 100%) atau menjalankan eksperimen A/B untuk mengukur dampak pengoptimalan baru pada metrik pemutaran inti seperti latensi startup, rasio buffering ulang, dan kegagalan pemutaran.

3. Tombol penghentian jarak jauh dan rollback cepat

Jika regresi terjadi dalam produksi pada model perangkat atau versi OS tertentu, Anda dapat menonaktifkan mode Canary dari jarak jauh (atau ID tanda tertentu yang bertanggung jawab) menggunakan konfigurasi sisi server. Tindakan ini akan langsung mengembalikan library ke perilaku penggantian lama yang stabil untuk pengguna yang terpengaruh tanpa memerlukan hotfix aplikasi darurat atau rilis biner.

Mengonfigurasi mode dan flag Canary

Flags API menyediakan metode untuk mengontrol mode Canary global dan penggantian tanda individual.

Mode Canary Global

Untuk mengaktifkan atau menonaktifkan semua peningkatan yang tercakup dalam mode Canary:

Kotlin

// Enable or disable Canary mode globally (defaults to true).
Flags.setCanaryModeEnabled(false)

Java

// Enable or disable Canary mode globally (defaults to true).
Flags.setCanaryModeEnabled(false);

Mengganti flag satu per satu

Anda juga dapat secara eksplisit mengaktifkan atau menonaktifkan flag tertentu secara terpisah dari setelan mode Canary global:

Kotlin

// Explicitly enable an experimental flag.
Flags.enableFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION)

// Explicitly disable a flag.
Flags.disableFlag(Flags.FLAG_DYNAMIC_SCHEDULING)

Java

// Explicitly enable an experimental flag.
Flags.enableFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION);

// Explicitly disable a flag.
Flags.disableFlag(Flags.FLAG_DYNAMIC_SCHEDULING);

Penggantian eksplisit selalu lebih diutamakan daripada setelan default mode Canary global.

Memeriksa status tanda

Untuk memeriksa apakah mode Canary atau flag tertentu aktif dalam kode Anda:

Kotlin

// Query whether Canary mode is active globally.
val isCanaryActive = Flags.isCanaryModeEnabled()

// Query whether a specific flag is active.
val isFeatureActive = Flags.isEnabled(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION)

Java

// Query whether Canary mode is active globally.
boolean isCanaryActive = Flags.isCanaryModeEnabled();

// Query whether a specific flag is active.
boolean isFeatureActive = Flags.isEnabled(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION);

Urutan resolusi flag

Saat Media3 memeriksa apakah suatu fitur diaktifkan saat runtime, Media3 akan me-resolve status dalam urutan berikut:

  1. Penggantian runtime eksplisit: Jika enableFlag atau disableFlag dipanggil untuk ID flag, nilai penggantian tersebut akan ditampilkan.
  2. Status library statis: Jika flag dinonaktifkan secara statis (misalnya, fitur pengembangan awal yang belum siap untuk mode Canary) atau diaktifkan secara statis (fitur yang lulus dari mode Canary yang mempertahankan penggantian penonaktifan sementara), nilai statis tersebut akan ditampilkan.
  3. Status mode Canary: Jika tidak, tanda akan mengikuti setelan mode Canary global (diaktifkan jika mode Canary adalah true, dinonaktifkan jika false).

Persyaratan inisialisasi

Konfigurasikan flag sebelum membuat instance komponen Media3 apa pun (seperti ExoPlayer, Transformer, atau MediaSession):

  • Penyiapan awal: Konfigurasikan Flags selama startup aplikasi (misalnya, di dalam Application.onCreate) atau sebelum melakukan inisialisasi lapisan media aplikasi Anda.
  • Keamanan thread: Komponen Media3 membaca flag selama pembuatan instance dan menyebarkan nilai tersebut ke thread pemutaran dan pemrosesan internal. Pastikan konfigurasi flag terjadi sebelum membuat komponen Media3. Mengubah flag saat pemutar atau transformer berjalan secara aktif tidak didukung.

Mengintegrasikan dengan konfigurasi jarak jauh

Arsitektur yang direkomendasikan adalah mengekspos tiga parameter di platform konfigurasi jarak jauh Anda:

  • media3_canary_mode_enabled (Boolean): Tombol global untuk mode Canary (defaultnya adalah true).
  • media3_force_enable_flags (Daftar Bilangan Bulat): ID flag tertentu yang akan diaktifkan secara paksa untuk uji coba yang ditargetkan.
  • media3_force_disable_flags (Daftar Bilangan Bulat): ID tanda tertentu yang akan dinonaktifkan secara paksa jika ditemukan masalah.

Terapkan nilai ini selama startup sebelum membuat instance pemutar:

Kotlin

fun initializeMedia3Flags(
  canaryModeEnabled: Boolean,
  forceEnabledFlags: List<Int>,
  forceDisabledFlags: List<Int>,
) {
  // 1. Set global Canary mode state.
  Flags.setCanaryModeEnabled(canaryModeEnabled)

  // 2. Apply explicit force-enable overrides.
  for (flagId in forceEnabledFlags) {
    Flags.enableFlag(flagId)
  }

  // 3. Apply explicit force-disable overrides (remote kill switch).
  for (flagId in forceDisabledFlags) {
    Flags.disableFlag(flagId)
  }
}

Java

public static void initializeMedia3Flags(
    boolean canaryModeEnabled,
    List<Integer> forceEnabledFlags,
    List<Integer> forceDisabledFlags) {
  // 1. Set global Canary mode state.
  Flags.setCanaryModeEnabled(canaryModeEnabled);

  // 2. Apply explicit force-enable overrides.
  for (int flagId : forceEnabledFlags) {
    Flags.enableFlag(flagId);
  }

  // 3. Apply explicit force-disable overrides (remote kill switch).
  for (int flagId : forceDisabledFlags) {
    Flags.disableFlag(flagId);
  }
}

Menguji dengan flag

Saat menulis pengujian unit atau pengujian Robolectric untuk jalur kode yang terpengaruh oleh tombol fitur, gunakan androidx.media3.test.utils.Media3FlagsRule (tersedia dalam modul media3-test-utils) untuk memastikan pengujian tidak mengganggu status statis satu sama lain.

Pembersihan otomatis dengan Media3FlagsRule

Menambahkan Media3FlagsRule akan memastikan bahwa semua penggantian tanda dan modifikasi mode Canary otomatis direset setelah setiap pengujian:

Kotlin

class MyPlayerTest {

  @get:Rule val flagsRule = Media3FlagsRule(this)

  @Test
  fun playback_withFeatureFlagEnabled() {
    Flags.enableFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION)
    // Run test with the flag enabled...
  }
}

Java

public static class MyPlayerTest {

  @Rule public final Media3FlagsRule flagsRule = new Media3FlagsRule(this);

  @Test
  public void playback_withFeatureFlagEnabled() {
    Flags.enableFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION);
    // Run test with the flag enabled...
  }
}

Pengujian berparameter

Anda dapat menggabungkan Media3FlagsRule dengan anotasi @BindFlag dan @BindCanaryMode untuk menjalankan pengujian berparameter di seluruh status flag:

Kotlin

class MyParameterizedPlayerTest {

  @BindCanaryMode var canaryMode: Boolean = false

  @BindFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION) var perStreamProgression: Boolean = false

  @get:Rule val flagsRule = Media3FlagsRule(this)

  @Test
  fun playback() {
    // Flags are automatically set for each test parameter combination.
  }
}

Java

public static class MyParameterizedPlayerTest {

  @BindCanaryMode public boolean canaryMode;

  @BindFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION)
  public boolean perStreamProgression;

  @Rule public final Media3FlagsRule flagsRule = new Media3FlagsRule(this);

  @Test
  public void playback() {
    // Flags are automatically set for each test parameter combination.
  }
}

Diagnostik dan logging

Media3 menyediakan alat diagnostik untuk memverifikasi flag aktif dan status mode Canary selama inisialisasi pemutaran dan saat runtime.

Log inisialisasi

Saat diinisialisasi, instance ExoPlayer akan mencetak status Canary yang aktif dan penggantian eksplisit apa pun ke logcat bersama dengan versi library:

ExoPlayerImpl: Init 59a18ab [AndroidXMedia3/1.10.1] [flame, Pixel 4, Google, 33] [Canary:ON]

Jika penggantian aktif, hanya penyimpangan dari status default yang akan dicantumkan:

ExoPlayerImpl: Init 59a18ab [AndroidXMedia3/1.10.1] [flame, Pixel 4, Google, 33] [Canary:ON, Overrides: enabled=[1], disabled=[3]]

Pemeriksaan terprogram

Anda dapat mengambil string diagnostik yang diformat atau daftar penggantian kueri secara terprogram (misalnya, untuk menyertakan status flag dalam laporan error atau analisis aplikasi):

Kotlin

// Get formatted string representing active Canary state and overrides.
val flagLogString = Flags.getLogString()

// Query explicit override IDs if needed.
val enabledFlags = Flags.getEnabledOverrides()
val disabledFlags = Flags.getDisabledOverrides()

Java

// Get formatted string representing active Canary state and overrides.
String flagLogString = Flags.getLogString();

// Query explicit override IDs if needed.
int[] enabledFlags = Flags.getEnabledOverrides();
int[] disabledFlags = Flags.getDisabledOverrides();

Siklus proses flag

Flag di Media3 dirancang agar bersifat sementara:

  1. Pengembangan: Pengoptimalan atau fitur baru ditambahkan di balik ID tanda di Flags.java.
  2. Mode Canary: Setelah diverifikasi dan siap untuk penggunaan umum, fitur ini akan aktif dalam mode Canary di seluruh rilis.
  3. Promosi & Pembersihan: Setelah periode pengujian yang membuktikan stabilitas dalam produksi, fitur ini dipromosikan untuk diaktifkan secara permanen di library, dan konstanta flag, jalur kode penggantian, dan pemeriksaan bersyarat akan dihapus.

Jika Anda mengalami masalah dengan tombol fitur, laporkan di Issue Tracker GitHub AndroidX Media3 agar tim dapat mengatasinya sebelum promosi permanen.