Flagi funkcji i tryb Canary

Media3 wprowadza nowe optymalizacje, ulepszenia działania i ulepszenia architektury we wszystkich bibliotekach. Chociaż te zmiany są dokładnie testowane i weryfikowane przed wprowadzeniem, Media3 zawiera scentralizowaną infrastrukturę flag funkcji (androidx.media3.common.Flags) skupioną wokół trybu Canary, która umożliwia aplikacjom kontrolowanie sposobu i czasu wdrażania nowych zachowań.

Na tej stronie wyjaśniamy, jak działają tryb Canary i flagi funkcji oraz jak możesz ich używać w aplikacji, aby zmniejszyć ryzyko związane z uaktualnieniem w różnych wersjach, przeprowadzać kontrolowane wdrożenia i konfigurować awaryjne wycofania.

Przegląd

Tryb Canary grupuje nowo wprowadzone, zweryfikowane ulepszenia biblioteki pod ujednoliconym, globalnym przełącznikiem:

  • Domyślnie włączone: w standardowych wersjach Media3 tryb Canary jest domyślnie włączony (true). Dzięki temu aplikacja automatycznie korzysta z bezpiecznych ulepszeń wydajności, optymalizacji i nowych funkcji.
  • Możliwość rezygnacji i wycofania: aplikacje mogą wyłączyć tryb Canary globalnie lub zastąpić określone flagi funkcji indywidualnie w czasie działania.
  • Brak skomplikowanych połączeń: flagami zarządza się za pomocą centralnej klasy Flags w module common, co eliminuje potrzebę stosowania niestandardowych metod ustawiających lub obiektów konfiguracji w różnych komponentach.

Dlaczego warto używać flag w aplikacji?

Tryb Canary jest domyślnie aktywny, ale integracja Flags z konfiguracją aplikacji lub platformą eksperymentalną zapewnia kilka korzyści:

1. Zmniejszanie ryzyka związanego z uaktualnieniem wersji

Uaktualnienie głównych lub mniejszych wersji biblioteki w środowisku produkcyjnym może spowodować nieoczekiwane interakcje na określonych urządzeniach OEM lub w niestandardowych potokach multimedialnych. Podczas aktualizowania Media3 możesz używać trybu Canary i zdalnej konfiguracji, aby zapewnić bezpieczniejszy proces uaktualniania w przypadku różnych wersji:

  1. Wdrażanie aktualizacji z wyłączonym trybem Canary: wydanie nowej wersji Media3 z wyłączonym trybem Canary pozwala zachować zestaw funkcji z poprzedniej wersji (z włączonym trybem Canary). Dzięki temu możesz sprawdzić stabilność biblioteki podstawowej i ogólne poprawki błędów w środowisku produkcyjnym przed wdrożeniem nowych zachowań.
  2. Stopniowo włączaj tryb Canary: użyj zdalnej konfiguracji, aby włączać tryb Canary etapami w różnych kohortach użytkowników (np. 5% → 25% → 100%) lub przeprowadzaj eksperymenty A/B, aby mierzyć wpływ na dane.
  3. W razie potrzeby wycofaj zmiany: jeśli na określonych urządzeniach wystąpi regresja, zdalnie wyłącz tryb Canary lub określony identyfikator flagi bez konieczności awaryjnego wydawania aplikacji.
  4. Przyjmij jako domyślne: po zweryfikowaniu pozostaw tryb Canary włączony domyślnie do następnego uaktualnienia wersji, gdy wcześniej zweryfikowane funkcje Canary staną się stałe.

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. kontrolowane wdrażanie etapowe i testy A/B;

Zamiast od razu udostępniać nowe zachowania biblioteki wszystkim użytkownikom, możesz połączyć Flags ze zdalną konfiguracją lub systemem eksperymentów.

Możesz włączać tryb Canary etapami (np. 5% użytkowników → 25% → 100%) lub przeprowadzać eksperymenty A/B, aby mierzyć wpływ nowych optymalizacji na podstawowe dane dotyczące odtwarzania, takie jak opóźnienie uruchomienia, częstotliwość ponownego buforowania i błędy odtwarzania.

3. Zdalny wyłącznik awaryjny i szybkie przywracanie poprzedniej wersji

Jeśli w środowisku produkcyjnym na określonym modelu urządzenia lub w określonej wersji systemu operacyjnego wystąpi regresja, możesz zdalnie wyłączyć tryb Canary (lub konkretny identyfikator flagi, który za to odpowiada) za pomocą konfiguracji po stronie serwera. Spowoduje to natychmiastowe przywrócenie stabilnego, starszego działania biblioteki u użytkowników, których dotyczy problem, bez konieczności wprowadzania awaryjnej poprawki aplikacji lub wersji binarnej.

Konfigurowanie trybu Canary i flag

Interfejs API Flags udostępnia metody kontrolowania globalnego trybu Canary i zastępowania poszczególnych flag.

Globalny tryb Canary

Aby włączyć lub wyłączyć wszystkie ulepszenia objęte trybem 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);

Zastępowanie poszczególnych flag

