不知道你有么有发现。来自菜鸟的成长史: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:

  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 设备:

  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 设备:

  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权限。

  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系统做出更好的该进。

在此感谢一下

id=nextapp.fx&hl=zh_CN">FX 文件管理工具的开发人员Tod
Liebeck
 在G+对我问题的及时解答及帮助。同一时候也感谢一下给

Tod Liebeck解决Kitkat外置sd文件操作方案的X-plore的开发人员。

Android 外部存储权限分析的更多相关文章

  1. Android外部存储

    WeTest 导读 外部存储作为开发中经常接触的一个重要系统组成,在Android历代版本中,有过许许多多重要的变更.我也曾疑惑过,为什么一个简简单单外部存储,会存在存在这么多奇奇怪怪的路径:/sdc ...

  2. Android外部存储 - 官方文档解读

    预备知识:External Storage Technical Information 摘要: "The WRITE_EXTERNAL_STORAGE permission must onl ...

  3. Android数据存储原理分析

    Android上常见的数据存储方式为: SharedPreferences是 Android 中比较常用的存储方法,本篇将从源码角度带大家分析一下Android中常用的轻量级数据存储工具SharedP ...

  4. Android - 数据存储 -存储文件

    Android使用的文件系统和其他平台的基本磁盘的文件系统很相似.这里将要介绍如何使用File API在Android文件系统中读写文件. File对象适合按顺序读写大量的数据.例如,适合图片文件或者 ...

  5. (数据存储)Android系统存储数据

    移动设备需要存储数据,处理数据并输出处理后的信息. 主题一:存储键值对 If you have a relatively small collection of key-values that you ...

  6. 彻底了解android中的内部存储与外部存储

    我们先来考虑这样一个问题: 打开手机设置,选择应用管理,选择任意一个App,然后你会看到两个按钮,一个是清除缓存,另一个是清除数据,那么当我们点击清除缓存的时候清除的是哪里的数据?当我们点击清除数据的 ...

  7. 彻底理解android中的内部存储与外部存储

    我们先来考虑这样一个问题: 打开手机设置,选择应用管理,选择任意一个App,然后你会看到两个按钮,一个是清除缓存,另一个是清除数据,那么当我们点击清除缓存的时候清除的是哪里的数据?当我们点击清除数据的 ...

  8. 【转】彻底理解android中的内部存储与外部存储

    我们先来考虑这样一个问题: 打开手机设置,选择应用管理,选择任意一个App,然后你会看到两个按钮,一个是清除缓存,另一个是清除数据,那么当我们点击清除缓存的时候清除的是哪里的数据?当我们点击清除数据的 ...

  9. android中的内部存储与外部存储

    我们先来考虑这样一个问题: 打开手机设置,选择应用管理,选择任意一个App,然后你会看到两个按钮,一个是清除缓存,另一个是清除数据,那么当我们点击清除缓存的时候清除的是哪里的数据?当我们点击清除数据的 ...

随机推荐

  1. 通过yum命令搭建lamp环境(centos6.5)

    centos 6.5 1.yum安装和源代码编译在使用的时候没啥区别,但是安装的过程就大相径庭了,yum只需要3个命令就可以完成,源代码需要13个包,还得加压编译,步骤很麻烦,而且当做有时候会出错,源 ...

  2. sql server 数据库跨服务器备份,复制监视器——快照代理,复制流程

    在做数据库跨服务器复制时,查看复制监视器的快照代理,可以看到复制流程,具体如下: 初始化 连接发布服务器 设置服务器数据库兼容性级别 更新索引的统计信息 在生成快照时锁定已发布的表 复制快照数据(每个 ...

  3. node 搭建本地服务器

    /** * 代理服务器 natapp -authtoken f1bdaa0535788971 * 热部署指令 supervisor index */ const Koa = require('koa' ...

  4. html——表单控件

    基本的表单控件还有html5的一些新的表单控件: <!DOCTYPE html> <html> <head> <meta charset="utf- ...

  5. Java_Web三大框架之Hibernate+HQL语言基础

    12.1 HQL语言基础Hibernate查询语言为HQL(Hibernate Query Language),可以直接使用实体类名及属性.HQL语法类似于SQL,有SQL的关键词如select.fr ...

  6. web移动端适配

    /*** html节点字体大小随屏幕大小改变 用于rem布局***/首先这是一个立即执行函数(function (doc, win) { var docEl = doc.documentElement ...

  7. bat配置JDK环境变量

    最近总是部署服务器,总是要安装配置JDK,今天就想写个bat来配置JDK的环境变量,首先介绍点bat的小知识 @符号后面的命令不会显示在terminal上 例如: @echo运行时 隐藏命令(不在te ...

  8. GridView中字符串太长处理方式

    <asp:TemplateField HeaderText="子机构编号"> <ItemTemplate> <asp:Label ID="L ...

  9. Java中内部类详解—匿名内部类

    什么是内部类? 将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类.   成员内部类 定义在类中方法外的类. 定义格式: class 外部类 { class 内部类{ } } ...

  10. cstringlist

    CStringList类成员 构造 CStringList 构造一个空的CString对象列表   首/尾访问 GetHead 返回此列表(不能是空的)中头部的元素 GetTail 返回此列表(不能是 ...