ContentResolver.java revision 0e9ac20d7e0c9aca8cd342d97465adfac4c7e6e1
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 <code>true</code>, 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, @Intent.AccessUriMode int modeFlags) {
1645        try {
1646            ActivityManagerNative.getDefault().takePersistableUriPermission(
1647                    ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
1648        } catch (RemoteException e) {
1649        }
1650    }
1651
1652    /**
1653     * Relinquish a persisted URI permission grant. The URI must have been
1654     * previously made persistent with
1655     * {@link #takePersistableUriPermission(Uri, int)}. Any non-persistent
1656     * grants to the calling package will remain intact.
1657     *
1658     * @see #getPersistedUriPermissions()
1659     */
1660    public void releasePersistableUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags) {
1661        try {
1662            ActivityManagerNative.getDefault().releasePersistableUriPermission(
1663                    ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
1664        } catch (RemoteException e) {
1665        }
1666    }
1667
1668    /**
1669     * Return list of all URI permission grants that have been persisted by the
1670     * calling app. That is, the returned permissions have been granted
1671     * <em>to</em> the calling app. Only persistable grants taken with
1672     * {@link #takePersistableUriPermission(Uri, int)} are returned.
1673     *
1674     * @see #takePersistableUriPermission(Uri, int)
1675     * @see #releasePersistableUriPermission(Uri, int)
1676     */
1677    public List<UriPermission> getPersistedUriPermissions() {
1678        try {
1679            return ActivityManagerNative.getDefault()
1680                    .getPersistedUriPermissions(mPackageName, true).getList();
1681        } catch (RemoteException e) {
1682            throw new RuntimeException("Activity manager has died", e);
1683        }
1684    }
1685
1686    /**
1687     * Return list of all persisted URI permission grants that are hosted by the
1688     * calling app. That is, the returned permissions have been granted
1689     * <em>from</em> the calling app. Only grants taken with
1690     * {@link #takePersistableUriPermission(Uri, int)} are returned.
1691     */
1692    public List<UriPermission> getOutgoingPersistedUriPermissions() {
1693        try {
1694            return ActivityManagerNative.getDefault()
1695                    .getPersistedUriPermissions(mPackageName, false).getList();
1696        } catch (RemoteException e) {
1697            throw new RuntimeException("Activity manager has died", e);
1698        }
1699    }
1700
1701    /**
1702     * Start an asynchronous sync operation. If you want to monitor the progress
1703     * of the sync you may register a SyncObserver. Only values of the following
1704     * types may be used in the extras bundle:
1705     * <ul>
1706     * <li>Integer</li>
1707     * <li>Long</li>
1708     * <li>Boolean</li>
1709     * <li>Float</li>
1710     * <li>Double</li>
1711     * <li>String</li>
1712     * <li>Account</li>
1713     * <li>null</li>
1714     * </ul>
1715     *
1716     * @param uri the uri of the provider to sync or null to sync all providers.
1717     * @param extras any extras to pass to the SyncAdapter.
1718     * @deprecated instead use
1719     * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
1720     */
1721    @Deprecated
1722    public void startSync(Uri uri, Bundle extras) {
1723        Account account = null;
1724        if (extras != null) {
1725            String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT);
1726            if (!TextUtils.isEmpty(accountName)) {
1727                account = new Account(accountName, "com.google");
1728            }
1729            extras.remove(SYNC_EXTRAS_ACCOUNT);
1730        }
1731        requestSync(account, uri != null ? uri.getAuthority() : null, extras);
1732    }
1733
1734    /**
1735     * Start an asynchronous sync operation. If you want to monitor the progress
1736     * of the sync you may register a SyncObserver. Only values of the following
1737     * types may be used in the extras bundle:
1738     * <ul>
1739     * <li>Integer</li>
1740     * <li>Long</li>
1741     * <li>Boolean</li>
1742     * <li>Float</li>
1743     * <li>Double</li>
1744     * <li>String</li>
1745     * <li>Account</li>
1746     * <li>null</li>
1747     * </ul>
1748     *
1749     * @param account which account should be synced
1750     * @param authority which authority should be synced
1751     * @param extras any extras to pass to the SyncAdapter.
1752     */
1753    public static void requestSync(Account account, String authority, Bundle extras) {
1754        requestSyncAsUser(account, authority, UserHandle.getCallingUserId(), extras);
1755    }
1756
1757    /**
1758     * @see #requestSync(Account, String, Bundle)
1759     * @hide
1760     */
1761    public static void requestSyncAsUser(Account account, String authority, int userId,
1762            Bundle extras) {
1763        if (extras == null) {
1764            throw new IllegalArgumentException("Must specify extras.");
1765        }
1766        SyncRequest request =
1767            new SyncRequest.Builder()
1768                .setSyncAdapter(account, authority)
1769                .setExtras(extras)
1770                .syncOnce()     // Immediate sync.
1771                .build();
1772        try {
1773            getContentService().syncAsUser(request, userId);
1774        } catch(RemoteException e) {
1775            // Shouldn't happen.
1776        }
1777    }
1778
1779    /**
1780     * Register a sync with the SyncManager. These requests are built using the
1781     * {@link SyncRequest.Builder}.
1782     */
1783    public static void requestSync(SyncRequest request) {
1784        try {
1785            getContentService().sync(request);
1786        } catch(RemoteException e) {
1787            // Shouldn't happen.
1788        }
1789    }
1790
1791    /**
1792     * Check that only values of the following types are in the Bundle:
1793     * <ul>
1794     * <li>Integer</li>
1795     * <li>Long</li>
1796     * <li>Boolean</li>
1797     * <li>Float</li>
1798     * <li>Double</li>
1799     * <li>String</li>
1800     * <li>Account</li>
1801     * <li>null</li>
1802     * </ul>
1803     * @param extras the Bundle to check
1804     */
1805    public static void validateSyncExtrasBundle(Bundle extras) {
1806        try {
1807            for (String key : extras.keySet()) {
1808                Object value = extras.get(key);
1809                if (value == null) continue;
1810                if (value instanceof Long) continue;
1811                if (value instanceof Integer) continue;
1812                if (value instanceof Boolean) continue;
1813                if (value instanceof Float) continue;
1814                if (value instanceof Double) continue;
1815                if (value instanceof String) continue;
1816                if (value instanceof Account) continue;
1817                throw new IllegalArgumentException("unexpected value type: "
1818                        + value.getClass().getName());
1819            }
1820        } catch (IllegalArgumentException e) {
1821            throw e;
1822        } catch (RuntimeException exc) {
1823            throw new IllegalArgumentException("error unparceling Bundle", exc);
1824        }
1825    }
1826
1827    /**
1828     * Cancel any active or pending syncs that match the Uri. If the uri is null then
1829     * all syncs will be canceled.
1830     *
1831     * @param uri the uri of the provider to sync or null to sync all providers.
1832     * @deprecated instead use {@link #cancelSync(android.accounts.Account, String)}
1833     */
1834    @Deprecated
1835    public void cancelSync(Uri uri) {
1836        cancelSync(null /* all accounts */, uri != null ? uri.getAuthority() : null);
1837    }
1838
1839    /**
1840     * Cancel any active or pending syncs that match account and authority. The account and
1841     * authority can each independently be set to null, which means that syncs with any account
1842     * or authority, respectively, will match.
1843     *
1844     * @param account filters the syncs that match by this account
1845     * @param authority filters the syncs that match by this authority
1846     */
1847    public static void cancelSync(Account account, String authority) {
1848        try {
1849            getContentService().cancelSync(account, authority, null);
1850        } catch (RemoteException e) {
1851        }
1852    }
1853
1854    /**
1855     * @see #cancelSync(Account, String)
1856     * @hide
1857     */
1858    public static void cancelSyncAsUser(Account account, String authority, int userId) {
1859        try {
1860            getContentService().cancelSyncAsUser(account, authority, null, userId);
1861        } catch (RemoteException e) {
1862        }
1863    }
1864
1865    /**
1866     * Get information about the SyncAdapters that are known to the system.
1867     * @return an array of SyncAdapters that have registered with the system
1868     */
1869    public static SyncAdapterType[] getSyncAdapterTypes() {
1870        try {
1871            return getContentService().getSyncAdapterTypes();
1872        } catch (RemoteException e) {
1873            throw new RuntimeException("the ContentService should always be reachable", e);
1874        }
1875    }
1876
1877    /**
1878     * @see #getSyncAdapterTypes()
1879     * @hide
1880     */
1881    public static SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
1882        try {
1883            return getContentService().getSyncAdapterTypesAsUser(userId);
1884        } catch (RemoteException e) {
1885            throw new RuntimeException("the ContentService should always be reachable", e);
1886        }
1887    }
1888
1889    /**
1890     * Check if the provider should be synced when a network tickle is received
1891     * <p>This method requires the caller to hold the permission
1892     * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
1893     *
1894     * @param account the account whose setting we are querying
1895     * @param authority the provider whose setting we are querying
1896     * @return true if the provider should be synced when a network tickle is received
1897     */
1898    public static boolean getSyncAutomatically(Account account, String authority) {
1899        try {
1900            return getContentService().getSyncAutomatically(account, authority);
1901        } catch (RemoteException e) {
1902            throw new RuntimeException("the ContentService should always be reachable", e);
1903        }
1904    }
1905
1906    /**
1907     * @see #getSyncAutomatically(Account, String)
1908     * @hide
1909     */
1910    public static boolean getSyncAutomaticallyAsUser(Account account, String authority,
1911            int userId) {
1912        try {
1913            return getContentService().getSyncAutomaticallyAsUser(account, authority, userId);
1914        } catch (RemoteException e) {
1915            throw new RuntimeException("the ContentService should always be reachable", e);
1916        }
1917    }
1918
1919    /**
1920     * Set whether or not the provider is synced when it receives a network tickle.
1921     * <p>This method requires the caller to hold the permission
1922     * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
1923     *
1924     * @param account the account whose setting we are querying
1925     * @param authority the provider whose behavior is being controlled
1926     * @param sync true if the provider should be synced when tickles are received for it
1927     */
1928    public static void setSyncAutomatically(Account account, String authority, boolean sync) {
1929        setSyncAutomaticallyAsUser(account, authority, sync, UserHandle.getCallingUserId());
1930    }
1931
1932    /**
1933     * @see #setSyncAutomatically(Account, String, boolean)
1934     * @hide
1935     */
1936    public static void setSyncAutomaticallyAsUser(Account account, String authority, boolean sync,
1937            int userId) {
1938        try {
1939            getContentService().setSyncAutomaticallyAsUser(account, authority, sync, userId);
1940        } catch (RemoteException e) {
1941            // exception ignored; if this is thrown then it means the runtime is in the midst of
1942            // being restarted
1943        }
1944    }
1945
1946    /**
1947     * Specifies that a sync should be requested with the specified the account, authority,
1948     * and extras at the given frequency. If there is already another periodic sync scheduled
1949     * with the account, authority and extras then a new periodic sync won't be added, instead
1950     * the frequency of the previous one will be updated.
1951     * <p>
1952     * These periodic syncs honor the "syncAutomatically" and "masterSyncAutomatically" settings.
1953     * Although these sync are scheduled at the specified frequency, it may take longer for it to
1954     * actually be started if other syncs are ahead of it in the sync operation queue. This means
1955     * that the actual start time may drift.
1956     * <p>
1957     * Periodic syncs are not allowed to have any of {@link #SYNC_EXTRAS_DO_NOT_RETRY},
1958     * {@link #SYNC_EXTRAS_IGNORE_BACKOFF}, {@link #SYNC_EXTRAS_IGNORE_SETTINGS},
1959     * {@link #SYNC_EXTRAS_INITIALIZE}, {@link #SYNC_EXTRAS_FORCE},
1960     * {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL} set to true.
1961     * If any are supplied then an {@link IllegalArgumentException} will be thrown.
1962     *
1963     * <p>This method requires the caller to hold the permission
1964     * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
1965     * <p>The bundle for a periodic sync can be queried by applications with the correct
1966     * permissions using
1967     * {@link ContentResolver#getPeriodicSyncs(Account account, String provider)}, so no
1968     * sensitive data should be transferred here.
1969     *
1970     * @param account the account to specify in the sync
1971     * @param authority the provider to specify in the sync request
1972     * @param extras extra parameters to go along with the sync request
1973     * @param pollFrequency how frequently the sync should be performed, in seconds.
1974     * @throws IllegalArgumentException if an illegal extra was set or if any of the parameters
1975     * are null.
1976     */
1977    public static void addPeriodicSync(Account account, String authority, Bundle extras,
1978            long pollFrequency) {
1979        validateSyncExtrasBundle(extras);
1980        if (extras.getBoolean(SYNC_EXTRAS_MANUAL, false)
1981                || extras.getBoolean(SYNC_EXTRAS_DO_NOT_RETRY, false)
1982                || extras.getBoolean(SYNC_EXTRAS_IGNORE_BACKOFF, false)
1983                || extras.getBoolean(SYNC_EXTRAS_IGNORE_SETTINGS, false)
1984                || extras.getBoolean(SYNC_EXTRAS_INITIALIZE, false)
1985                || extras.getBoolean(SYNC_EXTRAS_FORCE, false)
1986                || extras.getBoolean(SYNC_EXTRAS_EXPEDITED, false)) {
1987            throw new IllegalArgumentException("illegal extras were set");
1988        }
1989        try {
1990             getContentService().addPeriodicSync(account, authority, extras, pollFrequency);
1991        } catch (RemoteException e) {
1992            // exception ignored; if this is thrown then it means the runtime is in the midst of
1993            // being restarted
1994        }
1995    }
1996
1997    /**
1998     * {@hide}
1999     * Helper function to throw an <code>IllegalArgumentException</code> if any illegal
2000     * extras were set for a periodic sync.
2001     *
2002     * @param extras bundle to validate.
2003     */
2004    public static boolean invalidPeriodicExtras(Bundle extras) {
2005        if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)
2006                || extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)
2007                || extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)
2008                || extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
2009                || extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)
2010                || extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false)
2011                || extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
2012            return true;
2013        }
2014        return false;
2015    }
2016
2017    /**
2018     * Remove a periodic sync. Has no affect if account, authority and extras don't match
2019     * an existing periodic sync.
2020     * <p>This method requires the caller to hold the permission
2021     * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
2022     *
2023     * @param account the account of the periodic sync to remove
2024     * @param authority the provider of the periodic sync to remove
2025     * @param extras the extras of the periodic sync to remove
2026     */
2027    public static void removePeriodicSync(Account account, String authority, Bundle extras) {
2028        validateSyncExtrasBundle(extras);
2029        try {
2030            getContentService().removePeriodicSync(account, authority, extras);
2031        } catch (RemoteException e) {
2032            throw new RuntimeException("the ContentService should always be reachable", e);
2033        }
2034    }
2035
2036    /**
2037     * Remove the specified sync. This will cancel any pending or active syncs. If the request is
2038     * for a periodic sync, this call will remove any future occurrences.
2039     * <p>
2040     *     If a periodic sync is specified, the caller must hold the permission
2041     *     {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
2042     *</p>
2043     * It is possible to cancel a sync using a SyncRequest object that is not the same object
2044     * with which you requested the sync. Do so by building a SyncRequest with the same
2045     * adapter, frequency, <b>and</b> extras bundle.
2046     *
2047     * @param request SyncRequest object containing information about sync to cancel.
2048     */
2049    public static void cancelSync(SyncRequest request) {
2050        if (request == null) {
2051            throw new IllegalArgumentException("request cannot be null");
2052        }
2053        try {
2054            getContentService().cancelRequest(request);
2055        } catch (RemoteException e) {
2056            // exception ignored; if this is thrown then it means the runtime is in the midst of
2057            // being restarted
2058        }
2059    }
2060
2061    /**
2062     * Get the list of information about the periodic syncs for the given account and authority.
2063     * <p>This method requires the caller to hold the permission
2064     * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
2065     *
2066     * @param account the account whose periodic syncs we are querying
2067     * @param authority the provider whose periodic syncs we are querying
2068     * @return a list of PeriodicSync objects. This list may be empty but will never be null.
2069     */
2070    public static List<PeriodicSync> getPeriodicSyncs(Account account, String authority) {
2071        try {
2072            return getContentService().getPeriodicSyncs(account, authority, null);
2073        } catch (RemoteException e) {
2074            throw new RuntimeException("the ContentService should always be reachable", e);
2075        }
2076    }
2077
2078    /**
2079     * Check if this account/provider is syncable.
2080     * <p>This method requires the caller to hold the permission
2081     * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
2082     * @return >0 if it is syncable, 0 if not, and <0 if the state isn't known yet.
2083     */
2084    public static int getIsSyncable(Account account, String authority) {
2085        try {
2086            return getContentService().getIsSyncable(account, authority);
2087        } catch (RemoteException e) {
2088            throw new RuntimeException("the ContentService should always be reachable", e);
2089        }
2090    }
2091
2092    /**
2093     * @see #getIsSyncable(Account, String)
2094     * @hide
2095     */
2096    public static int getIsSyncableAsUser(Account account, String authority, int userId) {
2097        try {
2098            return getContentService().getIsSyncableAsUser(account, authority, userId);
2099        } catch (RemoteException e) {
2100            throw new RuntimeException("the ContentService should always be reachable", e);
2101        }
2102    }
2103
2104    /**
2105     * Set whether this account/provider is syncable.
2106     * <p>This method requires the caller to hold the permission
2107     * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
2108     * @param syncable >0 denotes syncable, 0 means not syncable, <0 means unknown
2109     */
2110    public static void setIsSyncable(Account account, String authority, int syncable) {
2111        try {
2112            getContentService().setIsSyncable(account, authority, syncable);
2113        } catch (RemoteException e) {
2114            // exception ignored; if this is thrown then it means the runtime is in the midst of
2115            // being restarted
2116        }
2117    }
2118
2119    /**
2120     * Gets the master auto-sync setting that applies to all the providers and accounts.
2121     * If this is false then the per-provider auto-sync setting is ignored.
2122     * <p>This method requires the caller to hold the permission
2123     * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
2124     *
2125     * @return the master auto-sync setting that applies to all the providers and accounts
2126     */
2127    public static boolean getMasterSyncAutomatically() {
2128        try {
2129            return getContentService().getMasterSyncAutomatically();
2130        } catch (RemoteException e) {
2131            throw new RuntimeException("the ContentService should always be reachable", e);
2132        }
2133    }
2134
2135    /**
2136     * @see #getMasterSyncAutomatically()
2137     * @hide
2138     */
2139    public static boolean getMasterSyncAutomaticallyAsUser(int userId) {
2140        try {
2141            return getContentService().getMasterSyncAutomaticallyAsUser(userId);
2142        } catch (RemoteException e) {
2143            throw new RuntimeException("the ContentService should always be reachable", e);
2144        }
2145    }
2146
2147    /**
2148     * Sets the master auto-sync setting that applies to all the providers and accounts.
2149     * If this is false then the per-provider auto-sync setting is ignored.
2150     * <p>This method requires the caller to hold the permission
2151     * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
2152     *
2153     * @param sync the master auto-sync setting that applies to all the providers and accounts
2154     */
2155    public static void setMasterSyncAutomatically(boolean sync) {
2156        setMasterSyncAutomaticallyAsUser(sync, UserHandle.getCallingUserId());
2157    }
2158
2159    /**
2160     * @see #setMasterSyncAutomatically(boolean)
2161     * @hide
2162     */
2163    public static void setMasterSyncAutomaticallyAsUser(boolean sync, int userId) {
2164        try {
2165            getContentService().setMasterSyncAutomaticallyAsUser(sync, userId);
2166        } catch (RemoteException e) {
2167            // exception ignored; if this is thrown then it means the runtime is in the midst of
2168            // being restarted
2169        }
2170    }
2171
2172    /**
2173     * Returns true if there is currently a sync operation for the given account or authority
2174     * actively being processed.
2175     * <p>This method requires the caller to hold the permission
2176     * {@link android.Manifest.permission#READ_SYNC_STATS}.
2177     * @param account the account whose setting we are querying
2178     * @param authority the provider whose behavior is being queried
2179     * @return true if a sync is active for the given account or authority.
2180     */
2181    public static boolean isSyncActive(Account account, String authority) {
2182        if (account == null) {
2183            throw new IllegalArgumentException("account must not be null");
2184        }
2185        if (authority == null) {
2186            throw new IllegalArgumentException("authority must not be null");
2187        }
2188
2189        try {
2190            return getContentService().isSyncActive(account, authority, null);
2191        } catch (RemoteException e) {
2192            throw new RuntimeException("the ContentService should always be reachable", e);
2193        }
2194    }
2195
2196    /**
2197     * If a sync is active returns the information about it, otherwise returns null.
2198     * <p>
2199     * This method requires the caller to hold the permission
2200     * {@link android.Manifest.permission#READ_SYNC_STATS}.
2201     * <p>
2202     * @return the SyncInfo for the currently active sync or null if one is not active.
2203     * @deprecated
2204     * Since multiple concurrent syncs are now supported you should use
2205     * {@link #getCurrentSyncs()} to get the accurate list of current syncs.
2206     * This method returns the first item from the list of current syncs
2207     * or null if there are none.
2208     */
2209    @Deprecated
2210    public static SyncInfo getCurrentSync() {
2211        try {
2212            final List<SyncInfo> syncs = getContentService().getCurrentSyncs();
2213            if (syncs.isEmpty()) {
2214                return null;
2215            }
2216            return syncs.get(0);
2217        } catch (RemoteException e) {
2218            throw new RuntimeException("the ContentService should always be reachable", e);
2219        }
2220    }
2221
2222    /**
2223     * Returns a list with information about all the active syncs. This list will be empty
2224     * if there are no active syncs.
2225     * <p>
2226     * This method requires the caller to hold the permission
2227     * {@link android.Manifest.permission#READ_SYNC_STATS}.
2228     * <p>
2229     * @return a List of SyncInfo objects for the currently active syncs.
2230     */
2231    public static List<SyncInfo> getCurrentSyncs() {
2232        try {
2233            return getContentService().getCurrentSyncs();
2234        } catch (RemoteException e) {
2235            throw new RuntimeException("the ContentService should always be reachable", e);
2236        }
2237    }
2238
2239    /**
2240     * @see #getCurrentSyncs()
2241     * @hide
2242     */
2243    public static List<SyncInfo> getCurrentSyncsAsUser(int userId) {
2244        try {
2245            return getContentService().getCurrentSyncsAsUser(userId);
2246        } catch (RemoteException e) {
2247            throw new RuntimeException("the ContentService should always be reachable", e);
2248        }
2249    }
2250
2251    /**
2252     * Returns the status that matches the authority.
2253     * @param account the account whose setting we are querying
2254     * @param authority the provider whose behavior is being queried
2255     * @return the SyncStatusInfo for the authority, or null if none exists
2256     * @hide
2257     */
2258    public static SyncStatusInfo getSyncStatus(Account account, String authority) {
2259        try {
2260            return getContentService().getSyncStatus(account, authority, null);
2261        } catch (RemoteException e) {
2262            throw new RuntimeException("the ContentService should always be reachable", e);
2263        }
2264    }
2265
2266    /**
2267     * @see #getSyncStatus(Account, String)
2268     * @hide
2269     */
2270    public static SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
2271            int userId) {
2272        try {
2273            return getContentService().getSyncStatusAsUser(account, authority, null, userId);
2274        } catch (RemoteException e) {
2275            throw new RuntimeException("the ContentService should always be reachable", e);
2276        }
2277    }
2278
2279    /**
2280     * Return true if the pending status is true of any matching authorities.
2281     * <p>This method requires the caller to hold the permission
2282     * {@link android.Manifest.permission#READ_SYNC_STATS}.
2283     * @param account the account whose setting we are querying
2284     * @param authority the provider whose behavior is being queried
2285     * @return true if there is a pending sync with the matching account and authority
2286     */
2287    public static boolean isSyncPending(Account account, String authority) {
2288        return isSyncPendingAsUser(account, authority, UserHandle.getCallingUserId());
2289    }
2290
2291    /**
2292     * @see #requestSync(Account, String, Bundle)
2293     * @hide
2294     */
2295    public static boolean isSyncPendingAsUser(Account account, String authority, int userId) {
2296        try {
2297            return getContentService().isSyncPendingAsUser(account, authority, null, userId);
2298        } catch (RemoteException e) {
2299            throw new RuntimeException("the ContentService should always be reachable", e);
2300        }
2301    }
2302
2303    /**
2304     * Request notifications when the different aspects of the SyncManager change. The
2305     * different items that can be requested are:
2306     * <ul>
2307     * <li> {@link #SYNC_OBSERVER_TYPE_PENDING}
2308     * <li> {@link #SYNC_OBSERVER_TYPE_ACTIVE}
2309     * <li> {@link #SYNC_OBSERVER_TYPE_SETTINGS}
2310     * </ul>
2311     * The caller can set one or more of the status types in the mask for any
2312     * given listener registration.
2313     * @param mask the status change types that will cause the callback to be invoked
2314     * @param callback observer to be invoked when the status changes
2315     * @return a handle that can be used to remove the listener at a later time
2316     */
2317    public static Object addStatusChangeListener(int mask, final SyncStatusObserver callback) {
2318        if (callback == null) {
2319            throw new IllegalArgumentException("you passed in a null callback");
2320        }
2321        try {
2322            ISyncStatusObserver.Stub observer = new ISyncStatusObserver.Stub() {
2323                public void onStatusChanged(int which) throws RemoteException {
2324                    callback.onStatusChanged(which);
2325                }
2326            };
2327            getContentService().addStatusChangeListener(mask, observer);
2328            return observer;
2329        } catch (RemoteException e) {
2330            throw new RuntimeException("the ContentService should always be reachable", e);
2331        }
2332    }
2333
2334    /**
2335     * Remove a previously registered status change listener.
2336     * @param handle the handle that was returned by {@link #addStatusChangeListener}
2337     */
2338    public static void removeStatusChangeListener(Object handle) {
2339        if (handle == null) {
2340            throw new IllegalArgumentException("you passed in a null handle");
2341        }
2342        try {
2343            getContentService().removeStatusChangeListener((ISyncStatusObserver.Stub) handle);
2344        } catch (RemoteException e) {
2345            // exception ignored; if this is thrown then it means the runtime is in the midst of
2346            // being restarted
2347        }
2348    }
2349
2350    /**
2351     * Returns sampling percentage for a given duration.
2352     *
2353     * Always returns at least 1%.
2354     */
2355    private int samplePercentForDuration(long durationMillis) {
2356        if (durationMillis >= SLOW_THRESHOLD_MILLIS) {
2357            return 100;
2358        }
2359        return (int) (100 * durationMillis / SLOW_THRESHOLD_MILLIS) + 1;
2360    }
2361
2362    private void maybeLogQueryToEventLog(long durationMillis,
2363                                         Uri uri, String[] projection,
2364                                         String selection, String sortOrder) {
2365        if (!ENABLE_CONTENT_SAMPLE) return;
2366        int samplePercent = samplePercentForDuration(durationMillis);
2367        if (samplePercent < 100) {
2368            synchronized (mRandom) {
2369                if (mRandom.nextInt(100) >= samplePercent) {
2370                    return;
2371                }
2372            }
2373        }
2374
2375        StringBuilder projectionBuffer = new StringBuilder(100);
2376        if (projection != null) {
2377            for (int i = 0; i < projection.length; ++i) {
2378                // Note: not using a comma delimiter here, as the
2379                // multiple arguments to EventLog.writeEvent later
2380                // stringify with a comma delimiter, which would make
2381                // parsing uglier later.
2382                if (i != 0) projectionBuffer.append('/');
2383                projectionBuffer.append(projection[i]);
2384            }
2385        }
2386
2387        // ActivityThread.currentPackageName() only returns non-null if the
2388        // current thread is an application main thread.  This parameter tells
2389        // us whether an event loop is blocked, and if so, which app it is.
2390        String blockingPackage = AppGlobals.getInitialPackage();
2391
2392        EventLog.writeEvent(
2393            EventLogTags.CONTENT_QUERY_SAMPLE,
2394            uri.toString(),
2395            projectionBuffer.toString(),
2396            selection != null ? selection : "",
2397            sortOrder != null ? sortOrder : "",
2398            durationMillis,
2399            blockingPackage != null ? blockingPackage : "",
2400            samplePercent);
2401    }
2402
2403    private void maybeLogUpdateToEventLog(
2404        long durationMillis, Uri uri, String operation, String selection) {
2405        if (!ENABLE_CONTENT_SAMPLE) return;
2406        int samplePercent = samplePercentForDuration(durationMillis);
2407        if (samplePercent < 100) {
2408            synchronized (mRandom) {
2409                if (mRandom.nextInt(100) >= samplePercent) {
2410                    return;
2411                }
2412            }
2413        }
2414        String blockingPackage = AppGlobals.getInitialPackage();
2415        EventLog.writeEvent(
2416            EventLogTags.CONTENT_UPDATE_SAMPLE,
2417            uri.toString(),
2418            operation,
2419            selection != null ? selection : "",
2420            durationMillis,
2421            blockingPackage != null ? blockingPackage : "",
2422            samplePercent);
2423    }
2424
2425    private final class CursorWrapperInner extends CrossProcessCursorWrapper {
2426        private final IContentProvider mContentProvider;
2427        public static final String TAG="CursorWrapperInner";
2428
2429        private final CloseGuard mCloseGuard = CloseGuard.get();
2430        private boolean mProviderReleased;
2431
2432        CursorWrapperInner(Cursor cursor, IContentProvider icp) {
2433            super(cursor);
2434            mContentProvider = icp;
2435            mCloseGuard.open("close");
2436        }
2437
2438        @Override
2439        public void close() {
2440            super.close();
2441            ContentResolver.this.releaseProvider(mContentProvider);
2442            mProviderReleased = true;
2443
2444            if (mCloseGuard != null) {
2445                mCloseGuard.close();
2446            }
2447        }
2448
2449        @Override
2450        protected void finalize() throws Throwable {
2451            try {
2452                if (mCloseGuard != null) {
2453                    mCloseGuard.warnIfOpen();
2454                }
2455
2456                if (!mProviderReleased && mContentProvider != null) {
2457                    // Even though we are using CloseGuard, log this anyway so that
2458                    // application developers always see the message in the log.
2459                    Log.w(TAG, "Cursor finalized without prior close()");
2460                    ContentResolver.this.releaseProvider(mContentProvider);
2461                }
2462            } finally {
2463                super.finalize();
2464            }
2465        }
2466    }
2467
2468    private final class ParcelFileDescriptorInner extends ParcelFileDescriptor {
2469        private final IContentProvider mContentProvider;
2470        private boolean mProviderReleased;
2471
2472        ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) {
2473            super(pfd);
2474            mContentProvider = icp;
2475        }
2476
2477        @Override
2478        public void releaseResources() {
2479            if (!mProviderReleased) {
2480                ContentResolver.this.releaseProvider(mContentProvider);
2481                mProviderReleased = true;
2482            }
2483        }
2484    }
2485
2486    /** @hide */
2487    public static final String CONTENT_SERVICE_NAME = "content";
2488
2489    /** @hide */
2490    public static IContentService getContentService() {
2491        if (sContentService != null) {
2492            return sContentService;
2493        }
2494        IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME);
2495        if (false) Log.v("ContentService", "default service binder = " + b);
2496        sContentService = IContentService.Stub.asInterface(b);
2497        if (false) Log.v("ContentService", "default service = " + sContentService);
2498        return sContentService;
2499    }
2500
2501    /** @hide */
2502    public String getPackageName() {
2503        return mPackageName;
2504    }
2505
2506    private static IContentService sContentService;
2507    private final Context mContext;
2508    final String mPackageName;
2509    private static final String TAG = "ContentResolver";
2510
2511    /** @hide */
2512    public int resolveUserId(Uri uri) {
2513        return ContentProvider.getUserIdFromUri(uri, mContext.getUserId());
2514    }
2515}
2516