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