您的位置:首页 > 移动开发 > Android开发

Android M Runtime Permission

2016-05-06 10:45 716 查看
本文旨在全面介绍Android M 上新发布的runtime permission的相关功能,与之相关的app编程以及一些相关重要API,并对framework部分作了简单介绍。
一、什么是runtime permission

先了解一下什么叫install time permission model。 在app安装过程中要求用户授予app相应权限,否则不能安装,这叫install time permission. 在android M以前的版本都是installtime permission。app安装以后用户不能修改permission的授权情况,也不允许对单项permission进行单独授权和撤回操作。

在android M版本上,对permission的管理作了部分改进,针对dangerous permission, 不在安装时候给予授权,而是在运行过程中咨询用户是否给予app相应权限, 这叫runtime permission model。注意只是针对dangerous permission. 其他类型的permission,例如normal或者signature 和signatureOrSystem,仍然在安装时给予授权。

· 默认情况下,app安装后,所有的dangerous permission 都是deny状态。

· app运行过程中, app必须主动询问用户是否允许app拥有这些权限。用户可以选择允许或者不允许。

· 用户也可以在系统settings里面,对某个app的某项permission单独给予权限或撤销权限。

· 运营商或者厂商可以预安装app,但是不会预先给与dangerous permission权限。

· 只有activity可以申请相应的permission. Service不再能直接申请dangerous permission,如果service想要申请相应的permission, 有两种方式:

a)
添加一个activity去请求相应的permission

b)
通过share UID的方式获取与其UID相同的application的权限。后一种方式通常使用在多个apk需要运行在同一个application中的情况。

注意:有一些permission 可以预先授权给相应的系统默认的一些基础功能的app。比如ACTION_CALLL就会预先授权给系统默认的打电话app.而短信相关的一些permmisions会预先授权给短信app.预授权功能通过packagemanager中的新类DefaultPermissionGrantPolicy实现。

同时注意,在M 机器上,必须安装Google 签发的PackageInstaller,这是google强制要求的。该app负责授权相关的界面显示和操作等相关功能。

二、 兼容性问题

1. 如果target 不是M的app 安装在M 版的机器上,那么所有的permission 按照以前的旧的方式管理,也就是install time permission model.

需要注意的是,在M的机器上,用户可以在settings里面撤销对permission的授权,app 运行中因为没有相应授权,可能会出现crash或者其他意外情况。

2. 如果app使用了新的M上的permission model, 但是运行在非M的机器上,那么所有的permission 还是按照install time permission去管理。

注意:如果一个app 是针对M 的preview release开发的,那么它的manifest文件必须指明minimum SDK 版本为MNC, 这种情况下, 该APP是不能运行在M以下的机器上的。

三、受影响的permissions。

只有dangerous permission 被要求采用新的runtime permission 管理方式。

其他的,如normal、signature 和signatureOrSystem permission 还是按照以前的permission 管理方式,在安装时给与授权。

1. dangerous permission定义。

用户可以定义自己的dangerous permission。 manifest文件中,permission 定义:

[html]
view plain
copy

<permission android:description="string resource"
android:icon="drawable resource"
android:label="string resource"
android:name="string"
android:permissionGroup="string"
android:protectionLevel=["normal" | "dangerous" |
"signature" | "signatureOrSystem"] />

2. 关于permissionGroup

注意上面的定义中有一项permissionGroup。 相关的一些permission可以归类为到一个permission Group,
比如CONTACTS 组包括读联系人和写联系人等相关permission.对于一个permission group, app只要获得该组内任意一个permission的授权,就可以拥有该组下的所有permission的授权。例如一个app 要求SEND_SMS 和 RECEIVE_SMS两个permission, 当app要使用SEND_SMS相关功能时,需要请求用户給予SEND_SMS权限,稍后app要使用RECEIVE_SMS相关功能时,RECEIVE_SMS就已经自动授权给了app,不需要app再申请一次。

3. 新增adb命令

配合runtime permission, 也新增了一些相关的adb 命令:

1) 查看所有的dangerous permissions:

adb shell pm list permissions –g –d

2) 安装app并且对所有列在app manifest文件下的所有permission给予授权:

adb install -g <path_to_apk>

3) 授权给某个app某个permission:

adb pm grant <package_name> <permission_name>

4) 撤销授权:

adb pm revoke <package_name> <permission_name>

下表列出了目前M上的所有的dangerous permission 和相应组:



四、app如何编写适用于runtime permission的代码

如果APP想要在M上运行,并且使用新的permission model, 除了在manifest 里声明需要的permission, APP还要在运行阶段去检查是否拥有相应的permission, 如果没有该permission,则要咨询用户是否给予相应的permissin。

1. Manifest 中SDK版本声明

要声明该app适用于M新的permission model,需要在manifest文件中声明:targetSdkVersion等于MNC 并且compileSdkVersion等于android-MNC。

如果这个app是针对M的preview release开发的,必须声明minSdkVersion等于MNC。

2. 定义M preview release上特有的permission.

