Paso de FUSIBLE

Android 12 admite el paso a través de FUSE, lo que minimiza la sobrecarga de FUSE para lograr un rendimiento comparable al acceso directo al sistema de archivos inferior. El paso a través de FUSE es compatible con los kernels android12-5.4 , android12-5.10 y android-mainline (solo prueba), lo que significa que la compatibilidad con esta función depende del kernel utilizado por el dispositivo y de la versión de Android que ejecuta el dispositivo:

  • Los dispositivos que se actualizan de Android 11 a Android 12 no pueden admitir el paso a través de FUSE ya que los kernels de estos dispositivos están congelados y no pueden pasar a un kernel que se haya actualizado oficialmente con los cambios de paso a través de FUSE.

  • Los dispositivos que se inician con Android 12 pueden admitir el paso a través de FUSE cuando usan un kernel oficial. Para dichos dispositivos, el código del marco de Android que implementa el paso a través de FUSE está integrado en el módulo principal de MediaProvider , que se actualiza automáticamente. Los dispositivos que no implementan MediaProvider como módulo principal (por ejemplo, dispositivos Android Go) también pueden acceder a los cambios de MediaProvider a medida que se comparten públicamente.

FUSE frente a SDCardFS

El sistema de archivos en el espacio de usuario (FUSE) es un mecanismo que permite que el kernel (controlador FUSE) subcontrate las operaciones realizadas en un sistema de archivos FUSE a un programa de espacio de usuario (daemon FUSE), que implementa las operaciones. Android 11 dejó obsoleto SDCardFS e hizo de FUSE la solución predeterminada para la emulación de almacenamiento. Como parte de este cambio, Android implementó su propio demonio FUSE para interceptar el acceso a archivos, aplicar funciones adicionales de seguridad y privacidad y manipular archivos en tiempo de ejecución.

Si bien FUSE funciona bien cuando se trata de información almacenable en caché, como páginas o atributos, introduce regresiones de rendimiento al acceder al almacenamiento externo que son especialmente visibles en dispositivos de gama media y baja. Estas regresiones son causadas por una cadena de componentes que cooperan en la implementación del sistema de archivos FUSE, así como por múltiples cambios del espacio del kernel al espacio del usuario en las comunicaciones entre el controlador FUSE y el demonio FUSE (en comparación con el acceso directo al archivo inferior). sistema más ágil y completamente implementado en el kernel).

Para mitigar estas regresiones, las aplicaciones pueden usar empalme para reducir la copia de datos y usar la API ContentProvider para obtener acceso directo a archivos del sistema de archivos inferiores. Incluso con estas y otras optimizaciones , las operaciones de lectura y escritura pueden ver reducido el ancho de banda cuando se usa FUSE en comparación con el acceso directo al sistema de archivos inferior, especialmente con operaciones de lectura aleatorias, donde ningún almacenamiento en caché o lectura anticipada puede ayudar. Y las aplicaciones que acceden directamente al almacenamiento a través de la ruta heredada /sdcard/ continúan experimentando caídas notables en el rendimiento, especialmente cuando realizan operaciones intensivas de E/S.

Solicitudes de espacio de usuario SDcardFS

El uso de SDcardFS puede acelerar la emulación de almacenamiento y las comprobaciones de permisos de FUSE eliminando la llamada al espacio de usuario del kernel. Las solicitudes de espacio de usuario siguen la ruta: Espacio de usuario → VFS → sdcardfs → VFS → ext4 → Caché/almacenamiento de página.

FUSE Passthrough SDcardFS

Figura 1. Solicitudes de espacio de usuario de SDcardFS

Solicitudes de espacio de usuario FUSE

FUSE se utilizó inicialmente para habilitar la emulación de almacenamiento y permitir que las aplicaciones utilicen de forma transparente el almacenamiento interno o una tarjeta SD externa. El uso de FUSE introduce cierta sobrecarga porque cada solicitud de espacio de usuario sigue la ruta: Espacio de usuario → VFS → controlador FUSE → demonio FUSE → VFS → ext4 → caché/almacenamiento de página.

FUSIBLE de paso FUSIBLE

Figura 2. Solicitudes de espacio de usuario de FUSE

Solicitudes de transferencia FUSE

