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