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