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