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