ContentProvider.java revision 23fdaf6fb62a9b5154b2508916a21c678462c5d0
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 17package android.content; 18 19import android.content.pm.PackageManager; 20import android.content.pm.PathPermission; 21import android.content.pm.ProviderInfo; 22import android.content.res.AssetFileDescriptor; 23import android.content.res.Configuration; 24import android.database.Cursor; 25import android.database.CursorToBulkCursorAdaptor; 26import android.database.CursorWindow; 27import android.database.IBulkCursor; 28import android.database.IContentObserver; 29import android.database.SQLException; 30import android.net.Uri; 31import android.os.AsyncTask; 32import android.os.Binder; 33import android.os.Bundle; 34import android.os.ParcelFileDescriptor; 35import android.os.Process; 36import android.util.Log; 37 38import java.io.File; 39import java.io.FileNotFoundException; 40import java.io.IOException; 41import java.util.ArrayList; 42 43/** 44 * Content providers are one of the primary building blocks of Android applications, providing 45 * content to applications. They encapsulate data and provide it to applications through the single 46 * {@link ContentResolver} interface. A content provider is only required if you need to share 47 * data between multiple applications. For example, the contacts data is used by multiple 48 * applications and must be stored in a content provider. If you don't need to share data amongst 49 * multiple applications you can use a database directly via 50 * {@link android.database.sqlite.SQLiteDatabase}. 51 * 52 * <p>For more information, read <a href="{@docRoot}guide/topics/providers/content-providers.html">Content 53 * Providers</a>.</p> 54 * 55 * <p>When a request is made via 56 * a {@link ContentResolver} the system inspects the authority of the given URI and passes the 57 * request to the content provider registered with the authority. The content provider can interpret 58 * the rest of the URI however it wants. The {@link UriMatcher} class is helpful for parsing 59 * URIs.</p> 60 * 61 * <p>The primary methods that need to be implemented are: 62 * <ul> 63 * <li>{@link #onCreate} which is called to initialize the provider</li> 64 * <li>{@link #query} which returns data to the caller</li> 65 * <li>{@link #insert} which inserts new data into the content provider</li> 66 * <li>{@link #update} which updates existing data in the content provider</li> 67 * <li>{@link #delete} which deletes data from the content provider</li> 68 * <li>{@link #getType} which returns the MIME type of data in the content provider</li> 69 * </ul></p> 70 * 71 * <p class="caution">Data access methods (such as {@link #insert} and 72 * {@link #update}) may be called from many threads at once, and must be thread-safe. 73 * Other methods (such as {@link #onCreate}) are only called from the application 74 * main thread, and must avoid performing lengthy operations. See the method 75 * descriptions for their expected thread behavior.</p> 76 * 77 * <p>Requests to {@link ContentResolver} are automatically forwarded to the appropriate 78 * ContentProvider instance, so subclasses don't have to worry about the details of 79 * cross-process calls.</p> 80 */ 81public abstract class ContentProvider implements ComponentCallbacks { 82 private static final String TAG = "ContentProvider"; 83 84 /* 85 * Note: if you add methods to ContentProvider, you must add similar methods to 86 * MockContentProvider. 87 */ 88 89 private Context mContext = null; 90 private int mMyUid; 91 private String mReadPermission; 92 private String mWritePermission; 93 private PathPermission[] mPathPermissions; 94 95 private Transport mTransport = new Transport(); 96 97 /** 98 * Construct a ContentProvider instance. Content providers must be 99 * <a href="{@docRoot}guide/topics/manifest/provider-element.html">declared 100 * in the manifest</a>, accessed with {@link ContentResolver}, and created 101 * automatically by the system, so applications usually do not create 102 * ContentProvider instances directly. 103 * 104 * <p>At construction time, the object is uninitialized, and most fields and 105 * methods are unavailable. Subclasses should initialize themselves in 106 * {@link #onCreate}, not the constructor. 107 * 108 * <p>Content providers are created on the application main thread at 109 * application launch time. The constructor must not perform lengthy 110 * operations, or application startup will be delayed. 111 */ 112 public ContentProvider() { 113 } 114 115 /** 116 * Constructor just for mocking. 117 * 118 * @param context A Context object which should be some mock instance (like the 119 * instance of {@link android.test.mock.MockContext}). 120 * @param readPermission The read permision you want this instance should have in the 121 * test, which is available via {@link #getReadPermission()}. 122 * @param writePermission The write permission you want this instance should have 123 * in the test, which is available via {@link #getWritePermission()}. 124 * @param pathPermissions The PathPermissions you want this instance should have 125 * in the test, which is available via {@link #getPathPermissions()}. 126 * @hide 127 */ 128 public ContentProvider( 129 Context context, 130 String readPermission, 131 String writePermission, 132 PathPermission[] pathPermissions) { 133 mContext = context; 134 mReadPermission = readPermission; 135 mWritePermission = writePermission; 136 mPathPermissions = pathPermissions; 137 } 138 139 /** 140 * Given an IContentProvider, try to coerce it back to the real 141 * ContentProvider object if it is running in the local process. This can 142 * be used if you know you are running in the same process as a provider, 143 * and want to get direct access to its implementation details. Most 144 * clients should not nor have a reason to use it. 145 * 146 * @param abstractInterface The ContentProvider interface that is to be 147 * coerced. 148 * @return If the IContentProvider is non-null and local, returns its actual 149 * ContentProvider instance. Otherwise returns null. 150 * @hide 151 */ 152 public static ContentProvider coerceToLocalContentProvider( 153 IContentProvider abstractInterface) { 154 if (abstractInterface instanceof Transport) { 155 return ((Transport)abstractInterface).getContentProvider(); 156 } 157 return null; 158 } 159 160 /** 161 * Binder object that deals with remoting. 162 * 163 * @hide 164 */ 165 class Transport extends ContentProviderNative { 166 ContentProvider getContentProvider() { 167 return ContentProvider.this; 168 } 169 170 /** 171 * Remote version of a query, which returns an IBulkCursor. The bulk 172 * cursor should be wrapped with BulkCursorToCursorAdaptor before use. 173 */ 174 public IBulkCursor bulkQuery(Uri uri, String[] projection, 175 String selection, String[] selectionArgs, String sortOrder, 176 IContentObserver observer, CursorWindow window) { 177 enforceReadPermission(uri); 178 Cursor cursor = ContentProvider.this.query(uri, projection, 179 selection, selectionArgs, sortOrder); 180 if (cursor == null) { 181 return null; 182 } 183 return new CursorToBulkCursorAdaptor(cursor, observer, 184 ContentProvider.this.getClass().getName(), 185 hasWritePermission(uri), window); 186 } 187 188 public Cursor query(Uri uri, String[] projection, 189 String selection, String[] selectionArgs, String sortOrder) { 190 enforceReadPermission(uri); 191 return ContentProvider.this.query(uri, projection, selection, 192 selectionArgs, sortOrder); 193 } 194 195 public String getType(Uri uri) { 196 return ContentProvider.this.getType(uri); 197 } 198 199 200 public Uri insert(Uri uri, ContentValues initialValues) { 201 enforceWritePermission(uri); 202 return ContentProvider.this.insert(uri, initialValues); 203 } 204 205 public int bulkInsert(Uri uri, ContentValues[] initialValues) { 206 enforceWritePermission(uri); 207 return ContentProvider.this.bulkInsert(uri, initialValues); 208 } 209 210 public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 211 throws OperationApplicationException { 212 for (ContentProviderOperation operation : operations) { 213 if (operation.isReadOperation()) { 214 enforceReadPermission(operation.getUri()); 215 } 216 217 if (operation.isWriteOperation()) { 218 enforceWritePermission(operation.getUri()); 219 } 220 } 221 return ContentProvider.this.applyBatch(operations); 222 } 223 224 public int delete(Uri uri, String selection, String[] selectionArgs) { 225 enforceWritePermission(uri); 226 return ContentProvider.this.delete(uri, selection, selectionArgs); 227 } 228 229 public int update(Uri uri, ContentValues values, String selection, 230 String[] selectionArgs) { 231 enforceWritePermission(uri); 232 return ContentProvider.this.update(uri, values, selection, selectionArgs); 233 } 234 235 public ParcelFileDescriptor openFile(Uri uri, String mode) 236 throws FileNotFoundException { 237 if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri); 238 else enforceReadPermission(uri); 239 return ContentProvider.this.openFile(uri, mode); 240 } 241 242 public AssetFileDescriptor openAssetFile(Uri uri, String mode) 243 throws FileNotFoundException { 244 if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri); 245 else enforceReadPermission(uri); 246 return ContentProvider.this.openAssetFile(uri, mode); 247 } 248 249 /** 250 * @hide 251 */ 252 public Bundle call(String method, String request, Bundle args) { 253 return ContentProvider.this.call(method, request, args); 254 } 255 256 @Override 257 public String[] getStreamTypes(Uri uri, String mimeTypeFilter) { 258 return ContentProvider.this.getStreamTypes(uri, mimeTypeFilter); 259 } 260 261 @Override 262 public AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeType, Bundle opts) 263 throws FileNotFoundException { 264 enforceReadPermission(uri); 265 return ContentProvider.this.openTypedAssetFile(uri, mimeType, opts); 266 } 267 268 private void enforceReadPermission(Uri uri) { 269 final int uid = Binder.getCallingUid(); 270 if (uid == mMyUid) { 271 return; 272 } 273 274 final Context context = getContext(); 275 final String rperm = getReadPermission(); 276 final int pid = Binder.getCallingPid(); 277 if (rperm == null 278 || context.checkPermission(rperm, pid, uid) 279 == PackageManager.PERMISSION_GRANTED) { 280 return; 281 } 282 283 PathPermission[] pps = getPathPermissions(); 284 if (pps != null) { 285 final String path = uri.getPath(); 286 int i = pps.length; 287 while (i > 0) { 288 i--; 289 final PathPermission pp = pps[i]; 290 final String pprperm = pp.getReadPermission(); 291 if (pprperm != null && pp.match(path)) { 292 if (context.checkPermission(pprperm, pid, uid) 293 == PackageManager.PERMISSION_GRANTED) { 294 return; 295 } 296 } 297 } 298 } 299 300 if (context.checkUriPermission(uri, pid, uid, 301 Intent.FLAG_GRANT_READ_URI_PERMISSION) 302 == PackageManager.PERMISSION_GRANTED) { 303 return; 304 } 305 306 String msg = "Permission Denial: reading " 307 + ContentProvider.this.getClass().getName() 308 + " uri " + uri + " from pid=" + Binder.getCallingPid() 309 + ", uid=" + Binder.getCallingUid() 310 + " requires " + rperm; 311 throw new SecurityException(msg); 312 } 313 314 private boolean hasWritePermission(Uri uri) { 315 final int uid = Binder.getCallingUid(); 316 if (uid == mMyUid) { 317 return true; 318 } 319 320 final Context context = getContext(); 321 final String wperm = getWritePermission(); 322 final int pid = Binder.getCallingPid(); 323 if (wperm == null 324 || context.checkPermission(wperm, pid, uid) 325 == PackageManager.PERMISSION_GRANTED) { 326 return true; 327 } 328 329 PathPermission[] pps = getPathPermissions(); 330 if (pps != null) { 331 final String path = uri.getPath(); 332 int i = pps.length; 333 while (i > 0) { 334 i--; 335 final PathPermission pp = pps[i]; 336 final String ppwperm = pp.getWritePermission(); 337 if (ppwperm != null && pp.match(path)) { 338 if (context.checkPermission(ppwperm, pid, uid) 339 == PackageManager.PERMISSION_GRANTED) { 340 return true; 341 } 342 } 343 } 344 } 345 346 if (context.checkUriPermission(uri, pid, uid, 347 Intent.FLAG_GRANT_WRITE_URI_PERMISSION) 348 == PackageManager.PERMISSION_GRANTED) { 349 return true; 350 } 351 352 return false; 353 } 354 355 private void enforceWritePermission(Uri uri) { 356 if (hasWritePermission(uri)) { 357 return; 358 } 359 360 String msg = "Permission Denial: writing " 361 + ContentProvider.this.getClass().getName() 362 + " uri " + uri + " from pid=" + Binder.getCallingPid() 363 + ", uid=" + Binder.getCallingUid() 364 + " requires " + getWritePermission(); 365 throw new SecurityException(msg); 366 } 367 } 368 369 370 /** 371 * Retrieves the Context this provider is running in. Only available once 372 * {@link #onCreate} has been called -- this will return null in the 373 * constructor. 374 */ 375 public final Context getContext() { 376 return mContext; 377 } 378 379 /** 380 * Change the permission required to read data from the content 381 * provider. This is normally set for you from its manifest information 382 * when the provider is first created. 383 * 384 * @param permission Name of the permission required for read-only access. 385 */ 386 protected final void setReadPermission(String permission) { 387 mReadPermission = permission; 388 } 389 390 /** 391 * Return the name of the permission required for read-only access to 392 * this content provider. This method can be called from multiple 393 * threads, as described in 394 * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals: 395 * Processes and Threads</a>. 396 */ 397 public final String getReadPermission() { 398 return mReadPermission; 399 } 400 401 /** 402 * Change the permission required to read and write data in the content 403 * provider. This is normally set for you from its manifest information 404 * when the provider is first created. 405 * 406 * @param permission Name of the permission required for read/write access. 407 */ 408 protected final void setWritePermission(String permission) { 409 mWritePermission = permission; 410 } 411 412 /** 413 * Return the name of the permission required for read/write access to 414 * this content provider. This method can be called from multiple 415 * threads, as described in 416 * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals: 417 * Processes and Threads</a>. 418 */ 419 public final String getWritePermission() { 420 return mWritePermission; 421 } 422 423 /** 424 * Change the path-based permission required to read and/or write data in 425 * the content provider. This is normally set for you from its manifest 426 * information when the provider is first created. 427 * 428 * @param permissions Array of path permission descriptions. 429 */ 430 protected final void setPathPermissions(PathPermission[] permissions) { 431 mPathPermissions = permissions; 432 } 433 434 /** 435 * Return the path-based permissions required for read and/or write access to 436 * this content provider. This method can be called from multiple 437 * threads, as described in 438 * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals: 439 * Processes and Threads</a>. 440 */ 441 public final PathPermission[] getPathPermissions() { 442 return mPathPermissions; 443 } 444 445 /** 446 * Implement this to initialize your content provider on startup. 447 * This method is called for all registered content providers on the 448 * application main thread at application launch time. It must not perform 449 * lengthy operations, or application startup will be delayed. 450 * 451 * <p>You should defer nontrivial initialization (such as opening, 452 * upgrading, and scanning databases) until the content provider is used 453 * (via {@link #query}, {@link #insert}, etc). Deferred initialization 454 * keeps application startup fast, avoids unnecessary work if the provider 455 * turns out not to be needed, and stops database errors (such as a full 456 * disk) from halting application launch. 457 * 458 * <p>If you use SQLite, {@link android.database.sqlite.SQLiteOpenHelper} 459 * is a helpful utility class that makes it easy to manage databases, 460 * and will automatically defer opening until first use. If you do use 461 * SQLiteOpenHelper, make sure to avoid calling 462 * {@link android.database.sqlite.SQLiteOpenHelper#getReadableDatabase} or 463 * {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase} 464 * from this method. (Instead, override 465 * {@link android.database.sqlite.SQLiteOpenHelper#onOpen} to initialize the 466 * database when it is first opened.) 467 * 468 * @return true if the provider was successfully loaded, false otherwise 469 */ 470 public abstract boolean onCreate(); 471 472 /** 473 * {@inheritDoc} 474 * This method is always called on the application main thread, and must 475 * not perform lengthy operations. 476 * 477 * <p>The default content provider implementation does nothing. 478 * Override this method to take appropriate action. 479 * (Content providers do not usually care about things like screen 480 * orientation, but may want to know about locale changes.) 481 */ 482 public void onConfigurationChanged(Configuration newConfig) { 483 } 484 485 /** 486 * {@inheritDoc} 487 * This method is always called on the application main thread, and must 488 * not perform lengthy operations. 489 * 490 * <p>The default content provider implementation does nothing. 491 * Subclasses may override this method to take appropriate action. 492 */ 493 public void onLowMemory() { 494 } 495 496 /** 497 * Implement this to handle query requests from clients. 498 * This method can be called from multiple threads, as described in 499 * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals: 500 * Processes and Threads</a>. 501 * <p> 502 * Example client call:<p> 503 * <pre>// Request a specific record. 504 * Cursor managedCursor = managedQuery( 505 ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2), 506 projection, // Which columns to return. 507 null, // WHERE clause. 508 null, // WHERE clause value substitution 509 People.NAME + " ASC"); // Sort order.</pre> 510 * Example implementation:<p> 511 * <pre>// SQLiteQueryBuilder is a helper class that creates the 512 // proper SQL syntax for us. 513 SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder(); 514 515 // Set the table we're querying. 516 qBuilder.setTables(DATABASE_TABLE_NAME); 517 518 // If the query ends in a specific record number, we're 519 // being asked for a specific record, so set the 520 // WHERE clause in our query. 521 if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){ 522 qBuilder.appendWhere("_id=" + uri.getPathLeafId()); 523 } 524 525 // Make the query. 526 Cursor c = qBuilder.query(mDb, 527 projection, 528 selection, 529 selectionArgs, 530 groupBy, 531 having, 532 sortOrder); 533 c.setNotificationUri(getContext().getContentResolver(), uri); 534 return c;</pre> 535 * 536 * @param uri The URI to query. This will be the full URI sent by the client; 537 * if the client is requesting a specific record, the URI will end in a record number 538 * that the implementation should parse and add to a WHERE or HAVING clause, specifying 539 * that _id value. 540 * @param projection The list of columns to put into the cursor. If 541 * null all columns are included. 542 * @param selection A selection criteria to apply when filtering rows. 543 * If null then all rows are included. 544 * @param selectionArgs You may include ?s in selection, which will be replaced by 545 * the values from selectionArgs, in order that they appear in the selection. 546 * The values will be bound as Strings. 547 * @param sortOrder How the rows in the cursor should be sorted. 548 * If null then the provider is free to define the sort order. 549 * @return a Cursor or null. 550 */ 551 public abstract Cursor query(Uri uri, String[] projection, 552 String selection, String[] selectionArgs, String sortOrder); 553 554 /** 555 * Implement this to handle requests for the MIME type of the data at the 556 * given URI. The returned MIME type should start with 557 * <code>vnd.android.cursor.item</code> for a single record, 558 * or <code>vnd.android.cursor.dir/</code> for multiple items. 559 * This method can be called from multiple threads, as described in 560 * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals: 561 * Processes and Threads</a>. 562 * 563 * @param uri the URI to query. 564 * @return a MIME type string, or null if there is no type. 565 */ 566 public abstract String getType(Uri uri); 567 568 /** 569 * Implement this to handle requests to insert a new row. 570 * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()} 571 * after inserting. 572 * This method can be called from multiple threads, as described in 573 * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals: 574 * Processes and Threads</a>. 575 * @param uri The content:// URI of the insertion request. 576 * @param values A set of column_name/value pairs to add to the database. 577 * @return The URI for the newly inserted item. 578 */ 579 public abstract Uri insert(Uri uri, ContentValues values); 580 581 /** 582 * Override this to handle requests to insert a set of new rows, or the 583 * default implementation will iterate over the values and call 584 * {@link #insert} on each of them. 585 * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()} 586 * after inserting. 587 * This method can be called from multiple threads, as described in 588 * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals: 589 * Processes and Threads</a>. 590 * 591 * @param uri The content:// URI of the insertion request. 592 * @param values An array of sets of column_name/value pairs to add to the database. 593 * @return The number of values that were inserted. 594 */ 595 public int bulkInsert(Uri uri, ContentValues[] values) { 596 int numValues = values.length; 597 for (int i = 0; i < numValues; i++) { 598 insert(uri, values[i]); 599 } 600 return numValues; 601 } 602 603 /** 604 * Implement this to handle requests to delete one or more rows. 605 * The implementation should apply the selection clause when performing 606 * deletion, allowing the operation to affect multiple rows in a directory. 607 * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyDelete()} 608 * after deleting. 609 * This method can be called from multiple threads, as described in 610 * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals: 611 * Processes and Threads</a>. 612 * 613 * <p>The implementation is responsible for parsing out a row ID at the end 614 * of the URI, if a specific row is being deleted. That is, the client would 615 * pass in <code>content://contacts/people/22</code> and the implementation is 616 * responsible for parsing the record number (22) when creating a SQL statement. 617 * 618 * @param uri The full URI to query, including a row ID (if a specific record is requested). 619 * @param selection An optional restriction to apply to rows when deleting. 620 * @return The number of rows affected. 621 * @throws SQLException 622 */ 623 public abstract int delete(Uri uri, String selection, String[] selectionArgs); 624 625 /** 626 * Implement this to handle requests to update one or more rows. 627 * The implementation should update all rows matching the selection 628 * to set the columns according to the provided values map. 629 * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()} 630 * after updating. 631 * This method can be called from multiple threads, as described in 632 * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals: 633 * Processes and Threads</a>. 634 * 635 * @param uri The URI to query. This can potentially have a record ID if this 636 * is an update request for a specific record. 637 * @param values A Bundle mapping from column names to new column values (NULL is a 638 * valid value). 639 * @param selection An optional filter to match rows to update. 640 * @return the number of rows affected. 641 */ 642 public abstract int update(Uri uri, ContentValues values, String selection, 643 String[] selectionArgs); 644 645 /** 646 * Override this to handle requests to open a file blob. 647 * The default implementation always throws {@link FileNotFoundException}. 648 * This method can be called from multiple threads, as described in 649 * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals: 650 * Processes and Threads</a>. 651 * 652 * <p>This method returns a ParcelFileDescriptor, which is returned directly 653 * to the caller. This way large data (such as images and documents) can be 654 * returned without copying the content. 655 * 656 * <p>The returned ParcelFileDescriptor is owned by the caller, so it is 657 * their responsibility to close it when done. That is, the implementation 658 * of this method should create a new ParcelFileDescriptor for each call. 659 * 660 * @param uri The URI whose file is to be opened. 661 * @param mode Access mode for the file. May be "r" for read-only access, 662 * "rw" for read and write access, or "rwt" for read and write access 663 * that truncates any existing file. 664 * 665 * @return Returns a new ParcelFileDescriptor which you can use to access 666 * the file. 667 * 668 * @throws FileNotFoundException Throws FileNotFoundException if there is 669 * no file associated with the given URI or the mode is invalid. 670 * @throws SecurityException Throws SecurityException if the caller does 671 * not have permission to access the file. 672 * 673 * @see #openAssetFile(Uri, String) 674 * @see #openFileHelper(Uri, String) 675 */ 676 public ParcelFileDescriptor openFile(Uri uri, String mode) 677 throws FileNotFoundException { 678 throw new FileNotFoundException("No files supported by provider at " 679 + uri); 680 } 681 682 /** 683 * This is like {@link #openFile}, but can be implemented by providers 684 * that need to be able to return sub-sections of files, often assets 685 * inside of their .apk. 686 * This method can be called from multiple threads, as described in 687 * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals: 688 * Processes and Threads</a>. 689 * 690 * <p>If you implement this, your clients must be able to deal with such 691 * file slices, either directly with 692 * {@link ContentResolver#openAssetFileDescriptor}, or by using the higher-level 693 * {@link ContentResolver#openInputStream ContentResolver.openInputStream} 694 * or {@link ContentResolver#openOutputStream ContentResolver.openOutputStream} 695 * methods. 696 * 697 * <p class="note">If you are implementing this to return a full file, you 698 * should create the AssetFileDescriptor with 699 * {@link AssetFileDescriptor#UNKNOWN_LENGTH} to be compatible with 700 * applications that can not handle sub-sections of files.</p> 701 * 702 * @param uri The URI whose file is to be opened. 703 * @param mode Access mode for the file. May be "r" for read-only access, 704 * "w" for write-only access (erasing whatever data is currently in 705 * the file), "wa" for write-only access to append to any existing data, 706 * "rw" for read and write access on any existing data, and "rwt" for read 707 * and write access that truncates any existing file. 708 * 709 * @return Returns a new AssetFileDescriptor which you can use to access 710 * the file. 711 * 712 * @throws FileNotFoundException Throws FileNotFoundException if there is 713 * no file associated with the given URI or the mode is invalid. 714 * @throws SecurityException Throws SecurityException if the caller does 715 * not have permission to access the file. 716 * 717 * @see #openFile(Uri, String) 718 * @see #openFileHelper(Uri, String) 719 */ 720 public AssetFileDescriptor openAssetFile(Uri uri, String mode) 721 throws FileNotFoundException { 722 ParcelFileDescriptor fd = openFile(uri, mode); 723 return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null; 724 } 725 726 /** 727 * Convenience for subclasses that wish to implement {@link #openFile} 728 * by looking up a column named "_data" at the given URI. 729 * 730 * @param uri The URI to be opened. 731 * @param mode The file mode. May be "r" for read-only access, 732 * "w" for write-only access (erasing whatever data is currently in 733 * the file), "wa" for write-only access to append to any existing data, 734 * "rw" for read and write access on any existing data, and "rwt" for read 735 * and write access that truncates any existing file. 736 * 737 * @return Returns a new ParcelFileDescriptor that can be used by the 738 * client to access the file. 739 */ 740 protected final ParcelFileDescriptor openFileHelper(Uri uri, 741 String mode) throws FileNotFoundException { 742 Cursor c = query(uri, new String[]{"_data"}, null, null, null); 743 int count = (c != null) ? c.getCount() : 0; 744 if (count != 1) { 745 // If there is not exactly one result, throw an appropriate 746 // exception. 747 if (c != null) { 748 c.close(); 749 } 750 if (count == 0) { 751 throw new FileNotFoundException("No entry for " + uri); 752 } 753 throw new FileNotFoundException("Multiple items at " + uri); 754 } 755 756 c.moveToFirst(); 757 int i = c.getColumnIndex("_data"); 758 String path = (i >= 0 ? c.getString(i) : null); 759 c.close(); 760 if (path == null) { 761 throw new FileNotFoundException("Column _data not found."); 762 } 763 764 int modeBits = ContentResolver.modeToMode(uri, mode); 765 return ParcelFileDescriptor.open(new File(path), modeBits); 766 } 767 768 /** 769 * Helper to compare two MIME types, where one may be a pattern. 770 * @param concreteType A fully-specified MIME type. 771 * @param desiredType A desired MIME type that may be a pattern such as *\/*. 772 * @return Returns true if the two MIME types match. 773 */ 774 public static boolean compareMimeTypes(String concreteType, String desiredType) { 775 final int typeLength = desiredType.length(); 776 if (typeLength == 3 && desiredType.equals("*/*")) { 777 return true; 778 } 779 780 final int slashpos = desiredType.indexOf('/'); 781 if (slashpos > 0) { 782 if (typeLength == slashpos+2 && desiredType.charAt(slashpos+1) == '*') { 783 if (desiredType.regionMatches(0, concreteType, 0, slashpos+1)) { 784 return true; 785 } 786 } else if (desiredType.equals(concreteType)) { 787 return true; 788 } 789 } 790 791 return false; 792 } 793 794 /** 795 * Called by a client to determine the types of data streams that this 796 * content provider supports for the given URI. The default implementation 797 * returns null, meaning no types. If your content provider stores data 798 * of a particular type, return that MIME type if it matches the given 799 * mimeTypeFilter. If it can perform type conversions, return an array 800 * of all supported MIME types that match mimeTypeFilter. 801 * 802 * @param uri The data in the content provider being queried. 803 * @param mimeTypeFilter The type of data the client desires. May be 804 * a pattern, such as *\/* to retrieve all possible data types. 805 * @returns Returns null if there are no possible data streams for the 806 * given mimeTypeFilter. Otherwise returns an array of all available 807 * concrete MIME types. 808 * 809 * @see #getType(Uri) 810 * @see #openTypedAssetFile(Uri, String, Bundle) 811 * @see #compareMimeTypes(String, String) 812 */ 813 public String[] getStreamTypes(Uri uri, String mimeTypeFilter) { 814 return null; 815 } 816 817 /** 818 * Called by a client to open a read-only stream containing data of a 819 * particular MIME type. This is like {@link #openAssetFile(Uri, String)}, 820 * except the file can only be read-only and the content provider may 821 * perform data conversions to generate data of the desired type. 822 * 823 * <p>The default implementation compares the given mimeType against the 824 * result of {@link #getType(Uri)} and, if the match, simple calls 825 * {@link #openAssetFile(Uri, String)}. 826 * 827 * <p>See {@link ClippedData} for examples of the use and implementation 828 * of this method. 829 * 830 * @param uri The data in the content provider being queried. 831 * @param mimeTypeFilter The type of data the client desires. May be 832 * a pattern, such as *\/*, if the caller does not have specific type 833 * requirements; in this case the content provider will pick its best 834 * type matching the pattern. 835 * @param opts Additional options from the client. The definitions of 836 * these are specific to the content provider being called. 837 * 838 * @return Returns a new AssetFileDescriptor from which the client can 839 * read data of the desired type. 840 * 841 * @throws FileNotFoundException Throws FileNotFoundException if there is 842 * no file associated with the given URI or the mode is invalid. 843 * @throws SecurityException Throws SecurityException if the caller does 844 * not have permission to access the data. 845 * @throws IllegalArgumentException Throws IllegalArgumentException if the 846 * content provider does not support the requested MIME type. 847 * 848 * @see #getStreamTypes(Uri, String) 849 * @see #openAssetFile(Uri, String) 850 * @see #compareMimeTypes(String, String) 851 */ 852 public AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts) 853 throws FileNotFoundException { 854 String baseType = getType(uri); 855 if (baseType != null && compareMimeTypes(baseType, mimeTypeFilter)) { 856 return openAssetFile(uri, "r"); 857 } 858 throw new FileNotFoundException("Can't open " + uri + " as type " + mimeTypeFilter); 859 } 860 861 /** 862 * Interface to write a stream of data to a pipe. Use with 863 * {@link ContentProvider#openPipeHelper}. 864 */ 865 public interface PipeDataWriter<T> { 866 /** 867 * Called from a background thread to stream data out to a pipe. 868 * Note that the pipe is blocking, so this thread can block on 869 * writes for an arbitrary amount of time if the client is slow 870 * at reading. 871 * 872 * @param output The pipe where data should be written. This will be 873 * closed for you upon returning from this function. 874 * @param uri The URI whose data is to be written. 875 * @param mimeType The desired type of data to be written. 876 * @param opts Options supplied by caller. 877 * @param args Your own custom arguments. 878 */ 879 public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String mimeType, 880 Bundle opts, T args); 881 } 882 883 /** 884 * A helper function for implementing {@link #openTypedAssetFile}, for 885 * creating a data pipe and background thread allowing you to stream 886 * generated data back to the client. This function returns a new 887 * ParcelFileDescriptor that should be returned to the caller (the caller 888 * is responsible for closing it). 889 * 890 * @param uri The URI whose data is to be written. 891 * @param mimeType The desired type of data to be written. 892 * @param opts Options supplied by caller. 893 * @param args Your own custom arguments. 894 * @param func Interface implementing the function that will actually 895 * stream the data. 896 * @return Returns a new ParcelFileDescriptor holding the read side of 897 * the pipe. This should be returned to the caller for reading; the caller 898 * is responsible for closing it when done. 899 */ 900 public <T> ParcelFileDescriptor openPipeHelper(final Uri uri, final String mimeType, 901 final Bundle opts, final T args, final PipeDataWriter<T> func) 902 throws FileNotFoundException { 903 try { 904 final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe(); 905 906 AsyncTask<Object, Object, Object> task = new AsyncTask<Object, Object, Object>() { 907 @Override 908 protected Object doInBackground(Object... params) { 909 func.writeDataToPipe(fds[1], uri, mimeType, opts, args); 910 try { 911 fds[1].close(); 912 } catch (IOException e) { 913 Log.w(TAG, "Failure closing pipe", e); 914 } 915 return null; 916 } 917 }; 918 task.execute((Object[])null); 919 920 return fds[0]; 921 } catch (IOException e) { 922 throw new FileNotFoundException("failure making pipe"); 923 } 924 } 925 926 /** 927 * Returns true if this instance is a temporary content provider. 928 * @return true if this instance is a temporary content provider 929 */ 930 protected boolean isTemporary() { 931 return false; 932 } 933 934 /** 935 * Returns the Binder object for this provider. 936 * 937 * @return the Binder object for this provider 938 * @hide 939 */ 940 public IContentProvider getIContentProvider() { 941 return mTransport; 942 } 943 944 /** 945 * After being instantiated, this is called to tell the content provider 946 * about itself. 947 * 948 * @param context The context this provider is running in 949 * @param info Registered information about this content provider 950 */ 951 public void attachInfo(Context context, ProviderInfo info) { 952 /* 953 * We may be using AsyncTask from binder threads. Make it init here 954 * so its static handler is on the main thread. 955 */ 956 AsyncTask.init(); 957 958 /* 959 * Only allow it to be set once, so after the content service gives 960 * this to us clients can't change it. 961 */ 962 if (mContext == null) { 963 mContext = context; 964 mMyUid = Process.myUid(); 965 if (info != null) { 966 setReadPermission(info.readPermission); 967 setWritePermission(info.writePermission); 968 setPathPermissions(info.pathPermissions); 969 } 970 ContentProvider.this.onCreate(); 971 } 972 } 973 974 /** 975 * Override this to handle requests to perform a batch of operations, or the 976 * default implementation will iterate over the operations and call 977 * {@link ContentProviderOperation#apply} on each of them. 978 * If all calls to {@link ContentProviderOperation#apply} succeed 979 * then a {@link ContentProviderResult} array with as many 980 * elements as there were operations will be returned. If any of the calls 981 * fail, it is up to the implementation how many of the others take effect. 982 * This method can be called from multiple threads, as described in 983 * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals: 984 * Processes and Threads</a>. 985 * 986 * @param operations the operations to apply 987 * @return the results of the applications 988 * @throws OperationApplicationException thrown if any operation fails. 989 * @see ContentProviderOperation#apply 990 */ 991 public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 992 throws OperationApplicationException { 993 final int numOperations = operations.size(); 994 final ContentProviderResult[] results = new ContentProviderResult[numOperations]; 995 for (int i = 0; i < numOperations; i++) { 996 results[i] = operations.get(i).apply(this, results, i); 997 } 998 return results; 999 } 1000 1001 /** 1002 * @hide -- until interface has proven itself 1003 * 1004 * Call an provider-defined method. This can be used to implement 1005 * interfaces that are cheaper than using a Cursor. 1006 * 1007 * @param method Method name to call. Opaque to framework. 1008 * @param request Nullable String argument passed to method. 1009 * @param args Nullable Bundle argument passed to method. 1010 */ 1011 public Bundle call(String method, String request, Bundle args) { 1012 return null; 1013 } 1014 1015 /** 1016 * Shuts down this instance of the ContentProvider. It is useful when writing tests that use 1017 * the ContentProvider. 1018 * <p> 1019 * If a unittest starts the ContentProvider in its test(..() methods, it could run into sqlite 1020 * errors "disk I/O error" or "corruption" in the following scenario: 1021 * <ul> 1022 * <li>Say, there are 2 test methods in the unittest</li> 1023 * <li>test1() (or setUp()) causes ContentProvider object to be initialized and 1024 * assume it opens a database connection to "foo.db"</li> 1025 * <li>est1() completes and test2() starts</li> 1026 * <li>During the execution of test2() there will be 2 connections to "foo.db"</li> 1027 * <li>Different threads in the ContentProvider may have one of these two connection 1028 * handles. This is not a problem per se</li> 1029 * <li>But if the two threads with 2 database connections don't interact correctly, 1030 * there could be unexpected errors from sqlite</li> 1031 * <li>Some of those unexpected errros are "disk I/O error" or "corruption" error</li> 1032 * <li>Common practice in tearDown() is to delete test directory (and the database files)</li> 1033 * <li>If this is done while some threads are still holding unclosed database connections, 1034 * sqlite quite easily gets into corruption and disk I/O errors</li> 1035 * </ul> 1036 * <p> 1037 * tearDown() in the unittests should call this method to have ContentProvider gracefully 1038 * shutdown all database connections. 1039 */ 1040 public void shutdown() { 1041 Log.w(TAG, "implement ContentProvider shutdown() to make sure all database " + 1042 "connections are gracefully shutdown"); 1043 } 1044} 1045