Android给你讲清楚读写权限和Linux文件权限

1,270 阅读8分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天,点击查看活动详情

前言

写这篇文章是因为开发时间长了,对读写文件权限这块的不同场景涉及比较多。有经历过Android6前的,有6到9的,有分区存储的,也有自己做终端有root情况的。然后前几天碰到一个问题,就是一个场景,不需要申请权限也能读写文件,我印象中是需要的,但确实不用,所以总结这个问题的过程中回顾了以前的一些场景,就想记录下来,这样以后时间久了如果还有问题的话就能快速的找到突破口。

权限的变更

这里的权限指的是

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

根据我的总结,权限的变更分为几个阶段:
(1) Android 6.0之前,只需要在Manifest中申请就行
(2) Android 6.0之后,在Manifest中申请权限的同时还需要在代码中动态申请权限。(我开发测试的时候有个小技巧,我直接在Manifest中申请,然后在设置中直接给应用权限,这样就不用去写动态申请权限的代码)
(3) 分区存储的提出,可以参考这篇我写的旧文章,当时是经过Demo测试的,我感觉写得还不错 juejin.cn/post/715717… 。分区存储是Android10提出的,但是它影响的是9、10、11 三个版本。
(4) Android 11之后,意思是分区存储提出的时候,那三个版本挺混乱的。11之后是一个趋向稳定的状态。 (5) 有root权限,这个没什么好说的,就两个字“无敌”,有root你想怎么玩怎么玩。

在完全看懂权限这块东西之前,你需要熟悉两个知识点。第一个是分区存储,上面说了,因为比较乱,所以需要熟悉。第二个是linux的文件系统,因为Android是基于linux的。分区存储可以看看我的上一篇文章,下面我会简单说下Linux的文件系统

Linux的文件系统

我还是要强调一下,linux文件权限的重要性,因为你在Android中设置的权限都会体现在这里,我个人的习惯是如果设置权限不起作用或者使用过程中出现权限相关的问题,我会直接看linux这边的一个文件情况,再去反推一个具体的问题原因。

先介绍一下,直接在命令框内输入ls -al就能看到一个具体的文件情况:
Environment.getExternalStorageDirectory().path 的路径就是storage/emulated/0
context.getExternalFilesDir().path 的路径就是storage/emulated/0/Android/data/包名/file

ddceacd1f2e86f07715f82b0d769a57.png

f0d5bc9446fd44387b41b329df2c93e.png

其中比较重要的是权限和权限的定义。先来看看权限的描述:

-rw-rw----,拆分成-和rw-和rw-和----4个部分

第一部分描述的是文件类型:
(1) d: 文件夹
(2) -: 普通文件
(3) l: 连接文件
(4) p: 管道
(5) s: 套接口
(6) c: 字符设备
(7) b: 设备文件

举个例子,一般我们会看到d和-比较多,就是普通的文件和文件夹,我这里举例下l连接文件。

006474860db3cac8200e4c94ec33601.png

这里能看到我们常用的sdcard其实是storage/sself/primary这个路径下的。
然后看看rwx这三个含义:
-表示没权限,r表示读,w表示写,x表示操作这是最基本的。他们的组成有几种相信大家一看就能领悟,比如r--表示只读,rw-表可读可写,---表示没权限,相信一眼就能看出来。
再往深扩展一下,每个标志都是一个二进制,比如rwx就是111,转换过来就是7,那么例如drwxrwxrwx这样的,转过来就是777,也就是说是有个数字能表示这个文件的权限的,而这个数字就是这么计算而来的。修改文件权限的命令我就不说了,因为相信很多人都没有root,没root你也改不了,有root的也知道怎么改。

然后需要再了解下,文件所有者、文件所属组、其它用户,这3个代表什么。
简单来讲,文件所有者就是是谁创建了这个文件,而每个文件所有者都有一个所属组,其它用户的意思就是这个组之外的用户。
比如上面截图中,文件所有者root,说明这个文件是root创建的,它属于root这个组,那下面那个shell能不能读写这个文件?能读,不能写,为什么?因为文件所有者是root,不是shell,所以第一段的rw-对shell不起作用,shell也不属于root这个组,所以第二段的r--也不适用,那它就是属于其它用户,shell对于sdcard这个文件属于其它用户,所以第三段r--对它试用,r--就是只读。

对于Android来说,storage/emulated/0下的,我们称之为外部存储,在分区存储出现之前,你能在外部存储的根目录下创建文件,这些不会随应用的卸载而被删除,所以乱,所以才出现分区存储,扯远了拉回来。那么getDir()就是内部存储,内部存储会随应用的卸载而删除,就是data/data/报名这个目录下。

3c5c120a7ecde35e19e999a1521ee9e.png

但是,我们这没有权限进去。

举例文件权限问题的解决过程

我碰到的问题是这样的,因为我近2年是做终端的,有root权限,就是想怎么玩就怎么玩。然后我最近在写Demo的时候就发现getExternalFilesDir("xxx"),也会是storage/emulated/0/Android/data/包名/files/xxx这个目录下,不用申请权限。
这时我就觉得有点奇怪,就看了下这个文件。我这里埋一个点,之后的截图我会用两个设备进行交替,如果看不懂,说明你对上面讲的linux文件权限还是没懂,需要再认真去看。

d4501fb6b1b7ea59f0b7536fd6c8ffb.png

看到我的files文件下的文件所有者是u0_a2036,这个是什么,这个就是我的这个应用。我现在这里的是未申请读写权限的情况下,看到它的权限是rwx,也就是说我们的应用有这个文件的读写权限,这个就是结论。通过这个结论再去推为什么我们不用申请权限也能读写。

可能说得不太清楚,这里rwx...... u0_a2036的意思就是这个文件的拥有者是我的应用,这个文件给文件拥有者的权限是rwx。而如果我假设这个文件是drwxrwxrwx 2 root root,这种情况下,我们u0_a2036能读写这个文件就是因为这个文件是全开发,而不是因为我们是这个文件的拥有者。再比如假设文件是drwxrwx--- 2 root aaa,并且我们的u0_a2036属于aaa这个组的情况下也能读写这个文件,这时候就是因为我们u0_a2036属于的组aaa拥有这个文件的读写权限。相信这样说已经很详细了。

反推的话我去官网看为什么会这样,是不是一开始这个路径下的文件的读写操作就不需要去申请读写权限。

0dce74fd560a3187cedb089259f4a7c.png

能看到官网确实有这样的一个说明。

那如果有人说,我知道文件用这者是谁,我想知道它属于哪个组怎么办,这个可以用命令去查看

95a2c6b6af36f4ae100bbe6e084d996.png

比如这里,我们看到u0_a194这个拥有者他所属的组就是他自己,一般来说,拥有者自己的组如果没有去特殊设置的话就是他自己,那么我们能设置它的组吗?当然可以,但是你得拥有root权限。

38934629b68ad833ed168bd0d3aa40a.png

假如我这里没有root权限,我去给文件设置组,会发现没有任何效果。

结论

结论就是Android里面的所有对文件权限的操作,其实都是反应到linux上。假如你碰到某些问题,你可以直接先去看这个文件的拥有者和权限这些信息,这些就是结论。再通过结论去反推造成你出现权限问题的原因。像我上面说的Android不同版本有不同的文件权限管理,6之前,6之后,分区存储的9、10、11三个版本,11之后,看着很乱,实则所有操作都会反映到Linux上。这是我对linux文件权限的一个了解,如果有说得不对的地方,希望能有大佬及时指出,我个人也是在一个学习的阶段,并没有说对Linux这块精通。