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 static android.Manifest.permission.INTERACT_ACROSS_USERS;
20 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
21 import static android.app.AppOpsManager.MODE_ALLOWED;
22 import static android.app.AppOpsManager.MODE_DEFAULT;
23 import static android.app.AppOpsManager.MODE_ERRORED;
24 import static android.app.AppOpsManager.MODE_IGNORED;
25 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
26 import static android.os.Trace.TRACE_TAG_DATABASE;
27 
28 import android.annotation.NonNull;
29 import android.annotation.Nullable;
30 import android.annotation.SystemApi;
31 import android.annotation.TestApi;
32 import android.app.AppOpsManager;
33 import android.compat.annotation.UnsupportedAppUsage;
34 import android.content.pm.PackageManager;
35 import android.content.pm.PathPermission;
36 import android.content.pm.ProviderInfo;
37 import android.content.res.AssetFileDescriptor;
38 import android.content.res.Configuration;
39 import android.database.Cursor;
40 import android.database.MatrixCursor;
41 import android.database.SQLException;
42 import android.net.Uri;
43 import android.os.AsyncTask;
44 import android.os.Binder;
45 import android.os.Build;
46 import android.os.Bundle;
47 import android.os.CancellationSignal;
48 import android.os.IBinder;
49 import android.os.ICancellationSignal;
50 import android.os.ParcelFileDescriptor;
51 import android.os.ParcelableException;
52 import android.os.Process;
53 import android.os.RemoteCallback;
54 import android.os.RemoteException;
55 import android.os.Trace;
56 import android.os.UserHandle;
57 import android.os.storage.StorageManager;
58 import android.text.TextUtils;
59 import android.util.Log;
60 import android.util.Pair;
61 
62 import com.android.internal.annotations.VisibleForTesting;
63 
64 import java.io.File;
65 import java.io.FileDescriptor;
66 import java.io.FileNotFoundException;
67 import java.io.IOException;
68 import java.io.PrintWriter;
69 import java.util.ArrayList;
70 import java.util.Arrays;
71 import java.util.Objects;
72 
73 /**
74  * Content providers are one of the primary building blocks of Android applications, providing
75  * content to applications. They encapsulate data and provide it to applications through the single
76  * {@link ContentResolver} interface. A content provider is only required if you need to share
77  * data between multiple applications. For example, the contacts data is used by multiple
78  * applications and must be stored in a content provider. If you don't need to share data amongst
79  * multiple applications you can use a database directly via
80  * {@link android.database.sqlite.SQLiteDatabase}.
81  *
82  * <p>When a request is made via
83  * a {@link ContentResolver} the system inspects the authority of the given URI and passes the
84  * request to the content provider registered with the authority. The content provider can interpret
85  * the rest of the URI however it wants. The {@link UriMatcher} class is helpful for parsing
86  * URIs.</p>
87  *
88  * <p>The primary methods that need to be implemented are:
89  * <ul>
90  *   <li>{@link #onCreate} which is called to initialize the provider</li>
91  *   <li>{@link #query} which returns data to the caller</li>
92  *   <li>{@link #insert} which inserts new data into the content provider</li>
93  *   <li>{@link #update} which updates existing data in the content provider</li>
94  *   <li>{@link #delete} which deletes data from the content provider</li>
95  *   <li>{@link #getType} which returns the MIME type of data in the content provider</li>
96  * </ul></p>
97  *
98  * <p class="caution">Data access methods (such as {@link #insert} and
99  * {@link #update}) may be called from many threads at once, and must be thread-safe.
100  * Other methods (such as {@link #onCreate}) are only called from the application
101  * main thread, and must avoid performing lengthy operations.  See the method
102  * descriptions for their expected thread behavior.</p>
103  *
104  * <p>Requests to {@link ContentResolver} are automatically forwarded to the appropriate
105  * ContentProvider instance, so subclasses don't have to worry about the details of
106  * cross-process calls.</p>
107  *
108  * <div class="special reference">
109  * <h3>Developer Guides</h3>
110  * <p>For more information about using content providers, read the
111  * <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
112  * developer guide.</p>
113  * </div>
114  */
115 public abstract class ContentProvider implements ContentInterface, ComponentCallbacks2 {
116 
117     private static final String TAG = "ContentProvider";
118 
119     /*
120      * Note: if you add methods to ContentProvider, you must add similar methods to
121      *       MockContentProvider.
122      */
123 
124     @UnsupportedAppUsage
125     private Context mContext = null;
126     private int mMyUid;
127 
128     // Since most Providers have only one authority, we keep both a String and a String[] to improve
129     // performance.
130     @UnsupportedAppUsage
131     private String mAuthority;
132     @UnsupportedAppUsage
133     private String[] mAuthorities;
134     @UnsupportedAppUsage
135     private String mReadPermission;
136     @UnsupportedAppUsage
137     private String mWritePermission;
138     @UnsupportedAppUsage
139     private PathPermission[] mPathPermissions;
140     private boolean mExported;
141     private boolean mNoPerms;
142     private boolean mSingleUser;
143 
144     private ThreadLocal<Pair<String, String>> mCallingPackage;
145 
146     private Transport mTransport = new Transport();
147 
148     /**
149      * Construct a ContentProvider instance.  Content providers must be
150      * <a href="{@docRoot}guide/topics/manifest/provider-element.html">declared
151      * in the manifest</a>, accessed with {@link ContentResolver}, and created
152      * automatically by the system, so applications usually do not create
153      * ContentProvider instances directly.
154      *
155      * <p>At construction time, the object is uninitialized, and most fields and
156      * methods are unavailable.  Subclasses should initialize themselves in
157      * {@link #onCreate}, not the constructor.
158      *
159      * <p>Content providers are created on the application main thread at
160      * application launch time.  The constructor must not perform lengthy
161      * operations, or application startup will be delayed.
162      */
ContentProvider()163     public ContentProvider() {
164     }
165 
166     /**
167      * Constructor just for mocking.
168      *
169      * @param context A Context object which should be some mock instance (like the
170      * instance of {@link android.test.mock.MockContext}).
171      * @param readPermission The read permision you want this instance should have in the
172      * test, which is available via {@link #getReadPermission()}.
173      * @param writePermission The write permission you want this instance should have
174      * in the test, which is available via {@link #getWritePermission()}.
175      * @param pathPermissions The PathPermissions you want this instance should have
176      * in the test, which is available via {@link #getPathPermissions()}.
177      * @hide
178      */
179     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
ContentProvider( Context context, String readPermission, String writePermission, PathPermission[] pathPermissions)180     public ContentProvider(
181             Context context,
182             String readPermission,
183             String writePermission,
184             PathPermission[] pathPermissions) {
185         mContext = context;
186         mReadPermission = readPermission;
187         mWritePermission = writePermission;
188         mPathPermissions = pathPermissions;
189     }
190 
191     /**
192      * Given an IContentProvider, try to coerce it back to the real
193      * ContentProvider object if it is running in the local process.  This can
194      * be used if you know you are running in the same process as a provider,
195      * and want to get direct access to its implementation details.  Most
196      * clients should not nor have a reason to use it.
197      *
198      * @param abstractInterface The ContentProvider interface that is to be
199      *              coerced.
200      * @return If the IContentProvider is non-{@code null} and local, returns its actual
201      * ContentProvider instance.  Otherwise returns {@code null}.
202      * @hide
203      */
204     @UnsupportedAppUsage
coerceToLocalContentProvider( IContentProvider abstractInterface)205     public static ContentProvider coerceToLocalContentProvider(
206             IContentProvider abstractInterface) {
207         if (abstractInterface instanceof Transport) {
208             return ((Transport)abstractInterface).getContentProvider();
209         }
210         return null;
211     }
212 
213     /**
214      * Binder object that deals with remoting.
215      *
216      * @hide
217      */
218     class Transport extends ContentProviderNative {
219         volatile AppOpsManager mAppOpsManager = null;
220         volatile int mReadOp = AppOpsManager.OP_NONE;
221         volatile int mWriteOp = AppOpsManager.OP_NONE;
222         volatile ContentInterface mInterface = ContentProvider.this;
223 
getContentProvider()224         ContentProvider getContentProvider() {
225             return ContentProvider.this;
226         }
227 
228         @Override
getProviderName()229         public String getProviderName() {
230             return getContentProvider().getClass().getName();
231         }
232 
233         @Override
query(String callingPkg, @Nullable String attributionTag, Uri uri, @Nullable String[] projection, @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal)234         public Cursor query(String callingPkg, @Nullable String attributionTag, Uri uri,
235                 @Nullable String[] projection, @Nullable Bundle queryArgs,
236                 @Nullable ICancellationSignal cancellationSignal) {
237             uri = validateIncomingUri(uri);
238             uri = maybeGetUriWithoutUserId(uri);
239             if (enforceReadPermission(callingPkg, attributionTag, uri, null)
240                     != AppOpsManager.MODE_ALLOWED) {
241                 // The caller has no access to the data, so return an empty cursor with
242                 // the columns in the requested order. The caller may ask for an invalid
243                 // column and we would not catch that but this is not a problem in practice.
244                 // We do not call ContentProvider#query with a modified where clause since
245                 // the implementation is not guaranteed to be backed by a SQL database, hence
246                 // it may not handle properly the tautology where clause we would have created.
247                 if (projection != null) {
248                     return new MatrixCursor(projection, 0);
249                 }
250 
251                 // Null projection means all columns but we have no idea which they are.
252                 // However, the caller may be expecting to access them my index. Hence,
253                 // we have to execute the query as if allowed to get a cursor with the
254                 // columns. We then use the column names to return an empty cursor.
255                 Cursor cursor;
256                 final Pair<String, String> original = setCallingPackage(
257                         new Pair<>(callingPkg, attributionTag));
258                 try {
259                     cursor = mInterface.query(
260                             uri, projection, queryArgs,
261                             CancellationSignal.fromTransport(cancellationSignal));
262                 } catch (RemoteException e) {
263                     throw e.rethrowAsRuntimeException();
264                 } finally {
265                     setCallingPackage(original);
266                 }
267                 if (cursor == null) {
268                     return null;
269                 }
270 
271                 // Return an empty cursor for all columns.
272                 return new MatrixCursor(cursor.getColumnNames(), 0);
273             }
274             Trace.traceBegin(TRACE_TAG_DATABASE, "query");
275             final Pair<String, String> original = setCallingPackage(
276                     new Pair<>(callingPkg, attributionTag));
277             try {
278                 return mInterface.query(
279                         uri, projection, queryArgs,
280                         CancellationSignal.fromTransport(cancellationSignal));
281             } catch (RemoteException e) {
282                 throw e.rethrowAsRuntimeException();
283             } finally {
284                 setCallingPackage(original);
285                 Trace.traceEnd(TRACE_TAG_DATABASE);
286             }
287         }
288 
289         @Override
getType(Uri uri)290         public String getType(Uri uri) {
291             // getCallingPackage() isn't available in getType(), as the javadoc states.
292             uri = validateIncomingUri(uri);
293             uri = maybeGetUriWithoutUserId(uri);
294             Trace.traceBegin(TRACE_TAG_DATABASE, "getType");
295             try {
296                 return mInterface.getType(uri);
297             } catch (RemoteException e) {
298                 throw e.rethrowAsRuntimeException();
299             } finally {
300                 Trace.traceEnd(TRACE_TAG_DATABASE);
301             }
302         }
303 
304         @Override
getTypeAsync(Uri uri, RemoteCallback callback)305         public void getTypeAsync(Uri uri, RemoteCallback callback) {
306             final Bundle result = new Bundle();
307             try {
308                 result.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getType(uri));
309             } catch (Exception e) {
310                 result.putParcelable(ContentResolver.REMOTE_CALLBACK_ERROR,
311                         new ParcelableException(e));
312             }
313             callback.sendResult(result);
314         }
315 
316         @Override
insert(String callingPkg, @Nullable String attributionTag, Uri uri, ContentValues initialValues, Bundle extras)317         public Uri insert(String callingPkg, @Nullable String attributionTag, Uri uri,
318                 ContentValues initialValues, Bundle extras) {
319             uri = validateIncomingUri(uri);
320             int userId = getUserIdFromUri(uri);
321             uri = maybeGetUriWithoutUserId(uri);
322             if (enforceWritePermission(callingPkg, attributionTag, uri, null)
323                     != AppOpsManager.MODE_ALLOWED) {
324                 final Pair<String, String> original = setCallingPackage(
325                         new Pair<>(callingPkg, attributionTag));
326                 try {
327                     return rejectInsert(uri, initialValues);
328                 } finally {
329                     setCallingPackage(original);
330                 }
331             }
332             Trace.traceBegin(TRACE_TAG_DATABASE, "insert");
333             final Pair<String, String> original = setCallingPackage(
334                     new Pair<>(callingPkg, attributionTag));
335             try {
336                 return maybeAddUserId(mInterface.insert(uri, initialValues, extras), userId);
337             } catch (RemoteException e) {
338                 throw e.rethrowAsRuntimeException();
339             } finally {
340                 setCallingPackage(original);
341                 Trace.traceEnd(TRACE_TAG_DATABASE);
342             }
343         }
344 
345         @Override
bulkInsert(String callingPkg, @Nullable String attributionTag, Uri uri, ContentValues[] initialValues)346         public int bulkInsert(String callingPkg, @Nullable String attributionTag, Uri uri,
347                 ContentValues[] initialValues) {
348             uri = validateIncomingUri(uri);
349             uri = maybeGetUriWithoutUserId(uri);
350             if (enforceWritePermission(callingPkg, attributionTag, uri, null)
351                     != AppOpsManager.MODE_ALLOWED) {
352                 return 0;
353             }
354             Trace.traceBegin(TRACE_TAG_DATABASE, "bulkInsert");
355             final Pair<String, String> original = setCallingPackage(
356                     new Pair<>(callingPkg, attributionTag));
357             try {
358                 return mInterface.bulkInsert(uri, initialValues);
359             } catch (RemoteException e) {
360                 throw e.rethrowAsRuntimeException();
361             } finally {
362                 setCallingPackage(original);
363                 Trace.traceEnd(TRACE_TAG_DATABASE);
364             }
365         }
366 
367         @Override
applyBatch(String callingPkg, @Nullable String attributionTag, String authority, ArrayList<ContentProviderOperation> operations)368         public ContentProviderResult[] applyBatch(String callingPkg,
369                 @Nullable String attributionTag, String authority,
370                 ArrayList<ContentProviderOperation> operations)
371                 throws OperationApplicationException {
372             validateIncomingAuthority(authority);
373             int numOperations = operations.size();
374             final int[] userIds = new int[numOperations];
375             for (int i = 0; i < numOperations; i++) {
376                 ContentProviderOperation operation = operations.get(i);
377                 Uri uri = operation.getUri();
378                 userIds[i] = getUserIdFromUri(uri);
379                 uri = validateIncomingUri(uri);
380                 uri = maybeGetUriWithoutUserId(uri);
381                 // Rebuild operation if we changed the Uri above
382                 if (!Objects.equals(operation.getUri(), uri)) {
383                     operation = new ContentProviderOperation(operation, uri);
384                     operations.set(i, operation);
385                 }
386                 if (operation.isReadOperation()) {
387                     if (enforceReadPermission(callingPkg, attributionTag, uri, null)
388                             != AppOpsManager.MODE_ALLOWED) {
389                         throw new OperationApplicationException("App op not allowed", 0);
390                     }
391                 }
392                 if (operation.isWriteOperation()) {
393                     if (enforceWritePermission(callingPkg, attributionTag, uri, null)
394                             != AppOpsManager.MODE_ALLOWED) {
395                         throw new OperationApplicationException("App op not allowed", 0);
396                     }
397                 }
398             }
399             Trace.traceBegin(TRACE_TAG_DATABASE, "applyBatch");
400             final Pair<String, String> original = setCallingPackage(
401                     new Pair<>(callingPkg, attributionTag));
402             try {
403                 ContentProviderResult[] results = mInterface.applyBatch(authority,
404                         operations);
405                 if (results != null) {
406                     for (int i = 0; i < results.length ; i++) {
407                         if (userIds[i] != UserHandle.USER_CURRENT) {
408                             // Adding the userId to the uri.
409                             results[i] = new ContentProviderResult(results[i], userIds[i]);
410                         }
411                     }
412                 }
413                 return results;
414             } catch (RemoteException e) {
415                 throw e.rethrowAsRuntimeException();
416             } finally {
417                 setCallingPackage(original);
418                 Trace.traceEnd(TRACE_TAG_DATABASE);
419             }
420         }
421 
422         @Override
delete(String callingPkg, @Nullable String attributionTag, Uri uri, Bundle extras)423         public int delete(String callingPkg, @Nullable String attributionTag, Uri uri,
424                 Bundle extras) {
425             uri = validateIncomingUri(uri);
426             uri = maybeGetUriWithoutUserId(uri);
427             if (enforceWritePermission(callingPkg, attributionTag, uri, null)
428                     != AppOpsManager.MODE_ALLOWED) {
429                 return 0;
430             }
431             Trace.traceBegin(TRACE_TAG_DATABASE, "delete");
432             final Pair<String, String> original = setCallingPackage(
433                     new Pair<>(callingPkg, attributionTag));
434             try {
435                 return mInterface.delete(uri, extras);
436             } catch (RemoteException e) {
437                 throw e.rethrowAsRuntimeException();
438             } finally {
439                 setCallingPackage(original);
440                 Trace.traceEnd(TRACE_TAG_DATABASE);
441             }
442         }
443 
444         @Override
update(String callingPkg, @Nullable String attributionTag, Uri uri, ContentValues values, Bundle extras)445         public int update(String callingPkg, @Nullable String attributionTag, Uri uri,
446                 ContentValues values, Bundle extras) {
447             uri = validateIncomingUri(uri);
448             uri = maybeGetUriWithoutUserId(uri);
449             if (enforceWritePermission(callingPkg, attributionTag, uri, null)
450                     != AppOpsManager.MODE_ALLOWED) {
451                 return 0;
452             }
453             Trace.traceBegin(TRACE_TAG_DATABASE, "update");
454             final Pair<String, String> original = setCallingPackage(
455                     new Pair<>(callingPkg, attributionTag));
456             try {
457                 return mInterface.update(uri, values, extras);
458             } catch (RemoteException e) {
459                 throw e.rethrowAsRuntimeException();
460             } finally {
461                 setCallingPackage(original);
462                 Trace.traceEnd(TRACE_TAG_DATABASE);
463             }
464         }
465 
466         @Override
openFile(String callingPkg, @Nullable String attributionTag, Uri uri, String mode, ICancellationSignal cancellationSignal, IBinder callerToken)467         public ParcelFileDescriptor openFile(String callingPkg, @Nullable String attributionTag,
468                 Uri uri, String mode, ICancellationSignal cancellationSignal, IBinder callerToken)
469                 throws FileNotFoundException {
470             uri = validateIncomingUri(uri);
471             uri = maybeGetUriWithoutUserId(uri);
472             enforceFilePermission(callingPkg, attributionTag, uri, mode, callerToken);
473             Trace.traceBegin(TRACE_TAG_DATABASE, "openFile");
474             final Pair<String, String> original = setCallingPackage(
475                     new Pair<>(callingPkg, attributionTag));
476             try {
477                 return mInterface.openFile(
478                         uri, mode, CancellationSignal.fromTransport(cancellationSignal));
479             } catch (RemoteException e) {
480                 throw e.rethrowAsRuntimeException();
481             } finally {
482                 setCallingPackage(original);
483                 Trace.traceEnd(TRACE_TAG_DATABASE);
484             }
485         }
486 
487         @Override
openAssetFile(String callingPkg, @Nullable String attributionTag, Uri uri, String mode, ICancellationSignal cancellationSignal)488         public AssetFileDescriptor openAssetFile(String callingPkg, @Nullable String attributionTag,
489                 Uri uri, String mode, ICancellationSignal cancellationSignal)
490                 throws FileNotFoundException {
491             uri = validateIncomingUri(uri);
492             uri = maybeGetUriWithoutUserId(uri);
493             enforceFilePermission(callingPkg, attributionTag, uri, mode, null);
494             Trace.traceBegin(TRACE_TAG_DATABASE, "openAssetFile");
495             final Pair<String, String> original = setCallingPackage(
496                     new Pair<>(callingPkg, attributionTag));
497             try {
498                 return mInterface.openAssetFile(
499                         uri, mode, CancellationSignal.fromTransport(cancellationSignal));
500             } catch (RemoteException e) {
501                 throw e.rethrowAsRuntimeException();
502             } finally {
503                 setCallingPackage(original);
504                 Trace.traceEnd(TRACE_TAG_DATABASE);
505             }
506         }
507 
508         @Override
call(String callingPkg, @Nullable String attributionTag, String authority, String method, @Nullable String arg, @Nullable Bundle extras)509         public Bundle call(String callingPkg, @Nullable String attributionTag, String authority,
510                 String method, @Nullable String arg, @Nullable Bundle extras) {
511             validateIncomingAuthority(authority);
512             Bundle.setDefusable(extras, true);
513             Trace.traceBegin(TRACE_TAG_DATABASE, "call");
514             final Pair<String, String> original = setCallingPackage(
515                     new Pair<>(callingPkg, attributionTag));
516             try {
517                 return mInterface.call(authority, method, arg, extras);
518             } catch (RemoteException e) {
519                 throw e.rethrowAsRuntimeException();
520             } finally {
521                 setCallingPackage(original);
522                 Trace.traceEnd(TRACE_TAG_DATABASE);
523             }
524         }
525 
526         @Override
getStreamTypes(Uri uri, String mimeTypeFilter)527         public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
528             // getCallingPackage() isn't available in getType(), as the javadoc states.
529             uri = validateIncomingUri(uri);
530             uri = maybeGetUriWithoutUserId(uri);
531             Trace.traceBegin(TRACE_TAG_DATABASE, "getStreamTypes");
532             try {
533                 return mInterface.getStreamTypes(uri, mimeTypeFilter);
534             } catch (RemoteException e) {
535                 throw e.rethrowAsRuntimeException();
536             } finally {
537                 Trace.traceEnd(TRACE_TAG_DATABASE);
538             }
539         }
540 
541         @Override
openTypedAssetFile(String callingPkg, @Nullable String attributionTag, Uri uri, String mimeType, Bundle opts, ICancellationSignal cancellationSignal)542         public AssetFileDescriptor openTypedAssetFile(String callingPkg,
543                 @Nullable String attributionTag, Uri uri, String mimeType, Bundle opts,
544                 ICancellationSignal cancellationSignal) throws FileNotFoundException {
545             Bundle.setDefusable(opts, true);
546             uri = validateIncomingUri(uri);
547             uri = maybeGetUriWithoutUserId(uri);
548             enforceFilePermission(callingPkg, attributionTag, uri, "r", null);
549             Trace.traceBegin(TRACE_TAG_DATABASE, "openTypedAssetFile");
550             final Pair<String, String> original = setCallingPackage(
551                     new Pair<>(callingPkg, attributionTag));
552             try {
553                 return mInterface.openTypedAssetFile(
554                         uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal));
555             } catch (RemoteException e) {
556                 throw e.rethrowAsRuntimeException();
557             } finally {
558                 setCallingPackage(original);
559                 Trace.traceEnd(TRACE_TAG_DATABASE);
560             }
561         }
562 
563         @Override
createCancellationSignal()564         public ICancellationSignal createCancellationSignal() {
565             return CancellationSignal.createTransport();
566         }
567 
568         @Override
canonicalize(String callingPkg, @Nullable String attributionTag, Uri uri)569         public Uri canonicalize(String callingPkg, @Nullable String attributionTag, Uri uri) {
570             uri = validateIncomingUri(uri);
571             int userId = getUserIdFromUri(uri);
572             uri = getUriWithoutUserId(uri);
573             if (enforceReadPermission(callingPkg, attributionTag, uri, null)
574                     != AppOpsManager.MODE_ALLOWED) {
575                 return null;
576             }
577             Trace.traceBegin(TRACE_TAG_DATABASE, "canonicalize");
578             final Pair<String, String> original = setCallingPackage(
579                     new Pair<>(callingPkg, attributionTag));
580             try {
581                 return maybeAddUserId(mInterface.canonicalize(uri), userId);
582             } catch (RemoteException e) {
583                 throw e.rethrowAsRuntimeException();
584             } finally {
585                 setCallingPackage(original);
586                 Trace.traceEnd(TRACE_TAG_DATABASE);
587             }
588         }
589 
590         @Override
canonicalizeAsync(String callingPkg, @Nullable String attributionTag, Uri uri, RemoteCallback callback)591         public void canonicalizeAsync(String callingPkg, @Nullable String attributionTag, Uri uri,
592                 RemoteCallback callback) {
593             final Bundle result = new Bundle();
594             try {
595                 result.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT,
596                         canonicalize(callingPkg, attributionTag, uri));
597             } catch (Exception e) {
598                 result.putParcelable(ContentResolver.REMOTE_CALLBACK_ERROR,
599                         new ParcelableException(e));
600             }
601             callback.sendResult(result);
602         }
603 
604         @Override
uncanonicalize(String callingPkg, String attributionTag, Uri uri)605         public Uri uncanonicalize(String callingPkg, String attributionTag,  Uri uri) {
606             uri = validateIncomingUri(uri);
607             int userId = getUserIdFromUri(uri);
608             uri = getUriWithoutUserId(uri);
609             if (enforceReadPermission(callingPkg, attributionTag, uri, null)
610                     != AppOpsManager.MODE_ALLOWED) {
611                 return null;
612             }
613             Trace.traceBegin(TRACE_TAG_DATABASE, "uncanonicalize");
614             final Pair<String, String> original = setCallingPackage(
615                     new Pair<>(callingPkg, attributionTag));
616             try {
617                 return maybeAddUserId(mInterface.uncanonicalize(uri), userId);
618             } catch (RemoteException e) {
619                 throw e.rethrowAsRuntimeException();
620             } finally {
621                 setCallingPackage(original);
622                 Trace.traceEnd(TRACE_TAG_DATABASE);
623             }
624         }
625 
626         @Override
refresh(String callingPkg, String attributionTag, Uri uri, Bundle extras, ICancellationSignal cancellationSignal)627         public boolean refresh(String callingPkg, String attributionTag, Uri uri, Bundle extras,
628                 ICancellationSignal cancellationSignal) throws RemoteException {
629             uri = validateIncomingUri(uri);
630             uri = getUriWithoutUserId(uri);
631             if (enforceReadPermission(callingPkg, attributionTag, uri, null)
632                     != AppOpsManager.MODE_ALLOWED) {
633                 return false;
634             }
635             Trace.traceBegin(TRACE_TAG_DATABASE, "refresh");
636             final Pair<String, String> original = setCallingPackage(
637                     new Pair<>(callingPkg, attributionTag));
638             try {
639                 return mInterface.refresh(uri, extras,
640                         CancellationSignal.fromTransport(cancellationSignal));
641             } finally {
642                 setCallingPackage(original);
643                 Trace.traceEnd(TRACE_TAG_DATABASE);
644             }
645         }
646 
647         @Override
checkUriPermission(String callingPkg, @Nullable String attributionTag, Uri uri, int uid, int modeFlags)648         public int checkUriPermission(String callingPkg, @Nullable String attributionTag, Uri uri,
649                 int uid, int modeFlags) {
650             uri = validateIncomingUri(uri);
651             uri = maybeGetUriWithoutUserId(uri);
652             Trace.traceBegin(TRACE_TAG_DATABASE, "checkUriPermission");
653             final Pair<String, String> original = setCallingPackage(
654                     new Pair<>(callingPkg, attributionTag));
655             try {
656                 return mInterface.checkUriPermission(uri, uid, modeFlags);
657             } catch (RemoteException e) {
658                 throw e.rethrowAsRuntimeException();
659             } finally {
660                 setCallingPackage(original);
661                 Trace.traceEnd(TRACE_TAG_DATABASE);
662             }
663         }
664 
enforceFilePermission(String callingPkg, @Nullable String attributionTag, Uri uri, String mode, IBinder callerToken)665         private void enforceFilePermission(String callingPkg, @Nullable String attributionTag,
666                 Uri uri, String mode, IBinder callerToken)
667                 throws FileNotFoundException, SecurityException {
668             if (mode != null && mode.indexOf('w') != -1) {
669                 if (enforceWritePermission(callingPkg, attributionTag, uri, callerToken)
670                         != AppOpsManager.MODE_ALLOWED) {
671                     throw new FileNotFoundException("App op not allowed");
672                 }
673             } else {
674                 if (enforceReadPermission(callingPkg, attributionTag, uri, callerToken)
675                         != AppOpsManager.MODE_ALLOWED) {
676                     throw new FileNotFoundException("App op not allowed");
677                 }
678             }
679         }
680 
enforceReadPermission(String callingPkg, @Nullable String attributionTag, Uri uri, IBinder callerToken)681         private int enforceReadPermission(String callingPkg, @Nullable String attributionTag,
682                 Uri uri, IBinder callerToken)
683                 throws SecurityException {
684             final int mode = enforceReadPermissionInner(uri, callingPkg, attributionTag,
685                     callerToken);
686             if (mode != MODE_ALLOWED) {
687                 return mode;
688             }
689 
690             return noteProxyOp(callingPkg, attributionTag, mReadOp);
691         }
692 
enforceWritePermission(String callingPkg, String attributionTag, Uri uri, IBinder callerToken)693         private int enforceWritePermission(String callingPkg, String attributionTag, Uri uri,
694                 IBinder callerToken)
695                 throws SecurityException {
696             final int mode = enforceWritePermissionInner(uri, callingPkg, attributionTag,
697                     callerToken);
698             if (mode != MODE_ALLOWED) {
699                 return mode;
700             }
701 
702             return noteProxyOp(callingPkg, attributionTag, mWriteOp);
703         }
704 
noteProxyOp(String callingPkg, String attributionTag, int op)705         private int noteProxyOp(String callingPkg, String attributionTag, int op) {
706             if (op != AppOpsManager.OP_NONE) {
707                 int mode = mAppOpsManager.noteProxyOp(op, callingPkg, Binder.getCallingUid(),
708                         attributionTag, null);
709                 return mode == MODE_DEFAULT ? MODE_IGNORED : mode;
710             }
711 
712             return AppOpsManager.MODE_ALLOWED;
713         }
714     }
715 
checkUser(int pid, int uid, Context context)716     boolean checkUser(int pid, int uid, Context context) {
717         if (UserHandle.getUserId(uid) == context.getUserId() || mSingleUser) {
718             return true;
719         }
720         return context.checkPermission(INTERACT_ACROSS_USERS, pid, uid) == PERMISSION_GRANTED
721                 || context.checkPermission(INTERACT_ACROSS_USERS_FULL, pid, uid)
722                 == PERMISSION_GRANTED;
723     }
724 
725     /**
726      * Verify that calling app holds both the given permission and any app-op
727      * associated with that permission.
728      */
checkPermissionAndAppOp(String permission, String callingPkg, @Nullable String attributionTag, IBinder callerToken)729     private int checkPermissionAndAppOp(String permission, String callingPkg,
730             @Nullable String attributionTag, IBinder callerToken) {
731         if (getContext().checkPermission(permission, Binder.getCallingPid(), Binder.getCallingUid(),
732                 callerToken) != PERMISSION_GRANTED) {
733             return MODE_ERRORED;
734         }
735 
736         return mTransport.noteProxyOp(callingPkg, attributionTag,
737                 AppOpsManager.permissionToOpCode(permission));
738     }
739 
740     /** {@hide} */
enforceReadPermissionInner(Uri uri, String callingPkg, @Nullable String attributionTag, IBinder callerToken)741     protected int enforceReadPermissionInner(Uri uri, String callingPkg,
742             @Nullable String attributionTag, IBinder callerToken) throws SecurityException {
743         final Context context = getContext();
744         final int pid = Binder.getCallingPid();
745         final int uid = Binder.getCallingUid();
746         String missingPerm = null;
747         int strongestMode = MODE_ALLOWED;
748 
749         if (UserHandle.isSameApp(uid, mMyUid)) {
750             return MODE_ALLOWED;
751         }
752 
753         if (mExported && checkUser(pid, uid, context)) {
754             final String componentPerm = getReadPermission();
755             if (componentPerm != null) {
756                 final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, attributionTag,
757                         callerToken);
758                 if (mode == MODE_ALLOWED) {
759                     return MODE_ALLOWED;
760                 } else {
761                     missingPerm = componentPerm;
762                     strongestMode = Math.max(strongestMode, mode);
763                 }
764             }
765 
766             // track if unprotected read is allowed; any denied
767             // <path-permission> below removes this ability
768             boolean allowDefaultRead = (componentPerm == null);
769 
770             final PathPermission[] pps = getPathPermissions();
771             if (pps != null) {
772                 final String path = uri.getPath();
773                 for (PathPermission pp : pps) {
774                     final String pathPerm = pp.getReadPermission();
775                     if (pathPerm != null && pp.match(path)) {
776                         final int mode = checkPermissionAndAppOp(pathPerm, callingPkg,
777                                 attributionTag, callerToken);
778                         if (mode == MODE_ALLOWED) {
779                             return MODE_ALLOWED;
780                         } else {
781                             // any denied <path-permission> means we lose
782                             // default <provider> access.
783                             allowDefaultRead = false;
784                             missingPerm = pathPerm;
785                             strongestMode = Math.max(strongestMode, mode);
786                         }
787                     }
788                 }
789             }
790 
791             // if we passed <path-permission> checks above, and no default
792             // <provider> permission, then allow access.
793             if (allowDefaultRead) return MODE_ALLOWED;
794         }
795 
796         // last chance, check against any uri grants
797         final int callingUserId = UserHandle.getUserId(uid);
798         final Uri userUri = (mSingleUser && !UserHandle.isSameUser(mMyUid, uid))
799                 ? maybeAddUserId(uri, callingUserId) : uri;
800         if (context.checkUriPermission(userUri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION,
801                 callerToken) == PERMISSION_GRANTED) {
802             return MODE_ALLOWED;
803         }
804 
805         // If the worst denial we found above was ignored, then pass that
806         // ignored through; otherwise we assume it should be a real error below.
807         if (strongestMode == MODE_IGNORED) {
808             return MODE_IGNORED;
809         }
810 
811         final String suffix;
812         if (android.Manifest.permission.MANAGE_DOCUMENTS.equals(mReadPermission)) {
813             suffix = " requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs";
814         } else if (mExported) {
815             suffix = " requires " + missingPerm + ", or grantUriPermission()";
816         } else {
817             suffix = " requires the provider be exported, or grantUriPermission()";
818         }
819         throw new SecurityException("Permission Denial: reading "
820                 + ContentProvider.this.getClass().getName() + " uri " + uri + " from pid=" + pid
821                 + ", uid=" + uid + suffix);
822     }
823 
824     /** {@hide} */
enforceWritePermissionInner(Uri uri, String callingPkg, @Nullable String attributionTag, IBinder callerToken)825     protected int enforceWritePermissionInner(Uri uri, String callingPkg,
826             @Nullable String attributionTag, IBinder callerToken) throws SecurityException {
827         final Context context = getContext();
828         final int pid = Binder.getCallingPid();
829         final int uid = Binder.getCallingUid();
830         String missingPerm = null;
831         int strongestMode = MODE_ALLOWED;
832 
833         if (UserHandle.isSameApp(uid, mMyUid)) {
834             return MODE_ALLOWED;
835         }
836 
837         if (mExported && checkUser(pid, uid, context)) {
838             final String componentPerm = getWritePermission();
839             if (componentPerm != null) {
840                 final int mode = checkPermissionAndAppOp(componentPerm, callingPkg,
841                         attributionTag, callerToken);
842                 if (mode == MODE_ALLOWED) {
843                     return MODE_ALLOWED;
844                 } else {
845                     missingPerm = componentPerm;
846                     strongestMode = Math.max(strongestMode, mode);
847                 }
848             }
849 
850             // track if unprotected write is allowed; any denied
851             // <path-permission> below removes this ability
852             boolean allowDefaultWrite = (componentPerm == null);
853 
854             final PathPermission[] pps = getPathPermissions();
855             if (pps != null) {
856                 final String path = uri.getPath();
857                 for (PathPermission pp : pps) {
858                     final String pathPerm = pp.getWritePermission();
859                     if (pathPerm != null && pp.match(path)) {
860                         final int mode = checkPermissionAndAppOp(pathPerm, callingPkg,
861                                 attributionTag, callerToken);
862                         if (mode == MODE_ALLOWED) {
863                             return MODE_ALLOWED;
864                         } else {
865                             // any denied <path-permission> means we lose
866                             // default <provider> access.
867                             allowDefaultWrite = false;
868                             missingPerm = pathPerm;
869                             strongestMode = Math.max(strongestMode, mode);
870                         }
871                     }
872                 }
873             }
874 
875             // if we passed <path-permission> checks above, and no default
876             // <provider> permission, then allow access.
877             if (allowDefaultWrite) return MODE_ALLOWED;
878         }
879 
880         // last chance, check against any uri grants
881         if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
882                 callerToken) == PERMISSION_GRANTED) {
883             return MODE_ALLOWED;
884         }
885 
886         // If the worst denial we found above was ignored, then pass that
887         // ignored through; otherwise we assume it should be a real error below.
888         if (strongestMode == MODE_IGNORED) {
889             return MODE_IGNORED;
890         }
891 
892         final String failReason = mExported
893                 ? " requires " + missingPerm + ", or grantUriPermission()"
894                 : " requires the provider be exported, or grantUriPermission()";
895         throw new SecurityException("Permission Denial: writing "
896                 + ContentProvider.this.getClass().getName() + " uri " + uri + " from pid=" + pid
897                 + ", uid=" + uid + failReason);
898     }
899 
900     /**
901      * Retrieves the Context this provider is running in.  Only available once
902      * {@link #onCreate} has been called -- this will return {@code null} in the
903      * constructor.
904      */
getContext()905     public final @Nullable Context getContext() {
906         return mContext;
907     }
908 
909     /**
910      * Retrieves a Non-Nullable Context this provider is running in, this is intended to be called
911      * after {@link #onCreate}. When called before context was created, an IllegalStateException
912      * will be thrown.
913      * <p>
914      * Note A provider must be declared in the manifest and created automatically by the system,
915      * and context is only available after {@link #onCreate} is called.
916      */
917     @NonNull
requireContext()918     public final Context requireContext() {
919         final Context ctx = getContext();
920         if (ctx == null) {
921             throw new IllegalStateException("Cannot find context from the provider.");
922         }
923         return ctx;
924     }
925 
926     /**
927      * Set the calling package/feature, returning the current value (or {@code null})
928      * which can be used later to restore the previous state.
929      */
setCallingPackage(Pair<String, String> callingPackage)930     private Pair<String, String> setCallingPackage(Pair<String, String> callingPackage) {
931         final Pair<String, String> original = mCallingPackage.get();
932         mCallingPackage.set(callingPackage);
933         onCallingPackageChanged();
934         return original;
935     }
936 
937     /**
938      * Return the package name of the caller that initiated the request being
939      * processed on the current thread. The returned package will have been
940      * verified to belong to the calling UID. Returns {@code null} if not
941      * currently processing a request.
942      * <p>
943      * This will always return {@code null} when processing
944      * {@link #getType(Uri)} or {@link #getStreamTypes(Uri, String)} requests.
945      *
946      * @see Binder#getCallingUid()
947      * @see Context#grantUriPermission(String, Uri, int)
948      * @throws SecurityException if the calling package doesn't belong to the
949      *             calling UID.
950      */
getCallingPackage()951     public final @Nullable String getCallingPackage() {
952         final Pair<String, String> pkg = mCallingPackage.get();
953         if (pkg != null) {
954             mTransport.mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg.first);
955             return pkg.first;
956         }
957 
958         return null;
959     }
960 
961     /**
962      * Return the attribution tag of the caller that initiated the request being
963      * processed on the current thread. Returns {@code null} if not currently processing
964      * a request of the request is for the default attribution.
965      * <p>
966      * This will always return {@code null} when processing
967      * {@link #getType(Uri)} or {@link #getStreamTypes(Uri, String)} requests.
968      *
969      * @see #getCallingPackage
970      */
getCallingAttributionTag()971     public final @Nullable String getCallingAttributionTag() {
972         final Pair<String, String> pkg = mCallingPackage.get();
973         if (pkg != null) {
974             return pkg.second;
975         }
976 
977         return null;
978     }
979 
980     /**
981      * @removed
982      */
983     @Deprecated
getCallingFeatureId()984     public final @Nullable String getCallingFeatureId() {
985         return getCallingAttributionTag();
986     }
987 
988     /**
989      * Return the package name of the caller that initiated the request being
990      * processed on the current thread. The returned package will have
991      * <em>not</em> been verified to belong to the calling UID. Returns
992      * {@code null} if not currently processing a request.
993      * <p>
994      * This will always return {@code null} when processing
995      * {@link #getType(Uri)} or {@link #getStreamTypes(Uri, String)} requests.
996      *
997      * @see Binder#getCallingUid()
998      * @see Context#grantUriPermission(String, Uri, int)
999      */
getCallingPackageUnchecked()1000     public final @Nullable String getCallingPackageUnchecked() {
1001         final Pair<String, String> pkg = mCallingPackage.get();
1002         if (pkg != null) {
1003             return pkg.first;
1004         }
1005 
1006         return null;
1007     }
1008 
1009     /**
1010      * Called whenever the value of {@link #getCallingPackage()} changes, giving
1011      * the provider an opportunity to invalidate any security related caching it
1012      * may be performing.
1013      * <p>
1014      * This typically happens when a {@link ContentProvider} makes a nested call
1015      * back into itself when already processing a call from a remote process.
1016      */
onCallingPackageChanged()1017     public void onCallingPackageChanged() {
1018     }
1019 
1020     /**
1021      * Opaque token representing the identity of an incoming IPC.
1022      */
1023     public final class CallingIdentity {
1024         /** {@hide} */
1025         public final long binderToken;
1026         /** {@hide} */
1027         public final Pair<String, String> callingPackage;
1028 
1029         /** {@hide} */
CallingIdentity(long binderToken, Pair<String, String> callingPackage)1030         public CallingIdentity(long binderToken, Pair<String, String> callingPackage) {
1031             this.binderToken = binderToken;
1032             this.callingPackage = callingPackage;
1033         }
1034     }
1035 
1036     /**
1037      * Reset the identity of the incoming IPC on the current thread.
1038      * <p>
1039      * Internally this calls {@link Binder#clearCallingIdentity()} and also
1040      * clears any value stored in {@link #getCallingPackage()}.
1041      *
1042      * @return Returns an opaque token that can be used to restore the original
1043      *         calling identity by passing it to
1044      *         {@link #restoreCallingIdentity}.
1045      */
clearCallingIdentity()1046     public final @NonNull CallingIdentity clearCallingIdentity() {
1047         return new CallingIdentity(Binder.clearCallingIdentity(), setCallingPackage(null));
1048     }
1049 
1050     /**
1051      * Restore the identity of the incoming IPC on the current thread back to a
1052      * previously identity that was returned by {@link #clearCallingIdentity}.
1053      * <p>
1054      * Internally this calls {@link Binder#restoreCallingIdentity(long)} and
1055      * also restores any value stored in {@link #getCallingPackage()}.
1056      */
restoreCallingIdentity(@onNull CallingIdentity identity)1057     public final void restoreCallingIdentity(@NonNull CallingIdentity identity) {
1058         Binder.restoreCallingIdentity(identity.binderToken);
1059         mCallingPackage.set(identity.callingPackage);
1060     }
1061 
1062     /**
1063      * Change the authorities of the ContentProvider.
1064      * This is normally set for you from its manifest information when the provider is first
1065      * created.
1066      * @hide
1067      * @param authorities the semi-colon separated authorities of the ContentProvider.
1068      */
setAuthorities(String authorities)1069     protected final void setAuthorities(String authorities) {
1070         if (authorities != null) {
1071             if (authorities.indexOf(';') == -1) {
1072                 mAuthority = authorities;
1073                 mAuthorities = null;
1074             } else {
1075                 mAuthority = null;
1076                 mAuthorities = authorities.split(";");
1077             }
1078         }
1079     }
1080 
1081     /** @hide */
matchesOurAuthorities(String authority)1082     protected final boolean matchesOurAuthorities(String authority) {
1083         if (mAuthority != null) {
1084             return mAuthority.equals(authority);
1085         }
1086         if (mAuthorities != null) {
1087             int length = mAuthorities.length;
1088             for (int i = 0; i < length; i++) {
1089                 if (mAuthorities[i].equals(authority)) return true;
1090             }
1091         }
1092         return false;
1093     }
1094 
1095 
1096     /**
1097      * Change the permission required to read data from the content
1098      * provider.  This is normally set for you from its manifest information
1099      * when the provider is first created.
1100      *
1101      * @param permission Name of the permission required for read-only access.
1102      */
setReadPermission(@ullable String permission)1103     protected final void setReadPermission(@Nullable String permission) {
1104         mReadPermission = permission;
1105     }
1106 
1107     /**
1108      * Return the name of the permission required for read-only access to
1109      * this content provider.  This method can be called from multiple
1110      * threads, as described in
1111      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
1112      * and Threads</a>.
1113      */
getReadPermission()1114     public final @Nullable String getReadPermission() {
1115         return mReadPermission;
1116     }
1117 
1118     /**
1119      * Change the permission required to read and write data in the content
1120      * provider.  This is normally set for you from its manifest information
1121      * when the provider is first created.
1122      *
1123      * @param permission Name of the permission required for read/write access.
1124      */
setWritePermission(@ullable String permission)1125     protected final void setWritePermission(@Nullable String permission) {
1126         mWritePermission = permission;
1127     }
1128 
1129     /**
1130      * Return the name of the permission required for read/write access to
1131      * this content provider.  This method can be called from multiple
1132      * threads, as described in
1133      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
1134      * and Threads</a>.
1135      */
getWritePermission()1136     public final @Nullable String getWritePermission() {
1137         return mWritePermission;
1138     }
1139 
1140     /**
1141      * Change the path-based permission required to read and/or write data in
1142      * the content provider.  This is normally set for you from its manifest
1143      * information when the provider is first created.
1144      *
1145      * @param permissions Array of path permission descriptions.
1146      */
setPathPermissions(@ullable PathPermission[] permissions)1147     protected final void setPathPermissions(@Nullable PathPermission[] permissions) {
1148         mPathPermissions = permissions;
1149     }
1150 
1151     /**
1152      * Return the path-based permissions required for read and/or write access to
1153      * this content provider.  This method can be called from multiple
1154      * threads, as described in
1155      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
1156      * and Threads</a>.
1157      */
getPathPermissions()1158     public final @Nullable PathPermission[] getPathPermissions() {
1159         return mPathPermissions;
1160     }
1161 
1162     /** @hide */
1163     @UnsupportedAppUsage
setAppOps(int readOp, int writeOp)1164     public final void setAppOps(int readOp, int writeOp) {
1165         if (!mNoPerms) {
1166             mTransport.mReadOp = readOp;
1167             mTransport.mWriteOp = writeOp;
1168         }
1169     }
1170 
1171     /** @hide */
getAppOpsManager()1172     public AppOpsManager getAppOpsManager() {
1173         return mTransport.mAppOpsManager;
1174     }
1175 
1176     /** @hide */
setTransportLoggingEnabled(boolean enabled)1177     public final void setTransportLoggingEnabled(boolean enabled) {
1178         if (mTransport == null) {
1179             return;
1180         }
1181         if (enabled) {
1182             mTransport.mInterface = new LoggingContentInterface(getClass().getSimpleName(), this);
1183         } else {
1184             mTransport.mInterface = this;
1185         }
1186     }
1187 
1188     /**
1189      * Implement this to initialize your content provider on startup.
1190      * This method is called for all registered content providers on the
1191      * application main thread at application launch time.  It must not perform
1192      * lengthy operations, or application startup will be delayed.
1193      *
1194      * <p>You should defer nontrivial initialization (such as opening,
1195      * upgrading, and scanning databases) until the content provider is used
1196      * (via {@link #query}, {@link #insert}, etc).  Deferred initialization
1197      * keeps application startup fast, avoids unnecessary work if the provider
1198      * turns out not to be needed, and stops database errors (such as a full
1199      * disk) from halting application launch.
1200      *
1201      * <p>If you use SQLite, {@link android.database.sqlite.SQLiteOpenHelper}
1202      * is a helpful utility class that makes it easy to manage databases,
1203      * and will automatically defer opening until first use.  If you do use
1204      * SQLiteOpenHelper, make sure to avoid calling
1205      * {@link android.database.sqlite.SQLiteOpenHelper#getReadableDatabase} or
1206      * {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase}
1207      * from this method.  (Instead, override
1208      * {@link android.database.sqlite.SQLiteOpenHelper#onOpen} to initialize the
1209      * database when it is first opened.)
1210      *
1211      * @return true if the provider was successfully loaded, false otherwise
1212      */
onCreate()1213     public abstract boolean onCreate();
1214 
1215     /**
1216      * {@inheritDoc}
1217      * This method is always called on the application main thread, and must
1218      * not perform lengthy operations.
1219      *
1220      * <p>The default content provider implementation does nothing.
1221      * Override this method to take appropriate action.
1222      * (Content providers do not usually care about things like screen
1223      * orientation, but may want to know about locale changes.)
1224      */
1225     @Override
onConfigurationChanged(Configuration newConfig)1226     public void onConfigurationChanged(Configuration newConfig) {
1227     }
1228 
1229     /**
1230      * {@inheritDoc}
1231      * This method is always called on the application main thread, and must
1232      * not perform lengthy operations.
1233      *
1234      * <p>The default content provider implementation does nothing.
1235      * Subclasses may override this method to take appropriate action.
1236      */
1237     @Override
onLowMemory()1238     public void onLowMemory() {
1239     }
1240 
1241     @Override
onTrimMemory(int level)1242     public void onTrimMemory(int level) {
1243     }
1244 
1245     /**
1246      * Implement this to handle query requests from clients.
1247      *
1248      * <p>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher should override
1249      * {@link #query(Uri, String[], Bundle, CancellationSignal)} and provide a stub
1250      * implementation of this method.
1251      *
1252      * <p>This method can be called from multiple threads, as described in
1253      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
1254      * and Threads</a>.
1255      * <p>
1256      * Example client call:<p>
1257      * <pre>// Request a specific record.
1258      * Cursor managedCursor = managedQuery(
1259                 ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2),
1260                 projection,    // Which columns to return.
1261                 null,          // WHERE clause.
1262                 null,          // WHERE clause value substitution
1263                 People.NAME + " ASC");   // Sort order.</pre>
1264      * Example implementation:<p>
1265      * <pre>// SQLiteQueryBuilder is a helper class that creates the
1266         // proper SQL syntax for us.
1267         SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
1268 
1269         // Set the table we're querying.
1270         qBuilder.setTables(DATABASE_TABLE_NAME);
1271 
1272         // If the query ends in a specific record number, we're
1273         // being asked for a specific record, so set the
1274         // WHERE clause in our query.
1275         if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){
1276             qBuilder.appendWhere("_id=" + uri.getPathLeafId());
1277         }
1278 
1279         // Make the query.
1280         Cursor c = qBuilder.query(mDb,
1281                 projection,
1282                 selection,
1283                 selectionArgs,
1284                 groupBy,
1285                 having,
1286                 sortOrder);
1287         c.setNotificationUri(getContext().getContentResolver(), uri);
1288         return c;</pre>
1289      *
1290      * @param uri The URI to query. This will be the full URI sent by the client;
1291      *      if the client is requesting a specific record, the URI will end in a record number
1292      *      that the implementation should parse and add to a WHERE or HAVING clause, specifying
1293      *      that _id value.
1294      * @param projection The list of columns to put into the cursor. If
1295      *      {@code null} all columns are included.
1296      * @param selection A selection criteria to apply when filtering rows.
1297      *      If {@code null} then all rows are included.
1298      * @param selectionArgs You may include ?s in selection, which will be replaced by
1299      *      the values from selectionArgs, in order that they appear in the selection.
1300      *      The values will be bound as Strings.
1301      * @param sortOrder How the rows in the cursor should be sorted.
1302      *      If {@code null} then the provider is free to define the sort order.
1303      * @return a Cursor or {@code null}.
1304      */
query(@onNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder)1305     public abstract @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
1306             @Nullable String selection, @Nullable String[] selectionArgs,
1307             @Nullable String sortOrder);
1308 
1309     /**
1310      * Implement this to handle query requests from clients with support for cancellation.
1311      *
1312      * <p>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher should override
1313      * {@link #query(Uri, String[], Bundle, CancellationSignal)} instead of this method.
1314      *
1315      * <p>This method can be called from multiple threads, as described in
1316      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
1317      * and Threads</a>.
1318      * <p>
1319      * Example client call:<p>
1320      * <pre>// Request a specific record.
1321      * Cursor managedCursor = managedQuery(
1322                 ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2),
1323                 projection,    // Which columns to return.
1324                 null,          // WHERE clause.
1325                 null,          // WHERE clause value substitution
1326                 People.NAME + " ASC");   // Sort order.</pre>
1327      * Example implementation:<p>
1328      * <pre>// SQLiteQueryBuilder is a helper class that creates the
1329         // proper SQL syntax for us.
1330         SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
1331 
1332         // Set the table we're querying.
1333         qBuilder.setTables(DATABASE_TABLE_NAME);
1334 
1335         // If the query ends in a specific record number, we're
1336         // being asked for a specific record, so set the
1337         // WHERE clause in our query.
1338         if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){
1339             qBuilder.appendWhere("_id=" + uri.getPathLeafId());
1340         }
1341 
1342         // Make the query.
1343         Cursor c = qBuilder.query(mDb,
1344                 projection,
1345                 selection,
1346                 selectionArgs,
1347                 groupBy,
1348                 having,
1349                 sortOrder);
1350         c.setNotificationUri(getContext().getContentResolver(), uri);
1351         return c;</pre>
1352      * <p>
1353      * If you implement this method then you must also implement the version of
1354      * {@link #query(Uri, String[], String, String[], String)} that does not take a cancellation
1355      * signal to ensure correct operation on older versions of the Android Framework in
1356      * which the cancellation signal overload was not available.
1357      *
1358      * @param uri The URI to query. This will be the full URI sent by the client;
1359      *      if the client is requesting a specific record, the URI will end in a record number
1360      *      that the implementation should parse and add to a WHERE or HAVING clause, specifying
1361      *      that _id value.
1362      * @param projection The list of columns to put into the cursor. If
1363      *      {@code null} all columns are included.
1364      * @param selection A selection criteria to apply when filtering rows.
1365      *      If {@code null} then all rows are included.
1366      * @param selectionArgs You may include ?s in selection, which will be replaced by
1367      *      the values from selectionArgs, in order that they appear in the selection.
1368      *      The values will be bound as Strings.
1369      * @param sortOrder How the rows in the cursor should be sorted.
1370      *      If {@code null} then the provider is free to define the sort order.
1371      * @param cancellationSignal A signal to cancel the operation in progress, or {@code null} if none.
1372      * If the operation is canceled, then {@link android.os.OperationCanceledException} will be thrown
1373      * when the query is executed.
1374      * @return a Cursor or {@code null}.
1375      */
query(@onNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal)1376     public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
1377             @Nullable String selection, @Nullable String[] selectionArgs,
1378             @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) {
1379         return query(uri, projection, selection, selectionArgs, sortOrder);
1380     }
1381 
1382     /**
1383      * Implement this to handle query requests where the arguments are packed into a {@link Bundle}.
1384      * Arguments may include traditional SQL style query arguments. When present these
1385      * should be handled  according to the contract established in
1386      * {@link #query(Uri, String[], String, String[], String, CancellationSignal)}.
1387      *
1388      * <p>Traditional SQL arguments can be found in the bundle using the following keys:
1389      * <li>{@link android.content.ContentResolver#QUERY_ARG_SQL_SELECTION}
1390      * <li>{@link android.content.ContentResolver#QUERY_ARG_SQL_SELECTION_ARGS}
1391      * <li>{@link android.content.ContentResolver#QUERY_ARG_SQL_SORT_ORDER}
1392      *
1393      * <p>This method can be called from multiple threads, as described in
1394      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
1395      * and Threads</a>.
1396      *
1397      * <p>
1398      * Example client call:<p>
1399      * <pre>// Request 20 records starting at row index 30.
1400        Bundle queryArgs = new Bundle();
1401        queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 30);
1402        queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 20);
1403 
1404        Cursor cursor = getContentResolver().query(
1405                 contentUri,    // Content Uri is specific to individual content providers.
1406                 projection,    // String[] describing which columns to return.
1407                 queryArgs,     // Query arguments.
1408                 null);         // Cancellation signal.</pre>
1409      *
1410      * Example implementation:<p>
1411      * <pre>
1412 
1413         int recordsetSize = 0x1000;  // Actual value is implementation specific.
1414         queryArgs = queryArgs != null ? queryArgs : Bundle.EMPTY;  // ensure queryArgs is non-null
1415 
1416         int offset = queryArgs.getInt(ContentResolver.QUERY_ARG_OFFSET, 0);
1417         int limit = queryArgs.getInt(ContentResolver.QUERY_ARG_LIMIT, Integer.MIN_VALUE);
1418 
1419         MatrixCursor c = new MatrixCursor(PROJECTION, limit);
1420 
1421         // Calculate the number of items to include in the cursor.
1422         int numItems = MathUtils.constrain(recordsetSize - offset, 0, limit);
1423 
1424         // Build the paged result set....
1425         for (int i = offset; i < offset + numItems; i++) {
1426             // populate row from your data.
1427         }
1428 
1429         Bundle extras = new Bundle();
1430         c.setExtras(extras);
1431 
1432         // Any QUERY_ARG_* key may be included if honored.
1433         // In an actual implementation, include only keys that are both present in queryArgs
1434         // and reflected in the Cursor output. For example, if QUERY_ARG_OFFSET were included
1435         // in queryArgs, but was ignored because it contained an invalid value (like –273),
1436         // then QUERY_ARG_OFFSET should be omitted.
1437         extras.putStringArray(ContentResolver.EXTRA_HONORED_ARGS, new String[] {
1438             ContentResolver.QUERY_ARG_OFFSET,
1439             ContentResolver.QUERY_ARG_LIMIT
1440         });
1441 
1442         extras.putInt(ContentResolver.EXTRA_TOTAL_COUNT, recordsetSize);
1443 
1444         cursor.setNotificationUri(getContext().getContentResolver(), uri);
1445 
1446         return cursor;</pre>
1447      * <p>
1448      * See {@link #query(Uri, String[], String, String[], String, CancellationSignal)}
1449      * for implementation details.
1450      *
1451      * @param uri The URI to query. This will be the full URI sent by the client.
1452      * @param projection The list of columns to put into the cursor.
1453      *            If {@code null} provide a default set of columns.
1454      * @param queryArgs A Bundle containing additional information necessary for
1455      *            the operation. Arguments may include SQL style arguments, such
1456      *            as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
1457      *            the documentation for each individual provider will indicate
1458      *            which arguments they support.
1459      * @param cancellationSignal A signal to cancel the operation in progress,
1460      *            or {@code null}.
1461      * @return a Cursor or {@code null}.
1462      */
1463     @Override
query(@onNull Uri uri, @Nullable String[] projection, @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal)1464     public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
1465             @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal) {
1466         queryArgs = queryArgs != null ? queryArgs : Bundle.EMPTY;
1467 
1468         // if client doesn't supply an SQL sort order argument, attempt to build one from
1469         // QUERY_ARG_SORT* arguments.
1470         String sortClause = queryArgs.getString(ContentResolver.QUERY_ARG_SQL_SORT_ORDER);
1471         if (sortClause == null && queryArgs.containsKey(ContentResolver.QUERY_ARG_SORT_COLUMNS)) {
1472             sortClause = ContentResolver.createSqlSortClause(queryArgs);
1473         }
1474 
1475         return query(
1476                 uri,
1477                 projection,
1478                 queryArgs.getString(ContentResolver.QUERY_ARG_SQL_SELECTION),
1479                 queryArgs.getStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS),
1480                 sortClause,
1481                 cancellationSignal);
1482     }
1483 
1484     /**
1485      * Implement this to handle requests for the MIME type of the data at the
1486      * given URI.  The returned MIME type should start with
1487      * <code>vnd.android.cursor.item</code> for a single record,
1488      * or <code>vnd.android.cursor.dir/</code> for multiple items.
1489      * This method can be called from multiple threads, as described in
1490      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
1491      * and Threads</a>.
1492      *
1493      * <p>Note that there are no permissions needed for an application to
1494      * access this information; if your content provider requires read and/or
1495      * write permissions, or is not exported, all applications can still call
1496      * this method regardless of their access permissions.  This allows them
1497      * to retrieve the MIME type for a URI when dispatching intents.
1498      *
1499      * @param uri the URI to query.
1500      * @return a MIME type string, or {@code null} if there is no type.
1501      */
1502     @Override
getType(@onNull Uri uri)1503     public abstract @Nullable String getType(@NonNull Uri uri);
1504 
1505     /**
1506      * Implement this to support canonicalization of URIs that refer to your
1507      * content provider.  A canonical URI is one that can be transported across
1508      * devices, backup/restore, and other contexts, and still be able to refer
1509      * to the same data item.  Typically this is implemented by adding query
1510      * params to the URI allowing the content provider to verify that an incoming
1511      * canonical URI references the same data as it was originally intended for and,
1512      * if it doesn't, to find that data (if it exists) in the current environment.
1513      *
1514      * <p>For example, if the content provider holds people and a normal URI in it
1515      * is created with a row index into that people database, the cananical representation
1516      * may have an additional query param at the end which specifies the name of the
1517      * person it is intended for.  Later calls into the provider with that URI will look
1518      * up the row of that URI's base index and, if it doesn't match or its entry's
1519      * name doesn't match the name in the query param, perform a query on its database
1520      * to find the correct row to operate on.</p>
1521      *
1522      * <p>If you implement support for canonical URIs, <b>all</b> incoming calls with
1523      * URIs (including this one) must perform this verification and recovery of any
1524      * canonical URIs they receive.  In addition, you must also implement
1525      * {@link #uncanonicalize} to strip the canonicalization of any of these URIs.</p>
1526      *
1527      * <p>The default implementation of this method returns null, indicating that
1528      * canonical URIs are not supported.</p>
1529      *
1530      * @param url The Uri to canonicalize.
1531      *
1532      * @return Return the canonical representation of <var>url</var>, or null if
1533      * canonicalization of that Uri is not supported.
1534      */
1535     @Override
canonicalize(@onNull Uri url)1536     public @Nullable Uri canonicalize(@NonNull Uri url) {
1537         return null;
1538     }
1539 
1540     /**
1541      * Remove canonicalization from canonical URIs previously returned by
1542      * {@link #canonicalize}.  For example, if your implementation is to add
1543      * a query param to canonicalize a URI, this method can simply trip any
1544      * query params on the URI.  The default implementation always returns the
1545      * same <var>url</var> that was passed in.
1546      *
1547      * @param url The Uri to remove any canonicalization from.
1548      *
1549      * @return Return the non-canonical representation of <var>url</var>, return
1550      * the <var>url</var> as-is if there is nothing to do, or return null if
1551      * the data identified by the canonical representation can not be found in
1552      * the current environment.
1553      */
1554     @Override
uncanonicalize(@onNull Uri url)1555     public @Nullable Uri uncanonicalize(@NonNull Uri url) {
1556         return url;
1557     }
1558 
1559     /**
1560      * Implement this to support refresh of content identified by {@code uri}.
1561      * By default, this method returns false; providers who wish to implement
1562      * this should return true to signal the client that the provider has tried
1563      * refreshing with its own implementation.
1564      * <p>
1565      * This allows clients to request an explicit refresh of content identified
1566      * by {@code uri}.
1567      * <p>
1568      * Client code should only invoke this method when there is a strong
1569      * indication (such as a user initiated pull to refresh gesture) that the
1570      * content is stale.
1571      * <p>
1572      * Remember to send
1573      * {@link ContentResolver#notifyChange(Uri, android.database.ContentObserver)}
1574      * notifications when content changes.
1575      *
1576      * @param uri The Uri identifying the data to refresh.
1577      * @param extras Additional options from the client. The definitions of
1578      *            these are specific to the content provider being called.
1579      * @param cancellationSignal A signal to cancel the operation in progress,
1580      *            or {@code null} if none. For example, if you called refresh on
1581      *            a particular uri, you should call
1582      *            {@link CancellationSignal#throwIfCanceled()} to check whether
1583      *            the client has canceled the refresh request.
1584      * @return true if the provider actually tried refreshing.
1585      */
1586     @Override
refresh(Uri uri, @Nullable Bundle extras, @Nullable CancellationSignal cancellationSignal)1587     public boolean refresh(Uri uri, @Nullable Bundle extras,
1588             @Nullable CancellationSignal cancellationSignal) {
1589         return false;
1590     }
1591 
1592     /**
1593      * Perform a detailed internal check on a {@link Uri} to determine if a UID
1594      * is able to access it with specific mode flags.
1595      * <p>
1596      * This method is typically used when the provider implements more dynamic
1597      * access controls that cannot be expressed with {@code <path-permission>}
1598      * style static rules.
1599      * <p>
1600      * Because validation of these dynamic access controls has significant
1601      * system health impact, this feature is only available to providers that
1602      * are built into the system.
1603      *
1604      * @param uri the {@link Uri} to perform an access check on.
1605      * @param uid the UID to check the permission for.
1606      * @param modeFlags the access flags to use for the access check, such as
1607      *            {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}.
1608      * @return {@link PackageManager#PERMISSION_GRANTED} if access is allowed,
1609      *         otherwise {@link PackageManager#PERMISSION_DENIED}.
1610      * @hide
1611      */
1612     @Override
1613     @SystemApi
checkUriPermission(@onNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags)1614     public int checkUriPermission(@NonNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags) {
1615         return PackageManager.PERMISSION_DENIED;
1616     }
1617 
1618     /**
1619      * @hide
1620      * Implementation when a caller has performed an insert on the content
1621      * provider, but that call has been rejected for the operation given
1622      * to {@link #setAppOps(int, int)}.  The default implementation simply
1623      * returns a dummy URI that is the base URI with a 0 path element
1624      * appended.
1625      */
rejectInsert(Uri uri, ContentValues values)1626     public Uri rejectInsert(Uri uri, ContentValues values) {
1627         // If not allowed, we need to return some reasonable URI.  Maybe the
1628         // content provider should be responsible for this, but for now we
1629         // will just return the base URI with a dummy '0' tagged on to it.
1630         // You shouldn't be able to read if you can't write, anyway, so it
1631         // shouldn't matter much what is returned.
1632         return uri.buildUpon().appendPath("0").build();
1633     }
1634 
1635     /**
1636      * Implement this to handle requests to insert a new row. As a courtesy,
1637      * call
1638      * {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver)
1639      * notifyChange()} after inserting. This method can be called from multiple
1640      * threads, as described in <a href="
1641      * {@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
1642      * and Threads</a>.
1643      *
1644      * @param uri The content:// URI of the insertion request.
1645      * @param values A set of column_name/value pairs to add to the database.
1646      * @return The URI for the newly inserted item.
1647      */
insert(@onNull Uri uri, @Nullable ContentValues values)1648     public abstract @Nullable Uri insert(@NonNull Uri uri, @Nullable ContentValues values);
1649 
1650     /**
1651      * Implement this to handle requests to insert a new row. As a courtesy,
1652      * call
1653      * {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver)
1654      * notifyChange()} after inserting. This method can be called from multiple
1655      * threads, as described in <a href="
1656      * {@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
1657      * and Threads</a>.
1658      *
1659      * @param uri The content:// URI of the insertion request.
1660      * @param values A set of column_name/value pairs to add to the database.
1661      * @param extras A Bundle containing additional information necessary for
1662      *            the operation. Arguments may include SQL style arguments, such
1663      *            as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
1664      *            the documentation for each individual provider will indicate
1665      *            which arguments they support.
1666      * @return The URI for the newly inserted item.
1667      * @throws IllegalArgumentException if the provider doesn't support one of
1668      *             the requested Bundle arguments.
1669      */
1670     @Override
insert(@onNull Uri uri, @Nullable ContentValues values, @Nullable Bundle extras)1671     public @Nullable Uri insert(@NonNull Uri uri, @Nullable ContentValues values,
1672             @Nullable Bundle extras) {
1673         return insert(uri, values);
1674     }
1675 
1676     /**
1677      * Override this to handle requests to insert a set of new rows, or the
1678      * default implementation will iterate over the values and call
1679      * {@link #insert} on each of them.
1680      * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
1681      * after inserting.
1682      * This method can be called from multiple threads, as described in
1683      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
1684      * and Threads</a>.
1685      *
1686      * @param uri The content:// URI of the insertion request.
1687      * @param values An array of sets of column_name/value pairs to add to the database.
1688      *    This must not be {@code null}.
1689      * @return The number of values that were inserted.
1690      */
1691     @Override
bulkInsert(@onNull Uri uri, @NonNull ContentValues[] values)1692     public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) {
1693         int numValues = values.length;
1694         for (int i = 0; i < numValues; i++) {
1695             insert(uri, values[i]);
1696         }
1697         return numValues;
1698     }
1699 
1700     /**
1701      * Implement this to handle requests to delete one or more rows. The
1702      * implementation should apply the selection clause when performing
1703      * deletion, allowing the operation to affect multiple rows in a directory.
1704      * As a courtesy, call
1705      * {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver)
1706      * notifyChange()} after deleting. This method can be called from multiple
1707      * threads, as described in <a href="
1708      * {@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
1709      * and Threads</a>.
1710      * <p>
1711      * The implementation is responsible for parsing out a row ID at the end of
1712      * the URI, if a specific row is being deleted. That is, the client would
1713      * pass in <code>content://contacts/people/22</code> and the implementation
1714      * is responsible for parsing the record number (22) when creating a SQL
1715      * statement.
1716      *
1717      * @param uri The full URI to query, including a row ID (if a specific
1718      *            record is requested).
1719      * @param selection An optional restriction to apply to rows when deleting.
1720      * @return The number of rows affected.
1721      * @throws SQLException
1722      */
delete(@onNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs)1723     public abstract int delete(@NonNull Uri uri, @Nullable String selection,
1724             @Nullable String[] selectionArgs);
1725 
1726     /**
1727      * Implement this to handle requests to delete one or more rows. The
1728      * implementation should apply the selection clause when performing
1729      * deletion, allowing the operation to affect multiple rows in a directory.
1730      * As a courtesy, call
1731      * {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver)
1732      * notifyChange()} after deleting. This method can be called from multiple
1733      * threads, as described in <a href="
1734      * {@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
1735      * and Threads</a>.
1736      * <p>
1737      * The implementation is responsible for parsing out a row ID at the end of
1738      * the URI, if a specific row is being deleted. That is, the client would
1739      * pass in <code>content://contacts/people/22</code> and the implementation
1740      * is responsible for parsing the record number (22) when creating a SQL
1741      * statement.
1742      *
1743      * @param uri The full URI to query, including a row ID (if a specific
1744      *            record is requested).
1745      * @param extras A Bundle containing additional information necessary for
1746      *            the operation. Arguments may include SQL style arguments, such
1747      *            as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
1748      *            the documentation for each individual provider will indicate
1749      *            which arguments they support.
1750      * @throws IllegalArgumentException if the provider doesn't support one of
1751      *             the requested Bundle arguments.
1752      * @throws SQLException
1753      */
1754     @Override
delete(@onNull Uri uri, @Nullable Bundle extras)1755     public int delete(@NonNull Uri uri, @Nullable Bundle extras) {
1756         extras = (extras != null) ? extras : Bundle.EMPTY;
1757         return delete(uri,
1758                 extras.getString(ContentResolver.QUERY_ARG_SQL_SELECTION),
1759                 extras.getStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS));
1760     }
1761 
1762     /**
1763      * Implement this to handle requests to update one or more rows. The
1764      * implementation should update all rows matching the selection to set the
1765      * columns according to the provided values map. As a courtesy, call
1766      * {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver)
1767      * notifyChange()} after updating. This method can be called from multiple
1768      * threads, as described in <a href="
1769      * {@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
1770      * and Threads</a>.
1771      *
1772      * @param uri The URI to query. This can potentially have a record ID if
1773      *            this is an update request for a specific record.
1774      * @param values A set of column_name/value pairs to update in the database.
1775      * @param selection An optional filter to match rows to update.
1776      * @return the number of rows affected.
1777      */
update(@onNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs)1778     public abstract int update(@NonNull Uri uri, @Nullable ContentValues values,
1779             @Nullable String selection, @Nullable String[] selectionArgs);
1780 
1781     /**
1782      * Implement this to handle requests to update one or more rows. The
1783      * implementation should update all rows matching the selection to set the
1784      * columns according to the provided values map. As a courtesy, call
1785      * {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver)
1786      * notifyChange()} after updating. This method can be called from multiple
1787      * threads, as described in <a href="
1788      * {@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
1789      * and Threads</a>.
1790      *
1791      * @param uri The URI to query. This can potentially have a record ID if
1792      *            this is an update request for a specific record.
1793      * @param values A set of column_name/value pairs to update in the database.
1794      * @param extras A Bundle containing additional information necessary for
1795      *            the operation. Arguments may include SQL style arguments, such
1796      *            as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that
1797      *            the documentation for each individual provider will indicate
1798      *            which arguments they support.
1799      * @return the number of rows affected.
1800      * @throws IllegalArgumentException if the provider doesn't support one of
1801      *             the requested Bundle arguments.
1802      */
1803     @Override
update(@onNull Uri uri, @Nullable ContentValues values, @Nullable Bundle extras)1804     public int update(@NonNull Uri uri, @Nullable ContentValues values,
1805             @Nullable Bundle extras) {
1806         extras = (extras != null) ? extras : Bundle.EMPTY;
1807         return update(uri, values,
1808                 extras.getString(ContentResolver.QUERY_ARG_SQL_SELECTION),
1809                 extras.getStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS));
1810     }
1811 
1812     /**
1813      * Override this to handle requests to open a file blob.
1814      * The default implementation always throws {@link FileNotFoundException}.
1815      * This method can be called from multiple threads, as described in
1816      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
1817      * and Threads</a>.
1818      *
1819      * <p>This method returns a ParcelFileDescriptor, which is returned directly
1820      * to the caller.  This way large data (such as images and documents) can be
1821      * returned without copying the content.
1822      *
1823      * <p>The returned ParcelFileDescriptor is owned by the caller, so it is
1824      * their responsibility to close it when done.  That is, the implementation
1825      * of this method should create a new ParcelFileDescriptor for each call.
1826      * <p>
1827      * If opened with the exclusive "r" or "w" modes, the returned
1828      * ParcelFileDescriptor can be a pipe or socket pair to enable streaming
1829      * of data. Opening with the "rw" or "rwt" modes implies a file on disk that
1830      * supports seeking.
1831      * <p>
1832      * If you need to detect when the returned ParcelFileDescriptor has been
1833      * closed, or if the remote process has crashed or encountered some other
1834      * error, you can use {@link ParcelFileDescriptor#open(File, int,
1835      * android.os.Handler, android.os.ParcelFileDescriptor.OnCloseListener)},
1836      * {@link ParcelFileDescriptor#createReliablePipe()}, or
1837      * {@link ParcelFileDescriptor#createReliableSocketPair()}.
1838      * <p>
1839      * If you need to return a large file that isn't backed by a real file on
1840      * disk, such as a file on a network share or cloud storage service,
1841      * consider using
1842      * {@link StorageManager#openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback, android.os.Handler)}
1843      * which will let you to stream the content on-demand.
1844      *
1845      * <p class="note">For use in Intents, you will want to implement {@link #getType}
1846      * to return the appropriate MIME type for the data returned here with
1847      * the same URI.  This will allow intent resolution to automatically determine the data MIME
1848      * type and select the appropriate matching targets as part of its operation.</p>
1849      *
1850      * <p class="note">For better interoperability with other applications, it is recommended
1851      * that for any URIs that can be opened, you also support queries on them
1852      * containing at least the columns specified by {@link android.provider.OpenableColumns}.
1853      * You may also want to support other common columns if you have additional meta-data
1854      * to supply, such as {@link android.provider.MediaStore.MediaColumns#DATE_ADDED}
1855      * in {@link android.provider.MediaStore.MediaColumns}.</p>
1856      *
1857      * @param uri The URI whose file is to be opened.
1858      * @param mode Access mode for the file.  May be "r" for read-only access,
1859      * "rw" for read and write access, or "rwt" for read and write access
1860      * that truncates any existing file.
1861      *
1862      * @return Returns a new ParcelFileDescriptor which you can use to access
1863      * the file.
1864      *
1865      * @throws FileNotFoundException Throws FileNotFoundException if there is
1866      * no file associated with the given URI or the mode is invalid.
1867      * @throws SecurityException Throws SecurityException if the caller does
1868      * not have permission to access the file.
1869      *
1870      * @see #openAssetFile(Uri, String)
1871      * @see #openFileHelper(Uri, String)
1872      * @see #getType(android.net.Uri)
1873      * @see ParcelFileDescriptor#parseMode(String)
1874      */
openFile(@onNull Uri uri, @NonNull String mode)1875     public @Nullable ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode)
1876             throws FileNotFoundException {
1877         throw new FileNotFoundException("No files supported by provider at "
1878                 + uri);
1879     }
1880 
1881     /**
1882      * Override this to handle requests to open a file blob.
1883      * The default implementation always throws {@link FileNotFoundException}.
1884      * This method can be called from multiple threads, as described in
1885      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
1886      * and Threads</a>.
1887      *
1888      * <p>This method returns a ParcelFileDescriptor, which is returned directly
1889      * to the caller.  This way large data (such as images and documents) can be
1890      * returned without copying the content.
1891      *
1892      * <p>The returned ParcelFileDescriptor is owned by the caller, so it is
1893      * their responsibility to close it when done.  That is, the implementation
1894      * of this method should create a new ParcelFileDescriptor for each call.
1895      * <p>
1896      * If opened with the exclusive "r" or "w" modes, the returned
1897      * ParcelFileDescriptor can be a pipe or socket pair to enable streaming
1898      * of data. Opening with the "rw" or "rwt" modes implies a file on disk that
1899      * supports seeking.
1900      * <p>
1901      * If you need to detect when the returned ParcelFileDescriptor has been
1902      * closed, or if the remote process has crashed or encountered some other
1903      * error, you can use {@link ParcelFileDescriptor#open(File, int,
1904      * android.os.Handler, android.os.ParcelFileDescriptor.OnCloseListener)},
1905      * {@link ParcelFileDescriptor#createReliablePipe()}, or
1906      * {@link ParcelFileDescriptor#createReliableSocketPair()}.
1907      *
1908      * <p class="note">For use in Intents, you will want to implement {@link #getType}
1909      * to return the appropriate MIME type for the data returned here with
1910      * the same URI.  This will allow intent resolution to automatically determine the data MIME
1911      * type and select the appropriate matching targets as part of its operation.</p>
1912      *
1913      * <p class="note">For better interoperability with other applications, it is recommended
1914      * that for any URIs that can be opened, you also support queries on them
1915      * containing at least the columns specified by {@link android.provider.OpenableColumns}.
1916      * You may also want to support other common columns if you have additional meta-data
1917      * to supply, such as {@link android.provider.MediaStore.MediaColumns#DATE_ADDED}
1918      * in {@link android.provider.MediaStore.MediaColumns}.</p>
1919      *
1920      * @param uri The URI whose file is to be opened.
1921      * @param mode Access mode for the file. May be "r" for read-only access,
1922      *            "w" for write-only access, "rw" for read and write access, or
1923      *            "rwt" for read and write access that truncates any existing
1924      *            file.
1925      * @param signal A signal to cancel the operation in progress, or
1926      *            {@code null} if none. For example, if you are downloading a
1927      *            file from the network to service a "rw" mode request, you
1928      *            should periodically call
1929      *            {@link CancellationSignal#throwIfCanceled()} to check whether
1930      *            the client has canceled the request and abort the download.
1931      *
1932      * @return Returns a new ParcelFileDescriptor which you can use to access
1933      * the file.
1934      *
1935      * @throws FileNotFoundException Throws FileNotFoundException if there is
1936      * no file associated with the given URI or the mode is invalid.
1937      * @throws SecurityException Throws SecurityException if the caller does
1938      * not have permission to access the file.
1939      *
1940      * @see #openAssetFile(Uri, String)
1941      * @see #openFileHelper(Uri, String)
1942      * @see #getType(android.net.Uri)
1943      * @see ParcelFileDescriptor#parseMode(String)
1944      */
1945     @Override
openFile(@onNull Uri uri, @NonNull String mode, @Nullable CancellationSignal signal)1946     public @Nullable ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode,
1947             @Nullable CancellationSignal signal) throws FileNotFoundException {
1948         return openFile(uri, mode);
1949     }
1950 
1951     /**
1952      * This is like {@link #openFile}, but can be implemented by providers
1953      * that need to be able to return sub-sections of files, often assets
1954      * inside of their .apk.
1955      * This method can be called from multiple threads, as described in
1956      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
1957      * and Threads</a>.
1958      *
1959      * <p>If you implement this, your clients must be able to deal with such
1960      * file slices, either directly with
1961      * {@link ContentResolver#openAssetFileDescriptor}, or by using the higher-level
1962      * {@link ContentResolver#openInputStream ContentResolver.openInputStream}
1963      * or {@link ContentResolver#openOutputStream ContentResolver.openOutputStream}
1964      * methods.
1965      * <p>
1966      * The returned AssetFileDescriptor can be a pipe or socket pair to enable
1967      * streaming of data.
1968      *
1969      * <p class="note">If you are implementing this to return a full file, you
1970      * should create the AssetFileDescriptor with
1971      * {@link AssetFileDescriptor#UNKNOWN_LENGTH} to be compatible with
1972      * applications that cannot handle sub-sections of files.</p>
1973      *
1974      * <p class="note">For use in Intents, you will want to implement {@link #getType}
1975      * to return the appropriate MIME type for the data returned here with
1976      * the same URI.  This will allow intent resolution to automatically determine the data MIME
1977      * type and select the appropriate matching targets as part of its operation.</p>
1978      *
1979      * <p class="note">For better interoperability with other applications, it is recommended
1980      * that for any URIs that can be opened, you also support queries on them
1981      * containing at least the columns specified by {@link android.provider.OpenableColumns}.</p>
1982      *
1983      * @param uri The URI whose file is to be opened.
1984      * @param mode Access mode for the file.  May be "r" for read-only access,
1985      * "w" for write-only access (erasing whatever data is currently in
1986      * the file), "wa" for write-only access to append to any existing data,
1987      * "rw" for read and write access on any existing data, and "rwt" for read
1988      * and write access that truncates any existing file.
1989      *
1990      * @return Returns a new AssetFileDescriptor which you can use to access
1991      * the file.
1992      *
1993      * @throws FileNotFoundException Throws FileNotFoundException if there is
1994      * no file associated with the given URI or the mode is invalid.
1995      * @throws SecurityException Throws SecurityException if the caller does
1996      * not have permission to access the file.
1997      *
1998      * @see #openFile(Uri, String)
1999      * @see #openFileHelper(Uri, String)
2000      * @see #getType(android.net.Uri)
2001      */
openAssetFile(@onNull Uri uri, @NonNull String mode)2002     public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode)
2003             throws FileNotFoundException {
2004         ParcelFileDescriptor fd = openFile(uri, mode);
2005         return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null;
2006     }
2007 
2008     /**
2009      * This is like {@link #openFile}, but can be implemented by providers
2010      * that need to be able to return sub-sections of files, often assets
2011      * inside of their .apk.
2012      * This method can be called from multiple threads, as described in
2013      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
2014      * and Threads</a>.
2015      *
2016      * <p>If you implement this, your clients must be able to deal with such
2017      * file slices, either directly with
2018      * {@link ContentResolver#openAssetFileDescriptor}, or by using the higher-level
2019      * {@link ContentResolver#openInputStream ContentResolver.openInputStream}
2020      * or {@link ContentResolver#openOutputStream ContentResolver.openOutputStream}
2021      * methods.
2022      * <p>
2023      * The returned AssetFileDescriptor can be a pipe or socket pair to enable
2024      * streaming of data.
2025      *
2026      * <p class="note">If you are implementing this to return a full file, you
2027      * should create the AssetFileDescriptor with
2028      * {@link AssetFileDescriptor#UNKNOWN_LENGTH} to be compatible with
2029      * applications that cannot handle sub-sections of files.</p>
2030      *
2031      * <p class="note">For use in Intents, you will want to implement {@link #getType}
2032      * to return the appropriate MIME type for the data returned here with
2033      * the same URI.  This will allow intent resolution to automatically determine the data MIME
2034      * type and select the appropriate matching targets as part of its operation.</p>
2035      *
2036      * <p class="note">For better interoperability with other applications, it is recommended
2037      * that for any URIs that can be opened, you also support queries on them
2038      * containing at least the columns specified by {@link android.provider.OpenableColumns}.</p>
2039      *
2040      * @param uri The URI whose file is to be opened.
2041      * @param mode Access mode for the file.  May be "r" for read-only access,
2042      * "w" for write-only access (erasing whatever data is currently in
2043      * the file), "wa" for write-only access to append to any existing data,
2044      * "rw" for read and write access on any existing data, and "rwt" for read
2045      * and write access that truncates any existing file.
2046      * @param signal A signal to cancel the operation in progress, or
2047      *            {@code null} if none. For example, if you are downloading a
2048      *            file from the network to service a "rw" mode request, you
2049      *            should periodically call
2050      *            {@link CancellationSignal#throwIfCanceled()} to check whether
2051      *            the client has canceled the request and abort the download.
2052      *
2053      * @return Returns a new AssetFileDescriptor which you can use to access
2054      * the file.
2055      *
2056      * @throws FileNotFoundException Throws FileNotFoundException if there is
2057      * no file associated with the given URI or the mode is invalid.
2058      * @throws SecurityException Throws SecurityException if the caller does
2059      * not have permission to access the file.
2060      *
2061      * @see #openFile(Uri, String)
2062      * @see #openFileHelper(Uri, String)
2063      * @see #getType(android.net.Uri)
2064      */
2065     @Override
openAssetFile(@onNull Uri uri, @NonNull String mode, @Nullable CancellationSignal signal)2066     public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode,
2067             @Nullable CancellationSignal signal) throws FileNotFoundException {
2068         return openAssetFile(uri, mode);
2069     }
2070 
2071     /**
2072      * Convenience for subclasses that wish to implement {@link #openFile}
2073      * by looking up a column named "_data" at the given URI.
2074      *
2075      * @param uri The URI to be opened.
2076      * @param mode The file mode.  May be "r" for read-only access,
2077      * "w" for write-only access (erasing whatever data is currently in
2078      * the file), "wa" for write-only access to append to any existing data,
2079      * "rw" for read and write access on any existing data, and "rwt" for read
2080      * and write access that truncates any existing file.
2081      *
2082      * @return Returns a new ParcelFileDescriptor that can be used by the
2083      * client to access the file.
2084      */
openFileHelper(@onNull Uri uri, @NonNull String mode)2085     protected final @NonNull ParcelFileDescriptor openFileHelper(@NonNull Uri uri,
2086             @NonNull String mode) throws FileNotFoundException {
2087         Cursor c = query(uri, new String[]{"_data"}, null, null, null);
2088         int count = (c != null) ? c.getCount() : 0;
2089         if (count != 1) {
2090             // If there is not exactly one result, throw an appropriate
2091             // exception.
2092             if (c != null) {
2093                 c.close();
2094             }
2095             if (count == 0) {
2096                 throw new FileNotFoundException("No entry for " + uri);
2097             }
2098             throw new FileNotFoundException("Multiple items at " + uri);
2099         }
2100 
2101         c.moveToFirst();
2102         int i = c.getColumnIndex("_data");
2103         String path = (i >= 0 ? c.getString(i) : null);
2104         c.close();
2105         if (path == null) {
2106             throw new FileNotFoundException("Column _data not found.");
2107         }
2108 
2109         int modeBits = ParcelFileDescriptor.parseMode(mode);
2110         return ParcelFileDescriptor.open(new File(path), modeBits);
2111     }
2112 
2113     /**
2114      * Called by a client to determine the types of data streams that this
2115      * content provider supports for the given URI.  The default implementation
2116      * returns {@code null}, meaning no types.  If your content provider stores data
2117      * of a particular type, return that MIME type if it matches the given
2118      * mimeTypeFilter.  If it can perform type conversions, return an array
2119      * of all supported MIME types that match mimeTypeFilter.
2120      *
2121      * @param uri The data in the content provider being queried.
2122      * @param mimeTypeFilter The type of data the client desires.  May be
2123      * a pattern, such as *&#47;* to retrieve all possible data types.
2124      * @return Returns {@code null} if there are no possible data streams for the
2125      * given mimeTypeFilter.  Otherwise returns an array of all available
2126      * concrete MIME types.
2127      *
2128      * @see #getType(Uri)
2129      * @see #openTypedAssetFile(Uri, String, Bundle)
2130      * @see ClipDescription#compareMimeTypes(String, String)
2131      */
2132     @Override
getStreamTypes(@onNull Uri uri, @NonNull String mimeTypeFilter)2133     public @Nullable String[] getStreamTypes(@NonNull Uri uri, @NonNull String mimeTypeFilter) {
2134         return null;
2135     }
2136 
2137     /**
2138      * Called by a client to open a read-only stream containing data of a
2139      * particular MIME type.  This is like {@link #openAssetFile(Uri, String)},
2140      * except the file can only be read-only and the content provider may
2141      * perform data conversions to generate data of the desired type.
2142      *
2143      * <p>The default implementation compares the given mimeType against the
2144      * result of {@link #getType(Uri)} and, if they match, simply calls
2145      * {@link #openAssetFile(Uri, String)}.
2146      *
2147      * <p>See {@link ClipData} for examples of the use and implementation
2148      * of this method.
2149      * <p>
2150      * The returned AssetFileDescriptor can be a pipe or socket pair to enable
2151      * streaming of data.
2152      *
2153      * <p class="note">For better interoperability with other applications, it is recommended
2154      * that for any URIs that can be opened, you also support queries on them
2155      * containing at least the columns specified by {@link android.provider.OpenableColumns}.
2156      * You may also want to support other common columns if you have additional meta-data
2157      * to supply, such as {@link android.provider.MediaStore.MediaColumns#DATE_ADDED}
2158      * in {@link android.provider.MediaStore.MediaColumns}.</p>
2159      *
2160      * @param uri The data in the content provider being queried.
2161      * @param mimeTypeFilter The type of data the client desires.  May be
2162      * a pattern, such as *&#47;*, if the caller does not have specific type
2163      * requirements; in this case the content provider will pick its best
2164      * type matching the pattern.
2165      * @param opts Additional options from the client.  The definitions of
2166      * these are specific to the content provider being called.
2167      *
2168      * @return Returns a new AssetFileDescriptor from which the client can
2169      * read data of the desired type.
2170      *
2171      * @throws FileNotFoundException Throws FileNotFoundException if there is
2172      * no file associated with the given URI or the mode is invalid.
2173      * @throws SecurityException Throws SecurityException if the caller does
2174      * not have permission to access the data.
2175      * @throws IllegalArgumentException Throws IllegalArgumentException if the
2176      * content provider does not support the requested MIME type.
2177      *
2178      * @see #getStreamTypes(Uri, String)
2179      * @see #openAssetFile(Uri, String)
2180      * @see ClipDescription#compareMimeTypes(String, String)
2181      */
openTypedAssetFile(@onNull Uri uri, @NonNull String mimeTypeFilter, @Nullable Bundle opts)2182     public @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri,
2183             @NonNull String mimeTypeFilter, @Nullable Bundle opts) throws FileNotFoundException {
2184         if ("*/*".equals(mimeTypeFilter)) {
2185             // If they can take anything, the untyped open call is good enough.
2186             return openAssetFile(uri, "r");
2187         }
2188         String baseType = getType(uri);
2189         if (baseType != null && ClipDescription.compareMimeTypes(baseType, mimeTypeFilter)) {
2190             // Use old untyped open call if this provider has a type for this
2191             // URI and it matches the request.
2192             return openAssetFile(uri, "r");
2193         }
2194         throw new FileNotFoundException("Can't open " + uri + " as type " + mimeTypeFilter);
2195     }
2196 
2197 
2198     /**
2199      * Called by a client to open a read-only stream containing data of a
2200      * particular MIME type.  This is like {@link #openAssetFile(Uri, String)},
2201      * except the file can only be read-only and the content provider may
2202      * perform data conversions to generate data of the desired type.
2203      *
2204      * <p>The default implementation compares the given mimeType against the
2205      * result of {@link #getType(Uri)} and, if they match, simply calls
2206      * {@link #openAssetFile(Uri, String)}.
2207      *
2208      * <p>See {@link ClipData} for examples of the use and implementation
2209      * of this method.
2210      * <p>
2211      * The returned AssetFileDescriptor can be a pipe or socket pair to enable
2212      * streaming of data.
2213      *
2214      * <p class="note">For better interoperability with other applications, it is recommended
2215      * that for any URIs that can be opened, you also support queries on them
2216      * containing at least the columns specified by {@link android.provider.OpenableColumns}.
2217      * You may also want to support other common columns if you have additional meta-data
2218      * to supply, such as {@link android.provider.MediaStore.MediaColumns#DATE_ADDED}
2219      * in {@link android.provider.MediaStore.MediaColumns}.</p>
2220      *
2221      * @param uri The data in the content provider being queried.
2222      * @param mimeTypeFilter The type of data the client desires.  May be
2223      * a pattern, such as *&#47;*, if the caller does not have specific type
2224      * requirements; in this case the content provider will pick its best
2225      * type matching the pattern.
2226      * @param opts Additional options from the client.  The definitions of
2227      * these are specific to the content provider being called.
2228      * @param signal A signal to cancel the operation in progress, or
2229      *            {@code null} if none. For example, if you are downloading a
2230      *            file from the network to service a "rw" mode request, you
2231      *            should periodically call
2232      *            {@link CancellationSignal#throwIfCanceled()} to check whether
2233      *            the client has canceled the request and abort the download.
2234      *
2235      * @return Returns a new AssetFileDescriptor from which the client can
2236      * read data of the desired type.
2237      *
2238      * @throws FileNotFoundException Throws FileNotFoundException if there is
2239      * no file associated with the given URI or the mode is invalid.
2240      * @throws SecurityException Throws SecurityException if the caller does
2241      * not have permission to access the data.
2242      * @throws IllegalArgumentException Throws IllegalArgumentException if the
2243      * content provider does not support the requested MIME type.
2244      *
2245      * @see #getStreamTypes(Uri, String)
2246      * @see #openAssetFile(Uri, String)
2247      * @see ClipDescription#compareMimeTypes(String, String)
2248      */
2249     @Override
openTypedAssetFile(@onNull Uri uri, @NonNull String mimeTypeFilter, @Nullable Bundle opts, @Nullable CancellationSignal signal)2250     public @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri,
2251             @NonNull String mimeTypeFilter, @Nullable Bundle opts,
2252             @Nullable CancellationSignal signal) throws FileNotFoundException {
2253         return openTypedAssetFile(uri, mimeTypeFilter, opts);
2254     }
2255 
2256     /**
2257      * Interface to write a stream of data to a pipe.  Use with
2258      * {@link ContentProvider#openPipeHelper}.
2259      */
2260     public interface PipeDataWriter<T> {
2261         /**
2262          * Called from a background thread to stream data out to a pipe.
2263          * Note that the pipe is blocking, so this thread can block on
2264          * writes for an arbitrary amount of time if the client is slow
2265          * at reading.
2266          *
2267          * @param output The pipe where data should be written.  This will be
2268          * closed for you upon returning from this function.
2269          * @param uri The URI whose data is to be written.
2270          * @param mimeType The desired type of data to be written.
2271          * @param opts Options supplied by caller.
2272          * @param args Your own custom arguments.
2273          */
writeDataToPipe(@onNull ParcelFileDescriptor output, @NonNull Uri uri, @NonNull String mimeType, @Nullable Bundle opts, @Nullable T args)2274         public void writeDataToPipe(@NonNull ParcelFileDescriptor output, @NonNull Uri uri,
2275                 @NonNull String mimeType, @Nullable Bundle opts, @Nullable T args);
2276     }
2277 
2278     /**
2279      * A helper function for implementing {@link #openTypedAssetFile}, for
2280      * creating a data pipe and background thread allowing you to stream
2281      * generated data back to the client.  This function returns a new
2282      * ParcelFileDescriptor that should be returned to the caller (the caller
2283      * is responsible for closing it).
2284      *
2285      * @param uri The URI whose data is to be written.
2286      * @param mimeType The desired type of data to be written.
2287      * @param opts Options supplied by caller.
2288      * @param args Your own custom arguments.
2289      * @param func Interface implementing the function that will actually
2290      * stream the data.
2291      * @return Returns a new ParcelFileDescriptor holding the read side of
2292      * the pipe.  This should be returned to the caller for reading; the caller
2293      * is responsible for closing it when done.
2294      */
openPipeHelper(final @NonNull Uri uri, final @NonNull String mimeType, final @Nullable Bundle opts, final @Nullable T args, final @NonNull PipeDataWriter<T> func)2295     public @NonNull <T> ParcelFileDescriptor openPipeHelper(final @NonNull Uri uri,
2296             final @NonNull String mimeType, final @Nullable Bundle opts, final @Nullable T args,
2297             final @NonNull PipeDataWriter<T> func) throws FileNotFoundException {
2298         try {
2299             final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
2300 
2301             AsyncTask<Object, Object, Object> task = new AsyncTask<Object, Object, Object>() {
2302                 @Override
2303                 protected Object doInBackground(Object... params) {
2304                     func.writeDataToPipe(fds[1], uri, mimeType, opts, args);
2305                     try {
2306                         fds[1].close();
2307                     } catch (IOException e) {
2308                         Log.w(TAG, "Failure closing pipe", e);
2309                     }
2310                     return null;
2311                 }
2312             };
2313             task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Object[])null);
2314 
2315             return fds[0];
2316         } catch (IOException e) {
2317             throw new FileNotFoundException("failure making pipe");
2318         }
2319     }
2320 
2321     /**
2322      * Returns true if this instance is a temporary content provider.
2323      * @return true if this instance is a temporary content provider
2324      */
isTemporary()2325     protected boolean isTemporary() {
2326         return false;
2327     }
2328 
2329     /**
2330      * Returns the Binder object for this provider.
2331      *
2332      * @return the Binder object for this provider
2333      * @hide
2334      */
2335     @UnsupportedAppUsage
getIContentProvider()2336     public IContentProvider getIContentProvider() {
2337         return mTransport;
2338     }
2339 
2340     /**
2341      * Like {@link #attachInfo(Context, android.content.pm.ProviderInfo)}, but for use
2342      * when directly instantiating the provider for testing.
2343      * @hide
2344      */
2345     @UnsupportedAppUsage
attachInfoForTesting(Context context, ProviderInfo info)2346     public void attachInfoForTesting(Context context, ProviderInfo info) {
2347         attachInfo(context, info, true);
2348     }
2349 
2350     /**
2351      * After being instantiated, this is called to tell the content provider
2352      * about itself.
2353      *
2354      * @param context The context this provider is running in
2355      * @param info Registered information about this content provider
2356      */
attachInfo(Context context, ProviderInfo info)2357     public void attachInfo(Context context, ProviderInfo info) {
2358         attachInfo(context, info, false);
2359     }
2360 
attachInfo(Context context, ProviderInfo info, boolean testing)2361     private void attachInfo(Context context, ProviderInfo info, boolean testing) {
2362         mNoPerms = testing;
2363         mCallingPackage = new ThreadLocal<>();
2364 
2365         /*
2366          * Only allow it to be set once, so after the content service gives
2367          * this to us clients can't change it.
2368          */
2369         if (mContext == null) {
2370             mContext = context;
2371             if (context != null && mTransport != null) {
2372                 mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
2373                         Context.APP_OPS_SERVICE);
2374             }
2375             mMyUid = Process.myUid();
2376             if (info != null) {
2377                 setReadPermission(info.readPermission);
2378                 setWritePermission(info.writePermission);
2379                 setPathPermissions(info.pathPermissions);
2380                 mExported = info.exported;
2381                 mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
2382                 setAuthorities(info.authority);
2383             }
2384             if (Build.IS_DEBUGGABLE) {
2385                 setTransportLoggingEnabled(Log.isLoggable(getClass().getSimpleName(),
2386                         Log.VERBOSE));
2387             }
2388             ContentProvider.this.onCreate();
2389         }
2390     }
2391 
2392     /**
2393      * Override this to handle requests to perform a batch of operations, or the
2394      * default implementation will iterate over the operations and call
2395      * {@link ContentProviderOperation#apply} on each of them.
2396      * If all calls to {@link ContentProviderOperation#apply} succeed
2397      * then a {@link ContentProviderResult} array with as many
2398      * elements as there were operations will be returned.  If any of the calls
2399      * fail, it is up to the implementation how many of the others take effect.
2400      * This method can be called from multiple threads, as described in
2401      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
2402      * and Threads</a>.
2403      *
2404      * @param operations the operations to apply
2405      * @return the results of the applications
2406      * @throws OperationApplicationException thrown if any operation fails.
2407      * @see ContentProviderOperation#apply
2408      */
2409     @Override
applyBatch(@onNull String authority, @NonNull ArrayList<ContentProviderOperation> operations)2410     public @NonNull ContentProviderResult[] applyBatch(@NonNull String authority,
2411             @NonNull ArrayList<ContentProviderOperation> operations)
2412                     throws OperationApplicationException {
2413         return applyBatch(operations);
2414     }
2415 
applyBatch( @onNull ArrayList<ContentProviderOperation> operations)2416     public @NonNull ContentProviderResult[] applyBatch(
2417             @NonNull ArrayList<ContentProviderOperation> operations)
2418                     throws OperationApplicationException {
2419         final int numOperations = operations.size();
2420         final ContentProviderResult[] results = new ContentProviderResult[numOperations];
2421         for (int i = 0; i < numOperations; i++) {
2422             results[i] = operations.get(i).apply(this, results, i);
2423         }
2424         return results;
2425     }
2426 
2427     /**
2428      * Call a provider-defined method.  This can be used to implement
2429      * interfaces that are cheaper and/or unnatural for a table-like
2430      * model.
2431      *
2432      * <p class="note"><strong>WARNING:</strong> The framework does no permission checking
2433      * on this entry into the content provider besides the basic ability for the application
2434      * to get access to the provider at all.  For example, it has no idea whether the call
2435      * being executed may read or write data in the provider, so can't enforce those
2436      * individual permissions.  Any implementation of this method <strong>must</strong>
2437      * do its own permission checks on incoming calls to make sure they are allowed.</p>
2438      *
2439      * @param method method name to call.  Opaque to framework, but should not be {@code null}.
2440      * @param arg provider-defined String argument.  May be {@code null}.
2441      * @param extras provider-defined Bundle argument.  May be {@code null}.
2442      * @return provider-defined return value.  May be {@code null}, which is also
2443      *   the default for providers which don't implement any call methods.
2444      */
2445     @Override
call(@onNull String authority, @NonNull String method, @Nullable String arg, @Nullable Bundle extras)2446     public @Nullable Bundle call(@NonNull String authority, @NonNull String method,
2447             @Nullable String arg, @Nullable Bundle extras) {
2448         return call(method, arg, extras);
2449     }
2450 
call(@onNull String method, @Nullable String arg, @Nullable Bundle extras)2451     public @Nullable Bundle call(@NonNull String method, @Nullable String arg,
2452             @Nullable Bundle extras) {
2453         return null;
2454     }
2455 
2456     /**
2457      * Implement this to shut down the ContentProvider instance. You can then
2458      * invoke this method in unit tests.
2459      *
2460      * <p>
2461      * Android normally handles ContentProvider startup and shutdown
2462      * automatically. You do not need to start up or shut down a
2463      * ContentProvider. When you invoke a test method on a ContentProvider,
2464      * however, a ContentProvider instance is started and keeps running after
2465      * the test finishes, even if a succeeding test instantiates another
2466      * ContentProvider. A conflict develops because the two instances are
2467      * usually running against the same underlying data source (for example, an
2468      * sqlite database).
2469      * </p>
2470      * <p>
2471      * Implementing shutDown() avoids this conflict by providing a way to
2472      * terminate the ContentProvider. This method can also prevent memory leaks
2473      * from multiple instantiations of the ContentProvider, and it can ensure
2474      * unit test isolation by allowing you to completely clean up the test
2475      * fixture before moving on to the next test.
2476      * </p>
2477      */
shutdown()2478     public void shutdown() {
2479         Log.w(TAG, "implement ContentProvider shutdown() to make sure all database " +
2480                 "connections are gracefully shutdown");
2481     }
2482 
2483     /**
2484      * Print the Provider's state into the given stream.  This gets invoked if
2485      * you run "adb shell dumpsys activity provider &lt;provider_component_name&gt;".
2486      *
2487      * @param fd The raw file descriptor that the dump is being sent to.
2488      * @param writer The PrintWriter to which you should dump your state.  This will be
2489      * closed for you after you return.
2490      * @param args additional arguments to the dump request.
2491      */
dump(FileDescriptor fd, PrintWriter writer, String[] args)2492     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
2493         writer.println("nothing to dump");
2494     }
2495 
validateIncomingAuthority(String authority)2496     private void validateIncomingAuthority(String authority) throws SecurityException {
2497         if (!matchesOurAuthorities(getAuthorityWithoutUserId(authority))) {
2498             String message = "The authority " + authority + " does not match the one of the "
2499                     + "contentProvider: ";
2500             if (mAuthority != null) {
2501                 message += mAuthority;
2502             } else {
2503                 message += Arrays.toString(mAuthorities);
2504             }
2505             throw new SecurityException(message);
2506         }
2507     }
2508 
2509     /** @hide */
2510     @VisibleForTesting
validateIncomingUri(Uri uri)2511     public Uri validateIncomingUri(Uri uri) throws SecurityException {
2512         String auth = uri.getAuthority();
2513         if (!mSingleUser) {
2514             int userId = getUserIdFromAuthority(auth, UserHandle.USER_CURRENT);
2515             if (userId != UserHandle.USER_CURRENT && userId != mContext.getUserId()) {
2516                 throw new SecurityException("trying to query a ContentProvider in user "
2517                         + mContext.getUserId() + " with a uri belonging to user " + userId);
2518             }
2519         }
2520         validateIncomingAuthority(auth);
2521 
2522         // Normalize the path by removing any empty path segments, which can be
2523         // a source of security issues.
2524         final String encodedPath = uri.getEncodedPath();
2525         if (encodedPath != null && encodedPath.indexOf("//") != -1) {
2526             final Uri normalized = uri.buildUpon()
2527                     .encodedPath(encodedPath.replaceAll("//+", "/")).build();
2528             Log.w(TAG, "Normalized " + uri + " to " + normalized
2529                     + " to avoid possible security issues");
2530             return normalized;
2531         } else {
2532             return uri;
2533         }
2534     }
2535 
2536     /** @hide */
maybeGetUriWithoutUserId(Uri uri)2537     private Uri maybeGetUriWithoutUserId(Uri uri) {
2538         if (mSingleUser) {
2539             return uri;
2540         }
2541         return getUriWithoutUserId(uri);
2542     }
2543 
2544     /** @hide */
getUserIdFromAuthority(String auth, int defaultUserId)2545     public static int getUserIdFromAuthority(String auth, int defaultUserId) {
2546         if (auth == null) return defaultUserId;
2547         int end = auth.lastIndexOf('@');
2548         if (end == -1) return defaultUserId;
2549         String userIdString = auth.substring(0, end);
2550         try {
2551             return Integer.parseInt(userIdString);
2552         } catch (NumberFormatException e) {
2553             Log.w(TAG, "Error parsing userId.", e);
2554             return UserHandle.USER_NULL;
2555         }
2556     }
2557 
2558     /** @hide */
getUserIdFromAuthority(String auth)2559     public static int getUserIdFromAuthority(String auth) {
2560         return getUserIdFromAuthority(auth, UserHandle.USER_CURRENT);
2561     }
2562 
2563     /** @hide */
getUserIdFromUri(Uri uri, int defaultUserId)2564     public static int getUserIdFromUri(Uri uri, int defaultUserId) {
2565         if (uri == null) return defaultUserId;
2566         return getUserIdFromAuthority(uri.getAuthority(), defaultUserId);
2567     }
2568 
2569     /** @hide */
getUserIdFromUri(Uri uri)2570     public static int getUserIdFromUri(Uri uri) {
2571         return getUserIdFromUri(uri, UserHandle.USER_CURRENT);
2572     }
2573 
2574     /**
2575      * Returns the user associated with the given URI.
2576      *
2577      * @hide
2578      */
2579     @TestApi
getUserHandleFromUri(@onNull Uri uri)2580     public @NonNull static UserHandle getUserHandleFromUri(@NonNull Uri uri) {
2581         return UserHandle.of(getUserIdFromUri(uri, Process.myUserHandle().getIdentifier()));
2582     }
2583 
2584     /**
2585      * Removes userId part from authority string. Expects format:
2586      * userId@some.authority
2587      * If there is no userId in the authority, it symply returns the argument
2588      * @hide
2589      */
getAuthorityWithoutUserId(String auth)2590     public static String getAuthorityWithoutUserId(String auth) {
2591         if (auth == null) return null;
2592         int end = auth.lastIndexOf('@');
2593         return auth.substring(end+1);
2594     }
2595 
2596     /** @hide */
getUriWithoutUserId(Uri uri)2597     public static Uri getUriWithoutUserId(Uri uri) {
2598         if (uri == null) return null;
2599         Uri.Builder builder = uri.buildUpon();
2600         builder.authority(getAuthorityWithoutUserId(uri.getAuthority()));
2601         return builder.build();
2602     }
2603 
2604     /** @hide */
uriHasUserId(Uri uri)2605     public static boolean uriHasUserId(Uri uri) {
2606         if (uri == null) return false;
2607         return !TextUtils.isEmpty(uri.getUserInfo());
2608     }
2609 
2610     /** @hide */
2611     @UnsupportedAppUsage
maybeAddUserId(Uri uri, int userId)2612     public static Uri maybeAddUserId(Uri uri, int userId) {
2613         if (uri == null) return null;
2614         if (userId != UserHandle.USER_CURRENT
2615                 && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
2616             if (!uriHasUserId(uri)) {
2617                 //We don't add the user Id if there's already one
2618                 Uri.Builder builder = uri.buildUpon();
2619                 builder.encodedAuthority("" + userId + "@" + uri.getEncodedAuthority());
2620                 return builder.build();
2621             }
2622         }
2623         return uri;
2624     }
2625 }
2626