проходной FUSE

Android 12 поддерживает сквозную передачу FUSE, которая сводит к минимуму накладные расходы FUSE и обеспечивает производительность, сравнимую с прямым доступом к нижней файловой системе. Сквозное соединение FUSE поддерживается в ядрах android12-5.4 , android12-5.10 и android-mainline (только тестирование). Это означает, что поддержка этой функции зависит от ядра, используемого устройством, и версии Android, на которой работает устройство:

  • Устройства, обновляющиеся с Android 11 до Android 12, не могут поддерживать сквозную передачу FUSE, поскольку ядра для этих устройств заморожены, и они не могут перейти на ядро, которое было официально обновлено с изменениями сквозной передачи FUSE.

  • Устройства, запускаемые с Android 12, могут поддерживать сквозную передачу FUSE при использовании официального ядра. Для таких устройств код платформы Android, реализующий сквозную передачу FUSE, встроен в основной модуль MediaProvider , который автоматически обновляется. Устройства, которые не реализуют MediaProvider в качестве основного модуля (например, устройства Android Go), также могут получать доступ к изменениям MediaProvider, поскольку они общедоступны.

FUSE против SDCardFS

Файловая система в пространстве пользователя (FUSE) — это механизм, который позволяет передавать операции, выполняемые в файловой системе FUSE, ядром (драйвер FUSE) программе пользовательского пространства (демон FUSE), которая реализует эти операции. В Android 11 SDCardFS устарела и FUSE стал решением по умолчанию для эмуляции хранилища. В рамках этого изменения в Android реализован собственный демон FUSE для перехвата доступа к файлам, обеспечения дополнительных функций безопасности и конфиденциальности, а также манипулирования файлами во время выполнения.

Хотя FUSE хорошо работает при работе с кэшируемой информацией, такой как страницы или атрибуты, он приводит к снижению производительности при доступе к внешнему хранилищу, что особенно заметно на устройствах среднего и низкого уровня. Эти регрессии вызваны цепочкой компонентов, взаимодействующих при реализации файловой системы FUSE, а также множественными переключениями из пространства ядра в пространство пользователя при обмене данными между драйвером FUSE и демоном FUSE (по сравнению с прямым доступом к нижнему файлу). более компактная система, полностью реализованная в ядре).

Чтобы смягчить эти регрессии, приложения могут использовать сращивание для уменьшения копирования данных и использовать API ContentProvider для получения прямого доступа к файлам нижней файловой системы. Даже с учетом этих и других оптимизаций операции чтения и записи могут столкнуться с уменьшением пропускной способности при использовании FUSE по сравнению с прямым доступом к нижней файловой системе — особенно при операциях случайного чтения, где никакое кэширование или упреждающее чтение не могут помочь. А приложения, которые напрямую обращаются к хранилищу через устаревший путь /sdcard/ продолжают испытывать заметное падение производительности, особенно при выполнении операций с интенсивным вводом-выводом.

Запросы пользовательского пространства SDcardFS

Использование SDcardFS может ускорить эмуляцию хранилища и проверку разрешений FUSE за счет удаления вызова пользовательского пространства из ядра. Запросы пользовательского пространства следуют по пути: Пользовательское пространство → VFS → sdcardfs → VFS → ext4 → Кэш страниц/Хранилище.

FUSE Passthrough SDcardFS

Рисунок 1. Запросы пользовательского пространства SDcardFS

Запросы пользовательского пространства FUSE

Первоначально FUSE использовался для включения эмуляции хранилища и разрешения приложениям прозрачно использовать либо внутреннее хранилище, либо внешнюю SD-карту. Использование FUSE приводит к некоторым накладным расходам, поскольку каждый запрос пользовательского пространства следует по пути: Пользовательское пространство → VFS → Драйвер FUSE → Демон FUSE → VFS → ext4 → Кэш/хранилище страниц.

ПРЕДОХРАНИТЕЛЬ Проходной ПРЕДОХРАНИТЕЛЬ

Рисунок 2. Запросы пользовательского пространства FUSE

Запросы на передачу FUSE