La mayoría de los permisos de acceso a archivos se verifican en el momento de abrir el archivo, y se realizan verificaciones de permisos adicionales al leer y escribir en ese archivo. En algunos casos, es posible saber en el momento de apertura del archivo que la aplicación solicitante tiene acceso completo al archivo solicitado, por lo que el sistema no necesita continuar reenviando las solicitudes de lectura y escritura del controlador FUSE al demonio FUSE (como eso solo movería datos de un lugar a otro).

Con el paso a través de FUSE, el demonio FUSE que maneja una solicitud abierta puede notificar al controlador FUSE que la operación está permitida y que todas las solicitudes de lectura y escritura posteriores se pueden reenviar directamente al sistema de archivos inferior. Esto evita la sobrecarga adicional de esperar a que el demonio FUSE del espacio de usuario responda a las solicitudes del controlador FUSE.

A continuación se muestra una comparación de las solicitudes de transferencia FUSE y FUSE.

Comparación de paso a través de FUSE

Figura 3. Solicitud de FUSE versus solicitud de paso a través de FUSE

Cuando una aplicación realiza un acceso al sistema de archivos FUSE, se producen las siguientes operaciones:

  1. El controlador FUSE maneja y pone en cola la solicitud, luego la presenta al demonio FUSE que maneja ese sistema de archivos FUSE a través de una instancia de conexión específica en el archivo /dev/fuse , cuya lectura el demonio FUSE no puede leer.

  2. Cuando el demonio FUSE recibe una solicitud para abrir un archivo, decide si el paso a través de FUSE debe estar disponible para ese archivo en particular. Si está disponible, el demonio:

    1. Notifica al controlador FUSE sobre esta solicitud.

    2. Habilita el paso a través de FUSE para el archivo mediante el ioctl FUSE_DEV_IOC_PASSTHROUGH_OPEN , que debe realizarse en el descriptor de archivo del /dev/fuse abierto.

  3. El ioctl recibe (como parámetro) una estructura de datos que contiene lo siguiente:

    • Descriptor de archivo del archivo del sistema de archivos inferior que es el destino de la función de transferencia.

    • Identificador único de la solicitud FUSE que se está manejando actualmente (debe estar abierta o crear y abrir).

    • Campos adicionales que se pueden dejar vacíos y están destinados a implementaciones futuras.

  4. Si ioctl tiene éxito, el demonio FUSE completa la solicitud de apertura, el controlador FUSE maneja la respuesta del demonio FUSE y se agrega una referencia al archivo del sistema de archivos inferior al archivo FUSE dentro del kernel. Cuando una aplicación solicita una operación de lectura/escritura en un archivo FUSE, el controlador FUSE comprueba si la referencia a un archivo del sistema de archivos inferior está disponible.

    • Si hay una referencia disponible, el controlador crea una nueva solicitud de sistema de archivos virtual (VFS) con los mismos parámetros dirigidos al archivo del sistema de archivos inferior.

    • Si no hay una referencia disponible, el controlador reenvía la solicitud al demonio FUSE.

Las operaciones anteriores ocurren para lectura/escritura y lectura/escritura en archivos genéricos y operaciones de lectura/escritura en archivos asignados en memoria. La transferencia FUSE para un archivo determinado existe hasta que se cierra ese archivo.

Implementar paso FUSE

Para habilitar el paso a través de FUSE en dispositivos que ejecutan Android 12, agregue las siguientes líneas al archivo $ANDROID_BUILD_TOP/device/…/device.mk del dispositivo de destino.

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

Para deshabilitar el paso a través de FUSE, omita el cambio de configuración anterior o establezca persist.sys.fuse.passthrough.enable en false . Si anteriormente habilitó el paso a través de FUSE, deshabilitarlo evita que el dispositivo use el paso a través de FUSE pero el dispositivo sigue funcionando.

Para habilitar/deshabilitar el paso a través de FUSE sin actualizar el dispositivo, cambie la propiedad del sistema usando los comandos ADB. A continuación se muestra un ejemplo.

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

Para obtener ayuda adicional, consulte la implementación de referencia .

Validar el paso de FUSE

Para validar que MediaProvider esté utilizando el paso a través de FUSE, verifique logcat para ver los mensajes de depuración. Por ejemplo:

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

La entrada FuseDaemon: Using FUSE passthrough en el registro garantiza que el paso a través de FUSE esté en uso.

El CTS de Android 12 incluye CtsStorageTest , que incluye pruebas que activan el paso a través de FUSE. Para ejecutar la prueba manualmente, utilice atest como se muestra a continuación:

atest CtsStorageTest