FUSE passthrough

Android 12 prend en charge le relais FUSE, qui minimise la surcharge de FUSE pour obtenir des performances comparables à un accès direct au système de fichiers inférieur. Le relais FUSE est pris en charge dans les noyaux android12-5.4 , android12-5.10 et android-mainline (tests uniquement), ce qui signifie que la prise en charge de cette fonctionnalité dépend du noyau utilisé par l'appareil et de la version d'Android que l'appareil exécute :

  • Les appareils mis à niveau d'Android 11 vers Android 12 ne peuvent pas prendre en charge le relais FUSE car les noyaux de ces appareils sont gelés et ils ne peuvent pas migrer vers un noyau qui a été officiellement mis à niveau avec les modifications du relais FUSE.

  • Les appareils lancés avec Android 12 peuvent prendre en charge le relais FUSE lors de l’utilisation d’un noyau officiel. Pour de tels appareils, le code du framework Android qui implémente le relais FUSE est intégré dans le module principal MediaProvider , qui est automatiquement mis à niveau. Les appareils qui n'implémentent pas MediaProvider en tant que module principal (par exemple, les appareils Android Go) peuvent également accéder aux modifications de MediaProvider lorsqu'elles sont partagées publiquement.

FUSE contre SDCardFS

Le système de fichiers dans l'espace utilisateur (FUSE) est un mécanisme qui permet aux opérations effectuées sur un système de fichiers FUSE d'être externalisées par le noyau (pilote FUSE) vers un programme en espace utilisateur (démon FUSE), qui implémente les opérations. Android 11 a rendu SDCardFS obsolète et a fait de FUSE la solution par défaut pour l'émulation du stockage. Dans le cadre de ce changement, Android a implémenté son propre démon FUSE pour intercepter les accès aux fichiers, appliquer des fonctionnalités de sécurité et de confidentialité supplémentaires et manipuler les fichiers au moment de l'exécution.

Bien que FUSE fonctionne bien lorsqu'il s'agit d'informations pouvant être mises en cache telles que des pages ou des attributs, il introduit des régressions de performances lors de l'accès au stockage externe, particulièrement visibles sur les appareils milieu et bas de gamme. Ces régressions sont causées par une chaîne de composants coopérant à l'implémentation du système de fichiers FUSE, ainsi que par de multiples basculements de l'espace noyau vers l'espace utilisateur dans les communications entre le pilote FUSE et le démon FUSE (par rapport à l'accès direct au fichier inférieur). système plus simple et entièrement implémenté dans le noyau).

Pour atténuer ces régressions, les applications peuvent utiliser l'épissage pour réduire la copie de données et utiliser l' API ContentProvider pour obtenir un accès direct aux fichiers inférieurs du système de fichiers. Même avec ces optimisations et d'autres , les opérations de lecture et d'écriture peuvent voir une bande passante réduite lors de l'utilisation de FUSE par rapport à l'accès direct au système de fichiers inférieur, en particulier avec les opérations de lecture aléatoire, pour lesquelles aucune mise en cache ou lecture anticipée ne peut aider. Et les applications qui accèdent directement au stockage via l’ancien chemin /sdcard/ continuent de subir des baisses de performances notables, en particulier lors de l’exécution d’opérations gourmandes en E/S.

Requêtes d'espace utilisateur SDcardFS

L'utilisation de SDcardFS peut accélérer l'émulation du stockage et les vérifications des autorisations de FUSE en supprimant l'appel à l'espace utilisateur du noyau. Les requêtes d'espace utilisateur suivent le chemin : Espace utilisateur → VFS → sdcardfs → VFS → ext4 → Cache/stockage de page.

FUSE Passthrough SDcardFS

Figure 1. Requêtes d'espace utilisateur SDcardFS

Requêtes d'espace utilisateur FUSE

FUSE a été initialement utilisé pour activer l’émulation du stockage et permettre aux applications d’utiliser de manière transparente soit le stockage interne, soit une carte SD externe. L'utilisation de FUSE introduit une certaine surcharge car chaque requête d'espace utilisateur suit le chemin : Espace utilisateur → VFS → Pilote FUSE → Démon FUSE → VFS → ext4 → Cache/stockage de page.

FUSE Passage FUSE

Figure 2. Requêtes d'espace utilisateur FUSE

Requêtes de relais FUSE

