权限简介
Android系统上每一个独立的应用运行在不同的系统空间,以User ID和Group ID来标识。不同应用之间互相访问数据接口资源,就牵涉到权限问题。
用户ID
我们在安装一个应用的时候系统就会为这个应用分配一个userid,这个userid是全局唯一的,在同一android系统的机器上不可能存在两个相同userid的应用,也就是说userid对于一个应用来说是唯一不变的,除非你卸载重新安装了该应用,但是userid并不像MAC地址一样是全球唯一的,同一个应用在不同的设备上userid可能会不同,上面说的唯一是指在同一个android设备上。
Android的安全机制是进程级别的,通常情况下一个应用就是一个进程,并且一个应用也只有一个进程,当然应用内实现多进程这个是没有任何问题的,本文不考虑此情况。也就是说一般情况下,应用A是无法直接运行在应用B的进程当中的,
但是有一点就是除非应用A和应用B使用了相同的shareduserid,配置了相同的shareduserid的应用他们被系统视作同一个应用,对应的userid和权限都是相同的,但是如果仅仅是配置了相同的shareduserid就能够到达目的,显然这是一个很大的漏洞,为此谷歌做了另外一个限制,就是必须保证签名一致,一般的A公司的签名肯定是跟B公司的签名是不一样的,也就是说想要应用A和应用B运行在同一个进程当中那么肯定得保证签名和shareduserid是一致的,shareduserid保持一致这个很容易满足,但是签名一致恐怕只能是同一个公司
应用的数据和user id是相对应的,默认情况下其他应用是无法访问的,但是如果我们设置了MODE_WORLD_READABLE 或者 MODE_WORLD_WRITEABLE的flag,那么其他应用就可以变得可读可写了,也就是说这些数据就变成了全局的数据。
用户ID是什么
上面说了那么多userid是有多么多么的重要,那么我们来看看userid在系统里面到底是什么
我们知道Android系统从4.2版本开始支持多用户,也就产生了用户id的概念uid,在这里uid和userid是两个完全不同的概念,android中的用户是存在物理文件级数据差异的,譬喻有两个用户:用户id分别是0和10,用户10安装了应用A,此时对于用户0来说是完全不可见的,不像两个应用A和B两者的数据虽然默认情况下是不能互相访问的,但是我们有办法能够实现。
那么用户id到底是什么:简单的说用户id就是当前用户下为了各个应用之间数据共享和访问的
查看userid可以使用下面的命令
adb shell dumpsys packages---->adb shell dumpsys com.android.settings
Package [com.android.settings] (3d9bf40):
userId=1000
sharedUser=SharedUserSetting{2627759 android.uid.system/1000}
pkg=Package{25c93ff com.android.settings}
codePath=/system/app/CP_SystemSetting
resourcePath=/system/app/CP_SystemSetting
legacyNativeLibraryDir=/system/app/CP_SystemSetting/lib
primaryCpuAbi=arm64-v8a
secondaryCpuAbi=null
versionCode=0 targetSdk=23
versionName=_VER_2016.06.13_20:56:48
splits=[base]
可以看到设置的userid是1000
在Android系统中有些常用的userid是提前定义好的,如system的用户id就是1000,这个是在代码中提前定义好的
具体的在:include/private/android_filesystem_config.h
#ifndef _ANDROID_FILESYSTEM_CONFIG_H_
#define _ANDROID_FILESYSTEM_CONFIG_H_
#include
#include
#include
#if defined(__ANDROID__)
#include
#else
#include "android_filesystem_capability.h"
#endif
#define CAP_MASK_LONG(cap_name) (1ULL << (cap_name))
/* This is the master Users and Groups config for the platform.
* DO NOT EVER RENUMBER
*/
#define AID_ROOT 0 /* traditional unix root user */
#define AID_SYSTEM 1000 /* system server */
#define AID_RADIO 1001 /* telephony subsystem, RIL */
#define AID_BLUETOOTH 1002 /* bluetooth subsystem */
#define AID_GRAPHICS 1003 /* graphics devices */
#define AID_INPUT 1004 /* input devices */
#define AID_AUDIO 1005 /* audio devices */
我们可以发现设置的userid和system的useri是相同的,我们找到设置的源码发现
android="http://schemas.android.com/apk/res/android"xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"package="com.android.settings"coreApp="true"android:sharedUserId="android.uid.system">
因此也验证了上面的观点。因为设置这个应用比较特殊,通常会写系统属性等需要较高权限的操作。
权限分类
我们都知道通过shareduserid来实现数据共享有一个限制就是相同的签名,这个是很高要求的,一般都是同一个公司开发出来的app才能满足获取内置到第三方ROM里面去才能满足,通常的做法是通过uses-permission来实现,我们自己定义一个权限,在需要被访问的地方加上这个权限限制这样就能到达目的。以电子邮件为例:
我们事先定义了一个权限:com.android.email.permission.READ_ATTACHMENT
如果我们需要访问下面的这个provider的话就需要上面定义的权限
并且我们可以看到上面的权限级别是dangerous,也就是说在安装该应用的时候不会默认给你分配该权限,需要用户确认的。
那么权限大概可以分成4类的
1:normal权限:也就是一般的权限,不需要用户去确认的,譬如一个应用申请连接网络等
2:dangerous权限:这种权限较normal权限高一些,需要用户手动点击确认的,譬喻应用需要读取联系人的信息,因为这些数据是比较隐私的可能会导致你的数据泄露等
3:signature:只有当申请权限的应用程序的数字签名与声明此权限的应用程序的数字签名相同时(如果是申请系统权限,则需要与系统签名相同),才能将权限授给它
4:signatureOrSystem:签名相同,或者申请权限的应用为系统应用(在system image中)。
第三条和第四条要求是很高,一般的只有是相同公司开发出来的应用才能满足
权限带来的问题
上次在公司就碰到了一个权限的问题,就是分享文件到电子邮件
当我点击电子邮件图标的时候突然casrh了,赶紧抓个日志看了下permission deny,导致调起分享功能对应的activity初始化失败了
为啥会提示没有权限了?
反编译原始的Email.apk发现,原来该权限申明成了signature的保护类型
由于分享ResolverActivity是运行在system进程中,也就是要求电子邮件的签名必须是系统签名,然后这个apk是客户提供的,因此导致了问题的发生