Android API Guides - System Permissions

来源:互联网 发布:人口迁徙数据图 编辑:程序博客网 时间:2024/06/01 10:11

System Permissions 系统权限

Android is a privilege-separated operating system, in which each application runs with a distinct system identity (Linux user ID and group ID). Parts of the system are also separated into distinct identities. Linux thereby isolates applications from each other and from the system.

安卓是一个权限分离的操作系统,应用程序都以一个唯一的系统标识来运行(Linux 用户ID 和 组ID)。部分的系统功能也被分离进不同的标识中。安卓系统就是用这种方法将应用程序彼此分离,也与系统功能所分离。

Additional finer-grained security features are provided through a "permission" mechanism that enforces restrictions on the specific operations that a particular process can perform, and per-URI permissions for granting ad hoc access to specific pieces of data.

另外,更精细的安全机制是通过一种或许可以称之为“许可”的安全机制(当某个需要执行特殊操作的进程运行时,强行对其进行限制)以及赋予每个URI一个仅能获取该URI对应数据的临时性权限来实现。

This document describes how application developers can use the security features provided by Android. A more general Android Security Overview is provided in the Android Open Source Project.

这个文档的主要内容就是开发人员究竟该如何使用安卓系统提供的安全机制。而关于这部分内容,安卓开源项目中有一个更简单更概括的介绍(传送门:Android Security Overview)。

Security Architecture 安全体系架构


A central design point of the Android security architecture is that no application, by default, has permission to perform any operations that would adversely impact other applications, the operating system, or the user. This includes reading or writing the user's private data (such as contacts or emails), reading or writing another application's files, performing network access, keeping the device awake, and so on.

安卓的安全体系结构的一个核心设计点就是,默认情况下,任何应用都没有权限去执行那些可能会对其他应用或其他用户造成不利影响的操作。包括读写用户的私有数据(比如联系人信息,电子邮件等等)、读写其他应用的文件、进行网络访问、持续唤醒设备等等。

Because each Android application operates in a process sandbox, applications must explicitly share resources and data. They do this by declaring the permissions they need for additional capabilities not provided by the basic sandbox. Applications statically declare the permissions they require, and the Android system prompts the user for consent at the time the application is installed. Android has no mechanism for granting permissions dynamically (at run-time) because it complicates the user experience to the detriment of security.

由于每个安卓应用都运行在一个进程沙盒中,所以应用程序需要明确地声明要共享资源或者数据。要这么做,就必须要明确地声明自己需要哪些沙盒所不具备的权限。应用程序静态地声明了它所需要的权限,而安卓系统会在应用被安装时提示用户是否允许该应用程序获得这些权限。安卓系统并不提供一种在程序运行过程中动态赋予安全权限的机制,因为这使得用户赋予应用程序各种权限的操作变得复杂(这些授权操作同时也意味着用户的信息越来越不安全)

The application sandbox does not depend on the technology used to build an application. In particular the Dalvik VM is not a security boundary, and any app can run native code (see the Android NDK). All types of applications — Java, native, and hybrid — are sandboxed in the same way and have the same degree of security from each other.

应用程序的沙盒并不依赖于构建应用程序的相关技术。尤其是 Dalvik 虚拟机自身也并非一个安全的环境,并且任何应用都可以在其中运行本地代码(native code)。任何应用,不管是java、本地应用还是两者的混合,都是以相同的方式装入沙箱并拥有着相同的安全权限。

Application Signing 应用程序签名


All APKs (.apk files) must be signed with a certificate whose private key is held by their developer. This certificate identifies the author of the application. The certificate does not need to be signed by a certificate authority; it is perfectly allowable, and typical, for Android applications to use self-signed certificates. The purpose of certificates in Android is to distinguish application authors. This allows the system to grant or deny applications access to signature-level permissions and to grant or deny an application's request to be given the same Linux identity as another application.

