ContentProvider.java revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.content;
18
19import android.content.pm.PackageManager;
20import android.content.pm.ProviderInfo;
21import android.content.res.Configuration;
22import android.database.Cursor;
23import android.database.CursorToBulkCursorAdaptor;
24import android.database.CursorWindow;
25import android.database.IBulkCursor;
26import android.database.IContentObserver;
27import android.database.SQLException;
28import android.net.Uri;
29import android.os.Binder;
30import android.os.ParcelFileDescriptor;
31
32import java.io.File;
33import java.io.FileNotFoundException;
34
35/**
36 * Content providers are one of the primary building blocks of Android applications, providing
37 * content to applications. They encapsulate data and provide it to applications through the single
38 * {@link ContentResolver} interface. A content provider is only required if you need to share
39 * data between multiple applications. For example, the contacts data is used by multiple
40 * applications and must be stored in a content provider. If you don't need to share data amongst
41 * multiple applications you can use a database directly via
42 * {@link android.database.sqlite.SQLiteDatabase}.
43 *
44 * <p>See <a href="{@docRoot}devel/data/contentproviders.html">this page</a> for more information on
45 * content providers.</p>
46 *
47 * <p>When a request is made via
48 * a {@link ContentResolver} the system inspects the authority of the given URI and passes the
49 * request to the content provider registered with the authority. The content provider can interpret
50 * the rest of the URI however it wants. The {@link UriMatcher} class is helpful for parsing
51 * URIs.</p>
52 *
53 * <p>The primary methods that need to be implemented are:
54 * <ul>
55 *   <li>{@link #query} which returns data to the caller</li>
56 *   <li>{@link #insert} which inserts new data into the content provider</li>
57 *   <li>{@link #update} which updates existing data in the content provider</li>
58 *   <li>{@link #delete} which deletes data from the content provider</li>
59 *   <li>{@link #getType} which returns the MIME type of data in the content provider</li>
60 * </ul></p>
61 *
62 * <p>This class takes care of cross process calls so subclasses don't have to worry about which
63 * process a request is coming from.</p>
64 */
65public abstract class ContentProvider implements ComponentCallbacks {
66    private Context mContext = null;
67    private String mReadPermission;
68    private String mWritePermission;
69
70    private Transport mTransport = new Transport();
71
72    /**
73     * Given an IContentProvider, try to coerce it back to the real
74     * ContentProvider object if it is running in the local process.  This can
75     * be used if you know you are running in the same process as a provider,
76     * and want to get direct access to its implementation details.  Most
77     * clients should not nor have a reason to use it.
78     *
79     * @param abstractInterface The ContentProvider interface that is to be
80     *              coerced.
81     * @return If the IContentProvider is non-null and local, returns its actual
82     * ContentProvider instance.  Otherwise returns null.
83     * @hide
84     */
85    public static ContentProvider coerceToLocalContentProvider(
86            IContentProvider abstractInterface) {
87        if (abstractInterface instanceof Transport) {
88            return ((Transport)abstractInterface).getContentProvider();
89        }
90        return null;
91    }
92
93    /**
94     * Binder object that deals with remoting.
95     *
96     * @hide
97     */
98    class Transport extends ContentProviderNative {
99        ContentProvider getContentProvider() {
100            return ContentProvider.this;
101        }
102
103        /**
104         * Remote version of a query, which returns an IBulkCursor. The bulk
105         * cursor should be wrapped with BulkCursorToCursorAdaptor before use.
106         */
107        public IBulkCursor bulkQuery(Uri uri, String[] projection,
108                String selection, String[] selectionArgs, String sortOrder,
109                IContentObserver observer, CursorWindow window) {
110            checkReadPermission(uri);
111            Cursor cursor = ContentProvider.this.query(uri, projection,
112                    selection, selectionArgs, sortOrder);
113            if (cursor == null) {
114                return null;
115            }
116            String wperm = getWritePermission();
117            return new CursorToBulkCursorAdaptor(cursor, observer,
118                    ContentProvider.this.getClass().getName(),
119                    wperm == null ||
120                    getContext().checkCallingOrSelfPermission(getWritePermission())
121                            == PackageManager.PERMISSION_GRANTED,
122                    window);
123        }
124
125        public Cursor query(Uri uri, String[] projection,
126                String selection, String[] selectionArgs, String sortOrder) {
127            checkReadPermission(uri);
128            return ContentProvider.this.query(uri, projection, selection,
129                    selectionArgs, sortOrder);
130        }
131
132        public String getType(Uri uri) {
133            return ContentProvider.this.getType(uri);
134        }
135
136
137        public Uri insert(Uri uri, ContentValues initialValues) {
138            checkWritePermission(uri);
139            return ContentProvider.this.insert(uri, initialValues);
140        }
141
142        public int bulkInsert(Uri uri, ContentValues[] initialValues) {
143            checkWritePermission(uri);
144            return ContentProvider.this.bulkInsert(uri, initialValues);
145        }
146
147        public int delete(Uri uri, String selection, String[] selectionArgs) {
148            checkWritePermission(uri);
149            return ContentProvider.this.delete(uri, selection, selectionArgs);
150        }
151
152        public int update(Uri uri, ContentValues values, String selection,
153                String[] selectionArgs) {
154            checkWritePermission(uri);
155            return ContentProvider.this.update(uri, values, selection, selectionArgs);
156        }
157
158        public ParcelFileDescriptor openFile(Uri uri, String mode)
159                throws FileNotFoundException {
160            if (mode != null && mode.startsWith("rw")) checkWritePermission(uri);
161            else checkReadPermission(uri);
162            return ContentProvider.this.openFile(uri, mode);
163        }
164
165        public ISyncAdapter getSyncAdapter() {
166            checkWritePermission(null);
167            return ContentProvider.this.getSyncAdapter().getISyncAdapter();
168        }
169
170        private void checkReadPermission(Uri uri) {
171            final String rperm = getReadPermission();
172            final int pid = Binder.getCallingPid();
173            final int uid = Binder.getCallingUid();
174            if (getContext().checkUriPermission(uri, rperm, null, pid, uid,
175                    Intent.FLAG_GRANT_READ_URI_PERMISSION)
176                    == PackageManager.PERMISSION_GRANTED) {
177                return;
178            }
179            String msg = "Permission Denial: reading "
180                    + ContentProvider.this.getClass().getName()
181                    + " uri " + uri + " from pid=" + Binder.getCallingPid()
182                    + ", uid=" + Binder.getCallingUid()
183                    + " requires " + rperm;
184            throw new SecurityException(msg);
185        }
186
187        private void checkWritePermission(Uri uri) {
188            final String wperm = getWritePermission();
189            final int pid = Binder.getCallingPid();
190            final int uid = Binder.getCallingUid();
191            if (getContext().checkUriPermission(uri, null, wperm, pid, uid,
192                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
193                    == PackageManager.PERMISSION_GRANTED) {
194                return;
195            }
196            String msg = "Permission Denial: writing "
197                    + ContentProvider.this.getClass().getName()
198                    + " uri " + uri + " from pid=" + Binder.getCallingPid()
199                    + ", uid=" + Binder.getCallingUid()
200                    + " requires " + wperm;
201            throw new SecurityException(msg);
202        }
203    }
204
205
206    /**
207     * Retrieve the Context this provider is running in.  Only available once
208     * onCreate(Map icicle) has been called -- this will be null in the
209     * constructor.
210     */
211    public final Context getContext() {
212        return mContext;
213    }
214
215    /**
216     * Change the permission required to read data from the content
217     * provider.  This is normally set for you from its manifest information
218     * when the provider is first created.
219     *
220     * @param permission Name of the permission required for read-only access.
221     */
222    protected final void setReadPermission(String permission) {
223        mReadPermission = permission;
224    }
225
226    /**
227     * Return the name of the permission required for read-only access to
228     * this content provider.  This method can be called from multiple
229     * threads, as described in the
230     * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of
231     * the Application Model overview</a>.
232     */
233    public final String getReadPermission() {
234        return mReadPermission;
235    }
236
237    /**
238     * Change the permission required to read and write data in the content
239     * provider.  This is normally set for you from its manifest information
240     * when the provider is first created.
241     *
242     * @param permission Name of the permission required for read/write access.
243     */
244    protected final void setWritePermission(String permission) {
245        mWritePermission = permission;
246    }
247
248    /**
249     * Return the name of the permission required for read/write access to
250     * this content provider.  This method can be called from multiple
251     * threads, as described in the
252     * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of
253     * the Application Model overview</a>.
254     */
255    public final String getWritePermission() {
256        return mWritePermission;
257    }
258
259    /**
260     * Called when the provider is being started.
261     *
262     * @return true if the provider was successfully loaded, false otherwise
263     */
264    public abstract boolean onCreate();
265
266    public void onConfigurationChanged(Configuration newConfig) {
267    }
268
269    public void onLowMemory() {
270    }
271
272    /**
273     * Receives a query request from a client in a local process, and
274     * returns a Cursor. This is called internally by the {@link ContentResolver}.
275     * This method can be called from multiple
276     * threads, as described in the
277     * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of
278     * the Application Model overview</a>.
279     * <p>
280     * Example client call:<p>
281     * <pre>// Request a specific record.
282     * Cursor managedCursor = managedQuery(
283                Contacts.People.CONTENT_URI.addId(2),
284                projection,    // Which columns to return.
285                null,          // WHERE clause.
286                People.NAME + " ASC");   // Sort order.</pre>
287     * Example implementation:<p>
288     * <pre>// SQLiteQueryBuilder is a helper class that creates the
289        // proper SQL syntax for us.
290        SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
291
292        // Set the table we're querying.
293        qBuilder.setTables(DATABASE_TABLE_NAME);
294
295        // If the query ends in a specific record number, we're
296        // being asked for a specific record, so set the
297        // WHERE clause in our query.
298        if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){
299            qBuilder.appendWhere("_id=" + uri.getPathLeafId());
300        }
301
302        // Make the query.
303        Cursor c = qBuilder.query(mDb,
304                projection,
305                selection,
306                selectionArgs,
307                groupBy,
308                having,
309                sortOrder);
310        c.setNotificationUri(getContext().getContentResolver(), uri);
311        return c;</pre>
312     *
313     * @param uri The URI to query. This will be the full URI sent by the client;
314     * if the client is requesting a specific record, the URI will end in a record number
315     * that the implementation should parse and add to a WHERE or HAVING clause, specifying
316     * that _id value.
317     * @param projection The list of columns to put into the cursor. If
318     *      null all columns are included.
319     * @param selection A selection criteria to apply when filtering rows.
320     *      If null then all rows are included.
321     * @param sortOrder How the rows in the cursor should be sorted.
322     *        If null then the provider is free to define the sort order.
323     * @return a Cursor or null.
324     */
325    public abstract Cursor query(Uri uri, String[] projection,
326            String selection, String[] selectionArgs, String sortOrder);
327
328    /**
329     * Return the MIME type of the data at the given URI. This should start with
330     * <code>vnd.android.cursor.item</code> for a single record,
331     * or <code>vnd.android.cursor.dir/</code> for multiple items.
332     * This method can be called from multiple
333     * threads, as described in the
334     * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of
335     * the Application Model overview</a>.
336     *
337     * @param uri the URI to query.
338     * @return a MIME type string, or null if there is no type.
339     */
340    public abstract String getType(Uri uri);
341
342    /**
343     * Implement this to insert a new row.
344     * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
345     * after inserting.
346     * This method can be called from multiple
347     * threads, as described in the
348     * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of the
349     * Application Model overview</a>.
350     * @param uri The content:// URI of the insertion request.
351     * @param values A set of column_name/value pairs to add to the database.
352     * @return The URI for the newly inserted item.
353     */
354    public abstract Uri insert(Uri uri, ContentValues values);
355
356    /**
357     * Implement this to insert a set of new rows, or the default implementation will
358     * iterate over the values and call {@link #insert} on each of them.
359     * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
360     * after inserting.
361     * This method can be called from multiple
362     * threads, as described in the
363     * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of
364     * the Application Model overview</a>.
365     *
366     * @param uri The content:// URI of the insertion request.
367     * @param values An array of sets of column_name/value pairs to add to the database.
368     * @return The number of values that were inserted.
369     */
370    public int bulkInsert(Uri uri, ContentValues[] values) {
371        int numValues = values.length;
372        for (int i = 0; i < numValues; i++) {
373            insert(uri, values[i]);
374        }
375        return numValues;
376    }
377
378    /**
379     * A request to delete one or more rows. The selection clause is applied when performing
380     * the deletion, allowing the operation to affect multiple rows in a
381     * directory.
382     * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyDelete()}
383     * after deleting.
384     * This method can be called from multiple
385     * threads, as described in the
386     * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of the
387     * Application Model overview</a>.
388     *
389     * <p>The implementation is responsible for parsing out a row ID at the end
390     * of the URI, if a specific row is being deleted. That is, the client would
391     * pass in <code>content://contacts/people/22</code> and the implementation is
392     * responsible for parsing the record number (22) when creating a SQL statement.
393     *
394     * @param uri The full URI to query, including a row ID (if a specific record is requested).
395     * @param selection An optional restriction to apply to rows when deleting.
396     * @return The number of rows affected.
397     * @throws SQLException
398     */
399    public abstract int delete(Uri uri, String selection, String[] selectionArgs);
400
401    /**
402     * Update a content URI. All rows matching the optionally provided selection
403     * will have their columns listed as the keys in the values map with the
404     * values of those keys.
405     * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
406     * after updating.
407     * This method can be called from multiple
408     * threads, as described in the
409     * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of the
410     * Application Model overview</a>.
411     *
412     * @param uri The URI to query. This can potentially have a record ID if this
413     * is an update request for a specific record.
414     * @param values A Bundle mapping from column names to new column values (NULL is a
415     *               valid value).
416     * @param selection An optional filter to match rows to update.
417     * @return the number of rows affected.
418     */
419    public abstract int update(Uri uri, ContentValues values, String selection,
420            String[] selectionArgs);
421
422    /**
423     * Open a file blob associated with a content URI.
424     * This method can be called from multiple
425     * threads, as described in the
426     * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of the
427     * Application Model overview</a>.
428     *
429     * <p>Returns a
430     * ParcelFileDescriptor, from which you can obtain a
431     * {@link java.io.FileDescriptor} for use with
432     * {@link java.io.FileInputStream}, {@link java.io.FileOutputStream}, etc.
433     * This can be used to store large data (such as an image) associated with
434     * a particular piece of content.
435     *
436     * <p>The returned ParcelFileDescriptor is owned by the caller, so it is
437     * their responsibility to close it when done.  That is, the implementation
438     * of this method should create a new ParcelFileDescriptor for each call.
439     *
440     * @param uri The URI whose file is to be opened.
441     * @param mode Access mode for the file.  May be "r" for read-only access
442     * or "rw" for read and write access.
443     *
444     * @return Returns a new ParcelFileDescriptor which you can use to access
445     * the file.
446     *
447     * @throws FileNotFoundException Throws FileNotFoundException if there is
448     * no file associated with the given URI or the mode is invalid.
449     * @throws SecurityException Throws SecurityException if the caller does
450     * not have permission to access the file.
451     */
452    public ParcelFileDescriptor openFile(Uri uri, String mode)
453            throws FileNotFoundException {
454        throw new FileNotFoundException("No files supported by provider at "
455                + uri);
456    }
457
458    /**
459     * Convenience for subclasses that wish to implement {@link #openFile}
460     * by looking up a column named "_data" at the given URI.
461     *
462     * @param uri The URI to be opened.
463     * @param mode The file mode.
464     *
465     * @return Returns a new ParcelFileDescriptor that can be used by the
466     * client to access the file.
467     */
468    protected final ParcelFileDescriptor openFileHelper(Uri uri,
469            String mode) throws FileNotFoundException {
470        Cursor c = query(uri, new String[]{"_data"}, null, null, null);
471        int count = (c != null) ? c.getCount() : 0;
472        if (count != 1) {
473            // If there is not exactly one result, throw an appropriate
474            // exception.
475            if (c != null) {
476                c.close();
477            }
478            if (count == 0) {
479                throw new FileNotFoundException("No entry for " + uri);
480            }
481            throw new FileNotFoundException("Multiple items at " + uri);
482        }
483
484        c.moveToFirst();
485        int i = c.getColumnIndex("_data");
486        String path = (i >= 0 ? c.getString(i) : null);
487        c.close();
488        if (path == null) {
489            throw new FileNotFoundException("Column _data not found.");
490        }
491
492        int modeBits;
493        if ("r".equals(mode)) {
494            modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
495        } else if ("rw".equals(mode)) {
496            modeBits = ParcelFileDescriptor.MODE_READ_WRITE
497                    | ParcelFileDescriptor.MODE_CREATE;
498        } else {
499            throw new FileNotFoundException("Bad mode for " + uri + ": "
500                    + mode);
501        }
502        return ParcelFileDescriptor.open(new File(path), modeBits);
503    }
504
505    /**
506     * Get the sync adapter that is to be used by this content provider.
507     * This is intended for use by the sync system. If null then this
508     * content provider is considered not syncable.
509     * This method can be called from multiple
510     * threads, as described in the
511     * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of
512     * the Application Model overview</a>.
513     *
514     * @return the SyncAdapter that is to be used by this ContentProvider, or null
515     *   if this ContentProvider is not syncable
516     * @hide
517     */
518    public SyncAdapter getSyncAdapter() {
519        return null;
520    }
521
522    /**
523     * Returns true if this instance is a temporary content provider.
524     * @return true if this instance is a temporary content provider
525     */
526    protected boolean isTemporary() {
527        return false;
528    }
529
530    /**
531     * Returns the Binder object for this provider.
532     *
533     * @return the Binder object for this provider
534     * @hide
535     */
536    public IContentProvider getIContentProvider() {
537        return mTransport;
538    }
539
540    /**
541     * After being instantiated, this is called to tell the content provider
542     * about itself.
543     *
544     * @param context The context this provider is running in
545     * @param info Registered information about this content provider
546     */
547    public void attachInfo(Context context, ProviderInfo info) {
548
549        /*
550         * Only allow it to be set once, so after the content service gives
551         * this to us clients can't change it.
552         */
553        if (mContext == null) {
554            mContext = context;
555            if (info != null) {
556                setReadPermission(info.readPermission);
557                setWritePermission(info.writePermission);
558            }
559            ContentProvider.this.onCreate();
560        }
561    }
562}
563