Truyền qua FUSE

Android 12 hỗ trợ tính năng truyền tải FUSE, giúp giảm thiểu mức hao tổn FUSE để đạt được hiệu suất tương đương với việc truy cập trực tiếp vào hệ thống tệp cấp thấp hơn. Tính năng truyền tải FUSE được hỗ trợ trong các hạt nhân android12-5.4, android12-5.10android-mainline (chỉ dành cho thử nghiệm). Điều này có nghĩa là tính năng hỗ trợ này phụ thuộc vào hạt nhân mà thiết bị sử dụng và phiên bản Android mà thiết bị đang chạy:

  • Các thiết bị nâng cấp từ Android 11 lên Android 12 không thể hỗ trợ tính năng truyền tải FUSE vì các hạt nhân của các thiết bị này bị đóng băng và không thể chuyển sang hạt nhân đã được nâng cấp chính thức bằng các thay đổi về tính năng truyền tải FUSE.

  • Các thiết bị chạy Android 12 có thể hỗ trợ tính năng truyền tải FUSE khi sử dụng hạt nhân chính thức. Đối với các thiết bị như vậy, mã khung Android triển khai tính năng truyền tải FUSE được nhúng trong mô-đun chính MediaProvider. Mô-đun này sẽ tự động được nâng cấp. Các thiết bị không triển khai MediaProvider làm mô-đun chính (ví dụ: thiết bị Android Go) cũng có thể truy cập vào các thay đổi của MediaProvider khi các thay đổi đó được chia sẻ công khai.

FUSE so với SDCardFS

Hệ thống tệp trong không gian người dùng (FUSE) là một cơ chế cho phép nhân (trình điều khiển FUSE) thuê ngoài các thao tác được thực hiện trên hệ thống tệp FUSE cho một chương trình không gian người dùng (trình nền FUSE) để triển khai các thao tác đó. Android 11 không dùng thẻ SDFS nữa và đặt FUSE làm giải pháp mặc định để mô phỏng bộ nhớ. Trong quá trình thay đổi này, Android đã triển khai trình nền FUSE riêng để chặn quyền truy cập vào tệp, thực thi các tính năng bảo mật và quyền riêng tư bổ sung cũng như thao tác với tệp trong thời gian chạy.

Mặc dù FUSE hoạt động tốt khi xử lý thông tin có thể lưu vào bộ nhớ đệm như trang hoặc thuộc tính, nhưng FUSE lại gây ra sự hồi quy về hiệu suất khi truy cập vào bộ nhớ ngoài, đặc biệt là trên các thiết bị cấp trung và cấp thấp. Các hồi quy này là do một chuỗi các thành phần phối hợp trong việc triển khai hệ thống tệp FUSE, cũng như nhiều nút chuyển từ không gian hạt nhân sang không gian người dùng trong quá trình giao tiếp giữa trình điều khiển FUSE và trình nền FUSE (so với quyền truy cập trực tiếp vào hệ thống tệp cấp thấp hơn, gọn nhẹ hơn và được triển khai hoàn toàn trong hạt nhân).

Để giảm thiểu các trường hợp hồi quy này, ứng dụng có thể sử dụng tính năng nối để giảm việc sao chép dữ liệu và sử dụng ContentProvider API để truy cập trực tiếp vào các tệp hệ thống tệp cấp thấp hơn. Ngay cả với những biện pháp này và các biện pháp tối ưu hoá khác, các thao tác đọc và ghi có thể bị giảm băng thông khi sử dụng FUSE so với quyền truy cập trực tiếp vào hệ thống tệp cấp thấp — đặc biệt là với các thao tác đọc ngẫu nhiên, trong đó không có tính năng lưu vào bộ nhớ đệm hoặc đọc trước nào có thể giúp ích. Và các ứng dụng truy cập trực tiếp vào bộ nhớ thông qua đường dẫn /sdcard/ cũ tiếp tục bị giảm hiệu suất đáng kể, đặc biệt là khi thực hiện các thao tác chuyên sâu về IO.

Yêu cầu không gian người dùng SDcardFS

Việc sử dụng SDcardFS có thể tăng tốc độ mô phỏng bộ nhớ và kiểm tra quyền của FUSE bằng cách xoá lệnh gọi không gian người dùng khỏi hạt nhân. Các yêu cầu không gian người dùng tuân theo đường dẫn: Không gian người dùng → VFS → sdcardfs → VFS → ext4 → Bộ nhớ đệm/Bộ nhớ trang.

FUSE Passthrough SDcardFS

Hình 1. Yêu cầu không gian người dùng SDcardFS

Yêu cầu không gian người dùng FUSE

Ban đầu, FUSE được dùng để bật tính năng mô phỏng bộ nhớ và cho phép các ứng dụng sử dụng bộ nhớ trong hoặc thẻ SD ngoài một cách minh bạch. Việc sử dụng FUSE sẽ gây ra một số hao tổn vì mỗi yêu cầu không gian người dùng đều tuân theo đường dẫn: Không gian người dùng → VFS → Trình điều khiển FUSE → Trình nền FUSE → VFS → ext4 → Bộ nhớ đệm trang/Bộ nhớ.

Chế độ truyền qua FUSE

Hình 2. Yêu cầu không gian người dùng FUSE

Yêu cầu truyền tải FUSE