Możesz też wyraźnie włączyć lub wyłączyć określone flagi niezależnie od globalnego ustawienia trybu Canary:

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);

Jawne zastąpienia zawsze mają pierwszeństwo przed domyślnym globalnym trybem Canary.

Sprawdzanie stanu oznaczenia

Aby sprawdzić, czy tryb Canary lub konkretna flaga są aktywne w kodzie:

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);

Kolejność rozwiązywania zgłoszeń

Gdy Media3 sprawdza, czy funkcja jest włączona w czasie działania, określa stan w tej kolejności:

  1. Jawne zastąpienie środowiska wykonawczego: jeśli dla identyfikatora flagi wywołano metodę enableFlag lub disableFlag, zwracana jest wartość zastąpienia.
  2. Stan biblioteki statycznej: jeśli flaga jest statycznie wyłączona (np. funkcja we wczesnej fazie rozwoju, która nie jest jeszcze gotowa do trybu Canary) lub statycznie włączona (funkcja, która została przeniesiona z trybu Canary i zachowała tymczasową opcję wycofania), zwracana jest ta wartość statyczna.
  3. Stan trybu Canary: w przeciwnym razie flaga jest zgodna z globalnym ustawieniem trybu Canary (włączona, jeśli tryb Canary to true, wyłączona, jeśli false).

Wymagania dotyczące inicjowania

Skonfiguruj flagi przed utworzeniem instancji komponentów Media3 (takich jak ExoPlayer, Transformer lub MediaSession):

  • Wczesna konfiguracja: skonfiguruj Flags podczas uruchamiania aplikacji (np. w Application.onCreate) lub przed zainicjowaniem warstwy multimedialnej aplikacji.
  • Bezpieczeństwo wątków: komponenty Media3 odczytują flagi podczas tworzenia instancji i propagują te wartości do wewnętrznych wątków odtwarzania i przetwarzania. Upewnij się, że konfiguracja flagi następuje przed utworzeniem komponentów Media3. Modyfikowanie flag, gdy odtwarzacze lub transformatory są aktywne, nie jest obsługiwane.

Integracja ze zdalną konfiguracją

Zalecana architektura polega na udostępnieniu 3 parametrów na platformie zdalnej konfiguracji:

  • media3_canary_mode_enabled (wartość logiczna): globalny przełącznik trybu Canary (domyślnie true).
  • media3_force_enable_flags (lista liczb całkowitych): identyfikatory konkretnych flag, które mają zostać wymuszone włączenie w przypadku testów kierowanych.
  • media3_force_disable_flags (lista liczb całkowitych): identyfikatory konkretnych flag, które mają zostać wymuszenie wyłączone w przypadku wykrycia problemu.

Zastosuj te wartości podczas uruchamiania, przed utworzeniem instancji odtwarzacza:

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);
  }
}

Testowanie za pomocą flag

Podczas pisania testów jednostkowych lub testów Robolectric dla ścieżek kodu, na które wpływają flagi funkcji, używaj androidx.media3.test.utils.Media3FlagsRule (dostępnego w module media3-test-utils), aby testy nie zakłócały wzajemnie swojego stanu statycznego.

Automatyczne czyszczenie za pomocą Media3FlagsRule

Dodanie Media3FlagsRule zapewnia, że wszystkie zastąpienia flag i modyfikacje trybu Canary są automatycznie resetowane po każdym teście:

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...
  }
}

Testowanie z użyciem parametrów

Możesz połączyć adnotacje Media3FlagsRule z @BindFlag i @BindCanaryMode, aby przeprowadzać testy z parametrami w różnych stanach 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.
  }
}

Diagnostyka i logowanie

Media3 udostępnia narzędzia diagnostyczne do sprawdzania aktywnych flag i stanów trybu Canary podczas inicjowania odtwarzania i w czasie działania.

Logi inicjowania

Po zainicjowaniu instancji ExoPlayer aktywny stan Canary i wszystkie jawne zastąpienia są drukowane w logcat wraz z wersją biblioteki:

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

Jeśli zastąpienia są aktywne, wyświetlane są tylko odchylenia od stanu domyślnego:

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

Kontrola automatyczna

Sformatowany ciąg diagnostyczny lub listy zastąpień zapytań możesz pobrać automatycznie (np. aby uwzględnić stan flagi w raportach o awariach lub statystykach aplikacji):

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();

Cykl życia flagi

Flagi w Media3 są tymczasowe:

  1. Programowanie: nowa optymalizacja lub funkcja jest dodawana za identyfikatorem flagi w pliku Flags.java.
  2. Tryb Canary: po zweryfikowaniu i przygotowaniu do ogólnego użytku funkcja jest aktywna w trybie Canary we wszystkich wersjach.
  3. Promowanie i czyszczenie: po okresie testowym, który potwierdzi stabilność w środowisku produkcyjnym, funkcja jest na stałe włączana w bibliotece, a stała flagi, zastępcze ścieżki kodu i testy warunkowe są usuwane.

Jeśli napotkasz problem z flagą funkcji, zgłoś go w narzędziu do śledzenia problemów na GitHubie AndroidX Media3, aby zespół mógł go rozwiązać przed stałym promowaniem.