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