Android权限浅析

权限,是对想要操作文件或者设备的使用者的约束;使用者拥有某个文件的操作权限方可对齐操作,反之则无法操作文件!

浅谈Linux的权限

Android文件设置互斥锁 android文件夹权限_Android文件设置互斥锁


如上图,是Linux系统中的一个JCamera文件夹,d表示一个文件夹,r可读,w可写,x表示可以执行;这三位是固定顺序,假如其中某一项为‘-’,则表示不拥有此项权限;

drwxr-xr-x : 表示jackzhous文件拥有者UID,具有可读可写可执行的权限,用户组staff有可读和可执行权限,其他用户有可读和可执行权限;

在Linux系统底层对读写执行权限实质是用二进制01来表示,为了好识别区分,采样8进制,所以上面的权限是:755

Android系统上权限的划分

用户组划分

和Linux权限类似,Android在system/core/include/private/android_filesystem_config.h文件下定义了许多用户组权限,如下:

Android文件设置互斥锁 android文件夹权限_App_02


如上图,AID_SYSTEM扮演一个系统用户组角色,它的ID为1000;那我们这用户组AID_SYSTEM可以操作哪些文件呢?

用户组可以访问哪些资源

上个步骤已经定义了系统中有哪些用户组,定义它访问的资源在./system/core/libcutils/fs_config.cpp中,如下图:

Android文件设置互斥锁 android文件夹权限_Android文件设置互斥锁_03


如上图,对于data/app这个文件夹,用户为AID_SYSTEM,用户组为AID_SYSTEM,771的权限操作,也就是用户和用户组都是可读可写可执行权限,其他用户只有执行权限;我们adb shell进入data/app目录看看这个文件夹的权限:

Android文件设置互斥锁 android文件夹权限_Android文件设置互斥锁_04


可设置一样,binggo!

Android App权限描述

开发App时,申请权限是一串字符串,如android.permission.ACCESS_FINE_LOCATION,那这个字符串怎么和上面的用户组联系在一起呢?
一步一步来

权限过滤

系统会为我们的权限划分为几种权限:normal,dangerous,signature,signatureOrSystem,system,development

normal权限只需要在AndroidManifest申请即可

dangerous需要动态权限申请

signature需要签名才可以申请

signatureOrSystem,system则需要系统签名、位于system/app下面才可以申请(没在下面就算你下了也没用)

过滤文件在frameworks/base/core/res/AndroidManifest.xml源码中:

Android文件设置互斥锁 android文件夹权限_Android文件设置互斥锁_05


如上如WRITE_CALENDAR是一个dangerous权限,则需要动态申请告知用户,才可以通过!所以你在AndroidManifest里面写了是没用的

App权限记录

这部分就需要用到PMS的知识了,系统初始化时候或者App安装时,PMS模块的Setting会创建一个package.xml和package.list;
package.xml是扫描解析apk后,会记录apk的包名、code位置、native lib位置,UID以及权限描述等信息,如下是package.xml的部分内容:

<package name="com.xxx" codePath="/system/app/helmet_hedgw" nativeLibraryPath="/system/app/helmet_hedgw/lib" primaryCpuAbi="armeabi-v7a" publicFlags="944291397" privateFlags="0" ft="11e8dc5d800" it="11e8dc5d800" ut="11e8dc5d800" version="27" userId="10066" isOrphaned="true">                                                                                                                                                                                                                                                                                  
    <sigs count="1">
        <cert index="1" />
    </sigs>
    <perms>
        <item name="android.permission.CHANGE_NETWORK_STATE" granted="true" flags="0" />
        <item name="android.permission.RECEIVE_BOOT_COMPLETED" granted="true" flags="0" />
        <item name="android.permission.WRITE_MEDIA_STORAGE" granted="true" flags="0" />
        <item name="android.permission.INTERNET" granted="true" flags="0" />
        <item name="android.permission.BATTERY_STATS" granted="true" flags="0" />
        <item name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" granted="true" flags="0" />
        <item name="android.permission.CHANGE_WIFI_STATE" granted="true" flags="0" />
        <item name="android.permission.ACCESS_NETWORK_STATE" granted="true" flags="0" />
        <item name="android.permission.VIBRATE" granted="true" flags="0" />
        <item name="android.permission.ACCESS_WIFI_STATE" granted="true" flags="0" />
    </perms>
    <proper-signing-keyset identifier="1" />
</package>

而package.list中会记录对应安装apk的信息,如下:

包名         UID                                                                                         用户组ID
com.xxx 10066 0 /data/user/0/com.xxx platform:targetSdkVersion=26 1023,1015,3003

package.list最后几位数字,就是这个用户所属的用户组,在这个用户组了,就可以享受系统为这些用户组分配的访问读写权限了
但是这个App是如何获取用户组ID的?
这就不得不提到另一个文件了platform.xml ?
它内部描述了每个字符串权限描述属于哪个用户组,这样我们通过字符串权限描述就知道他需要加入到哪个用户组里面去了;PMS初始化阶段就会解析这个文件,建立好权限描述和用户组的映射关系,最后看看这个文件:

<!-- Group that can modify how network statistics are accounted -->
<permission name="android.permission.MODIFY_NETWORK_ACCOUNTING">
    <group gid="net_bw_acct" />
</permission>

<permission name="android.permission.LOOP_RADIO" >
    <group gid="loop_radio" />
</permission>

这样就把权限和用户组联系起来,进而可以得到对应文件或设备的权限了