Android 外部存儲權限分析

不知道你有麼有發現,來自菜鳥的成長史:http://blog.csdn.net/zjbpku/article/details/25161131html

KitKat以後的版本再也不支持用戶對外置SDcard(Secondary Storage)的寫入等操做。若是用戶想要將文件等copy到手機中,則只能java

存儲到內部存儲器中,而沒法存儲到外置sdcard中,並且沒法建立新的文件夾,這樣一來給用戶和開發者都帶來了必定的不便。之所android

以在KitKat以後版本中沒法操做外置Sdcard,是由於Google更改了此模塊的權限,之前咱們能夠直接獲取WRITE_EXTERNAL_STORAGEshell

和READ_EXTERNAL_STORAGE權限來直接操做Sdcard,如今則不能,其目的是軟件卸載時能將該軟件建立的文件所有刪除。據Googleapi

員工Jeff SharKey(此模塊的開發者)介紹,自Kitkat以後Anroid提供了新的API去訪問Secondary External Storage,但這不是本文重點,本app

文重點是分析外部存儲權限是如何做用的。框架


在KitKat以前的Android版本會給應用程序單獨分出一塊外部存儲空間(external storage),這塊存儲空間可能在sdcardide

(可插拔的外置sdcaard)上,也可能在僅僅是在設備內部的閃存上,咱們要得到WRITE_EXTERNAL_STORAGE權限在能對這塊工具

空間進行訪問,若是隻是讀取內容則不須要權限。在4.4 KitKat及以後的版本中,Google作了兩個變化:一、進行讀取時須要ui

READ_EXTERNAL_STORAGE權限;二、訪問應用所屬的目錄下(如: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:

[java] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. on init  

  2.     mkdir /mnt/shell/emulated 0700 shell shell  

  3.     mkdir /storage/emulated 0555 root root  

  4.     mkdir /mnt/media_rw/sdcard1 0700 media_rw media_rw  

  5.     mkdir /storage/sdcard1 0700 root root  

  6.     export EXTERNAL_STORAGE /storage/emulated/legacy  

  7.     export EMULATED_STORAGE_SOURCE /mnt/shell/emulated  

  8.     export EMULATED_STORAGE_TARGET /storage/emulated  

  9.     export SECONDARY_STORAGE /storage/sdcard1  

系統內部的應用能夠訪問secondary storage的任何部分,對於第三方應用幾乎不可能(目前ES FileExploreAirdroidFx等幾個文件應用經過

特別的解決方法能夠實現對某些機型外部存儲文件的操做)。(關於如何在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 設備:

[java] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. root@generic :/storage/sdcard # ll  

  2. d---rwxr-x system sdcard_rw 2014-05-06 13:20 Alarms  

  3. d---rwxr-x system sdcard_rw 2014-05-06 13:21 Android  

  4. d---rwxr-x system sdcard_rw 2014-05-06 13:20 DCIM  

  5. d---rwxr-x system sdcard_rw 2014-05-06 13:20 Download  

  6. d---rwxr-x system sdcard_rw 2014-05-06 13:18 LOST.DIR  

  7. d---rwxr-x system sdcard_rw 2014-05-06 13:20 Movies  

  8. d---rwxr-x system sdcard_rw 2014-05-06 13:20 Music  

  9. d---rwxr-x system sdcard_rw 2014-05-06 13:20 Notifications  

  10. d---rwxr-x system sdcard_rw 2014-05-06 13:20 Pictures  

  11. d---rwxr-x system sdcard_rw 2014-05-06 13:20 Podcasts  

  12. d---rwxr-x system sdcard_rw 2014-05-06 13:20 Ringtones  

  13.   

  14. root@generic :/storage/sdcard # ll Android/data/  

  15. drwxrwx--- system sdcard_rw 2014-05-06 13:21 com.google.android.apps.maps  


4.4 設備:

[java] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. root@generic :/storage/sdcard # ll  

  2. drwxrwx--- root sdcard_r 2013-11-27 23:35 Alarms  

  3. drwxrwx--x root sdcard_r 2013-11-27 23:36 Android  

  4. drwxrwx--- root sdcard_r 2014-05-06 01:33 DCIM  

  5. drwxrwx--- root sdcard_r 2013-11-27 23:35 Download  

  6. drwxrwx--- root sdcard_r 2013-11-28 04:33 LOST.DIR  

  7. drwxrwx--- root sdcard_r 2013-11-27 23:35 Movies  

  8. drwxrwx--- root sdcard_r 2013-11-27 23:35 Music  

  9. drwxrwx--- root sdcard_r 2013-11-27 23:35 Notifications  

  10. drwxrwx--- root sdcard_r 2013-11-27 23:35 Pictures  

  11. drwxrwx--- root sdcard_r 2013-11-27 23:35 Podcasts  

  12. drwxrwx--- root sdcard_r 2013-11-27 23:35 Ringtones  

  13.   

  14. root@generic :/storage/sdcard # ll Android/data/  

  15. drwxrwx--- u0_a33 sdcard_r 2013-11-27 23:36 com.google.android.apps.maps  

  16.   

  17. root@generic :/storage/sdcard # ll Android/data/com.google.android.apps.maps/  

  18. drwxrwx--- u0_a33 sdcard_r 2013-11-27 23:36 cache  

  19. 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權限。

[java] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. service sdcard /system/bin/sdcard -u 1023 -g 1023 -l /data/media /mnt/shell/emulated  

  2.     class late_start  

  3.   

  4. service fuse_sdcard1 /system/bin/sdcard -u 1023 -g 1023 -w 1023 -d /mnt/media_rw/sdcard1 /storage/sdcard1  

  5.     class late_start  

  6.     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的開發者。

相關文章
相關標籤/搜索