Media3 introduit de nouvelles optimisations, des améliorations comportementales et des améliorations architecturales dans ses bibliothèques. Bien que ces modifications soient minutieusement testées et vérifiées avant leur publication, Media3 inclut une infrastructure centralisée de flags de fonctionnalité (androidx.media3.common.Flags) centrée sur le mode Canary pour permettre aux applications de contrôler comment et quand les nouveaux comportements sont adoptés.
Cette page explique le fonctionnement du mode Canary et des flags de fonctionnalité, et comment les utiliser dans votre application pour réduire les risques de mise à niveau entre les versions, exécuter des déploiements contrôlés et configurer des rollbacks d'urgence.
Présentation
Le mode Canary regroupe les améliorations de bibliothèque récemment introduites et validées sous un bouton d'activation/de désactivation global unifié :
- Activé par défaut : dans les versions Media3 standards, le mode Canary est activé par défaut (
true). Cela permet à votre application de bénéficier automatiquement d'améliorations des performances, d'optimisations et de nouvelles fonctionnalités sécurisées. - Fonctionnalité de désactivation et de rollback : les applications peuvent désactiver le mode Canary de manière globale ou remplacer des flags de fonctionnalité spécifiques individuellement au moment de l'exécution.
- Aucune complexité de câblage : les indicateurs sont gérés via la classe centrale
Flagsdans le modulecommon, ce qui élimine le besoin de setters ou d'objets de configuration personnalisés dans différents composants.
Pourquoi utiliser des indicateurs dans votre application ?
Bien que le mode Canary soit actif par défaut, l'intégration de Flags à la configuration ou au framework de test de votre application offre plusieurs avantages :
1. Limiter les risques liés à la mise à niveau de version
La mise à niveau des versions majeures ou mineures de la bibliothèque en production peut entraîner des interactions inattendues sur des appareils OEM spécifiques ou des pipelines multimédias personnalisés. Lorsque vous mettez à jour Media3, vous pouvez utiliser le mode Canary et la configuration à distance pour un flux de mise à niveau plus sûr entre les versions :
- Déployer la mise à jour avec le mode Canary désactivé : la publication d'une nouvelle version de Media3 avec le mode Canary désactivé conserve à peu près l'ensemble de caractéristiques de la version précédente (avec Canary activé). Cela vous permet de vérifier la stabilité de la bibliothèque de référence et les corrections de bugs générales en production avant d'adopter de nouveaux comportements.
- Activer progressivement le mode Canary : utilisez la configuration à distance pour activer le mode Canary par étapes sur des cohortes d'utilisateurs (par exemple, 5% → 25% → 100%) ou exécutez des tests A/B pour mesurer l'impact des métriques.
- Effectuer un rollback si nécessaire : si une régression se produit sur des appareils spécifiques, désactivez à distance le mode Canary ou l'ID de flag spécifique sans avoir à publier une version d'urgence de l'application.
- Adopter par défaut : une fois la validation effectuée, laissez le mode Canary activé par défaut jusqu'à la prochaine mise à niveau de version, où les fonctionnalités Canary précédemment validées deviennent permanentes.
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. Déploiements progressifs contrôlés et tests A/B
Plutôt que d'exposer 100 % de vos utilisateurs aux nouveaux comportements de la bibliothèque en même temps, vous pouvez associer Flags à une configuration à distance ou à un système d'expérimentation.
Vous pouvez activer le mode Canary par étapes (par exemple, 5 % des utilisateurs → 25 % → 100 %) ou exécuter des tests A/B pour mesurer l'impact des nouvelles optimisations sur les métriques de lecture de base telles que la latence de démarrage, le taux de remise en mémoire tampon et les échecs de lecture.
3. Bouton d'arrêt d'urgence à distance et rollback rapide
Si une régression se produit en production sur un modèle d'appareil ou une version d'OS spécifiques, vous pouvez désactiver à distance le mode Canary (ou l'ID de flag spécifique responsable) à l'aide de la configuration côté serveur. La bibliothèque revient immédiatement à son comportement de remplacement stable et ancien pour les utilisateurs concernés, sans nécessiter de correctif d'urgence ni de version binaire de l'application.
Configurer le mode et les options Canary
L'API Flags fournit des méthodes pour contrôler le mode Canary global et les remplacements d'options individuels.
Mode Canary global
Pour activer ou désactiver toutes les améliorations couvertes par le 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);
Remplacer des options individuelles
Vous pouvez également activer ou désactiver explicitement des options spécifiques indépendamment du paramètre global du mode 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);
Les remplacements explicites prévalent toujours sur le mode Canary par défaut global.
Vérification de l'état du signalement
Pour vérifier si le mode Canary ou un flag spécifique est actif dans votre code :
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);
Ordre de résolution des flags
Lorsque Media3 vérifie si une fonctionnalité est activée au moment de l'exécution, il résout l'état dans l'ordre suivant :
- Remplacement explicite de l'environnement d'exécution : si
enableFlagoudisableFlaga été appelé pour l'ID de l'indicateur, cette valeur de remplacement est renvoyée. - État de la bibliothèque statique : si l'option est désactivée de manière statique (par exemple, une fonctionnalité de développement précoce qui n'est pas encore prête pour le mode Canary) ou activée de manière statique (une fonctionnalité issue du mode Canary qui conserve une solution de remplacement temporaire), cette valeur statique est renvoyée.
- État du mode Canary : sinon, l'option suit le paramètre global du mode Canary (activé si le mode Canary est
true, désactivé sifalse).
Exigences d'initialisation
Configurez les options avant d'instancier des composants Media3 (tels que ExoPlayer, Transformer ou MediaSession) :
- Configuration anticipée : configurez
Flagsau démarrage de l'application (par exemple, dansApplication.onCreate) ou avant d'initialiser la couche multimédia de votre application. - Thread safety : les composants Media3 lisent les indicateurs lors de l'instanciation et propagent ces valeurs aux threads de lecture et de traitement internes. Assurez-vous que la configuration des flags se produit avant la création des composants Media3. La modification des options pendant l'exécution de lecteurs ou de transformateurs n'est pas possible.
Intégrer à la configuration à distance
Une architecture recommandée consiste à exposer trois paramètres sur votre plate-forme de configuration à distance :
media3_canary_mode_enabled(booléen) : activation/désactivation globale du mode Canary (par défaut :true).media3_force_enable_flags(liste d'entiers) : ID de flag spécifiques à activer de force pour les tests ciblés.media3_force_disable_flags(liste d'entiers) : ID de flags spécifiques à désactiver de force si un problème est détecté.
Appliquez ces valeurs au démarrage avant de créer des instances de lecteur :
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); } }
Tester avec des indicateurs
Lorsque vous écrivez des tests unitaires ou des tests Robolectric pour des chemins de code concernés par des flags de fonctionnalité, utilisez androidx.media3.test.utils.Media3FlagsRule (disponible dans le module media3-test-utils) pour vous assurer que les tests ne polluent pas l'état statique les uns des autres.
Nettoyage automatique avec Media3FlagsRule
L'ajout de Media3FlagsRule garantit que tous les remplacements d'indicateurs et les modifications du mode Canary sont automatiquement réinitialisés après chaque test :
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... } }
Tests paramétrés
Vous pouvez combiner Media3FlagsRule avec les annotations @BindFlag et @BindCanaryMode pour exécuter des tests paramétrés sur les états des options :
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. } }
Diagnostics et journalisation
Media3 fournit des outils de diagnostic pour vérifier les flags actifs et les états du mode Canary lors de l'initialisation de la lecture et de l'exécution.
Journaux d'initialisation
Lorsqu'une instance ExoPlayer est initialisée, elle imprime l'état Canary actif et tous les remplacements explicites dans logcat, ainsi que la version de la bibliothèque :
ExoPlayerImpl: Init 59a18ab [AndroidXMedia3/1.10.1] [flame, Pixel 4, Google, 33] [Canary:ON]
Si des forçages sont actifs, seules les différences par rapport à l'état par défaut sont listées :
ExoPlayerImpl: Init 59a18ab [AndroidXMedia3/1.10.1] [flame, Pixel 4, Google, 33] [Canary:ON, Overrides: enabled=[1], disabled=[3]]
Inspection programmatique
Vous pouvez récupérer la chaîne de diagnostic formatée ou les listes de remplacement de requêtes de manière programmatique (par exemple, pour inclure l'état des indicateurs dans les rapports d'erreur ou les analyses de votre application) :
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();
Cycle de vie des flags
Les options de Media3 sont conçues pour être temporaires :
- Développement : une nouvelle optimisation ou fonctionnalité est ajoutée derrière un ID d'option dans
Flags.java. - Mode Canary : une fois validée et prête à être utilisée de manière générale, la fonctionnalité est active en mode Canary dans toutes les versions.
- Promotion et nettoyage : après une période de test prouvant la stabilité en production, la fonctionnalité est promue pour être activée de manière permanente dans la bibliothèque, et la constante d'indicateur, les chemins de code de remplacement et les vérifications conditionnelles sont supprimés.
Si vous rencontrez un problème avec un flag de fonctionnalité, veuillez le signaler dans l'outil de suivi des problèmes GitHub AndroidX Media3 afin que l'équipe puisse le résoudre avant la promotion permanente.