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