所有的 APK (即 .apk 文件)都必须被一个证书所签名,而这个证书的私钥是被它的开发者所持有的。这个证书的作用就是指明它是被谁开发出来的。另外,这个证书也不需要被什么权威的证书签署部门所办法。安卓应用使用自己签署的证书来签名是完全被允许的,并且这也是一种非常典型的做法。这允许系统来判断是否要将签名级的权限(signature-level permissions )赋予给该应用并且是否要响应另一个持有相同Linux ID的应用程序发送过来的请求。

User IDs and File Access 用户ID和文件系统权限


At install time, Android gives each package a distinct Linux user ID. The identity remains constant for the duration of the package's life on that device. On a different device, the same package may have a different UID; what matters is that each package has a distinct UID on a given device.

在安装过程中,安卓系统授予每个包一个独有且不变的用户ID。而相同的应用程序安装在不同的设备上的话,他们的UID也许是不同的。不过这无关紧要,同一个设备上不同包的UID是不同的,这就足够了。

Because security enforcement happens at the process level, the code of any two packages cannot normally run in the same process, since they need to run as different Linux users. You can use the sharedUserId attribute in theAndroidManifest.xml's manifest tag of each package to have them assigned the same user ID. By doing this, for purposes of security the two packages are then treated as being the same application, with the same user ID and file permissions. Note that in order to retain security, only two applications signed with the same signature (and requesting the same sharedUserId) will be given the same user ID.

强制性的安全措施是在进程级别被执行的,另外,两个不同包的代码通常情况下也不会运行在同一个进程中的(因为它们需要以不同的Linux用户身份来运行)。所以,如果你需要多个包使用同一个用户ID的话,你就需要在 AndroidManifest.xml文件的 manifest 标签中使用  sharedUserId 属性。一旦你这么做了之后,系统为了保证安全,就会将这两个包视为同一个应用(拥有相同的用户ID和文件系统权限)。要注意,为了保证系统安全,只由当两个应用程序使用了同一个签名的时候(并且都申请了相同的 sharedUserId )才会被授予相同的用户ID。

Any data stored by an application will be assigned that application's user ID, and not normally accessible to other packages. When creating a new file with getSharedPreferences(String, int)openFileOutput(String, int), oropenOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory), you can use the MODE_WORLD_READABLE and/orMODE_WORLD_WRITEABLE flags to allow any other package to read/write the file. When setting these flags, the file is still owned by your application, but its global read and/or write permissions have been set appropriately so any other application can see it.

一个应用程序中存储的任何数据都会被这个应用的用户ID来表示,并且通常情况下其他应用程序是无法触及它们的。但当你要创建新文件时,如果使用getSharedPreferences(String, int)openFileOutput(String, int)openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory) 方法并且混合使用 MODE_WORLD_READABLE  MODE_WORLD_WRITEABLE 这两个参数的话,那么你所创建出来的新文件对于任何包而言都是可读甚至是可写的。另外,如果你真的这么做了,那么这些新创建的文件虽然外部应用程序也可以读写,但是它们依然是你程序中的一部分。

Using Permissions 权限的使用


A basic Android application has no permissions associated with it by default, meaning it cannot do anything that would adversely impact the user experience or any data on the device. To make use of protected features of the device, you must include in your AndroidManifest.xml one or more <uses-permission> tags declaring the permissions that your application needs.

一个基础的安卓应用程序默认情况下是没有什么权限的,这也就是说它做不了任何可能影响到用户体验或者损坏设备上任何已有数据的操作。如果要使用设备中那些受保护的功能,那你就必须在 AndroidManifest.xml 文件中使用 <uses-permission> 标签对你所需要的权限一一进行声明。

For example, an application that needs to monitor incoming SMS messages would specify:

举个甜的栗子吧,比如说现在有个应用程序要监听设备时候收到新短消息,那么它的 manifest 文件就必须要像下面这样来写:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.android.app.myapp" >    <uses-permission android:name="android.permission.RECEIVE_SMS" />    ...</manifest>

