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