不知道你有麼有發現,來自菜鳥的成長史:http://blog.csdn.net/zjbpku/article/details/25161131,
KitKat之後的版本不再支援使用者對外置SDcard(Secondary Storage)的寫入等操作。如果使用者想要將檔案等copy到手機中,則只能
儲存到內部儲存空間中,而無法儲存到外置sdcard中,而且無法建立新的檔案夾,這樣一來給使用者和開發人員都帶來了一定的不便。之所
以在KitKat之後版本中無法操作外置Sdcard,是因為Google更改了此模組的許可權,以前我們可以直接擷取WRITE_EXTERNAL_STORAGE
和READ_EXTERNAL_STORAGE許可權來直接操作Sdcard,現在則不能,其目的是軟體卸載時能將該軟體建立的檔案全部刪除。據Google
員工Jeff SharKey(此模組的開發人員)介紹,自Kitkat之後Anroid提供了新的API去訪問Secondary External Storage,但這不是本文重點,本
文重點是分析外部儲存許可權是如何作用的。
在KitKat之前的Android版本會給應用程式單獨分出一塊外部儲存空間(external storage),這Block Storage空間可能在sdcard
(可插拔的外置sdcaard)上,也可能在僅僅是在裝置內部的快閃記憶體上,我們要獲得WRITE_EXTERNAL_STORAGE許可權在能對這塊
空間進行訪問,如果只是讀取內容則不需要許可權。在4.4 KitKat及之後的版本中,Google做了兩個變化:1、進行讀取時需要
READ_EXTERNAL_STORAGE許可權;2、訪問應用所屬的目錄下(如:android/data/[package name])儲存的資料是不需要任
何許可權的。
KitKat中,外部儲存(external storage)被分割成了多個部分:一個“primary”部分,一個或多個“secondary”部分。在Kitkat之前的
API 可以用來操作 primary external storage,secondary external storage 是對write許可權做了稍微修改,與上邊所述一樣,在應用所
所屬的目錄(如:android/data/[package name])下,對檔案是有所有操作許可權的,在應用所能管理到目錄之外,該應用則不具有寫
的許可權,不能進行任何寫的操作。這裡也就引出了本文的重點。ps:Google雖然沒有要求各廠商在Sdcard的操作上添加額外許可權,但
是它卻強制要求製造商對secondary external storage做了許可權限制。如果你對Internal storage和external storage有疑問,可以看看文
檔 https://developer.android.com/guide/topics/data/data-storage.html#filesInternal
根據Jeff SharKey 的介紹,目前的版本的Android系統,也就是Kitkat,使用FUSE (Filesysgem in Userspace ) 對external storage進
行管理。為了在檔案建立時擷取必要的許可權,動態地接受或拒絕來自使用者/組的個別請求,會有一個Android 守護進程參與與FUSE 核心
驅動的互動。這僅僅是Android在FAT File System 格式化後的可移動卷上使用Linux型許可權的一部分,在核心中它也允許使用超出基本的
owner/gouper/user 執行的多級許可權控制。看看下面Jeff Sharkey的解釋:
https://android.googlesource.com/platform/system/core/+/master/sdcard喎?http://www.bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vc2RjYXJkLmM8YnI+CjwvcD4KPHA+PGJyPgo8L3A+CjxwPjwvcD4KPHA+1No0LjTWrsewo6xmcmFtZXdvcmsgYXBpttS05rSivu0oc3RvcmFnZSB2b2x1bWVzKbXEstnX97Kiw7vT0LrctPO1xLjEseSjrMnosbjWxtTsycy/ydLUtLS9qLWluPahsHByaW1hcnmhsb7tu/LV37bguPahsHNlY29uZGFyeaGxPC9wPgo8cD6+7aOstvjV4tCpsrvNrLXEvu22vMTcsbvPtc2zt/7O8VN0b3JhZ2VNYW5hZ2Vyus1Nb3VudFNlcnZpY2W53MDto6zV4tbQx+m/9s/Ct8POyqGwcHJpbWFyeaGxsr+31r7Nz/G3w87KtaW49mV4dGVybmFsIHN0b3JhZ2XSu9H5oaM8L3A+CjxwPrrctuDJ6LG409BTZL+oo6y1q8rHtrzDu9PQsNHL/LWx1/dleHRlcm5hbCBzdG9yYWdlo6zKtbzKyc/V4r7NysfV4tCpyeixuLXEobBzZWNvbmRhcnkgdm9sdW1lobGho8D9yOejrMj90Me1xEdhbGF4ec+1wdC+zcrHyvTT2tXiPC9wPgo8cD7Su8Dgo6y008ioz963vcPmwLTLtaOsc2S/qMbkyrXP8c3isr+05rSivu3Su9H5sbu53MDto6y1q8rH1/fOqsnosbi1xKGwc2Vjb25kYXJ5IGV4dGVybmFsIHN0b3JhZ2U=",是沒有API可以進行寫的操作的。
下面的這段代碼來自AOSP device storage conf iguration example:
on initmkdir /mnt/shell/emulated 0700 shell shellmkdir /storage/emulated 0555 root rootmkdir /mnt/media_rw/sdcard1 0700 media_rw media_rwmkdir /storage/sdcard1 0700 root rootexport EXTERNAL_STORAGE /storage/emulated/legacyexport EMULATED_STORAGE_SOURCE /mnt/shell/emulatedexport EMULATED_STORAGE_TARGET /storage/emulatedexport SECONDARY_STORAGE /storage/sdcard1
系統內部的應用可以訪問secondary storage的任何部分,對於第三方應用幾乎不可能(目前ES FileExplore、Airdroid、Fx等幾個檔案應用通過
特別的解決方案可以實現對某些機型外部隱藏檔的操作)。(關於如何在4.4上操作檔案可以參考Storage Options。自4.4開始,Google引入
SAF架構(Storage Access Framework),如果Google以後不改變現在對4.4系統外置sd的操作許可權,對於開發人員而言,熟悉SAF架構也許是必要的。
另,在4.4系統內部應用中,你會發現有一個叫DocumentUI的apk,這個就是用來處理SAF的一些介面的。)
在external storage下的目錄檔案擁有相同的許可權,如下:
4.4 裝置:
root@generic:/storage/sdcard # lld---rwxr-x system sdcard_rw 2014-05-06 13:20 Alarmsd---rwxr-x system sdcard_rw 2014-05-06 13:21 Androidd---rwxr-x system sdcard_rw 2014-05-06 13:20 DCIMd---rwxr-x system sdcard_rw 2014-05-06 13:20 Downloadd---rwxr-x system sdcard_rw 2014-05-06 13:18 LOST.DIRd---rwxr-x system sdcard_rw 2014-05-06 13:20 Moviesd---rwxr-x system sdcard_rw 2014-05-06 13:20 Musicd---rwxr-x system sdcard_rw 2014-05-06 13:20 Notificationsd---rwxr-x system sdcard_rw 2014-05-06 13:20 Picturesd---rwxr-x system sdcard_rw 2014-05-06 13:20 Podcastsd---rwxr-x system sdcard_rw 2014-05-06 13:20 Ringtonesroot@generic:/storage/sdcard # ll Android/data/drwxrwx--- system sdcard_rw 2014-05-06 13:21 com.google.android.apps.maps
4.4 裝置:
root@generic:/storage/sdcard # lldrwxrwx--- root sdcard_r 2013-11-27 23:35 Alarmsdrwxrwx--x root sdcard_r 2013-11-27 23:36 Androiddrwxrwx--- root sdcard_r 2014-05-06 01:33 DCIMdrwxrwx--- root sdcard_r 2013-11-27 23:35 Downloaddrwxrwx--- root sdcard_r 2013-11-28 04:33 LOST.DIRdrwxrwx--- root sdcard_r 2013-11-27 23:35 Moviesdrwxrwx--- root sdcard_r 2013-11-27 23:35 Musicdrwxrwx--- root sdcard_r 2013-11-27 23:35 Notificationsdrwxrwx--- root sdcard_r 2013-11-27 23:35 Picturesdrwxrwx--- root sdcard_r 2013-11-27 23:35 Podcastsdrwxrwx--- root sdcard_r 2013-11-27 23:35 Ringtonesroot@generic:/storage/sdcard # ll Android/data/drwxrwx--- u0_a33 sdcard_r 2013-11-27 23:36 com.google.android.apps.mapsroot@generic:/storage/sdcard # ll Android/data/com.google.android.apps.maps/drwxrwx--- u0_a33 sdcard_r 2013-11-27 23:36 cachedrwxrwx--- u0_a33 sdcard_r 2013-11-27 23:36 testdata
注意:在4.3中,sdcard_rw組有全部的讀寫權限,在Kitkat中,sdcard_r 組有 +rwx 所有許可權,實際上這是明顯不對的。並不等表示全部,
因為Fuse守護進程會在運行時中積極地參與修改應用的許可權。這對File APIs canWrite(),canRead()和canExecute()的執行結果有很大的影
響,這些方法返回的值被單獨地記錄在核心檔案系統中,所以他們都會返回true,即使試圖以POSIX開啟檔案也會失敗。(在4.4的外置sd
卡上,是不能在檔案夾寫入一下檔案的,但是當你試圖調用canWrite()方法來判斷該檔案夾是否可寫時,它仍會返回true值,所以此法不可取)
android.permission.WRITE_EXTERNAL_STORAGE許可權被授給sdcard_r組和sdcard_rw組的成員,但在kitkat中認證write許可權需要一些動
態的檢查,因此FUSE守護進程會被用來補充檔案系統的許可權,FUSE守護進程會強制賦予擁有特定目錄的App每個許可權(也就是訪問自身數
據儲存的目錄android/data/pack-agename...及一些公用目錄)。對於sdcard_rw組中使用-w標誌配置的非預設所有者,FUSE守護進程也會強
制賦予write-protected許可權。
service sdcard /system/bin/sdcard -u 1023 -g 1023 -l /data/media /mnt/shell/emulated class late_startservice fuse_sdcard1 /system/bin/sdcard -u 1023 -g 1023 -w 1023 -d /mnt/media_rw/sdcard1 /storage/sdcard1 class late_start disabled
從上面兩句程式可以看到,FUSE守護進程強制控制GID 1023(media_rw,系統應用才有)才能對secondar storage進行寫操作。再引入
一個問題,在4.4中將external storage 分為primary和secondary,在primary部分(內建sdcard)是可以進行寫操作的,而在secondary部分
(外置sdcard)是不允許的,那FUSE Daemon是如何區分控制的呢?據Jeff 解釋說: “-w 2013" 就表明了強制使用media_rw GID才能在
secondary部分具有write許可權。
下面我們就梳理一下,如果在擁有外置sd卡的kitkat裝置上進行檔案操作,對於開發人員而言哪些能做、哪些不能做?給出開發人員會嘗試
的一些操作及結果:
總結一下,自4.4開始Google對secondary volume做了限制之後,不僅為使用者帶來了不便,也為裝置製造商及開發人員帶來了諸多不便,華為
更是為此給開發人員們發了一份通告:Android4.4上應用寫外卡的相容性問題與解決建議。如今,除了一些OEM廠商自行修改許可權後的Rom對
第三方應用沒有限制外,大牛們也為已Root的裝置使用者提出修改platform.xml檔案來修改許可權(具體放法請百度之)以使第三方應用可以操作
外置sd卡;還有一些上面提到的檔案管理工具也可以操作外置sd卡。不管Google做限制的初衷是什麼,希望Google從使用者的角度來考慮問題,
對Android系統做出更好的該進。在此感謝一下FX 檔案管理工具的開發人員Tod Liebeck 在G+對我問題的及時解答及協助,同時也感謝一下給
Tod Liebeck解決Kitkat外置sd檔案操作方案的X-plore的開發人員。