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