La plupart des autorisations d'accès aux fichiers sont vérifiées au moment de l'ouverture du fichier, avec des vérifications d'autorisations supplémentaires lors de la lecture et de l'écriture dans ce fichier. Dans certains cas, il est possible de savoir au moment de l'ouverture du fichier que l'application requérante a un accès complet au fichier demandé, de sorte que le système n'a pas besoin de continuer à transmettre les requêtes de lecture et d'écriture du pilote FUSE au démon FUSE (car cela ne déplacerait que les données d'un endroit à un autre).

Avec le relais FUSE, le démon FUSE gérant une requête d'ouverture peut informer le pilote FUSE que l'opération est autorisée et que toutes les requêtes de lecture et d'écriture ultérieures peuvent être directement transmises au système de fichiers inférieur. Cela évite la surcharge supplémentaire liée à l'attente que le démon FUSE de l'espace utilisateur réponde aux requêtes du pilote FUSE.

Une comparaison des requêtes passthrough FUSE et FUSE est présentée ci-dessous.

Comparaison du relais FUSE

Figure 3. Requête FUSE et requête passthrough FUSE

Lorsqu'une application effectue un accès au système de fichiers FUSE, les opérations suivantes se produisent :

  1. Le pilote FUSE gère et met la demande en file d'attente, puis la présente au démon FUSE qui gère ce système de fichiers FUSE via une instance de connexion spécifique sur le fichier /dev/fuse , que le démon FUSE ne peut pas lire.

  2. Lorsque le démon FUSE reçoit une demande d'ouverture d'un fichier, il décide si le relais FUSE doit être disponible pour ce fichier particulier. S'il est disponible, le démon :

    1. Informe le pilote FUSE de cette demande.

    2. Active le relais FUSE pour le fichier à l'aide de l'ioctl FUSE_DEV_IOC_PASSTHROUGH_OPEN , qui doit être effectué sur le descripteur de fichier du /dev/fuse ouvert.

  3. L'ioctl reçoit (en paramètre) une structure de données qui contient les éléments suivants :

    • Descripteur de fichier du fichier inférieur du système de fichiers qui est la cible de la fonctionnalité passthrough.

    • Identifiant unique de la requête FUSE en cours de traitement (doit être ouverte ou créer-et-ouvrir).

    • Champs supplémentaires qui peuvent être laissés vides et sont destinés à de futures implémentations.

  4. Si l'ioctl réussit, le démon FUSE termine la demande d'ouverture, le pilote FUSE gère la réponse du démon FUSE et une référence au fichier du système de fichiers inférieur est ajoutée au fichier FUSE dans le noyau. Lorsqu'une application demande une opération de lecture/écriture sur un fichier FUSE, le pilote FUSE vérifie si la référence à un fichier du système de fichiers inférieur est disponible.

    • Si une référence est disponible, le pilote crée une nouvelle demande de système de fichiers virtuel (VFS) avec les mêmes paramètres ciblant le fichier du système de fichiers inférieur.

    • Si une référence n'est pas disponible, le pilote transmet la demande au démon FUSE.

Les opérations ci-dessus se produisent pour les opérations de lecture/écriture et de lecture/écriture sur les fichiers génériques et les opérations de lecture/écriture sur les fichiers mappés en mémoire. Le relais FUSE pour un fichier donné existe jusqu'à ce que ce fichier soit fermé.

Implémenter le relais FUSE

Pour activer le relais FUSE sur les appareils exécutant Android 12, ajoutez les lignes suivantes au fichier $ANDROID_BUILD_TOP/device/…/device.mk de l'appareil cible.

# Use FUSE passthrough
PRODUCT_PRODUCT_PROPERTIES += \
    persist.sys.fuse.passthrough.enable=true

Pour désactiver le relais FUSE, omettez la modification de configuration ci-dessus ou définissez persist.sys.fuse.passthrough.enable sur false . Si vous avez déjà activé le relais FUSE, sa désactivation empêche l'appareil d'utiliser le relais FUSE mais l'appareil reste fonctionnel.

Pour activer/désactiver le relais FUSE sans flasher le périphérique, modifiez la propriété système à l'aide des commandes ADB. Un exemple est présenté ci-dessous.

adb root
adb shell setprop persist.sys.fuse.passthrough.enable {true,false}
adb reboot

Pour obtenir une aide supplémentaire, reportez-vous à l' implémentation de référence .

Valider le relais FUSE

Pour vérifier que MediaProvider utilise le relais FUSE, vérifiez logcat pour les messages de débogage. Par exemple:

adb logcat FuseDaemon:V \*:S
--------- beginning of main
03-02 12:09:57.833  3499  3773 I FuseDaemon: Using FUSE passthrough
03-02 12:09:57.833  3499  3773 I FuseDaemon: Starting fuse...

L’entrée FuseDaemon: Using FUSE passthrough dans le journal garantit que le relais FUSE est utilisé.

Le CTS Android 12 inclut CtsStorageTest , qui inclut des tests qui déclenchent le relais FUSE. Pour exécuter le test manuellement, utilisez atest comme indiqué ci-dessous :

atest CtsStorageTest