一般再访问sd卡前都要获取sd卡的路径,以防止不同的厂商有不同的路径配置。Android提供了Environment类来获取系统当前sd卡路径。
Log.d(TAG, Environment.getExternalStorageDirectory().getAbsolutePath());
以手上的三星手机为例,打印出来的结果是
533 09-20 14:29:47.850 D 32105 32105 sdtest : /storage/emulated/0
adb shell连上手机确认下路径
1 root@degasveltechn:/proc/32105 # cat mounts 2 cat mounts 3 ... 4 /dev/block/platform/soc.2/by-name/USER /data ext4 rw,seclabel,nosuid,nodev,noatime,discard,journal_checksum,journal_asyn 5 c_commit,noauto_da_alloc,data=ordered 0 0 6 ... 7 /data/media /storage/emulated/0 sdcardfs rw,nosuid,nodev,relatime,uid=1023,gid=1023,derive=legacy,reserved=20MB 0 0
/storage/emulated/0 目录是以sdcardfs方式挂载到目录/data/media,/data目录是系统目录,由此可见
Environment.getExternalStorageDirectory()
获取到的是机身内部SD卡的地址,并不是真正外部SD卡的地址。android系统是区分内部SD卡和外部SD卡两种,一般内部SD卡是内部ROM存储空间的一部分切割出来的,逻辑的意义大于物理。
当我们想用如下方法访问SD卡的时候
1 File sd = new File(Environment.getExternalStorageDirectory(), "text.txt"); 2 try { 3 sd.createNewFile(); 4 } catch (IOException e) { 5 e.printStackTrace(); 6 }
会发现再createNewFile()的时候程序抛出了一个IO异常,系统调用open的时候被返回EACCES文件访问权限错误了。
1036 09-20 14:46:28.850 W 32368 32368 System.err: java.io.IOException: open failed: EACCES (Permission denied) 1037 09-20 14:46:28.850 W 32368 32368 System.err: at java.io.File.createNewFile(File.java:946)
1053 09-20 14:46:28.850 W 32368 32368 System.err: Caused by: libcore.io.ErrnoException: open failed: EACCES (Permission denied
因为我们没有在AndroidManifest.xml里面加入权限使用的声明
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Android对于SD卡目录的访问权限限制并不是直接通过控制linux内核文件权限rwx标志位来限制应用访问,而是间接通过package management service控制一个文件
/data/system/packages.list
来实现,我们先看下未加入uses-permission声明的时候,该文件的内容是什么
cat /data/system/packages.list | grep sdtest com.example.sdtest 10155 1 /data/data/com.example.sdtest default none
当前拥有的组权限是none,再增加了user-permission声明之后,再看文件内容变成了
cat /data/system/packages.list | grep sdtest com.example.sdtest 10155 1 /data/data/com.example.sdtest default 1028,1015
新增了1028和1015组权限。
而1028正好是sdcard_r,因而就间接拥有了SD卡的访问权限。