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

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



作者:九九叔
链接:https://www.jianshu.com/p/d31ea81f75a3
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

猜你喜欢

转载自my.oschina.net/u/2542649/blog/1620344
今日推荐