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