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