數據存儲之——Android文件存儲系統及文件系統(Android Q)

Android存儲系統及存儲的掛載


Android是基於Linux內核開發的,所以它的文件系統也是跟Linux文件系統類似。

首先我們來看Android存儲的分類。

內部存儲和外部存儲、內置SD卡和外置SD卡

一般的Android手機都有2個存儲卡,一個內置到手機裏的,不可更換,叫做內置存儲卡;另外一個可以通過擴展卡槽添加一個SD卡,叫做外置SD卡。內置存儲卡和外置SD卡,它們是從物理上來進行區分的,一個內置到設備,另一個是添加的擴展卡。

對於Android系統來說,存儲只分爲內部存儲和外部存儲兩類。內部存儲是在應用的安裝目錄下(data目錄),外部存儲(通常是sdcard目錄)在應用的安裝目錄外,它們是以目錄爲基準劃分的。我們不要和內置存儲卡和外置SD卡的概念混淆了,一個是邏輯上的劃分,另一個是物理上的劃分。

存儲所需要的權限

我們在進行App開發時,通常需要對App的存儲權限做一些處理:

  • 內部存儲不需要App單獨申請權限。
  • 外部存儲需要App申請外部存儲的讀寫權限,並且使用時,首先要判斷外部存儲是否已經掛載(因爲外部存儲並不總是可用)。
  • 讀權限:android.permission.READ_EXTERNAL_STORAGE
  • 讀寫權限:android.permission.WRITE_EXTERNAL_STORAGE

我們已經瞭解了存儲分爲內部存儲和外部存儲,接下來我們來分析外部存儲是如何被掛載到系統的。

外部存儲的掛載

sdcard是我們常說的sd卡根目錄,我們以它爲例,來分析外部存儲是如何掛載到系統的。

路徑的鏈接關係

我們來看sdcard的路徑鏈接關係:

/sdcard -> /storage/self/primary
/mnt/sdcard -> /storage/self/primary

/storage/self/primary -> /mnt/user/0/primary
/mnt/runtime/default/self/primary -> /mnt/user/0/primary

/mnt/user/0/primary -> /storage/emulated/0
說明:
  • sdcard是一個軟鏈接,它的真實地址是/storage/self/primary。
  • /storage/self/primary和/mnt/runtime/default/self/primary也是軟鏈接,它們的實際地址是/mnt/user/0/primary。
  • /mnt/user/0/primary也是軟鏈接,它的實際地址是/storage/emulated/0。
  • 最終是鏈接到/storage/emulated/0目錄。

/mnt/runtime/default的掛載

/mnt/runtime/default在開機執行init.rc時,掛載到storage下:

    # Mount default storage into root namespace
    mount none /mnt/runtime/default /storage bind rec

並且在執行init.rc腳本時進行了軟鏈接:

    # Symlink to keep legacy apps working in multi-user world
    symlink /storage/self/primary /sdcard
    symlink /storage/self/primary /mnt/sdcard
    symlink /mnt/user/0/primary /mnt/runtime/default/self/primary

/mnt/runtime各個目錄意義:

/mnt/runtime/default:對所有的應用、root命名空間 可見,而無需任何權限.
/mnt/runtime/read:對有READ_EXTERNAL_STORAGE權限的應用可見。
/mnt/runtime/write:對有WRITE_EXTERNAL_STORAGE權限的應用可見。

出現這三個不同權限目錄的原因是控制不同權限app訪問。然後利用掛載命名空間實現了掛載點的隔離,在不同掛載命名空間的進程,看到的目錄層次不同。

每個app都根據自己的授權,選擇了不同權限的runtime目錄進行訪問,而不同用戶訪問的目錄也根據當前用戶的id區分開了。

軟鏈接&硬鏈接

上文中,我們知道Android文件系統用到了很多軟鏈接,那麼什麼是軟鏈接呢?鏈接又分爲幾種類型呢?

* 軟鏈接

軟鏈接又叫符號鏈接,這個文件包含了另一個文件的路徑名。可以是任意文件或目錄,可以鏈接不同文件系統的文件,類似於windows中的快捷方式。鏈接文件甚至可以鏈接不存在的文件。

* 硬鏈接

硬鏈接相當於一個災備份,數據存放在兩處,與複製不同的是兩處之間存在同步機制,一處數據的改變會實時同步到另一處,另外一處數據如果被刪除了,不會影響到另一處的數據.

硬鏈接,以文件副本的形式存在,但不佔用實際空間。硬鏈接文件有兩個限制:不允許給目錄創建硬鏈接;只有在同一文件系統中的文件之間才能創建鏈接。

權限控制與文件系統


Android 8.0以上開始支持SDcardFS文件系統,它是由三星wrapfs改寫而成。

fuse文件系統(Filesystem in Userspace)

早期的版本android系統使用的是fuse文件系統,用於控制不同APP對文件訪問的權限。

Android將手機內置SD卡與userdata分區合併成爲一個分區。userdata分區使用ext4文件系統存儲數據,訪問userdata分區是直接操作ext4文件系統,而訪問內置SD卡,則是先訪問fuse文件系統,然後再訪問ext4文件系統。

fuse文件系統的基本方法是,創建fuse設備,並將fuse設備掛載到與內置SD卡目錄關聯的目錄。那麼,對內置SD卡的訪問變成了先訪問fuse文件系統,再訪問ext4文件系統。fuse的內核部分創建了多個隊列,其中包含一個pending隊列和一個processing隊列。每當有調用者對內置SD卡的系統調用時,fuse把文件訪問路徑轉換爲對ext4文件系統的操作路徑,設置對應的操作碼,並放入一個請求中。fuse在用戶態有3個監控線程,循環地讀取fuse設備。對fuse設備的讀取操作在內核部分轉換從pending隊列讀取請求,如果隊列中沒有請求,則對應的線程進入睡眠狀態。監控線程讀取到pending隊列中的請求後,把請求轉換爲對ext4文件系統的系統調用操作。系統調用執行完成後,監控線程把執行結果寫入到fuse設備,對fuse設備的寫操作在內核部分轉換爲把結果放入processing隊列。processing隊列依次取出結果,返回給調用者。

fuse需要進行多次的用戶態與內核態交互,這樣就會造成切換開銷。

SDcardFS文件系統

sdcardfs的作用與fuse相同,也是用於控制文件訪問的權限。sdcardfs的工作方式是把內置SD卡目錄掛載到用於權限控制目錄。對內置SD卡的系統調用,先經過sdcardfs,然後把訪問路徑改爲ext4文件系統的真正路徑,再到達ext4文件系統。ext4執行完以後,把結果返回給sdcardfs,再返回給調用者。

sdcardfs的優勢:
  1. 對同一個文件訪問,fuse需要經過6次用戶態與內核態的切換,但是sdcardfs只需要經過2次切換。
  2. fuse在內核中有多個隊列,隊列中元素的出列要等帶前面的元素先出列,因此單次文件訪問,fuse比sdcardfs需要更多的時間。當需要進行大量的文件訪問時,累積產生時間差異是可以明顯感覺出來的。
  3. SDcard由於減少了用戶態與內核態的切換,其理論性能會十分接近真實系統系統。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章