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