At application install time, permissions requested by the application are granted to it by the package installer, based on checks against the signatures of the applications declaring those permissions and/or interaction with the user. No checks with the user are done while an application is running; the app is either granted a particular permission when installed, and can use that feature as desired, or the permission is not granted and any attempt to use the feature fails without prompting the user.

在应用程序的安装过程中,应用程序会申请它所需要的权限并被包安装器来授予。而应用程序究竟需要哪些权限是由应用程序的签名信息来声明的,至于包安装器是否真的要授予程序锁申请的权限,则是在安装过程中通过用户手动操作来决定的。而才程序真正运行的时候,是没有任何权限校验的(因为在安装的时候就校验完了)。应用程序如果在安装过程中没有被用户授予它所申请的权限,那么在运行过程中,任何试图使用相关功能的操作就会直接失败而也不会提示用户是否允许程序这么做。

Often times a permission failure will result in a SecurityException being thrown back to the application. However, this is not guaranteed to occur everywhere. For example, the sendBroadcast(Intent) method checks permissions as data is being delivered to each receiver, after the method call has returned, so you will not receive an exception if there are permission failures. In almost all cases, however, a permission failure will be printed to the system log.

通常情况下,因为权限不足而导致的失败操作会抛一个 SecurityException 给这个应用程序。但也只是在大多数情况下会这样,而不是百分百。比如当调用  sendBroadcast(Intent) 方法来发送广播给每个接受者时,即使因为权限不足而导致广播发送过程中出了错,你也不会收到任何异常信息。当然,大多数情况下,因为权限不足而发生的错误,相关信息都会被写入到系统日志中去。

However, in a normal user situation (such as when the app is installed from Google Play Store), an app cannot be installed if the user does not grant the app each of the requested permissions. So you generally don't need to worry about runtime failures caused by missing permissions because the mere fact that the app is installed at all means that your app has been granted its desired permissions.

说了那么多,但其实通常情况下(比如从 Google Play Store 上下载安装应用的时候),如果用户拒绝授予某个应用它所申请的权限的话,那这个应用就不会被安装到用户所持有的设备上。所以其实一般而言你根本就不需要担心应用程序会在运行过程中因为权限不足而出现问题甚至程序奔溃,因为既然你装上了这个程序,也就意味着它已经被授予了它所需要的权限许可。

The permissions provided by the Android system can be found at Manifest.permission. Any application may also define and enforce its own permissions, so this is not a comprehensive list of all possible permissions.

所有由安卓系统所定义的权限都可以在 Manifest.permission 找到,另外,应用程序自己也可以定义并实行自己的权限规则,所以并没有一个包含所有可能出现的权限规则的清单列表。

A particular permission may be enforced at a number of places during your program's operation:

在一个应用程序运行的时候,很多地方都会需要相应的权限,比如说

  • At the time of a call into the system, to prevent an application from executing certain functions.
  • 当突然来了个电话需要停止程序时
  • When starting an activity, to prevent applications from launching activities of other applications.
  • 当启动一个 activity 时(需要防止错误地启动其他应用的 activity)
  • Both sending and receiving broadcasts, to control who can receive your broadcast or who can send a broadcast to you.
  • 当你在收发广播过程中需要指明谁能接收你的广播或者谁能向你发送广播时
  • When accessing and operating on a content provider.
  • 当获取一个content provider的使用权以及使用它的时候
  • Binding to or starting a service.
  • 绑定到一个service或者启动一个service的时候

Caution: Over time, new restrictions may be added to the platform such that, in order to use certain APIs, your app must request a permission that it previously did not need. Because existing apps assume access to those APIs is freely available, Android may apply the new permission request to the app's manifest to avoid breaking the app on the new platform version. Android makes the decision as to whether an app might need the permission based on the value provided for the targetSdkVersion attribute. If the value is lower than the version in which the permission was added, then Android adds the permission.

