在Android源码的很多地方都会出现权限检查的方法checkPermission,此篇文字主要介绍Android5.1.1源码中的checkPermission方法是如何实现的,在此以WallpaperManagerService.java中的checkPermission方法为例来分析。

./base/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java

........
    final Context mContext;
    ........
    public WallpaperManagerService(Context context) {
        mContext = context;
        ........
    }
    ........
    private void checkPermission(String permission) {

// 调用Context的checkCallingOrSelfPermission来检查权限

if (PackageManager.PERMISSION_GRANTED!= mContext.checkCallingOrSelfPermission(permission)) {

throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
                    + ", must have permission " + permission);
        }
    }

checkCallingOrSelfPermission中checkCallingOrSelfPermission的定义

./base/core/java/android/context/Context.java

public abstract int checkCallingOrSelfPermission(@NonNull String permission);

ContextImpl实现了Context接口,权限检查是在ContextImpl类的checkPermission方法来完成的
./base/core/java/android/app/ContextImpl.java 
    @Override
    public int checkPermission(String permission, int pid, int uid) {
        if (permission == null) {
            throw new IllegalArgumentException("permission is null");
        }

try {
            return ActivityManagerNative.getDefault().checkPermission(
                    permission, pid, uid); // 调用ActivityManagerNative的getDefault()方法来获取ActivityManagerService的对象
        } catch (RemoteException e) {
            return PackageManager.PERMISSION_DENIED;
        }
    }
    ........
    @Override
    public int checkCallingOrSelfPermission(String permission) {
        if (permission == null) {
            throw new IllegalArgumentException("permission is null");
        }

return checkPermission(permission, Binder.getCallingPid(),
                Binder.getCallingUid()); // 调用checkPermission函数来检查权限
    }

ActivityManagerNative中getDefault方法实现过程
./base/core/java/android/app/ActivityManagerNative.java
    static public IActivityManager getDefault() {
        return gDefault.get(); // 最终返回的是个ActivityManagerService的对象
    }

ActivityManagerService中checkPermission的实现过程
./base/services/core/java/com/android/server/am/ActivityManagerService.java
    int checkComponentPermission(String permission, int pid, int uid,
            int owningUid, boolean exported) {
        // We might be performing an operation on behalf of an indirect binder
        // invocation, e.g. via {@link #openContentUri}.  Check and adjust the
        // client identity accordingly before proceeding.
        Identity tlsIdentity = sCallerIdentity.get();
        if (tlsIdentity != null) {
            Slog.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
                    + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
            uid = tlsIdentity.uid;
            pid = tlsIdentity.pid;
        }

if (pid == MY_PID) {
            return PackageManager.PERMISSION_GRANTED;
        }

return ActivityManager.checkComponentPermission(permission, uid,
                owningUid, exported); // 调用ActivityManager的checkComponentPermission来检查权限
    }
    ........
    @Override
    public int checkPermission(String permission, int pid, int uid) {
        if (permission == null) {
            return PackageManager.PERMISSION_DENIED;

}

// 调用checkComponentPermission函数来检查权限

return checkComponentPermission(permission, pid, UserHandle.getAppId(uid), -1, true);
    }

ActivityManager中checkComponentPermission的实现过程
./base/core/java/android/app/ActivityManager.java
    public static int checkComponentPermission(String permission, int uid,
            int owningUid, boolean exported) {
        ........
        try {
            return AppGlobals.getPackageManager() // 调用AppGlobals的getPackageManager()函数返回IPackageManager对象
                    .checkUidPermission(permission, uid);
        } catch (RemoteException e) {
            // Should never happen, but if it does... deny!
            Slog.e(TAG, "PackageManager is dead?!?", e);
        }
        return PackageManager.PERMISSION_DENIED;
    }

AppGlobals的getPackageManager方法实现过程
./base/core/java/android/app/AppGlobals.java
    public static IPackageManager getPackageManager() {
        return ActivityThread.getPackageManager(); // 调用ActivityThread的getPackageManager()函数
    }

ActivityThread的getPackageManager实现过程
./base/core/java/android/app/ActivityThread.java
    public static IPackageManager getPackageManager() {
        if (sPackageManager != null) {
            //Slog.v("PackageManager", "returning cur default = " + sPackageManager);
            return sPackageManager;
        }
        IBinder b = ServiceManager.getService("package");
        //Slog.v("PackageManager", "default service binder = " + b);
        sPackageManager = IPackageManager.Stub.asInterface(b);  // 最终获取的是PackageManagerService的对象
        //Slog.v("PackageManager", "default service = " + sPackageManager);
        return sPackageManager;
    }

PackageManagerService的checkUidPermission实现过程
./base/services/core/java/com/android/server/pm/PackageManagerService.java
    @Override
    public int checkUidPermission(String permName, int uid) {
        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;
                }
            }
        }
        return PackageManager.PERMISSION_DENIED;

}