Большинство разрешений на доступ к файлу проверяются во время открытия файла, а дополнительные проверки разрешений происходят при чтении и записи в этот файл. В некоторых случаях во время открытия файла можно узнать, что запрашивающее приложение имеет полный доступ к запрошенному файлу, поэтому системе не нужно продолжать перенаправлять запросы на чтение и запись от драйвера FUSE демону FUSE (поскольку это будет только перемещать данные из одного места в другое).

При сквозной передаче FUSE демон FUSE, обрабатывающий запрос на открытие, может уведомить драйвер FUSE о том, что операция разрешена и что все последующие запросы на чтение и запись могут быть напрямую перенаправлены в файловую систему нижнего уровня. Это позволяет избежать дополнительных затрат на ожидание ответа демона FUSE пользовательского пространства на запросы драйвера FUSE.

Ниже показано сравнение запросов FUSE и FUSE passthrough.

Сравнение сквозных проходов FUSE

Рисунок 3. Запрос FUSE и запрос сквозной передачи FUSE

Когда приложение выполняет доступ к файловой системе FUSE, происходят следующие операции:

  1. Драйвер FUSE обрабатывает запрос и ставит его в очередь, а затем передает его демону FUSE, который обрабатывает эту файловую систему FUSE через определенный экземпляр соединения в файле /dev/fuse , чтение которого демону FUSE заблокировано.

  2. Когда демон FUSE получает запрос на открытие файла, он решает, должен ли быть доступен проход FUSE для этого конкретного файла. Если он доступен, демон:

    1. Уведомляет драйвер FUSE об этом запросе.

    2. Включает сквозную передачу FUSE для файла с помощью ioctl FUSE_DEV_IOC_PASSTHROUGH_OPEN , который должен быть выполнен для файлового дескриптора открытого /dev/fuse .

  3. ioctl получает (в качестве параметра) структуру данных, которая содержит следующее:

    • Дескриптор файла нижней файловой системы, который является целью функции сквозной передачи.

    • Уникальный идентификатор запроса FUSE, который обрабатывается в данный момент (должен быть открытым или созданным и открытым).

    • Дополнительные поля, которые можно оставить пустыми и предназначены для будущих реализаций.

  4. Если ioctl завершается успешно, демон FUSE завершает запрос на открытие, драйвер FUSE обрабатывает ответ демона FUSE, а ссылка на файл нижней файловой системы добавляется в файл FUSE внутри ядра. Когда приложение запрашивает операцию чтения/записи файла FUSE, драйвер FUSE проверяет, доступна ли ссылка на файл файловой системы более низкого уровня.

    • Если ссылка доступна, драйвер создает новый запрос виртуальной файловой системы (VFS) с теми же параметрами, нацеленный на файл нижней файловой системы.

    • Если ссылка недоступна, драйвер перенаправляет запрос демону FUSE.

Вышеупомянутые операции выполняются для чтения/записи и чтения/записи общих файлов, а также операций чтения/записи для файлов, отображаемых в памяти. Проход FUSE для данного файла существует до тех пор, пока этот файл не будет закрыт.

Реализация сквозной передачи FUSE

Чтобы включить сквозную передачу FUSE на устройствах под управлением Android 12, добавьте следующие строки в файл $ANDROID_BUILD_TOP/device/…/device.mk целевого устройства.

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

Чтобы отключить сквозную передачу FUSE, пропустите вышеуказанное изменение конфигурации или установите для persist.sys.fuse.passthrough.enable значение false . Если вы ранее включили сквозную передачу FUSE, ее отключение не позволит устройству использовать сквозную передачу FUSE, но устройство останется работоспособным.

Чтобы включить/отключить сквозную передачу FUSE без перепрошивки устройства, измените свойство системы с помощью команд ADB. Пример показан ниже.

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

Для получения дополнительной помощи обратитесь к эталонной реализации .

Подтвердить передачу FUSE

Чтобы убедиться, что MediaProvider использует сквозную передачу FUSE, проверьте logcat на наличие отладочных сообщений. Например:

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

FuseDaemon: Using FUSE passthrough в журнале гарантирует, что сквозная передача FUSE используется.

CTS Android 12 включает CtsStorageTest , который включает тесты, запускающие передачу FUSE. Чтобы запустить тест вручную, используйте atest, как показано ниже:

atest CtsStorageTest