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 static android.content.pm.PackageManager.GET_PROVIDERS;
     20 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
     21 
     22 import android.app.AppOpsManager;
     23 import android.content.pm.PackageManager;
     24 import android.content.pm.PathPermission;
     25 import android.content.pm.ProviderInfo;
     26 import android.content.res.AssetFileDescriptor;
     27 import android.content.res.Configuration;
     28 import android.database.Cursor;
     29 import android.database.SQLException;
     30 import android.net.Uri;
     31 import android.os.AsyncTask;
     32 import android.os.Binder;
     33 import android.os.Bundle;
     34 import android.os.CancellationSignal;
     35 import android.os.ICancellationSignal;
     36 import android.os.OperationCanceledException;
     37 import android.os.ParcelFileDescriptor;
     38 import android.os.Process;
     39 import android.os.RemoteException;
     40 import android.os.UserHandle;
     41 import android.util.Log;
     42 
     43 import java.io.File;
     44 import java.io.FileDescriptor;
     45 import java.io.FileNotFoundException;
     46 import java.io.IOException;
     47 import java.io.PrintWriter;
     48 import java.util.ArrayList;
     49 
     50 /**
     51  * Content providers are one of the primary building blocks of Android applications, providing
     52  * content to applications. They encapsulate data and provide it to applications through the single
     53  * {@link ContentResolver} interface. A content provider is only required if you need to share
     54  * data between multiple applications. For example, the contacts data is used by multiple
     55  * applications and must be stored in a content provider. If you don't need to share data amongst
     56  * multiple applications you can use a database directly via
     57  * {@link android.database.sqlite.SQLiteDatabase}.
     58  *
     59  * <p>When a request is made via
     60  * a {@link ContentResolver} the system inspects the authority of the given URI and passes the
     61  * request to the content provider registered with the authority. The content provider can interpret
     62  * the rest of the URI however it wants. The {@link UriMatcher} class is helpful for parsing
     63  * URIs.</p>
     64  *
     65  * <p>The primary methods that need to be implemented are:
     66  * <ul>
     67  *   <li>{@link #onCreate} which is called to initialize the provider</li>
     68  *   <li>{@link #query} which returns data to the caller</li>
     69  *   <li>{@link #insert} which inserts new data into the content provider</li>
     70  *   <li>{@link #update} which updates existing data in the content provider</li>
     71  *   <li>{@link #delete} which deletes data from the content provider</li>
     72  *   <li>{@link #getType} which returns the MIME type of data in the content provider</li>
     73  * </ul></p>
     74  *
     75  * <p class="caution">Data access methods (such as {@link #insert} and
     76  * {@link #update}) may be called from many threads at once, and must be thread-safe.
     77  * Other methods (such as {@link #onCreate}) are only called from the application
     78  * main thread, and must avoid performing lengthy operations.  See the method
     79  * descriptions for their expected thread behavior.</p>
     80  *
     81  * <p>Requests to {@link ContentResolver} are automatically forwarded to the appropriate
     82  * ContentProvider instance, so subclasses don't have to worry about the details of
     83  * cross-process calls.</p>
     84  *
     85  * <div class="special reference">
     86  * <h3>Developer Guides</h3>
     87  * <p>For more information about using content providers, read the
     88  * <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
     89  * developer guide.</p>
     90  */
     91 public abstract class ContentProvider implements ComponentCallbacks2 {
     92     private static final String TAG = "ContentProvider";
     93 
     94     /*
     95      * Note: if you add methods to ContentProvider, you must add similar methods to
     96      *       MockContentProvider.
     97      */
     98 
     99     private Context mContext = null;
    100     private int mMyUid;
    101     private String mReadPermission;
    102     private String mWritePermission;
    103     private PathPermission[] mPathPermissions;
    104     private boolean mExported;
    105     private boolean mNoPerms;
    106 
    107     private Transport mTransport = new Transport();
    108 
    109     /**
    110      * Construct a ContentProvider instance.  Content providers must be
    111      * <a href="{@docRoot}guide/topics/manifest/provider-element.html">declared
    112      * in the manifest</a>, accessed with {@link ContentResolver}, and created
    113      * automatically by the system, so applications usually do not create
    114      * ContentProvider instances directly.
    115      *
    116      * <p>At construction time, the object is uninitialized, and most fields and
    117      * methods are unavailable.  Subclasses should initialize themselves in
    118      * {@link #onCreate}, not the constructor.
    119      *
    120      * <p>Content providers are created on the application main thread at
    121      * application launch time.  The constructor must not perform lengthy
    122      * operations, or application startup will be delayed.
    123      */
    124     public ContentProvider() {
    125     }
    126 
    127     /**
    128      * Constructor just for mocking.
    129      *
    130      * @param context A Context object which should be some mock instance (like the
    131      * instance of {@link android.test.mock.MockContext}).
    132      * @param readPermission The read permision you want this instance should have in the
    133      * test, which is available via {@link #getReadPermission()}.
    134      * @param writePermission The write permission you want this instance should have
    135      * in the test, which is available via {@link #getWritePermission()}.
    136      * @param pathPermissions The PathPermissions you want this instance should have
    137      * in the test, which is available via {@link #getPathPermissions()}.
    138      * @hide
    139      */
    140     public ContentProvider(
    141             Context context,
    142             String readPermission,
    143             String writePermission,
    144             PathPermission[] pathPermissions) {
    145         mContext = context;
    146         mReadPermission = readPermission;
    147         mWritePermission = writePermission;
    148         mPathPermissions = pathPermissions;
    149     }
    150 
    151     /**
    152      * Given an IContentProvider, try to coerce it back to the real
    153      * ContentProvider object if it is running in the local process.  This can
    154      * be used if you know you are running in the same process as a provider,
    155      * and want to get direct access to its implementation details.  Most
    156      * clients should not nor have a reason to use it.
    157      *
    158      * @param abstractInterface The ContentProvider interface that is to be
    159      *              coerced.
    160      * @return If the IContentProvider is non-{@code null} and local, returns its actual
    161      * ContentProvider instance.  Otherwise returns {@code null}.
    162      * @hide
    163      */
    164     public static ContentProvider coerceToLocalContentProvider(
    165             IContentProvider abstractInterface) {
    166         if (abstractInterface instanceof Transport) {
    167             return ((Transport)abstractInterface).getContentProvider();
    168         }
    169         return null;
    170     }
    171 
    172     /**
    173      * Binder object that deals with remoting.
    174      *
    175      * @hide
    176      */
    177     class Transport extends ContentProviderNative {
    178         AppOpsManager mAppOpsManager = null;
    179         int mReadOp = AppOpsManager.OP_NONE;
    180         int mWriteOp = AppOpsManager.OP_NONE;
    181 
    182         ContentProvider getContentProvider() {
    183             return ContentProvider.this;
    184         }
    185 
    186         @Override
    187         public String getProviderName() {
    188             return getContentProvider().getClass().getName();
    189         }
    190 
    191         @Override
    192         public Cursor query(String callingPkg, Uri uri, String[] projection,
    193                 String selection, String[] selectionArgs, String sortOrder,
    194                 ICancellationSignal cancellationSignal) {
    195             if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
    196                 return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
    197                         CancellationSignal.fromTransport(cancellationSignal));
    198             }
    199             return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder,
    200                     CancellationSignal.fromTransport(cancellationSignal));
    201         }
    202 
    203         @Override
    204         public String getType(Uri uri) {
    205             return ContentProvider.this.getType(uri);
    206         }
    207 
    208         @Override
    209         public Uri insert(String callingPkg, Uri uri, ContentValues initialValues) {
    210             if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
    211                 return rejectInsert(uri, initialValues);
    212             }
    213             return ContentProvider.this.insert(uri, initialValues);
    214         }
    215 
    216         @Override
    217         public int bulkInsert(String callingPkg, Uri uri, ContentValues[] initialValues) {
    218             if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
    219                 return 0;
    220             }
    221             return ContentProvider.this.bulkInsert(uri, initialValues);
    222         }
    223 
    224         @Override
    225         public ContentProviderResult[] applyBatch(String callingPkg,
    226                 ArrayList<ContentProviderOperation> operations)
    227                 throws OperationApplicationException {
    228             for (ContentProviderOperation operation : operations) {
    229                 if (operation.isReadOperation()) {
    230                     if (enforceReadPermission(callingPkg, operation.getUri())
    231                             != AppOpsManager.MODE_ALLOWED) {
    232                         throw new OperationApplicationException("App op not allowed", 0);
    233                     }
    234                 }
    235 
    236                 if (operation.isWriteOperation()) {
    237                     if (enforceWritePermission(callingPkg, operation.getUri())
    238                             != AppOpsManager.MODE_ALLOWED) {
    239                         throw new OperationApplicationException("App op not allowed", 0);
    240                     }
    241                 }
    242             }
    243             return ContentProvider.this.applyBatch(operations);
    244         }
    245 
    246         @Override
    247         public int delete(String callingPkg, Uri uri, String selection, String[] selectionArgs) {
    248             if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
    249                 return 0;
    250             }
    251             return ContentProvider.this.delete(uri, selection, selectionArgs);
    252         }
    253 
    254         @Override
    255         public int update(String callingPkg, Uri uri, ContentValues values, String selection,
    256                 String[] selectionArgs) {
    257             if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
    258                 return 0;
    259             }
    260             return ContentProvider.this.update(uri, values, selection, selectionArgs);
    261         }
    262 
    263         @Override
    264         public ParcelFileDescriptor openFile(String callingPkg, Uri uri, String mode)
    265                 throws FileNotFoundException {
    266             enforceFilePermission(callingPkg, uri, mode);
    267             return ContentProvider.this.openFile(uri, mode);
    268         }
    269 
    270         @Override
    271         public AssetFileDescriptor openAssetFile(String callingPkg, Uri uri, String mode)
    272                 throws FileNotFoundException {
    273             enforceFilePermission(callingPkg, uri, mode);
    274             return ContentProvider.this.openAssetFile(uri, mode);
    275         }
    276 
    277         @Override
    278         public Bundle call(String callingPkg, String method, String arg, Bundle extras) {
    279             return ContentProvider.this.callFromPackage(callingPkg, method, arg, extras);
    280         }
    281 
    282         @Override
    283         public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
    284             return ContentProvider.this.getStreamTypes(uri, mimeTypeFilter);
    285         }
    286 
    287         @Override
    288         public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
    289                 Bundle opts) throws FileNotFoundException {
    290             enforceFilePermission(callingPkg, uri, "r");
    291             return ContentProvider.this.openTypedAssetFile(uri, mimeType, opts);
    292         }
    293 
    294         @Override
    295         public ICancellationSignal createCancellationSignal() throws RemoteException {
    296             return CancellationSignal.createTransport();
    297         }
    298 
    299         private void enforceFilePermission(String callingPkg, Uri uri, String mode)
    300                 throws FileNotFoundException, SecurityException {
    301             if (mode != null && mode.indexOf('w') != -1) {
    302                 if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
    303                     throw new FileNotFoundException("App op not allowed");
    304                 }
    305             } else {
    306                 if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
    307                     throw new FileNotFoundException("App op not allowed");
    308                 }
    309             }
    310         }
    311 
    312         private int enforceReadPermission(String callingPkg, Uri uri) throws SecurityException {
    313             enforceReadPermissionInner(uri);
    314             if (mReadOp != AppOpsManager.OP_NONE) {
    315                 return mAppOpsManager.noteOp(mReadOp, Binder.getCallingUid(), callingPkg);
    316             }
    317             return AppOpsManager.MODE_ALLOWED;
    318         }
    319 
    320         private void enforceReadPermissionInner(Uri uri) throws SecurityException {
    321             final Context context = getContext();
    322             final int pid = Binder.getCallingPid();
    323             final int uid = Binder.getCallingUid();
    324             String missingPerm = null;
    325 
    326             if (UserHandle.isSameApp(uid, mMyUid)) {
    327                 return;
    328             }
    329 
    330             if (mExported) {
    331                 final String componentPerm = getReadPermission();
    332                 if (componentPerm != null) {
    333                     if (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED) {
    334                         return;
    335                     } else {
    336                         missingPerm = componentPerm;
    337                     }
    338                 }
    339 
    340                 // track if unprotected read is allowed; any denied
    341                 // <path-permission> below removes this ability
    342                 boolean allowDefaultRead = (componentPerm == null);
    343 
    344                 final PathPermission[] pps = getPathPermissions();
    345                 if (pps != null) {
    346                     final String path = uri.getPath();
    347                     for (PathPermission pp : pps) {
    348                         final String pathPerm = pp.getReadPermission();
    349                         if (pathPerm != null && pp.match(path)) {
    350                             if (context.checkPermission(pathPerm, pid, uid) == PERMISSION_GRANTED) {
    351                                 return;
    352                             } else {
    353                                 // any denied <path-permission> means we lose
    354                                 // default <provider> access.
    355                                 allowDefaultRead = false;
    356                                 missingPerm = pathPerm;
    357                             }
    358                         }
    359                     }
    360                 }
    361 
    362                 // if we passed <path-permission> checks above, and no default
    363                 // <provider> permission, then allow access.
    364                 if (allowDefaultRead) return;
    365             }
    366 
    367             // last chance, check against any uri grants
    368             if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
    369                     == PERMISSION_GRANTED) {
    370                 return;
    371             }
    372 
    373             final String failReason = mExported
    374                     ? " requires " + missingPerm + ", or grantUriPermission()"
    375                     : " requires the provider be exported, or grantUriPermission()";
    376             throw new SecurityException("Permission Denial: reading "
    377                     + ContentProvider.this.getClass().getName() + " uri " + uri + " from pid=" + pid
    378                     + ", uid=" + uid + failReason);
    379         }
    380 
    381         private int enforceWritePermission(String callingPkg, Uri uri) throws SecurityException {
    382             enforceWritePermissionInner(uri);
    383             if (mWriteOp != AppOpsManager.OP_NONE) {
    384                 return mAppOpsManager.noteOp(mWriteOp, Binder.getCallingUid(), callingPkg);
    385             }
    386             return AppOpsManager.MODE_ALLOWED;
    387         }
    388 
    389         private void enforceWritePermissionInner(Uri uri) throws SecurityException {
    390             final Context context = getContext();
    391             final int pid = Binder.getCallingPid();
    392             final int uid = Binder.getCallingUid();
    393             String missingPerm = null;
    394 
    395             if (UserHandle.isSameApp(uid, mMyUid)) {
    396                 return;
    397             }
    398 
    399             if (mExported) {
    400                 final String componentPerm = getWritePermission();
    401                 if (componentPerm != null) {
    402                     if (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED) {
    403                         return;
    404                     } else {
    405                         missingPerm = componentPerm;
    406                     }
    407                 }
    408 
    409                 // track if unprotected write is allowed; any denied
    410                 // <path-permission> below removes this ability
    411                 boolean allowDefaultWrite = (componentPerm == null);
    412 
    413                 final PathPermission[] pps = getPathPermissions();
    414                 if (pps != null) {
    415                     final String path = uri.getPath();
    416                     for (PathPermission pp : pps) {
    417                         final String pathPerm = pp.getWritePermission();
    418                         if (pathPerm != null && pp.match(path)) {
    419                             if (context.checkPermission(pathPerm, pid, uid) == PERMISSION_GRANTED) {
    420                                 return;
    421                             } else {
    422                                 // any denied <path-permission> means we lose
    423                                 // default <provider> access.
    424                                 allowDefaultWrite = false;
    425                                 missingPerm = pathPerm;
    426                             }
    427                         }
    428                     }
    429                 }
    430 
    431                 // if we passed <path-permission> checks above, and no default
    432                 // <provider> permission, then allow access.
    433                 if (allowDefaultWrite) return;
    434             }
    435 
    436             // last chance, check against any uri grants
    437             if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
    438                     == PERMISSION_GRANTED) {
    439                 return;
    440             }
    441 
    442             final String failReason = mExported
    443                     ? " requires " + missingPerm + ", or grantUriPermission()"
    444                     : " requires the provider be exported, or grantUriPermission()";
    445             throw new SecurityException("Permission Denial: writing "
    446                     + ContentProvider.this.getClass().getName() + " uri " + uri + " from pid=" + pid
    447                     + ", uid=" + uid + failReason);
    448         }
    449     }
    450 
    451     /**
    452      * Retrieves the Context this provider is running in.  Only available once
    453      * {@link #onCreate} has been called -- this will return {@code null} in the
    454      * constructor.
    455      */
    456     public final Context getContext() {
    457         return mContext;
    458     }
    459 
    460     /**
    461      * Change the permission required to read data from the content
    462      * provider.  This is normally set for you from its manifest information
    463      * when the provider is first created.
    464      *
    465      * @param permission Name of the permission required for read-only access.
    466      */
    467     protected final void setReadPermission(String permission) {
    468         mReadPermission = permission;
    469     }
    470 
    471     /**
    472      * Return the name of the permission required for read-only access to
    473      * this content provider.  This method can be called from multiple
    474      * threads, as described in
    475      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
    476      * and Threads</a>.
    477      */
    478     public final String getReadPermission() {
    479         return mReadPermission;
    480     }
    481 
    482     /**
    483      * Change the permission required to read and write data in the content
    484      * provider.  This is normally set for you from its manifest information
    485      * when the provider is first created.
    486      *
    487      * @param permission Name of the permission required for read/write access.
    488      */
    489     protected final void setWritePermission(String permission) {
    490         mWritePermission = permission;
    491     }
    492 
    493     /**
    494      * Return the name of the permission required for read/write access to
    495      * this content provider.  This method can be called from multiple
    496      * threads, as described in
    497      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
    498      * and Threads</a>.
    499      */
    500     public final String getWritePermission() {
    501         return mWritePermission;
    502     }
    503 
    504     /**
    505      * Change the path-based permission required to read and/or write data in
    506      * the content provider.  This is normally set for you from its manifest
    507      * information when the provider is first created.
    508      *
    509      * @param permissions Array of path permission descriptions.
    510      */
    511     protected final void setPathPermissions(PathPermission[] permissions) {
    512         mPathPermissions = permissions;
    513     }
    514 
    515     /**
    516      * Return the path-based permissions required for read and/or write access to
    517      * this content provider.  This method can be called from multiple
    518      * threads, as described in
    519      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
    520      * and Threads</a>.
    521      */
    522     public final PathPermission[] getPathPermissions() {
    523         return mPathPermissions;
    524     }
    525 
    526     /** @hide */
    527     public final void setAppOps(int readOp, int writeOp) {
    528         if (!mNoPerms) {
    529             mTransport.mAppOpsManager = (AppOpsManager)mContext.getSystemService(
    530                     Context.APP_OPS_SERVICE);
    531             mTransport.mReadOp = readOp;
    532             mTransport.mWriteOp = writeOp;
    533         }
    534     }
    535 
    536     /** @hide */
    537     public AppOpsManager getAppOpsManager() {
    538         return mTransport.mAppOpsManager;
    539     }
    540 
    541     /**
    542      * Implement this to initialize your content provider on startup.
    543      * This method is called for all registered content providers on the
    544      * application main thread at application launch time.  It must not perform
    545      * lengthy operations, or application startup will be delayed.
    546      *
    547      * <p>You should defer nontrivial initialization (such as opening,
    548      * upgrading, and scanning databases) until the content provider is used
    549      * (via {@link #query}, {@link #insert}, etc).  Deferred initialization
    550      * keeps application startup fast, avoids unnecessary work if the provider
    551      * turns out not to be needed, and stops database errors (such as a full
    552      * disk) from halting application launch.
    553      *
    554      * <p>If you use SQLite, {@link android.database.sqlite.SQLiteOpenHelper}
    555      * is a helpful utility class that makes it easy to manage databases,
    556      * and will automatically defer opening until first use.  If you do use
    557      * SQLiteOpenHelper, make sure to avoid calling
    558      * {@link android.database.sqlite.SQLiteOpenHelper#getReadableDatabase} or
    559      * {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase}
    560      * from this method.  (Instead, override
    561      * {@link android.database.sqlite.SQLiteOpenHelper#onOpen} to initialize the
    562      * database when it is first opened.)
    563      *
    564      * @return true if the provider was successfully loaded, false otherwise
    565      */
    566     public abstract boolean onCreate();
    567 
    568     /**
    569      * {@inheritDoc}
    570      * This method is always called on the application main thread, and must
    571      * not perform lengthy operations.
    572      *
    573      * <p>The default content provider implementation does nothing.
    574      * Override this method to take appropriate action.
    575      * (Content providers do not usually care about things like screen
    576      * orientation, but may want to know about locale changes.)
    577      */
    578     public void onConfigurationChanged(Configuration newConfig) {
    579     }
    580 
    581     /**
    582      * {@inheritDoc}
    583      * This method is always called on the application main thread, and must
    584      * not perform lengthy operations.
    585      *
    586      * <p>The default content provider implementation does nothing.
    587      * Subclasses may override this method to take appropriate action.
    588      */
    589     public void onLowMemory() {
    590     }
    591 
    592     public void onTrimMemory(int level) {
    593     }
    594 
    595     /**
    596      * @hide
    597      * Implementation when a caller has performed a query on the content
    598      * provider, but that call has been rejected for the operation given
    599      * to {@link #setAppOps(int, int)}.  The default implementation
    600      * rewrites the <var>selection</var> argument to include a condition
    601      * that is never true (so will always result in an empty cursor)
    602      * and calls through to {@link #query(android.net.Uri, String[], String, String[],
    603      * String, android.os.CancellationSignal)} with that.
    604      */
    605     public Cursor rejectQuery(Uri uri, String[] projection,
    606             String selection, String[] selectionArgs, String sortOrder,
    607             CancellationSignal cancellationSignal) {
    608         // The read is not allowed...  to fake it out, we replace the given
    609         // selection statement with a dummy one that will always be false.
    610         // This way we will get a cursor back that has the correct structure
    611         // but contains no rows.
    612         if (selection == null || selection.isEmpty()) {
    613             selection = "'A' = 'B'";
    614         } else {
    615             selection = "'A' = 'B' AND (" + selection + ")";
    616         }
    617         return query(uri, projection, selection, selectionArgs, sortOrder, cancellationSignal);
    618     }
    619 
    620     /**
    621      * Implement this to handle query requests from clients.
    622      * This method can be called from multiple threads, as described in
    623      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
    624      * and Threads</a>.
    625      * <p>
    626      * Example client call:<p>
    627      * <pre>// Request a specific record.
    628      * Cursor managedCursor = managedQuery(
    629                 ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2),
    630                 projection,    // Which columns to return.
    631                 null,          // WHERE clause.
    632                 null,          // WHERE clause value substitution
    633                 People.NAME + " ASC");   // Sort order.</pre>
    634      * Example implementation:<p>
    635      * <pre>// SQLiteQueryBuilder is a helper class that creates the
    636         // proper SQL syntax for us.
    637         SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
    638 
    639         // Set the table we're querying.
    640         qBuilder.setTables(DATABASE_TABLE_NAME);
    641 
    642         // If the query ends in a specific record number, we're
    643         // being asked for a specific record, so set the
    644         // WHERE clause in our query.
    645         if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){
    646             qBuilder.appendWhere("_id=" + uri.getPathLeafId());
    647         }
    648 
    649         // Make the query.
    650         Cursor c = qBuilder.query(mDb,
    651                 projection,
    652                 selection,
    653                 selectionArgs,
    654                 groupBy,
    655                 having,
    656                 sortOrder);
    657         c.setNotificationUri(getContext().getContentResolver(), uri);
    658         return c;</pre>
    659      *
    660      * @param uri The URI to query. This will be the full URI sent by the client;
    661      *      if the client is requesting a specific record, the URI will end in a record number
    662      *      that the implementation should parse and add to a WHERE or HAVING clause, specifying
    663      *      that _id value.
    664      * @param projection The list of columns to put into the cursor. If
    665      *      {@code null} all columns are included.
    666      * @param selection A selection criteria to apply when filtering rows.
    667      *      If {@code null} then all rows are included.
    668      * @param selectionArgs You may include ?s in selection, which will be replaced by
    669      *      the values from selectionArgs, in order that they appear in the selection.
    670      *      The values will be bound as Strings.
    671      * @param sortOrder How the rows in the cursor should be sorted.
    672      *      If {@code null} then the provider is free to define the sort order.
    673      * @return a Cursor or {@code null}.
    674      */
    675     public abstract Cursor query(Uri uri, String[] projection,
    676             String selection, String[] selectionArgs, String sortOrder);
    677 
    678     /**
    679      * Implement this to handle query requests from clients with support for cancellation.
    680      * This method can be called from multiple threads, as described in
    681      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
    682      * and Threads</a>.
    683      * <p>
    684      * Example client call:<p>
    685      * <pre>// Request a specific record.
    686      * Cursor managedCursor = managedQuery(
    687                 ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2),
    688                 projection,    // Which columns to return.
    689                 null,          // WHERE clause.
    690                 null,          // WHERE clause value substitution
    691                 People.NAME + " ASC");   // Sort order.</pre>
    692      * Example implementation:<p>
    693      * <pre>// SQLiteQueryBuilder is a helper class that creates the
    694         // proper SQL syntax for us.
    695         SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
    696 
    697         // Set the table we're querying.
    698         qBuilder.setTables(DATABASE_TABLE_NAME);
    699 
    700         // If the query ends in a specific record number, we're
    701         // being asked for a specific record, so set the
    702         // WHERE clause in our query.
    703         if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){
    704             qBuilder.appendWhere("_id=" + uri.getPathLeafId());
    705         }
    706 
    707         // Make the query.
    708         Cursor c = qBuilder.query(mDb,
    709                 projection,
    710                 selection,
    711                 selectionArgs,
    712                 groupBy,
    713                 having,
    714                 sortOrder);
    715         c.setNotificationUri(getContext().getContentResolver(), uri);
    716         return c;</pre>
    717      * <p>
    718      * If you implement this method then you must also implement the version of
    719      * {@link #query(Uri, String[], String, String[], String)} that does not take a cancellation
    720      * signal to ensure correct operation on older versions of the Android Framework in
    721      * which the cancellation signal overload was not available.
    722      *
    723      * @param uri The URI to query. This will be the full URI sent by the client;
    724      *      if the client is requesting a specific record, the URI will end in a record number
    725      *      that the implementation should parse and add to a WHERE or HAVING clause, specifying
    726      *      that _id value.
    727      * @param projection The list of columns to put into the cursor. If
    728      *      {@code null} all columns are included.
    729      * @param selection A selection criteria to apply when filtering rows.
    730      *      If {@code null} then all rows are included.
    731      * @param selectionArgs You may include ?s in selection, which will be replaced by
    732      *      the values from selectionArgs, in order that they appear in the selection.
    733      *      The values will be bound as Strings.
    734      * @param sortOrder How the rows in the cursor should be sorted.
    735      *      If {@code null} then the provider is free to define the sort order.
    736      * @param cancellationSignal A signal to cancel the operation in progress, or {@code null} if none.
    737      * If the operation is canceled, then {@link OperationCanceledException} will be thrown
    738      * when the query is executed.
    739      * @return a Cursor or {@code null}.
    740      */
    741     public Cursor query(Uri uri, String[] projection,
    742             String selection, String[] selectionArgs, String sortOrder,
    743             CancellationSignal cancellationSignal) {
    744         return query(uri, projection, selection, selectionArgs, sortOrder);
    745     }
    746 
    747     /**
    748      * Implement this to handle requests for the MIME type of the data at the
    749      * given URI.  The returned MIME type should start with
    750      * <code>vnd.android.cursor.item</code> for a single record,
    751      * or <code>vnd.android.cursor.dir/</code> for multiple items.
    752      * This method can be called from multiple threads, as described in
    753      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
    754      * and Threads</a>.
    755      *
    756      * <p>Note that there are no permissions needed for an application to
    757      * access this information; if your content provider requires read and/or
    758      * write permissions, or is not exported, all applications can still call
    759      * this method regardless of their access permissions.  This allows them
    760      * to retrieve the MIME type for a URI when dispatching intents.
    761      *
    762      * @param uri the URI to query.
    763      * @return a MIME type string, or {@code null} if there is no type.
    764      */
    765     public abstract String getType(Uri uri);
    766 
    767     /**
    768      * @hide
    769      * Implementation when a caller has performed an insert on the content
    770      * provider, but that call has been rejected for the operation given
    771      * to {@link #setAppOps(int, int)}.  The default implementation simply
    772      * returns a dummy URI that is the base URI with a 0 path element
    773      * appended.
    774      */
    775     public Uri rejectInsert(Uri uri, ContentValues values) {
    776         // If not allowed, we need to return some reasonable URI.  Maybe the
    777         // content provider should be responsible for this, but for now we
    778         // will just return the base URI with a dummy '0' tagged on to it.
    779         // You shouldn't be able to read if you can't write, anyway, so it
    780         // shouldn't matter much what is returned.
    781         return uri.buildUpon().appendPath("0").build();
    782     }
    783 
    784     /**
    785      * Implement this to handle requests to insert a new row.
    786      * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
    787      * after inserting.
    788      * This method can be called from multiple threads, as described in
    789      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
    790      * and Threads</a>.
    791      * @param uri The content:// URI of the insertion request. This must not be {@code null}.
    792      * @param values A set of column_name/value pairs to add to the database.
    793      *     This must not be {@code null}.
    794      * @return The URI for the newly inserted item.
    795      */
    796     public abstract Uri insert(Uri uri, ContentValues values);
    797 
    798     /**
    799      * Override this to handle requests to insert a set of new rows, or the
    800      * default implementation will iterate over the values and call
    801      * {@link #insert} on each of them.
    802      * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
    803      * after inserting.
    804      * This method can be called from multiple threads, as described in
    805      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
    806      * and Threads</a>.
    807      *
    808      * @param uri The content:// URI of the insertion request.
    809      * @param values An array of sets of column_name/value pairs to add to the database.
    810      *    This must not be {@code null}.
    811      * @return The number of values that were inserted.
    812      */
    813     public int bulkInsert(Uri uri, ContentValues[] values) {
    814         int numValues = values.length;
    815         for (int i = 0; i < numValues; i++) {
    816             insert(uri, values[i]);
    817         }
    818         return numValues;
    819     }
    820 
    821     /**
    822      * Implement this to handle requests to delete one or more rows.
    823      * The implementation should apply the selection clause when performing
    824      * deletion, allowing the operation to affect multiple rows in a directory.
    825      * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyDelete()}
    826      * after deleting.
    827      * This method can be called from multiple threads, as described in
    828      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
    829      * and Threads</a>.
    830      *
    831      * <p>The implementation is responsible for parsing out a row ID at the end
    832      * of the URI, if a specific row is being deleted. That is, the client would
    833      * pass in <code>content://contacts/people/22</code> and the implementation is
    834      * responsible for parsing the record number (22) when creating a SQL statement.
    835      *
    836      * @param uri The full URI to query, including a row ID (if a specific record is requested).
    837      * @param selection An optional restriction to apply to rows when deleting.
    838      * @return The number of rows affected.
    839      * @throws SQLException
    840      */
    841     public abstract int delete(Uri uri, String selection, String[] selectionArgs);
    842 
    843     /**
    844      * Implement this to handle requests to update one or more rows.
    845      * The implementation should update all rows matching the selection
    846      * to set the columns according to the provided values map.
    847      * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
    848      * after updating.
    849      * This method can be called from multiple threads, as described in
    850      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
    851      * and Threads</a>.
    852      *
    853      * @param uri The URI to query. This can potentially have a record ID if this
    854      * is an update request for a specific record.
    855      * @param values A set of column_name/value pairs to update in the database.
    856      *     This must not be {@code null}.
    857      * @param selection An optional filter to match rows to update.
    858      * @return the number of rows affected.
    859      */
    860     public abstract int update(Uri uri, ContentValues values, String selection,
    861             String[] selectionArgs);
    862 
    863     /**
    864      * Override this to handle requests to open a file blob.
    865      * The default implementation always throws {@link FileNotFoundException}.
    866      * This method can be called from multiple threads, as described in
    867      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
    868      * and Threads</a>.
    869      *
    870      * <p>This method returns a ParcelFileDescriptor, which is returned directly
    871      * to the caller.  This way large data (such as images and documents) can be
    872      * returned without copying the content.
    873      *
    874      * <p>The returned ParcelFileDescriptor is owned by the caller, so it is
    875      * their responsibility to close it when done.  That is, the implementation
    876      * of this method should create a new ParcelFileDescriptor for each call.
    877      *
    878      * <p class="note">For use in Intents, you will want to implement {@link #getType}
    879      * to return the appropriate MIME type for the data returned here with
    880      * the same URI.  This will allow intent resolution to automatically determine the data MIME
    881      * type and select the appropriate matching targets as part of its operation.</p>
    882      *
    883      * <p class="note">For better interoperability with other applications, it is recommended
    884      * that for any URIs that can be opened, you also support queries on them
    885      * containing at least the columns specified by {@link android.provider.OpenableColumns}.
    886      * You may also want to support other common columns if you have additional meta-data
    887      * to supply, such as {@link android.provider.MediaStore.MediaColumns#DATE_ADDED}
    888      * in {@link android.provider.MediaStore.MediaColumns}.</p>
    889      *
    890      * @param uri The URI whose file is to be opened.
    891      * @param mode Access mode for the file.  May be "r" for read-only access,
    892      * "rw" for read and write access, or "rwt" for read and write access
    893      * that truncates any existing file.
    894      *
    895      * @return Returns a new ParcelFileDescriptor which you can use to access
    896      * the file.
    897      *
    898      * @throws FileNotFoundException Throws FileNotFoundException if there is
    899      * no file associated with the given URI or the mode is invalid.
    900      * @throws SecurityException Throws SecurityException if the caller does
    901      * not have permission to access the file.
    902      *
    903      * @see #openAssetFile(Uri, String)
    904      * @see #openFileHelper(Uri, String)
    905      * @see #getType(android.net.Uri)
    906      */
    907     public ParcelFileDescriptor openFile(Uri uri, String mode)
    908             throws FileNotFoundException {
    909         throw new FileNotFoundException("No files supported by provider at "
    910                 + uri);
    911     }
    912 
    913     /**
    914      * This is like {@link #openFile}, but can be implemented by providers
    915      * that need to be able to return sub-sections of files, often assets
    916      * inside of their .apk.
    917      * This method can be called from multiple threads, as described in
    918      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
    919      * and Threads</a>.
    920      *
    921      * <p>If you implement this, your clients must be able to deal with such
    922      * file slices, either directly with
    923      * {@link ContentResolver#openAssetFileDescriptor}, or by using the higher-level
    924      * {@link ContentResolver#openInputStream ContentResolver.openInputStream}
    925      * or {@link ContentResolver#openOutputStream ContentResolver.openOutputStream}
    926      * methods.
    927      *
    928      * <p class="note">If you are implementing this to return a full file, you
    929      * should create the AssetFileDescriptor with
    930      * {@link AssetFileDescriptor#UNKNOWN_LENGTH} to be compatible with
    931      * applications that can not handle sub-sections of files.</p>
    932      *
    933      * <p class="note">For use in Intents, you will want to implement {@link #getType}
    934      * to return the appropriate MIME type for the data returned here with
    935      * the same URI.  This will allow intent resolution to automatically determine the data MIME
    936      * type and select the appropriate matching targets as part of its operation.</p>
    937      *
    938      * <p class="note">For better interoperability with other applications, it is recommended
    939      * that for any URIs that can be opened, you also support queries on them
    940      * containing at least the columns specified by {@link android.provider.OpenableColumns}.</p>
    941      *
    942      * @param uri The URI whose file is to be opened.
    943      * @param mode Access mode for the file.  May be "r" for read-only access,
    944      * "w" for write-only access (erasing whatever data is currently in
    945      * the file), "wa" for write-only access to append to any existing data,
    946      * "rw" for read and write access on any existing data, and "rwt" for read
    947      * and write access that truncates any existing file.
    948      *
    949      * @return Returns a new AssetFileDescriptor which you can use to access
    950      * the file.
    951      *
    952      * @throws FileNotFoundException Throws FileNotFoundException if there is
    953      * no file associated with the given URI or the mode is invalid.
    954      * @throws SecurityException Throws SecurityException if the caller does
    955      * not have permission to access the file.
    956      *
    957      * @see #openFile(Uri, String)
    958      * @see #openFileHelper(Uri, String)
    959      * @see #getType(android.net.Uri)
    960      */
    961     public AssetFileDescriptor openAssetFile(Uri uri, String mode)
    962             throws FileNotFoundException {
    963         ParcelFileDescriptor fd = openFile(uri, mode);
    964         return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null;
    965     }
    966 
    967     /**
    968      * Convenience for subclasses that wish to implement {@link #openFile}
    969      * by looking up a column named "_data" at the given URI.
    970      *
    971      * @param uri The URI to be opened.
    972      * @param mode The file mode.  May be "r" for read-only access,
    973      * "w" for write-only access (erasing whatever data is currently in
    974      * the file), "wa" for write-only access to append to any existing data,
    975      * "rw" for read and write access on any existing data, and "rwt" for read
    976      * and write access that truncates any existing file.
    977      *
    978      * @return Returns a new ParcelFileDescriptor that can be used by the
    979      * client to access the file.
    980      */
    981     protected final ParcelFileDescriptor openFileHelper(Uri uri,
    982             String mode) throws FileNotFoundException {
    983         Cursor c = query(uri, new String[]{"_data"}, null, null, null);
    984         int count = (c != null) ? c.getCount() : 0;
    985         if (count != 1) {
    986             // If there is not exactly one result, throw an appropriate
    987             // exception.
    988             if (c != null) {
    989                 c.close();
    990             }
    991             if (count == 0) {
    992                 throw new FileNotFoundException("No entry for " + uri);
    993             }
    994             throw new FileNotFoundException("Multiple items at " + uri);
    995         }
    996 
    997         c.moveToFirst();
    998         int i = c.getColumnIndex("_data");
    999         String path = (i >= 0 ? c.getString(i) : null);
   1000         c.close();
   1001         if (path == null) {
   1002             throw new FileNotFoundException("Column _data not found.");
   1003         }
   1004 
   1005         int modeBits = ContentResolver.modeToMode(uri, mode);
   1006         return ParcelFileDescriptor.open(new File(path), modeBits);
   1007     }
   1008 
   1009     /**
   1010      * Called by a client to determine the types of data streams that this
   1011      * content provider supports for the given URI.  The default implementation
   1012      * returns {@code null}, meaning no types.  If your content provider stores data
   1013      * of a particular type, return that MIME type if it matches the given
   1014      * mimeTypeFilter.  If it can perform type conversions, return an array
   1015      * of all supported MIME types that match mimeTypeFilter.
   1016      *
   1017      * @param uri The data in the content provider being queried.
   1018      * @param mimeTypeFilter The type of data the client desires.  May be
   1019      * a pattern, such as *\/* to retrieve all possible data types.
   1020      * @return Returns {@code null} if there are no possible data streams for the
   1021      * given mimeTypeFilter.  Otherwise returns an array of all available
   1022      * concrete MIME types.
   1023      *
   1024      * @see #getType(Uri)
   1025      * @see #openTypedAssetFile(Uri, String, Bundle)
   1026      * @see ClipDescription#compareMimeTypes(String, String)
   1027      */
   1028     public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
   1029         return null;
   1030     }
   1031 
   1032     /**
   1033      * Called by a client to open a read-only stream containing data of a
   1034      * particular MIME type.  This is like {@link #openAssetFile(Uri, String)},
   1035      * except the file can only be read-only and the content provider may
   1036      * perform data conversions to generate data of the desired type.
   1037      *
   1038      * <p>The default implementation compares the given mimeType against the
   1039      * result of {@link #getType(Uri)} and, if they match, simply calls
   1040      * {@link #openAssetFile(Uri, String)}.
   1041      *
   1042      * <p>See {@link ClipData} for examples of the use and implementation
   1043      * of this method.
   1044      *
   1045      * <p class="note">For better interoperability with other applications, it is recommended
   1046      * that for any URIs that can be opened, you also support queries on them
   1047      * containing at least the columns specified by {@link android.provider.OpenableColumns}.
   1048      * You may also want to support other common columns if you have additional meta-data
   1049      * to supply, such as {@link android.provider.MediaStore.MediaColumns#DATE_ADDED}
   1050      * in {@link android.provider.MediaStore.MediaColumns}.</p>
   1051      *
   1052      * @param uri The data in the content provider being queried.
   1053      * @param mimeTypeFilter The type of data the client desires.  May be
   1054      * a pattern, such as *\/*, if the caller does not have specific type
   1055      * requirements; in this case the content provider will pick its best
   1056      * type matching the pattern.
   1057      * @param opts Additional options from the client.  The definitions of
   1058      * these are specific to the content provider being called.
   1059      *
   1060      * @return Returns a new AssetFileDescriptor from which the client can
   1061      * read data of the desired type.
   1062      *
   1063      * @throws FileNotFoundException Throws FileNotFoundException if there is
   1064      * no file associated with the given URI or the mode is invalid.
   1065      * @throws SecurityException Throws SecurityException if the caller does
   1066      * not have permission to access the data.
   1067      * @throws IllegalArgumentException Throws IllegalArgumentException if the
   1068      * content provider does not support the requested MIME type.
   1069      *
   1070      * @see #getStreamTypes(Uri, String)
   1071      * @see #openAssetFile(Uri, String)
   1072      * @see ClipDescription#compareMimeTypes(String, String)
   1073      */
   1074     public AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts)
   1075             throws FileNotFoundException {
   1076         if ("*/*".equals(mimeTypeFilter)) {
   1077             // If they can take anything, the untyped open call is good enough.
   1078             return openAssetFile(uri, "r");
   1079         }
   1080         String baseType = getType(uri);
   1081         if (baseType != null && ClipDescription.compareMimeTypes(baseType, mimeTypeFilter)) {
   1082             // Use old untyped open call if this provider has a type for this
   1083             // URI and it matches the request.
   1084             return openAssetFile(uri, "r");
   1085         }
   1086         throw new FileNotFoundException("Can't open " + uri + " as type " + mimeTypeFilter);
   1087     }
   1088 
   1089     /**
   1090      * Interface to write a stream of data to a pipe.  Use with
   1091      * {@link ContentProvider#openPipeHelper}.
   1092      */
   1093     public interface PipeDataWriter<T> {
   1094         /**
   1095          * Called from a background thread to stream data out to a pipe.
   1096          * Note that the pipe is blocking, so this thread can block on
   1097          * writes for an arbitrary amount of time if the client is slow
   1098          * at reading.
   1099          *
   1100          * @param output The pipe where data should be written.  This will be
   1101          * closed for you upon returning from this function.
   1102          * @param uri The URI whose data is to be written.
   1103          * @param mimeType The desired type of data to be written.
   1104          * @param opts Options supplied by caller.
   1105          * @param args Your own custom arguments.
   1106          */
   1107         public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String mimeType,
   1108                 Bundle opts, T args);
   1109     }
   1110 
   1111     /**
   1112      * A helper function for implementing {@link #openTypedAssetFile}, for
   1113      * creating a data pipe and background thread allowing you to stream
   1114      * generated data back to the client.  This function returns a new
   1115      * ParcelFileDescriptor that should be returned to the caller (the caller
   1116      * is responsible for closing it).
   1117      *
   1118      * @param uri The URI whose data is to be written.
   1119      * @param mimeType The desired type of data to be written.
   1120      * @param opts Options supplied by caller.
   1121      * @param args Your own custom arguments.
   1122      * @param func Interface implementing the function that will actually
   1123      * stream the data.
   1124      * @return Returns a new ParcelFileDescriptor holding the read side of
   1125      * the pipe.  This should be returned to the caller for reading; the caller
   1126      * is responsible for closing it when done.
   1127      */
   1128     public <T> ParcelFileDescriptor openPipeHelper(final Uri uri, final String mimeType,
   1129             final Bundle opts, final T args, final PipeDataWriter<T> func)
   1130             throws FileNotFoundException {
   1131         try {
   1132             final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
   1133 
   1134             AsyncTask<Object, Object, Object> task = new AsyncTask<Object, Object, Object>() {
   1135                 @Override
   1136                 protected Object doInBackground(Object... params) {
   1137                     func.writeDataToPipe(fds[1], uri, mimeType, opts, args);
   1138                     try {
   1139                         fds[1].close();
   1140                     } catch (IOException e) {
   1141                         Log.w(TAG, "Failure closing pipe", e);
   1142                     }
   1143                     return null;
   1144                 }
   1145             };
   1146             task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Object[])null);
   1147 
   1148             return fds[0];
   1149         } catch (IOException e) {
   1150             throw new FileNotFoundException("failure making pipe");
   1151         }
   1152     }
   1153 
   1154     /**
   1155      * Returns true if this instance is a temporary content provider.
   1156      * @return true if this instance is a temporary content provider
   1157      */
   1158     protected boolean isTemporary() {
   1159         return false;
   1160     }
   1161 
   1162     /**
   1163      * Returns the Binder object for this provider.
   1164      *
   1165      * @return the Binder object for this provider
   1166      * @hide
   1167      */
   1168     public IContentProvider getIContentProvider() {
   1169         return mTransport;
   1170     }
   1171 
   1172     /**
   1173      * Like {@link #attachInfo(Context, android.content.pm.ProviderInfo)}, but for use
   1174      * when directly instantiating the provider for testing.
   1175      * @hide
   1176      */
   1177     public void attachInfoForTesting(Context context, ProviderInfo info) {
   1178         attachInfo(context, info, true);
   1179     }
   1180 
   1181     /**
   1182      * After being instantiated, this is called to tell the content provider
   1183      * about itself.
   1184      *
   1185      * @param context The context this provider is running in
   1186      * @param info Registered information about this content provider
   1187      */
   1188     public void attachInfo(Context context, ProviderInfo info) {
   1189         attachInfo(context, info, false);
   1190     }
   1191 
   1192     private void attachInfo(Context context, ProviderInfo info, boolean testing) {
   1193         /*
   1194          * We may be using AsyncTask from binder threads.  Make it init here
   1195          * so its static handler is on the main thread.
   1196          */
   1197         AsyncTask.init();
   1198 
   1199         mNoPerms = testing;
   1200 
   1201         /*
   1202          * Only allow it to be set once, so after the content service gives
   1203          * this to us clients can't change it.
   1204          */
   1205         if (mContext == null) {
   1206             mContext = context;
   1207             mMyUid = Process.myUid();
   1208             if (info != null) {
   1209                 setReadPermission(info.readPermission);
   1210                 setWritePermission(info.writePermission);
   1211                 setPathPermissions(info.pathPermissions);
   1212                 mExported = info.exported;
   1213             }
   1214             ContentProvider.this.onCreate();
   1215         }
   1216     }
   1217 
   1218     /**
   1219      * Override this to handle requests to perform a batch of operations, or the
   1220      * default implementation will iterate over the operations and call
   1221      * {@link ContentProviderOperation#apply} on each of them.
   1222      * If all calls to {@link ContentProviderOperation#apply} succeed
   1223      * then a {@link ContentProviderResult} array with as many
   1224      * elements as there were operations will be returned.  If any of the calls
   1225      * fail, it is up to the implementation how many of the others take effect.
   1226      * This method can be called from multiple threads, as described in
   1227      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
   1228      * and Threads</a>.
   1229      *
   1230      * @param operations the operations to apply
   1231      * @return the results of the applications
   1232      * @throws OperationApplicationException thrown if any operation fails.
   1233      * @see ContentProviderOperation#apply
   1234      */
   1235     public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
   1236             throws OperationApplicationException {
   1237         final int numOperations = operations.size();
   1238         final ContentProviderResult[] results = new ContentProviderResult[numOperations];
   1239         for (int i = 0; i < numOperations; i++) {
   1240             results[i] = operations.get(i).apply(this, results, i);
   1241         }
   1242         return results;
   1243     }
   1244 
   1245     /**
   1246      * @hide
   1247      * Front-end to {@link #call(String, String, android.os.Bundle)} that provides the name
   1248      * of the calling package.
   1249      */
   1250     public Bundle callFromPackage(String callingPackag, String method, String arg, Bundle extras) {
   1251         return call(method, arg, extras);
   1252     }
   1253 
   1254     /**
   1255      * Call a provider-defined method.  This can be used to implement
   1256      * interfaces that are cheaper and/or unnatural for a table-like
   1257      * model.
   1258      *
   1259      * <p class="note"><strong>WARNING:</strong> The framework does no permission checking
   1260      * on this entry into the content provider besides the basic ability for the application
   1261      * to get access to the provider at all.  For example, it has no idea whether the call
   1262      * being executed may read or write data in the provider, so can't enforce those
   1263      * individual permissions.  Any implementation of this method <strong>must</strong>
   1264      * do its own permission checks on incoming calls to make sure they are allowed.</p>
   1265      *
   1266      * @param method method name to call.  Opaque to framework, but should not be {@code null}.
   1267      * @param arg provider-defined String argument.  May be {@code null}.
   1268      * @param extras provider-defined Bundle argument.  May be {@code null}.
   1269      * @return provider-defined return value.  May be {@code null}, which is also
   1270      *   the default for providers which don't implement any call methods.
   1271      */
   1272     public Bundle call(String method, String arg, Bundle extras) {
   1273         return null;
   1274     }
   1275 
   1276     /**
   1277      * Implement this to shut down the ContentProvider instance. You can then
   1278      * invoke this method in unit tests.
   1279      *
   1280      * <p>
   1281      * Android normally handles ContentProvider startup and shutdown
   1282      * automatically. You do not need to start up or shut down a
   1283      * ContentProvider. When you invoke a test method on a ContentProvider,
   1284      * however, a ContentProvider instance is started and keeps running after
   1285      * the test finishes, even if a succeeding test instantiates another
   1286      * ContentProvider. A conflict develops because the two instances are
   1287      * usually running against the same underlying data source (for example, an
   1288      * sqlite database).
   1289      * </p>
   1290      * <p>
   1291      * Implementing shutDown() avoids this conflict by providing a way to
   1292      * terminate the ContentProvider. This method can also prevent memory leaks
   1293      * from multiple instantiations of the ContentProvider, and it can ensure
   1294      * unit test isolation by allowing you to completely clean up the test
   1295      * fixture before moving on to the next test.
   1296      * </p>
   1297      */
   1298     public void shutdown() {
   1299         Log.w(TAG, "implement ContentProvider shutdown() to make sure all database " +
   1300                 "connections are gracefully shutdown");
   1301     }
   1302 
   1303     /**
   1304      * Print the Provider's state into the given stream.  This gets invoked if
   1305      * you run "adb shell dumpsys activity provider &lt;provider_component_name&gt;".
   1306      *
   1307      * @param fd The raw file descriptor that the dump is being sent to.
   1308      * @param writer The PrintWriter to which you should dump your state.  This will be
   1309      * closed for you after you return.
   1310      * @param args additional arguments to the dump request.
   1311      */
   1312     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
   1313         writer.println("nothing to dump");
   1314     }
   1315 }
   1316