- Android content provider uri permission
- Granting Content Provider URI Permissions
- Content Provider Basics
- In this document
- Key classes
- Related Samples
- See also
- Overview
- Accessing a provider
- Content URIs
- Retrieving Data from the Provider
- Requesting read access permission
- Constructing the query
- Protecting against malicious input
- Displaying query results
- Getting data from query results
- Content Provider Permissions
- Inserting, Updating, and Deleting Data
- Inserting data
- Updating data
- Deleting data
- Provider Data Types
- Alternative Forms of Provider Access
- Batch access
- Displaying data using a helper app
- Data access via intents
- Getting access with temporary permissions
- Using another application
- Contract Classes
- MIME Type Reference
Android content provider uri permission
description: Specifies which data subsets of the parent content provider permission can be granted for. Data subsets are indicated by the path part of a content: URI. (The authority part of the URI identifies the content provider.) Granting permission is a way of enabling clients of the provider that don’t normally have permission to access its data to overcome that restriction on a one-time basis.
If a content provider’s grantUriPermissions attribute is » true «, permission can be granted for any the data under the provider’s purview. However, if that attribute is » false «, permission can be granted only to data subsets that are specified by this element. A provider can contain any number of elements. Each one can specify only one path (only one of the three possible attributes).
For information on how permission is granted, see the element’s grantUriPermissions attribute.
attributes: android:path
android:pathPrefix
android:pathPattern A path identifying the data subset or subsets that permission can be granted for. The path attribute specifies a complete path; permission can be granted only to the particular data subset identified by that path. The pathPrefix attribute specifies the initial part of a path; permission can be granted to all data subsets with paths that share that initial part. The pathPattern attribute specifies a complete path, but one that can contain the following wildcards:
- An asterisk (‘ * ‘) matches a sequence of 0 to many occurrences of the immediately preceding character.
A period followed by an asterisk (» .* «) matches any sequence of 0 to many characters.
Because ‘ \ ‘ is used as an escape character when the string is read from XML (before it is parsed as a pattern), you will need to double-escape: For example, a literal ‘ * ‘ would be written as » \\* » and a literal ‘ \ ‘ would be written as » \\\\ «. This is basically the same as what you would need to write if constructing the string in Java code.
For more information on these types of patterns, see the descriptions of PATTERN_LITERAL , PATTERN_PREFIX , and PATTERN_SIMPLE_GLOB in the PatternMatcher class.
introduced in: API Level 1 see also: the grantUriPermissions attribute of the
Источник
Granting Content Provider URI Permissions
The goal of this short example is to show you how you can further protect your application’s data by enforcing permissions upon your custom content provider. For those who have never seen a custom content provider implementation, I invite you to check out my post Writing Your own Content Provider before reading on.
The purpose of giving your content provider the ability to grant access to its data should be pretty clear. Suppose you want to protect the integrity of your content provider’s data. Then, for some users/applications you may want to give them both read and write permissions, while for others you may only want to give them read permission. A simple example of this is attachments in a mail application [taken from Google]:
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.
These permissions are for a specific content URI, and will last until the Activity that receives them is finished. In other words, when an application grants read and/or write permissions to another Activity, these permissions are temporary. Before moving on to some code, let me note that this implementation is different than declaring the android:readPermission and android:writePermission attributes as these tags specify specific applications and give those applications permanent read/write access. In this way, the method below which uses the android:grantUriPermissions tag a.k.a the sub-tag grant-uri-permission is much more dynamic and flexible.
So let’s see how all this is done. Adding permission requirements to your content provider is actually quite simple. Let’s extend my Notes ContentProvider from the above example and give it the ability to grant URI permissions. Say you want to give the user the ability to share his/her notes through various mail/social-media applications, but you want to protect the content of the note. Then, you’ll want to add the following to your AndroidManifest.xml file:
What I mean by the distinction “permissions throughout the entire provider” versus “permissions to specific sub-branches of the provider” is that in the former, any URI with pattern:
Will have the ability to grant permissions, while in the second only URIs with pattern:
can grant URI permissions (for those struggling with the concept of URIs, just think of this as giving your entire hard drive some desired property, versus only giving one directory in your hard drive that same property). Finally, as for how you actually go about granting such permissions through Intents, the below shows it done in a generic Activity:
And with that, in order to resolve our custom Intent, we simply need to write a separate Activity (note this Activity need not be defined within the same application as the ContentProvider) with correctly specified intent filter:
And voila! Now your NoteReaderActivity simply needs to call the getIntent() method to retrieve the content of the note! Architecturally, this process looks like:
Granting Uri Permissions Architecture
And once the NoteReaderActivity obtains the content of the note, it has the ability to layer on top any additional functionality (i.e. including pictures, videos, other media content) before ultimately sharing it with your friends.
Here, at the end of the day, everyone is happy. The NotePad application can allow other applications on the device to consume its content without fear of data corruption, while the NoteReader application can focus on non-content related issues such as UI, media attachments, group sharing, etc.
Источник
Content Provider Basics
In this document
Key classes
Related Samples
See also
A content provider manages access to a central repository of data. A provider is part of an Android application, which often provides its own UI for working with the data. However, content providers are primarily intended to be used by other applications, which access the provider using a provider client object. Together, providers and provider clients offer a consistent, standard interface to data that also handles inter-process communication and secure data access.
This topic describes the basics of the following:
- How content providers work.
- The API you use retrieve data from a content provider.
- The API you use to insert, update, or delete data in a content provider.
- Other API features that facilitate working with providers.
Overview
A content provider presents data to external applications as one or more tables that are similar to the tables found in a relational database. A row represents an instance of some type of data the provider collects, and each row in the column represents an individual piece of data collected for an instance.
For example, one of the built-in providers in the Android platform is the user dictionary, which stores the spellings of non-standard words that the user wants to keep. Table 1 illustrates what the data might look like in this provider’s table:
Table 1: Sample user dictionary table.
word | app id | frequency | locale | _ID |
---|---|---|---|---|
mapreduce | user1 | 100 | en_US | 1 |
precompiler | user14 | 200 | fr_FR | 2 |
applet | user2 | 225 | fr_CA | 3 |
const | user1 | 255 | pt_BR | 4 |
int | user5 | 100 | en_UK | 5 |
In table 1, each row represents an instance of a word that might not be found in a standard dictionary. Each column represents some data for that word, such as the locale in which it was first encountered. The column headers are column names that are stored in the provider. To refer to a row’s locale, you refer to its locale column. For this provider, the _ID column serves as a «primary key» column that the provider automatically maintains.
Note: A provider isn’t required to have a primary key, and it isn’t required to use _ID as the column name of a primary key if one is present. However, if you want to bind data from a provider to a ListView , one of the column names has to be _ID . This requirement is explained in more detail in the section Displaying query results.
Accessing a provider
An application accesses the data from a content provider with a ContentResolver client object. This object has methods that call identically-named methods in the provider object, an instance of one of the concrete subclasses of ContentProvider . The ContentResolver methods provide the basic «CRUD» (create, retrieve, update, and delete) functions of persistent storage.
The ContentResolver object in the client application’s process and the ContentProvider object in the application that owns the provider automatically handle inter-process communication. ContentProvider also acts as an abstraction layer between its repository of data and the external appearance of data as tables.
Note: To access a provider, your application usually has to request specific permissions in its manifest file. This is described in more detail in the section Content Provider Permissions
For example, to get a list of the words and their locales from the User Dictionary Provider, you call ContentResolver.query() . The query() method calls the ContentProvider.query() method defined by the User Dictionary Provider. The following lines of code show a ContentResolver.query() call:
Table 2 shows how the arguments to query(Uri,projection,selection,selectionArgs,sortOrder) match an SQL SELECT statement:
Table 2: Query() compared to SQL query.
query() argument | SELECT keyword/parameter | Notes |
---|---|---|
Uri | FROM table_name | Uri maps to the table in the provider named table_name. |
projection | col,col,col. | projection is an array of columns that should be included for each row retrieved. |
selection | WHERE col = value | selection specifies the criteria for selecting rows. |
selectionArgs | (No exact equivalent. Selection arguments replace ? placeholders in the selection clause.) | |
sortOrder | ORDER BY col,col. | sortOrder specifies the order in which rows appear in the returned Cursor . |
Content URIs
A content URI is a URI that identifies data in a provider. Content URIs include the symbolic name of the entire provider (its authority) and a name that points to a table (a path). When you call a client method to access a table in a provider, the content URI for the table is one of the arguments.
In the preceding lines of code, the constant CONTENT_URI contains the content URI of the user dictionary’s «words» table. The ContentResolver object parses out the URI’s authority, and uses it to «resolve» the provider by comparing the authority to a system table of known providers. The ContentResolver can then dispatch the query arguments to the correct provider.
The ContentProvider uses the path part of the content URI to choose the table to access. A provider usually has a path for each table it exposes.
In the previous lines of code, the full URI for the «words» table is:
where the user_dictionary string is the provider’s authority, and words string is the table’s path. The string content:// (the scheme) is always present, and identifies this as a content URI.
Many providers allow you to access a single row in a table by appending an ID value to the end of the URI. For example, to retrieve a row whose _ID is 4 from user dictionary, you can use this content URI:
You often use id values when you’ve retrieved a set of rows and then want to update or delete one of them.
Note: The Uri and Uri.Builder classes contain convenience methods for constructing well-formed Uri objects from strings. The ContentUris contains convenience methods for appending id values to a URI. The previous snippet uses withAppendedId() to append an id to the UserDictionary content URI.
Retrieving Data from the Provider
This section describes how to retrieve data from a provider, using the User Dictionary Provider as an example.
For the sake of clarity, the code snippets in this section call ContentResolver.query() on the «UI thread»». In actual code, however, you should do queries asynchronously on a separate thread. One way to do this is to use the CursorLoader class, which is described in more detail in the Loaders guide. Also, the lines of code are snippets only; they don’t show a complete application.
To retrieve data from a provider, follow these basic steps:
- Request the read access permission for the provider.
- Define the code that sends a query to the provider.
Requesting read access permission
To retrieve data from a provider, your application needs «read access permission» for the provider. You can’t request this permission at run-time; instead, you have to specify that you need this permission in your manifest, using the element and the exact permission name defined by the provider. When you specify this element in your manifest, you are in effect «requesting» this permission for your application. When users install your application, they implicitly grant this request.
To find the exact name of the read access permission for the provider you’re using, as well as the names for other access permissions used by the provider, look in the provider’s documentation.
The role of permissions in accessing providers is described in more detail in the section Content Provider Permissions.
The User Dictionary Provider defines the permission android.permission.READ_USER_DICTIONARY in its manifest file, so an application that wants to read from the provider must request this permission.
Constructing the query
The next step in retrieving data a provider is to construct a query. This first snippet defines some variables for accessing the User Dictionary Provider:
The next snippet shows how to use ContentResolver.query() , using the User Dictionary Provider as an example. A provider client query is similar to an SQL query, and it contains a set of columns to return, a set of selection criteria, and a sort order.
The set of columns that the query should return is called a projection (the variable mProjection ).
The expression that specifies the rows to retrieve is split into a selection clause and selection arguments. The selection clause is a combination of logical and Boolean expressions, column names, and values (the variable mSelectionClause ). If you specify the replaceable parameter ? instead of a value, the query method retrieves the value from the selection arguments array (the variable mSelectionArgs ).
In the next snippet, if the user doesn’t enter a word, the selection clause is set to null , and the query returns all the words in the provider. If the user enters a word, the selection clause is set to UserDictionary.Words.WORD + » = ?» and the first element of selection arguments array is set to the word the user enters.
This query is analogous to the SQL statement:
In this SQL statement, the actual column names are used instead of contract class constants.
Protecting against malicious input
If the data managed by the content provider is in an SQL database, including external untrusted data into raw SQL statements can lead to SQL injection.
Consider this selection clause:
If you do this, you’re allowing the user to concatenate malicious SQL onto your SQL statement. For example, the user could enter «nothing; DROP TABLE *;» for mUserInput , which would result in the selection clause var = nothing; DROP TABLE *; . Since the selection clause is treated as an SQL statement, this might cause the provider to erase all of the tables in the underlying SQLite database (unless the provider is set up to catch SQL injection attempts).
To avoid this problem, use a selection clause that uses ? as a replaceable parameter and a separate array of selection arguments. When you do this, the user input is bound directly to the query rather than being interpreted as part of an SQL statement. Because it’s not treated as SQL, the user input can’t inject malicious SQL. Instead of using concatenation to include the user input, use this selection clause:
Set up the array of selection arguments like this:
Put a value in the selection arguments array like this:
A selection clause that uses ? as a replaceable parameter and an array of selection arguments array are preferred way to specify a selection, even if the provider isn’t based on an SQL database.
Displaying query results
The ContentResolver.query() client method always returns a Cursor containing the columns specified by the query’s projection for the rows that match the query’s selection criteria. A Cursor object provides random read access to the rows and columns it contains. Using Cursor methods, you can iterate over the rows in the results, determine the data type of each column, get the data out of a column, and examine other properties of the results. Some Cursor implementations automatically update the object when the provider’s data changes, or trigger methods in an observer object when the Cursor changes, or both.
Note: A provider may restrict access to columns based on the nature of the object making the query. For example, the Contacts Provider restricts access for some columns to sync adapters, so it won’t return them to an activity or service.
If no rows match the selection criteria, the provider returns a Cursor object for which Cursor.getCount() is 0 (an empty cursor).
If an internal error occurs, the results of the query depend on the particular provider. It may choose to return null , or it may throw an Exception .
Since a Cursor is a «list» of rows, a good way to display the contents of a Cursor is to link it to a ListView via a SimpleCursorAdapter .
The following snippet continues the code from the previous snippet. It creates a SimpleCursorAdapter object containing the Cursor retrieved by the query, and sets this object to be the adapter for a ListView :
Note: To back a ListView with a Cursor , the cursor must contain a column named _ID . Because of this, the query shown previously retrieves the _ID column for the «words» table, even though the ListView doesn’t display it. This restriction also explains why most providers have a _ID column for each of their tables.
Getting data from query results
Rather than simply displaying query results, you can use them for other tasks. For example, you can retrieve spellings from the user dictionary and then look them up in other providers. To do this, you iterate over the rows in the Cursor :
Cursor implementations contain several «get» methods for retrieving different types of data from the object. For example, the previous snippet uses getString() . They also have a getType() method that returns a value indicating the data type of the column.
Content Provider Permissions
A provider’s application can specify permissions that other applications must have in order to access the provider’s data. These permissions ensure that the user knows what data an application will try to access. Based on the provider’s requirements, other applications request the permissions they need in order to access the provider. End users see the requested permissions when they install the application.
If a provider’s application doesn’t specify any permissions, then other applications have no access to the provider’s data. However, components in the provider’s application always have full read and write access, regardless of the specified permissions.
As noted previously, the User Dictionary Provider requires the android.permission.READ_USER_DICTIONARY permission to retrieve data from it. The provider has the separate android.permission.WRITE_USER_DICTIONARY permission for inserting, updating, or deleting data.
To get the permissions needed to access a provider, an application requests them with a element in its manifest file. When the Android Package Manager installs the application, a user must approve all of the permissions the application requests. If the user approves all of them, Package Manager continues the installation; if the user doesn’t approve them, Package Manager aborts the installation.
The following element requests read access to the User Dictionary Provider:
The impact of permissions on provider access is explained in more detail in the Security and Permissions guide.
Inserting, Updating, and Deleting Data
In the same way that you retrieve data from a provider, you also use the interaction between a provider client and the provider’s ContentProvider to modify data. You call a method of ContentResolver with arguments that are passed to the corresponding method of ContentProvider . The provider and provider client automatically handle security and inter-process communication.
Inserting data
To insert data into a provider, you call the ContentResolver.insert() method. This method inserts a new row into the provider and returns a content URI for that row. This snippet shows how to insert a new word into the User Dictionary Provider:
The data for the new row goes into a single ContentValues object, which is similar in form to a one-row cursor. The columns in this object don’t need to have the same data type, and if you don’t want to specify a value at all, you can set a column to null using ContentValues.putNull() .
The snippet doesn’t add the _ID column, because this column is maintained automatically. The provider assigns a unique value of _ID to every row that is added. Providers usually use this value as the table’s primary key.
The content URI returned in newUri identifies the newly-added row, with the following format:
The is the contents of _ID for the new row. Most providers can detect this form of content URI automatically and then perform the requested operation on that particular row.
To get the value of _ID from the returned Uri , call ContentUris.parseId() .
Updating data
To update a row, you use a ContentValues object with the updated values just as you do with an insertion, and selection criteria just as you do with a query. The client method you use is ContentResolver.update() . You only need to add values to the ContentValues object for columns you’re updating. If you want to clear the contents of a column, set the value to null .
The following snippet changes all the rows whose locale has the language «en» to a have a locale of null . The return value is the number of rows that were updated:
You should also sanitize user input when you call ContentResolver.update() . To learn more about this, read the section Protecting against malicious input.
Deleting data
Deleting rows is similar to retrieving row data: you specify selection criteria for the rows you want to delete and the client method returns the number of deleted rows. The following snippet deletes rows whose appid matches «user». The method returns the number of deleted rows.
You should also sanitize user input when you call ContentResolver.delete() . To learn more about this, read the section Protecting against malicious input.
Provider Data Types
Content providers can offer many different data types. The User Dictionary Provider offers only text, but providers can also offer the following formats:
- integer
- long integer (long)
- floating point
- long floating point (double)
Another data type that providers often use is Binary Large OBject (BLOB) implemented as a 64KB byte array. You can see the available data types by looking at the Cursor class «get» methods.
The data type for each column in a provider is usually listed in its documentation. The data types for the User Dictionary Provider are listed in the reference documentation for its contract class UserDictionary.Words (contract classes are described in the section Contract Classes). You can also determine the data type by calling Cursor.getType() .
Providers also maintain MIME data type information for each content URI they define. You can use the MIME type information to find out if your application can handle data that the provider offers, or to choose a type of handling based on the MIME type. You usually need the MIME type when you are working with a provider that contains complex data structures or files. For example, the ContactsContract.Data table in the Contacts Provider uses MIME types to label the type of contact data stored in each row. To get the MIME type corresponding to a content URI, call ContentResolver.getType() .
The section MIME Type Reference describes the syntax of both standard and custom MIME types.
Alternative Forms of Provider Access
Three alternative forms of provider access are important in application development:
- Batch access: You can create a batch of access calls with methods in the ContentProviderOperation class, and then apply them with )»>ContentResolver.applyBatch() .
- Asynchronous queries: You should do queries in a separate thread. One way to do this is to use a CursorLoader object. The examples in the Loaders guide demonstrate how to do this.
- Data access via intents: Although you can’t send an intent directly to a provider, you can send an intent to the provider’s application, which is usually the best-equipped to modify the provider’s data.
Batch access and modification via intents are described in the following sections.
Batch access
Batch access to a provider is useful for inserting a large number of rows, or for inserting rows in multiple tables in the same method call, or in general for performing a set of operations across process boundaries as a transaction (an atomic operation).
To access a provider in «batch mode», you create an array of ContentProviderOperation objects and then dispatch them to a content provider with )»>ContentResolver.applyBatch() . You pass the content provider’s authority to this method, rather than a particular content URI. This allows each ContentProviderOperation object in the array to work against a different table. A call to )»>ContentResolver.applyBatch() returns an array of results.
The description of the ContactsContract.RawContacts contract class includes a code snippet that demonstrates batch insertion. The Contact Manager sample application contains an example of batch access in its ContactAdder.java source file.
Displaying data using a helper app
If your application does have access permissions, you still may want to use an intent to display data in another application. For example, the Calendar application accepts an ACTION_VIEW intent, which displays a particular date or event. This allows you to display calendar information without having to create your own UI. To learn more about this feature, see the Calendar Provider guide.
The application to which you send the intent doesn’t have to be the application associated with the provider. For example, you can retrieve a contact from the Contact Provider, then send an ACTION_VIEW intent containing the content URI for the contact’s image to an image viewer.
Data access via intents
Intents can provide indirect access to a content provider. You allow the user to access data in a provider even if your application doesn’t have access permissions, either by getting a result intent back from an application that has permissions, or by activating an application that has permissions and letting the user do work in it.
Getting access with temporary permissions
You can access data in a content provider, even if you don’t have the proper access permissions, by sending an intent to an application that does have the permissions and receiving back a result intent containing «URI» permissions. These are permissions for a specific content URI that last until the activity that receives them is finished. The application that has permanent permissions grants temporary permissions by setting a flag in the result intent:
Note: These flags don’t give general read or write access to the provider whose authority is contained in the content URI. The access is only for the URI itself.
A provider defines URI permissions for content URIs in its manifest, using the android:grantUriPermission attribute of the
element. The URI permissions mechanism is explained in more detail in the Security and Permissions guide, in the section «URI Permissions».
For example, you can retrieve data for a contact in the Contacts Provider, even if you don’t have the READ_CONTACTS permission. You might want to do this in an application that sends e-greetings to a contact on his or her birthday. Instead of requesting READ_CONTACTS , which gives you access to all of the user’s contacts and all of their information, you prefer to let the user control which contacts are used by your application. To do this, you use the following process:
- Your application sends an intent containing the action ACTION_PICK and the «contacts» MIME type CONTENT_ITEM_TYPE , using the method startActivityForResult() .
- Because this intent matches the intent filter for the People app’s «selection» activity, the activity will come to the foreground.
- In the selection activity, the user selects a contact to update. When this happens, the selection activity calls setResult(resultcode, intent) to set up a intent to give back to your application. The intent contains the content URI of the contact the user selected, and the «extras» flags FLAG_GRANT_READ_URI_PERMISSION . These flags grant URI permission to your app to read data for the contact pointed to by the content URI. The selection activity then calls finish() to return control to your application.
- Your activity returns to the foreground, and the system calls your activity’s onActivityResult() method. This method receives the result intent created by the selection activity in the People app.
- With the content URI from the result intent, you can read the contact’s data from the Contacts Provider, even though you didn’t request permanent read access permission to the provider in your manifest. You can then get the contact’s birthday information or his or her email address and then send the e-greeting.
Using another application
A simple way to allow the user to modify data to which you don’t have access permissions is to activate an application that has permissions and let the user do the work there.
For example, the Calendar application accepts an ACTION_INSERT intent, which allows you to activate the application’s insert UI. You can pass «extras» data in this intent, which the application uses to pre-populate the UI. Because recurring events have a complex syntax, the preferred way of inserting events into the Calendar Provider is to activate the Calendar app with an ACTION_INSERT and then let the user insert the event there.
Contract Classes
A contract class defines constants that help applications work with the content URIs, column names, intent actions, and other features of a content provider. Contract classes are not included automatically with a provider; the provider’s developer has to define them and then make them available to other developers. Many of the providers included with the Android platform have corresponding contract classes in the package android.provider .
For example, the User Dictionary Provider has a contract class UserDictionary containing content URI and column name constants. The content URI for the «words» table is defined in the constant UserDictionary.Words.CONTENT_URI . The UserDictionary.Words class also contains column name constants, which are used in the example snippets in this guide. For example, a query projection can be defined as:
Another contract class is ContactsContract for the Contacts Provider. The reference documentation for this class includes example code snippets. One of its subclasses, ContactsContract.Intents.Insert , is a contract class that contains constants for intents and intent data.
MIME Type Reference
Content providers can return standard MIME media types, or custom MIME type strings, or both.
MIME types have the format
For example, the well-known MIME type text/html has the text type and the html subtype. If the provider returns this type for a URI, it means that a query using that URI will return text containing HTML tags.
Custom MIME type strings, also called «vendor-specific» MIME types, have more complex type and subtype values. The type value is always
for multiple rows, or
for a single row.
The subtype is provider-specific. The Android built-in providers usually have a simple subtype. For example, the when the Contacts application creates a row for a telephone number, it sets the following MIME type in the row:
Notice that the subtype value is simply phone_v2 .
Other provider developers may create their own pattern of subtypes based on the provider’s authority and table names. For example, consider a provider that contains train timetables. The provider’s authority is com.example.trains , and it contains the tables Line1, Line2, and Line3. In response to the content URI
for table Line1, the provider returns the MIME type
In response to the content URI
for row 5 in table Line2, the provider returns the MIME type
Most content providers define contract class constants for the MIME types they use. The Contacts Provider contract class ContactsContract.RawContacts , for example, defines the constant CONTENT_ITEM_TYPE for the MIME type of a single raw contact row.
Content URIs for single rows are described in the section Content URIs.
Источник