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