FUSE Passthrough

Android 12 mendukung passthrough FUSE, yang meminimalkan overhead FUSE untuk mencapai kinerja yang sebanding dengan akses langsung ke sistem file yang lebih rendah. Passthrough FUSE didukung di kernel android12-5.4 , android12-5.10 , dan android-mainline (hanya pengujian), yang berarti bahwa dukungan untuk fitur ini bergantung pada kernel yang digunakan oleh perangkat dan versi Android yang dijalankan perangkat:

  • Peningkatan perangkat dari Android 11 ke Android 12 tidak dapat mendukung passthrough FUSE karena kernel untuk perangkat ini dibekukan dan mereka tidak dapat pindah ke kernel yang telah ditingkatkan secara resmi dengan perubahan passthrough FUSE.

  • Perangkat yang diluncurkan dengan Android 12 dapat mendukung passthrough FUSE saat menggunakan kernel resmi. Untuk perangkat semacam itu, kode kerangka kerja Android yang mengimplementasikan passthrough FUSE disematkan dalam modul jalur utama MediaProvider , yang secara otomatis ditingkatkan versinya. Perangkat yang tidak mengimplementasikan MediaProvider sebagai modul arus utama (misalnya, perangkat Android Go), juga dapat mengakses perubahan MediaProvider saat dibagikan secara publik.

FUSE versus SDCardFS

Sistem file di Userspace (FUSE) adalah mekanisme yang memungkinkan operasi yang dilakukan pada sistem file FUSE untuk dialihdayakan oleh kernel (driver FUSE) ke program userspace (daemon FUSE), yang mengimplementasikan operasi. Android 11 tidak lagi menggunakan SDCardFS dan menjadikan FUSE sebagai solusi default untuk emulasi penyimpanan. Sebagai bagian dari perubahan ini, Android mengimplementasikan daemon FUSE-nya sendiri untuk mencegat akses file, menerapkan fitur keamanan dan privasi ekstra, dan memanipulasi file saat runtime.

Sementara FUSE berkinerja baik saat menangani informasi yang dapat disimpan dalam cache seperti halaman atau atribut, FUSE memperkenalkan regresi kinerja saat mengakses penyimpanan eksternal yang terutama terlihat di perangkat kelas menengah dan kelas bawah. Regresi ini disebabkan oleh rantai komponen yang bekerja sama dalam implementasi sistem file FUSE, serta beberapa sakelar dari ruang kernel ke ruang pengguna dalam komunikasi antara driver FUSE dan daemon FUSE (dibandingkan dengan akses langsung ke file yang lebih rendah sistem yang lebih ramping dan sepenuhnya diimplementasikan di kernel).

Untuk mengurangi regresi ini, aplikasi dapat menggunakan penyambungan untuk mengurangi penyalinan data dan menggunakan ContentProvider API untuk mendapatkan akses langsung ke file sistem file yang lebih rendah. Bahkan dengan pengoptimalan ini dan lainnya , operasi baca dan tulis mungkin mengalami pengurangan bandwidth saat menggunakan FUSE jika dibandingkan dengan akses langsung ke sistem file yang lebih rendah — terutama dengan operasi baca acak, di mana tidak ada caching atau read-ahead yang dapat membantu. Dan aplikasi yang secara langsung mengakses penyimpanan melalui jalur /sdcard/ lama terus mengalami penurunan kinerja yang nyata, terutama saat melakukan operasi intensif IO.

Permintaan ruang pengguna SDcardFS

Menggunakan SDcardFS dapat mempercepat emulasi penyimpanan dan pemeriksaan izin FUSE dengan menghapus panggilan ruang pengguna dari kernel. Permintaan ruang pengguna mengikuti jalur: Userspace → VFS → sdcardfs → VFS → ext4 → Halaman cache/Penyimpanan.

FUSE Passthrough SDcardFS

Gambar 1. Permintaan ruang pengguna SDcardFS

Permintaan ruang pengguna FUSE

FUSE awalnya digunakan untuk mengaktifkan emulasi penyimpanan dan untuk memungkinkan aplikasi menggunakan penyimpanan internal atau kartu sd eksternal secara transparan. Menggunakan FUSE memperkenalkan beberapa overhead karena setiap permintaan ruang pengguna mengikuti jalur: Userspace → VFS → FUSE driver → FUSE daemon → VFS → ext4 → Page cache/Storage.

FUSE Passthrough FUSE

Gambar 2. Permintaan ruang pengguna FUSE

