Framework基础:系统源码理解6.0的运行时权限

图片发自简书App

Android 6.0 引入了运行时权限。就是权限是在程序运行的时候赋予的,而不是安装的时候赋予的。6.0之前权限的赋予都是在安装的时候列出一堆权限,然后用户点击确定后赋予的。下面对比图,有种你敢看。

Android L.png
Android M.png

大体说一下##

今天来说下6.0权限赋予的一个过程吧,先不上代码,先用自然语言说一下。
1.并不是所有权限都要运行时才申请的。有些是安装的时候自然就给你的,安装时候自动给你的都是一些小权限啦,没啥危险的。执行 adb shell pm dump com.example.rubbishdemo |find "permission" 可以看到有哪些权限是这个com.example.rubbishdemo安装的时候就被赋予的。这个可以叫做“安装时权限”,哈哈,名字是我乱起的。

Paste_Image.png

2.运行时权限的赋予是给整个权限组赋予权限,啥意思啊,是这样的,Android里面的权限都是分组的,便于管理,例如写sd卡,和读sd卡就是同一个权限组android.permission-group.STORAGE的。这些在frameworks/base/core/res/AndroidManifest.xml中定义

权限组定义.png
权限组下的两个权限.png

3.权限赋予后,会记录到设置数据库中。因而重启也不会失效。

代码走一下##

下面就进入代码时间
首先是应用部分,在onCreate里面申请发送信息的权限SEND_SMS。

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.requestPermissions(
                new String[]{Manifest.permission.SEND_SMS},
                2);
    }

AndroidManifest定义要获取的权限

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

上节我们说到运行时权限那个弹框是有应用安装器弹出的,所在的Activity是GrantPermissionsActivity。所以,过一下这个Activity的代码。

    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
       //mRequestedPermissions是要获取的权限,这里要获取的是android.permission.SEND_SMS
        mRequestedPermissions = getIntent().getStringArrayExtra(
                PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES);
        if (mRequestedPermissions == null) {
            mRequestedPermissions = new String[0];
        }
     
        final int requestedPermCount = mRequestedPermissions.length;
        mGrantResults = new int[requestedPermCount];  //用来保存权限获取结果
        //要获取权限的应用的包名
        PackageInfo callingPackageInfo = getCallingPackageInfo();
        //设备管理器
        DevicePolicyManager devicePolicyManager = getSystemService(DevicePolicyManager.class);
        //权限策略
        final int permissionPolicy = devicePolicyManager.getPermissionPolicy(null);
        //获取应用中所有的权限,这个返回值是AndroidManifest里面定义的所有权限,本例子就是下面一个,only one
    /*
    <uses-permission android:name="android.permission.SEND_SMS" />
     */
       //把这些权限保存到一个数据结构AppPermissions中去
        mAppPermissions = new AppPermissions(this, callingPackageInfo, null, false,
                new Runnable() {
                    @Override
                    public void run() {
                        setResultAndFinish();
                    }
                });

        for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) {
           //遍历应用的权限组groud
            boolean groupHasRequestedPermission = false;
            for (String requestedPermission : mRequestedPermissions) {
                if (group.hasPermission(requestedPermission)) {
                   //权限组已经有权限了,就不用再次赋予权限了
                    groupHasRequestedPermission = true;
                    break;
                }
            }
            if (!groupHasRequestedPermission) {
                continue;
            }
            // We allow the user to choose only non-fixed permissions. A permission
            // is fixed either by device policy or the user denying with prejudice.
            //根据权限策略赋予权限,正常这两个策略不满足
            if (!group.isUserFixed() && !group.isPolicyFixed()) {
                switch (permissionPolicy) {
                    case DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT: {
                        if (!group.areRuntimePermissionsGranted()) {
                            group.grantRuntimePermissions(false);
                        }
                        group.setPolicyFixed();
                    } break;

                    case DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY: {
                        if (group.areRuntimePermissionsGranted()) {
                            group.revokeRuntimePermissions(false);
                        }
                        group.setPolicyFixed();
                    } break;

                    default: {
                        if (!group.areRuntimePermissionsGranted()) {
                            //把要申请权限的权限组groud放在数据结构mRequestGrantPermissionGroups
                            mRequestGrantPermissionGroups.put(group.getName(),
                                    new GroupState(group));
                        } else {
                            group.grantRuntimePermissions(false);
                            updateGrantResults(group);
                        }
                    } break;
                }
            } else {
                // if the permission is fixed, ensure that we return the right request result
                updateGrantResults(group);
            }
        }
       //弹出弹框
        mViewHandler = new GrantPermissionsDefaultViewHandler(this).setResultListener(this);
        setContentView(mViewHandler.createView());
    }

先看一下上面的注释,大概步骤是
1.获取APK AndroidManifest中定义的所有权限,并保存在结构AppPermissions。
本例子只定义了一个权限android.permission.SEND_SMS,所以AppPermissions结构中只包含一个Permission,如果定义了多个Permission,则AppPermissions结构中包含多个Permission。

2.获取APK的权限组AppPermissionGroup ,本例子只定义了一个权限,所以权限组也只有一个。android.permission.SEND_SMS所在的权限组是android.permission-group.SMS。

3.查看要获取的权限所在的权限组是否之前已经获取到权限,如果已经获取到,不再获取。直接结束,否则会弹个框,吓吓你。

4.弹框通过GrantPermissionsDefaultViewHandler创建。

弹框吓吓你.png

下面进入GrantPermissionsDefaultViewHandler看看

//创建了弹框,只关注同意按钮
    public View createView() {
        mAllowButton = (Button) mRootView.findViewById(R.id.permission_allow_button);
        mDenyButton = (Button) mRootView.findViewById(R.id.permission_deny_button);
        return mRootView;
    }
  //看点击允许是怎么处理
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.permission_allow_button:
                if (mResultListener != null) {
                    view.clearAccessibilityFocus();
                    mResultListener.onPermissionGrantResult(mGroupName, true, false);  
                    //这里的mResultListener就是GrantPermissionsActivity
                }
                break;
        }
    }

    //GrantPermissionsActivity中
    public void onPermissionGrantResult(String name, boolean granted, boolean doNotAskAgain) {
        GroupState groupState = mRequestGrantPermissionGroups.get(name);
        if (groupState.mGroup != null) {
            if (granted) {
                groupState.mGroup.grantRuntimePermissions(doNotAskAgain);  //这里会往设置数据库写一个值,完成权限赋予
                groupState.mState = GroupState.STATE_ALLOWED;
            }
    }

可以看到,步骤也很简单
1.弹框创建了允许与拒绝的按钮,给按钮设置监听。
2.按下允许按键后,会给权限组赋予权限,最后调用PackageManagerService系统服务将结果写入设置数据库。groupState.mGroup就是权限组。

总结##

1.6.0的权限赋予是给整个权限组赋予权限。
2.权限赋予的入口是应用安装器。
3.有些权限是安装时赋予的,是没啥危险的权限。危险的权限通过运行时赋予。至于危险的定义也在frameworks/base/core/res/AndroidManifest.xml中,截个图你看

危险.png
不危险.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容