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.content.pm.PackageManager.GET_PROVIDERS; 20 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 21 22 import android.app.AppOpsManager; 23 import android.content.pm.PackageManager; 24 import android.content.pm.PathPermission; 25 import android.content.pm.ProviderInfo; 26 import android.content.res.AssetFileDescriptor; 27 import android.content.res.Configuration; 28 import android.database.Cursor; 29 import android.database.SQLException; 30 import android.net.Uri; 31 import android.os.AsyncTask; 32 import android.os.Binder; 33 import android.os.Bundle; 34 import android.os.CancellationSignal; 35 import android.os.ICancellationSignal; 36 import android.os.OperationCanceledException; 37 import android.os.ParcelFileDescriptor; 38 import android.os.Process; 39 import android.os.RemoteException; 40 import android.os.UserHandle; 41 import android.util.Log; 42 43 import java.io.File; 44 import java.io.FileDescriptor; 45 import java.io.FileNotFoundException; 46 import java.io.IOException; 47 import java.io.PrintWriter; 48 import java.util.ArrayList; 49 50 /** 51 * Content providers are one of the primary building blocks of Android applications, providing 52 * content to applications. They encapsulate data and provide it to applications through the single 53 * {@link ContentResolver} interface. A content provider is only required if you need to share 54 * data between multiple applications. For example, the contacts data is used by multiple 55 * applications and must be stored in a content provider. If you don't need to share data amongst 56 * multiple applications you can use a database directly via 57 * {@link android.database.sqlite.SQLiteDatabase}. 58 * 59 * <p>When a request is made via 60 * a {@link ContentResolver} the system inspects the authority of the given URI and passes the 61 * request to the content provider registered with the authority. The content provider can interpret 62 * the rest of the URI however it wants. The {@link UriMatcher} class is helpful for parsing 63 * URIs.</p> 64 * 65 * <p>The primary methods that need to be implemented are: 66 * <ul> 67 * <li>{@link #onCreate} which is called to initialize the provider</li> 68 * <li>{@link #query} which returns data to the caller</li> 69 * <li>{@link #insert} which inserts new data into the content provider</li> 70 * <li>{@link #update} which updates existing data in the content provider</li> 71 * <li>{@link #delete} which deletes data from the content provider</li> 72 * <li>{@link #getType} which returns the MIME type of data in the content provider</li> 73 * </ul></p> 74 * 75 * <p class="caution">Data access methods (such as {@link #insert} and 76 * {@link #update}) may be called from many threads at once, and must be thread-safe. 77 * Other methods (such as {@link #onCreate}) are only called from the application 78 * main thread, and must avoid performing lengthy operations. See the method 79 * descriptions for their expected thread behavior.</p> 80 * 81 * <p>Requests to {@link ContentResolver} are automatically forwarded to the appropriate 82 * ContentProvider instance, so subclasses don't have to worry about the details of 83 * cross-process calls.</p> 84 * 85 * <div class="special reference"> 86 * <h3>Developer Guides</h3> 87 * <p>For more information about using content providers, read the 88 * <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> 89 * developer guide.</p> 90 */ 91 public abstract class ContentProvider implements ComponentCallbacks2 { 92 private static final String TAG = "ContentProvider"; 93 94 /* 95 * Note: if you add methods to ContentProvider, you must add similar methods to 96 * MockContentProvider. 97 */ 98 99 private Context mContext = null; 100 private int mMyUid; 101 private String mReadPermission; 102 private String mWritePermission; 103 private PathPermission[] mPathPermissions; 104 private boolean mExported; 105 private boolean mNoPerms; 106 107 private Transport mTransport = new Transport(); 108 109 /** 110 * Construct a ContentProvider instance. Content providers must be 111 * <a href="{@docRoot}guide/topics/manifest/provider-element.html">declared 112 * in the manifest</a>, accessed with {@link ContentResolver}, and created 113 * automatically by the system, so applications usually do not create 114 * ContentProvider instances directly. 115 * 116 * <p>At construction time, the object is uninitialized, and most fields and 117 * methods are unavailable. Subclasses should initialize themselves in 118 * {@link #onCreate}, not the constructor. 119 * 120 * <p>Content providers are created on the application main thread at 121 * application launch time. The constructor must not perform lengthy 122 * operations, or application startup will be delayed. 123 */ 124 public ContentProvider() { 125 } 126 127 /** 128 * Constructor just for mocking. 129 * 130 * @param context A Context object which should be some mock instance (like the 131 * instance of {@link android.test.mock.MockContext}). 132 * @param readPermission The read permision you want this instance should have in the 133 * test, which is available via {@link #getReadPermission()}. 134 * @param writePermission The write permission you want this instance should have 135 * in the test, which is available via {@link #getWritePermission()}. 136 * @param pathPermissions The PathPermissions you want this instance should have 137 * in the test, which is available via {@link #getPathPermissions()}. 138 * @hide 139 */ 140 public ContentProvider( 141 Context context, 142 String readPermission, 143 String writePermission, 144 PathPermission[] pathPermissions) { 145 mContext = context; 146 mReadPermission = readPermission; 147 mWritePermission = writePermission; 148 mPathPermissions = pathPermissions; 149 } 150 151 /** 152 * Given an IContentProvider, try to coerce it back to the real 153 * ContentProvider object if it is running in the local process. This can 154 * be used if you know you are running in the same process as a provider, 155 * and want to get direct access to its implementation details. Most 156 * clients should not nor have a reason to use it. 157 * 158 * @param abstractInterface The ContentProvider interface that is to be 159 * coerced. 160 * @return If the IContentProvider is non-{@code null} and local, returns its actual 161 * ContentProvider instance. Otherwise returns {@code null}. 162 * @hide 163 */ 164 public static ContentProvider coerceToLocalContentProvider( 165 IContentProvider abstractInterface) { 166 if (abstractInterface instanceof Transport) { 167 return ((Transport)abstractInterface).getContentProvider(); 168 } 169 return null; 170 } 171 172 /** 173 * Binder object that deals with remoting. 174 * 175 * @hide 176 */ 177 class Transport extends ContentProviderNative { 178 AppOpsManager mAppOpsManager = null; 179 int mReadOp = AppOpsManager.OP_NONE; 180 int mWriteOp = AppOpsManager.OP_NONE; 181 182 ContentProvider getContentProvider() { 183 return ContentProvider.this; 184 } 185 186 @Override 187 public String getProviderName() { 188 return getContentProvider().getClass().getName(); 189 } 190 191 @Override 192 public Cursor query(String callingPkg, Uri uri, String[] projection, 193 String selection, String[] selectionArgs, String sortOrder, 194 ICancellationSignal cancellationSignal) { 195 if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { 196 return rejectQuery(uri, projection, selection, selectionArgs, sortOrder, 197 CancellationSignal.fromTransport(cancellationSignal)); 198 } 199 return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder, 200 CancellationSignal.fromTransport(cancellationSignal)); 201 } 202 203 @Override 204 public String getType(Uri uri) { 205 return ContentProvider.this.getType(uri); 206 } 207 208 @Override 209 public Uri insert(String callingPkg, Uri uri, ContentValues initialValues) { 210 if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { 211 return rejectInsert(uri, initialValues); 212 } 213 return ContentProvider.this.insert(uri, initialValues); 214 } 215 216 @Override 217 public int bulkInsert(String callingPkg, Uri uri, ContentValues[] initialValues) { 218 if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { 219 return 0; 220 } 221 return ContentProvider.this.bulkInsert(uri, initialValues); 222 } 223 224 @Override 225 public ContentProviderResult[] applyBatch(String callingPkg, 226 ArrayList<ContentProviderOperation> operations) 227 throws OperationApplicationException { 228 for (ContentProviderOperation operation : operations) { 229 if (operation.isReadOperation()) { 230 if (enforceReadPermission(callingPkg, operation.getUri()) 231 != AppOpsManager.MODE_ALLOWED) { 232 throw new OperationApplicationException("App op not allowed", 0); 233 } 234 } 235 236 if (operation.isWriteOperation()) { 237 if (enforceWritePermission(callingPkg, operation.getUri()) 238 != AppOpsManager.MODE_ALLOWED) { 239 throw new OperationApplicationException("App op not allowed", 0); 240 } 241 } 242 } 243 return ContentProvider.this.applyBatch(operations); 244 } 245 246 @Override 247 public int delete(String callingPkg, Uri uri, String selection, String[] selectionArgs) { 248 if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { 249 return 0; 250 } 251 return ContentProvider.this.delete(uri, selection, selectionArgs); 252 } 253 254 @Override 255 public int update(String callingPkg, Uri uri, ContentValues values, String selection, 256 String[] selectionArgs) { 257 if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { 258 return 0; 259 } 260 return ContentProvider.this.update(uri, values, selection, selectionArgs); 261 } 262 263 @Override 264 public ParcelFileDescriptor openFile(String callingPkg, Uri uri, String mode) 265 throws FileNotFoundException { 266 enforceFilePermission(callingPkg, uri, mode); 267 return ContentProvider.this.openFile(uri, mode); 268 } 269 270 @Override 271 public AssetFileDescriptor openAssetFile(String callingPkg, Uri uri, String mode) 272 throws FileNotFoundException { 273 enforceFilePermission(callingPkg, uri, mode); 274 return ContentProvider.this.openAssetFile(uri, mode); 275 } 276 277 @Override 278 public Bundle call(String callingPkg, String method, String arg, Bundle extras) { 279 return ContentProvider.this.callFromPackage(callingPkg, method, arg, extras); 280 } 281 282 @Override 283 public String[] getStreamTypes(Uri uri, String mimeTypeFilter) { 284 return ContentProvider.this.getStreamTypes(uri, mimeTypeFilter); 285 } 286 287 @Override 288 public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType, 289 Bundle opts) throws FileNotFoundException { 290 enforceFilePermission(callingPkg, uri, "r"); 291 return ContentProvider.this.openTypedAssetFile(uri, mimeType, opts); 292 } 293 294 @Override 295 public ICancellationSignal createCancellationSignal() throws RemoteException { 296 return CancellationSignal.createTransport(); 297 } 298 299 private void enforceFilePermission(String callingPkg, Uri uri, String mode) 300 throws FileNotFoundException, SecurityException { 301 if (mode != null && mode.indexOf('w') != -1) { 302 if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { 303 throw new FileNotFoundException("App op not allowed"); 304 } 305 } else { 306 if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { 307 throw new FileNotFoundException("App op not allowed"); 308 } 309 } 310 } 311 312 private int enforceReadPermission(String callingPkg, Uri uri) throws SecurityException { 313 enforceReadPermissionInner(uri); 314 if (mReadOp != AppOpsManager.OP_NONE) { 315 return mAppOpsManager.noteOp(mReadOp, Binder.getCallingUid(), callingPkg); 316 } 317 return AppOpsManager.MODE_ALLOWED; 318 } 319 320 private void enforceReadPermissionInner(Uri uri) throws SecurityException { 321 final Context context = getContext(); 322 final int pid = Binder.getCallingPid(); 323 final int uid = Binder.getCallingUid(); 324 String missingPerm = null; 325 326 if (UserHandle.isSameApp(uid, mMyUid)) { 327 return; 328 } 329 330 if (mExported) { 331 final String componentPerm = getReadPermission(); 332 if (componentPerm != null) { 333 if (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED) { 334 return; 335 } else { 336 missingPerm = componentPerm; 337 } 338 } 339 340 // track if unprotected read is allowed; any denied 341 // <path-permission> below removes this ability 342 boolean allowDefaultRead = (componentPerm == null); 343 344 final PathPermission[] pps = getPathPermissions(); 345 if (pps != null) { 346 final String path = uri.getPath(); 347 for (PathPermission pp : pps) { 348 final String pathPerm = pp.getReadPermission(); 349 if (pathPerm != null && pp.match(path)) { 350 if (context.checkPermission(pathPerm, pid, uid) == PERMISSION_GRANTED) { 351 return; 352 } else { 353 // any denied <path-permission> means we lose 354 // default <provider> access. 355 allowDefaultRead = false; 356 missingPerm = pathPerm; 357 } 358 } 359 } 360 } 361 362 // if we passed <path-permission> checks above, and no default 363 // <provider> permission, then allow access. 364 if (allowDefaultRead) return; 365 } 366 367 // last chance, check against any uri grants 368 if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION) 369 == PERMISSION_GRANTED) { 370 return; 371 } 372 373 final String failReason = mExported 374 ? " requires " + missingPerm + ", or grantUriPermission()" 375 : " requires the provider be exported, or grantUriPermission()"; 376 throw new SecurityException("Permission Denial: reading " 377 + ContentProvider.this.getClass().getName() + " uri " + uri + " from pid=" + pid 378 + ", uid=" + uid + failReason); 379 } 380 381 private int enforceWritePermission(String callingPkg, Uri uri) throws SecurityException { 382 enforceWritePermissionInner(uri); 383 if (mWriteOp != AppOpsManager.OP_NONE) { 384 return mAppOpsManager.noteOp(mWriteOp, Binder.getCallingUid(), callingPkg); 385 } 386 return AppOpsManager.MODE_ALLOWED; 387 } 388 389 private void enforceWritePermissionInner(Uri uri) throws SecurityException { 390 final Context context = getContext(); 391 final int pid = Binder.getCallingPid(); 392 final int uid = Binder.getCallingUid(); 393 String missingPerm = null; 394 395 if (UserHandle.isSameApp(uid, mMyUid)) { 396 return; 397 } 398 399 if (mExported) { 400 final String componentPerm = getWritePermission(); 401 if (componentPerm != null) { 402 if (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED) { 403 return; 404 } else { 405 missingPerm = componentPerm; 406 } 407 } 408 409 // track if unprotected write is allowed; any denied 410 // <path-permission> below removes this ability 411 boolean allowDefaultWrite = (componentPerm == null); 412 413 final PathPermission[] pps = getPathPermissions(); 414 if (pps != null) { 415 final String path = uri.getPath(); 416 for (PathPermission pp : pps) { 417 final String pathPerm = pp.getWritePermission(); 418 if (pathPerm != null && pp.match(path)) { 419 if (context.checkPermission(pathPerm, pid, uid) == PERMISSION_GRANTED) { 420 return; 421 } else { 422 // any denied <path-permission> means we lose 423 // default <provider> access. 424 allowDefaultWrite = false; 425 missingPerm = pathPerm; 426 } 427 } 428 } 429 } 430 431 // if we passed <path-permission> checks above, and no default 432 // <provider> permission, then allow access. 433 if (allowDefaultWrite) return; 434 } 435 436 // last chance, check against any uri grants 437 if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION) 438 == PERMISSION_GRANTED) { 439 return; 440 } 441 442 final String failReason = mExported 443 ? " requires " + missingPerm + ", or grantUriPermission()" 444 : " requires the provider be exported, or grantUriPermission()"; 445 throw new SecurityException("Permission Denial: writing " 446 + ContentProvider.this.getClass().getName() + " uri " + uri + " from pid=" + pid 447 + ", uid=" + uid + failReason); 448 } 449 } 450 451 /** 452 * Retrieves the Context this provider is running in. Only available once 453 * {@link #onCreate} has been called -- this will return {@code null} in the 454 * constructor. 455 */ 456 public final Context getContext() { 457 return mContext; 458 } 459 460 /** 461 * Change the permission required to read data from the content 462 * provider. This is normally set for you from its manifest information 463 * when the provider is first created. 464 * 465 * @param permission Name of the permission required for read-only access. 466 */ 467 protected final void setReadPermission(String permission) { 468 mReadPermission = permission; 469 } 470 471 /** 472 * Return the name of the permission required for read-only access to 473 * this content provider. This method can be called from multiple 474 * threads, as described in 475 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes 476 * and Threads</a>. 477 */ 478 public final String getReadPermission() { 479 return mReadPermission; 480 } 481 482 /** 483 * Change the permission required to read and write data in the content 484 * provider. This is normally set for you from its manifest information 485 * when the provider is first created. 486 * 487 * @param permission Name of the permission required for read/write access. 488 */ 489 protected final void setWritePermission(String permission) { 490 mWritePermission = permission; 491 } 492 493 /** 494 * Return the name of the permission required for read/write access to 495 * this content provider. This method can be called from multiple 496 * threads, as described in 497 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes 498 * and Threads</a>. 499 */ 500 public final String getWritePermission() { 501 return mWritePermission; 502 } 503 504 /** 505 * Change the path-based permission required to read and/or write data in 506 * the content provider. This is normally set for you from its manifest 507 * information when the provider is first created. 508 * 509 * @param permissions Array of path permission descriptions. 510 */ 511 protected final void setPathPermissions(PathPermission[] permissions) { 512 mPathPermissions = permissions; 513 } 514 515 /** 516 * Return the path-based permissions required for read and/or write access to 517 * this content provider. This method can be called from multiple 518 * threads, as described in 519 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes 520 * and Threads</a>. 521 */ 522 public final PathPermission[] getPathPermissions() { 523 return mPathPermissions; 524 } 525 526 /** @hide */ 527 public final void setAppOps(int readOp, int writeOp) { 528 if (!mNoPerms) { 529 mTransport.mAppOpsManager = (AppOpsManager)mContext.getSystemService( 530 Context.APP_OPS_SERVICE); 531 mTransport.mReadOp = readOp; 532 mTransport.mWriteOp = writeOp; 533 } 534 } 535 536 /** @hide */ 537 public AppOpsManager getAppOpsManager() { 538 return mTransport.mAppOpsManager; 539 } 540 541 /** 542 * Implement this to initialize your content provider on startup. 543 * This method is called for all registered content providers on the 544 * application main thread at application launch time. It must not perform 545 * lengthy operations, or application startup will be delayed. 546 * 547 * <p>You should defer nontrivial initialization (such as opening, 548 * upgrading, and scanning databases) until the content provider is used 549 * (via {@link #query}, {@link #insert}, etc). Deferred initialization 550 * keeps application startup fast, avoids unnecessary work if the provider 551 * turns out not to be needed, and stops database errors (such as a full 552 * disk) from halting application launch. 553 * 554 * <p>If you use SQLite, {@link android.database.sqlite.SQLiteOpenHelper} 555 * is a helpful utility class that makes it easy to manage databases, 556 * and will automatically defer opening until first use. If you do use 557 * SQLiteOpenHelper, make sure to avoid calling 558 * {@link android.database.sqlite.SQLiteOpenHelper#getReadableDatabase} or 559 * {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase} 560 * from this method. (Instead, override 561 * {@link android.database.sqlite.SQLiteOpenHelper#onOpen} to initialize the 562 * database when it is first opened.) 563 * 564 * @return true if the provider was successfully loaded, false otherwise 565 */ 566 public abstract boolean onCreate(); 567 568 /** 569 * {@inheritDoc} 570 * This method is always called on the application main thread, and must 571 * not perform lengthy operations. 572 * 573 * <p>The default content provider implementation does nothing. 574 * Override this method to take appropriate action. 575 * (Content providers do not usually care about things like screen 576 * orientation, but may want to know about locale changes.) 577 */ 578 public void onConfigurationChanged(Configuration newConfig) { 579 } 580 581 /** 582 * {@inheritDoc} 583 * This method is always called on the application main thread, and must 584 * not perform lengthy operations. 585 * 586 * <p>The default content provider implementation does nothing. 587 * Subclasses may override this method to take appropriate action. 588 */ 589 public void onLowMemory() { 590 } 591 592 public void onTrimMemory(int level) { 593 } 594 595 /** 596 * @hide 597 * Implementation when a caller has performed a query on the content 598 * provider, but that call has been rejected for the operation given 599 * to {@link #setAppOps(int, int)}. The default implementation 600 * rewrites the <var>selection</var> argument to include a condition 601 * that is never true (so will always result in an empty cursor) 602 * and calls through to {@link #query(android.net.Uri, String[], String, String[], 603 * String, android.os.CancellationSignal)} with that. 604 */ 605 public Cursor rejectQuery(Uri uri, String[] projection, 606 String selection, String[] selectionArgs, String sortOrder, 607 CancellationSignal cancellationSignal) { 608 // The read is not allowed... to fake it out, we replace the given 609 // selection statement with a dummy one that will always be false. 610 // This way we will get a cursor back that has the correct structure 611 // but contains no rows. 612 if (selection == null || selection.isEmpty()) { 613 selection = "'A' = 'B'"; 614 } else { 615 selection = "'A' = 'B' AND (" + selection + ")"; 616 } 617 return query(uri, projection, selection, selectionArgs, sortOrder, cancellationSignal); 618 } 619 620 /** 621 * Implement this to handle query requests from clients. 622 * This method can be called from multiple threads, as described in 623 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes 624 * and Threads</a>. 625 * <p> 626 * Example client call:<p> 627 * <pre>// Request a specific record. 628 * Cursor managedCursor = managedQuery( 629 ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2), 630 projection, // Which columns to return. 631 null, // WHERE clause. 632 null, // WHERE clause value substitution 633 People.NAME + " ASC"); // Sort order.</pre> 634 * Example implementation:<p> 635 * <pre>// SQLiteQueryBuilder is a helper class that creates the 636 // proper SQL syntax for us. 637 SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder(); 638 639 // Set the table we're querying. 640 qBuilder.setTables(DATABASE_TABLE_NAME); 641 642 // If the query ends in a specific record number, we're 643 // being asked for a specific record, so set the 644 // WHERE clause in our query. 645 if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){ 646 qBuilder.appendWhere("_id=" + uri.getPathLeafId()); 647 } 648 649 // Make the query. 650 Cursor c = qBuilder.query(mDb, 651 projection, 652 selection, 653 selectionArgs, 654 groupBy, 655 having, 656 sortOrder); 657 c.setNotificationUri(getContext().getContentResolver(), uri); 658 return c;</pre> 659 * 660 * @param uri The URI to query. This will be the full URI sent by the client; 661 * if the client is requesting a specific record, the URI will end in a record number 662 * that the implementation should parse and add to a WHERE or HAVING clause, specifying 663 * that _id value. 664 * @param projection The list of columns to put into the cursor. If 665 * {@code null} all columns are included. 666 * @param selection A selection criteria to apply when filtering rows. 667 * If {@code null} then all rows are included. 668 * @param selectionArgs You may include ?s in selection, which will be replaced by 669 * the values from selectionArgs, in order that they appear in the selection. 670 * The values will be bound as Strings. 671 * @param sortOrder How the rows in the cursor should be sorted. 672 * If {@code null} then the provider is free to define the sort order. 673 * @return a Cursor or {@code null}. 674 */ 675 public abstract Cursor query(Uri uri, String[] projection, 676 String selection, String[] selectionArgs, String sortOrder); 677 678 /** 679 * Implement this to handle query requests from clients with support for cancellation. 680 * This method can be called from multiple threads, as described in 681 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes 682 * and Threads</a>. 683 * <p> 684 * Example client call:<p> 685 * <pre>// Request a specific record. 686 * Cursor managedCursor = managedQuery( 687 ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2), 688 projection, // Which columns to return. 689 null, // WHERE clause. 690 null, // WHERE clause value substitution 691 People.NAME + " ASC"); // Sort order.</pre> 692 * Example implementation:<p> 693 * <pre>// SQLiteQueryBuilder is a helper class that creates the 694 // proper SQL syntax for us. 695 SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder(); 696 697 // Set the table we're querying. 698 qBuilder.setTables(DATABASE_TABLE_NAME); 699 700 // If the query ends in a specific record number, we're 701 // being asked for a specific record, so set the 702 // WHERE clause in our query. 703 if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){ 704 qBuilder.appendWhere("_id=" + uri.getPathLeafId()); 705 } 706 707 // Make the query. 708 Cursor c = qBuilder.query(mDb, 709 projection, 710 selection, 711 selectionArgs, 712 groupBy, 713 having, 714 sortOrder); 715 c.setNotificationUri(getContext().getContentResolver(), uri); 716 return c;</pre> 717 * <p> 718 * If you implement this method then you must also implement the version of 719 * {@link #query(Uri, String[], String, String[], String)} that does not take a cancellation 720 * signal to ensure correct operation on older versions of the Android Framework in 721 * which the cancellation signal overload was not available. 722 * 723 * @param uri The URI to query. This will be the full URI sent by the client; 724 * if the client is requesting a specific record, the URI will end in a record number 725 * that the implementation should parse and add to a WHERE or HAVING clause, specifying 726 * that _id value. 727 * @param projection The list of columns to put into the cursor. If 728 * {@code null} all columns are included. 729 * @param selection A selection criteria to apply when filtering rows. 730 * If {@code null} then all rows are included. 731 * @param selectionArgs You may include ?s in selection, which will be replaced by 732 * the values from selectionArgs, in order that they appear in the selection. 733 * The values will be bound as Strings. 734 * @param sortOrder How the rows in the cursor should be sorted. 735 * If {@code null} then the provider is free to define the sort order. 736 * @param cancellationSignal A signal to cancel the operation in progress, or {@code null} if none. 737 * If the operation is canceled, then {@link OperationCanceledException} will be thrown 738 * when the query is executed. 739 * @return a Cursor or {@code null}. 740 */ 741 public Cursor query(Uri uri, String[] projection, 742 String selection, String[] selectionArgs, String sortOrder, 743 CancellationSignal cancellationSignal) { 744 return query(uri, projection, selection, selectionArgs, sortOrder); 745 } 746 747 /** 748 * Implement this to handle requests for the MIME type of the data at the 749 * given URI. The returned MIME type should start with 750 * <code>vnd.android.cursor.item</code> for a single record, 751 * or <code>vnd.android.cursor.dir/</code> for multiple items. 752 * This method can be called from multiple threads, as described in 753 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes 754 * and Threads</a>. 755 * 756 * <p>Note that there are no permissions needed for an application to 757 * access this information; if your content provider requires read and/or 758 * write permissions, or is not exported, all applications can still call 759 * this method regardless of their access permissions. This allows them 760 * to retrieve the MIME type for a URI when dispatching intents. 761 * 762 * @param uri the URI to query. 763 * @return a MIME type string, or {@code null} if there is no type. 764 */ 765 public abstract String getType(Uri uri); 766 767 /** 768 * @hide 769 * Implementation when a caller has performed an insert on the content 770 * provider, but that call has been rejected for the operation given 771 * to {@link #setAppOps(int, int)}. The default implementation simply 772 * returns a dummy URI that is the base URI with a 0 path element 773 * appended. 774 */ 775 public Uri rejectInsert(Uri uri, ContentValues values) { 776 // If not allowed, we need to return some reasonable URI. Maybe the 777 // content provider should be responsible for this, but for now we 778 // will just return the base URI with a dummy '0' tagged on to it. 779 // You shouldn't be able to read if you can't write, anyway, so it 780 // shouldn't matter much what is returned. 781 return uri.buildUpon().appendPath("0").build(); 782 } 783 784 /** 785 * Implement this to handle requests to insert a new row. 786 * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()} 787 * after inserting. 788 * This method can be called from multiple threads, as described in 789 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes 790 * and Threads</a>. 791 * @param uri The content:// URI of the insertion request. This must not be {@code null}. 792 * @param values A set of column_name/value pairs to add to the database. 793 * This must not be {@code null}. 794 * @return The URI for the newly inserted item. 795 */ 796 public abstract Uri insert(Uri uri, ContentValues values); 797 798 /** 799 * Override this to handle requests to insert a set of new rows, or the 800 * default implementation will iterate over the values and call 801 * {@link #insert} on each of them. 802 * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()} 803 * after inserting. 804 * This method can be called from multiple threads, as described in 805 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes 806 * and Threads</a>. 807 * 808 * @param uri The content:// URI of the insertion request. 809 * @param values An array of sets of column_name/value pairs to add to the database. 810 * This must not be {@code null}. 811 * @return The number of values that were inserted. 812 */ 813 public int bulkInsert(Uri uri, ContentValues[] values) { 814 int numValues = values.length; 815 for (int i = 0; i < numValues; i++) { 816 insert(uri, values[i]); 817 } 818 return numValues; 819 } 820 821 /** 822 * Implement this to handle requests to delete one or more rows. 823 * The implementation should apply the selection clause when performing 824 * deletion, allowing the operation to affect multiple rows in a directory. 825 * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyDelete()} 826 * after deleting. 827 * This method can be called from multiple threads, as described in 828 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes 829 * and Threads</a>. 830 * 831 * <p>The implementation is responsible for parsing out a row ID at the end 832 * of the URI, if a specific row is being deleted. That is, the client would 833 * pass in <code>content://contacts/people/22</code> and the implementation is 834 * responsible for parsing the record number (22) when creating a SQL statement. 835 * 836 * @param uri The full URI to query, including a row ID (if a specific record is requested). 837 * @param selection An optional restriction to apply to rows when deleting. 838 * @return The number of rows affected. 839 * @throws SQLException 840 */ 841 public abstract int delete(Uri uri, String selection, String[] selectionArgs); 842 843 /** 844 * Implement this to handle requests to update one or more rows. 845 * The implementation should update all rows matching the selection 846 * to set the columns according to the provided values map. 847 * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()} 848 * after updating. 849 * This method can be called from multiple threads, as described in 850 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes 851 * and Threads</a>. 852 * 853 * @param uri The URI to query. This can potentially have a record ID if this 854 * is an update request for a specific record. 855 * @param values A set of column_name/value pairs to update in the database. 856 * This must not be {@code null}. 857 * @param selection An optional filter to match rows to update. 858 * @return the number of rows affected. 859 */ 860 public abstract int update(Uri uri, ContentValues values, String selection, 861 String[] selectionArgs); 862 863 /** 864 * Override this to handle requests to open a file blob. 865 * The default implementation always throws {@link FileNotFoundException}. 866 * This method can be called from multiple threads, as described in 867 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes 868 * and Threads</a>. 869 * 870 * <p>This method returns a ParcelFileDescriptor, which is returned directly 871 * to the caller. This way large data (such as images and documents) can be 872 * returned without copying the content. 873 * 874 * <p>The returned ParcelFileDescriptor is owned by the caller, so it is 875 * their responsibility to close it when done. That is, the implementation 876 * of this method should create a new ParcelFileDescriptor for each call. 877 * 878 * <p class="note">For use in Intents, you will want to implement {@link #getType} 879 * to return the appropriate MIME type for the data returned here with 880 * the same URI. This will allow intent resolution to automatically determine the data MIME 881 * type and select the appropriate matching targets as part of its operation.</p> 882 * 883 * <p class="note">For better interoperability with other applications, it is recommended 884 * that for any URIs that can be opened, you also support queries on them 885 * containing at least the columns specified by {@link android.provider.OpenableColumns}. 886 * You may also want to support other common columns if you have additional meta-data 887 * to supply, such as {@link android.provider.MediaStore.MediaColumns#DATE_ADDED} 888 * in {@link android.provider.MediaStore.MediaColumns}.</p> 889 * 890 * @param uri The URI whose file is to be opened. 891 * @param mode Access mode for the file. May be "r" for read-only access, 892 * "rw" for read and write access, or "rwt" for read and write access 893 * that truncates any existing file. 894 * 895 * @return Returns a new ParcelFileDescriptor which you can use to access 896 * the file. 897 * 898 * @throws FileNotFoundException Throws FileNotFoundException if there is 899 * no file associated with the given URI or the mode is invalid. 900 * @throws SecurityException Throws SecurityException if the caller does 901 * not have permission to access the file. 902 * 903 * @see #openAssetFile(Uri, String) 904 * @see #openFileHelper(Uri, String) 905 * @see #getType(android.net.Uri) 906 */ 907 public ParcelFileDescriptor openFile(Uri uri, String mode) 908 throws FileNotFoundException { 909 throw new FileNotFoundException("No files supported by provider at " 910 + uri); 911 } 912 913 /** 914 * This is like {@link #openFile}, but can be implemented by providers 915 * that need to be able to return sub-sections of files, often assets 916 * inside of their .apk. 917 * This method can be called from multiple threads, as described in 918 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes 919 * and Threads</a>. 920 * 921 * <p>If you implement this, your clients must be able to deal with such 922 * file slices, either directly with 923 * {@link ContentResolver#openAssetFileDescriptor}, or by using the higher-level 924 * {@link ContentResolver#openInputStream ContentResolver.openInputStream} 925 * or {@link ContentResolver#openOutputStream ContentResolver.openOutputStream} 926 * methods. 927 * 928 * <p class="note">If you are implementing this to return a full file, you 929 * should create the AssetFileDescriptor with 930 * {@link AssetFileDescriptor#UNKNOWN_LENGTH} to be compatible with 931 * applications that can not handle sub-sections of files.</p> 932 * 933 * <p class="note">For use in Intents, you will want to implement {@link #getType} 934 * to return the appropriate MIME type for the data returned here with 935 * the same URI. This will allow intent resolution to automatically determine the data MIME 936 * type and select the appropriate matching targets as part of its operation.</p> 937 * 938 * <p class="note">For better interoperability with other applications, it is recommended 939 * that for any URIs that can be opened, you also support queries on them 940 * containing at least the columns specified by {@link android.provider.OpenableColumns}.</p> 941 * 942 * @param uri The URI whose file is to be opened. 943 * @param mode Access mode for the file. May be "r" for read-only access, 944 * "w" for write-only access (erasing whatever data is currently in 945 * the file), "wa" for write-only access to append to any existing data, 946 * "rw" for read and write access on any existing data, and "rwt" for read 947 * and write access that truncates any existing file. 948 * 949 * @return Returns a new AssetFileDescriptor which you can use to access 950 * the file. 951 * 952 * @throws FileNotFoundException Throws FileNotFoundException if there is 953 * no file associated with the given URI or the mode is invalid. 954 * @throws SecurityException Throws SecurityException if the caller does 955 * not have permission to access the file. 956 * 957 * @see #openFile(Uri, String) 958 * @see #openFileHelper(Uri, String) 959 * @see #getType(android.net.Uri) 960 */ 961 public AssetFileDescriptor openAssetFile(Uri uri, String mode) 962 throws FileNotFoundException { 963 ParcelFileDescriptor fd = openFile(uri, mode); 964 return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null; 965 } 966 967 /** 968 * Convenience for subclasses that wish to implement {@link #openFile} 969 * by looking up a column named "_data" at the given URI. 970 * 971 * @param uri The URI to be opened. 972 * @param mode The file mode. May be "r" for read-only access, 973 * "w" for write-only access (erasing whatever data is currently in 974 * the file), "wa" for write-only access to append to any existing data, 975 * "rw" for read and write access on any existing data, and "rwt" for read 976 * and write access that truncates any existing file. 977 * 978 * @return Returns a new ParcelFileDescriptor that can be used by the 979 * client to access the file. 980 */ 981 protected final ParcelFileDescriptor openFileHelper(Uri uri, 982 String mode) throws FileNotFoundException { 983 Cursor c = query(uri, new String[]{"_data"}, null, null, null); 984 int count = (c != null) ? c.getCount() : 0; 985 if (count != 1) { 986 // If there is not exactly one result, throw an appropriate 987 // exception. 988 if (c != null) { 989 c.close(); 990 } 991 if (count == 0) { 992 throw new FileNotFoundException("No entry for " + uri); 993 } 994 throw new FileNotFoundException("Multiple items at " + uri); 995 } 996 997 c.moveToFirst(); 998 int i = c.getColumnIndex("_data"); 999 String path = (i >= 0 ? c.getString(i) : null); 1000 c.close(); 1001 if (path == null) { 1002 throw new FileNotFoundException("Column _data not found."); 1003 } 1004 1005 int modeBits = ContentResolver.modeToMode(uri, mode); 1006 return ParcelFileDescriptor.open(new File(path), modeBits); 1007 } 1008 1009 /** 1010 * Called by a client to determine the types of data streams that this 1011 * content provider supports for the given URI. The default implementation 1012 * returns {@code null}, meaning no types. If your content provider stores data 1013 * of a particular type, return that MIME type if it matches the given 1014 * mimeTypeFilter. If it can perform type conversions, return an array 1015 * of all supported MIME types that match mimeTypeFilter. 1016 * 1017 * @param uri The data in the content provider being queried. 1018 * @param mimeTypeFilter The type of data the client desires. May be 1019 * a pattern, such as *\/* to retrieve all possible data types. 1020 * @return Returns {@code null} if there are no possible data streams for the 1021 * given mimeTypeFilter. Otherwise returns an array of all available 1022 * concrete MIME types. 1023 * 1024 * @see #getType(Uri) 1025 * @see #openTypedAssetFile(Uri, String, Bundle) 1026 * @see ClipDescription#compareMimeTypes(String, String) 1027 */ 1028 public String[] getStreamTypes(Uri uri, String mimeTypeFilter) { 1029 return null; 1030 } 1031 1032 /** 1033 * Called by a client to open a read-only stream containing data of a 1034 * particular MIME type. This is like {@link #openAssetFile(Uri, String)}, 1035 * except the file can only be read-only and the content provider may 1036 * perform data conversions to generate data of the desired type. 1037 * 1038 * <p>The default implementation compares the given mimeType against the 1039 * result of {@link #getType(Uri)} and, if they match, simply calls 1040 * {@link #openAssetFile(Uri, String)}. 1041 * 1042 * <p>See {@link ClipData} for examples of the use and implementation 1043 * of this method. 1044 * 1045 * <p class="note">For better interoperability with other applications, it is recommended 1046 * that for any URIs that can be opened, you also support queries on them 1047 * containing at least the columns specified by {@link android.provider.OpenableColumns}. 1048 * You may also want to support other common columns if you have additional meta-data 1049 * to supply, such as {@link android.provider.MediaStore.MediaColumns#DATE_ADDED} 1050 * in {@link android.provider.MediaStore.MediaColumns}.</p> 1051 * 1052 * @param uri The data in the content provider being queried. 1053 * @param mimeTypeFilter The type of data the client desires. May be 1054 * a pattern, such as *\/*, if the caller does not have specific type 1055 * requirements; in this case the content provider will pick its best 1056 * type matching the pattern. 1057 * @param opts Additional options from the client. The definitions of 1058 * these are specific to the content provider being called. 1059 * 1060 * @return Returns a new AssetFileDescriptor from which the client can 1061 * read data of the desired type. 1062 * 1063 * @throws FileNotFoundException Throws FileNotFoundException if there is 1064 * no file associated with the given URI or the mode is invalid. 1065 * @throws SecurityException Throws SecurityException if the caller does 1066 * not have permission to access the data. 1067 * @throws IllegalArgumentException Throws IllegalArgumentException if the 1068 * content provider does not support the requested MIME type. 1069 * 1070 * @see #getStreamTypes(Uri, String) 1071 * @see #openAssetFile(Uri, String) 1072 * @see ClipDescription#compareMimeTypes(String, String) 1073 */ 1074 public AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts) 1075 throws FileNotFoundException { 1076 if ("*/*".equals(mimeTypeFilter)) { 1077 // If they can take anything, the untyped open call is good enough. 1078 return openAssetFile(uri, "r"); 1079 } 1080 String baseType = getType(uri); 1081 if (baseType != null && ClipDescription.compareMimeTypes(baseType, mimeTypeFilter)) { 1082 // Use old untyped open call if this provider has a type for this 1083 // URI and it matches the request. 1084 return openAssetFile(uri, "r"); 1085 } 1086 throw new FileNotFoundException("Can't open " + uri + " as type " + mimeTypeFilter); 1087 } 1088 1089 /** 1090 * Interface to write a stream of data to a pipe. Use with 1091 * {@link ContentProvider#openPipeHelper}. 1092 */ 1093 public interface PipeDataWriter<T> { 1094 /** 1095 * Called from a background thread to stream data out to a pipe. 1096 * Note that the pipe is blocking, so this thread can block on 1097 * writes for an arbitrary amount of time if the client is slow 1098 * at reading. 1099 * 1100 * @param output The pipe where data should be written. This will be 1101 * closed for you upon returning from this function. 1102 * @param uri The URI whose data is to be written. 1103 * @param mimeType The desired type of data to be written. 1104 * @param opts Options supplied by caller. 1105 * @param args Your own custom arguments. 1106 */ 1107 public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String mimeType, 1108 Bundle opts, T args); 1109 } 1110 1111 /** 1112 * A helper function for implementing {@link #openTypedAssetFile}, for 1113 * creating a data pipe and background thread allowing you to stream 1114 * generated data back to the client. This function returns a new 1115 * ParcelFileDescriptor that should be returned to the caller (the caller 1116 * is responsible for closing it). 1117 * 1118 * @param uri The URI whose data is to be written. 1119 * @param mimeType The desired type of data to be written. 1120 * @param opts Options supplied by caller. 1121 * @param args Your own custom arguments. 1122 * @param func Interface implementing the function that will actually 1123 * stream the data. 1124 * @return Returns a new ParcelFileDescriptor holding the read side of 1125 * the pipe. This should be returned to the caller for reading; the caller 1126 * is responsible for closing it when done. 1127 */ 1128 public <T> ParcelFileDescriptor openPipeHelper(final Uri uri, final String mimeType, 1129 final Bundle opts, final T args, final PipeDataWriter<T> func) 1130 throws FileNotFoundException { 1131 try { 1132 final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe(); 1133 1134 AsyncTask<Object, Object, Object> task = new AsyncTask<Object, Object, Object>() { 1135 @Override 1136 protected Object doInBackground(Object... params) { 1137 func.writeDataToPipe(fds[1], uri, mimeType, opts, args); 1138 try { 1139 fds[1].close(); 1140 } catch (IOException e) { 1141 Log.w(TAG, "Failure closing pipe", e); 1142 } 1143 return null; 1144 } 1145 }; 1146 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Object[])null); 1147 1148 return fds[0]; 1149 } catch (IOException e) { 1150 throw new FileNotFoundException("failure making pipe"); 1151 } 1152 } 1153 1154 /** 1155 * Returns true if this instance is a temporary content provider. 1156 * @return true if this instance is a temporary content provider 1157 */ 1158 protected boolean isTemporary() { 1159 return false; 1160 } 1161 1162 /** 1163 * Returns the Binder object for this provider. 1164 * 1165 * @return the Binder object for this provider 1166 * @hide 1167 */ 1168 public IContentProvider getIContentProvider() { 1169 return mTransport; 1170 } 1171 1172 /** 1173 * Like {@link #attachInfo(Context, android.content.pm.ProviderInfo)}, but for use 1174 * when directly instantiating the provider for testing. 1175 * @hide 1176 */ 1177 public void attachInfoForTesting(Context context, ProviderInfo info) { 1178 attachInfo(context, info, true); 1179 } 1180 1181 /** 1182 * After being instantiated, this is called to tell the content provider 1183 * about itself. 1184 * 1185 * @param context The context this provider is running in 1186 * @param info Registered information about this content provider 1187 */ 1188 public void attachInfo(Context context, ProviderInfo info) { 1189 attachInfo(context, info, false); 1190 } 1191 1192 private void attachInfo(Context context, ProviderInfo info, boolean testing) { 1193 /* 1194 * We may be using AsyncTask from binder threads. Make it init here 1195 * so its static handler is on the main thread. 1196 */ 1197 AsyncTask.init(); 1198 1199 mNoPerms = testing; 1200 1201 /* 1202 * Only allow it to be set once, so after the content service gives 1203 * this to us clients can't change it. 1204 */ 1205 if (mContext == null) { 1206 mContext = context; 1207 mMyUid = Process.myUid(); 1208 if (info != null) { 1209 setReadPermission(info.readPermission); 1210 setWritePermission(info.writePermission); 1211 setPathPermissions(info.pathPermissions); 1212 mExported = info.exported; 1213 } 1214 ContentProvider.this.onCreate(); 1215 } 1216 } 1217 1218 /** 1219 * Override this to handle requests to perform a batch of operations, or the 1220 * default implementation will iterate over the operations and call 1221 * {@link ContentProviderOperation#apply} on each of them. 1222 * If all calls to {@link ContentProviderOperation#apply} succeed 1223 * then a {@link ContentProviderResult} array with as many 1224 * elements as there were operations will be returned. If any of the calls 1225 * fail, it is up to the implementation how many of the others take effect. 1226 * This method can be called from multiple threads, as described in 1227 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes 1228 * and Threads</a>. 1229 * 1230 * @param operations the operations to apply 1231 * @return the results of the applications 1232 * @throws OperationApplicationException thrown if any operation fails. 1233 * @see ContentProviderOperation#apply 1234 */ 1235 public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 1236 throws OperationApplicationException { 1237 final int numOperations = operations.size(); 1238 final ContentProviderResult[] results = new ContentProviderResult[numOperations]; 1239 for (int i = 0; i < numOperations; i++) { 1240 results[i] = operations.get(i).apply(this, results, i); 1241 } 1242 return results; 1243 } 1244 1245 /** 1246 * @hide 1247 * Front-end to {@link #call(String, String, android.os.Bundle)} that provides the name 1248 * of the calling package. 1249 */ 1250 public Bundle callFromPackage(String callingPackag, String method, String arg, Bundle extras) { 1251 return call(method, arg, extras); 1252 } 1253 1254 /** 1255 * Call a provider-defined method. This can be used to implement 1256 * interfaces that are cheaper and/or unnatural for a table-like 1257 * model. 1258 * 1259 * <p class="note"><strong>WARNING:</strong> The framework does no permission checking 1260 * on this entry into the content provider besides the basic ability for the application 1261 * to get access to the provider at all. For example, it has no idea whether the call 1262 * being executed may read or write data in the provider, so can't enforce those 1263 * individual permissions. Any implementation of this method <strong>must</strong> 1264 * do its own permission checks on incoming calls to make sure they are allowed.</p> 1265 * 1266 * @param method method name to call. Opaque to framework, but should not be {@code null}. 1267 * @param arg provider-defined String argument. May be {@code null}. 1268 * @param extras provider-defined Bundle argument. May be {@code null}. 1269 * @return provider-defined return value. May be {@code null}, which is also 1270 * the default for providers which don't implement any call methods. 1271 */ 1272 public Bundle call(String method, String arg, Bundle extras) { 1273 return null; 1274 } 1275 1276 /** 1277 * Implement this to shut down the ContentProvider instance. You can then 1278 * invoke this method in unit tests. 1279 * 1280 * <p> 1281 * Android normally handles ContentProvider startup and shutdown 1282 * automatically. You do not need to start up or shut down a 1283 * ContentProvider. When you invoke a test method on a ContentProvider, 1284 * however, a ContentProvider instance is started and keeps running after 1285 * the test finishes, even if a succeeding test instantiates another 1286 * ContentProvider. A conflict develops because the two instances are 1287 * usually running against the same underlying data source (for example, an 1288 * sqlite database). 1289 * </p> 1290 * <p> 1291 * Implementing shutDown() avoids this conflict by providing a way to 1292 * terminate the ContentProvider. This method can also prevent memory leaks 1293 * from multiple instantiations of the ContentProvider, and it can ensure 1294 * unit test isolation by allowing you to completely clean up the test 1295 * fixture before moving on to the next test. 1296 * </p> 1297 */ 1298 public void shutdown() { 1299 Log.w(TAG, "implement ContentProvider shutdown() to make sure all database " + 1300 "connections are gracefully shutdown"); 1301 } 1302 1303 /** 1304 * Print the Provider's state into the given stream. This gets invoked if 1305 * you run "adb shell dumpsys activity provider <provider_component_name>". 1306 * 1307 * @param fd The raw file descriptor that the dump is being sent to. 1308 * @param writer The PrintWriter to which you should dump your state. This will be 1309 * closed for you after you return. 1310 * @param args additional arguments to the dump request. 1311 */ 1312 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 1313 writer.println("nothing to dump"); 1314 } 1315 } 1316