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