zoukankan      html  css  js  c++  java
  • Android权限机制(二) 权限控制的设计

    本文将会深入Framework层了解Android权限机制是如何起作用的。

    由于Android尚未引入权限控制功能,我们将会讨论如何修改Android代码来达到权限控制的目的,以及一些解决方案。

    一、调用需要权限的API

    我们将通过一个API调用的例子来了解Android系统是如何判断权限的:

    ContentResolver resolver = getContentResolver();
    Cursor cur = resolver.query(  
            ContactsContract.Contacts.CONTENT_URI,  
            null,  
            null,  
            null,  
            ContactsContract.Contacts.DISPLAY_NAME  
                    + " COLLATE LOCALIZED ASC");

    以上代码用于读取联系人,所以需要在AndroidManifest中加上:

    <uses-permission android:name="android.permission.READ_CONTACTS" />
    

      

    OK,开始通过时序图一探究竟。

    /frameworks/base/services/java/com/android/server/pm/PackageManagerService.java

    PackageManagerService.checkUidPermission(String, int):

    public int checkUidPermission(String permName, int uid) {
        final boolean enforcedDefault = isPermissionEnforcedDefault(permName);
        synchronized (mPackages) {
            Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
            if (obj != null) {
                GrantedPermissions gp = (GrantedPermissions)obj;
                // 判断是否具有该权限
                if (gp.grantedPermissions.contains(permName)) {
                    return PackageManager.PERMISSION_GRANTED;
                }
            } else {
                HashSet<String> perms = mSystemPermissions.get(uid);
                if (perms != null && perms.contains(permName)) {
                    return PackageManager.PERMISSION_GRANTED;
                }
            }
            if (!isPermissionEnforcedLocked(permName, enforcedDefault)) {
                return PackageManager.PERMISSION_GRANTED;
            }
        }
        return PackageManager.PERMISSION_DENIED;
    }
    

      

    我们可以从“Android权限机制(一) 权限申请” -> “四、两个数据结构:PackageParser.Package和Settings.mUserIds” -> “2. Settings.mUserIds”得知权限信息是如何被存放进去的。

    二、检查是否具有权限

    因此,调用需要权限的API时候,部分会通过Context.checkPermission(String permission, int pid, int uid)来查询该app进程是否声明了对应的permission。
    最后调用到PackageManagerService的checkUidPermission()(检查大部分permissions)或checkPermission()(如RECEIVE_BOOT_COMPLETED,ACCESS_ALL_EXTERNAL_STORAGE)。
    如果缺乏权限的话,最终会返回PackageManager.PERMISSION_DENIED,于是调用API处根据判断会抛出异常,停止执行。

    有人可能会问:为什么从Context.checkPermission()到最终的PackageManagerService.checkUidPermission(),中间要经过那么多个类?
    这是为了先通过pid来判断,如果不符合条件就会直接返回PackageManager.PERMISSION_DENIED,节省时间。

    三、如何在安装后控制app的权限(修改Framework代码)

    根据以上的代码分析,我们可以得知大部分permission的查询都会经过

    ActivityManagerService.checkComponentPermission() -> ActivityManager.checkComponentPermission() ->
    PackageManagerService.checkUidPermission()
    的流程,那么我们便可以在这些地方插入我们想要的权限控制代码(以下称为BlockedPermission)。

    1. BlockedPermission的保存

    根据“Android权限机制(一)”的分析我们得知,保存uid/package的permission的数据结构是在PKMS当中,那么为了方便,可以把BlockedPermission的数据结构放在这里面。
    为了简单,可以创建一个HashMap<string, string="">,两个string分别对应permission和package。(当然这样就不如前面以uid为下标的ArrayList高效,但实际实践中发现没什么影响。)

    由于HashMap只能在PKMS运行时存在,所以需要保存到文件系统中。可以采用XML的方式(如Framework内部提供的FastXmlSerializer),方便备份和恢复。

    备份时间:每一次更新BlockedPermission的时候备份;
    恢复时间:PKMS构造的时候。
    XML存放位置:具有系统权限的目录下,如/data/system/

    2. API的设计

    写:

    PKMS需要向App层开放写BlockedPermission的API,如writeBlockedPermission()方法,那么除了在PackageManagerService中实现这个方法之外,还要在IPckageManager.aidl中声明。

    读:

    同样在PKMS中实现方法readBlockedPermission(),通过对permission和package的查询返回是否被block。

    安全检查:

    对于写API而言,只能允许被特定的system app调用,所以需要对调用进程的pid和uid做检查。

    3. API的调用

    写API的调用:

    在完成的Framework的改进之后,需要在App层编写具有UI的system app,方便用户直观地控制每个app的权限。注意system app需要platform的signature。

    读API的调用:

    通过前面的permisssion查询流程,我们可以选择在AMS,AM和PKMS中调用API检查是否需要拦截。为了在API拦截之后做好错误处理,最好在AMS中调用。
    在返回PackageManager.PERMISSION_DENIED之后,Framework往往会抛出SecurityException。但是大部分第三方app并不会去捕获这个异常,所以会导致app crash。

    当app crash时,AMS的crashApplication()将会被调用,为了将BlockedPermission与普通的缺乏permission情况区分出来,所以需要在调用读BlockedPermission的API之后留下足够的信息,这也就是为什么把读API放在AMS的原因。

    四、其他方法

    to be continued...

  • 相关阅读:
    优先队列
    Problem W UVA 662 二十三 Fast Food
    UVA 607 二十二 Scheduling Lectures
    UVA 590 二十一 Always on the run
    UVA 442 二十 Matrix Chain Multiplication
    UVA 437 十九 The Tower of Babylon
    UVA 10254 十八 The Priest Mathematician
    UVA 10453 十七 Make Palindrome
    UVA 10163 十六 Storage Keepers
    UVA 1252 十五 Twenty Questions
  • 原文地址:https://www.cnblogs.com/jacobchen/p/3828588.html
Copyright © 2011-2022 走看看