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