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