Hầu hết các quyền truy cập vào tệp đều được kiểm tra tại thời điểm mở tệp, với các bước kiểm tra quyền bổ sung xảy ra khi đọc và ghi vào tệp đó. Trong một số trường hợp, bạn có thể biết tại thời điểm mở tệp, ứng dụng yêu cầu có toàn quyền truy cập vào tệp được yêu cầu, vì vậy, hệ thống không cần tiếp tục chuyển tiếp các yêu cầu đọc và ghi từ trình điều khiển FUSE đến trình nền FUSE (vì việc đó sẽ chỉ di chuyển dữ liệu từ nơi này sang nơi khác).

Với tính năng chuyển tiếp FUSE, trình nền FUSE xử lý yêu cầu mở có thể thông báo cho trình điều khiển FUSE rằng thao tác này được cho phép và tất cả các yêu cầu đọc và ghi tiếp theo có thể được chuyển tiếp trực tiếp đến hệ thống tệp cấp thấp hơn. Điều này giúp tránh được chi phí hao tổn khi chờ trình nền FUSE của không gian người dùng trả lời các yêu cầu của trình điều khiển FUSE.

Dưới đây là thông tin so sánh về yêu cầu truyền tải FUSE và FUSE.

So sánh tính năng truyền tải FUSE

Hình 3. Yêu cầu FUSE so với yêu cầu truyền tải FUSE

Khi một ứng dụng thực hiện quyền truy cập vào hệ thống tệp FUSE, các thao tác sau sẽ xảy ra:

  1. Trình điều khiển FUSE xử lý và thêm yêu cầu vào hàng đợi, sau đó hiển thị yêu cầu đó cho trình nền FUSE xử lý hệ thống tệp FUSE đó thông qua một thực thể kết nối cụ thể trên tệp /dev/fuse mà trình nền FUSE bị chặn đọc.

  2. Khi nhận được yêu cầu mở tệp, trình nền FUSE sẽ quyết định xem có nên cung cấp tính năng truyền tải FUSE cho tệp cụ thể đó hay không. Nếu có, trình nền sẽ:

    1. Thông báo cho trình điều khiển FUSE về yêu cầu này.

    2. Bật tính năng truyền tải FUSE cho tệp bằng cách sử dụng ioctl FUSE_DEV_IOC_PASSTHROUGH_OPEN. Thao tác này phải được thực hiện trên chỉ số mô tả tệp của /dev/fuse đã mở.

  3. ioctl nhận được (dưới dạng tham số) một cấu trúc dữ liệu chứa các thông tin sau:

    • Chỉ số mô tả tệp của tệp hệ thống tệp thấp hơn là mục tiêu của tính năng truyền tải.

    • Giá trị nhận dạng duy nhất của yêu cầu FUSE đang được xử lý (phải là mở hoặc tạo và mở).

    • Các trường bổ sung có thể để trống và dành cho các hoạt động triển khai trong tương lai.

  4. Nếu ioctl thành công, trình nền FUSE sẽ hoàn tất yêu cầu mở, trình điều khiển FUSE sẽ xử lý phản hồi của trình nền FUSE và tham chiếu đến tệp hệ thống tệp thấp hơn sẽ được thêm vào tệp FUSE trong hạt nhân. Khi một ứng dụng yêu cầu thao tác đọc/ghi trên tệp FUSE, trình điều khiển FUSE sẽ kiểm tra xem có tham chiếu đến tệp hệ thống tệp cấp thấp hơn hay không.

    • Nếu có tham chiếu, trình điều khiển sẽ tạo một yêu cầu Hệ thống tệp ảo (VFS) mới với cùng các tham số nhắm đến tệp hệ thống tệp cấp thấp hơn.

    • Nếu không có tệp tham chiếu, trình điều khiển sẽ chuyển tiếp yêu cầu đến trình nền FUSE.

Các thao tác trên xảy ra đối với read/write và read-iter/write-iter trên các tệp chung và thao tác read/write trên các tệp ánh xạ bộ nhớ. Chế độ truyền tải FUSE cho một tệp nhất định sẽ tồn tại cho đến khi tệp đó bị đóng.

Triển khai tính năng truyền qua FUSE

Để bật tính năng truyền tải FUSE trên các thiết bị chạy Android 12, hãy thêm các dòng sau vào tệp $ANDROID_BUILD_TOP/device/…/device.mk của thiết bị mục tiêu.

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

Để tắt tính năng truyền tải FUSE, hãy bỏ qua thay đổi cấu hình ở trên hoặc đặt persist.sys.fuse.passthrough.enable thành false. Nếu trước đó bạn đã bật tính năng truyền tải FUSE, thì việc tắt tính năng này sẽ ngăn thiết bị sử dụng tính năng truyền tải FUSE nhưng thiết bị vẫn hoạt động.

Để bật/tắt tính năng truyền tải FUSE mà không cần cài đặt ROM cho thiết bị, hãy thay đổi thuộc tính hệ thống bằng các lệnh ADB. Sau đây là ví dụ.

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

Để được trợ giúp thêm, hãy tham khảo phần triển khai tài liệu tham khảo.

Xác thực tính năng truyền tải FUSE

Để xác thực rằng MediaProvider đang sử dụng tính năng truyền tải FUSE, hãy kiểm tra logcat để tìm thông báo gỡ lỗi. Ví dụ:

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

Mục nhập FuseDaemon: Using FUSE passthrough trong nhật ký đảm bảo rằng tính năng truyền tải FUSE đang được sử dụng.

CTS Android 12 bao gồm CtsStorageTest, trong đó có các chương trình kiểm thử kích hoạt tính năng truyền tải FUSE. Để chạy kiểm thử theo cách thủ công, hãy sử dụng atest như minh hoạ bên dưới:

atest CtsStorageTest