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