android:label="@string/permlab_deadlyActivity"
android:description="@string/permdesc_deadlyActivity"
android:permissionGroup="android.permission-group.COST_MONEY"
android:protectionLevel="dangerous" />
这里
属性是必需的,通过声明该属性,我们就可以告知系统如何去通知用户哪些应用程序需要这个许可,或者谁可以拥有该许可。具体请参看链接的文档。
属性是可选的,只是用于帮助系统显示许可permission给用户(实际是告知系统该许可是属于哪个许可组permission group的)。你通常会选择使用标准的system group来设定该属性,或者更为少见的用你自己定义的group。推荐使用一个已经存在的group,因为这样UI给用户显示许可的时候会更简单。
需要注意的是标签(label)和描述(description)都是需要为许可提供的。这些都是字符串资源,当用户去看许可列表(android:label)或者某个许可的详细信息(android:description)时,这些字符串资源就可以显示给用户。label应当尽量简短,之需要告知用户该许可是在保护什么功能就行。而description可以用于具体描述获取该许可的程序可以做哪些事情,实际上让用户可以知道如果他们同意程序获取该权限的话,该程序可以做什么。我们通常用两句话来描述许可,第一句描述该许可,第二句警告用户如果批准该权限会可能有什么不好的事情发生。下面是一个描述CALL_PHONE 许可的label和description的例子:
directly call phone numbers
Allows the application to call
phone numbers without your intervention. Malicious applications may
cause unexpected calls on your phone bill. Note that this does not
allow the application to call emergency numbers.
你可以通过shell指令 adb shell pm list permissions 来查看目前系统已有的permissions. 特别的,"-s"选项会以一种用户会看到的基本相同的格式来显示这些permissions:
$ adb shell pm list permissions -s
All Permissions:
Network communication: view Wi-Fi state, create Bluetooth connections, full
Internet access, view network state
Your location: access extra location provider commands, fine (GPS) location,
mock location sources for testing, coarse (network-based) location
Services that cost you money: send SMS messages, directly call phone numbers
...
在清单文件里实施许可Enforcing Permissions in AndroidManifest.xml
用于限制进入系统或应用程序的Components的高级别许可可以再AndroidManifest.xml中实现.所有这些都可以通过在相应的component中包含 android:permission 属性,命名该permission以使其被用以控制进入的权限。
Activity许可(应用于
标签)限制了谁才可以启动相应的活动。permission会在Context.startActivity()和Activity.startActivityForResult()的时候进行检查。如果caller没有所需的权限,则会抛出一个SecurityException。
Service许可(应用于标签)用于限制谁才可以start或bind该service。在Context.startService() , Context.stopService()和Context.bindService()调用的时候会进行权限检查。如果caller没有所需的权限,则会抛出一个SecurityException。
BroadcastReceiver许可(应用于标签)用于限制谁才可以向该receiver发送广播。权限检查会在Context.sendBroadcast() 返回时进行,由系统去发送已经提交的广播给相应的Receiver。最终,一个permission failure不会再返回给Caller一个exception;它只是不会去deliver该Intent而已。同样地,Context.registerReceiver()也可以有自己permission用于限制谁才可以向一个在程序中注册的receiver发送广播。另一种方式是,一个permission也可以提供给Context.sendBroadcast() 用以限制哪一个BroadcastReceiver才可以接收该广播。
ContentProvider许可(应用于
标签)用于限制谁才可以访问ContentProvider提供的数据。(Content providers有一套而外的安全机制叫做URI permissions,这些在稍后讨论)不同于其它的Components,这里有两种不同的permission属性可以设置: android:readPermission 用于限制谁可以读取provider中的数据,而 android:writePermission 用于限制谁才可以向provider中写入数据。需要注意的是如果provider同时被读写许可,如果这时只有写许可并不意味着你就可以读取provider中的数据了。当你第一次获取provider的时候就要进行权限检查(如果你没有任何permission,则会抛出SecurityException), 并且这时你对provider执行了某些操作。当使用ContentResolver.query()时需要读权限,而当使用ContentResolver.insert(), ContentResolver.update(), ContentResolver.delete()时需要写权限。在所有这些情况下,没有所需的permission将会导致SecurityException被抛出。
发送广播时实施许可Enforcing Permissions when Sending Broadcasts
除了之前说过的Permission(用于限制谁才可以发送广播给相应的BroadcastReceiver),你还可以在发送广播的时候指定一个permission。在调用Context.sendBroadcast()的时候使用一个permission string,你就可以要求receiver的宿主程序必须有相应的permission。
值得注意的是Receiver和broadcaster都可以要求permission。当这种情况发生时,这两种permission检查都需要通过后才会将相应的intent发送给相关的目的地。
其他权限实施Other Permission Enforcement
在调用service的过程中可以设置任意细化的许可。这是通过Context.checkCallingPermission()方法来完成的。呼叫的时候使用一个想得到的permission string,并且当该权限获批的时候可以返回给呼叫方一个Integer(没有获批也会返回一个Integer)。需要注意的是这种情况只能发生在来自另一个进程的呼叫,通常是一个service发布的IDL接口或者是其他方式提供给其他的进程。
Android提供了很多其他的方式用于检查permissions。如果你有另一个进程的pid,你就可以通过Context.checkPermission(String, int, int)去针对那个pid去检查permission。如果你有另一个应用程序的package name,你可以直接用PackageManager的方法PackageManager.checkPermission(String, String)来确定该package是否已经拥有了相应的权限。
URI许可URI Permissions
到目前为止我们讨论的标准的permission系统对于内容提供器(content provider)来说是不够的。一个内容提供器可能想保护它的读写权限,而同时与它对应的直属客户端也需要将特定的URI传递给其它应用程序,以便对该URI进行操作。一个典型的例子是邮件应用程序的附件。访问邮件需要使用permission来保护,因为这些是敏感的用户数据。然而,如果有一个指向图片附件的URI需要传递给图片浏览器,那个图片浏览器是不会有访问附件的权利的,因为它不可能拥有所有的邮件的访问权限。
针对这个问题的解决方案就是per-URI permission: 当启动一个activity或者给一个activity返回结果的时候,呼叫方可以设置Intent.FLAG_GRANT_READ_URI_PERMISSION和/或 Intent.FLAG_GRANT_WRITE_URI_PERMISSION。这赋予接收活动(activity)访问该意图(Intent)指定的URI的权限,而不论它是否有权限进入该意图对应的内容提供器。
这种机制允许一个通常的能力-风格(capability-style)模型,以用户交互(如打开一个附件, 从列表中选择一个联系人)来驱动细化的特别授权。这是一个很关键的能力,可以减少应用程序所需要的权限,只留下和程序行为直接相关的权限。
这些URI permission的获取需要内容提供器(包含那些URI)的配合。强烈推荐在内容提供器中实现这种能力,并通过android:grantUriPermissions或者标签来声明支持。