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