在android系统中,应用程序如果想操作系统资源,往往都需要去申请权限。比如:如果想去操作摄像头,那么就需要去申请下面的权限
那android系统是怎么去做这个权限的校验呢?在了解应用程序权限校验之前,先了解每个应用程序权限数据存储结构、权限的解析。我们的应用在第一次安装的时候,都是会经过PKMS来解析,然后在PKMS中会去保存每个应用需要用的权限。
1、权限数据结构
保存权限的相关数据结构如下图:
应用权限数据结构
每个安装的应用都会对应一个变量PackageSettingBase packageSetting来与之对应,而每个packageSetting都包含一个变量PermissionsState来记录这个应用的权限信息,而每个PermissionsState下面都会有多个PermissionData,每个permissionData来对应一个权限,而permissionData下面有一个permissionState用来直接记录该权限是否授权、权限名称等信息。
2、应用权限的解析
应用安装完后,所有的信息会保存在data/system/package.xml中,如下图
应用安装信息
红色框框tag是权限信息,这部分会在PKMS启动的时候,会调用下面的接口来解析对应权限信息。readInstallPermissionsLPr(parser,packageSetting.getPermissionsState());这里会将这个应用所对应的PermissionsState传递进去。
readInstallPermissionsLPr这个接口是在Settings.java中,接口里面会去获取这个权限的名称,再根据权限的名称向Settings.mPermissions获取这个权限名称所对应的BasePermission即是PKMS最前解析到的permission与UID的映射BP列表(android应用程序上层权限与底层linux的用户组GID都是一一映射的,用来规定哪些GID的可以进行访问、操作等。映射表是在PKMS构造函数里面解析路径:system/etc/permissions文件所得)
在readInstallPermissionsLPr()中最后会调用permissionsState.grantInstallPermission(bp) ——>grantPermission()来授权:
授权代码
这里前后各做了一个computeGids得到oldGids / newGids,再通过比较得出授权后GID是否发生了变化,如果发生变化,那就很明显这个权限是新增的。在这两个computeGids有两个关键函数ensurePermissionData(),permissionData.grant(),其实这两个接口,前面那个是根据权限的name来获取到对应的PermissionData,后面那个接口只是将其下面的变量permission标志为授权而已。
3、权限校验
在系统服务中需要可以到看下面这段代码mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BIND_DEVICE_ADMIN,null); 参数是各种各样的权限名称,这部分是做权限校验部分
权限校验流程
各个流程就上图,最后会来到PKMS的checkUidPermission()
权限校验
android原生的代码,权限校验部分,前面说到每个安装的应用都会对应一个变量PackageSettingBase packageSetting来与之对应,PackageSettingBase的父类就是SettingBase,所以这里面还是一样先去获取这个应用的permissionsState,查看这个权限是否授权,再返回值,注释有一个special case,说明还有例外的情况。。。
另外如果没有获取到这个应用的LPr,则会继续去判断mSystemPermissions,这个变量跟前面提到的mPermissions是那么一点点联系,解析system/etc/permissions的时候,
上面这部分则会被解析到mPermisisons中,而tag为则会被解析到这个变量中,mSystemPermissions,原生的注释的意思是给开发者一个更开放的开发环境。比如android开发人员想要查看surface layout的信息,那么他直接可以adb shell后再运行dumpsys SurfaceFlinger,即可以看到信息,这里有一个权限,这个权限是在mSystemPermissions中,所以开发人员可以直接利用这个权限去调试,这是属于高等权限之一。。。