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