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.accounts.Account;
     20 import android.app.ActivityManagerNative;
     21 import android.app.ActivityThread;
     22 import android.app.AppGlobals;
     23 import android.content.pm.PackageManager.NameNotFoundException;
     24 import android.content.res.AssetFileDescriptor;
     25 import android.content.res.Resources;
     26 import android.database.ContentObserver;
     27 import android.database.CrossProcessCursorWrapper;
     28 import android.database.Cursor;
     29 import android.database.IContentObserver;
     30 import android.net.Uri;
     31 import android.os.Bundle;
     32 import android.os.CancellationSignal;
     33 import android.os.DeadObjectException;
     34 import android.os.IBinder;
     35 import android.os.ICancellationSignal;
     36 import android.os.OperationCanceledException;
     37 import android.os.ParcelFileDescriptor;
     38 import android.os.RemoteException;
     39 import android.os.ServiceManager;
     40 import android.os.SystemClock;
     41 import android.os.UserHandle;
     42 import android.text.TextUtils;
     43 import android.util.EventLog;
     44 import android.util.Log;
     45 
     46 import dalvik.system.CloseGuard;
     47 
     48 import java.io.File;
     49 import java.io.FileInputStream;
     50 import java.io.FileNotFoundException;
     51 import java.io.IOException;
     52 import java.io.InputStream;
     53 import java.io.OutputStream;
     54 import java.util.ArrayList;
     55 import java.util.List;
     56 import java.util.Random;
     57 
     58 /**
     59  * This class provides applications access to the content model.
     60  *
     61  * <div class="special reference">
     62  * <h3>Developer Guides</h3>
     63  * <p>For more information about using a ContentResolver with content providers, read the
     64  * <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
     65  * developer guide.</p>
     66  */
     67 public abstract class ContentResolver {
     68     /**
     69      * @deprecated instead use
     70      * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
     71      */
     72     @Deprecated
     73     public static final String SYNC_EXTRAS_ACCOUNT = "account";
     74 
     75     /**
     76      * If this extra is set to true, the sync request will be scheduled
     77      * at the front of the sync request queue and without any delay
     78      */
     79     public static final String SYNC_EXTRAS_EXPEDITED = "expedited";
     80 
     81     /**
     82      * @deprecated instead use
     83      * {@link #SYNC_EXTRAS_MANUAL}
     84      */
     85     @Deprecated
     86     public static final String SYNC_EXTRAS_FORCE = "force";
     87 
     88     /**
     89      * If this extra is set to true then the sync settings (like getSyncAutomatically())
     90      * are ignored by the sync scheduler.
     91      */
     92     public static final String SYNC_EXTRAS_IGNORE_SETTINGS = "ignore_settings";
     93 
     94     /**
     95      * If this extra is set to true then any backoffs for the initial attempt (e.g. due to retries)
     96      * are ignored by the sync scheduler. If this request fails and gets rescheduled then the
     97      * retries will still honor the backoff.
     98      */
     99     public static final String SYNC_EXTRAS_IGNORE_BACKOFF = "ignore_backoff";
    100 
    101     /**
    102      * If this extra is set to true then the request will not be retried if it fails.
    103      */
    104     public static final String SYNC_EXTRAS_DO_NOT_RETRY = "do_not_retry";
    105 
    106     /**
    107      * Setting this extra is the equivalent of setting both {@link #SYNC_EXTRAS_IGNORE_SETTINGS}
    108      * and {@link #SYNC_EXTRAS_IGNORE_BACKOFF}
    109      */
    110     public static final String SYNC_EXTRAS_MANUAL = "force";
    111 
    112     /**
    113      * Indicates that this sync is intended to only upload local changes to the server.
    114      * For example, this will be set to true if the sync is initiated by a call to
    115      * {@link ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)}
    116      */
    117     public static final String SYNC_EXTRAS_UPLOAD = "upload";
    118 
    119     /**
    120      * Indicates that the sync adapter should proceed with the delete operations,
    121      * even if it determines that there are too many.
    122      * See {@link SyncResult#tooManyDeletions}
    123      */
    124     public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override";
    125 
    126     /**
    127      * Indicates that the sync adapter should not proceed with the delete operations,
    128      * if it determines that there are too many.
    129      * See {@link SyncResult#tooManyDeletions}
    130      */
    131     public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions";
    132 
    133     /* Extensions to API. TODO: Not clear if we will keep these as public flags. */
    134     /** {@hide} User-specified flag for expected upload size. */
    135     public static final String SYNC_EXTRAS_EXPECTED_UPLOAD = "expected_upload";
    136 
    137     /** {@hide} User-specified flag for expected download size. */
    138     public static final String SYNC_EXTRAS_EXPECTED_DOWNLOAD = "expected_download";
    139 
    140     /** {@hide} Priority of this sync with respect to other syncs scheduled for this application. */
    141     public static final String SYNC_EXTRAS_PRIORITY = "sync_priority";
    142 
    143     /** {@hide} Flag to allow sync to occur on metered network. */
    144     public static final String SYNC_EXTRAS_DISALLOW_METERED = "disallow_metered";
    145 
    146     /**
    147      * Set by the SyncManager to request that the SyncAdapter initialize itself for
    148      * the given account/authority pair. One required initialization step is to
    149      * ensure that {@link #setIsSyncable(android.accounts.Account, String, int)} has been
    150      * called with a >= 0 value. When this flag is set the SyncAdapter does not need to
    151      * do a full sync, though it is allowed to do so.
    152      */
    153     public static final String SYNC_EXTRAS_INITIALIZE = "initialize";
    154 
    155     /** @hide */
    156     public static final Intent ACTION_SYNC_CONN_STATUS_CHANGED =
    157             new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED");
    158 
    159     public static final String SCHEME_CONTENT = "content";
    160     public static final String SCHEME_ANDROID_RESOURCE = "android.resource";
    161     public static final String SCHEME_FILE = "file";
    162 
    163     /**
    164      * This is the Android platform's base MIME type for a content: URI
    165      * containing a Cursor of a single item.  Applications should use this
    166      * as the base type along with their own sub-type of their content: URIs
    167      * that represent a particular item.  For example, hypothetical IMAP email
    168      * client may have a URI
    169      * <code>content://com.company.provider.imap/inbox/1</code> for a particular
    170      * message in the inbox, whose MIME type would be reported as
    171      * <code>CURSOR_ITEM_BASE_TYPE + "/vnd.company.imap-msg"</code>
    172      *
    173      * <p>Compare with {@link #CURSOR_DIR_BASE_TYPE}.
    174      */
    175     public static final String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item";
    176 
    177     /**
    178      * This is the Android platform's base MIME type for a content: URI
    179      * containing a Cursor of zero or more items.  Applications should use this
    180      * as the base type along with their own sub-type of their content: URIs
    181      * that represent a directory of items.  For example, hypothetical IMAP email
    182      * client may have a URI
    183      * <code>content://com.company.provider.imap/inbox</code> for all of the
    184      * messages in its inbox, whose MIME type would be reported as
    185      * <code>CURSOR_DIR_BASE_TYPE + "/vnd.company.imap-msg"</code>
    186      *
    187      * <p>Note how the base MIME type varies between this and
    188      * {@link #CURSOR_ITEM_BASE_TYPE} depending on whether there is
    189      * one single item or multiple items in the data set, while the sub-type
    190      * remains the same because in either case the data structure contained
    191      * in the cursor is the same.
    192      */
    193     public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
    194 
    195     /** @hide */
    196     public static final int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1;
    197     /** @hide */
    198     public static final int SYNC_ERROR_AUTHENTICATION = 2;
    199     /** @hide */
    200     public static final int SYNC_ERROR_IO = 3;
    201     /** @hide */
    202     public static final int SYNC_ERROR_PARSE = 4;
    203     /** @hide */
    204     public static final int SYNC_ERROR_CONFLICT = 5;
    205     /** @hide */
    206     public static final int SYNC_ERROR_TOO_MANY_DELETIONS = 6;
    207     /** @hide */
    208     public static final int SYNC_ERROR_TOO_MANY_RETRIES = 7;
    209     /** @hide */
    210     public static final int SYNC_ERROR_INTERNAL = 8;
    211 
    212     private static final String[] SYNC_ERROR_NAMES = new String[] {
    213           "already-in-progress",
    214           "authentication-error",
    215           "io-error",
    216           "parse-error",
    217           "conflict",
    218           "too-many-deletions",
    219           "too-many-retries",
    220           "internal-error",
    221     };
    222 
    223     /** @hide */
    224     public static String syncErrorToString(int error) {
    225         if (error < 1 || error > SYNC_ERROR_NAMES.length) {
    226             return String.valueOf(error);
    227         }
    228         return SYNC_ERROR_NAMES[error - 1];
    229     }
    230 
    231     /** @hide */
    232     public static int syncErrorStringToInt(String error) {
    233         for (int i = 0, n = SYNC_ERROR_NAMES.length; i < n; i++) {
    234             if (SYNC_ERROR_NAMES[i].equals(error)) {
    235                 return i + 1;
    236             }
    237         }
    238         if (error != null) {
    239             try {
    240                 return Integer.parseInt(error);
    241             } catch (NumberFormatException e) {
    242                 Log.d(TAG, "error parsing sync error: " + error);
    243             }
    244         }
    245         return 0;
    246     }
    247 
    248     public static final int SYNC_OBSERVER_TYPE_SETTINGS = 1<<0;
    249     public static final int SYNC_OBSERVER_TYPE_PENDING = 1<<1;
    250     public static final int SYNC_OBSERVER_TYPE_ACTIVE = 1<<2;
    251     /** @hide */
    252     public static final int SYNC_OBSERVER_TYPE_STATUS = 1<<3;
    253     /** @hide */
    254     public static final int SYNC_OBSERVER_TYPE_ALL = 0x7fffffff;
    255 
    256     // Always log queries which take 500ms+; shorter queries are
    257     // sampled accordingly.
    258     private static final boolean ENABLE_CONTENT_SAMPLE = false;
    259     private static final int SLOW_THRESHOLD_MILLIS = 500;
    260     private final Random mRandom = new Random();  // guarded by itself
    261 
    262     public ContentResolver(Context context) {
    263         mContext = context != null ? context : ActivityThread.currentApplication();
    264         mPackageName = mContext.getOpPackageName();
    265     }
    266 
    267     /** @hide */
    268     protected abstract IContentProvider acquireProvider(Context c, String name);
    269 
    270     /**
    271      * Providing a default implementation of this, to avoid having to change a
    272      * lot of other things, but implementations of ContentResolver should
    273      * implement it.
    274      *
    275      * @hide
    276      */
    277     protected IContentProvider acquireExistingProvider(Context c, String name) {
    278         return acquireProvider(c, name);
    279     }
    280 
    281     /** @hide */
    282     public abstract boolean releaseProvider(IContentProvider icp);
    283     /** @hide */
    284     protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
    285     /** @hide */
    286     public abstract boolean releaseUnstableProvider(IContentProvider icp);
    287     /** @hide */
    288     public abstract void unstableProviderDied(IContentProvider icp);
    289 
    290     /** @hide */
    291     public void appNotRespondingViaProvider(IContentProvider icp) {
    292         throw new UnsupportedOperationException("appNotRespondingViaProvider");
    293     }
    294 
    295     /**
    296      * Return the MIME type of the given content URL.
    297      *
    298      * @param url A Uri identifying content (either a list or specific type),
    299      * using the content:// scheme.
    300      * @return A MIME type for the content, or null if the URL is invalid or the type is unknown
    301      */
    302     public final String getType(Uri url) {
    303         // XXX would like to have an acquireExistingUnstableProvider for this.
    304         IContentProvider provider = acquireExistingProvider(url);
    305         if (provider != null) {
    306             try {
    307                 return provider.getType(url);
    308             } catch (RemoteException e) {
    309                 return null;
    310             } catch (java.lang.Exception e) {
    311                 Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")");
    312                 return null;
    313             } finally {
    314                 releaseProvider(provider);
    315             }
    316         }
    317 
    318         if (!SCHEME_CONTENT.equals(url.getScheme())) {
    319             return null;
    320         }
    321 
    322         try {
    323             String type = ActivityManagerNative.getDefault().getProviderMimeType(
    324                     url, UserHandle.myUserId());
    325             return type;
    326         } catch (RemoteException e) {
    327             // Arbitrary and not worth documenting, as Activity
    328             // Manager will kill this process shortly anyway.
    329             return null;
    330         } catch (java.lang.Exception e) {
    331             Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")");
    332             return null;
    333         }
    334     }
    335 
    336     /**
    337      * Query for the possible MIME types for the representations the given
    338      * content URL can be returned when opened as as stream with
    339      * {@link #openTypedAssetFileDescriptor}.  Note that the types here are
    340      * not necessarily a superset of the type returned by {@link #getType} --
    341      * many content providers cannot return a raw stream for the structured
    342      * data that they contain.
    343      *
    344      * @param url A Uri identifying content (either a list or specific type),
    345      * using the content:// scheme.
    346      * @param mimeTypeFilter The desired MIME type.  This may be a pattern,
    347      * such as *\/*, to query for all available MIME types that match the
    348      * pattern.
    349      * @return Returns an array of MIME type strings for all available
    350      * data streams that match the given mimeTypeFilter.  If there are none,
    351      * null is returned.
    352      */
    353     public String[] getStreamTypes(Uri url, String mimeTypeFilter) {
    354         IContentProvider provider = acquireProvider(url);
    355         if (provider == null) {
    356             return null;
    357         }
    358 
    359         try {
    360             return provider.getStreamTypes(url, mimeTypeFilter);
    361         } catch (RemoteException e) {
    362             // Arbitrary and not worth documenting, as Activity
    363             // Manager will kill this process shortly anyway.
    364             return null;
    365         } finally {
    366             releaseProvider(provider);
    367         }
    368     }
    369 
    370     /**
    371      * <p>
    372      * Query the given URI, returning a {@link Cursor} over the result set.
    373      * </p>
    374      * <p>
    375      * For best performance, the caller should follow these guidelines:
    376      * <ul>
    377      * <li>Provide an explicit projection, to prevent
    378      * reading data from storage that aren't going to be used.</li>
    379      * <li>Use question mark parameter markers such as 'phone=?' instead of
    380      * explicit values in the {@code selection} parameter, so that queries
    381      * that differ only by those values will be recognized as the same
    382      * for caching purposes.</li>
    383      * </ul>
    384      * </p>
    385      *
    386      * @param uri The URI, using the content:// scheme, for the content to
    387      *         retrieve.
    388      * @param projection A list of which columns to return. Passing null will
    389      *         return all columns, which is inefficient.
    390      * @param selection A filter declaring which rows to return, formatted as an
    391      *         SQL WHERE clause (excluding the WHERE itself). Passing null will
    392      *         return all rows for the given URI.
    393      * @param selectionArgs You may include ?s in selection, which will be
    394      *         replaced by the values from selectionArgs, in the order that they
    395      *         appear in the selection. The values will be bound as Strings.
    396      * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
    397      *         clause (excluding the ORDER BY itself). Passing null will use the
    398      *         default sort order, which may be unordered.
    399      * @return A Cursor object, which is positioned before the first entry, or null
    400      * @see Cursor
    401      */
    402     public final Cursor query(Uri uri, String[] projection,
    403             String selection, String[] selectionArgs, String sortOrder) {
    404         return query(uri, projection, selection, selectionArgs, sortOrder, null);
    405     }
    406 
    407     /**
    408      * <p>
    409      * Query the given URI, returning a {@link Cursor} over the result set.
    410      * </p>
    411      * <p>
    412      * For best performance, the caller should follow these guidelines:
    413      * <ul>
    414      * <li>Provide an explicit projection, to prevent
    415      * reading data from storage that aren't going to be used.</li>
    416      * <li>Use question mark parameter markers such as 'phone=?' instead of
    417      * explicit values in the {@code selection} parameter, so that queries
    418      * that differ only by those values will be recognized as the same
    419      * for caching purposes.</li>
    420      * </ul>
    421      * </p>
    422      *
    423      * @param uri The URI, using the content:// scheme, for the content to
    424      *         retrieve.
    425      * @param projection A list of which columns to return. Passing null will
    426      *         return all columns, which is inefficient.
    427      * @param selection A filter declaring which rows to return, formatted as an
    428      *         SQL WHERE clause (excluding the WHERE itself). Passing null will
    429      *         return all rows for the given URI.
    430      * @param selectionArgs You may include ?s in selection, which will be
    431      *         replaced by the values from selectionArgs, in the order that they
    432      *         appear in the selection. The values will be bound as Strings.
    433      * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
    434      *         clause (excluding the ORDER BY itself). Passing null will use the
    435      *         default sort order, which may be unordered.
    436      * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
    437      * If the operation is canceled, then {@link OperationCanceledException} will be thrown
    438      * when the query is executed.
    439      * @return A Cursor object, which is positioned before the first entry, or null
    440      * @see Cursor
    441      */
    442     public final Cursor query(final Uri uri, String[] projection,
    443             String selection, String[] selectionArgs, String sortOrder,
    444             CancellationSignal cancellationSignal) {
    445         IContentProvider unstableProvider = acquireUnstableProvider(uri);
    446         if (unstableProvider == null) {
    447             return null;
    448         }
    449         IContentProvider stableProvider = null;
    450         Cursor qCursor = null;
    451         try {
    452             long startTime = SystemClock.uptimeMillis();
    453 
    454             ICancellationSignal remoteCancellationSignal = null;
    455             if (cancellationSignal != null) {
    456                 cancellationSignal.throwIfCanceled();
    457                 remoteCancellationSignal = unstableProvider.createCancellationSignal();
    458                 cancellationSignal.setRemote(remoteCancellationSignal);
    459             }
    460             try {
    461                 qCursor = unstableProvider.query(mPackageName, uri, projection,
    462                         selection, selectionArgs, sortOrder, remoteCancellationSignal);
    463             } catch (DeadObjectException e) {
    464                 // The remote process has died...  but we only hold an unstable
    465                 // reference though, so we might recover!!!  Let's try!!!!
    466                 // This is exciting!!1!!1!!!!1
    467                 unstableProviderDied(unstableProvider);
    468                 stableProvider = acquireProvider(uri);
    469                 if (stableProvider == null) {
    470                     return null;
    471                 }
    472                 qCursor = stableProvider.query(mPackageName, uri, projection,
    473                         selection, selectionArgs, sortOrder, remoteCancellationSignal);
    474             }
    475             if (qCursor == null) {
    476                 return null;
    477             }
    478 
    479             // Force query execution.  Might fail and throw a runtime exception here.
    480             qCursor.getCount();
    481             long durationMillis = SystemClock.uptimeMillis() - startTime;
    482             maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);
    483 
    484             // Wrap the cursor object into CursorWrapperInner object.
    485             CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
    486                     stableProvider != null ? stableProvider : acquireProvider(uri));
    487             stableProvider = null;
    488             qCursor = null;
    489             return wrapper;
    490         } catch (RemoteException e) {
    491             // Arbitrary and not worth documenting, as Activity
    492             // Manager will kill this process shortly anyway.
    493             return null;
    494         } finally {
    495             if (qCursor != null) {
    496                 qCursor.close();
    497             }
    498             if (cancellationSignal != null) {
    499                 cancellationSignal.setRemote(null);
    500             }
    501             if (unstableProvider != null) {
    502                 releaseUnstableProvider(unstableProvider);
    503             }
    504             if (stableProvider != null) {
    505                 releaseProvider(stableProvider);
    506             }
    507         }
    508     }
    509 
    510     /**
    511      * Transform the given <var>url</var> to a canonical representation of
    512      * its referenced resource, which can be used across devices, persisted,
    513      * backed up and restored, etc.  The returned Uri is still a fully capable
    514      * Uri for use with its content provider, allowing you to do all of the
    515      * same content provider operations as with the original Uri --
    516      * {@link #query}, {@link #openInputStream(android.net.Uri)}, etc.  The
    517      * only difference in behavior between the original and new Uris is that
    518      * the content provider may need to do some additional work at each call
    519      * using it to resolve it to the correct resource, especially if the
    520      * canonical Uri has been moved to a different environment.
    521      *
    522      * <p>If you are moving a canonical Uri between environments, you should
    523      * perform another call to {@link #canonicalize} with that original Uri to
    524      * re-canonicalize it for the current environment.  Alternatively, you may
    525      * want to use {@link #uncanonicalize} to transform it to a non-canonical
    526      * Uri that works only in the current environment but potentially more
    527      * efficiently than the canonical representation.</p>
    528      *
    529      * @param url The {@link Uri} that is to be transformed to a canonical
    530      * representation.  Like all resolver calls, the input can be either
    531      * a non-canonical or canonical Uri.
    532      *
    533      * @return Returns the official canonical representation of <var>url</var>,
    534      * or null if the content provider does not support a canonical representation
    535      * of the given Uri.  Many providers may not support canonicalization of some
    536      * or all of their Uris.
    537      *
    538      * @see #uncanonicalize
    539      */
    540     public final Uri canonicalize(Uri url) {
    541         IContentProvider provider = acquireProvider(url);
    542         if (provider == null) {
    543             return null;
    544         }
    545 
    546         try {
    547             return provider.canonicalize(mPackageName, url);
    548         } catch (RemoteException e) {
    549             // Arbitrary and not worth documenting, as Activity
    550             // Manager will kill this process shortly anyway.
    551             return null;
    552         } finally {
    553             releaseProvider(provider);
    554         }
    555     }
    556 
    557     /**
    558      * Given a canonical Uri previously generated by {@link #canonicalize}, convert
    559      * it to its local non-canonical form.  This can be useful in some cases where
    560      * you know that you will only be using the Uri in the current environment and
    561      * want to avoid any possible overhead when using it with the content
    562      * provider or want to verify that the referenced data exists at all in the
    563      * new environment.
    564      *
    565      * @param url The canonical {@link Uri} that is to be convered back to its
    566      * non-canonical form.
    567      *
    568      * @return Returns the non-canonical representation of <var>url</var>.  This will
    569      * return null if data identified by the canonical Uri can not be found in
    570      * the current environment; callers must always check for null and deal with
    571      * that by appropriately falling back to an alternative.
    572      *
    573      * @see #canonicalize
    574      */
    575     public final Uri uncanonicalize(Uri url) {
    576         IContentProvider provider = acquireProvider(url);
    577         if (provider == null) {
    578             return null;
    579         }
    580 
    581         try {
    582             return provider.uncanonicalize(mPackageName, url);
    583         } catch (RemoteException e) {
    584             // Arbitrary and not worth documenting, as Activity
    585             // Manager will kill this process shortly anyway.
    586             return null;
    587         } finally {
    588             releaseProvider(provider);
    589         }
    590     }
    591 
    592     /**
    593      * Open a stream on to the content associated with a content URI.  If there
    594      * is no data associated with the URI, FileNotFoundException is thrown.
    595      *
    596      * <h5>Accepts the following URI schemes:</h5>
    597      * <ul>
    598      * <li>content ({@link #SCHEME_CONTENT})</li>
    599      * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
    600      * <li>file ({@link #SCHEME_FILE})</li>
    601      * </ul>
    602      *
    603      * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
    604      * on these schemes.
    605      *
    606      * @param uri The desired URI.
    607      * @return InputStream
    608      * @throws FileNotFoundException if the provided URI could not be opened.
    609      * @see #openAssetFileDescriptor(Uri, String)
    610      */
    611     public final InputStream openInputStream(Uri uri)
    612             throws FileNotFoundException {
    613         String scheme = uri.getScheme();
    614         if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
    615             // Note: left here to avoid breaking compatibility.  May be removed
    616             // with sufficient testing.
    617             OpenResourceIdResult r = getResourceId(uri);
    618             try {
    619                 InputStream stream = r.r.openRawResource(r.id);
    620                 return stream;
    621             } catch (Resources.NotFoundException ex) {
    622                 throw new FileNotFoundException("Resource does not exist: " + uri);
    623             }
    624         } else if (SCHEME_FILE.equals(scheme)) {
    625             // Note: left here to avoid breaking compatibility.  May be removed
    626             // with sufficient testing.
    627             return new FileInputStream(uri.getPath());
    628         } else {
    629             AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r", null);
    630             try {
    631                 return fd != null ? fd.createInputStream() : null;
    632             } catch (IOException e) {
    633                 throw new FileNotFoundException("Unable to create stream");
    634             }
    635         }
    636     }
    637 
    638     /**
    639      * Synonym for {@link #openOutputStream(Uri, String)
    640      * openOutputStream(uri, "w")}.
    641      * @throws FileNotFoundException if the provided URI could not be opened.
    642      */
    643     public final OutputStream openOutputStream(Uri uri)
    644             throws FileNotFoundException {
    645         return openOutputStream(uri, "w");
    646     }
    647 
    648     /**
    649      * Open a stream on to the content associated with a content URI.  If there
    650      * is no data associated with the URI, FileNotFoundException is thrown.
    651      *
    652      * <h5>Accepts the following URI schemes:</h5>
    653      * <ul>
    654      * <li>content ({@link #SCHEME_CONTENT})</li>
    655      * <li>file ({@link #SCHEME_FILE})</li>
    656      * </ul>
    657      *
    658      * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
    659      * on these schemes.
    660      *
    661      * @param uri The desired URI.
    662      * @param mode May be "w", "wa", "rw", or "rwt".
    663      * @return OutputStream
    664      * @throws FileNotFoundException if the provided URI could not be opened.
    665      * @see #openAssetFileDescriptor(Uri, String)
    666      */
    667     public final OutputStream openOutputStream(Uri uri, String mode)
    668             throws FileNotFoundException {
    669         AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode, null);
    670         try {
    671             return fd != null ? fd.createOutputStream() : null;
    672         } catch (IOException e) {
    673             throw new FileNotFoundException("Unable to create stream");
    674         }
    675     }
    676 
    677     /**
    678      * Open a raw file descriptor to access data under a URI.  This
    679      * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the
    680      * underlying {@link ContentProvider#openFile}
    681      * ContentProvider.openFile()} method, so will <em>not</em> work with
    682      * providers that return sub-sections of files.  If at all possible,
    683      * you should use {@link #openAssetFileDescriptor(Uri, String)}.  You
    684      * will receive a FileNotFoundException exception if the provider returns a
    685      * sub-section of a file.
    686      *
    687      * <h5>Accepts the following URI schemes:</h5>
    688      * <ul>
    689      * <li>content ({@link #SCHEME_CONTENT})</li>
    690      * <li>file ({@link #SCHEME_FILE})</li>
    691      * </ul>
    692      *
    693      * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
    694      * on these schemes.
    695      * <p>
    696      * If opening with the exclusive "r" or "w" modes, the returned
    697      * ParcelFileDescriptor could be a pipe or socket pair to enable streaming
    698      * of data. Opening with the "rw" mode implies a file on disk that supports
    699      * seeking. If possible, always use an exclusive mode to give the underlying
    700      * {@link ContentProvider} the most flexibility.
    701      * <p>
    702      * If you are writing a file, and need to communicate an error to the
    703      * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.
    704      *
    705      * @param uri The desired URI to open.
    706      * @param mode The file mode to use, as per {@link ContentProvider#openFile
    707      * ContentProvider.openFile}.
    708      * @return Returns a new ParcelFileDescriptor pointing to the file.  You
    709      * own this descriptor and are responsible for closing it when done.
    710      * @throws FileNotFoundException Throws FileNotFoundException if no
    711      * file exists under the URI or the mode is invalid.
    712      * @see #openAssetFileDescriptor(Uri, String)
    713      */
    714     public final ParcelFileDescriptor openFileDescriptor(Uri uri, String mode)
    715             throws FileNotFoundException {
    716         return openFileDescriptor(uri, mode, null);
    717     }
    718 
    719     /**
    720      * Open a raw file descriptor to access data under a URI.  This
    721      * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the
    722      * underlying {@link ContentProvider#openFile}
    723      * ContentProvider.openFile()} method, so will <em>not</em> work with
    724      * providers that return sub-sections of files.  If at all possible,
    725      * you should use {@link #openAssetFileDescriptor(Uri, String)}.  You
    726      * will receive a FileNotFoundException exception if the provider returns a
    727      * sub-section of a file.
    728      *
    729      * <h5>Accepts the following URI schemes:</h5>
    730      * <ul>
    731      * <li>content ({@link #SCHEME_CONTENT})</li>
    732      * <li>file ({@link #SCHEME_FILE})</li>
    733      * </ul>
    734      *
    735      * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
    736      * on these schemes.
    737      * <p>
    738      * If opening with the exclusive "r" or "w" modes, the returned
    739      * ParcelFileDescriptor could be a pipe or socket pair to enable streaming
    740      * of data. Opening with the "rw" mode implies a file on disk that supports
    741      * seeking. If possible, always use an exclusive mode to give the underlying
    742      * {@link ContentProvider} the most flexibility.
    743      * <p>
    744      * If you are writing a file, and need to communicate an error to the
    745      * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.
    746      *
    747      * @param uri The desired URI to open.
    748      * @param mode The file mode to use, as per {@link ContentProvider#openFile
    749      * ContentProvider.openFile}.
    750      * @param cancellationSignal A signal to cancel the operation in progress,
    751      *         or null if none. If the operation is canceled, then
    752      *         {@link OperationCanceledException} will be thrown.
    753      * @return Returns a new ParcelFileDescriptor pointing to the file.  You
    754      * own this descriptor and are responsible for closing it when done.
    755      * @throws FileNotFoundException Throws FileNotFoundException if no
    756      * file exists under the URI or the mode is invalid.
    757      * @see #openAssetFileDescriptor(Uri, String)
    758      */
    759     public final ParcelFileDescriptor openFileDescriptor(Uri uri,
    760             String mode, CancellationSignal cancellationSignal) throws FileNotFoundException {
    761         AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode, cancellationSignal);
    762         if (afd == null) {
    763             return null;
    764         }
    765 
    766         if (afd.getDeclaredLength() < 0) {
    767             // This is a full file!
    768             return afd.getParcelFileDescriptor();
    769         }
    770 
    771         // Client can't handle a sub-section of a file, so close what
    772         // we got and bail with an exception.
    773         try {
    774             afd.close();
    775         } catch (IOException e) {
    776         }
    777 
    778         throw new FileNotFoundException("Not a whole file");
    779     }
    780 
    781     /**
    782      * Open a raw file descriptor to access data under a URI.  This
    783      * interacts with the underlying {@link ContentProvider#openAssetFile}
    784      * method of the provider associated with the given URI, to retrieve any file stored there.
    785      *
    786      * <h5>Accepts the following URI schemes:</h5>
    787      * <ul>
    788      * <li>content ({@link #SCHEME_CONTENT})</li>
    789      * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
    790      * <li>file ({@link #SCHEME_FILE})</li>
    791      * </ul>
    792      * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5>
    793      * <p>
    794      * A Uri object can be used to reference a resource in an APK file.  The
    795      * Uri should be one of the following formats:
    796      * <ul>
    797      * <li><code>android.resource://package_name/id_number</code><br/>
    798      * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
    799      * For example <code>com.example.myapp</code><br/>
    800      * <code>id_number</code> is the int form of the ID.<br/>
    801      * The easiest way to construct this form is
    802      * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre>
    803      * </li>
    804      * <li><code>android.resource://package_name/type/name</code><br/>
    805      * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
    806      * For example <code>com.example.myapp</code><br/>
    807      * <code>type</code> is the string form of the resource type.  For example, <code>raw</code>
    808      * or <code>drawable</code>.
    809      * <code>name</code> is the string form of the resource name.  That is, whatever the file
    810      * name was in your res directory, without the type extension.
    811      * The easiest way to construct this form is
    812      * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre>
    813      * </li>
    814      * </ul>
    815      *
    816      * <p>Note that if this function is called for read-only input (mode is "r")
    817      * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor}
    818      * for you with a MIME type of "*\/*".  This allows such callers to benefit
    819      * from any built-in data conversion that a provider implements.
    820      *
    821      * @param uri The desired URI to open.
    822      * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile
    823      * ContentProvider.openAssetFile}.
    824      * @return Returns a new ParcelFileDescriptor pointing to the file.  You
    825      * own this descriptor and are responsible for closing it when done.
    826      * @throws FileNotFoundException Throws FileNotFoundException of no
    827      * file exists under the URI or the mode is invalid.
    828      */
    829     public final AssetFileDescriptor openAssetFileDescriptor(Uri uri, String mode)
    830             throws FileNotFoundException {
    831         return openAssetFileDescriptor(uri, mode, null);
    832     }
    833 
    834     /**
    835      * Open a raw file descriptor to access data under a URI.  This
    836      * interacts with the underlying {@link ContentProvider#openAssetFile}
    837      * method of the provider associated with the given URI, to retrieve any file stored there.
    838      *
    839      * <h5>Accepts the following URI schemes:</h5>
    840      * <ul>
    841      * <li>content ({@link #SCHEME_CONTENT})</li>
    842      * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
    843      * <li>file ({@link #SCHEME_FILE})</li>
    844      * </ul>
    845      * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5>
    846      * <p>
    847      * A Uri object can be used to reference a resource in an APK file.  The
    848      * Uri should be one of the following formats:
    849      * <ul>
    850      * <li><code>android.resource://package_name/id_number</code><br/>
    851      * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
    852      * For example <code>com.example.myapp</code><br/>
    853      * <code>id_number</code> is the int form of the ID.<br/>
    854      * The easiest way to construct this form is
    855      * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre>
    856      * </li>
    857      * <li><code>android.resource://package_name/type/name</code><br/>
    858      * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
    859      * For example <code>com.example.myapp</code><br/>
    860      * <code>type</code> is the string form of the resource type.  For example, <code>raw</code>
    861      * or <code>drawable</code>.
    862      * <code>name</code> is the string form of the resource name.  That is, whatever the file
    863      * name was in your res directory, without the type extension.
    864      * The easiest way to construct this form is
    865      * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre>
    866      * </li>
    867      * </ul>
    868      *
    869      * <p>Note that if this function is called for read-only input (mode is "r")
    870      * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor}
    871      * for you with a MIME type of "*\/*".  This allows such callers to benefit
    872      * from any built-in data conversion that a provider implements.
    873      *
    874      * @param uri The desired URI to open.
    875      * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile
    876      * ContentProvider.openAssetFile}.
    877      * @param cancellationSignal A signal to cancel the operation in progress, or null if
    878      *            none. If the operation is canceled, then
    879      *            {@link OperationCanceledException} will be thrown.
    880      * @return Returns a new ParcelFileDescriptor pointing to the file.  You
    881      * own this descriptor and are responsible for closing it when done.
    882      * @throws FileNotFoundException Throws FileNotFoundException of no
    883      * file exists under the URI or the mode is invalid.
    884      */
    885     public final AssetFileDescriptor openAssetFileDescriptor(Uri uri,
    886             String mode, CancellationSignal cancellationSignal) throws FileNotFoundException {
    887         String scheme = uri.getScheme();
    888         if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
    889             if (!"r".equals(mode)) {
    890                 throw new FileNotFoundException("Can't write resources: " + uri);
    891             }
    892             OpenResourceIdResult r = getResourceId(uri);
    893             try {
    894                 return r.r.openRawResourceFd(r.id);
    895             } catch (Resources.NotFoundException ex) {
    896                 throw new FileNotFoundException("Resource does not exist: " + uri);
    897             }
    898         } else if (SCHEME_FILE.equals(scheme)) {
    899             ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
    900                     new File(uri.getPath()), ParcelFileDescriptor.parseMode(mode));
    901             return new AssetFileDescriptor(pfd, 0, -1);
    902         } else {
    903             if ("r".equals(mode)) {
    904                 return openTypedAssetFileDescriptor(uri, "*/*", null, cancellationSignal);
    905             } else {
    906                 IContentProvider unstableProvider = acquireUnstableProvider(uri);
    907                 if (unstableProvider == null) {
    908                     throw new FileNotFoundException("No content provider: " + uri);
    909                 }
    910                 IContentProvider stableProvider = null;
    911                 AssetFileDescriptor fd = null;
    912 
    913                 try {
    914                     ICancellationSignal remoteCancellationSignal = null;
    915                     if (cancellationSignal != null) {
    916                         cancellationSignal.throwIfCanceled();
    917                         remoteCancellationSignal = unstableProvider.createCancellationSignal();
    918                         cancellationSignal.setRemote(remoteCancellationSignal);
    919                     }
    920 
    921                     try {
    922                         fd = unstableProvider.openAssetFile(
    923                                 mPackageName, uri, mode, remoteCancellationSignal);
    924                         if (fd == null) {
    925                             // The provider will be released by the finally{} clause
    926                             return null;
    927                         }
    928                     } catch (DeadObjectException e) {
    929                         // The remote process has died...  but we only hold an unstable
    930                         // reference though, so we might recover!!!  Let's try!!!!
    931                         // This is exciting!!1!!1!!!!1
    932                         unstableProviderDied(unstableProvider);
    933                         stableProvider = acquireProvider(uri);
    934                         if (stableProvider == null) {
    935                             throw new FileNotFoundException("No content provider: " + uri);
    936                         }
    937                         fd = stableProvider.openAssetFile(
    938                                 mPackageName, uri, mode, remoteCancellationSignal);
    939                         if (fd == null) {
    940                             // The provider will be released by the finally{} clause
    941                             return null;
    942                         }
    943                     }
    944 
    945                     if (stableProvider == null) {
    946                         stableProvider = acquireProvider(uri);
    947                     }
    948                     releaseUnstableProvider(unstableProvider);
    949                     ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
    950                             fd.getParcelFileDescriptor(), stableProvider);
    951 
    952                     // Success!  Don't release the provider when exiting, let
    953                     // ParcelFileDescriptorInner do that when it is closed.
    954                     stableProvider = null;
    955 
    956                     return new AssetFileDescriptor(pfd, fd.getStartOffset(),
    957                             fd.getDeclaredLength());
    958 
    959                 } catch (RemoteException e) {
    960                     // Whatever, whatever, we'll go away.
    961                     throw new FileNotFoundException(
    962                             "Failed opening content provider: " + uri);
    963                 } catch (FileNotFoundException e) {
    964                     throw e;
    965                 } finally {
    966                     if (cancellationSignal != null) {
    967                         cancellationSignal.setRemote(null);
    968                     }
    969                     if (stableProvider != null) {
    970                         releaseProvider(stableProvider);
    971                     }
    972                     if (unstableProvider != null) {
    973                         releaseUnstableProvider(unstableProvider);
    974                     }
    975                 }
    976             }
    977         }
    978     }
    979 
    980     /**
    981      * Open a raw file descriptor to access (potentially type transformed)
    982      * data from a "content:" URI.  This interacts with the underlying
    983      * {@link ContentProvider#openTypedAssetFile} method of the provider
    984      * associated with the given URI, to retrieve retrieve any appropriate
    985      * data stream for the data stored there.
    986      *
    987      * <p>Unlike {@link #openAssetFileDescriptor}, this function only works
    988      * with "content:" URIs, because content providers are the only facility
    989      * with an associated MIME type to ensure that the returned data stream
    990      * is of the desired type.
    991      *
    992      * <p>All text/* streams are encoded in UTF-8.
    993      *
    994      * @param uri The desired URI to open.
    995      * @param mimeType The desired MIME type of the returned data.  This can
    996      * be a pattern such as *\/*, which will allow the content provider to
    997      * select a type, though there is no way for you to determine what type
    998      * it is returning.
    999      * @param opts Additional provider-dependent options.
   1000      * @return Returns a new ParcelFileDescriptor from which you can read the
   1001      * data stream from the provider.  Note that this may be a pipe, meaning
   1002      * you can't seek in it.  The only seek you should do is if the
   1003      * AssetFileDescriptor contains an offset, to move to that offset before
   1004      * reading.  You own this descriptor and are responsible for closing it when done.
   1005      * @throws FileNotFoundException Throws FileNotFoundException of no
   1006      * data of the desired type exists under the URI.
   1007      */
   1008     public final AssetFileDescriptor openTypedAssetFileDescriptor(
   1009             Uri uri, String mimeType, Bundle opts) throws FileNotFoundException {
   1010         return openTypedAssetFileDescriptor(uri, mimeType, opts, null);
   1011     }
   1012 
   1013     /**
   1014      * Open a raw file descriptor to access (potentially type transformed)
   1015      * data from a "content:" URI.  This interacts with the underlying
   1016      * {@link ContentProvider#openTypedAssetFile} method of the provider
   1017      * associated with the given URI, to retrieve retrieve any appropriate
   1018      * data stream for the data stored there.
   1019      *
   1020      * <p>Unlike {@link #openAssetFileDescriptor}, this function only works
   1021      * with "content:" URIs, because content providers are the only facility
   1022      * with an associated MIME type to ensure that the returned data stream
   1023      * is of the desired type.
   1024      *
   1025      * <p>All text/* streams are encoded in UTF-8.
   1026      *
   1027      * @param uri The desired URI to open.
   1028      * @param mimeType The desired MIME type of the returned data.  This can
   1029      * be a pattern such as *\/*, which will allow the content provider to
   1030      * select a type, though there is no way for you to determine what type
   1031      * it is returning.
   1032      * @param opts Additional provider-dependent options.
   1033      * @param cancellationSignal A signal to cancel the operation in progress,
   1034      *         or null if none. If the operation is canceled, then
   1035      *         {@link OperationCanceledException} will be thrown.
   1036      * @return Returns a new ParcelFileDescriptor from which you can read the
   1037      * data stream from the provider.  Note that this may be a pipe, meaning
   1038      * you can't seek in it.  The only seek you should do is if the
   1039      * AssetFileDescriptor contains an offset, to move to that offset before
   1040      * reading.  You own this descriptor and are responsible for closing it when done.
   1041      * @throws FileNotFoundException Throws FileNotFoundException of no
   1042      * data of the desired type exists under the URI.
   1043      */
   1044     public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
   1045             String mimeType, Bundle opts, CancellationSignal cancellationSignal)
   1046             throws FileNotFoundException {
   1047         IContentProvider unstableProvider = acquireUnstableProvider(uri);
   1048         if (unstableProvider == null) {
   1049             throw new FileNotFoundException("No content provider: " + uri);
   1050         }
   1051         IContentProvider stableProvider = null;
   1052         AssetFileDescriptor fd = null;
   1053 
   1054         try {
   1055             ICancellationSignal remoteCancellationSignal = null;
   1056             if (cancellationSignal != null) {
   1057                 cancellationSignal.throwIfCanceled();
   1058                 remoteCancellationSignal = unstableProvider.createCancellationSignal();
   1059                 cancellationSignal.setRemote(remoteCancellationSignal);
   1060             }
   1061 
   1062             try {
   1063                 fd = unstableProvider.openTypedAssetFile(
   1064                         mPackageName, uri, mimeType, opts, remoteCancellationSignal);
   1065                 if (fd == null) {
   1066                     // The provider will be released by the finally{} clause
   1067                     return null;
   1068                 }
   1069             } catch (DeadObjectException e) {
   1070                 // The remote process has died...  but we only hold an unstable
   1071                 // reference though, so we might recover!!!  Let's try!!!!
   1072                 // This is exciting!!1!!1!!!!1
   1073                 unstableProviderDied(unstableProvider);
   1074                 stableProvider = acquireProvider(uri);
   1075                 if (stableProvider == null) {
   1076                     throw new FileNotFoundException("No content provider: " + uri);
   1077                 }
   1078                 fd = stableProvider.openTypedAssetFile(
   1079                         mPackageName, uri, mimeType, opts, remoteCancellationSignal);
   1080                 if (fd == null) {
   1081                     // The provider will be released by the finally{} clause
   1082                     return null;
   1083                 }
   1084             }
   1085 
   1086             if (stableProvider == null) {
   1087                 stableProvider = acquireProvider(uri);
   1088             }
   1089             releaseUnstableProvider(unstableProvider);
   1090             ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
   1091                     fd.getParcelFileDescriptor(), stableProvider);
   1092 
   1093             // Success!  Don't release the provider when exiting, let
   1094             // ParcelFileDescriptorInner do that when it is closed.
   1095             stableProvider = null;
   1096 
   1097             return new AssetFileDescriptor(pfd, fd.getStartOffset(),
   1098                     fd.getDeclaredLength());
   1099 
   1100         } catch (RemoteException e) {
   1101             // Whatever, whatever, we'll go away.
   1102             throw new FileNotFoundException(
   1103                     "Failed opening content provider: " + uri);
   1104         } catch (FileNotFoundException e) {
   1105             throw e;
   1106         } finally {
   1107             if (cancellationSignal != null) {
   1108                 cancellationSignal.setRemote(null);
   1109             }
   1110             if (stableProvider != null) {
   1111                 releaseProvider(stableProvider);
   1112             }
   1113             if (unstableProvider != null) {
   1114                 releaseUnstableProvider(unstableProvider);
   1115             }
   1116         }
   1117     }
   1118 
   1119     /**
   1120      * A resource identified by the {@link Resources} that contains it, and a resource id.
   1121      *
   1122      * @hide
   1123      */
   1124     public class OpenResourceIdResult {
   1125         public Resources r;
   1126         public int id;
   1127     }
   1128 
   1129     /**
   1130      * Resolves an android.resource URI to a {@link Resources} and a resource id.
   1131      *
   1132      * @hide
   1133      */
   1134     public OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException {
   1135         String authority = uri.getAuthority();
   1136         Resources r;
   1137         if (TextUtils.isEmpty(authority)) {
   1138             throw new FileNotFoundException("No authority: " + uri);
   1139         } else {
   1140             try {
   1141                 r = mContext.getPackageManager().getResourcesForApplication(authority);
   1142             } catch (NameNotFoundException ex) {
   1143                 throw new FileNotFoundException("No package found for authority: " + uri);
   1144             }
   1145         }
   1146         List<String> path = uri.getPathSegments();
   1147         if (path == null) {
   1148             throw new FileNotFoundException("No path: " + uri);
   1149         }
   1150         int len = path.size();
   1151         int id;
   1152         if (len == 1) {
   1153             try {
   1154                 id = Integer.parseInt(path.get(0));
   1155             } catch (NumberFormatException e) {
   1156                 throw new FileNotFoundException("Single path segment is not a resource ID: " + uri);
   1157             }
   1158         } else if (len == 2) {
   1159             id = r.getIdentifier(path.get(1), path.get(0), authority);
   1160         } else {
   1161             throw new FileNotFoundException("More than two path segments: " + uri);
   1162         }
   1163         if (id == 0) {
   1164             throw new FileNotFoundException("No resource found for: " + uri);
   1165         }
   1166         OpenResourceIdResult res = new OpenResourceIdResult();
   1167         res.r = r;
   1168         res.id = id;
   1169         return res;
   1170     }
   1171 
   1172     /**
   1173      * Inserts a row into a table at the given URL.
   1174      *
   1175      * If the content provider supports transactions the insertion will be atomic.
   1176      *
   1177      * @param url The URL of the table to insert into.
   1178      * @param values The initial values for the newly inserted row. The key is the column name for
   1179      *               the field. Passing an empty ContentValues will create an empty row.
   1180      * @return the URL of the newly created row.
   1181      */
   1182     public final Uri insert(Uri url, ContentValues values)
   1183     {
   1184         IContentProvider provider = acquireProvider(url);
   1185         if (provider == null) {
   1186             throw new IllegalArgumentException("Unknown URL " + url);
   1187         }
   1188         try {
   1189             long startTime = SystemClock.uptimeMillis();
   1190             Uri createdRow = provider.insert(mPackageName, url, values);
   1191             long durationMillis = SystemClock.uptimeMillis() - startTime;
   1192             maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
   1193             return createdRow;
   1194         } catch (RemoteException e) {
   1195             // Arbitrary and not worth documenting, as Activity
   1196             // Manager will kill this process shortly anyway.
   1197             return null;
   1198         } finally {
   1199             releaseProvider(provider);
   1200         }
   1201     }
   1202 
   1203     /**
   1204      * Applies each of the {@link ContentProviderOperation} objects and returns an array
   1205      * of their results. Passes through OperationApplicationException, which may be thrown
   1206      * by the call to {@link ContentProviderOperation#apply}.
   1207      * If all the applications succeed then a {@link ContentProviderResult} array with the
   1208      * same number of elements as the operations will be returned. It is implementation-specific
   1209      * how many, if any, operations will have been successfully applied if a call to
   1210      * apply results in a {@link OperationApplicationException}.
   1211      * @param authority the authority of the ContentProvider to which this batch should be applied
   1212      * @param operations the operations to apply
   1213      * @return the results of the applications
   1214      * @throws OperationApplicationException thrown if an application fails.
   1215      * See {@link ContentProviderOperation#apply} for more information.
   1216      * @throws RemoteException thrown if a RemoteException is encountered while attempting
   1217      *   to communicate with a remote provider.
   1218      */
   1219     public ContentProviderResult[] applyBatch(String authority,
   1220             ArrayList<ContentProviderOperation> operations)
   1221             throws RemoteException, OperationApplicationException {
   1222         ContentProviderClient provider = acquireContentProviderClient(authority);
   1223         if (provider == null) {
   1224             throw new IllegalArgumentException("Unknown authority " + authority);
   1225         }
   1226         try {
   1227             return provider.applyBatch(operations);
   1228         } finally {
   1229             provider.release();
   1230         }
   1231     }
   1232 
   1233     /**
   1234      * Inserts multiple rows into a table at the given URL.
   1235      *
   1236      * This function make no guarantees about the atomicity of the insertions.
   1237      *
   1238      * @param url The URL of the table to insert into.
   1239      * @param values The initial values for the newly inserted rows. The key is the column name for
   1240      *               the field. Passing null will create an empty row.
   1241      * @return the number of newly created rows.
   1242      */
   1243     public final int bulkInsert(Uri url, ContentValues[] values)
   1244     {
   1245         IContentProvider provider = acquireProvider(url);
   1246         if (provider == null) {
   1247             throw new IllegalArgumentException("Unknown URL " + url);
   1248         }
   1249         try {
   1250             long startTime = SystemClock.uptimeMillis();
   1251             int rowsCreated = provider.bulkInsert(mPackageName, url, values);
   1252             long durationMillis = SystemClock.uptimeMillis() - startTime;
   1253             maybeLogUpdateToEventLog(durationMillis, url, "bulkinsert", null /* where */);
   1254             return rowsCreated;
   1255         } catch (RemoteException e) {
   1256             // Arbitrary and not worth documenting, as Activity
   1257             // Manager will kill this process shortly anyway.
   1258             return 0;
   1259         } finally {
   1260             releaseProvider(provider);
   1261         }
   1262     }
   1263 
   1264     /**
   1265      * Deletes row(s) specified by a content URI.
   1266      *
   1267      * If the content provider supports transactions, the deletion will be atomic.
   1268      *
   1269      * @param url The URL of the row to delete.
   1270      * @param where A filter to apply to rows before deleting, formatted as an SQL WHERE clause
   1271                     (excluding the WHERE itself).
   1272      * @return The number of rows deleted.
   1273      */
   1274     public final int delete(Uri url, String where, String[] selectionArgs)
   1275     {
   1276         IContentProvider provider = acquireProvider(url);
   1277         if (provider == null) {
   1278             throw new IllegalArgumentException("Unknown URL " + url);
   1279         }
   1280         try {
   1281             long startTime = SystemClock.uptimeMillis();
   1282             int rowsDeleted = provider.delete(mPackageName, url, where, selectionArgs);
   1283             long durationMillis = SystemClock.uptimeMillis() - startTime;
   1284             maybeLogUpdateToEventLog(durationMillis, url, "delete", where);
   1285             return rowsDeleted;
   1286         } catch (RemoteException e) {
   1287             // Arbitrary and not worth documenting, as Activity
   1288             // Manager will kill this process shortly anyway.
   1289             return -1;
   1290         } finally {
   1291             releaseProvider(provider);
   1292         }
   1293     }
   1294 
   1295     /**
   1296      * Update row(s) in a content URI.
   1297      *
   1298      * If the content provider supports transactions the update will be atomic.
   1299      *
   1300      * @param uri The URI to modify.
   1301      * @param values The new field values. The key is the column name for the field.
   1302                      A null value will remove an existing field value.
   1303      * @param where A filter to apply to rows before updating, formatted as an SQL WHERE clause
   1304                     (excluding the WHERE itself).
   1305      * @return the number of rows updated.
   1306      * @throws NullPointerException if uri or values are null
   1307      */
   1308     public final int update(Uri uri, ContentValues values, String where,
   1309             String[] selectionArgs) {
   1310         IContentProvider provider = acquireProvider(uri);
   1311         if (provider == null) {
   1312             throw new IllegalArgumentException("Unknown URI " + uri);
   1313         }
   1314         try {
   1315             long startTime = SystemClock.uptimeMillis();
   1316             int rowsUpdated = provider.update(mPackageName, uri, values, where, selectionArgs);
   1317             long durationMillis = SystemClock.uptimeMillis() - startTime;
   1318             maybeLogUpdateToEventLog(durationMillis, uri, "update", where);
   1319             return rowsUpdated;
   1320         } catch (RemoteException e) {
   1321             // Arbitrary and not worth documenting, as Activity
   1322             // Manager will kill this process shortly anyway.
   1323             return -1;
   1324         } finally {
   1325             releaseProvider(provider);
   1326         }
   1327     }
   1328 
   1329     /**
   1330      * Call a provider-defined method.  This can be used to implement
   1331      * read or write interfaces which are cheaper than using a Cursor and/or
   1332      * do not fit into the traditional table model.
   1333      *
   1334      * @param method provider-defined method name to call.  Opaque to
   1335      *   framework, but must be non-null.
   1336      * @param arg provider-defined String argument.  May be null.
   1337      * @param extras provider-defined Bundle argument.  May be null.
   1338      * @return a result Bundle, possibly null.  Will be null if the ContentProvider
   1339      *   does not implement call.
   1340      * @throws NullPointerException if uri or method is null
   1341      * @throws IllegalArgumentException if uri is not known
   1342      */
   1343     public final Bundle call(Uri uri, String method, String arg, Bundle extras) {
   1344         if (uri == null) {
   1345             throw new NullPointerException("uri == null");
   1346         }
   1347         if (method == null) {
   1348             throw new NullPointerException("method == null");
   1349         }
   1350         IContentProvider provider = acquireProvider(uri);
   1351         if (provider == null) {
   1352             throw new IllegalArgumentException("Unknown URI " + uri);
   1353         }
   1354         try {
   1355             return provider.call(mPackageName, method, arg, extras);
   1356         } catch (RemoteException e) {
   1357             // Arbitrary and not worth documenting, as Activity
   1358             // Manager will kill this process shortly anyway.
   1359             return null;
   1360         } finally {
   1361             releaseProvider(provider);
   1362         }
   1363     }
   1364 
   1365     /**
   1366      * Returns the content provider for the given content URI.
   1367      *
   1368      * @param uri The URI to a content provider
   1369      * @return The ContentProvider for the given URI, or null if no content provider is found.
   1370      * @hide
   1371      */
   1372     public final IContentProvider acquireProvider(Uri uri) {
   1373         if (!SCHEME_CONTENT.equals(uri.getScheme())) {
   1374             return null;
   1375         }
   1376         final String auth = uri.getAuthority();
   1377         if (auth != null) {
   1378             return acquireProvider(mContext, auth);
   1379         }
   1380         return null;
   1381     }
   1382 
   1383     /**
   1384      * Returns the content provider for the given content URI if the process
   1385      * already has a reference on it.
   1386      *
   1387      * @param uri The URI to a content provider
   1388      * @return The ContentProvider for the given URI, or null if no content provider is found.
   1389      * @hide
   1390      */
   1391     public final IContentProvider acquireExistingProvider(Uri uri) {
   1392         if (!SCHEME_CONTENT.equals(uri.getScheme())) {
   1393             return null;
   1394         }
   1395         final String auth = uri.getAuthority();
   1396         if (auth != null) {
   1397             return acquireExistingProvider(mContext, auth);
   1398         }
   1399         return null;
   1400     }
   1401 
   1402     /**
   1403      * @hide
   1404      */
   1405     public final IContentProvider acquireProvider(String name) {
   1406         if (name == null) {
   1407             return null;
   1408         }
   1409         return acquireProvider(mContext, name);
   1410     }
   1411 
   1412     /**
   1413      * Returns the content provider for the given content URI.
   1414      *
   1415      * @param uri The URI to a content provider
   1416      * @return The ContentProvider for the given URI, or null if no content provider is found.
   1417      * @hide
   1418      */
   1419     public final IContentProvider acquireUnstableProvider(Uri uri) {
   1420         if (!SCHEME_CONTENT.equals(uri.getScheme())) {
   1421             return null;
   1422         }
   1423         String auth = uri.getAuthority();
   1424         if (auth != null) {
   1425             return acquireUnstableProvider(mContext, uri.getAuthority());
   1426         }
   1427         return null;
   1428     }
   1429 
   1430     /**
   1431      * @hide
   1432      */
   1433     public final IContentProvider acquireUnstableProvider(String name) {
   1434         if (name == null) {
   1435             return null;
   1436         }
   1437         return acquireUnstableProvider(mContext, name);
   1438     }
   1439 
   1440     /**
   1441      * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
   1442      * that services the content at uri, starting the provider if necessary. Returns
   1443      * null if there is no provider associated wih the uri. The caller must indicate that they are
   1444      * done with the provider by calling {@link ContentProviderClient#release} which will allow
   1445      * the system to release the provider it it determines that there is no other reason for
   1446      * keeping it active.
   1447      * @param uri specifies which provider should be acquired
   1448      * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
   1449      * that services the content at uri or null if there isn't one.
   1450      */
   1451     public final ContentProviderClient acquireContentProviderClient(Uri uri) {
   1452         IContentProvider provider = acquireProvider(uri);
   1453         if (provider != null) {
   1454             return new ContentProviderClient(this, provider, true);
   1455         }
   1456 
   1457         return null;
   1458     }
   1459 
   1460     /**
   1461      * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
   1462      * with the authority of name, starting the provider if necessary. Returns
   1463      * null if there is no provider associated wih the uri. The caller must indicate that they are
   1464      * done with the provider by calling {@link ContentProviderClient#release} which will allow
   1465      * the system to release the provider it it determines that there is no other reason for
   1466      * keeping it active.
   1467      * @param name specifies which provider should be acquired
   1468      * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
   1469      * with the authority of name or null if there isn't one.
   1470      */
   1471     public final ContentProviderClient acquireContentProviderClient(String name) {
   1472         IContentProvider provider = acquireProvider(name);
   1473         if (provider != null) {
   1474             return new ContentProviderClient(this, provider, true);
   1475         }
   1476 
   1477         return null;
   1478     }
   1479 
   1480     /**
   1481      * Like {@link #acquireContentProviderClient(Uri)}, but for use when you do
   1482      * not trust the stability of the target content provider.  This turns off
   1483      * the mechanism in the platform clean up processes that are dependent on
   1484      * a content provider if that content provider's process goes away.  Normally
   1485      * you can safely assume that once you have acquired a provider, you can freely
   1486      * use it as needed and it won't disappear, even if your process is in the
   1487      * background.  If using this method, you need to take care to deal with any
   1488      * failures when communicating with the provider, and be sure to close it
   1489      * so that it can be re-opened later.  In particular, catching a
   1490      * {@link android.os.DeadObjectException} from the calls there will let you
   1491      * know that the content provider has gone away; at that point the current
   1492      * ContentProviderClient object is invalid, and you should release it.  You
   1493      * can acquire a new one if you would like to try to restart the provider
   1494      * and perform new operations on it.
   1495      */
   1496     public final ContentProviderClient acquireUnstableContentProviderClient(Uri uri) {
   1497         IContentProvider provider = acquireUnstableProvider(uri);
   1498         if (provider != null) {
   1499             return new ContentProviderClient(this, provider, false);
   1500         }
   1501 
   1502         return null;
   1503     }
   1504 
   1505     /**
   1506      * Like {@link #acquireContentProviderClient(String)}, but for use when you do
   1507      * not trust the stability of the target content provider.  This turns off
   1508      * the mechanism in the platform clean up processes that are dependent on
   1509      * a content provider if that content provider's process goes away.  Normally
   1510      * you can safely assume that once you have acquired a provider, you can freely
   1511      * use it as needed and it won't disappear, even if your process is in the
   1512      * background.  If using this method, you need to take care to deal with any
   1513      * failures when communicating with the provider, and be sure to close it
   1514      * so that it can be re-opened later.  In particular, catching a
   1515      * {@link android.os.DeadObjectException} from the calls there will let you
   1516      * know that the content provider has gone away; at that point the current
   1517      * ContentProviderClient object is invalid, and you should release it.  You
   1518      * can acquire a new one if you would like to try to restart the provider
   1519      * and perform new operations on it.
   1520      */
   1521     public final ContentProviderClient acquireUnstableContentProviderClient(String name) {
   1522         IContentProvider provider = acquireUnstableProvider(name);
   1523         if (provider != null) {
   1524             return new ContentProviderClient(this, provider, false);
   1525         }
   1526 
   1527         return null;
   1528     }
   1529 
   1530     /**
   1531      * Register an observer class that gets callbacks when data identified by a
   1532      * given content URI changes.
   1533      *
   1534      * @param uri The URI to watch for changes. This can be a specific row URI, or a base URI
   1535      * for a whole class of content.
   1536      * @param notifyForDescendents If <code>true</code> changes to URIs beginning with <code>uri</code>
   1537      * will also cause notifications to be sent. If <code>false</code> only changes to the exact URI
   1538      * specified by <em>uri</em> will cause notifications to be sent. If true, than any URI values
   1539      * at or below the specified URI will also trigger a match.
   1540      * @param observer The object that receives callbacks when changes occur.
   1541      * @see #unregisterContentObserver
   1542      */
   1543     public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
   1544             ContentObserver observer)
   1545     {
   1546         registerContentObserver(uri, notifyForDescendents, observer, UserHandle.myUserId());
   1547     }
   1548 
   1549     /** @hide - designated user version */
   1550     public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
   1551             ContentObserver observer, int userHandle)
   1552     {
   1553         try {
   1554             getContentService().registerContentObserver(uri, notifyForDescendents,
   1555                     observer.getContentObserver(), userHandle);
   1556         } catch (RemoteException e) {
   1557         }
   1558     }
   1559 
   1560     /**
   1561      * Unregisters a change observer.
   1562      *
   1563      * @param observer The previously registered observer that is no longer needed.
   1564      * @see #registerContentObserver
   1565      */
   1566     public final void unregisterContentObserver(ContentObserver observer) {
   1567         try {
   1568             IContentObserver contentObserver = observer.releaseContentObserver();
   1569             if (contentObserver != null) {
   1570                 getContentService().unregisterContentObserver(
   1571                         contentObserver);
   1572             }
   1573         } catch (RemoteException e) {
   1574         }
   1575     }
   1576 
   1577     /**
   1578      * Notify registered observers that a row was updated and attempt to sync changes
   1579      * to the network.
   1580      * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
   1581      * By default, CursorAdapter objects will get this notification.
   1582      *
   1583      * @param uri The uri of the content that was changed.
   1584      * @param observer The observer that originated the change, may be <code>null</null>.
   1585      * The observer that originated the change will only receive the notification if it
   1586      * has requested to receive self-change notifications by implementing
   1587      * {@link ContentObserver#deliverSelfNotifications()} to return true.
   1588      */
   1589     public void notifyChange(Uri uri, ContentObserver observer) {
   1590         notifyChange(uri, observer, true /* sync to network */);
   1591     }
   1592 
   1593     /**
   1594      * Notify registered observers that a row was updated.
   1595      * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
   1596      * By default, CursorAdapter objects will get this notification.
   1597      * If syncToNetwork is true, this will attempt to schedule a local sync using the sync
   1598      * adapter that's registered for the authority of the provided uri. No account will be
   1599      * passed to the sync adapter, so all matching accounts will be synchronized.
   1600      *
   1601      * @param uri The uri of the content that was changed.
   1602      * @param observer The observer that originated the change, may be <code>null</null>.
   1603      * The observer that originated the change will only receive the notification if it
   1604      * has requested to receive self-change notifications by implementing
   1605      * {@link ContentObserver#deliverSelfNotifications()} to return true.
   1606      * @param syncToNetwork If true, attempt to sync the change to the network.
   1607      * @see #requestSync(android.accounts.Account, String, android.os.Bundle)
   1608      */
   1609     public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
   1610         notifyChange(uri, observer, syncToNetwork, UserHandle.getCallingUserId());
   1611     }
   1612 
   1613     /**
   1614      * Notify registered observers within the designated user(s) that a row was updated.
   1615      *
   1616      * @hide
   1617      */
   1618     public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork,
   1619             int userHandle) {
   1620         try {
   1621             getContentService().notifyChange(
   1622                     uri, observer == null ? null : observer.getContentObserver(),
   1623                     observer != null && observer.deliverSelfNotifications(), syncToNetwork,
   1624                     userHandle);
   1625         } catch (RemoteException e) {
   1626         }
   1627     }
   1628 
   1629     /**
   1630      * Take a persistable URI permission grant that has been offered. Once
   1631      * taken, the permission grant will be remembered across device reboots.
   1632      * Only URI permissions granted with
   1633      * {@link Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION} can be persisted. If
   1634      * the grant has already been persisted, taking it again will touch
   1635      * {@link UriPermission#getPersistedTime()}.
   1636      *
   1637      * @see #getPersistedUriPermissions()
   1638      */
   1639     public void takePersistableUriPermission(Uri uri, int modeFlags) {
   1640         try {
   1641             ActivityManagerNative.getDefault().takePersistableUriPermission(uri, modeFlags);
   1642         } catch (RemoteException e) {
   1643         }
   1644     }
   1645 
   1646     /**
   1647      * Relinquish a persisted URI permission grant. The URI must have been
   1648      * previously made persistent with
   1649      * {@link #takePersistableUriPermission(Uri, int)}. Any non-persistent
   1650      * grants to the calling package will remain intact.
   1651      *
   1652      * @see #getPersistedUriPermissions()
   1653      */
   1654     public void releasePersistableUriPermission(Uri uri, int modeFlags) {
   1655         try {
   1656             ActivityManagerNative.getDefault().releasePersistableUriPermission(uri, modeFlags);
   1657         } catch (RemoteException e) {
   1658         }
   1659     }
   1660 
   1661     /**
   1662      * Return list of all URI permission grants that have been persisted by the
   1663      * calling app. That is, the returned permissions have been granted
   1664      * <em>to</em> the calling app. Only persistable grants taken with
   1665      * {@link #takePersistableUriPermission(Uri, int)} are returned.
   1666      *
   1667      * @see #takePersistableUriPermission(Uri, int)
   1668      * @see #releasePersistableUriPermission(Uri, int)
   1669      */
   1670     public List<UriPermission> getPersistedUriPermissions() {
   1671         try {
   1672             return ActivityManagerNative.getDefault()
   1673                     .getPersistedUriPermissions(mPackageName, true).getList();
   1674         } catch (RemoteException e) {
   1675             throw new RuntimeException("Activity manager has died", e);
   1676         }
   1677     }
   1678 
   1679     /**
   1680      * Return list of all persisted URI permission grants that are hosted by the
   1681      * calling app. That is, the returned permissions have been granted
   1682      * <em>from</em> the calling app. Only grants taken with
   1683      * {@link #takePersistableUriPermission(Uri, int)} are returned.
   1684      */
   1685     public List<UriPermission> getOutgoingPersistedUriPermissions() {
   1686         try {
   1687             return ActivityManagerNative.getDefault()
   1688                     .getPersistedUriPermissions(mPackageName, false).getList();
   1689         } catch (RemoteException e) {
   1690             throw new RuntimeException("Activity manager has died", e);
   1691         }
   1692     }
   1693 
   1694     /**
   1695      * Start an asynchronous sync operation. If you want to monitor the progress
   1696      * of the sync you may register a SyncObserver. Only values of the following
   1697      * types may be used in the extras bundle:
   1698      * <ul>
   1699      * <li>Integer</li>
   1700      * <li>Long</li>
   1701      * <li>Boolean</li>
   1702      * <li>Float</li>
   1703      * <li>Double</li>
   1704      * <li>String</li>
   1705      * <li>Account</li>
   1706      * <li>null</li>
   1707      * </ul>
   1708      *
   1709      * @param uri the uri of the provider to sync or null to sync all providers.
   1710      * @param extras any extras to pass to the SyncAdapter.
   1711      * @deprecated instead use
   1712      * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
   1713      */
   1714     @Deprecated
   1715     public void startSync(Uri uri, Bundle extras) {
   1716         Account account = null;
   1717         if (extras != null) {
   1718             String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT);
   1719             if (!TextUtils.isEmpty(accountName)) {
   1720                 account = new Account(accountName, "com.google");
   1721             }
   1722             extras.remove(SYNC_EXTRAS_ACCOUNT);
   1723         }
   1724         requestSync(account, uri != null ? uri.getAuthority() : null, extras);
   1725     }
   1726 
   1727     /**
   1728      * Start an asynchronous sync operation. If you want to monitor the progress
   1729      * of the sync you may register a SyncObserver. Only values of the following
   1730      * types may be used in the extras bundle:
   1731      * <ul>
   1732      * <li>Integer</li>
   1733      * <li>Long</li>
   1734      * <li>Boolean</li>
   1735      * <li>Float</li>
   1736      * <li>Double</li>
   1737      * <li>String</li>
   1738      * <li>Account</li>
   1739      * <li>null</li>
   1740      * </ul>
   1741      *
   1742      * @param account which account should be synced
   1743      * @param authority which authority should be synced
   1744      * @param extras any extras to pass to the SyncAdapter.
   1745      */
   1746     public static void requestSync(Account account, String authority, Bundle extras) {
   1747         if (extras == null) {
   1748             throw new IllegalArgumentException("Must specify extras.");
   1749         }
   1750         SyncRequest request =
   1751             new SyncRequest.Builder()
   1752                 .setSyncAdapter(account, authority)
   1753                 .setExtras(extras)
   1754                 .syncOnce()
   1755                 .build();
   1756         requestSync(request);
   1757     }
   1758 
   1759     /**
   1760      * Register a sync with the SyncManager. These requests are built using the
   1761      * {@link SyncRequest.Builder}.
   1762      *
   1763      * @param request The immutable SyncRequest object containing the sync parameters. Use
   1764      * {@link SyncRequest.Builder} to construct these.
   1765      */
   1766     public static void requestSync(SyncRequest request) {
   1767         try {
   1768             getContentService().sync(request);
   1769         } catch(RemoteException e) {
   1770             // Shouldn't happen.
   1771         }
   1772     }
   1773 
   1774     /**
   1775      * Check that only values of the following types are in the Bundle:
   1776      * <ul>
   1777      * <li>Integer</li>
   1778      * <li>Long</li>
   1779      * <li>Boolean</li>
   1780      * <li>Float</li>
   1781      * <li>Double</li>
   1782      * <li>String</li>
   1783      * <li>Account</li>
   1784      * <li>null</li>
   1785      * </ul>
   1786      * @param extras the Bundle to check
   1787      */
   1788     public static void validateSyncExtrasBundle(Bundle extras) {
   1789         try {
   1790             for (String key : extras.keySet()) {
   1791                 Object value = extras.get(key);
   1792                 if (value == null) continue;
   1793                 if (value instanceof Long) continue;
   1794                 if (value instanceof Integer) continue;
   1795                 if (value instanceof Boolean) continue;
   1796                 if (value instanceof Float) continue;
   1797                 if (value instanceof Double) continue;
   1798                 if (value instanceof String) continue;
   1799                 if (value instanceof Account) continue;
   1800                 throw new IllegalArgumentException("unexpected value type: "
   1801                         + value.getClass().getName());
   1802             }
   1803         } catch (IllegalArgumentException e) {
   1804             throw e;
   1805         } catch (RuntimeException exc) {
   1806             throw new IllegalArgumentException("error unparceling Bundle", exc);
   1807         }
   1808     }
   1809 
   1810     /**
   1811      * Cancel any active or pending syncs that match the Uri. If the uri is null then
   1812      * all syncs will be canceled.
   1813      *
   1814      * @param uri the uri of the provider to sync or null to sync all providers.
   1815      * @deprecated instead use {@link #cancelSync(android.accounts.Account, String)}
   1816      */
   1817     @Deprecated
   1818     public void cancelSync(Uri uri) {
   1819         cancelSync(null /* all accounts */, uri != null ? uri.getAuthority() : null);
   1820     }
   1821 
   1822     /**
   1823      * Cancel any active or pending syncs that match account and authority. The account and
   1824      * authority can each independently be set to null, which means that syncs with any account
   1825      * or authority, respectively, will match.
   1826      *
   1827      * @param account filters the syncs that match by this account
   1828      * @param authority filters the syncs that match by this authority
   1829      */
   1830     public static void cancelSync(Account account, String authority) {
   1831         try {
   1832             getContentService().cancelSync(account, authority);
   1833         } catch (RemoteException e) {
   1834         }
   1835     }
   1836 
   1837     /**
   1838      * Get information about the SyncAdapters that are known to the system.
   1839      * @return an array of SyncAdapters that have registered with the system
   1840      */
   1841     public static SyncAdapterType[] getSyncAdapterTypes() {
   1842         try {
   1843             return getContentService().getSyncAdapterTypes();
   1844         } catch (RemoteException e) {
   1845             throw new RuntimeException("the ContentService should always be reachable", e);
   1846         }
   1847     }
   1848 
   1849     /**
   1850      * Check if the provider should be synced when a network tickle is received
   1851      * <p>This method requires the caller to hold the permission
   1852      * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
   1853      *
   1854      * @param account the account whose setting we are querying
   1855      * @param authority the provider whose setting we are querying
   1856      * @return true if the provider should be synced when a network tickle is received
   1857      */
   1858     public static boolean getSyncAutomatically(Account account, String authority) {
   1859         try {
   1860             return getContentService().getSyncAutomatically(account, authority);
   1861         } catch (RemoteException e) {
   1862             throw new RuntimeException("the ContentService should always be reachable", e);
   1863         }
   1864     }
   1865 
   1866     /**
   1867      * Set whether or not the provider is synced when it receives a network tickle.
   1868      * <p>This method requires the caller to hold the permission
   1869      * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
   1870      *
   1871      * @param account the account whose setting we are querying
   1872      * @param authority the provider whose behavior is being controlled
   1873      * @param sync true if the provider should be synced when tickles are received for it
   1874      */
   1875     public static void setSyncAutomatically(Account account, String authority, boolean sync) {
   1876         try {
   1877             getContentService().setSyncAutomatically(account, authority, sync);
   1878         } catch (RemoteException e) {
   1879             // exception ignored; if this is thrown then it means the runtime is in the midst of
   1880             // being restarted
   1881         }
   1882     }
   1883 
   1884     /**
   1885      * Specifies that a sync should be requested with the specified the account, authority,
   1886      * and extras at the given frequency. If there is already another periodic sync scheduled
   1887      * with the account, authority and extras then a new periodic sync won't be added, instead
   1888      * the frequency of the previous one will be updated.
   1889      * <p>
   1890      * These periodic syncs honor the "syncAutomatically" and "masterSyncAutomatically" settings.
   1891      * Although these sync are scheduled at the specified frequency, it may take longer for it to
   1892      * actually be started if other syncs are ahead of it in the sync operation queue. This means
   1893      * that the actual start time may drift.
   1894      * <p>
   1895      * Periodic syncs are not allowed to have any of {@link #SYNC_EXTRAS_DO_NOT_RETRY},
   1896      * {@link #SYNC_EXTRAS_IGNORE_BACKOFF}, {@link #SYNC_EXTRAS_IGNORE_SETTINGS},
   1897      * {@link #SYNC_EXTRAS_INITIALIZE}, {@link #SYNC_EXTRAS_FORCE},
   1898      * {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL} set to true.
   1899      * If any are supplied then an {@link IllegalArgumentException} will be thrown.
   1900      * <p>As of API level 19 this function introduces a default flexibility of ~4% (up to a maximum
   1901      * of one hour in the day) into the requested period. Use
   1902      * {@link SyncRequest.Builder#syncPeriodic(long, long)} to set this flexibility manually.
   1903      *
   1904      * <p>This method requires the caller to hold the permission
   1905      * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
   1906      *
   1907      * @param account the account to specify in the sync
   1908      * @param authority the provider to specify in the sync request
   1909      * @param extras extra parameters to go along with the sync request
   1910      * @param pollFrequency how frequently the sync should be performed, in seconds.
   1911      * @throws IllegalArgumentException if an illegal extra was set or if any of the parameters
   1912      * are null.
   1913      */
   1914     public static void addPeriodicSync(Account account, String authority, Bundle extras,
   1915             long pollFrequency) {
   1916         validateSyncExtrasBundle(extras);
   1917         if (extras.getBoolean(SYNC_EXTRAS_MANUAL, false)
   1918                 || extras.getBoolean(SYNC_EXTRAS_DO_NOT_RETRY, false)
   1919                 || extras.getBoolean(SYNC_EXTRAS_IGNORE_BACKOFF, false)
   1920                 || extras.getBoolean(SYNC_EXTRAS_IGNORE_SETTINGS, false)
   1921                 || extras.getBoolean(SYNC_EXTRAS_INITIALIZE, false)
   1922                 || extras.getBoolean(SYNC_EXTRAS_FORCE, false)
   1923                 || extras.getBoolean(SYNC_EXTRAS_EXPEDITED, false)) {
   1924             throw new IllegalArgumentException("illegal extras were set");
   1925         }
   1926         try {
   1927              getContentService().addPeriodicSync(account, authority, extras, pollFrequency);
   1928         } catch (RemoteException e) {
   1929             // exception ignored; if this is thrown then it means the runtime is in the midst of
   1930             // being restarted
   1931         }
   1932     }
   1933 
   1934     /**
   1935      * Remove a periodic sync. Has no affect if account, authority and extras don't match
   1936      * an existing periodic sync.
   1937      * <p>This method requires the caller to hold the permission
   1938      * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
   1939      *
   1940      * @param account the account of the periodic sync to remove
   1941      * @param authority the provider of the periodic sync to remove
   1942      * @param extras the extras of the periodic sync to remove
   1943      */
   1944     public static void removePeriodicSync(Account account, String authority, Bundle extras) {
   1945         validateSyncExtrasBundle(extras);
   1946         try {
   1947             getContentService().removePeriodicSync(account, authority, extras);
   1948         } catch (RemoteException e) {
   1949             throw new RuntimeException("the ContentService should always be reachable", e);
   1950         }
   1951     }
   1952 
   1953     /**
   1954      * Get the list of information about the periodic syncs for the given account and authority.
   1955      * <p>This method requires the caller to hold the permission
   1956      * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
   1957      *
   1958      * @param account the account whose periodic syncs we are querying
   1959      * @param authority the provider whose periodic syncs we are querying
   1960      * @return a list of PeriodicSync objects. This list may be empty but will never be null.
   1961      */
   1962     public static List<PeriodicSync> getPeriodicSyncs(Account account, String authority) {
   1963         try {
   1964             return getContentService().getPeriodicSyncs(account, authority);
   1965         } catch (RemoteException e) {
   1966             throw new RuntimeException("the ContentService should always be reachable", e);
   1967         }
   1968     }
   1969 
   1970     /**
   1971      * Check if this account/provider is syncable.
   1972      * <p>This method requires the caller to hold the permission
   1973      * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
   1974      * @return >0 if it is syncable, 0 if not, and <0 if the state isn't known yet.
   1975      */
   1976     public static int getIsSyncable(Account account, String authority) {
   1977         try {
   1978             return getContentService().getIsSyncable(account, authority);
   1979         } catch (RemoteException e) {
   1980             throw new RuntimeException("the ContentService should always be reachable", e);
   1981         }
   1982     }
   1983 
   1984     /**
   1985      * Set whether this account/provider is syncable.
   1986      * <p>This method requires the caller to hold the permission
   1987      * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
   1988      * @param syncable >0 denotes syncable, 0 means not syncable, <0 means unknown
   1989      */
   1990     public static void setIsSyncable(Account account, String authority, int syncable) {
   1991         try {
   1992             getContentService().setIsSyncable(account, authority, syncable);
   1993         } catch (RemoteException e) {
   1994             // exception ignored; if this is thrown then it means the runtime is in the midst of
   1995             // being restarted
   1996         }
   1997     }
   1998 
   1999     /**
   2000      * Gets the master auto-sync setting that applies to all the providers and accounts.
   2001      * If this is false then the per-provider auto-sync setting is ignored.
   2002      * <p>This method requires the caller to hold the permission
   2003      * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
   2004      *
   2005      * @return the master auto-sync setting that applies to all the providers and accounts
   2006      */
   2007     public static boolean getMasterSyncAutomatically() {
   2008         try {
   2009             return getContentService().getMasterSyncAutomatically();
   2010         } catch (RemoteException e) {
   2011             throw new RuntimeException("the ContentService should always be reachable", e);
   2012         }
   2013     }
   2014 
   2015     /**
   2016      * Sets the master auto-sync setting that applies to all the providers and accounts.
   2017      * If this is false then the per-provider auto-sync setting is ignored.
   2018      * <p>This method requires the caller to hold the permission
   2019      * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
   2020      *
   2021      * @param sync the master auto-sync setting that applies to all the providers and accounts
   2022      */
   2023     public static void setMasterSyncAutomatically(boolean sync) {
   2024         try {
   2025             getContentService().setMasterSyncAutomatically(sync);
   2026         } catch (RemoteException e) {
   2027             // exception ignored; if this is thrown then it means the runtime is in the midst of
   2028             // being restarted
   2029         }
   2030     }
   2031 
   2032     /**
   2033      * Returns true if there is currently a sync operation for the given
   2034      * account or authority in the pending list, or actively being processed.
   2035      * <p>This method requires the caller to hold the permission
   2036      * {@link android.Manifest.permission#READ_SYNC_STATS}.
   2037      * @param account the account whose setting we are querying
   2038      * @param authority the provider whose behavior is being queried
   2039      * @return true if a sync is active for the given account or authority.
   2040      */
   2041     public static boolean isSyncActive(Account account, String authority) {
   2042         try {
   2043             return getContentService().isSyncActive(account, authority);
   2044         } catch (RemoteException e) {
   2045             throw new RuntimeException("the ContentService should always be reachable", e);
   2046         }
   2047     }
   2048 
   2049     /**
   2050      * If a sync is active returns the information about it, otherwise returns null.
   2051      * <p>
   2052      * This method requires the caller to hold the permission
   2053      * {@link android.Manifest.permission#READ_SYNC_STATS}.
   2054      * <p>
   2055      * @return the SyncInfo for the currently active sync or null if one is not active.
   2056      * @deprecated
   2057      * Since multiple concurrent syncs are now supported you should use
   2058      * {@link #getCurrentSyncs()} to get the accurate list of current syncs.
   2059      * This method returns the first item from the list of current syncs
   2060      * or null if there are none.
   2061      */
   2062     @Deprecated
   2063     public static SyncInfo getCurrentSync() {
   2064         try {
   2065             final List<SyncInfo> syncs = getContentService().getCurrentSyncs();
   2066             if (syncs.isEmpty()) {
   2067                 return null;
   2068             }
   2069             return syncs.get(0);
   2070         } catch (RemoteException e) {
   2071             throw new RuntimeException("the ContentService should always be reachable", e);
   2072         }
   2073     }
   2074 
   2075     /**
   2076      * Returns a list with information about all the active syncs. This list will be empty
   2077      * if there are no active syncs.
   2078      * <p>
   2079      * This method requires the caller to hold the permission
   2080      * {@link android.Manifest.permission#READ_SYNC_STATS}.
   2081      * <p>
   2082      * @return a List of SyncInfo objects for the currently active syncs.
   2083      */
   2084     public static List<SyncInfo> getCurrentSyncs() {
   2085         try {
   2086             return getContentService().getCurrentSyncs();
   2087         } catch (RemoteException e) {
   2088             throw new RuntimeException("the ContentService should always be reachable", e);
   2089         }
   2090     }
   2091 
   2092     /**
   2093      * Returns the status that matches the authority.
   2094      * @param account the account whose setting we are querying
   2095      * @param authority the provider whose behavior is being queried
   2096      * @return the SyncStatusInfo for the authority, or null if none exists
   2097      * @hide
   2098      */
   2099     public static SyncStatusInfo getSyncStatus(Account account, String authority) {
   2100         try {
   2101             return getContentService().getSyncStatus(account, authority);
   2102         } catch (RemoteException e) {
   2103             throw new RuntimeException("the ContentService should always be reachable", e);
   2104         }
   2105     }
   2106 
   2107     /**
   2108      * Return true if the pending status is true of any matching authorities.
   2109      * <p>This method requires the caller to hold the permission
   2110      * {@link android.Manifest.permission#READ_SYNC_STATS}.
   2111      * @param account the account whose setting we are querying
   2112      * @param authority the provider whose behavior is being queried
   2113      * @return true if there is a pending sync with the matching account and authority
   2114      */
   2115     public static boolean isSyncPending(Account account, String authority) {
   2116         try {
   2117             return getContentService().isSyncPending(account, authority);
   2118         } catch (RemoteException e) {
   2119             throw new RuntimeException("the ContentService should always be reachable", e);
   2120         }
   2121     }
   2122 
   2123     /**
   2124      * Request notifications when the different aspects of the SyncManager change. The
   2125      * different items that can be requested are:
   2126      * <ul>
   2127      * <li> {@link #SYNC_OBSERVER_TYPE_PENDING}
   2128      * <li> {@link #SYNC_OBSERVER_TYPE_ACTIVE}
   2129      * <li> {@link #SYNC_OBSERVER_TYPE_SETTINGS}
   2130      * </ul>
   2131      * The caller can set one or more of the status types in the mask for any
   2132      * given listener registration.
   2133      * @param mask the status change types that will cause the callback to be invoked
   2134      * @param callback observer to be invoked when the status changes
   2135      * @return a handle that can be used to remove the listener at a later time
   2136      */
   2137     public static Object addStatusChangeListener(int mask, final SyncStatusObserver callback) {
   2138         if (callback == null) {
   2139             throw new IllegalArgumentException("you passed in a null callback");
   2140         }
   2141         try {
   2142             ISyncStatusObserver.Stub observer = new ISyncStatusObserver.Stub() {
   2143                 public void onStatusChanged(int which) throws RemoteException {
   2144                     callback.onStatusChanged(which);
   2145                 }
   2146             };
   2147             getContentService().addStatusChangeListener(mask, observer);
   2148             return observer;
   2149         } catch (RemoteException e) {
   2150             throw new RuntimeException("the ContentService should always be reachable", e);
   2151         }
   2152     }
   2153 
   2154     /**
   2155      * Remove a previously registered status change listener.
   2156      * @param handle the handle that was returned by {@link #addStatusChangeListener}
   2157      */
   2158     public static void removeStatusChangeListener(Object handle) {
   2159         if (handle == null) {
   2160             throw new IllegalArgumentException("you passed in a null handle");
   2161         }
   2162         try {
   2163             getContentService().removeStatusChangeListener((ISyncStatusObserver.Stub) handle);
   2164         } catch (RemoteException e) {
   2165             // exception ignored; if this is thrown then it means the runtime is in the midst of
   2166             // being restarted
   2167         }
   2168     }
   2169 
   2170     /**
   2171      * Returns sampling percentage for a given duration.
   2172      *
   2173      * Always returns at least 1%.
   2174      */
   2175     private int samplePercentForDuration(long durationMillis) {
   2176         if (durationMillis >= SLOW_THRESHOLD_MILLIS) {
   2177             return 100;
   2178         }
   2179         return (int) (100 * durationMillis / SLOW_THRESHOLD_MILLIS) + 1;
   2180     }
   2181 
   2182     private void maybeLogQueryToEventLog(long durationMillis,
   2183                                          Uri uri, String[] projection,
   2184                                          String selection, String sortOrder) {
   2185         if (!ENABLE_CONTENT_SAMPLE) return;
   2186         int samplePercent = samplePercentForDuration(durationMillis);
   2187         if (samplePercent < 100) {
   2188             synchronized (mRandom) {
   2189                 if (mRandom.nextInt(100) >= samplePercent) {
   2190                     return;
   2191                 }
   2192             }
   2193         }
   2194 
   2195         StringBuilder projectionBuffer = new StringBuilder(100);
   2196         if (projection != null) {
   2197             for (int i = 0; i < projection.length; ++i) {
   2198                 // Note: not using a comma delimiter here, as the
   2199                 // multiple arguments to EventLog.writeEvent later
   2200                 // stringify with a comma delimiter, which would make
   2201                 // parsing uglier later.
   2202                 if (i != 0) projectionBuffer.append('/');
   2203                 projectionBuffer.append(projection[i]);
   2204             }
   2205         }
   2206 
   2207         // ActivityThread.currentPackageName() only returns non-null if the
   2208         // current thread is an application main thread.  This parameter tells
   2209         // us whether an event loop is blocked, and if so, which app it is.
   2210         String blockingPackage = AppGlobals.getInitialPackage();
   2211 
   2212         EventLog.writeEvent(
   2213             EventLogTags.CONTENT_QUERY_SAMPLE,
   2214             uri.toString(),
   2215             projectionBuffer.toString(),
   2216             selection != null ? selection : "",
   2217             sortOrder != null ? sortOrder : "",
   2218             durationMillis,
   2219             blockingPackage != null ? blockingPackage : "",
   2220             samplePercent);
   2221     }
   2222 
   2223     private void maybeLogUpdateToEventLog(
   2224         long durationMillis, Uri uri, String operation, String selection) {
   2225         if (!ENABLE_CONTENT_SAMPLE) return;
   2226         int samplePercent = samplePercentForDuration(durationMillis);
   2227         if (samplePercent < 100) {
   2228             synchronized (mRandom) {
   2229                 if (mRandom.nextInt(100) >= samplePercent) {
   2230                     return;
   2231                 }
   2232             }
   2233         }
   2234         String blockingPackage = AppGlobals.getInitialPackage();
   2235         EventLog.writeEvent(
   2236             EventLogTags.CONTENT_UPDATE_SAMPLE,
   2237             uri.toString(),
   2238             operation,
   2239             selection != null ? selection : "",
   2240             durationMillis,
   2241             blockingPackage != null ? blockingPackage : "",
   2242             samplePercent);
   2243     }
   2244 
   2245     private final class CursorWrapperInner extends CrossProcessCursorWrapper {
   2246         private final IContentProvider mContentProvider;
   2247         public static final String TAG="CursorWrapperInner";
   2248 
   2249         private final CloseGuard mCloseGuard = CloseGuard.get();
   2250         private boolean mProviderReleased;
   2251 
   2252         CursorWrapperInner(Cursor cursor, IContentProvider icp) {
   2253             super(cursor);
   2254             mContentProvider = icp;
   2255             mCloseGuard.open("close");
   2256         }
   2257 
   2258         @Override
   2259         public void close() {
   2260             super.close();
   2261             ContentResolver.this.releaseProvider(mContentProvider);
   2262             mProviderReleased = true;
   2263 
   2264             if (mCloseGuard != null) {
   2265                 mCloseGuard.close();
   2266             }
   2267         }
   2268 
   2269         @Override
   2270         protected void finalize() throws Throwable {
   2271             try {
   2272                 if (mCloseGuard != null) {
   2273                     mCloseGuard.warnIfOpen();
   2274                 }
   2275 
   2276                 if (!mProviderReleased && mContentProvider != null) {
   2277                     // Even though we are using CloseGuard, log this anyway so that
   2278                     // application developers always see the message in the log.
   2279                     Log.w(TAG, "Cursor finalized without prior close()");
   2280                     ContentResolver.this.releaseProvider(mContentProvider);
   2281                 }
   2282             } finally {
   2283                 super.finalize();
   2284             }
   2285         }
   2286     }
   2287 
   2288     private final class ParcelFileDescriptorInner extends ParcelFileDescriptor {
   2289         private final IContentProvider mContentProvider;
   2290         private boolean mProviderReleased;
   2291 
   2292         ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) {
   2293             super(pfd);
   2294             mContentProvider = icp;
   2295         }
   2296 
   2297         @Override
   2298         public void releaseResources() {
   2299             if (!mProviderReleased) {
   2300                 ContentResolver.this.releaseProvider(mContentProvider);
   2301                 mProviderReleased = true;
   2302             }
   2303         }
   2304     }
   2305 
   2306     /** @hide */
   2307     public static final String CONTENT_SERVICE_NAME = "content";
   2308 
   2309     /** @hide */
   2310     public static IContentService getContentService() {
   2311         if (sContentService != null) {
   2312             return sContentService;
   2313         }
   2314         IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME);
   2315         if (false) Log.v("ContentService", "default service binder = " + b);
   2316         sContentService = IContentService.Stub.asInterface(b);
   2317         if (false) Log.v("ContentService", "default service = " + sContentService);
   2318         return sContentService;
   2319     }
   2320 
   2321     /** @hide */
   2322     public String getPackageName() {
   2323         return mPackageName;
   2324     }
   2325 
   2326     private static IContentService sContentService;
   2327     private final Context mContext;
   2328     final String mPackageName;
   2329     private static final String TAG = "ContentResolver";
   2330 }
   2331