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