ContentResolver.java revision bd3b902567b09379e1b62c60b3319ad82102efad
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.accounts.Account; 20import android.app.ActivityManagerNative; 21import android.app.ActivityThread; 22import android.app.AppGlobals; 23import android.content.pm.PackageManager.NameNotFoundException; 24import android.content.res.AssetFileDescriptor; 25import android.content.res.Resources; 26import android.database.ContentObserver; 27import android.database.CrossProcessCursorWrapper; 28import android.database.Cursor; 29import android.database.IContentObserver; 30import android.net.Uri; 31import android.os.Bundle; 32import android.os.CancellationSignal; 33import android.os.DeadObjectException; 34import android.os.IBinder; 35import android.os.ICancellationSignal; 36import android.os.OperationCanceledException; 37import android.os.ParcelFileDescriptor; 38import android.os.RemoteException; 39import android.os.ServiceManager; 40import android.os.SystemClock; 41import android.os.UserHandle; 42import android.text.TextUtils; 43import android.util.EventLog; 44import android.util.Log; 45 46import dalvik.system.CloseGuard; 47 48import java.io.File; 49import java.io.FileInputStream; 50import java.io.FileNotFoundException; 51import java.io.IOException; 52import java.io.InputStream; 53import java.io.OutputStream; 54import java.util.ArrayList; 55import java.util.List; 56import java.util.Random; 57 58/** 59 * This class provides applications access to the content model. 60 * 61 * <div class="special reference"> 62 * <h3>Developer Guides</h3> 63 * <p>For more information about using a ContentResolver with content providers, read the 64 * <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> 65 * developer guide.</p> 66 */ 67public abstract class ContentResolver { 68 /** 69 * @deprecated instead use 70 * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)} 71 */ 72 @Deprecated 73 public static final String SYNC_EXTRAS_ACCOUNT = "account"; 74 75 /** 76 * If this extra is set to true, the sync request will be scheduled 77 * at the front of the sync request queue and without any delay 78 */ 79 public static final String SYNC_EXTRAS_EXPEDITED = "expedited"; 80 81 /** 82 * @deprecated instead use 83 * {@link #SYNC_EXTRAS_MANUAL} 84 */ 85 @Deprecated 86 public static final String SYNC_EXTRAS_FORCE = "force"; 87 88 /** 89 * If this extra is set to true then the sync settings (like getSyncAutomatically()) 90 * are ignored by the sync scheduler. 91 */ 92 public static final String SYNC_EXTRAS_IGNORE_SETTINGS = "ignore_settings"; 93 94 /** 95 * If this extra is set to true then any backoffs for the initial attempt (e.g. due to retries) 96 * are ignored by the sync scheduler. If this request fails and gets rescheduled then the 97 * retries will still honor the backoff. 98 */ 99 public static final String SYNC_EXTRAS_IGNORE_BACKOFF = "ignore_backoff"; 100 101 /** 102 * If this extra is set to true then the request will not be retried if it fails. 103 */ 104 public static final String SYNC_EXTRAS_DO_NOT_RETRY = "do_not_retry"; 105 106 /** 107 * Setting this extra is the equivalent of setting both {@link #SYNC_EXTRAS_IGNORE_SETTINGS} 108 * and {@link #SYNC_EXTRAS_IGNORE_BACKOFF} 109 */ 110 public static final String SYNC_EXTRAS_MANUAL = "force"; 111 112 /** 113 * Indicates that this sync is intended to only upload local changes to the server. 114 * For example, this will be set to true if the sync is initiated by a call to 115 * {@link ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)} 116 */ 117 public static final String SYNC_EXTRAS_UPLOAD = "upload"; 118 119 /** 120 * Indicates that the sync adapter should proceed with the delete operations, 121 * even if it determines that there are too many. 122 * See {@link SyncResult#tooManyDeletions} 123 */ 124 public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override"; 125 126 /** 127 * Indicates that the sync adapter should not proceed with the delete operations, 128 * if it determines that there are too many. 129 * See {@link SyncResult#tooManyDeletions} 130 */ 131 public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions"; 132 133 /* Extensions to API. TODO: Not clear if we will keep these as public flags. */ 134 /** {@hide} User-specified flag for expected upload size. */ 135 public static final String SYNC_EXTRAS_EXPECTED_UPLOAD = "expected_upload"; 136 137 /** {@hide} User-specified flag for expected download size. */ 138 public static final String SYNC_EXTRAS_EXPECTED_DOWNLOAD = "expected_download"; 139 140 /** {@hide} Priority of this sync with respect to other syncs scheduled for this application. */ 141 public static final String SYNC_EXTRAS_PRIORITY = "sync_priority"; 142 143 /** {@hide} Flag to allow sync to occur on metered network. */ 144 public static final String SYNC_EXTRAS_ALLOW_METERED = "allow_metered"; 145 146 /** 147 * Set by the SyncManager to request that the SyncAdapter initialize itself for 148 * the given account/authority pair. One required initialization step is to 149 * ensure that {@link #setIsSyncable(android.accounts.Account, String, int)} has been 150 * called with a >= 0 value. When this flag is set the SyncAdapter does not need to 151 * do a full sync, though it is allowed to do so. 152 */ 153 public static final String SYNC_EXTRAS_INITIALIZE = "initialize"; 154 155 /** @hide */ 156 public static final Intent ACTION_SYNC_CONN_STATUS_CHANGED = 157 new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED"); 158 159 public static final String SCHEME_CONTENT = "content"; 160 public static final String SCHEME_ANDROID_RESOURCE = "android.resource"; 161 public static final String SCHEME_FILE = "file"; 162 163 /** 164 * This is the Android platform's base MIME type for a content: URI 165 * containing a Cursor of a single item. Applications should use this 166 * as the base type along with their own sub-type of their content: URIs 167 * that represent a particular item. For example, hypothetical IMAP email 168 * client may have a URI 169 * <code>content://com.company.provider.imap/inbox/1</code> for a particular 170 * message in the inbox, whose MIME type would be reported as 171 * <code>CURSOR_ITEM_BASE_TYPE + "/vnd.company.imap-msg"</code> 172 * 173 * <p>Compare with {@link #CURSOR_DIR_BASE_TYPE}. 174 */ 175 public static final String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item"; 176 177 /** 178 * This is the Android platform's base MIME type for a content: URI 179 * containing a Cursor of zero or more items. Applications should use this 180 * as the base type along with their own sub-type of their content: URIs 181 * that represent a directory of items. For example, hypothetical IMAP email 182 * client may have a URI 183 * <code>content://com.company.provider.imap/inbox</code> for all of the 184 * messages in its inbox, whose MIME type would be reported as 185 * <code>CURSOR_DIR_BASE_TYPE + "/vnd.company.imap-msg"</code> 186 * 187 * <p>Note how the base MIME type varies between this and 188 * {@link #CURSOR_ITEM_BASE_TYPE} depending on whether there is 189 * one single item or multiple items in the data set, while the sub-type 190 * remains the same because in either case the data structure contained 191 * in the cursor is the same. 192 */ 193 public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir"; 194 195 /** @hide */ 196 public static final int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1; 197 /** @hide */ 198 public static final int SYNC_ERROR_AUTHENTICATION = 2; 199 /** @hide */ 200 public static final int SYNC_ERROR_IO = 3; 201 /** @hide */ 202 public static final int SYNC_ERROR_PARSE = 4; 203 /** @hide */ 204 public static final int SYNC_ERROR_CONFLICT = 5; 205 /** @hide */ 206 public static final int SYNC_ERROR_TOO_MANY_DELETIONS = 6; 207 /** @hide */ 208 public static final int SYNC_ERROR_TOO_MANY_RETRIES = 7; 209 /** @hide */ 210 public static final int SYNC_ERROR_INTERNAL = 8; 211 212 private static final String[] SYNC_ERROR_NAMES = new String[] { 213 "already-in-progress", 214 "authentication-error", 215 "io-error", 216 "parse-error", 217 "conflict", 218 "too-many-deletions", 219 "too-many-retries", 220 "internal-error", 221 }; 222 223 /** @hide */ 224 public static String syncErrorToString(int error) { 225 if (error < 1 || error > SYNC_ERROR_NAMES.length) { 226 return String.valueOf(error); 227 } 228 return SYNC_ERROR_NAMES[error - 1]; 229 } 230 231 /** @hide */ 232 public static int syncErrorStringToInt(String error) { 233 for (int i = 0, n = SYNC_ERROR_NAMES.length; i < n; i++) { 234 if (SYNC_ERROR_NAMES[i].equals(error)) { 235 return i + 1; 236 } 237 } 238 if (error != null) { 239 try { 240 return Integer.parseInt(error); 241 } catch (NumberFormatException e) { 242 Log.d(TAG, "error parsing sync error: " + error); 243 } 244 } 245 return 0; 246 } 247 248 public static final int SYNC_OBSERVER_TYPE_SETTINGS = 1<<0; 249 public static final int SYNC_OBSERVER_TYPE_PENDING = 1<<1; 250 public static final int SYNC_OBSERVER_TYPE_ACTIVE = 1<<2; 251 /** @hide */ 252 public static final int SYNC_OBSERVER_TYPE_STATUS = 1<<3; 253 /** @hide */ 254 public static final int SYNC_OBSERVER_TYPE_ALL = 0x7fffffff; 255 256 // Always log queries which take 500ms+; shorter queries are 257 // sampled accordingly. 258 private static final boolean ENABLE_CONTENT_SAMPLE = false; 259 private static final int SLOW_THRESHOLD_MILLIS = 500; 260 private final Random mRandom = new Random(); // guarded by itself 261 262 public ContentResolver(Context context) { 263 mContext = context != null ? context : ActivityThread.currentApplication(); 264 mPackageName = mContext.getBasePackageName(); 265 } 266 267 /** @hide */ 268 protected abstract IContentProvider acquireProvider(Context c, String name); 269 /** Providing a default implementation of this, to avoid having to change 270 * a lot of other things, but implementations of ContentResolver should 271 * implement it. @hide */ 272 protected IContentProvider acquireExistingProvider(Context c, String name) { 273 return acquireProvider(c, name); 274 } 275 /** @hide */ 276 public abstract boolean releaseProvider(IContentProvider icp); 277 /** @hide */ 278 protected abstract IContentProvider acquireUnstableProvider(Context c, String name); 279 /** @hide */ 280 public abstract boolean releaseUnstableProvider(IContentProvider icp); 281 /** @hide */ 282 public abstract void unstableProviderDied(IContentProvider icp); 283 284 /** 285 * Return the MIME type of the given content URL. 286 * 287 * @param url A Uri identifying content (either a list or specific type), 288 * using the content:// scheme. 289 * @return A MIME type for the content, or null if the URL is invalid or the type is unknown 290 */ 291 public final String getType(Uri url) { 292 // XXX would like to have an acquireExistingUnstableProvider for this. 293 IContentProvider provider = acquireExistingProvider(url); 294 if (provider != null) { 295 try { 296 return provider.getType(url); 297 } catch (RemoteException e) { 298 return null; 299 } catch (java.lang.Exception e) { 300 Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")"); 301 return null; 302 } finally { 303 releaseProvider(provider); 304 } 305 } 306 307 if (!SCHEME_CONTENT.equals(url.getScheme())) { 308 return null; 309 } 310 311 try { 312 String type = ActivityManagerNative.getDefault().getProviderMimeType( 313 url, UserHandle.myUserId()); 314 return type; 315 } catch (RemoteException e) { 316 // Arbitrary and not worth documenting, as Activity 317 // Manager will kill this process shortly anyway. 318 return null; 319 } catch (java.lang.Exception e) { 320 Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")"); 321 return null; 322 } 323 } 324 325 /** 326 * Query for the possible MIME types for the representations the given 327 * content URL can be returned when opened as as stream with 328 * {@link #openTypedAssetFileDescriptor}. Note that the types here are 329 * not necessarily a superset of the type returned by {@link #getType} -- 330 * many content providers cannot return a raw stream for the structured 331 * data that they contain. 332 * 333 * @param url A Uri identifying content (either a list or specific type), 334 * using the content:// scheme. 335 * @param mimeTypeFilter The desired MIME type. This may be a pattern, 336 * such as *\/*, to query for all available MIME types that match the 337 * pattern. 338 * @return Returns an array of MIME type strings for all available 339 * data streams that match the given mimeTypeFilter. If there are none, 340 * null is returned. 341 */ 342 public String[] getStreamTypes(Uri url, String mimeTypeFilter) { 343 IContentProvider provider = acquireProvider(url); 344 if (provider == null) { 345 return null; 346 } 347 348 try { 349 return provider.getStreamTypes(url, mimeTypeFilter); 350 } catch (RemoteException e) { 351 // Arbitrary and not worth documenting, as Activity 352 // Manager will kill this process shortly anyway. 353 return null; 354 } finally { 355 releaseProvider(provider); 356 } 357 } 358 359 /** 360 * <p> 361 * Query the given URI, returning a {@link Cursor} over the result set. 362 * </p> 363 * <p> 364 * For best performance, the caller should follow these guidelines: 365 * <ul> 366 * <li>Provide an explicit projection, to prevent 367 * reading data from storage that aren't going to be used.</li> 368 * <li>Use question mark parameter markers such as 'phone=?' instead of 369 * explicit values in the {@code selection} parameter, so that queries 370 * that differ only by those values will be recognized as the same 371 * for caching purposes.</li> 372 * </ul> 373 * </p> 374 * 375 * @param uri The URI, using the content:// scheme, for the content to 376 * retrieve. 377 * @param projection A list of which columns to return. Passing null will 378 * return all columns, which is inefficient. 379 * @param selection A filter declaring which rows to return, formatted as an 380 * SQL WHERE clause (excluding the WHERE itself). Passing null will 381 * return all rows for the given URI. 382 * @param selectionArgs You may include ?s in selection, which will be 383 * replaced by the values from selectionArgs, in the order that they 384 * appear in the selection. The values will be bound as Strings. 385 * @param sortOrder How to order the rows, formatted as an SQL ORDER BY 386 * clause (excluding the ORDER BY itself). Passing null will use the 387 * default sort order, which may be unordered. 388 * @return A Cursor object, which is positioned before the first entry, or null 389 * @see Cursor 390 */ 391 public final Cursor query(Uri uri, String[] projection, 392 String selection, String[] selectionArgs, String sortOrder) { 393 return query(uri, projection, selection, selectionArgs, sortOrder, null); 394 } 395 396 /** 397 * <p> 398 * Query the given URI, returning a {@link Cursor} over the result set. 399 * </p> 400 * <p> 401 * For best performance, the caller should follow these guidelines: 402 * <ul> 403 * <li>Provide an explicit projection, to prevent 404 * reading data from storage that aren't going to be used.</li> 405 * <li>Use question mark parameter markers such as 'phone=?' instead of 406 * explicit values in the {@code selection} parameter, so that queries 407 * that differ only by those values will be recognized as the same 408 * for caching purposes.</li> 409 * </ul> 410 * </p> 411 * 412 * @param uri The URI, using the content:// scheme, for the content to 413 * retrieve. 414 * @param projection A list of which columns to return. Passing null will 415 * return all columns, which is inefficient. 416 * @param selection A filter declaring which rows to return, formatted as an 417 * SQL WHERE clause (excluding the WHERE itself). Passing null will 418 * return all rows for the given URI. 419 * @param selectionArgs You may include ?s in selection, which will be 420 * replaced by the values from selectionArgs, in the order that they 421 * appear in the selection. The values will be bound as Strings. 422 * @param sortOrder How to order the rows, formatted as an SQL ORDER BY 423 * clause (excluding the ORDER BY itself). Passing null will use the 424 * default sort order, which may be unordered. 425 * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 426 * If the operation is canceled, then {@link OperationCanceledException} will be thrown 427 * when the query is executed. 428 * @return A Cursor object, which is positioned before the first entry, or null 429 * @see Cursor 430 */ 431 public final Cursor query(final Uri uri, String[] projection, 432 String selection, String[] selectionArgs, String sortOrder, 433 CancellationSignal cancellationSignal) { 434 IContentProvider unstableProvider = acquireUnstableProvider(uri); 435 if (unstableProvider == null) { 436 return null; 437 } 438 IContentProvider stableProvider = null; 439 Cursor qCursor = null; 440 try { 441 long startTime = SystemClock.uptimeMillis(); 442 443 ICancellationSignal remoteCancellationSignal = null; 444 if (cancellationSignal != null) { 445 cancellationSignal.throwIfCanceled(); 446 remoteCancellationSignal = unstableProvider.createCancellationSignal(); 447 cancellationSignal.setRemote(remoteCancellationSignal); 448 } 449 try { 450 qCursor = unstableProvider.query(mPackageName, uri, projection, 451 selection, selectionArgs, sortOrder, remoteCancellationSignal); 452 } catch (DeadObjectException e) { 453 // The remote process has died... but we only hold an unstable 454 // reference though, so we might recover!!! Let's try!!!! 455 // This is exciting!!1!!1!!!!1 456 unstableProviderDied(unstableProvider); 457 stableProvider = acquireProvider(uri); 458 if (stableProvider == null) { 459 return null; 460 } 461 qCursor = stableProvider.query(mPackageName, uri, projection, 462 selection, selectionArgs, sortOrder, remoteCancellationSignal); 463 } 464 if (qCursor == null) { 465 return null; 466 } 467 468 // Force query execution. Might fail and throw a runtime exception here. 469 qCursor.getCount(); 470 long durationMillis = SystemClock.uptimeMillis() - startTime; 471 maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder); 472 473 // Wrap the cursor object into CursorWrapperInner object. 474 CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, 475 stableProvider != null ? stableProvider : acquireProvider(uri)); 476 stableProvider = null; 477 qCursor = null; 478 return wrapper; 479 } catch (RemoteException e) { 480 // Arbitrary and not worth documenting, as Activity 481 // Manager will kill this process shortly anyway. 482 return null; 483 } finally { 484 if (qCursor != null) { 485 qCursor.close(); 486 } 487 if (cancellationSignal != null) { 488 cancellationSignal.setRemote(null); 489 } 490 if (unstableProvider != null) { 491 releaseUnstableProvider(unstableProvider); 492 } 493 if (stableProvider != null) { 494 releaseProvider(stableProvider); 495 } 496 } 497 } 498 499 /** 500 * Open a stream on to the content associated with a content URI. If there 501 * is no data associated with the URI, FileNotFoundException is thrown. 502 * 503 * <h5>Accepts the following URI schemes:</h5> 504 * <ul> 505 * <li>content ({@link #SCHEME_CONTENT})</li> 506 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li> 507 * <li>file ({@link #SCHEME_FILE})</li> 508 * </ul> 509 * 510 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information 511 * on these schemes. 512 * 513 * @param uri The desired URI. 514 * @return InputStream 515 * @throws FileNotFoundException if the provided URI could not be opened. 516 * @see #openAssetFileDescriptor(Uri, String) 517 */ 518 public final InputStream openInputStream(Uri uri) 519 throws FileNotFoundException { 520 String scheme = uri.getScheme(); 521 if (SCHEME_ANDROID_RESOURCE.equals(scheme)) { 522 // Note: left here to avoid breaking compatibility. May be removed 523 // with sufficient testing. 524 OpenResourceIdResult r = getResourceId(uri); 525 try { 526 InputStream stream = r.r.openRawResource(r.id); 527 return stream; 528 } catch (Resources.NotFoundException ex) { 529 throw new FileNotFoundException("Resource does not exist: " + uri); 530 } 531 } else if (SCHEME_FILE.equals(scheme)) { 532 // Note: left here to avoid breaking compatibility. May be removed 533 // with sufficient testing. 534 return new FileInputStream(uri.getPath()); 535 } else { 536 AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r", null); 537 try { 538 return fd != null ? fd.createInputStream() : null; 539 } catch (IOException e) { 540 throw new FileNotFoundException("Unable to create stream"); 541 } 542 } 543 } 544 545 /** 546 * Synonym for {@link #openOutputStream(Uri, String) 547 * openOutputStream(uri, "w")}. 548 * @throws FileNotFoundException if the provided URI could not be opened. 549 */ 550 public final OutputStream openOutputStream(Uri uri) 551 throws FileNotFoundException { 552 return openOutputStream(uri, "w"); 553 } 554 555 /** 556 * Open a stream on to the content associated with a content URI. If there 557 * is no data associated with the URI, FileNotFoundException is thrown. 558 * 559 * <h5>Accepts the following URI schemes:</h5> 560 * <ul> 561 * <li>content ({@link #SCHEME_CONTENT})</li> 562 * <li>file ({@link #SCHEME_FILE})</li> 563 * </ul> 564 * 565 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information 566 * on these schemes. 567 * 568 * @param uri The desired URI. 569 * @param mode May be "w", "wa", "rw", or "rwt". 570 * @return OutputStream 571 * @throws FileNotFoundException if the provided URI could not be opened. 572 * @see #openAssetFileDescriptor(Uri, String) 573 */ 574 public final OutputStream openOutputStream(Uri uri, String mode) 575 throws FileNotFoundException { 576 AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode, null); 577 try { 578 return fd != null ? fd.createOutputStream() : null; 579 } catch (IOException e) { 580 throw new FileNotFoundException("Unable to create stream"); 581 } 582 } 583 584 /** 585 * Open a raw file descriptor to access data under a URI. This 586 * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the 587 * underlying {@link ContentProvider#openFile} 588 * ContentProvider.openFile()} method, so will <em>not</em> work with 589 * providers that return sub-sections of files. If at all possible, 590 * you should use {@link #openAssetFileDescriptor(Uri, String)}. You 591 * will receive a FileNotFoundException exception if the provider returns a 592 * sub-section of a file. 593 * 594 * <h5>Accepts the following URI schemes:</h5> 595 * <ul> 596 * <li>content ({@link #SCHEME_CONTENT})</li> 597 * <li>file ({@link #SCHEME_FILE})</li> 598 * </ul> 599 * 600 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information 601 * on these schemes. 602 * <p> 603 * If opening with the exclusive "r" or "w" modes, the returned 604 * ParcelFileDescriptor could be a pipe or socket pair to enable streaming 605 * of data. Opening with the "rw" mode implies a file on disk that supports 606 * seeking. If possible, always use an exclusive mode to give the underlying 607 * {@link ContentProvider} the most flexibility. 608 * <p> 609 * If you are writing a file, and need to communicate an error to the 610 * provider, use {@link ParcelFileDescriptor#closeWithError(String)}. 611 * 612 * @param uri The desired URI to open. 613 * @param mode The file mode to use, as per {@link ContentProvider#openFile 614 * ContentProvider.openFile}. 615 * @return Returns a new ParcelFileDescriptor pointing to the file. You 616 * own this descriptor and are responsible for closing it when done. 617 * @throws FileNotFoundException Throws FileNotFoundException if no 618 * file exists under the URI or the mode is invalid. 619 * @see #openAssetFileDescriptor(Uri, String) 620 */ 621 public final ParcelFileDescriptor openFileDescriptor(Uri uri, String mode) 622 throws FileNotFoundException { 623 return openFileDescriptor(uri, mode, null); 624 } 625 626 /** 627 * Open a raw file descriptor to access data under a URI. This 628 * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the 629 * underlying {@link ContentProvider#openFile} 630 * ContentProvider.openFile()} method, so will <em>not</em> work with 631 * providers that return sub-sections of files. If at all possible, 632 * you should use {@link #openAssetFileDescriptor(Uri, String)}. You 633 * will receive a FileNotFoundException exception if the provider returns a 634 * sub-section of a file. 635 * 636 * <h5>Accepts the following URI schemes:</h5> 637 * <ul> 638 * <li>content ({@link #SCHEME_CONTENT})</li> 639 * <li>file ({@link #SCHEME_FILE})</li> 640 * </ul> 641 * 642 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information 643 * on these schemes. 644 * <p> 645 * If opening with the exclusive "r" or "w" modes, the returned 646 * ParcelFileDescriptor could be a pipe or socket pair to enable streaming 647 * of data. Opening with the "rw" mode implies a file on disk that supports 648 * seeking. If possible, always use an exclusive mode to give the underlying 649 * {@link ContentProvider} the most flexibility. 650 * <p> 651 * If you are writing a file, and need to communicate an error to the 652 * provider, use {@link ParcelFileDescriptor#closeWithError(String)}. 653 * 654 * @param uri The desired URI to open. 655 * @param mode The file mode to use, as per {@link ContentProvider#openFile 656 * ContentProvider.openFile}. 657 * @param signal A signal to cancel the operation in progress, or null if 658 * none. If the operation is canceled, then 659 * {@link OperationCanceledException} will be thrown. 660 * @return Returns a new ParcelFileDescriptor pointing to the file. You 661 * own this descriptor and are responsible for closing it when done. 662 * @throws FileNotFoundException Throws FileNotFoundException if no 663 * file exists under the URI or the mode is invalid. 664 * @see #openAssetFileDescriptor(Uri, String) 665 */ 666 public final ParcelFileDescriptor openFileDescriptor(Uri uri, 667 String mode, CancellationSignal cancellationSignal) throws FileNotFoundException { 668 AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode, cancellationSignal); 669 if (afd == null) { 670 return null; 671 } 672 673 if (afd.getDeclaredLength() < 0) { 674 // This is a full file! 675 return afd.getParcelFileDescriptor(); 676 } 677 678 // Client can't handle a sub-section of a file, so close what 679 // we got and bail with an exception. 680 try { 681 afd.close(); 682 } catch (IOException e) { 683 } 684 685 throw new FileNotFoundException("Not a whole file"); 686 } 687 688 /** 689 * Open a raw file descriptor to access data under a URI. This 690 * interacts with the underlying {@link ContentProvider#openAssetFile} 691 * method of the provider associated with the given URI, to retrieve any file stored there. 692 * 693 * <h5>Accepts the following URI schemes:</h5> 694 * <ul> 695 * <li>content ({@link #SCHEME_CONTENT})</li> 696 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li> 697 * <li>file ({@link #SCHEME_FILE})</li> 698 * </ul> 699 * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5> 700 * <p> 701 * A Uri object can be used to reference a resource in an APK file. The 702 * Uri should be one of the following formats: 703 * <ul> 704 * <li><code>android.resource://package_name/id_number</code><br/> 705 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml. 706 * For example <code>com.example.myapp</code><br/> 707 * <code>id_number</code> is the int form of the ID.<br/> 708 * The easiest way to construct this form is 709 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre> 710 * </li> 711 * <li><code>android.resource://package_name/type/name</code><br/> 712 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml. 713 * For example <code>com.example.myapp</code><br/> 714 * <code>type</code> is the string form of the resource type. For example, <code>raw</code> 715 * or <code>drawable</code>. 716 * <code>name</code> is the string form of the resource name. That is, whatever the file 717 * name was in your res directory, without the type extension. 718 * The easiest way to construct this form is 719 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre> 720 * </li> 721 * </ul> 722 * 723 * <p>Note that if this function is called for read-only input (mode is "r") 724 * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor} 725 * for you with a MIME type of "*\/*". This allows such callers to benefit 726 * from any built-in data conversion that a provider implements. 727 * 728 * @param uri The desired URI to open. 729 * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile 730 * ContentProvider.openAssetFile}. 731 * @return Returns a new ParcelFileDescriptor pointing to the file. You 732 * own this descriptor and are responsible for closing it when done. 733 * @throws FileNotFoundException Throws FileNotFoundException of no 734 * file exists under the URI or the mode is invalid. 735 */ 736 public final AssetFileDescriptor openAssetFileDescriptor(Uri uri, String mode) 737 throws FileNotFoundException { 738 return openAssetFileDescriptor(uri, mode, null); 739 } 740 741 /** 742 * Open a raw file descriptor to access data under a URI. This 743 * interacts with the underlying {@link ContentProvider#openAssetFile} 744 * method of the provider associated with the given URI, to retrieve any file stored there. 745 * 746 * <h5>Accepts the following URI schemes:</h5> 747 * <ul> 748 * <li>content ({@link #SCHEME_CONTENT})</li> 749 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li> 750 * <li>file ({@link #SCHEME_FILE})</li> 751 * </ul> 752 * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5> 753 * <p> 754 * A Uri object can be used to reference a resource in an APK file. The 755 * Uri should be one of the following formats: 756 * <ul> 757 * <li><code>android.resource://package_name/id_number</code><br/> 758 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml. 759 * For example <code>com.example.myapp</code><br/> 760 * <code>id_number</code> is the int form of the ID.<br/> 761 * The easiest way to construct this form is 762 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre> 763 * </li> 764 * <li><code>android.resource://package_name/type/name</code><br/> 765 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml. 766 * For example <code>com.example.myapp</code><br/> 767 * <code>type</code> is the string form of the resource type. For example, <code>raw</code> 768 * or <code>drawable</code>. 769 * <code>name</code> is the string form of the resource name. That is, whatever the file 770 * name was in your res directory, without the type extension. 771 * The easiest way to construct this form is 772 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre> 773 * </li> 774 * </ul> 775 * 776 * <p>Note that if this function is called for read-only input (mode is "r") 777 * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor} 778 * for you with a MIME type of "*\/*". This allows such callers to benefit 779 * from any built-in data conversion that a provider implements. 780 * 781 * @param uri The desired URI to open. 782 * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile 783 * ContentProvider.openAssetFile}. 784 * @param signal A signal to cancel the operation in progress, or null if 785 * none. If the operation is canceled, then 786 * {@link OperationCanceledException} will be thrown. 787 * @return Returns a new ParcelFileDescriptor pointing to the file. You 788 * own this descriptor and are responsible for closing it when done. 789 * @throws FileNotFoundException Throws FileNotFoundException of no 790 * file exists under the URI or the mode is invalid. 791 */ 792 public final AssetFileDescriptor openAssetFileDescriptor(Uri uri, 793 String mode, CancellationSignal cancellationSignal) throws FileNotFoundException { 794 String scheme = uri.getScheme(); 795 if (SCHEME_ANDROID_RESOURCE.equals(scheme)) { 796 if (!"r".equals(mode)) { 797 throw new FileNotFoundException("Can't write resources: " + uri); 798 } 799 OpenResourceIdResult r = getResourceId(uri); 800 try { 801 return r.r.openRawResourceFd(r.id); 802 } catch (Resources.NotFoundException ex) { 803 throw new FileNotFoundException("Resource does not exist: " + uri); 804 } 805 } else if (SCHEME_FILE.equals(scheme)) { 806 ParcelFileDescriptor pfd = ParcelFileDescriptor.open( 807 new File(uri.getPath()), modeToMode(uri, mode)); 808 return new AssetFileDescriptor(pfd, 0, -1); 809 } else { 810 if ("r".equals(mode)) { 811 return openTypedAssetFileDescriptor(uri, "*/*", null, cancellationSignal); 812 } else { 813 IContentProvider unstableProvider = acquireUnstableProvider(uri); 814 if (unstableProvider == null) { 815 throw new FileNotFoundException("No content provider: " + uri); 816 } 817 IContentProvider stableProvider = null; 818 AssetFileDescriptor fd = null; 819 820 try { 821 ICancellationSignal remoteCancellationSignal = null; 822 if (cancellationSignal != null) { 823 cancellationSignal.throwIfCanceled(); 824 remoteCancellationSignal = unstableProvider.createCancellationSignal(); 825 cancellationSignal.setRemote(remoteCancellationSignal); 826 } 827 828 try { 829 fd = unstableProvider.openAssetFile( 830 mPackageName, uri, mode, remoteCancellationSignal); 831 if (fd == null) { 832 // The provider will be released by the finally{} clause 833 return null; 834 } 835 } catch (DeadObjectException e) { 836 // The remote process has died... but we only hold an unstable 837 // reference though, so we might recover!!! Let's try!!!! 838 // This is exciting!!1!!1!!!!1 839 unstableProviderDied(unstableProvider); 840 stableProvider = acquireProvider(uri); 841 if (stableProvider == null) { 842 throw new FileNotFoundException("No content provider: " + uri); 843 } 844 fd = stableProvider.openAssetFile( 845 mPackageName, uri, mode, remoteCancellationSignal); 846 if (fd == null) { 847 // The provider will be released by the finally{} clause 848 return null; 849 } 850 } 851 852 if (stableProvider == null) { 853 stableProvider = acquireProvider(uri); 854 } 855 releaseUnstableProvider(unstableProvider); 856 ParcelFileDescriptor pfd = new ParcelFileDescriptorInner( 857 fd.getParcelFileDescriptor(), stableProvider); 858 859 // Success! Don't release the provider when exiting, let 860 // ParcelFileDescriptorInner do that when it is closed. 861 stableProvider = null; 862 863 return new AssetFileDescriptor(pfd, fd.getStartOffset(), 864 fd.getDeclaredLength()); 865 866 } catch (RemoteException e) { 867 // Whatever, whatever, we'll go away. 868 throw new FileNotFoundException( 869 "Failed opening content provider: " + uri); 870 } catch (FileNotFoundException e) { 871 throw e; 872 } finally { 873 if (cancellationSignal != null) { 874 cancellationSignal.setRemote(null); 875 } 876 if (stableProvider != null) { 877 releaseProvider(stableProvider); 878 } 879 if (unstableProvider != null) { 880 releaseUnstableProvider(unstableProvider); 881 } 882 } 883 } 884 } 885 } 886 887 /** 888 * Open a raw file descriptor to access (potentially type transformed) 889 * data from a "content:" URI. This interacts with the underlying 890 * {@link ContentProvider#openTypedAssetFile} method of the provider 891 * associated with the given URI, to retrieve retrieve any appropriate 892 * data stream for the data stored there. 893 * 894 * <p>Unlike {@link #openAssetFileDescriptor}, this function only works 895 * with "content:" URIs, because content providers are the only facility 896 * with an associated MIME type to ensure that the returned data stream 897 * is of the desired type. 898 * 899 * <p>All text/* streams are encoded in UTF-8. 900 * 901 * @param uri The desired URI to open. 902 * @param mimeType The desired MIME type of the returned data. This can 903 * be a pattern such as *\/*, which will allow the content provider to 904 * select a type, though there is no way for you to determine what type 905 * it is returning. 906 * @param opts Additional provider-dependent options. 907 * @return Returns a new ParcelFileDescriptor from which you can read the 908 * data stream from the provider. Note that this may be a pipe, meaning 909 * you can't seek in it. The only seek you should do is if the 910 * AssetFileDescriptor contains an offset, to move to that offset before 911 * reading. You own this descriptor and are responsible for closing it when done. 912 * @throws FileNotFoundException Throws FileNotFoundException of no 913 * data of the desired type exists under the URI. 914 */ 915 public final AssetFileDescriptor openTypedAssetFileDescriptor( 916 Uri uri, String mimeType, Bundle opts) throws FileNotFoundException { 917 return openTypedAssetFileDescriptor(uri, mimeType, opts, null); 918 } 919 920 /** 921 * Open a raw file descriptor to access (potentially type transformed) 922 * data from a "content:" URI. This interacts with the underlying 923 * {@link ContentProvider#openTypedAssetFile} method of the provider 924 * associated with the given URI, to retrieve retrieve any appropriate 925 * data stream for the data stored there. 926 * 927 * <p>Unlike {@link #openAssetFileDescriptor}, this function only works 928 * with "content:" URIs, because content providers are the only facility 929 * with an associated MIME type to ensure that the returned data stream 930 * is of the desired type. 931 * 932 * <p>All text/* streams are encoded in UTF-8. 933 * 934 * @param uri The desired URI to open. 935 * @param mimeType The desired MIME type of the returned data. This can 936 * be a pattern such as *\/*, which will allow the content provider to 937 * select a type, though there is no way for you to determine what type 938 * it is returning. 939 * @param opts Additional provider-dependent options. 940 * @param signal A signal to cancel the operation in progress, or null if 941 * none. If the operation is canceled, then 942 * {@link OperationCanceledException} will be thrown. 943 * @return Returns a new ParcelFileDescriptor from which you can read the 944 * data stream from the provider. Note that this may be a pipe, meaning 945 * you can't seek in it. The only seek you should do is if the 946 * AssetFileDescriptor contains an offset, to move to that offset before 947 * reading. You own this descriptor and are responsible for closing it when done. 948 * @throws FileNotFoundException Throws FileNotFoundException of no 949 * data of the desired type exists under the URI. 950 */ 951 public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri, 952 String mimeType, Bundle opts, CancellationSignal cancellationSignal) 953 throws FileNotFoundException { 954 IContentProvider unstableProvider = acquireUnstableProvider(uri); 955 if (unstableProvider == null) { 956 throw new FileNotFoundException("No content provider: " + uri); 957 } 958 IContentProvider stableProvider = null; 959 AssetFileDescriptor fd = null; 960 961 try { 962 ICancellationSignal remoteCancellationSignal = null; 963 if (cancellationSignal != null) { 964 cancellationSignal.throwIfCanceled(); 965 remoteCancellationSignal = unstableProvider.createCancellationSignal(); 966 cancellationSignal.setRemote(remoteCancellationSignal); 967 } 968 969 try { 970 fd = unstableProvider.openTypedAssetFile( 971 mPackageName, uri, mimeType, opts, remoteCancellationSignal); 972 if (fd == null) { 973 // The provider will be released by the finally{} clause 974 return null; 975 } 976 } catch (DeadObjectException e) { 977 // The remote process has died... but we only hold an unstable 978 // reference though, so we might recover!!! Let's try!!!! 979 // This is exciting!!1!!1!!!!1 980 unstableProviderDied(unstableProvider); 981 stableProvider = acquireProvider(uri); 982 if (stableProvider == null) { 983 throw new FileNotFoundException("No content provider: " + uri); 984 } 985 fd = stableProvider.openTypedAssetFile( 986 mPackageName, uri, mimeType, opts, remoteCancellationSignal); 987 if (fd == null) { 988 // The provider will be released by the finally{} clause 989 return null; 990 } 991 } 992 993 if (stableProvider == null) { 994 stableProvider = acquireProvider(uri); 995 } 996 releaseUnstableProvider(unstableProvider); 997 ParcelFileDescriptor pfd = new ParcelFileDescriptorInner( 998 fd.getParcelFileDescriptor(), stableProvider); 999 1000 // Success! Don't release the provider when exiting, let 1001 // ParcelFileDescriptorInner do that when it is closed. 1002 stableProvider = null; 1003 1004 return new AssetFileDescriptor(pfd, fd.getStartOffset(), 1005 fd.getDeclaredLength()); 1006 1007 } catch (RemoteException e) { 1008 // Whatever, whatever, we'll go away. 1009 throw new FileNotFoundException( 1010 "Failed opening content provider: " + uri); 1011 } catch (FileNotFoundException e) { 1012 throw e; 1013 } finally { 1014 if (cancellationSignal != null) { 1015 cancellationSignal.setRemote(null); 1016 } 1017 if (stableProvider != null) { 1018 releaseProvider(stableProvider); 1019 } 1020 if (unstableProvider != null) { 1021 releaseUnstableProvider(unstableProvider); 1022 } 1023 } 1024 } 1025 1026 /** 1027 * A resource identified by the {@link Resources} that contains it, and a resource id. 1028 * 1029 * @hide 1030 */ 1031 public class OpenResourceIdResult { 1032 public Resources r; 1033 public int id; 1034 } 1035 1036 /** 1037 * Resolves an android.resource URI to a {@link Resources} and a resource id. 1038 * 1039 * @hide 1040 */ 1041 public OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException { 1042 String authority = uri.getAuthority(); 1043 Resources r; 1044 if (TextUtils.isEmpty(authority)) { 1045 throw new FileNotFoundException("No authority: " + uri); 1046 } else { 1047 try { 1048 r = mContext.getPackageManager().getResourcesForApplication(authority); 1049 } catch (NameNotFoundException ex) { 1050 throw new FileNotFoundException("No package found for authority: " + uri); 1051 } 1052 } 1053 List<String> path = uri.getPathSegments(); 1054 if (path == null) { 1055 throw new FileNotFoundException("No path: " + uri); 1056 } 1057 int len = path.size(); 1058 int id; 1059 if (len == 1) { 1060 try { 1061 id = Integer.parseInt(path.get(0)); 1062 } catch (NumberFormatException e) { 1063 throw new FileNotFoundException("Single path segment is not a resource ID: " + uri); 1064 } 1065 } else if (len == 2) { 1066 id = r.getIdentifier(path.get(1), path.get(0), authority); 1067 } else { 1068 throw new FileNotFoundException("More than two path segments: " + uri); 1069 } 1070 if (id == 0) { 1071 throw new FileNotFoundException("No resource found for: " + uri); 1072 } 1073 OpenResourceIdResult res = new OpenResourceIdResult(); 1074 res.r = r; 1075 res.id = id; 1076 return res; 1077 } 1078 1079 /** @hide */ 1080 static public int modeToMode(Uri uri, String mode) throws FileNotFoundException { 1081 int modeBits; 1082 if ("r".equals(mode)) { 1083 modeBits = ParcelFileDescriptor.MODE_READ_ONLY; 1084 } else if ("w".equals(mode) || "wt".equals(mode)) { 1085 modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY 1086 | ParcelFileDescriptor.MODE_CREATE 1087 | ParcelFileDescriptor.MODE_TRUNCATE; 1088 } else if ("wa".equals(mode)) { 1089 modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY 1090 | ParcelFileDescriptor.MODE_CREATE 1091 | ParcelFileDescriptor.MODE_APPEND; 1092 } else if ("rw".equals(mode)) { 1093 modeBits = ParcelFileDescriptor.MODE_READ_WRITE 1094 | ParcelFileDescriptor.MODE_CREATE; 1095 } else if ("rwt".equals(mode)) { 1096 modeBits = ParcelFileDescriptor.MODE_READ_WRITE 1097 | ParcelFileDescriptor.MODE_CREATE 1098 | ParcelFileDescriptor.MODE_TRUNCATE; 1099 } else { 1100 throw new FileNotFoundException("Bad mode for " + uri + ": " 1101 + mode); 1102 } 1103 return modeBits; 1104 } 1105 1106 /** 1107 * Inserts a row into a table at the given URL. 1108 * 1109 * If the content provider supports transactions the insertion will be atomic. 1110 * 1111 * @param url The URL of the table to insert into. 1112 * @param values The initial values for the newly inserted row. The key is the column name for 1113 * the field. Passing an empty ContentValues will create an empty row. 1114 * @return the URL of the newly created row. 1115 */ 1116 public final Uri insert(Uri url, ContentValues values) 1117 { 1118 IContentProvider provider = acquireProvider(url); 1119 if (provider == null) { 1120 throw new IllegalArgumentException("Unknown URL " + url); 1121 } 1122 try { 1123 long startTime = SystemClock.uptimeMillis(); 1124 Uri createdRow = provider.insert(mPackageName, url, values); 1125 long durationMillis = SystemClock.uptimeMillis() - startTime; 1126 maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */); 1127 return createdRow; 1128 } catch (RemoteException e) { 1129 // Arbitrary and not worth documenting, as Activity 1130 // Manager will kill this process shortly anyway. 1131 return null; 1132 } finally { 1133 releaseProvider(provider); 1134 } 1135 } 1136 1137 /** 1138 * Applies each of the {@link ContentProviderOperation} objects and returns an array 1139 * of their results. Passes through OperationApplicationException, which may be thrown 1140 * by the call to {@link ContentProviderOperation#apply}. 1141 * If all the applications succeed then a {@link ContentProviderResult} array with the 1142 * same number of elements as the operations will be returned. It is implementation-specific 1143 * how many, if any, operations will have been successfully applied if a call to 1144 * apply results in a {@link OperationApplicationException}. 1145 * @param authority the authority of the ContentProvider to which this batch should be applied 1146 * @param operations the operations to apply 1147 * @return the results of the applications 1148 * @throws OperationApplicationException thrown if an application fails. 1149 * See {@link ContentProviderOperation#apply} for more information. 1150 * @throws RemoteException thrown if a RemoteException is encountered while attempting 1151 * to communicate with a remote provider. 1152 */ 1153 public ContentProviderResult[] applyBatch(String authority, 1154 ArrayList<ContentProviderOperation> operations) 1155 throws RemoteException, OperationApplicationException { 1156 ContentProviderClient provider = acquireContentProviderClient(authority); 1157 if (provider == null) { 1158 throw new IllegalArgumentException("Unknown authority " + authority); 1159 } 1160 try { 1161 return provider.applyBatch(operations); 1162 } finally { 1163 provider.release(); 1164 } 1165 } 1166 1167 /** 1168 * Inserts multiple rows into a table at the given URL. 1169 * 1170 * This function make no guarantees about the atomicity of the insertions. 1171 * 1172 * @param url The URL of the table to insert into. 1173 * @param values The initial values for the newly inserted rows. The key is the column name for 1174 * the field. Passing null will create an empty row. 1175 * @return the number of newly created rows. 1176 */ 1177 public final int bulkInsert(Uri url, ContentValues[] values) 1178 { 1179 IContentProvider provider = acquireProvider(url); 1180 if (provider == null) { 1181 throw new IllegalArgumentException("Unknown URL " + url); 1182 } 1183 try { 1184 long startTime = SystemClock.uptimeMillis(); 1185 int rowsCreated = provider.bulkInsert(mPackageName, url, values); 1186 long durationMillis = SystemClock.uptimeMillis() - startTime; 1187 maybeLogUpdateToEventLog(durationMillis, url, "bulkinsert", null /* where */); 1188 return rowsCreated; 1189 } catch (RemoteException e) { 1190 // Arbitrary and not worth documenting, as Activity 1191 // Manager will kill this process shortly anyway. 1192 return 0; 1193 } finally { 1194 releaseProvider(provider); 1195 } 1196 } 1197 1198 /** 1199 * Deletes row(s) specified by a content URI. 1200 * 1201 * If the content provider supports transactions, the deletion will be atomic. 1202 * 1203 * @param url The URL of the row to delete. 1204 * @param where A filter to apply to rows before deleting, formatted as an SQL WHERE clause 1205 (excluding the WHERE itself). 1206 * @return The number of rows deleted. 1207 */ 1208 public final int delete(Uri url, String where, String[] selectionArgs) 1209 { 1210 IContentProvider provider = acquireProvider(url); 1211 if (provider == null) { 1212 throw new IllegalArgumentException("Unknown URL " + url); 1213 } 1214 try { 1215 long startTime = SystemClock.uptimeMillis(); 1216 int rowsDeleted = provider.delete(mPackageName, url, where, selectionArgs); 1217 long durationMillis = SystemClock.uptimeMillis() - startTime; 1218 maybeLogUpdateToEventLog(durationMillis, url, "delete", where); 1219 return rowsDeleted; 1220 } catch (RemoteException e) { 1221 // Arbitrary and not worth documenting, as Activity 1222 // Manager will kill this process shortly anyway. 1223 return -1; 1224 } finally { 1225 releaseProvider(provider); 1226 } 1227 } 1228 1229 /** 1230 * Update row(s) in a content URI. 1231 * 1232 * If the content provider supports transactions the update will be atomic. 1233 * 1234 * @param uri The URI to modify. 1235 * @param values The new field values. The key is the column name for the field. 1236 A null value will remove an existing field value. 1237 * @param where A filter to apply to rows before updating, formatted as an SQL WHERE clause 1238 (excluding the WHERE itself). 1239 * @return the number of rows updated. 1240 * @throws NullPointerException if uri or values are null 1241 */ 1242 public final int update(Uri uri, ContentValues values, String where, 1243 String[] selectionArgs) { 1244 IContentProvider provider = acquireProvider(uri); 1245 if (provider == null) { 1246 throw new IllegalArgumentException("Unknown URI " + uri); 1247 } 1248 try { 1249 long startTime = SystemClock.uptimeMillis(); 1250 int rowsUpdated = provider.update(mPackageName, uri, values, where, selectionArgs); 1251 long durationMillis = SystemClock.uptimeMillis() - startTime; 1252 maybeLogUpdateToEventLog(durationMillis, uri, "update", where); 1253 return rowsUpdated; 1254 } catch (RemoteException e) { 1255 // Arbitrary and not worth documenting, as Activity 1256 // Manager will kill this process shortly anyway. 1257 return -1; 1258 } finally { 1259 releaseProvider(provider); 1260 } 1261 } 1262 1263 /** 1264 * Call a provider-defined method. This can be used to implement 1265 * read or write interfaces which are cheaper than using a Cursor and/or 1266 * do not fit into the traditional table model. 1267 * 1268 * @param method provider-defined method name to call. Opaque to 1269 * framework, but must be non-null. 1270 * @param arg provider-defined String argument. May be null. 1271 * @param extras provider-defined Bundle argument. May be null. 1272 * @return a result Bundle, possibly null. Will be null if the ContentProvider 1273 * does not implement call. 1274 * @throws NullPointerException if uri or method is null 1275 * @throws IllegalArgumentException if uri is not known 1276 */ 1277 public final Bundle call(Uri uri, String method, String arg, Bundle extras) { 1278 if (uri == null) { 1279 throw new NullPointerException("uri == null"); 1280 } 1281 if (method == null) { 1282 throw new NullPointerException("method == null"); 1283 } 1284 IContentProvider provider = acquireProvider(uri); 1285 if (provider == null) { 1286 throw new IllegalArgumentException("Unknown URI " + uri); 1287 } 1288 try { 1289 return provider.call(mPackageName, method, arg, extras); 1290 } catch (RemoteException e) { 1291 // Arbitrary and not worth documenting, as Activity 1292 // Manager will kill this process shortly anyway. 1293 return null; 1294 } finally { 1295 releaseProvider(provider); 1296 } 1297 } 1298 1299 /** 1300 * Returns the content provider for the given content URI. 1301 * 1302 * @param uri The URI to a content provider 1303 * @return The ContentProvider for the given URI, or null if no content provider is found. 1304 * @hide 1305 */ 1306 public final IContentProvider acquireProvider(Uri uri) { 1307 if (!SCHEME_CONTENT.equals(uri.getScheme())) { 1308 return null; 1309 } 1310 final String auth = uri.getAuthority(); 1311 if (auth != null) { 1312 return acquireProvider(mContext, auth); 1313 } 1314 return null; 1315 } 1316 1317 /** 1318 * Returns the content provider for the given content URI if the process 1319 * already has a reference on it. 1320 * 1321 * @param uri The URI to a content provider 1322 * @return The ContentProvider for the given URI, or null if no content provider is found. 1323 * @hide 1324 */ 1325 public final IContentProvider acquireExistingProvider(Uri uri) { 1326 if (!SCHEME_CONTENT.equals(uri.getScheme())) { 1327 return null; 1328 } 1329 final String auth = uri.getAuthority(); 1330 if (auth != null) { 1331 return acquireExistingProvider(mContext, auth); 1332 } 1333 return null; 1334 } 1335 1336 /** 1337 * @hide 1338 */ 1339 public final IContentProvider acquireProvider(String name) { 1340 if (name == null) { 1341 return null; 1342 } 1343 return acquireProvider(mContext, name); 1344 } 1345 1346 /** 1347 * Returns the content provider for the given content URI. 1348 * 1349 * @param uri The URI to a content provider 1350 * @return The ContentProvider for the given URI, or null if no content provider is found. 1351 * @hide 1352 */ 1353 public final IContentProvider acquireUnstableProvider(Uri uri) { 1354 if (!SCHEME_CONTENT.equals(uri.getScheme())) { 1355 return null; 1356 } 1357 String auth = uri.getAuthority(); 1358 if (auth != null) { 1359 return acquireUnstableProvider(mContext, uri.getAuthority()); 1360 } 1361 return null; 1362 } 1363 1364 /** 1365 * @hide 1366 */ 1367 public final IContentProvider acquireUnstableProvider(String name) { 1368 if (name == null) { 1369 return null; 1370 } 1371 return acquireUnstableProvider(mContext, name); 1372 } 1373 1374 /** 1375 * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider} 1376 * that services the content at uri, starting the provider if necessary. Returns 1377 * null if there is no provider associated wih the uri. The caller must indicate that they are 1378 * done with the provider by calling {@link ContentProviderClient#release} which will allow 1379 * the system to release the provider it it determines that there is no other reason for 1380 * keeping it active. 1381 * @param uri specifies which provider should be acquired 1382 * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider} 1383 * that services the content at uri or null if there isn't one. 1384 */ 1385 public final ContentProviderClient acquireContentProviderClient(Uri uri) { 1386 IContentProvider provider = acquireProvider(uri); 1387 if (provider != null) { 1388 return new ContentProviderClient(this, provider, true); 1389 } 1390 1391 return null; 1392 } 1393 1394 /** 1395 * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider} 1396 * with the authority of name, starting the provider if necessary. Returns 1397 * null if there is no provider associated wih the uri. The caller must indicate that they are 1398 * done with the provider by calling {@link ContentProviderClient#release} which will allow 1399 * the system to release the provider it it determines that there is no other reason for 1400 * keeping it active. 1401 * @param name specifies which provider should be acquired 1402 * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider} 1403 * with the authority of name or null if there isn't one. 1404 */ 1405 public final ContentProviderClient acquireContentProviderClient(String name) { 1406 IContentProvider provider = acquireProvider(name); 1407 if (provider != null) { 1408 return new ContentProviderClient(this, provider, true); 1409 } 1410 1411 return null; 1412 } 1413 1414 /** 1415 * Like {@link #acquireContentProviderClient(Uri)}, but for use when you do 1416 * not trust the stability of the target content provider. This turns off 1417 * the mechanism in the platform clean up processes that are dependent on 1418 * a content provider if that content provider's process goes away. Normally 1419 * you can safely assume that once you have acquired a provider, you can freely 1420 * use it as needed and it won't disappear, even if your process is in the 1421 * background. If using this method, you need to take care to deal with any 1422 * failures when communicating with the provider, and be sure to close it 1423 * so that it can be re-opened later. In particular, catching a 1424 * {@link android.os.DeadObjectException} from the calls there will let you 1425 * know that the content provider has gone away; at that point the current 1426 * ContentProviderClient object is invalid, and you should release it. You 1427 * can acquire a new one if you would like to try to restart the provider 1428 * and perform new operations on it. 1429 */ 1430 public final ContentProviderClient acquireUnstableContentProviderClient(Uri uri) { 1431 IContentProvider provider = acquireUnstableProvider(uri); 1432 if (provider != null) { 1433 return new ContentProviderClient(this, provider, false); 1434 } 1435 1436 return null; 1437 } 1438 1439 /** 1440 * Like {@link #acquireContentProviderClient(String)}, but for use when you do 1441 * not trust the stability of the target content provider. This turns off 1442 * the mechanism in the platform clean up processes that are dependent on 1443 * a content provider if that content provider's process goes away. Normally 1444 * you can safely assume that once you have acquired a provider, you can freely 1445 * use it as needed and it won't disappear, even if your process is in the 1446 * background. If using this method, you need to take care to deal with any 1447 * failures when communicating with the provider, and be sure to close it 1448 * so that it can be re-opened later. In particular, catching a 1449 * {@link android.os.DeadObjectException} from the calls there will let you 1450 * know that the content provider has gone away; at that point the current 1451 * ContentProviderClient object is invalid, and you should release it. You 1452 * can acquire a new one if you would like to try to restart the provider 1453 * and perform new operations on it. 1454 */ 1455 public final ContentProviderClient acquireUnstableContentProviderClient(String name) { 1456 IContentProvider provider = acquireUnstableProvider(name); 1457 if (provider != null) { 1458 return new ContentProviderClient(this, provider, false); 1459 } 1460 1461 return null; 1462 } 1463 1464 /** 1465 * Register an observer class that gets callbacks when data identified by a 1466 * given content URI changes. 1467 * 1468 * @param uri The URI to watch for changes. This can be a specific row URI, or a base URI 1469 * for a whole class of content. 1470 * @param notifyForDescendents If <code>true</code> changes to URIs beginning with <code>uri</code> 1471 * will also cause notifications to be sent. If <code>false</code> only changes to the exact URI 1472 * specified by <em>uri</em> will cause notifications to be sent. If true, than any URI values 1473 * at or below the specified URI will also trigger a match. 1474 * @param observer The object that receives callbacks when changes occur. 1475 * @see #unregisterContentObserver 1476 */ 1477 public final void registerContentObserver(Uri uri, boolean notifyForDescendents, 1478 ContentObserver observer) 1479 { 1480 registerContentObserver(uri, notifyForDescendents, observer, UserHandle.myUserId()); 1481 } 1482 1483 /** @hide - designated user version */ 1484 public final void registerContentObserver(Uri uri, boolean notifyForDescendents, 1485 ContentObserver observer, int userHandle) 1486 { 1487 try { 1488 getContentService().registerContentObserver(uri, notifyForDescendents, 1489 observer.getContentObserver(), userHandle); 1490 } catch (RemoteException e) { 1491 } 1492 } 1493 1494 /** 1495 * Unregisters a change observer. 1496 * 1497 * @param observer The previously registered observer that is no longer needed. 1498 * @see #registerContentObserver 1499 */ 1500 public final void unregisterContentObserver(ContentObserver observer) { 1501 try { 1502 IContentObserver contentObserver = observer.releaseContentObserver(); 1503 if (contentObserver != null) { 1504 getContentService().unregisterContentObserver( 1505 contentObserver); 1506 } 1507 } catch (RemoteException e) { 1508 } 1509 } 1510 1511 /** 1512 * Notify registered observers that a row was updated and attempt to sync changes 1513 * to the network. 1514 * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}. 1515 * By default, CursorAdapter objects will get this notification. 1516 * 1517 * @param uri The uri of the content that was changed. 1518 * @param observer The observer that originated the change, may be <code>null</null>. 1519 * The observer that originated the change will only receive the notification if it 1520 * has requested to receive self-change notifications by implementing 1521 * {@link ContentObserver#deliverSelfNotifications()} to return true. 1522 */ 1523 public void notifyChange(Uri uri, ContentObserver observer) { 1524 notifyChange(uri, observer, true /* sync to network */); 1525 } 1526 1527 /** 1528 * Notify registered observers that a row was updated. 1529 * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}. 1530 * By default, CursorAdapter objects will get this notification. 1531 * If syncToNetwork is true, this will attempt to schedule a local sync using the sync 1532 * adapter that's registered for the authority of the provided uri. No account will be 1533 * passed to the sync adapter, so all matching accounts will be synchronized. 1534 * 1535 * @param uri The uri of the content that was changed. 1536 * @param observer The observer that originated the change, may be <code>null</null>. 1537 * The observer that originated the change will only receive the notification if it 1538 * has requested to receive self-change notifications by implementing 1539 * {@link ContentObserver#deliverSelfNotifications()} to return true. 1540 * @param syncToNetwork If true, attempt to sync the change to the network. 1541 * @see #requestSync(android.accounts.Account, String, android.os.Bundle) 1542 */ 1543 public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) { 1544 notifyChange(uri, observer, syncToNetwork, UserHandle.getCallingUserId()); 1545 } 1546 1547 /** 1548 * Notify registered observers within the designated user(s) that a row was updated. 1549 * 1550 * @hide 1551 */ 1552 public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork, 1553 int userHandle) { 1554 try { 1555 getContentService().notifyChange( 1556 uri, observer == null ? null : observer.getContentObserver(), 1557 observer != null && observer.deliverSelfNotifications(), syncToNetwork, 1558 userHandle); 1559 } catch (RemoteException e) { 1560 } 1561 } 1562 1563 /** 1564 * Return list of all Uri permissions that have been granted <em>to</em> the 1565 * calling package, and which exactly match the requested flags. For 1566 * example, to return all Uris that the calling application has 1567 * <em>non-persistent</em> read access to: 1568 * 1569 * <pre class="prettyprint"> 1570 * getIncomingUriPermissionGrants(Intent.FLAG_GRANT_READ_URI_PERMISSION, 1571 * Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION); 1572 * </pre> 1573 * 1574 * @param modeFlags any combination of 1575 * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}, 1576 * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, or 1577 * {@link Intent#FLAG_PERSIST_GRANT_URI_PERMISSION}. 1578 * @param modeMask mask indicating which flags must match. 1579 */ 1580 public Uri[] getIncomingUriPermissionGrants(int modeFlags, int modeMask) { 1581 try { 1582 return ActivityManagerNative.getDefault() 1583 .getGrantedUriPermissions(null, getPackageName(), modeFlags, modeMask); 1584 } catch (RemoteException e) { 1585 return new Uri[0]; 1586 } 1587 } 1588 1589 /** 1590 * Return list of all Uri permissions that have been granted <em>from</em> the 1591 * calling package, and which exactly match the requested flags. For 1592 * example, to return all Uris that the calling application has granted 1593 * <em>non-persistent</em> read access to: 1594 * 1595 * <pre class="prettyprint"> 1596 * getOutgoingUriPermissionGrants(Intent.FLAG_GRANT_READ_URI_PERMISSION, 1597 * Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION); 1598 * </pre> 1599 * 1600 * @param modeFlags any combination of 1601 * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}, 1602 * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, or 1603 * {@link Intent#FLAG_PERSIST_GRANT_URI_PERMISSION}. 1604 * @param modeMask mask indicating which flags must match. 1605 */ 1606 public Uri[] getOutgoingUriPermissionGrants(int modeFlags, int modeMask) { 1607 try { 1608 return ActivityManagerNative.getDefault() 1609 .getGrantedUriPermissions(getPackageName(), null, modeFlags, modeMask); 1610 } catch (RemoteException e) { 1611 return new Uri[0]; 1612 } 1613 } 1614 1615 /** 1616 * Start an asynchronous sync operation. If you want to monitor the progress 1617 * of the sync you may register a SyncObserver. Only values of the following 1618 * types may be used in the extras bundle: 1619 * <ul> 1620 * <li>Integer</li> 1621 * <li>Long</li> 1622 * <li>Boolean</li> 1623 * <li>Float</li> 1624 * <li>Double</li> 1625 * <li>String</li> 1626 * <li>Account</li> 1627 * <li>null</li> 1628 * </ul> 1629 * 1630 * @param uri the uri of the provider to sync or null to sync all providers. 1631 * @param extras any extras to pass to the SyncAdapter. 1632 * @deprecated instead use 1633 * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)} 1634 */ 1635 @Deprecated 1636 public void startSync(Uri uri, Bundle extras) { 1637 Account account = null; 1638 if (extras != null) { 1639 String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT); 1640 if (!TextUtils.isEmpty(accountName)) { 1641 account = new Account(accountName, "com.google"); 1642 } 1643 extras.remove(SYNC_EXTRAS_ACCOUNT); 1644 } 1645 requestSync(account, uri != null ? uri.getAuthority() : null, extras); 1646 } 1647 1648 /** 1649 * Start an asynchronous sync operation. If you want to monitor the progress 1650 * of the sync you may register a SyncObserver. Only values of the following 1651 * types may be used in the extras bundle: 1652 * <ul> 1653 * <li>Integer</li> 1654 * <li>Long</li> 1655 * <li>Boolean</li> 1656 * <li>Float</li> 1657 * <li>Double</li> 1658 * <li>String</li> 1659 * <li>Account</li> 1660 * <li>null</li> 1661 * </ul> 1662 * 1663 * @param account which account should be synced 1664 * @param authority which authority should be synced 1665 * @param extras any extras to pass to the SyncAdapter. 1666 */ 1667 public static void requestSync(Account account, String authority, Bundle extras) { 1668 SyncRequest request = 1669 new SyncRequest.Builder() 1670 .setSyncAdapter(account, authority) 1671 .setExtras(extras) 1672 .syncOnce(0, 0) // Immediate sync. 1673 .build(); 1674 requestSync(request); 1675 } 1676 1677 /** 1678 * Register a sync with the SyncManager. These requests are built using the 1679 * {@link SyncRequest.Builder}. 1680 */ 1681 public static void requestSync(SyncRequest request) { 1682 try { 1683 getContentService().sync(request); 1684 } catch(RemoteException e) { 1685 // Shouldn't happen. 1686 } 1687 } 1688 1689 /** 1690 * Check that only values of the following types are in the Bundle: 1691 * <ul> 1692 * <li>Integer</li> 1693 * <li>Long</li> 1694 * <li>Boolean</li> 1695 * <li>Float</li> 1696 * <li>Double</li> 1697 * <li>String</li> 1698 * <li>Account</li> 1699 * <li>null</li> 1700 * </ul> 1701 * @param extras the Bundle to check 1702 */ 1703 public static void validateSyncExtrasBundle(Bundle extras) { 1704 try { 1705 for (String key : extras.keySet()) { 1706 Object value = extras.get(key); 1707 if (value == null) continue; 1708 if (value instanceof Long) continue; 1709 if (value instanceof Integer) continue; 1710 if (value instanceof Boolean) continue; 1711 if (value instanceof Float) continue; 1712 if (value instanceof Double) continue; 1713 if (value instanceof String) continue; 1714 if (value instanceof Account) continue; 1715 throw new IllegalArgumentException("unexpected value type: " 1716 + value.getClass().getName()); 1717 } 1718 } catch (IllegalArgumentException e) { 1719 throw e; 1720 } catch (RuntimeException exc) { 1721 throw new IllegalArgumentException("error unparceling Bundle", exc); 1722 } 1723 } 1724 1725 /** 1726 * Cancel any active or pending syncs that match the Uri. If the uri is null then 1727 * all syncs will be canceled. 1728 * 1729 * @param uri the uri of the provider to sync or null to sync all providers. 1730 * @deprecated instead use {@link #cancelSync(android.accounts.Account, String)} 1731 */ 1732 @Deprecated 1733 public void cancelSync(Uri uri) { 1734 cancelSync(null /* all accounts */, uri != null ? uri.getAuthority() : null); 1735 } 1736 1737 /** 1738 * Cancel any active or pending syncs that match account and authority. The account and 1739 * authority can each independently be set to null, which means that syncs with any account 1740 * or authority, respectively, will match. 1741 * 1742 * @param account filters the syncs that match by this account 1743 * @param authority filters the syncs that match by this authority 1744 */ 1745 public static void cancelSync(Account account, String authority) { 1746 try { 1747 getContentService().cancelSync(account, authority); 1748 } catch (RemoteException e) { 1749 } 1750 } 1751 1752 /** 1753 * Get information about the SyncAdapters that are known to the system. 1754 * @return an array of SyncAdapters that have registered with the system 1755 */ 1756 public static SyncAdapterType[] getSyncAdapterTypes() { 1757 try { 1758 return getContentService().getSyncAdapterTypes(); 1759 } catch (RemoteException e) { 1760 throw new RuntimeException("the ContentService should always be reachable", e); 1761 } 1762 } 1763 1764 /** 1765 * Check if the provider should be synced when a network tickle is received 1766 * <p>This method requires the caller to hold the permission 1767 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}. 1768 * 1769 * @param account the account whose setting we are querying 1770 * @param authority the provider whose setting we are querying 1771 * @return true if the provider should be synced when a network tickle is received 1772 */ 1773 public static boolean getSyncAutomatically(Account account, String authority) { 1774 try { 1775 return getContentService().getSyncAutomatically(account, authority); 1776 } catch (RemoteException e) { 1777 throw new RuntimeException("the ContentService should always be reachable", e); 1778 } 1779 } 1780 1781 /** 1782 * Set whether or not the provider is synced when it receives a network tickle. 1783 * <p>This method requires the caller to hold the permission 1784 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 1785 * 1786 * @param account the account whose setting we are querying 1787 * @param authority the provider whose behavior is being controlled 1788 * @param sync true if the provider should be synced when tickles are received for it 1789 */ 1790 public static void setSyncAutomatically(Account account, String authority, boolean sync) { 1791 try { 1792 getContentService().setSyncAutomatically(account, authority, sync); 1793 } catch (RemoteException e) { 1794 // exception ignored; if this is thrown then it means the runtime is in the midst of 1795 // being restarted 1796 } 1797 } 1798 1799 /** 1800 * Specifies that a sync should be requested with the specified the account, authority, 1801 * and extras at the given frequency. If there is already another periodic sync scheduled 1802 * with the account, authority and extras then a new periodic sync won't be added, instead 1803 * the frequency of the previous one will be updated. 1804 * <p> 1805 * These periodic syncs honor the "syncAutomatically" and "masterSyncAutomatically" settings. 1806 * Although these sync are scheduled at the specified frequency, it may take longer for it to 1807 * actually be started if other syncs are ahead of it in the sync operation queue. This means 1808 * that the actual start time may drift. 1809 * <p> 1810 * Periodic syncs are not allowed to have any of {@link #SYNC_EXTRAS_DO_NOT_RETRY}, 1811 * {@link #SYNC_EXTRAS_IGNORE_BACKOFF}, {@link #SYNC_EXTRAS_IGNORE_SETTINGS}, 1812 * {@link #SYNC_EXTRAS_INITIALIZE}, {@link #SYNC_EXTRAS_FORCE}, 1813 * {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL} set to true. 1814 * If any are supplied then an {@link IllegalArgumentException} will be thrown. 1815 * 1816 * <p>This method requires the caller to hold the permission 1817 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 1818 * 1819 * @param account the account to specify in the sync 1820 * @param authority the provider to specify in the sync request 1821 * @param extras extra parameters to go along with the sync request 1822 * @param pollFrequency how frequently the sync should be performed, in seconds. 1823 * @throws IllegalArgumentException if an illegal extra was set or if any of the parameters 1824 * are null. 1825 */ 1826 public static void addPeriodicSync(Account account, String authority, Bundle extras, 1827 long pollFrequency) { 1828 validateSyncExtrasBundle(extras); 1829 if (account == null) { 1830 throw new IllegalArgumentException("account must not be null"); 1831 } 1832 if (authority == null) { 1833 throw new IllegalArgumentException("authority must not be null"); 1834 } 1835 if (extras.getBoolean(SYNC_EXTRAS_MANUAL, false) 1836 || extras.getBoolean(SYNC_EXTRAS_DO_NOT_RETRY, false) 1837 || extras.getBoolean(SYNC_EXTRAS_IGNORE_BACKOFF, false) 1838 || extras.getBoolean(SYNC_EXTRAS_IGNORE_SETTINGS, false) 1839 || extras.getBoolean(SYNC_EXTRAS_INITIALIZE, false) 1840 || extras.getBoolean(SYNC_EXTRAS_FORCE, false) 1841 || extras.getBoolean(SYNC_EXTRAS_EXPEDITED, false)) { 1842 throw new IllegalArgumentException("illegal extras were set"); 1843 } 1844 try { 1845 getContentService().addPeriodicSync(account, authority, extras, pollFrequency); 1846 } catch (RemoteException e) { 1847 // exception ignored; if this is thrown then it means the runtime is in the midst of 1848 // being restarted 1849 } 1850 } 1851 1852 /** 1853 * Remove a periodic sync. Has no affect if account, authority and extras don't match 1854 * an existing periodic sync. 1855 * <p>This method requires the caller to hold the permission 1856 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 1857 * 1858 * @param account the account of the periodic sync to remove 1859 * @param authority the provider of the periodic sync to remove 1860 * @param extras the extras of the periodic sync to remove 1861 */ 1862 public static void removePeriodicSync(Account account, String authority, Bundle extras) { 1863 validateSyncExtrasBundle(extras); 1864 if (account == null) { 1865 throw new IllegalArgumentException("account must not be null"); 1866 } 1867 if (authority == null) { 1868 throw new IllegalArgumentException("authority must not be null"); 1869 } 1870 try { 1871 getContentService().removePeriodicSync(account, authority, extras); 1872 } catch (RemoteException e) { 1873 throw new RuntimeException("the ContentService should always be reachable", e); 1874 } 1875 } 1876 1877 /** 1878 * Remove the specified sync. This will remove any syncs that have been scheduled to run, but 1879 * will not cancel any running syncs. 1880 * <p>This method requires the caller to hold the permission</p> 1881 * If the request is for a periodic sync this will cancel future occurrences of the sync. 1882 * 1883 * It is possible to cancel a sync using a SyncRequest object that is different from the object 1884 * with which you requested the sync. Do so by building a SyncRequest with exactly the same 1885 * service/adapter, frequency, <b>and</b> extras bundle. 1886 * 1887 * @param request SyncRequest object containing information about sync to cancel. 1888 */ 1889 public static void cancelSync(SyncRequest request) { 1890 // TODO: Finish this implementation. 1891 } 1892 1893 /** 1894 * Get the list of information about the periodic syncs for the given account and authority. 1895 * <p>This method requires the caller to hold the permission 1896 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}. 1897 * 1898 * @param account the account whose periodic syncs we are querying 1899 * @param authority the provider whose periodic syncs we are querying 1900 * @return a list of PeriodicSync objects. This list may be empty but will never be null. 1901 */ 1902 public static List<PeriodicSync> getPeriodicSyncs(Account account, String authority) { 1903 if (account == null) { 1904 throw new IllegalArgumentException("account must not be null"); 1905 } 1906 if (authority == null) { 1907 throw new IllegalArgumentException("authority must not be null"); 1908 } 1909 try { 1910 return getContentService().getPeriodicSyncs(account, authority); 1911 } catch (RemoteException e) { 1912 throw new RuntimeException("the ContentService should always be reachable", e); 1913 } 1914 } 1915 1916 /** 1917 * Check if this account/provider is syncable. 1918 * <p>This method requires the caller to hold the permission 1919 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}. 1920 * @return >0 if it is syncable, 0 if not, and <0 if the state isn't known yet. 1921 */ 1922 public static int getIsSyncable(Account account, String authority) { 1923 try { 1924 return getContentService().getIsSyncable(account, authority); 1925 } catch (RemoteException e) { 1926 throw new RuntimeException("the ContentService should always be reachable", e); 1927 } 1928 } 1929 1930 /** 1931 * Set whether this account/provider is syncable. 1932 * <p>This method requires the caller to hold the permission 1933 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 1934 * @param syncable >0 denotes syncable, 0 means not syncable, <0 means unknown 1935 */ 1936 public static void setIsSyncable(Account account, String authority, int syncable) { 1937 try { 1938 getContentService().setIsSyncable(account, authority, syncable); 1939 } catch (RemoteException e) { 1940 // exception ignored; if this is thrown then it means the runtime is in the midst of 1941 // being restarted 1942 } 1943 } 1944 1945 /** 1946 * Gets the master auto-sync setting that applies to all the providers and accounts. 1947 * If this is false then the per-provider auto-sync setting is ignored. 1948 * <p>This method requires the caller to hold the permission 1949 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}. 1950 * 1951 * @return the master auto-sync setting that applies to all the providers and accounts 1952 */ 1953 public static boolean getMasterSyncAutomatically() { 1954 try { 1955 return getContentService().getMasterSyncAutomatically(); 1956 } catch (RemoteException e) { 1957 throw new RuntimeException("the ContentService should always be reachable", e); 1958 } 1959 } 1960 1961 /** 1962 * Sets the master auto-sync setting that applies to all the providers and accounts. 1963 * If this is false then the per-provider auto-sync setting is ignored. 1964 * <p>This method requires the caller to hold the permission 1965 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 1966 * 1967 * @param sync the master auto-sync setting that applies to all the providers and accounts 1968 */ 1969 public static void setMasterSyncAutomatically(boolean sync) { 1970 try { 1971 getContentService().setMasterSyncAutomatically(sync); 1972 } catch (RemoteException e) { 1973 // exception ignored; if this is thrown then it means the runtime is in the midst of 1974 // being restarted 1975 } 1976 } 1977 1978 /** 1979 * Returns true if there is currently a sync operation for the given 1980 * account or authority in the pending list, or actively being processed. 1981 * <p>This method requires the caller to hold the permission 1982 * {@link android.Manifest.permission#READ_SYNC_STATS}. 1983 * @param account the account whose setting we are querying 1984 * @param authority the provider whose behavior is being queried 1985 * @return true if a sync is active for the given account or authority. 1986 */ 1987 public static boolean isSyncActive(Account account, String authority) { 1988 try { 1989 return getContentService().isSyncActive(account, authority); 1990 } catch (RemoteException e) { 1991 throw new RuntimeException("the ContentService should always be reachable", e); 1992 } 1993 } 1994 1995 /** 1996 * If a sync is active returns the information about it, otherwise returns null. 1997 * <p> 1998 * This method requires the caller to hold the permission 1999 * {@link android.Manifest.permission#READ_SYNC_STATS}. 2000 * <p> 2001 * @return the SyncInfo for the currently active sync or null if one is not active. 2002 * @deprecated 2003 * Since multiple concurrent syncs are now supported you should use 2004 * {@link #getCurrentSyncs()} to get the accurate list of current syncs. 2005 * This method returns the first item from the list of current syncs 2006 * or null if there are none. 2007 */ 2008 @Deprecated 2009 public static SyncInfo getCurrentSync() { 2010 try { 2011 final List<SyncInfo> syncs = getContentService().getCurrentSyncs(); 2012 if (syncs.isEmpty()) { 2013 return null; 2014 } 2015 return syncs.get(0); 2016 } catch (RemoteException e) { 2017 throw new RuntimeException("the ContentService should always be reachable", e); 2018 } 2019 } 2020 2021 /** 2022 * Returns a list with information about all the active syncs. This list will be empty 2023 * if there are no active syncs. 2024 * <p> 2025 * This method requires the caller to hold the permission 2026 * {@link android.Manifest.permission#READ_SYNC_STATS}. 2027 * <p> 2028 * @return a List of SyncInfo objects for the currently active syncs. 2029 */ 2030 public static List<SyncInfo> getCurrentSyncs() { 2031 try { 2032 return getContentService().getCurrentSyncs(); 2033 } catch (RemoteException e) { 2034 throw new RuntimeException("the ContentService should always be reachable", e); 2035 } 2036 } 2037 2038 /** 2039 * Returns the status that matches the authority. 2040 * @param account the account whose setting we are querying 2041 * @param authority the provider whose behavior is being queried 2042 * @return the SyncStatusInfo for the authority, or null if none exists 2043 * @hide 2044 */ 2045 public static SyncStatusInfo getSyncStatus(Account account, String authority) { 2046 try { 2047 return getContentService().getSyncStatus(account, authority); 2048 } catch (RemoteException e) { 2049 throw new RuntimeException("the ContentService should always be reachable", e); 2050 } 2051 } 2052 2053 /** 2054 * Return true if the pending status is true of any matching authorities. 2055 * <p>This method requires the caller to hold the permission 2056 * {@link android.Manifest.permission#READ_SYNC_STATS}. 2057 * @param account the account whose setting we are querying 2058 * @param authority the provider whose behavior is being queried 2059 * @return true if there is a pending sync with the matching account and authority 2060 */ 2061 public static boolean isSyncPending(Account account, String authority) { 2062 try { 2063 return getContentService().isSyncPending(account, authority); 2064 } catch (RemoteException e) { 2065 throw new RuntimeException("the ContentService should always be reachable", e); 2066 } 2067 } 2068 2069 /** 2070 * Request notifications when the different aspects of the SyncManager change. The 2071 * different items that can be requested are: 2072 * <ul> 2073 * <li> {@link #SYNC_OBSERVER_TYPE_PENDING} 2074 * <li> {@link #SYNC_OBSERVER_TYPE_ACTIVE} 2075 * <li> {@link #SYNC_OBSERVER_TYPE_SETTINGS} 2076 * </ul> 2077 * The caller can set one or more of the status types in the mask for any 2078 * given listener registration. 2079 * @param mask the status change types that will cause the callback to be invoked 2080 * @param callback observer to be invoked when the status changes 2081 * @return a handle that can be used to remove the listener at a later time 2082 */ 2083 public static Object addStatusChangeListener(int mask, final SyncStatusObserver callback) { 2084 if (callback == null) { 2085 throw new IllegalArgumentException("you passed in a null callback"); 2086 } 2087 try { 2088 ISyncStatusObserver.Stub observer = new ISyncStatusObserver.Stub() { 2089 public void onStatusChanged(int which) throws RemoteException { 2090 callback.onStatusChanged(which); 2091 } 2092 }; 2093 getContentService().addStatusChangeListener(mask, observer); 2094 return observer; 2095 } catch (RemoteException e) { 2096 throw new RuntimeException("the ContentService should always be reachable", e); 2097 } 2098 } 2099 2100 /** 2101 * Remove a previously registered status change listener. 2102 * @param handle the handle that was returned by {@link #addStatusChangeListener} 2103 */ 2104 public static void removeStatusChangeListener(Object handle) { 2105 if (handle == null) { 2106 throw new IllegalArgumentException("you passed in a null handle"); 2107 } 2108 try { 2109 getContentService().removeStatusChangeListener((ISyncStatusObserver.Stub) handle); 2110 } catch (RemoteException e) { 2111 // exception ignored; if this is thrown then it means the runtime is in the midst of 2112 // being restarted 2113 } 2114 } 2115 2116 /** 2117 * Returns sampling percentage for a given duration. 2118 * 2119 * Always returns at least 1%. 2120 */ 2121 private int samplePercentForDuration(long durationMillis) { 2122 if (durationMillis >= SLOW_THRESHOLD_MILLIS) { 2123 return 100; 2124 } 2125 return (int) (100 * durationMillis / SLOW_THRESHOLD_MILLIS) + 1; 2126 } 2127 2128 private void maybeLogQueryToEventLog(long durationMillis, 2129 Uri uri, String[] projection, 2130 String selection, String sortOrder) { 2131 if (!ENABLE_CONTENT_SAMPLE) return; 2132 int samplePercent = samplePercentForDuration(durationMillis); 2133 if (samplePercent < 100) { 2134 synchronized (mRandom) { 2135 if (mRandom.nextInt(100) >= samplePercent) { 2136 return; 2137 } 2138 } 2139 } 2140 2141 StringBuilder projectionBuffer = new StringBuilder(100); 2142 if (projection != null) { 2143 for (int i = 0; i < projection.length; ++i) { 2144 // Note: not using a comma delimiter here, as the 2145 // multiple arguments to EventLog.writeEvent later 2146 // stringify with a comma delimiter, which would make 2147 // parsing uglier later. 2148 if (i != 0) projectionBuffer.append('/'); 2149 projectionBuffer.append(projection[i]); 2150 } 2151 } 2152 2153 // ActivityThread.currentPackageName() only returns non-null if the 2154 // current thread is an application main thread. This parameter tells 2155 // us whether an event loop is blocked, and if so, which app it is. 2156 String blockingPackage = AppGlobals.getInitialPackage(); 2157 2158 EventLog.writeEvent( 2159 EventLogTags.CONTENT_QUERY_SAMPLE, 2160 uri.toString(), 2161 projectionBuffer.toString(), 2162 selection != null ? selection : "", 2163 sortOrder != null ? sortOrder : "", 2164 durationMillis, 2165 blockingPackage != null ? blockingPackage : "", 2166 samplePercent); 2167 } 2168 2169 private void maybeLogUpdateToEventLog( 2170 long durationMillis, Uri uri, String operation, String selection) { 2171 if (!ENABLE_CONTENT_SAMPLE) return; 2172 int samplePercent = samplePercentForDuration(durationMillis); 2173 if (samplePercent < 100) { 2174 synchronized (mRandom) { 2175 if (mRandom.nextInt(100) >= samplePercent) { 2176 return; 2177 } 2178 } 2179 } 2180 String blockingPackage = AppGlobals.getInitialPackage(); 2181 EventLog.writeEvent( 2182 EventLogTags.CONTENT_UPDATE_SAMPLE, 2183 uri.toString(), 2184 operation, 2185 selection != null ? selection : "", 2186 durationMillis, 2187 blockingPackage != null ? blockingPackage : "", 2188 samplePercent); 2189 } 2190 2191 private final class CursorWrapperInner extends CrossProcessCursorWrapper { 2192 private final IContentProvider mContentProvider; 2193 public static final String TAG="CursorWrapperInner"; 2194 2195 private final CloseGuard mCloseGuard = CloseGuard.get(); 2196 private boolean mProviderReleased; 2197 2198 CursorWrapperInner(Cursor cursor, IContentProvider icp) { 2199 super(cursor); 2200 mContentProvider = icp; 2201 mCloseGuard.open("close"); 2202 } 2203 2204 @Override 2205 public void close() { 2206 super.close(); 2207 ContentResolver.this.releaseProvider(mContentProvider); 2208 mProviderReleased = true; 2209 2210 if (mCloseGuard != null) { 2211 mCloseGuard.close(); 2212 } 2213 } 2214 2215 @Override 2216 protected void finalize() throws Throwable { 2217 try { 2218 if (mCloseGuard != null) { 2219 mCloseGuard.warnIfOpen(); 2220 } 2221 2222 if (!mProviderReleased && mContentProvider != null) { 2223 // Even though we are using CloseGuard, log this anyway so that 2224 // application developers always see the message in the log. 2225 Log.w(TAG, "Cursor finalized without prior close()"); 2226 ContentResolver.this.releaseProvider(mContentProvider); 2227 } 2228 } finally { 2229 super.finalize(); 2230 } 2231 } 2232 } 2233 2234 private final class ParcelFileDescriptorInner extends ParcelFileDescriptor { 2235 private final IContentProvider mContentProvider; 2236 private boolean mProviderReleased; 2237 2238 ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) { 2239 super(pfd); 2240 mContentProvider = icp; 2241 } 2242 2243 @Override 2244 public void close() throws IOException { 2245 super.close(); 2246 if (!mProviderReleased) { 2247 ContentResolver.this.releaseProvider(mContentProvider); 2248 mProviderReleased = true; 2249 } 2250 } 2251 } 2252 2253 /** @hide */ 2254 public static final String CONTENT_SERVICE_NAME = "content"; 2255 2256 /** @hide */ 2257 public static IContentService getContentService() { 2258 if (sContentService != null) { 2259 return sContentService; 2260 } 2261 IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME); 2262 if (false) Log.v("ContentService", "default service binder = " + b); 2263 sContentService = IContentService.Stub.asInterface(b); 2264 if (false) Log.v("ContentService", "default service = " + sContentService); 2265 return sContentService; 2266 } 2267 2268 /** @hide */ 2269 public String getPackageName() { 2270 return mPackageName; 2271 } 2272 2273 private static IContentService sContentService; 2274 private final Context mContext; 2275 final String mPackageName; 2276 private static final String TAG = "ContentResolver"; 2277} 2278