[go: nahoru, domu]

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