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