Permintaan passthrough FUSE {#fuse-passthrough-requests}

Sebagian besar izin akses file diperiksa pada waktu file terbuka, dengan pemeriksaan izin tambahan terjadi saat membaca dari dan menulis ke file itu. Dalam beberapa kasus, mungkin untuk mengetahui pada waktu file terbuka bahwa aplikasi yang meminta memiliki akses penuh ke file yang diminta, sehingga sistem tidak perlu meneruskan permintaan baca dan tulis dari driver FUSE ke daemon FUSE (seperti yang hanya akan memindahkan data dari satu tempat ke tempat lain).

Dengan passthrough FUSE, daemon FUSE yang menangani permintaan terbuka dapat memberi tahu driver FUSE bahwa operasi diizinkan dan bahwa semua permintaan baca dan tulis berikutnya dapat langsung diteruskan ke sistem file yang lebih rendah. Ini menghindari overhead ekstra menunggu daemon FUSE ruang pengguna untuk membalas permintaan driver FUSE.

Perbandingan permintaan passthrough FUSE dan FUSE ditunjukkan di bawah ini.

Perbandingan Passthrough FUSE

Gambar 3. Permintaan FUSE versus permintaan passthrough FUSE

Saat aplikasi melakukan akses sistem file FUSE, operasi berikut terjadi:

  1. Driver FUSE menangani dan mengantrekan permintaan, lalu menyajikannya ke daemon FUSE yang menangani sistem file FUSE tersebut melalui instance koneksi tertentu pada file /dev/fuse , yang diblokir oleh daemon FUSE untuk membacanya.

  2. Ketika daemon FUSE menerima permintaan untuk membuka file, ia memutuskan apakah passthrough FUSE harus tersedia untuk file tertentu. Jika tersedia, daemonnya:

    1. Memberi tahu driver FUSE tentang permintaan ini.

    2. Mengaktifkan passthrough FUSE untuk file menggunakan FUSE_DEV_IOC_PASSTHROUGH_OPEN ioctl, yang harus dilakukan pada deskriptor file dari /dev/fuse yang dibuka.

  3. ioctl menerima (sebagai parameter) struktur data yang berisi berikut ini:

    • Deskriptor file dari file sistem file yang lebih rendah yang menjadi target untuk fitur passthrough.

    • Pengidentifikasi unik dari permintaan FUSE yang sedang ditangani (harus terbuka atau buat-dan-buka).

    • Bidang tambahan yang dapat dibiarkan kosong dan dimaksudkan untuk implementasi di masa mendatang.

  4. Jika ioctl berhasil, daemon FUSE menyelesaikan permintaan terbuka, driver FUSE menangani balasan daemon FUSE, dan referensi ke file sistem file yang lebih rendah ditambahkan ke file FUSE di dalam kernel. Saat aplikasi meminta operasi baca/tulis pada file FUSE, driver FUSE memeriksa apakah referensi ke file sistem file yang lebih rendah tersedia.

    • Jika referensi tersedia, driver membuat permintaan Sistem File Virtual (VFS) baru dengan parameter yang sama yang menargetkan file sistem file yang lebih rendah.

    • Jika referensi tidak tersedia, driver meneruskan permintaan ke daemon FUSE.

Operasi di atas terjadi untuk baca/tulis dan baca-iter/tulis-iter pada file generik dan operasi baca/tulis pada file yang dipetakan memori. Passthrough FUSE untuk file tertentu ada hingga file tersebut ditutup.

Menerapkan passthrough FUSE

Untuk mengaktifkan passthrough FUSE pada perangkat yang menjalankan Android 12, tambahkan baris berikut ke file $ANDROID_BUILD_TOP/device/…/device.mk dari perangkat target.

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

Untuk menonaktifkan passthrough FUSE, abaikan perubahan konfigurasi di atas atau setel persist.sys.fuse.passthrough.enable ke false . Jika sebelumnya Anda telah mengaktifkan passthrough FUSE, menonaktifkannya akan mencegah perangkat menggunakan passthrough FUSE tetapi perangkat tetap berfungsi.

Untuk mengaktifkan/menonaktifkan passthrough FUSE tanpa mem-flash perangkat, ubah properti sistem menggunakan perintah ADB. Sebuah contoh ditunjukkan di bawah ini.

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

Untuk bantuan tambahan, lihat implementasi referensi .

Memvalidasi passthrough FUSE

Untuk memvalidasi bahwa MediaProvider menggunakan passthrough FUSE, periksa logcat untuk pesan debug. Sebagai contoh:

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 di log memastikan bahwa passthrough FUSE sedang digunakan.

CTS Android 12 menyertakan CtsStorageTest , yang mencakup pengujian yang memicu passthrough FUSE. Untuk menjalankan tes secara manual, gunakan atest seperti yang ditunjukkan di bawah ini:

atest CtsStorageTest