FUSE ส่งผ่าน

Android 12 รองรับ FUSE passthrough ซึ่งลดค่าใช้จ่ายของ FUSE ให้เหลือน้อยที่สุดเพื่อให้ได้ประสิทธิภาพที่เทียบเท่ากับการเข้าถึงโดยตรงไปยังระบบไฟล์ระดับล่าง FUSE passthrough ได้รับการสนับสนุนในเคอร์เนล android12-5.4 , android12-5.10 และ android-mainline (ทดสอบเท่านั้น) ซึ่งหมายความว่าการรองรับคุณสมบัตินี้ขึ้นอยู่กับเคอร์เนลที่ใช้โดยอุปกรณ์และเวอร์ชันของ Android ที่อุปกรณ์ใช้งานอยู่:

  • อุปกรณ์ที่อัปเกรดจาก Android 11 เป็น Android 12 ไม่รองรับการส่งผ่าน FUSE เนื่องจากเคอร์เนลสำหรับอุปกรณ์เหล่านี้ถูกแช่แข็งและไม่สามารถย้ายไปยังเคอร์เนลที่ได้รับการอัปเกรดอย่างเป็นทางการด้วยการเปลี่ยนแปลงการส่งผ่าน FUSE

  • อุปกรณ์ที่เปิดตัวด้วย Android 12 สามารถรองรับ FUSE passthrough เมื่อใช้เคอร์เนลอย่างเป็นทางการ สำหรับอุปกรณ์ดังกล่าว โค้ดเฟรมเวิร์ก Android ที่ใช้ FUSE passthrough จะถูกฝังอยู่ในโมดูลหลัก ของ MediaProvider ซึ่งได้รับการอัปเกรดโดยอัตโนมัติ อุปกรณ์ที่ไม่ได้ใช้ MediaProvider เป็นโมดูลหลัก (เช่น อุปกรณ์ Android Go) ยังสามารถเข้าถึงการเปลี่ยนแปลงของ MediaProvider ได้เมื่อมีการแชร์แบบสาธารณะ

ฟิวส์กับ SDCardFS

ระบบไฟล์ใน Userspace (FUSE) เป็นกลไกที่ช่วยให้การดำเนินการที่ดำเนินการบนระบบไฟล์ FUSE ได้รับการเอาท์ซอร์สโดยเคอร์เนล (ไดรเวอร์ FUSE) ไปยังโปรแกรม userspace (FUSE daemon) ซึ่งดำเนินการดำเนินการ Android 11 เลิกใช้ SDCardFS และทำให้ FUSE เป็นโซลูชันเริ่มต้นสำหรับการจำลองพื้นที่เก็บข้อมูล ส่วนหนึ่งของการเปลี่ยนแปลงนี้ Android ได้ใช้ FUSE daemon ของตัวเองเพื่อสกัดกั้นการเข้าถึงไฟล์ บังคับใช้คุณสมบัติความปลอดภัยและความเป็นส่วนตัวเพิ่มเติม และจัดการไฟล์ในขณะรันไทม์

แม้ว่า FUSE จะทำงานได้ดีเมื่อจัดการกับข้อมูลที่สามารถแคชได้ เช่น หน้าหรือคุณลักษณะ แต่จะทำให้เกิดความถดถอยของประสิทธิภาพเมื่อเข้าถึงที่จัดเก็บข้อมูลภายนอกที่มองเห็นได้ชัดเจนในอุปกรณ์ระดับกลางและระดับล่าง การถดถอยเหล่านี้มีสาเหตุมาจากกลุ่มส่วนประกอบที่ร่วมมือกันในการใช้งานระบบไฟล์ FUSE เช่นเดียวกับสวิตช์หลายตัวจากพื้นที่เคอร์เนลไปยังพื้นที่ผู้ใช้ในการสื่อสารระหว่างไดรเวอร์ FUSE และ FUSE daemon (เมื่อเปรียบเทียบกับการเข้าถึงโดยตรงไปยังไฟล์ด้านล่าง ระบบที่บางกว่าและนำไปใช้งานอย่างสมบูรณ์ในเคอร์เนล)

