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