警告:随着版本的不断更新,安卓系统也可能会新增一些原本没有的权限限制。因此,为了能够调用被这些新的限制条件保护住的API,你就必须添加一些旧版本所 不需要的权限请求。由于现有的应用可能会认为这些API应该是可以直接被调用的(但其实在新版本中,这些API的调用已经需要申请相应的权限许可了)所以安卓为了兼容基于旧版安卓系统开发的安卓应用,就会在旧有应用程序的 manifest 基础上使用一个新的权限请求来避免旧应用在新版本的安卓系统中直接崩溃,即将应用程序 manifest 中的 targetSdkVersion 的值和系统当前的实际版本级别进行对比,如果前者低于后者,则会自动添加一些当前实际的安卓版本才需要的权限请求声明。

For example, the WRITE_EXTERNAL_STORAGE permission was added in API level 4 to restrict access to the shared storage space. If your targetSdkVersion is 3 or lower, this permission is added to your app on newer versions of Android.

比如 WRITE_EXTERNAL_STORAGE 权限是在 API level 4 的时候才被添加的,为了限制程序访问可共享的存储空间。如果你的targetSdkVersion 是3,甚至更低的时候,新版本的安卓就会自动帮你添加申请这个权限的声明

Beware that if this happens to your app, your app listing on Google Play will show these required permissions even though your app might not actually require them.

请注意,当这种情况发生在你的应用程序上时,哪怕你实际上没有申明需要这个权限,Google Play 也会自行判断并认为你需要这个权限,并提醒想要安装这个应用的用户。

To avoid this and remove the default permissions you don't need, always update your targetSdkVersion to be as high as possible. You can see which permissions were added with each release in the Build.VERSION_CODES documentation.

为了避免这种情况,也为了避免申请你不需要的权限,你应该总是把 targetSdkVersion 的值尽可能地标高。你可以在Build.VERSION_CODES   文档中查看每个安卓版本中新增了哪些权限限制。

Declaring and Enforcing Permissions 声明以及执行权限限制


To enforce your own permissions, you must first declare them in your AndroidManifest.xml using one or more<permission> tags.

为了强制实施你自己定义的权限限制,你必须首先在你的 AndroidManifest.xml 文件中使用<permission> 标签来定义你自己的权限设定。

For example, an application that wants to control who can start one of its activities could declare a permission for this operation as follows:

举个栗子,当一个应用想要声明谁才能调用它的 activity 时,就可以这么来做

<manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.me.app.myapp" >    <permission android:name="com.me.app.myapp.permission.DEADLY_ACTIVITY"        android:label="@string/permlab_deadlyActivity"        android:description="@string/permdesc_deadlyActivity"        android:permissionGroup="android.permission-group.COST_MONEY"        android:protectionLevel="dangerous" />    ...</manifest>

The <protectionLevel> attribute is required, telling the system how the user is to be informed of applications requiring the permission, or who is allowed to hold that permission, as described in the linked documentation.