至此权限检查就已完成

原文地址:

AndroidL的checkPermission方法详解相关推荐

  1. python统计csv行数_对Python 多线程统计所有csv文件的行数方法详解

    如下所示: #统计某文件夹下的所有csv文件的行数(多线程) import threading import csv import os class MyThreadLine(threading.Th ...

  2. python修改文件内容_Python批量修改文本文件内容的方法详解

    这篇文章主要介绍了Python批量修改文本文件内容的方法的相关资料,需要的朋友可以参考下 Python批量替换文件内容,支持嵌套文件夹 import os path="./" fo ...

  3. python二维元组_python中读入二维csv格式的表格方法详解(以元组/列表形式表示)

    如何去读取一个没有表头的二维csv文件(如下图所示)? 并以元组的形式表现数据: ((1.0, 0.0, 3.0, 180.0), (2.0, 0.0, 2.0, 180.0), (3.0, 0.0, ...

  4. Spring JdbcTemplate方法详解

    2019独角兽企业重金招聘Python工程师标准>>> Spring JdbcTemplate方法详解 标签: springhsqldbjava存储数据库相关sql 2012-07- ...

  5. golang 解析php序列化,golang实现php里的serialize()和unserialize()序列和反序列方法详解...

    Golang 实现 PHP里的 serialize() . unserialize() 安装 go get -u github.com/techleeone/gophp/serialize 用法 pa ...

  6. ES5和ES6数组遍历方法详解

    ES5和ES6数组遍历方法详解 在ES5中常用的10种数组遍历方法: 1.原始的for循环语句 2.Array.prototype.forEach数组对象内置方法 3.Array.prototype. ...

  7. linux expect 输入密码,shell脚本无密码登录 expect的使用方法详解

    shell脚本无密码登录 expect的使用方法详解 今天需要做一个定时任务脚本将最新的数据包文件传到远程的服务器上,虽然有密钥但也是要求输入密码的那种,所以只能另想办法实现让脚本自动输入密码了. 从 ...

  8. 饥荒怎么自动订阅服务器,饥荒联机版自动挂礼物mod及使用方法详解

    饥荒联机版中官方经常会推出一些挂机掉落礼物的活动,可能一些玩家会觉得很麻烦,下面给大家分享一些自动挂礼物mod和其使用方法,希望可以帮助到各位玩家. 饥荒联机版自动挂礼物mod及使用方法详解 挂礼物m ...

  9. linux oracle 用户创建,LINUX下Oracle数据库用户创建方法详解

    本文实例分析了LINUX下Oracle数据库用户创建方法.分享给大家供大家参考,具体如下: 1)登录linux,以oracle用户登录(如果是root用户登录的,登录后用 su - oracle命令切 ...

最新文章

  1. 脚本征集大赛开启啦!100% 有奖!
  2. 引导界面(二)使用ViewPager实现欢迎引导页面
  3. CFileDialog 打开多个目录下的多个文件
  4. 转:3d max 2013 安装教程,凭着一种互联网精神提供给广大朋友
  5. 【IT笔试面试题整理】给定一个数组a[N]构造数组b [N]
  6. 面试官问:JS的继承
  7. 如何通过本地化事件正确实现微服务内部强一致性,事件总线跨微服务间最终一致性...
  8. 从Hadoop到ClickHouse,现代BI系统有哪些问题?如何解决?
  9. Web前端开发大系概览 (前端开发技术栈)
  10. 基于JAVA_JSP电子书下载系统
  11. js浏览器数据库 IndexedDB Web SQL
  12. win10联想Y7000重启蓝牙消失报显卡错误代码43
  13. android高仿ios控制中心,仿 iOS 11原生控制中心
  14. 双系统时间不一致解决方案
  15. 秦储承办 | 西部数博会暨第三届西安区块链产业发展论坛成功召开!
  16. 如何维持手机电池寿命_手机电池寿命怎么延长
  17. matlab——整数规划
  18. 记一次quartz定时任务不执行排雷
  19. 360搜索“触链”聚焦版权领域,“图刻”是噱头还是不忘安全初心?
  20. 进阶三部曲第一部《Android进阶之光》第2版已出版

热门文章

  1. 山寨一把QQ移动终端聊天框,网页版效果其实也很好的!
  2. 详解Python中的下划线
  3. va_list 简介
  4. 【算法】SVM分类精度为0,结果很烂怎么办?
  5. 【Python】数组索引到底怎么整?
  6. 云炬Android开发笔记 12基于WebView的混合App框架设计(包含浏览器与原生请求Cookie的处理)
  7. MindSpore!这款刚刚开源的深度学习框架我爱了!
  8. django 操作MySQL 中文乱码_Django 连接mysql数据库中文乱码
  9. 23种设计模式C++源码与UML实现--组合模式
  10. bash-shell高级编程--退出和退出状态码