您的位置:首页 > 其它

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

2018-02-08 00:00 375 查看
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
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: