• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 extra’s 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 */
syncErrorToString(int error)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 */
syncErrorStringToInt(String error)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 
ContentResolver(Context context)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 */
acquireProvider(Context c, String name)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      */
acquireExistingProvider(Context c, String name)531     protected IContentProvider acquireExistingProvider(Context c, String name) {
532         return acquireProvider(c, name);
533     }
534 
535     /** @hide */
releaseProvider(IContentProvider icp)536     public abstract boolean releaseProvider(IContentProvider icp);
537     /** @hide */
acquireUnstableProvider(Context c, String name)538     protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
539     /** @hide */
releaseUnstableProvider(IContentProvider icp)540     public abstract boolean releaseUnstableProvider(IContentProvider icp);
541     /** @hide */
unstableProviderDied(IContentProvider icp)542     public abstract void unstableProviderDied(IContentProvider icp);
543 
544     /** @hide */
appNotRespondingViaProvider(IContentProvider icp)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      */
getType(@onNull Uri url)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      */
getStreamTypes(@onNull Uri url, @NonNull String mimeTypeFilter)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      */
query(@equiresPermission.Read @onNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder)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      */
query(@equiresPermission.Read @onNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal)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      */
query(final @RequiresPermission.Read @NonNull Uri uri, @Nullable String[] projection, @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal)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      */
canonicalize(@onNull Uri url)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      */
uncanonicalize(@onNull Uri url)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      */
refresh(@onNull Uri url, @Nullable Bundle args, @Nullable CancellationSignal cancellationSignal)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      */
openInputStream(@onNull Uri uri)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      */
openOutputStream(@onNull Uri uri)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      */
openOutputStream(@onNull Uri uri, @NonNull String mode)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      */
openFileDescriptor(@onNull Uri uri, @NonNull String mode)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      */
openFileDescriptor(@onNull Uri uri, @NonNull String mode, @Nullable CancellationSignal cancellationSignal)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      */
openAssetFileDescriptor(@onNull Uri uri, @NonNull String mode)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      */
openAssetFileDescriptor(@onNull Uri uri, @NonNull String mode, @Nullable CancellationSignal cancellationSignal)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      */
openTypedAssetFileDescriptor(@onNull Uri uri, @NonNull String mimeType, @Nullable Bundle opts)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      */
openTypedAssetFileDescriptor(@onNull Uri uri, @NonNull String mimeType, @Nullable Bundle opts, @Nullable CancellationSignal cancellationSignal)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      */
getResourceId(Uri uri)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      */
insert(@equiresPermission.Write @onNull Uri url, @Nullable ContentValues values)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      */
applyBatch(@onNull String authority, @NonNull ArrayList<ContentProviderOperation> operations)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      */
bulkInsert(@equiresPermission.Write @onNull Uri url, @NonNull ContentValues[] values)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      */
delete(@equiresPermission.Write @onNull Uri url, @Nullable String where, @Nullable String[] selectionArgs)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      */
update(@equiresPermission.Write @onNull Uri uri, @Nullable ContentValues values, @Nullable String where, @Nullable String[] selectionArgs)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      */
call(@onNull Uri uri, @NonNull String method, @Nullable String arg, @Nullable Bundle extras)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      */
acquireProvider(Uri uri)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      */
acquireExistingProvider(Uri uri)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      */
acquireProvider(String name)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      */
acquireUnstableProvider(Uri uri)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      */
acquireUnstableProvider(String name)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      */
acquireContentProviderClient(@onNull Uri uri)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      */
acquireContentProviderClient( @onNull String name)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      */
acquireUnstableContentProviderClient( @onNull Uri uri)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      */
acquireUnstableContentProviderClient( @onNull String name)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      */
registerContentObserver(@onNull Uri uri, boolean notifyForDescendants, @NonNull ContentObserver observer)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 */
registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer, @UserIdInt int userHandle)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      */
unregisterContentObserver(@onNull ContentObserver observer)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      */
notifyChange(@onNull Uri uri, @Nullable ContentObserver observer)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      */
notifyChange(@onNull Uri uri, @Nullable ContentObserver observer, boolean syncToNetwork)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      */
notifyChange(@onNull Uri uri, @Nullable ContentObserver observer, @NotifyFlags int flags)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      */
notifyChange(@onNull Uri uri, ContentObserver observer, boolean syncToNetwork, @UserIdInt int userHandle)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      */
notifyChange(@onNull Uri uri, ContentObserver observer, @NotifyFlags int flags, @UserIdInt int userHandle)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      */
takePersistableUriPermission(@onNull Uri uri, @Intent.AccessUriMode int modeFlags)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      */
releasePersistableUriPermission(@onNull Uri uri, @Intent.AccessUriMode int modeFlags)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      */
getPersistedUriPermissions()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      */
getOutgoingPersistedUriPermissions()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
startSync(Uri uri, Bundle extras)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      */
requestSync(Account account, String authority, Bundle extras)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      */
requestSyncAsUser(Account account, String authority, @UserIdInt int userId, Bundle extras)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      */
requestSync(SyncRequest request)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      */
validateSyncExtrasBundle(Bundle extras)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
cancelSync(Uri uri)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      */
cancelSync(Account account, String authority)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      */
cancelSyncAsUser(Account account, String authority, @UserIdInt int userId)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      */
getSyncAdapterTypes()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      */
getSyncAdapterTypesAsUser(@serIdInt int userId)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
getSyncAdapterPackagesForAuthorityAsUser(String authority, @UserIdInt int userId)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      */
getSyncAutomatically(Account account, String authority)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      */
getSyncAutomaticallyAsUser(Account account, String authority, @UserIdInt int userId)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      */
setSyncAutomatically(Account account, String authority, boolean sync)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      */
setSyncAutomaticallyAsUser(Account account, String authority, boolean sync, @UserIdInt int userId)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      */
addPeriodicSync(Account account, String authority, Bundle extras, long pollFrequency)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      */
invalidPeriodicExtras(Bundle extras)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      */
removePeriodicSync(Account account, String authority, Bundle extras)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      */
cancelSync(SyncRequest request)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      */
getPeriodicSyncs(Account account, String authority)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      */
getIsSyncable(Account account, String authority)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      */
getIsSyncableAsUser(Account account, String authority, @UserIdInt int userId)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      */
setIsSyncable(Account account, String authority, int syncable)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      */
getMasterSyncAutomatically()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      */
getMasterSyncAutomaticallyAsUser(@serIdInt int userId)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      */
setMasterSyncAutomatically(boolean sync)2615     public static void setMasterSyncAutomatically(boolean sync) {
2616         setMasterSyncAutomaticallyAsUser(sync, UserHandle.myUserId());
2617     }
2618 
2619     /**
2620      * @see #setMasterSyncAutomatically(boolean)
2621      * @hide
2622      */
setMasterSyncAutomaticallyAsUser(boolean sync, @UserIdInt int userId)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      */
isSyncActive(Account account, String authority)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
getCurrentSync()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      */
getCurrentSyncs()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      */
getCurrentSyncsAsUser(@serIdInt int userId)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      */
getSyncStatus(Account account, String authority)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      */
getSyncStatusAsUser(Account account, String authority, @UserIdInt int userId)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      */
isSyncPending(Account account, String authority)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      */
isSyncPendingAsUser(Account account, String authority, @UserIdInt int userId)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      */
addStatusChangeListener(int mask, final SyncStatusObserver callback)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      */
removeStatusChangeListener(Object handle)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} */
putCache(Uri key, Bundle value)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} */
getCache(Uri key)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} */
getTargetSdkVersion()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      */
samplePercentForDuration(long durationMillis)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 
maybeLogQueryToEventLog( long durationMillis, Uri uri, String[] projection, @Nullable Bundle queryArgs)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 
maybeLogUpdateToEventLog( long durationMillis, Uri uri, String operation, String selection)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 
CursorWrapperInner(Cursor cursor, IContentProvider contentProvider)2922         CursorWrapperInner(Cursor cursor, IContentProvider contentProvider) {
2923             super(cursor);
2924             mContentProvider = contentProvider;
2925             mCloseGuard.open("close");
2926         }
2927 
2928         @Override
close()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
finalize()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 
ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp)2956         ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) {
2957             super(pfd);
2958             mContentProvider = icp;
2959         }
2960 
2961         @Override
releaseResources()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 */
getContentService()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 */
getPackageName()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 */
resolveUserId(Uri uri)2998     public int resolveUserId(Uri uri) {
2999         return ContentProvider.getUserIdFromUri(uri, mContext.getUserId());
3000     }
3001 
3002     /** @hide */
getTypeDrawable(String mimeType)3003     public Drawable getTypeDrawable(String mimeType) {
3004         return MimeIconUtils.loadMimeIcon(mContext, mimeType);
3005     }
3006 
3007     /**
3008      * @hide
3009      */
createSqlQueryBundle( @ullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder)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      */
createSqlSortClause(Bundle queryArgs)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