2. Android系统架构与安全基础
Android 的安全模型并不是从 Java 层“凭空长出来”的,它的根基是 Linux 内核。理解 Android 权限,必须先理解内核提供的进程隔离、用户身份、文件访问控制这三块基石。Android 在这套通用机制之上,叠加了应用沙箱、权限声明、SELinux 强制访问控制等增强层,最终形成“一个应用一个身份、一个应用一个沙箱”的安全格局。
一、核心原理:从内核到应用的四层安全栈
Android 系统架构自上而下大致分为应用层、应用框架层、系统运行库与 HAL 层、Linux 内核层。安全能力主要沉淀在下面两层,并向上暴露为权限接口。可以用一张分层图看清各层承担的安全职责:
关键结论是:框架层的权限检查只是“入口”,真正阻止越权访问的是内核。即使绕过框架层,内核的 UID 与文件权限仍会拦截非法读写。
二、应用沙箱:一个应用一个身份
Android 为每个安装的应用分配一个唯一的 Linux 用户 ID(UID)。应用在运行时以该 UID 启动进程,进程只能访问属于自己 UID 或被显式授权的资源。这就是应用沙箱的本质——用 Linux 的进程隔离和用户隔离,实现应用之间的隔离。
沙箱体现在三个层面:
- 进程隔离:每个应用运行在独立进程中,拥有独立的内存空间,无法直接读取其他应用的内存。
- 数据隔离:应用私有目录
/data/data/<包名>/的属主是该应用 UID,其他应用默认无权访问。 - 权限隔离:访问系统资源(相机、位置、通讯录)必须通过权限声明与授权。
三、UID/GID 与文件系统权限
Android 在 Linux UID 基础上做了扩展:应用 UID 从 10000 开始分配,系统服务使用固定 UID(如 system=1000、root=0)。GID 则用于表达“权限组”,例如 inet、sdcard_rw、bluetooth 等,应用被加入某个 GID 就相当于获得了对应资源的访问能力。
文件系统权限遵循经典的 rwx 模型,但 Android 的私有目录权限非常严格。典型目录权限如下:
# 应用私有目录
drwx------ u0_a123 u0_a123 /data/data/com.example.app
drwxrwx--x u0_a123 u0_a123 /data/data/com.example.app/files
drwx--x--x system system /data/data
# 外部存储(共享)
drwxrwx--x media_rw media_rw /storage/emulated/0
可以看到,/data/data/com.example.app 的权限是 700,只有属主可读写执行,其他应用即使知道路径也无法进入。这正是沙箱在文件系统层面的直接体现。
| 对象 | 标识 | 作用 | 典型值 |
|---|---|---|---|
| root | UID 0 | 超级用户,拥有全部权限 | 0 |
| system | UID 1000 | 系统服务运行身份 | 1000 |
| 应用 UID | u0_aXXX | 每个应用唯一,隔离依据 | 10000+ |
| 权限组 | GID | 表达资源访问能力 | inet / sdcard_rw |
| 私有目录 | 700 | 仅属主可访问 | /data/data/包名 |
四、案例与场景:越权读取为何失败
假设应用 A 想读取应用 B 的私有数据库 /data/data/com.b/databases/user.db。即使 A 通过反射或路径拼接拿到了完整路径,执行读取时内核会检查:当前进程 UID 是 u0_a123,而目标文件属主是 u0_a456,权限为 600。由于 UID 不匹配且无其他位权限,内核直接返回 EACCES,Java 层表现为 FileNotFoundException 或 Permission denied。
再比如,应用要访问网络,必须在 AndroidManifest.xml 中声明 INTERNET 权限。系统在安装时把应用加入 inet GID,内核才允许其创建 socket。没有该 GID,网络调用会被拒绝。
adb shell ps -A -o USER,PID,NAME 查看进程 UID,用 adb shell ls -l /data/data/ 观察目录属主与权限,能直观验证沙箱是否生效。
五、常见误区与复盘
- 误区一:认为权限只是 Java 层开关。实际上权限最终由内核 UID/GID 与文件权限裁决,框架层只是策略分发。
- 误区二:认为 root 后沙箱消失。root 可以绕过 UID 限制,但 SELinux 仍会限制其行为,现代 Android 的 root 并非“无所不能”。
- 误区三:把外部存储当私有目录。外部存储是共享的,权限较宽,敏感数据不应放在这里。
- 误区四:忽略多用户与工作资料。Android 支持多用户,同一应用在不同用户下 UID 不同,沙箱相互独立。
chmod 777 解决权限问题。在 Android 上,私有目录权限由系统管理,随意放宽会破坏沙箱,且可能被安全扫描判定为高风险。
总结来说,Android 安全基础可以浓缩为一句话:内核用 UID/GID 和文件权限划出沙箱边界,框架层用权限声明和 SELinux 加固边界,应用只能在自己的边界内活动。理解这条主线,后续的权限申请、组件导出、SELinux 策略等内容都会变得有据可依。