不知道你有么有發現。來自菜鳥的成長史: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),這塊存儲空間可能在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/sdcard.c
在4.4之前,framework api對存儲卷(storage volumes)的操作並沒有非常大的改變,設備制造商能夠創建單個“primary”卷或者多個“secondary”
卷。而這些不同的卷都能被系統服務StorageManager和MountService管理,這中情況下訪問“primary”部分就像訪問單個external storage一樣。
非常多設備有Sd卡,可是都沒有把它當作external storage,實際上這就是這些設備的“secondary volume”。比如,三星的Galaxy系列就是屬於這
一類,從權限方面來說。sd卡事實上像外部存儲卷一樣被管理。可是作為設備的“secondary external storage",是沒有API能夠進行寫的操作的。
以下的這段代碼來自AOSP device storage conf iguration example:
on init mkdir /mnt/shell/emulated 0700 shell shell mkdir /storage/emulated 0555 root root mkdir /mnt/media_rw/sdcard1 0700 media_rw media_rw mkdir /storage/sdcard1 0700 root root export EXTERNAL_STORAGE /storage/emulated/legacy export EMULATED_STORAGE_SOURCE /mnt/shell/emulated export EMULATED_STORAGE_TARGET /storage/emulated export 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 # ll d---rwxr-x system sdcard_rw 2014-05-06 13:20 Alarms d---rwxr-x system sdcard_rw 2014-05-06 13:21 Android d---rwxr-x system sdcard_rw 2014-05-06 13:20 DCIM d---rwxr-x system sdcard_rw 2014-05-06 13:20 Download d---rwxr-x system sdcard_rw 2014-05-06 13:18 LOST.DIR d---rwxr-x system sdcard_rw 2014-05-06 13:20 Movies d---rwxr-x system sdcard_rw 2014-05-06 13:20 Music d---rwxr-x system sdcard_rw 2014-05-06 13:20 Notifications d---rwxr-x system sdcard_rw 2014-05-06 13:20 Pictures d---rwxr-x system sdcard_rw 2014-05-06 13:20 Podcasts d---rwxr-x system sdcard_rw 2014-05-06 13:20 Ringtones root@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 # ll drwxrwx--- root sdcard_r 2013-11-27 23:35 Alarms drwxrwx--x root sdcard_r 2013-11-27 23:36 Android drwxrwx--- root sdcard_r 2014-05-06 01:33 DCIM drwxrwx--- root sdcard_r 2013-11-27 23:35 Download drwxrwx--- root sdcard_r 2013-11-28 04:33 LOST.DIR drwxrwx--- root sdcard_r 2013-11-27 23:35 Movies drwxrwx--- root sdcard_r 2013-11-27 23:35 Music drwxrwx--- root sdcard_r 2013-11-27 23:35 Notifications drwxrwx--- root sdcard_r 2013-11-27 23:35 Pictures drwxrwx--- root sdcard_r 2013-11-27 23:35 Podcasts drwxrwx--- root sdcard_r 2013-11-27 23:35 Ringtones root@generic:/storage/sdcard # ll Android/data/ drwxrwx--- u0_a33 sdcard_r 2013-11-27 23:36 com.google.android.apps.maps root@generic:/storage/sdcard # ll Android/data/com.google.android.apps.maps/ drwxrwx--- u0_a33 sdcard_r 2013-11-27 23:36 cache drwxrwx--- 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_start service 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的開發人員。