เพื่อลดการถดถอยเหล่านี้ แอปสามารถใช้ การประกบ เพื่อลดการคัดลอกข้อมูล และใช้ ContentProvider API เพื่อเข้าถึงไฟล์ระบบไฟล์ระดับล่างได้โดยตรง แม้จะมี การเพิ่มประสิทธิภาพเหล่านี้และอื่นๆ การดำเนินการอ่านและเขียนอาจเห็นแบนด์วิธลดลงเมื่อใช้ FUSE เมื่อเปรียบเทียบกับการเข้าถึงโดยตรงไปยังระบบไฟล์ระดับล่าง โดยเฉพาะอย่างยิ่งกับการดำเนินการอ่านแบบสุ่ม ซึ่งไม่มีการแคชหรือการอ่านล่วงหน้าใดสามารถช่วยได้ และแอปที่เข้าถึงที่เก็บข้อมูลโดยตรงผ่านเส้นทาง /sdcard/ เดิม ยังคงประสบปัญหาประสิทธิภาพลดลงอย่างเห็นได้ชัด โดยเฉพาะอย่างยิ่งเมื่อดำเนินการที่ต้องใช้ IO มาก

คำขอพื้นที่ผู้ใช้ SDcardFS

การใช้ SDcardFS สามารถเพิ่มความเร็วในการจำลองการจัดเก็บข้อมูลและการตรวจสอบสิทธิ์ของ FUSE โดยการลบการเรียกพื้นที่ผู้ใช้ออกจากเคอร์เนล คำขอ Userspace เป็นไปตามเส้นทาง: Userspace → VFS → sdcardfs → VFS → ext4 → Page cache/Storage

ฟิวส์ส่งผ่าน SDcardFS

รูปที่ 1. คำขอพื้นที่ผู้ใช้ SDcardFS

คำขอพื้นที่ผู้ใช้ FUSE

เริ่มแรก FUSE ใช้เพื่อเปิดใช้งานการจำลองการจัดเก็บข้อมูลและอนุญาตให้แอปใช้ที่เก็บข้อมูลภายในหรือ sdcard ภายนอกอย่างโปร่งใส การใช้ FUSE ทำให้เกิดโอเวอร์เฮดบางส่วนเนื่องจากคำขอพื้นที่ผู้ใช้แต่ละรายการเป็นไปตามเส้นทาง: Userspace → VFS → FUSE driver → FUSE daemon → VFS → ext4 → Page cache/Storage

ฟิวส์ ฟิวส์ทะลุผ่าน

รูปที่ 2. คำร้องขอพื้นที่ผู้ใช้ FUSE

คำขอส่งผ่าน FUSE

สิทธิ์การเข้าถึงไฟล์ส่วนใหญ่จะได้รับการตรวจสอบ ณ เวลาเปิดไฟล์ โดยจะมีการตรวจสอบสิทธิ์เพิ่มเติมเมื่ออ่านและเขียนไฟล์นั้น ในบางกรณี เป็นไปได้ที่จะทราบในเวลาเปิดไฟล์ว่าแอปที่ร้องขอสามารถเข้าถึงไฟล์ที่ร้องขอได้อย่างสมบูรณ์ ดังนั้นระบบจึงไม่จำเป็นต้องส่งต่อการอ่านและเขียนคำขอจากไดรเวอร์ FUSE ไปยัง FUSE daemon ต่อไป (เช่นนั้น จะย้ายข้อมูลจากที่หนึ่งไปอีกที่หนึ่งเท่านั้น)

ด้วย FUSE passthrough FUSE daemon ที่จัดการคำขอที่เปิดอยู่สามารถแจ้งไดรเวอร์ FUSE ว่าการดำเนินการนั้นได้รับอนุญาต และคำขอการอ่านและเขียนที่ตามมาทั้งหมดสามารถส่งต่อโดยตรงไปยังระบบไฟล์ระดับล่างได้ วิธีนี้จะหลีกเลี่ยงค่าใช้จ่ายเพิ่มเติมในการรอ FUSE daemon พื้นที่ผู้ใช้เพื่อตอบกลับคำขอไดรเวอร์ FUSE

การเปรียบเทียบคำขอส่งผ่าน FUSE และ FUSE แสดงอยู่ด้านล่าง

การเปรียบเทียบการส่งผ่านฟิวส์

รูปที่ 3 คำขอ FUSE เทียบกับคำขอ FUSE passthrough