在manifest文件中,app可以使用<uses-permission-sdk-m>来声明所需要的permission只适用于M版本。那么如果app 是被安装在M以下的版本,这个permission会被忽略——不提示用户需要这个permission,也不会授权给app这个permission. 而当app在M版本上运行时,<uses-permission-sdk-m>等同于
<uses-permission>
,会按照新的
permission
管理方式管理。
用这种方式可以在
app
升级的时候声明需要新的
permission


例如,如果新增需要READ_CONTACTS permission,可以在manifest文件中添加以下声明:

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

3.
app 如何编程

使用了dangerous permission的app,在运行过程中,要检查是否有相应的权限,如果没有,要在适当的时候提醒用户为什么需要这个权限,并且请求用户给予相应的权限。这涉及到四个基本API:

1)
检查是否有权限:checkSelfPermission(String)

2)
是否需要提示用户为什么需要这个权限:shouldShowRequestPermissionRationale (String permission)

returns true 如果app以前要求过这个权限,但是用户拒绝了。

returns false
如果以前用户拒绝给予这个权限并且在系统对话框中选择了“Don't ask again ”选项。

returns false
如果device policy 禁止app拥有这个权限。这种通常都是在DevicePolicyManager中设置的。

3)
请求权限: requestPermissions (String[] permissions,
int requestCode)

调用该函数,系统会调出一个对话框,提示用户是否要给予相应权限。用户允许或拒绝相应的权限后,app的onRequestPermissionsResult(int,
String[], int[])会被调用,告诉app相应的permission是被授权或者拒绝。

4)
处理回调:onRequestPermissionsResult(int,
String[], int[])

请求permission后系统调用该函数,通知app permission是被允许还是拒绝。

编码范例:app想要显示contacts。From android developer.

[html]
view plain
copy

private void showContacts() {
if (checkSelfPermission(Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {

// Should we show an explanation?
if (shouldShowRequestPermissionRationale(
Manifest.permission.READ_CONTACTS)) {
// Explain to the user why we need to read the contacts
}

requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);

// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant

return;
}
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
showContacts();
}
}

五、关于自动授权

·
带有PRIVATE_FLAG_PRIVILEGED & FLAG_PERSISTENT flag的app会被自动给予授权。

·
系统默认的基础app会被自动给予相应的permission.比如默认的电话本app自动会拥有CONTACT相关的permission.

自动授权是通过函数grantDefaultPermissions() @DefaultPermissionFrantPolicy.Java实现的。该函数会在system
ready和创建新用户时调用。DefaultPermissionFrantPolicy.java文件是PM(package manager service)中在M上新增的一个类,用于实现自动授权的相关功能。

六、framework实现介绍:

App的permission状态在PM中统一管理维护。PM提供了一些相应的API。PackageInstaller
负责permission管理的相关UI,并通过PM的相关接口设置permission状态。DevicePolicyManager也会根据device的要求对某些app设置一些permission的状态。PM中关于permission管理的代码实现并不复杂,不做详细介绍,只指出下面关键的几点,知道以下几点会非常有助于理解相应的代码。

v 在PM中新增了几个新类:

· DefaultPermissionGrantPolicy:这个在自动授权中说过负责自动授权的相关功能。

· PermissionsState: 每个app在package manager service 里面维护一个该实例,记录该app的所有permission的状态。

· PermissionData:在PermissionsState 中管理了一组PermissionData , 记录app的每个permission 的状态信息。

· SettingBase: PM中某个App的相关基本的Setting信息

PM中permission相关类图:

v
Permission flag: 在PM中,会用到这些flag判断permisssion状态。

·
PackageManager.FLAG_PERMISSION_USER_SET: user 选择允许或者拒绝的授权。

·
PackageManager.FLAG_PERMISSION_USER_FIXED:user选择允许或者拒绝授权同时购选了“never ask again”选项。

·
PackageManager.FLAG_PERMISSION_POLICY_FIXED:device policy设定的权限。

·
PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE:如果permission被标记了这个flag,那么表示,app升级后被deny的permission,会依然是deny的状态。这个flag会在下面的情况中用到。适用于L以前版本的app,安装得到M的device上,如果它的dangerous
permission被撤销了,比如通过settings里面的permission管理撤销或者device policy中设定,那么该APP升级到适用于M新的permission模式后,那么升级后这个permission依然是撤销的状态。也就是dangerous
permission如果在升级之前被撤销过,升级后依然是撤销的状态。

·
PackageManager.FLAG_PERMISSION_SYSTEM_FIXED 系统app获得的自动授权的permission。

·
PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT 默认的系统基本功能app获得的自动授权的permission.

Framework
部分permission 管理逻辑相对简单,理解以上内容后看相关代码会很容易。

七、其他API.

revokeRuntimePermission()

addOnPermissionsChangeListener()

removeOnpermissionsChangeListener()

grantRuntimePermission()

isPermissionRevokedByPolicy()

getPermissionControllerPackageName()

getPermissionFlags()

updatePermissionFlags()

BuildRequestPermissionsIntent()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: