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