เมื่อแอปทำการเข้าถึงระบบไฟล์ FUSE การดำเนินการต่อไปนี้จะเกิดขึ้น:

  1. ไดรเวอร์ FUSE จะจัดการและจัดคิวคำขอ จากนั้นนำเสนอต่อ FUSE daemon ที่จัดการระบบไฟล์ FUSE นั้นผ่านอินสแตนซ์การเชื่อมต่อเฉพาะบนไฟล์ /dev/fuse ซึ่ง FUSE daemon ถูกบล็อกไม่ให้อ่าน

  2. เมื่อ FUSE daemon ได้รับการร้องขอให้เปิดไฟล์ มันจะตัดสินใจว่า FUSE passthrough ควรจะพร้อมใช้งานสำหรับไฟล์นั้นหรือไม่ หากมีให้ใช้งาน daemon:

    1. แจ้งไดรเวอร์ FUSE เกี่ยวกับคำขอนี้

    2. เปิดใช้งาน FUSE passthrough สำหรับไฟล์โดยใช้ FUSE_DEV_IOC_PASSTHROUGH_OPEN ioctl ซึ่งจะต้องดำเนินการกับตัวอธิบายไฟล์ของ /dev/fuse ที่เปิดอยู่

  3. ioctl ได้รับ (เป็นพารามิเตอร์) โครงสร้างข้อมูลที่มีสิ่งต่อไปนี้:

    • ตัวอธิบายไฟล์ของไฟล์ระบบไฟล์ระดับล่างที่เป็นเป้าหมายสำหรับคุณลักษณะการส่งผ่าน

    • ตัวระบุเฉพาะของคำขอ FUSE ที่กำลังได้รับการจัดการ (ต้องเปิดหรือสร้างและเปิด)

    • ช่องเพิ่มเติมที่สามารถเว้นว่างไว้ได้และมีไว้สำหรับการใช้งานในอนาคต

  4. หาก ioctl สำเร็จ FUSE daemon จะดำเนินการตามคำขอที่เปิดอยู่ ไดรเวอร์ FUSE จะจัดการการตอบกลับ FUSE daemon และการอ้างอิงถึงไฟล์ระบบไฟล์ระดับล่างจะถูกเพิ่มลงในไฟล์ FUSE ภายในเคอร์เนล เมื่อแอปร้องขอการดำเนินการอ่าน/เขียนไฟล์ FUSE ไดรเวอร์ FUSE จะตรวจสอบว่ามีการอ้างอิงถึงไฟล์ระบบไฟล์ระดับล่างหรือไม่

    • หากมีการอ้างอิง ไดรเวอร์จะสร้างคำขอ Virtual File System (VFS) ใหม่โดยมีพารามิเตอร์เดียวกันซึ่งกำหนดเป้าหมายไปที่ไฟล์ระบบไฟล์ระดับล่าง

    • หากไม่มีข้อมูลอ้างอิง ไดรเวอร์จะส่งต่อคำขอไปยัง FUSE daemon

การดำเนินการข้างต้นเกิดขึ้นสำหรับการอ่าน/เขียนและ read-iter/write-iter บนไฟล์ทั่วไปและการดำเนินการอ่าน/เขียนบนไฟล์ที่แมปหน่วยความจำ FUSE passthrough สำหรับไฟล์ที่กำหนดมีอยู่จนกว่าไฟล์นั้นจะถูกปิด

ใช้การส่งผ่าน FUSE

หากต้องการเปิดใช้งาน FUSE Passthrough บนอุปกรณ์ที่ใช้ Android 12 ให้เพิ่มบรรทัดต่อไปนี้ในไฟล์ $ANDROID_BUILD_TOP/device/…/device.mk ของอุปกรณ์เป้าหมาย

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

หากต้องการปิดใช้งาน FUSE passthrough ให้ละเว้นการเปลี่ยนแปลงการกำหนดค่าข้างต้นหรือตั้งค่า persist.sys.fuse.passthrough.enable เป็น false หากคุณได้เปิดใช้งาน FUSE passthrough ไว้ก่อนหน้านี้ การปิดใช้งานจะป้องกันไม่ให้อุปกรณ์ใช้ FUSE passthrough แต่อุปกรณ์ยังคงทำงานได้

หากต้องการเปิดใช้งาน/ปิดใช้งาน FUSE passthrough โดยไม่กะพริบอุปกรณ์ ให้เปลี่ยนคุณสมบัติของระบบโดยใช้คำสั่ง ADB ตัวอย่างแสดงไว้ด้านล่าง

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

หากต้องการความช่วยเหลือเพิ่มเติม โปรดดู การใช้งานอ้างอิง

ตรวจสอบการส่งผ่าน FUSE

หากต้องการตรวจสอบว่า MediaProvider ใช้ FUSE passthrough ให้ตรวจสอบ 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 passthrough ถูกใช้งานอยู่

Android 12 CTS มี CtsStorageTest ซึ่งรวมถึงการทดสอบที่ทริกเกอร์การส่งผ่าน FUSE หากต้องการรันการทดสอบด้วยตนเอง ให้ใช้ atest ดังที่แสดงด้านล่าง:

atest CtsStorageTest