Home | History | Annotate | Download | only in content
      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 
     17 package android.content;
     18 
     19 import android.content.pm.PackageManager;
     20 import android.content.pm.PathPermission;
     21 import android.content.pm.ProviderInfo;
     22 import android.content.res.AssetFileDescriptor;
     23 import android.content.res.Configuration;
     24 import android.database.Cursor;
     25 import android.database.CursorToBulkCursorAdaptor;
     26 import android.database.CursorWindow;
     27 import android.database.IBulkCursor;
     28 import android.database.IContentObserver;
     29 import android.database.SQLException;
     30 import android.net.Uri;
     31 import android.os.Binder;
     32 import android.os.Bundle;
     33 import android.os.ParcelFileDescriptor;
     34 import android.os.Process;
     35 
     36 import java.io.File;
     37 import java.io.FileNotFoundException;
     38 import java.util.ArrayList;
     39 
     40 /**
     41  * Content providers are one of the primary building blocks of Android applications, providing
     42  * content to applications. They encapsulate data and provide it to applications through the single
     43  * {@link ContentResolver} interface. A content provider is only required if you need to share
     44  * data between multiple applications. For example, the contacts data is used by multiple
     45  * applications and must be stored in a content provider. If you don't need to share data amongst
     46  * multiple applications you can use a database directly via
     47  * {@link android.database.sqlite.SQLiteDatabase}.
     48  *
     49  * <p>For more information, read <a href="{@docRoot}guide/topics/providers/content-providers.html">Content
     50  * Providers</a>.</p>
     51  *
     52  * <p>When a request is made via
     53  * a {@link ContentResolver} the system inspects the authority of the given URI and passes the
     54  * request to the content provider registered with the authority. The content provider can interpret
     55  * the rest of the URI however it wants. The {@link UriMatcher} class is helpful for parsing
     56  * URIs.</p>
     57  *
     58  * <p>The primary methods that need to be implemented are:
     59  * <ul>
     60  *   <li>{@link #onCreate} which is called to initialize the provider</li>
     61  *   <li>{@link #query} which returns data to the caller</li>
     62  *   <li>{@link #insert} which inserts new data into the content provider</li>
     63  *   <li>{@link #update} which updates existing data in the content provider</li>
     64  *   <li>{@link #delete} which deletes data from the content provider</li>
     65  *   <li>{@link #getType} which returns the MIME type of data in the content provider</li>
     66  * </ul></p>
     67  *
     68  * <p class="caution">Data access methods (such as {@link #insert} and
     69  * {@link #update}) may be called from many threads at once, and must be thread-safe.
     70  * Other methods (such as {@link #onCreate}) are only called from the application
     71  * main thread, and must avoid performing lengthy operations.  See the method
     72  * descriptions for their expected thread behavior.</p>
     73  *
     74  * <p>Requests to {@link ContentResolver} are automatically forwarded to the appropriate
     75  * ContentProvider instance, so subclasses don't have to worry about the details of
     76  * cross-process calls.</p>
     77  */
     78 public abstract class ContentProvider implements ComponentCallbacks {
     79     /*
     80      * Note: if you add methods to ContentProvider, you must add similar methods to
     81      *       MockContentProvider.
     82      */
     83 
     84     private Context mContext = null;
     85     private int mMyUid;
     86     private String mReadPermission;
     87     private String mWritePermission;
     88     private PathPermission[] mPathPermissions;
     89     private boolean mExported;
     90 
     91     private Transport mTransport = new Transport();
     92 
     93     /**
     94      * Construct a ContentProvider instance.  Content providers must be
     95      * <a href="{@docRoot}guide/topics/manifest/provider-element.html">declared
     96      * in the manifest</a>, accessed with {@link ContentResolver}, and created
     97      * automatically by the system, so applications usually do not create
     98      * ContentProvider instances directly.
     99      *
    100      * <p>At construction time, the object is uninitialized, and most fields and
    101      * methods are unavailable.  Subclasses should initialize themselves in
    102      * {@link #onCreate}, not the constructor.
    103      *
    104      * <p>Content providers are created on the application main thread at
    105      * application launch time.  The constructor must not perform lengthy
    106      * operations, or application startup will be delayed.
    107      */
    108     public ContentProvider() {
    109     }
    110 
    111     /**
    112      * Constructor just for mocking.
    113      *
    114      * @param context A Context object which should be some mock instance (like the
    115      * instance of {@link android.test.mock.MockContext}).
    116      * @param readPermission The read permision you want this instance should have in the
    117      * test, which is available via {@link #getReadPermission()}.
    118      * @param writePermission The write permission you want this instance should have
    119      * in the test, which is available via {@link #getWritePermission()}.
    120      * @param pathPermissions The PathPermissions you want this instance should have
    121      * in the test, which is available via {@link #getPathPermissions()}.
    122      * @hide
    123      */
    124     public ContentProvider(
    125             Context context,
    126             String readPermission,
    127             String writePermission,
    128             PathPermission[] pathPermissions) {
    129         mContext = context;
    130         mReadPermission = readPermission;
    131         mWritePermission = writePermission;
    132         mPathPermissions = pathPermissions;
    133     }
    134 
    135     /**
    136      * Given an IContentProvider, try to coerce it back to the real
    137      * ContentProvider object if it is running in the local process.  This can
    138      * be used if you know you are running in the same process as a provider,
    139      * and want to get direct access to its implementation details.  Most
    140      * clients should not nor have a reason to use it.
    141      *
    142      * @param abstractInterface The ContentProvider interface that is to be
    143      *              coerced.
    144      * @return If the IContentProvider is non-null and local, returns its actual
    145      * ContentProvider instance.  Otherwise returns null.
    146      * @hide
    147      */
    148     public static ContentProvider coerceToLocalContentProvider(
    149             IContentProvider abstractInterface) {
    150         if (abstractInterface instanceof Transport) {
    151             return ((Transport)abstractInterface).getContentProvider();
    152         }
    153         return null;
    154     }
    155 
    156     /**
    157      * Binder object that deals with remoting.
    158      *
    159      * @hide
    160      */
    161     class Transport extends ContentProviderNative {
    162         ContentProvider getContentProvider() {
    163             return ContentProvider.this;
    164         }
    165 
    166         /**
    167          * Remote version of a query, which returns an IBulkCursor. The bulk
    168          * cursor should be wrapped with BulkCursorToCursorAdaptor before use.
    169          */
    170         public IBulkCursor bulkQuery(Uri uri, String[] projection,
    171                 String selection, String[] selectionArgs, String sortOrder,
    172                 IContentObserver observer, CursorWindow window) {
    173             enforceReadPermission(uri);
    174             Cursor cursor = ContentProvider.this.query(uri, projection,
    175                     selection, selectionArgs, sortOrder);
    176             if (cursor == null) {
    177                 return null;
    178             }
    179             return new CursorToBulkCursorAdaptor(cursor, observer,
    180                     ContentProvider.this.getClass().getName(),
    181                     hasWritePermission(uri), window);
    182         }
    183 
    184         public Cursor query(Uri uri, String[] projection,
    185                 String selection, String[] selectionArgs, String sortOrder) {
    186             enforceReadPermission(uri);
    187             return ContentProvider.this.query(uri, projection, selection,
    188                     selectionArgs, sortOrder);
    189         }
    190 
    191         public String getType(Uri uri) {
    192             return ContentProvider.this.getType(uri);
    193         }
    194 
    195 
    196         public Uri insert(Uri uri, ContentValues initialValues) {
    197             enforceWritePermission(uri);
    198             return ContentProvider.this.insert(uri, initialValues);
    199         }
    200 
    201         public int bulkInsert(Uri uri, ContentValues[] initialValues) {
    202             enforceWritePermission(uri);
    203             return ContentProvider.this.bulkInsert(uri, initialValues);
    204         }
    205 
    206         public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
    207                 throws OperationApplicationException {
    208             for (ContentProviderOperation operation : operations) {
    209                 if (operation.isReadOperation()) {
    210                     enforceReadPermission(operation.getUri());
    211                 }
    212 
    213                 if (operation.isWriteOperation()) {
    214                     enforceWritePermission(operation.getUri());
    215                 }
    216             }
    217             return ContentProvider.this.applyBatch(operations);
    218         }
    219 
    220         public int delete(Uri uri, String selection, String[] selectionArgs) {
    221             enforceWritePermission(uri);
    222             return ContentProvider.this.delete(uri, selection, selectionArgs);
    223         }
    224 
    225         public int update(Uri uri, ContentValues values, String selection,
    226                 String[] selectionArgs) {
    227             enforceWritePermission(uri);
    228             return ContentProvider.this.update(uri, values, selection, selectionArgs);
    229         }
    230 
    231         public ParcelFileDescriptor openFile(Uri uri, String mode)
    232                 throws FileNotFoundException {
    233             if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
    234             else enforceReadPermission(uri);
    235             return ContentProvider.this.openFile(uri, mode);
    236         }
    237 
    238         public AssetFileDescriptor openAssetFile(Uri uri, String mode)
    239                 throws FileNotFoundException {
    240             if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
    241             else enforceReadPermission(uri);
    242             return ContentProvider.this.openAssetFile(uri, mode);
    243         }
    244 
    245         /**
    246          * @hide
    247          */
    248         public Bundle call(String method, String request, Bundle args) {
    249             return ContentProvider.this.call(method, request, args);
    250         }
    251 
    252         private void enforceReadPermission(Uri uri) {
    253             final int uid = Binder.getCallingUid();
    254             if (uid == mMyUid) {
    255                 return;
    256             }
    257 
    258             final Context context = getContext();
    259             final String rperm = getReadPermission();
    260             final int pid = Binder.getCallingPid();
    261             if (mExported && (rperm == null
    262                     || context.checkPermission(rperm, pid, uid)
    263                     == PackageManager.PERMISSION_GRANTED)) {
    264                 return;
    265             }
    266 
    267             PathPermission[] pps = getPathPermissions();
    268             if (pps != null) {
    269                 final String path = uri.getPath();
    270                 int i = pps.length;
    271                 while (i > 0) {
    272                     i--;
    273                     final PathPermission pp = pps[i];
    274                     final String pprperm = pp.getReadPermission();
    275                     if (pprperm != null && pp.match(path)) {
    276                         if (context.checkPermission(pprperm, pid, uid)
    277                                 == PackageManager.PERMISSION_GRANTED) {
    278                             return;
    279                         }
    280                     }
    281                 }
    282             }
    283 
    284             if (context.checkUriPermission(uri, pid, uid,
    285                     Intent.FLAG_GRANT_READ_URI_PERMISSION)
    286                     == PackageManager.PERMISSION_GRANTED) {
    287                 return;
    288             }
    289 
    290             String msg = "Permission Denial: reading "
    291                     + ContentProvider.this.getClass().getName()
    292                     + " uri " + uri + " from pid=" + Binder.getCallingPid()
    293                     + ", uid=" + Binder.getCallingUid()
    294                     + " requires " + rperm;
    295             throw new SecurityException(msg);
    296         }
    297 
    298         private boolean hasWritePermission(Uri uri) {
    299             final int uid = Binder.getCallingUid();
    300             if (uid == mMyUid) {
    301                 return true;
    302             }
    303 
    304             final Context context = getContext();
    305             final String wperm = getWritePermission();
    306             final int pid = Binder.getCallingPid();
    307             if (mExported && (wperm == null
    308                     || context.checkPermission(wperm, pid, uid)
    309                     == PackageManager.PERMISSION_GRANTED)) {
    310                 return true;
    311             }
    312 
    313             PathPermission[] pps = getPathPermissions();
    314             if (pps != null) {
    315                 final String path = uri.getPath();
    316                 int i = pps.length;
    317                 while (i > 0) {
    318                     i--;
    319                     final PathPermission pp = pps[i];
    320                     final String ppwperm = pp.getWritePermission();
    321                     if (ppwperm != null && pp.match(path)) {
    322                         if (context.checkPermission(ppwperm, pid, uid)
    323                                 == PackageManager.PERMISSION_GRANTED) {
    324                             return true;
    325                         }
    326                     }
    327                 }
    328             }
    329 
    330             if (context.checkUriPermission(uri, pid, uid,
    331                     Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
    332                     == PackageManager.PERMISSION_GRANTED) {
    333                 return true;
    334             }
    335 
    336             return false;
    337         }
    338 
    339         private void enforceWritePermission(Uri uri) {
    340             if (hasWritePermission(uri)) {
    341                 return;
    342             }
    343 
    344             String msg = "Permission Denial: writing "
    345                     + ContentProvider.this.getClass().getName()
    346                     + " uri " + uri + " from pid=" + Binder.getCallingPid()
    347                     + ", uid=" + Binder.getCallingUid()
    348                     + " requires " + getWritePermission();
    349             throw new SecurityException(msg);
    350         }
    351     }
    352 
    353 
    354     /**
    355      * Retrieves the Context this provider is running in.  Only available once
    356      * {@link #onCreate} has been called -- this will return null in the
    357      * constructor.
    358      */
    359     public final Context getContext() {
    360         return mContext;
    361     }
    362 
    363     /**
    364      * Change the permission required to read data from the content
    365      * provider.  This is normally set for you from its manifest information
    366      * when the provider is first created.
    367      *
    368      * @param permission Name of the permission required for read-only access.
    369      */
    370     protected final void setReadPermission(String permission) {
    371         mReadPermission = permission;
    372     }
    373 
    374     /**
    375      * Return the name of the permission required for read-only access to
    376      * this content provider.  This method can be called from multiple
    377      * threads, as described in
    378      * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
    379      * Processes and Threads</a>.
    380      */
    381     public final String getReadPermission() {
    382         return mReadPermission;
    383     }
    384 
    385     /**
    386      * Change the permission required to read and write data in the content
    387      * provider.  This is normally set for you from its manifest information
    388      * when the provider is first created.
    389      *
    390      * @param permission Name of the permission required for read/write access.
    391      */
    392     protected final void setWritePermission(String permission) {
    393         mWritePermission = permission;
    394     }
    395 
    396     /**
    397      * Return the name of the permission required for read/write access to
    398      * this content provider.  This method can be called from multiple
    399      * threads, as described in
    400      * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
    401      * Processes and Threads</a>.
    402      */
    403     public final String getWritePermission() {
    404         return mWritePermission;
    405     }
    406 
    407     /**
    408      * Change the path-based permission required to read and/or write data in
    409      * the content provider.  This is normally set for you from its manifest
    410      * information when the provider is first created.
    411      *
    412      * @param permissions Array of path permission descriptions.
    413      */
    414     protected final void setPathPermissions(PathPermission[] permissions) {
    415         mPathPermissions = permissions;
    416     }
    417 
    418     /**
    419      * Return the path-based permissions required for read and/or write access to
    420      * this content provider.  This method can be called from multiple
    421      * threads, as described in
    422      * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
    423      * Processes and Threads</a>.
    424      */
    425     public final PathPermission[] getPathPermissions() {
    426         return mPathPermissions;
    427     }
    428 
    429     /**
    430      * Implement this to initialize your content provider on startup.
    431      * This method is called for all registered content providers on the
    432      * application main thread at application launch time.  It must not perform
    433      * lengthy operations, or application startup will be delayed.
    434      *
    435      * <p>You should defer nontrivial initialization (such as opening,
    436      * upgrading, and scanning databases) until the content provider is used
    437      * (via {@link #query}, {@link #insert}, etc).  Deferred initialization
    438      * keeps application startup fast, avoids unnecessary work if the provider
    439      * turns out not to be needed, and stops database errors (such as a full
    440      * disk) from halting application launch.
    441      *
    442      * <p>If you use SQLite, {@link android.database.sqlite.SQLiteOpenHelper}
    443      * is a helpful utility class that makes it easy to manage databases,
    444      * and will automatically defer opening until first use.  If you do use
    445      * SQLiteOpenHelper, make sure to avoid calling
    446      * {@link android.database.sqlite.SQLiteOpenHelper#getReadableDatabase} or
    447      * {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase}
    448      * from this method.  (Instead, override
    449      * {@link android.database.sqlite.SQLiteOpenHelper#onOpen} to initialize the
    450      * database when it is first opened.)
    451      *
    452      * @return true if the provider was successfully loaded, false otherwise
    453      */
    454     public abstract boolean onCreate();
    455 
    456     /**
    457      * {@inheritDoc}
    458      * This method is always called on the application main thread, and must
    459      * not perform lengthy operations.
    460      *
    461      * <p>The default content provider implementation does nothing.
    462      * Override this method to take appropriate action.
    463      * (Content providers do not usually care about things like screen
    464      * orientation, but may want to know about locale changes.)
    465      */
    466     public void onConfigurationChanged(Configuration newConfig) {
    467     }
    468 
    469     /**
    470      * {@inheritDoc}
    471      * This method is always called on the application main thread, and must
    472      * not perform lengthy operations.
    473      *
    474      * <p>The default content provider implementation does nothing.
    475      * Subclasses may override this method to take appropriate action.
    476      */
    477     public void onLowMemory() {
    478     }
    479 
    480     /**
    481      * Implement this to handle query requests from clients.
    482      * This method can be called from multiple threads, as described in
    483      * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
    484      * Processes and Threads</a>.
    485      * <p>
    486      * Example client call:<p>
    487      * <pre>// Request a specific record.
    488      * Cursor managedCursor = managedQuery(
    489                 ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2),
    490                 projection,    // Which columns to return.
    491                 null,          // WHERE clause.
    492                 null,          // WHERE clause value substitution
    493                 People.NAME + " ASC");   // Sort order.</pre>
    494      * Example implementation:<p>
    495      * <pre>// SQLiteQueryBuilder is a helper class that creates the
    496         // proper SQL syntax for us.
    497         SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
    498 
    499         // Set the table we're querying.
    500         qBuilder.setTables(DATABASE_TABLE_NAME);
    501 
    502         // If the query ends in a specific record number, we're
    503         // being asked for a specific record, so set the
    504         // WHERE clause in our query.
    505         if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){
    506             qBuilder.appendWhere("_id=" + uri.getPathLeafId());
    507         }
    508 
    509         // Make the query.
    510         Cursor c = qBuilder.query(mDb,
    511                 projection,
    512                 selection,
    513                 selectionArgs,
    514                 groupBy,
    515                 having,
    516                 sortOrder);
    517         c.setNotificationUri(getContext().getContentResolver(), uri);
    518         return c;</pre>
    519      *
    520      * @param uri The URI to query. This will be the full URI sent by the client;
    521      *      if the client is requesting a specific record, the URI will end in a record number
    522      *      that the implementation should parse and add to a WHERE or HAVING clause, specifying
    523      *      that _id value.
    524      * @param projection The list of columns to put into the cursor. If
    525      *      null all columns are included.
    526      * @param selection A selection criteria to apply when filtering rows.
    527      *      If null then all rows are included.
    528      * @param selectionArgs You may include ?s in selection, which will be replaced by
    529      *      the values from selectionArgs, in order that they appear in the selection.
    530      *      The values will be bound as Strings.
    531      * @param sortOrder How the rows in the cursor should be sorted.
    532      *      If null then the provider is free to define the sort order.
    533      * @return a Cursor or null.
    534      */
    535     public abstract Cursor query(Uri uri, String[] projection,
    536             String selection, String[] selectionArgs, String sortOrder);
    537 
    538     /**
    539      * Implement this to handle requests for the MIME type of the data at the
    540      * given URI.  The returned MIME type should start with
    541      * <code>vnd.android.cursor.item</code> for a single record,
    542      * or <code>vnd.android.cursor.dir/</code> for multiple items.
    543      * This method can be called from multiple threads, as described in
    544      * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
    545      * Processes and Threads</a>.
    546      *
    547      * <p>Note that there are no permissions needed for an application to
    548      * access this information; if your content provider requires read and/or
    549      * write permissions, or is not exported, all applications can still call
    550      * this method regardless of their access permissions.  This allows them
    551      * to retrieve the MIME type for a URI when dispatching intents.
    552      *
    553      * @param uri the URI to query.
    554      * @return a MIME type string, or null if there is no type.
    555      */
    556     public abstract String getType(Uri uri);
    557 
    558     /**
    559      * Implement this to handle requests to insert a new row.
    560      * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
    561      * after inserting.
    562      * This method can be called from multiple threads, as described in
    563      * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
    564      * Processes and Threads</a>.
    565      * @param uri The content:// URI of the insertion request.
    566      * @param values A set of column_name/value pairs to add to the database.
    567      * @return The URI for the newly inserted item.
    568      */
    569     public abstract Uri insert(Uri uri, ContentValues values);
    570 
    571     /**
    572      * Override this to handle requests to insert a set of new rows, or the
    573      * default implementation will iterate over the values and call
    574      * {@link #insert} on each of them.
    575      * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
    576      * after inserting.
    577      * This method can be called from multiple threads, as described in
    578      * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
    579      * Processes and Threads</a>.
    580      *
    581      * @param uri The content:// URI of the insertion request.
    582      * @param values An array of sets of column_name/value pairs to add to the database.
    583      * @return The number of values that were inserted.
    584      */
    585     public int bulkInsert(Uri uri, ContentValues[] values) {
    586         int numValues = values.length;
    587         for (int i = 0; i < numValues; i++) {
    588             insert(uri, values[i]);
    589         }
    590         return numValues;
    591     }
    592 
    593     /**
    594      * Implement this to handle requests to delete one or more rows.
    595      * The implementation should apply the selection clause when performing
    596      * deletion, allowing the operation to affect multiple rows in a directory.
    597      * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyDelete()}
    598      * after deleting.
    599      * This method can be called from multiple threads, as described in
    600      * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
    601      * Processes and Threads</a>.
    602      *
    603      * <p>The implementation is responsible for parsing out a row ID at the end
    604      * of the URI, if a specific row is being deleted. That is, the client would
    605      * pass in <code>content://contacts/people/22</code> and the implementation is
    606      * responsible for parsing the record number (22) when creating a SQL statement.
    607      *
    608      * @param uri The full URI to query, including a row ID (if a specific record is requested).
    609      * @param selection An optional restriction to apply to rows when deleting.
    610      * @return The number of rows affected.
    611      * @throws SQLException
    612      */
    613     public abstract int delete(Uri uri, String selection, String[] selectionArgs);
    614 
    615     /**
    616      * Implement this to handle requests to update one or more rows.
    617      * The implementation should update all rows matching the selection
    618      * to set the columns according to the provided values map.
    619      * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
    620      * after updating.
    621      * This method can be called from multiple threads, as described in
    622      * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
    623      * Processes and Threads</a>.
    624      *
    625      * @param uri The URI to query. This can potentially have a record ID if this
    626      * is an update request for a specific record.
    627      * @param values A Bundle mapping from column names to new column values (NULL is a
    628      *               valid value).
    629      * @param selection An optional filter to match rows to update.
    630      * @return the number of rows affected.
    631      */
    632     public abstract int update(Uri uri, ContentValues values, String selection,
    633             String[] selectionArgs);
    634 
    635     /**
    636      * Override this to handle requests to open a file blob.
    637      * The default implementation always throws {@link FileNotFoundException}.
    638      * This method can be called from multiple threads, as described in
    639      * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
    640      * Processes and Threads</a>.
    641      *
    642      * <p>This method returns a ParcelFileDescriptor, which is returned directly
    643      * to the caller.  This way large data (such as images and documents) can be
    644      * returned without copying the content.
    645      *
    646      * <p>The returned ParcelFileDescriptor is owned by the caller, so it is
    647      * their responsibility to close it when done.  That is, the implementation
    648      * of this method should create a new ParcelFileDescriptor for each call.
    649      *
    650      * @param uri The URI whose file is to be opened.
    651      * @param mode Access mode for the file.  May be "r" for read-only access,
    652      * "rw" for read and write access, or "rwt" for read and write access
    653      * that truncates any existing file.
    654      *
    655      * @return Returns a new ParcelFileDescriptor which you can use to access
    656      * the file.
    657      *
    658      * @throws FileNotFoundException Throws FileNotFoundException if there is
    659      * no file associated with the given URI or the mode is invalid.
    660      * @throws SecurityException Throws SecurityException if the caller does
    661      * not have permission to access the file.
    662      *
    663      * @see #openAssetFile(Uri, String)
    664      * @see #openFileHelper(Uri, String)
    665      */
    666     public ParcelFileDescriptor openFile(Uri uri, String mode)
    667             throws FileNotFoundException {
    668         throw new FileNotFoundException("No files supported by provider at "
    669                 + uri);
    670     }
    671 
    672     /**
    673      * This is like {@link #openFile}, but can be implemented by providers
    674      * that need to be able to return sub-sections of files, often assets
    675      * inside of their .apk.
    676      * This method can be called from multiple threads, as described in
    677      * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
    678      * Processes and Threads</a>.
    679      *
    680      * <p>If you implement this, your clients must be able to deal with such
    681      * file slices, either directly with
    682      * {@link ContentResolver#openAssetFileDescriptor}, or by using the higher-level
    683      * {@link ContentResolver#openInputStream ContentResolver.openInputStream}
    684      * or {@link ContentResolver#openOutputStream ContentResolver.openOutputStream}
    685      * methods.
    686      *
    687      * <p class="note">If you are implementing this to return a full file, you
    688      * should create the AssetFileDescriptor with
    689      * {@link AssetFileDescriptor#UNKNOWN_LENGTH} to be compatible with
    690      * applications that can not handle sub-sections of files.</p>
    691      *
    692      * @param uri The URI whose file is to be opened.
    693      * @param mode Access mode for the file.  May be "r" for read-only access,
    694      * "w" for write-only access (erasing whatever data is currently in
    695      * the file), "wa" for write-only access to append to any existing data,
    696      * "rw" for read and write access on any existing data, and "rwt" for read
    697      * and write access that truncates any existing file.
    698      *
    699      * @return Returns a new AssetFileDescriptor which you can use to access
    700      * the file.
    701      *
    702      * @throws FileNotFoundException Throws FileNotFoundException if there is
    703      * no file associated with the given URI or the mode is invalid.
    704      * @throws SecurityException Throws SecurityException if the caller does
    705      * not have permission to access the file.
    706      *
    707      * @see #openFile(Uri, String)
    708      * @see #openFileHelper(Uri, String)
    709      */
    710     public AssetFileDescriptor openAssetFile(Uri uri, String mode)
    711             throws FileNotFoundException {
    712         ParcelFileDescriptor fd = openFile(uri, mode);
    713         return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null;
    714     }
    715 
    716     /**
    717      * Convenience for subclasses that wish to implement {@link #openFile}
    718      * by looking up a column named "_data" at the given URI.
    719      *
    720      * @param uri The URI to be opened.
    721      * @param mode The file mode.  May be "r" for read-only access,
    722      * "w" for write-only access (erasing whatever data is currently in
    723      * the file), "wa" for write-only access to append to any existing data,
    724      * "rw" for read and write access on any existing data, and "rwt" for read
    725      * and write access that truncates any existing file.
    726      *
    727      * @return Returns a new ParcelFileDescriptor that can be used by the
    728      * client to access the file.
    729      */
    730     protected final ParcelFileDescriptor openFileHelper(Uri uri,
    731             String mode) throws FileNotFoundException {
    732         Cursor c = query(uri, new String[]{"_data"}, null, null, null);
    733         int count = (c != null) ? c.getCount() : 0;
    734         if (count != 1) {
    735             // If there is not exactly one result, throw an appropriate
    736             // exception.
    737             if (c != null) {
    738                 c.close();
    739             }
    740             if (count == 0) {
    741                 throw new FileNotFoundException("No entry for " + uri);
    742             }
    743             throw new FileNotFoundException("Multiple items at " + uri);
    744         }
    745 
    746         c.moveToFirst();
    747         int i = c.getColumnIndex("_data");
    748         String path = (i >= 0 ? c.getString(i) : null);
    749         c.close();
    750         if (path == null) {
    751             throw new FileNotFoundException("Column _data not found.");
    752         }
    753 
    754         int modeBits = ContentResolver.modeToMode(uri, mode);
    755         return ParcelFileDescriptor.open(new File(path), modeBits);
    756     }
    757 
    758     /**
    759      * Returns true if this instance is a temporary content provider.
    760      * @return true if this instance is a temporary content provider
    761      */
    762     protected boolean isTemporary() {
    763         return false;
    764     }
    765 
    766     /**
    767      * Returns the Binder object for this provider.
    768      *
    769      * @return the Binder object for this provider
    770      * @hide
    771      */
    772     public IContentProvider getIContentProvider() {
    773         return mTransport;
    774     }
    775 
    776     /**
    777      * After being instantiated, this is called to tell the content provider
    778      * about itself.
    779      *
    780      * @param context The context this provider is running in
    781      * @param info Registered information about this content provider
    782      */
    783     public void attachInfo(Context context, ProviderInfo info) {
    784 
    785         /*
    786          * Only allow it to be set once, so after the content service gives
    787          * this to us clients can't change it.
    788          */
    789         if (mContext == null) {
    790             mContext = context;
    791             mMyUid = Process.myUid();
    792             if (info != null) {
    793                 setReadPermission(info.readPermission);
    794                 setWritePermission(info.writePermission);
    795                 setPathPermissions(info.pathPermissions);
    796                 mExported = info.exported;
    797             }
    798             ContentProvider.this.onCreate();
    799         }
    800     }
    801 
    802     /**
    803      * Override this to handle requests to perform a batch of operations, or the
    804      * default implementation will iterate over the operations and call
    805      * {@link ContentProviderOperation#apply} on each of them.
    806      * If all calls to {@link ContentProviderOperation#apply} succeed
    807      * then a {@link ContentProviderResult} array with as many
    808      * elements as there were operations will be returned.  If any of the calls
    809      * fail, it is up to the implementation how many of the others take effect.
    810      * This method can be called from multiple threads, as described in
    811      * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
    812      * Processes and Threads</a>.
    813      *
    814      * @param operations the operations to apply
    815      * @return the results of the applications
    816      * @throws OperationApplicationException thrown if any operation fails.
    817      * @see ContentProviderOperation#apply
    818      */
    819     public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
    820             throws OperationApplicationException {
    821         final int numOperations = operations.size();
    822         final ContentProviderResult[] results = new ContentProviderResult[numOperations];
    823         for (int i = 0; i < numOperations; i++) {
    824             results[i] = operations.get(i).apply(this, results, i);
    825         }
    826         return results;
    827     }
    828 
    829     /**
    830      * @hide -- until interface has proven itself
    831      *
    832      * Call an provider-defined method.  This can be used to implement
    833      * interfaces that are cheaper than using a Cursor.
    834      *
    835      * @param method Method name to call.  Opaque to framework.
    836      * @param request Nullable String argument passed to method.
    837      * @param args Nullable Bundle argument passed to method.
    838      */
    839     public Bundle call(String method, String request, Bundle args) {
    840         return null;
    841     }
    842 }
    843