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