Android系统 理解/sys/目录权限和UID和GID?
数据和文件存储概览 | Android 开发者 | Android Developers..
Android应用的存储路径分为内部和外部存储。内部存储固定且小,外部存储如SD卡容量大但可能不稳定。应用在这两种存储中都有私有目录,仅该应用可访问且随应用卸载而删除。外部存储的公共目录可被其他应用访问,且不随应用卸载而删除。
存储类型 | 特点 | 是否私有 | 是否随应用卸载删除 | 是否可被其他应用访问 |
内部存储 | 固定且容量小 | 是 | 是 | 否 |
外部存储(专属目录) | 容量大,可能不稳定 | 是 | 是 | 否 |
外部存储(公共目录) | 容量大,可能不稳定 | 否 | 否 | 是 |
Android应用的文件访问能力基于其请求的权限。与存储相关的权限有READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE和MANAGE_EXTERNAL_STORAGE。Android 10及以上版本引入了分区存储,限制应用只能访问其专属目录和特定媒体文件。
权限名称 | 功能描述 | Android 10及以上版本的特点 |
READ_EXTERNAL_STORAGE | 读取外部存储中的文件 | 只能访问专属目录和特定媒体文件 |
WRITE_EXTERNAL_STORAGE | 写入外部存储中的文件 | 只能访问专属目录和特定媒体文件 |
MANAGE_EXTERNAL_STORAGE | 管理外部存储的文件 | 可以访问和管理所有文件 |
Android文件系统和目录结构
Android有特殊类型的应用,根据其存储路径和权限不同,分为系统预装应用、特权系统应用、用户安装应用和平台签名应用。它们的存储位置和权限级别各不相同。
这些特殊类型的应用包括:
应用类型 | 存储路径 | 权限级别 | 是否可被用户卸载 | 特点 |
系统预装应用 | /system/app |
高 | 否 | 系统预装 |
特权系统应用 | /system/priv-app |
最高 | 否 | 系统预装、且具有特权签名 |
用户安装应用 | /data/app |
普通 | 是 | 通过商店或手动安装 |
平台签名应用 | /system/app 或/system/priv-app |
高至最高 | 取决于存储位置 | 使用与系统相同的签名密钥 |
Android文件系统概述
Android文件系统是一种基于Linux的文件系统,它用于管理设备上的文件和目录。Android文件系统可以分为两个主要部分:系统分区和数据分区。系统分区是指存储设备上的一块固定大小的空间,它用于存储Android系统的核心组件,如内核,引导加载器,恢复模式,系统应用等。数据分区是指存储设备上的剩余空间,它用于存储用户数据,如应用,照片,音乐,文档等。
Android目录结构和主要目录的作用
Android文件系统包含多个主要目录,如根目录、系统分区、数据分区、外部存储、缓存和设备文件目录。每个目录都有其特定的作用和访问权限。
目录名称 | 描述 | 访问权限 | 主要用途 |
/ |
根目录 | 取决于子目录 | 所有其他目录的父目录 |
/system |
系统分区根目录 | 通常只读 (除非有root权限 umount) | 存储Android系统核心组件和配置 |
/data |
数据分区根目录 | 可读写 (需要权限) | 存储用户数据和应用数据 |
/sdcard |
外部存储根目录 | 可读写 (需要权限) | 存储用户在外部存储的文件 |
/cache |
临时缓存目录 | 可读写 | 存储临时文件,如更新包 |
/dev |
设备文件目录 | 通常只读 (需要特殊权限) | 表示设备上的硬件 |
此外,还有其他目录如/proc
,/sys
,/mnt
等,用于特定的系统任务和功能。
/system/app目录的作用和特性
/system/app
目录存储系统预装或通过刷机安装的应用。这些应用具有高权限,不可被用户卸载,且在设备启动时自动加载。它们通常使用系统签名,不需申请运行时权限,并可通过sharedUserId
共享数据。安装应用到此目录可以通过adb
命令或刷机包。
特性/操作 | 描述 |
目录作用与特性 | |
访问权限 | 通常只读,需要root/remount权限进行修改 |
加载时机 | 设备启动时自动加载 |
权限与API | 可访问系统保护的权限和API |
文件访问 | 可访问所有文件和目录 |
应用特点 | |
签名 | 通常使用与系统相同的签名 |
权限请求 | 使用AndroidManifest.xml 声明,无需运行时权限 |
数据共享 | 使用sharedUserId 共享UID和进程空间 |
安装方法 | |
使用adb | 使用adb命令复制应用到目录,修改权限和所有者 |
预置 | 系统打包固件的时候预置进系统 |
/system/priv-app目录的作用和特性
/system/priv-app
目录存储具有特权签名的系统预装或刷机安装应用。这些应用具有最高权限,不可被用户卸载。它们在设备启动时加载,可访问所有权限/API,并通常使用系统签名。
/data/app目录的作用和特性
特性/操作 | 描述 |
目录作用与特性 | |
访问权限 | 通常只读,需要root或刷机操作进行修改 |
加载时机 | 设备启动时自动加载 |
权限与API | 可访问所有权限和API,包括特权权限 |
文件访问 | 可访问所有文件和目录 |
应用特点 | |
签名 | 必须使用与系统相同的签名,并声明android:sharedUserId="android.uid.system" |
权限请求 | 可直接使用任何权限,无需声明 |
数据共享 | 使用sharedUserId 共享UID和进程空间 |
安装方法 | |
使用adb | 使用adb命令复制应用到目录,修改权限和所有者 |
预置 | 系统打包固件的时候预置进系统 |
/data/app
目录存储用户通过商店或其他渠道安装的应用。这些应用具有普通权限,可被用户卸载。它们在安装或更新时加载,可访问普通权限/API,但需申请运行时权限。
特性/操作 | 描述 |
目录作用与特性 | |
访问权限 | 可读写,需root或adb shell权限 |
加载时机 | 用户安装或更新时加载 |
权限与API | 可访问普通权限/API,不可访问系统保护权限 |
文件访问 | 可访问专属目录/特定媒体,需特权或SAF访问其他 |
应用特点 | |
签名 | 使用自己的签名密钥 |
权限请求 | 需声明和申请运行时权限 |
数据共享 | 通常不使用sharedUserId 共享UID/进程空间 |
安装方法 | |
商店/其他渠道 | 使用Google Play等商店安装应用 |
使用adb | 使用adb命令复制应用到目录,修改权限和所有者 |
预置 | 系统打包固件的时候预置进系统 |
平台签名的app使用与系统相同的签名密钥,允许它们访问特权权限和API。这些应用通常位于/system/app
或/system/priv-app
。它们可以直接使用任何权限,不需申请运行时权限,并可能使用sharedUserId
共享数据。
平台签名的app的权限特性
特性/操作 | 描述 |
权限特性 | |
权限与API | 可访问所有权限和API,包括特权权限 |
权限请求 | 不需使用AndroidManifest.xml 声明或申请运行时权限 |
数据共享 | 使用sharedUserId 共享UID和进程空间 |
请求与使用方法 | |
使用AndroidManifest.xml |
声明所需权限,无需用户授权 |
使用代码 | 直接调用API,无需权限检查 |
普通app的权限特性
普通app是指使用自己的签名密钥签名的应用,它们没有任何特殊的存储路径或者权限特性。这些应用可以存储在任何目录中,但是通常存储在/data/app中。例如,一些自己开发或者下载的应用,都是普通app。
普通app的权限特性有以下几点:
- 普通app可以访问一些普通的权限和API,例如访问网络,读取位置,拍照等。但是它们不能访问一些系统保护的权限和API,例如修改系统设置,访问电话状态,读取联系人等。
- 普通app需要使用AndroidManifest.xml文件中声明的权限和运行时权限来请求和使用权限。运行时权限是指一些敏感的权限,它们需要在应用运行时向用户申请授权才能使用。例如,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE等。
- 普通app通常不使用AndroidManifest.xml文件中声明的sharedUserId属性来共享UID和进程空间的,因为这样会增加安全风险和兼容性问题。
普通app如何请求和使用权限呢?有以下几种方法:
- 使用AndroidManifest.xml文件:需要在AndroidManifest.xml文件中声明想要使用的权限,并且根据不同版本的Android系统来申请运行时权限。例如,如果想要使用READ_EXTERNAL_STORAGE权限,需要在AndroidManifest.xml文件中添加以下代码:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- 使用代码:需要在代码中检查并申请运行时权限,并且处理用户的授权结果。例如,如果想要读取外部存储空间中的文件,需要在代码中使用以下代码:
// 定义一个常量作为请求码 private static final int REQUEST_CODE_READ_EXTERNAL_STORAGE = 1; // 检查是否已经有READ_EXTERNAL_STORAGE权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { // 如果已经有了,直接读取文件 readFileFromExternalStorage(); } else { // 如果没有,向用户申请 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_CODE_READ_EXTERNAL_STORAGE); } // 重写onRequestPermissionsResult方法来处理用户的授权结果 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); // 判断请求码是否匹配 if (requestCode == REQUEST_CODE_READ_EXTERNAL_STORAGE) { // 判断授权结果是否成功 if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 如果成功,读取文件 readFileFromExternalStorage(); } else { // 如果失败,提示用户 Toast.makeText(this, "You need to grant READ_EXTERNAL_STORAGE permission to read files", Toast.LENGTH_SHORT).show(); } } } // 定义一个方法来读取外部存储空间中的文件 private void readFileFromExternalStorage() { // 获取外部存储空间的根目录 File externalStorageDirectory = Environment.getExternalStorageDirectory(); // 创建一个文件对象表示要读取的文件 File file = new File(externalStorageDirectory, "test.txt"); // 创建一个输入流对象来读取文件内容 try (FileInputStream fis = new FileInputStream(file)) { // 创建一个字节数组来存储文件内容 byte[] buffer = new byte[fis.available()]; // 将文件内容读取到字节数组中 fis.read(buffer); // 将字节数组转换为字符串 String content = new String(buffer); // 显示文件内容 Toast.makeText(this, content, Toast.LENGTH_SHORT).show(); } catch (IOException e) { // 处理异常情况 e.printStackTrace(); } }
不同类型应用的存储路径和权限区别
不同的应用存储路径如/system/app
, /system/priv-app
, 和 /data/app
具有不同的存储和权限特性。系统和特权应用通常存储在系统分区,具有更高的权限,而普通应用存储在数据分区,权限较低。选择应用的安装位置和权限应基于应用的类型、需求和安全性。
表格:
特性/操作 | /system/app & /system/priv-app |
/data/app |
存储特性 | ||
存储位置 | 系统分区 | 数据分区 |
存储方式 | 刷机/adb命令 | 商店/其他渠道 |
用户操作 | 需要root/刷机操作 | 用户自由安装/卸载 |
权限特性 | ||
权限级别 | 高级权限 & API | 普通权限 & API |
权限申请 | 不需运行时权限 | 需要运行时权限 |
数据共享 | 可使用sharedUserId |
通常不使用sharedUserId |
建议 | ||
权限最小化 | ✔ | ✔ |
使用普通权限 | ✖ | ✔ |
使用运行时权限 | ✖ | ✔ |
- 普通应用使用了系统平台签名 但不使用android:sharedUserId=“android.uid.system”:
- 这种应用使用了与系统相同的签名密钥,因此它可以被视为一个平台签名的app。但由于它没有使用
android:sharedUserId="android.uid.system"
,它不会具有与系统应用相同的UID,所以它不是特权应用。
- 普通应用使用了系统平台签名 使用android:sharedUserId=“android.uid.system”:
- 这种应用使用了与系统相同的签名密钥并且使用了
android:sharedUserId="android.uid.system"
,因此它可以被视为一个特权应用。
- 普通应用如果Android源码预置到/system/app & /system/priv-app:
- 如果预置在
/system/app
,它仍然是一个系统应用,但可能没有特权应用的所有权限。 - 如果预置在
/system/priv-app
,它是一个特权应用,因为这个目录是为具有特权签名的应用预留的。
- 查看 /system/app, /system/priv-app 和 /data/app 中的应用:
- 首先,确保你的设备已经连接到电脑并且 ADB 正在运行。
- 打开命令行或终端。
- 输入以下命令:
adb shell
- 然后,你可以使用
ls
命令来查看各个目录中的内容:
ls /system/app ls /system/priv-app ls /data/app
- 区分 shareid 和签名:
- Android 的应用可以使用相同的
sharedUserId
来共享数据和代码。这通常在 AndroidManifest.xml 文件中定义。要查看应用的sharedUserId
,你可以使用以下命令:
dumpsys package <package_name> | grep Share
其中 `<package_name>` 是你想要查询的应用的包名。
- 对于签名,你可以使用以下命令来获取应用的签名信息:
dumpsys package <package_name> | grep Sign
- 注意:这些命令可能会返回大量的信息,所以你可能需要仔细查看或使用更多的
grep
命令来过滤结果。
希望这篇文章能对您有所帮助。如果还有其他问题或建议,请留言与私信。