<protectionLevel> 属性是必填的,它能告诉系统该以何种方式来告知用户该应用需要这个权限,或者谁被允许持有这个权限,这在相关文档里也有所描述(, as described in the linked documentation.这特么什么鸟意思- -#)。

The <permissionGroup> attribute is optional, and only used to help the system display permissions to the user. You will usually want to set this to either a standard system group (listed in android.Manifest.permission_group) or in more rare cases to one defined by yourself. It is preferred to use an existing group, as this simplifies the permission UI shown to the user.

<permissionGroup> 属性是可选的,它仅仅是帮助系统显示这个权限信息给用户而已。通常情况下,开发人员会把它设置成标准的系统分组(有关标准的系统分组,请参阅 android.Manifest.permission_group )或者更多情况下设置成一个自定义的分组。而前一种做法应该是你的首选做法,因为这简化了显示呈现给用户的有关权限的界面。

Note that both a label and description should be supplied for the permission. These are string resources that can be displayed to the user when they are viewing a list of permissions (android:label) or details on a single permission ( android:description). The label should be short, a few words describing the key piece of functionality the permission is protecting. The description should be a couple sentences describing what the permission allows a holder to do. Our convention for the description is two sentences, the first describing the permission, the second warning the user of what bad things can happen if an application is granted the permission.

应当注意的是,你应该将 label 和 description 信息都写清楚。这些文字性描述信息在用户查看程序需要哪些权限(android:label)或者点开某个权限查看该权限的具体内容(android:description)时会被呈现给用户。label 应该尽可能的言简意赅,简要描述下这个权限主要是为了保护哪块功能。

Here is an example of a label and description for the CALL_PHONE permission:

这是一个 CALL_PHONE 权限的栗子:

    <string name="permlab_callPhone">directly call phone numbers</string>    <string name="permdesc_callPhone">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.</string>

You can look at the permissions currently defined in the system with the Settings app and the shell command adb shell pm list permissions. To use the Settings app, go to Settings > Applications. Pick an app and scroll down to see the permissions that the app uses. For developers, the adb '-s' option displays the permissions in a form similar to how the user will see them:

你可以使用系统内置的设置功能或者使用 shell 命令 adb shell pm list permissions 来查看当前系统中有哪些权限可以供调用。要只用系统内置的设置功能的话你就要选择“设置”然后选择里面的“应用”。点击某个应用然后将屏幕滚动到最下面来查看这个应用程序使用了哪些权限。开发人员可以给 adb 命令添加 “-s”参数来显示一个与用户差不多展现形式的权限列表(不加这个参数的话权限的显示格式是 <permission>标签的  android:name 属性的值):

$ adb shell pm list permissionsAll Permissions:permission:cn.amazon.mShop.android.permission.C2D_MESSAGEpermission:android.permission.DMP_REPORT_MSGpermission:android.permission.INTERNAL_SYSTEM_WINDOWpermission:android.permission.MOVE_PACKAGEpermission:android.permission.CONTROL_WIFI_DISPLAYpermission:android.permission.READ_INPUT_STATEpermission:com.google.android.providers.settings.permission.READ_GSETTINGS 
$ adb shell pm list permissions -sAll Permissions:Network communication: view Wi-Fi state, create Bluetooth connections, fullInternet access, view network stateYour location: access extra location provider commands, fine (GPS) location,mock location sources for testing, coarse (network-based) locationServices that cost you money: send SMS messages, directly call phone numbers...

Enforcing Permissions in AndroidManifest.xml 在 manifest 中实行权限限制

High-level permissions restricting access to entire components of the system or application can be applied through your AndroidManifest.xml. All that this requires is including an android:permission attribute on the desired component, naming the permission that will be used to control access to it.

你可以在 manifest 文件中限制系统组件或应用程序来访问你的组件。你只要在需要保护的组件上添加  android:permission 属性即可,这个属性作用就是只由拥有了这个属性所对应的权限才能够调用这个组件。

Activity permissions (applied to the <activity> tag) restrict who can start the associated activity. The permission is checked during Context.startActivity() and Activity.startActivityForResult(); if the caller does not have the required permission then SecurityException is thrown from the call.

Activity 权限(加在<activity>标签上)限制了谁才能启动你的activity.这个权限制约会在Context.startActivity()Activity.startActivityForResult()方法的执行过程中被检查,如果方法的调用者权限不足则会抛出 SecurityException 异常。

Service permissions (applied to the <service> tag) restrict who can start or bind to the associated service. The permission is checked during Context.startService()Context.stopService() and Context.bindService(); if the caller does not have the required permission then SecurityException is thrown from the call.

Service 权限(加在<service>标签上)限制了谁才能启动或者关联到这个服务上。这个权限制约会在Context.startService()Context.stopService()Context.bindService()这三个方法的执行过程中被检查,如果方法的调用者权限不足则会抛出 SecurityException 异常。

BroadcastReceiver permissions (applied to the <receiver> tag) restrict who can send broadcasts to the associated receiver. The permission is checked after Context.sendBroadcast() returns, as the system tries to deliver the submitted broadcast to the given receiver. As a result, a permission failure will not result in an exception being thrown back to the caller; it will just not deliver the intent. In the same way, a permission can be supplied to Context.registerReceiver() to control who can broadcast to a programmatically registered receiver. Going the other way, a permission can be supplied when calling Context.sendBroadcast() to restrict which BroadcastReceiver objects are allowed to receive the broadcast (see below).

BroadcastReceiver 权限(加在<receiver>标签上)限制了谁才能发送广播给这个broadcast receiver。这个权限制约会在 Context.sendBroadcast() 方法执行完毕即系统尝试将广播内容传递给指定的接受者之后才会被检查。因此,如果方法的调用者权限不足的话,相关的错误信息也不会返回给 sendBroadcast() 方法的调用者,sendBroadcast()方法所做的工作仅仅是把广播内容广播出去而不管被广播出去的内容是否被正确接收。对使用 Context.registerReceiver() 注册的 Broadcast Receiver 而言也一样。另外,相关权限也可以在调用  Context.sendBroadcast() 的时候再加上去以便来限制究竟哪些broadcast receiver 对象才能接收到这个广播。

ContentProvider permissions (applied to the <provider> tag) restrict who can access the data in a ContentProvider. (Content providers have an important additional security facility available to them called URI permissions which is described later.) Unlike the other components, there are two separate permission attributes you can set: android:readPermission restricts who can read from the provider, and android:writePermissionrestricts who can write to it. Note that if a provider is protected with both a read and write permission, holding only the write permission does not mean you can read from a provider. The permissions are checked when you first retrieve a provider (if you don't have either permission, a SecurityException will be thrown), and as you perform operations on the provider. Using ContentResolver.query() requires holding the read permission; usingContentResolver.insert()ContentResolver.update()ContentResolver.delete() requires the write permission. In all of these cases, not holding the required permission results in a SecurityException being thrown from the call.

ContentProvider 权限(在<provider>标签里限制)限制了谁才能够获取到ContentProvider中的数据。(Content Provider 另外还拥有一种非常重要的叫做 URI permissions 的安全机制)

Enforcing Permissions when Sending Broadcasts 在发送广播时进行权限制约

In addition to the permission enforcing who can send Intents to a registered BroadcastReceiver (as described above), you can also specify a required permission when sending a broadcast. By calling Context.sendBroadcast() with a permission string, you require that a receiver's application must hold that permission in order to receive your broadcast.

为了给“谁能给一个已经注册好的 BroadcastReceiver 发送 Intent”加上权限限制(就像上面所说的那样),你也可以在发送一个广播的同时指定一个所需要的权限。当你在调用 Context.sendBroadcast() 时如果传入一个权限信息,那么只由拥有这个权限的应用程序中的receiver才能够接收到你发送的这个广播。

Note that both a receiver and a broadcaster can require a permission. When this happens, both permission checks must pass for the Intent to be delivered to the associated target.

需要注意的是,广播的接收端和发送端都可以给它一个权限,而当你这么做了之后,这两次权限校验都必须要通过,只由这样,这个intent才能被正确地投递到指定的接收端。

Other Permission Enforcement 其他的权限应用情况

Arbitrarily fine-grained permissions can be enforced at any call into a service. This is accomplished with the Context.checkCallingPermission() method. Call with a desired permission string and it will return an integer indicating whether that permission has been granted to the current calling process. Note that this can only be used when you are executing a call coming in from another process, usually through an IDL interface published from a service or in some other way given to another process.

任何精细的权限限制都可以调用service之后被启用。这个操作是由 Context.checkCallingPermission() 来完成的。在调用这个方法的同时传入一个含有权限信息的文字信息,那么这个方法就会返回一个整数来表示这个权限在本次方法调用过程中是否已经被授予。需要注意的是,这个方法只能在你处理一个从其他进程中传来的调用时使用,另外一个进程的调用一般是通过 service 已发布的 IDL 接口(或者其他被允许的方式)传入的。

There are a number of other useful ways to check permissions. If you have the pid of another process, you can use the Context method Context.checkPermission(String, int, int) to check a permission against that pid. If you have the package name of another application, you can use the direct PackageManager method PackageManager.checkPermission(String, String) to find out whether that particular package has been granted a specific permission.

另外还有很多非常有用的权限校验功能。比如说,如果你有另一个进程的 PID ,那么就可以使用 Context.checkPermission(String, int, int) 来判断那个 PID 是否持有某个权限;又或者,如果你有另一个应用程序的包名,那么你就可以直接使用包管理器的 PackageManager.checkPermission(String, String) 方法来判断这个包是否持有某个权限。

URI Permissions URI 权限机制


The standard permission system described so far is often not sufficient when used with content providers. A content provider may want to protect itself with read and write permissions, while its direct clients also need to hand specific URIs to other applications for them to operate on. A typical example is attachments in a mail application. Access to the mail should be protected by permissions, since this is sensitive user data. However, if a URI to an image attachment is given to an image viewer, that image viewer will not have permission to open the attachment since it has no reason to hold a permission to access all e-mail.

(翻译地要吐了)有关于标准的权限系统哔哔了这么多,但其实当你使用到 content provider 时,依然不太安全(S.H.E《安全感》 - “你如果没有安全感,把安全帽戴上,自信就不怕有人跟你抢昂~~~~”)。当调用 content provider 的调用者又需要另一个应用程序来处理 URI 所指定的数据时,这个 content provider 就可能会需要一个读写权限来保护自己。一个典型的栗子是邮箱应用在的附件功能。用户的邮件数据是非常隐私的东西,所以应当对其加以权限保护,但如果一个递交给图片浏览器的URI指向的是邮件的附件图片,那么图片浏览器就没办法打开这个附件,因为一个图片浏览器正常情况下是没有理由拥有查阅邮件的权限(所以才需要更精细的权限控制机制)

The solution to this problem is per-URI permissions: when starting an activity or returning a result to an activity, the caller can set Intent.FLAG_GRANT_READ_URI_PERMISSION and/or Intent.FLAG_GRANT_WRITE_URI_PERMISSION. This grants the receiving activity permission access the specific data URI in the Intent, regardless of whether it has any permission to access data in the content provider corresponding to the Intent. 

解决上述问题的方案就是为每个 URI 授予权限,也就是说当你需要启动一个 activity 或者返回一个结果给某一个 activity 时,就可以设置  Intent.FLAG_GRANT_READ_URI_PERMISSION 或者 Intent.FLAG_GRANT_WRITE_URI_PERMISSION 权限。这个设置就授予了获得该 URI 资源的activity一个临时的权限来访问该 URI 指定的资源而不管它是否拥有这个 intent 在content provider 中对应数据的访问权限。

This mechanism allows a common capability-style model where user interaction (opening an attachment, selecting a contact from a list, etc) drives ad-hoc granting of fine-grained permission. This can be a key facility for reducing the permissions needed by applications to only those directly related to their behavior.

这种机制建立了一种普通的功能性的模型,当用户在与系统交互的过程中即授予了一个特定的、更精细的权限(比如打开一个附件,从联系人列表中选中某个联系人等等)。这或许也是减少应用程序申请冗余的权限的一种关键机制。

The granting of fine-grained URI permissions does, however, require some cooperation with the content provider holding those URIs. It is strongly recommended that content providers implement this facility, and declare that they support it through the android:grantUriPermissions attribute or <grant-uri-permissions> tag.

在授予了这些精细的URI权限之后,还需要持有这些 UIR 的 content provider 的配合。所以,强烈建议 content provider 实现这个功能,并通过 android:grantUriPermissions 属性或者 <grant-uri-permissions> 标签来声明它们支持这种机制。

More information can be found in the Context.grantUriPermission()Context.revokeUriPermission(), andContext.checkUriPermission() methods.

更多相关信息可以在以下传送门中被找到: Context.grantUriPermission()Context.revokeUriPermission() 以及 Context.checkUriPermission() 


0 0