ContentResolver.java revision b3ac67a0ece71bcf484dd92914dc3599dadffb05
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_DISALLOW_METERED = "disallow_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 * Transform the given <var>url</var> to a canonical representation of 501 * its referenced resource, which can be used across devices, persisted, 502 * backed up and restored, etc. The returned Uri is still a fully capable 503 * Uri for use with its content provider, allowing you to do all of the 504 * same content provider operations as with the original Uri -- 505 * {@link #query}, {@link #openInputStream(android.net.Uri)}, etc. The 506 * only difference in behavior between the original and new Uris is that 507 * the content provider may need to do some additional work at each call 508 * using it to resolve it to the correct resource, especially if the 509 * canonical Uri has been moved to a different environment. 510 * 511 * <p>If you are moving a canonical Uri between environments, you should 512 * perform another call to {@link #canonicalize} with that original Uri to 513 * re-canonicalize it for the current environment. Alternatively, you may 514 * want to use {@link #uncanonicalize} to transform it to a non-canonical 515 * Uri that works only in the current environment but potentially more 516 * efficiently than the canonical representation.</p> 517 * 518 * @param url The {@link Uri} that is to be transformed to a canonical 519 * representation. Like all resolver calls, the input can be either 520 * a non-canonical or canonical Uri. 521 * 522 * @return Returns the official canonical representation of <var>url</var>, 523 * or null if the content provider does not support a canonical representation 524 * of the given Uri. Many providers may not support canonicalization of some 525 * or all of their Uris. 526 * 527 * @see #uncanonicalize 528 */ 529 public final Uri canonicalize(Uri url) { 530 IContentProvider provider = acquireProvider(url); 531 if (provider == null) { 532 return null; 533 } 534 535 try { 536 return provider.canonicalize(mPackageName, url); 537 } catch (RemoteException e) { 538 // Arbitrary and not worth documenting, as Activity 539 // Manager will kill this process shortly anyway. 540 return null; 541 } finally { 542 releaseProvider(provider); 543 } 544 } 545 546 /** 547 * Given a canonical Uri previously generated by {@link #canonicalize}, convert 548 * it to its local non-canonical form. This can be useful in some cases where 549 * you know that you will only be using the Uri in the current environment and 550 * want to avoid any possible overhead when using it with the content 551 * provider or want to verify that the referenced data exists at all in the 552 * new environment. 553 * 554 * @param url The canonical {@link Uri} that is to be convered back to its 555 * non-canonical form. 556 * 557 * @return Returns the non-canonical representation of <var>url</var>. This will 558 * return null if data identified by the canonical Uri can not be found in 559 * the current environment; callers must always check for null and deal with 560 * that by appropriately falling back to an alternative. 561 * 562 * @see #canonicalize 563 */ 564 public final Uri uncanonicalize(Uri url) { 565 IContentProvider provider = acquireProvider(url); 566 if (provider == null) { 567 return null; 568 } 569 570 try { 571 return provider.uncanonicalize(mPackageName, url); 572 } catch (RemoteException e) { 573 // Arbitrary and not worth documenting, as Activity 574 // Manager will kill this process shortly anyway. 575 return null; 576 } finally { 577 releaseProvider(provider); 578 } 579 } 580 581 /** 582 * Open a stream on to the content associated with a content URI. If there 583 * is no data associated with the URI, FileNotFoundException is thrown. 584 * 585 * <h5>Accepts the following URI schemes:</h5> 586 * <ul> 587 * <li>content ({@link #SCHEME_CONTENT})</li> 588 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li> 589 * <li>file ({@link #SCHEME_FILE})</li> 590 * </ul> 591 * 592 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information 593 * on these schemes. 594 * 595 * @param uri The desired URI. 596 * @return InputStream 597 * @throws FileNotFoundException if the provided URI could not be opened. 598 * @see #openAssetFileDescriptor(Uri, String) 599 */ 600 public final InputStream openInputStream(Uri uri) 601 throws FileNotFoundException { 602 String scheme = uri.getScheme(); 603 if (SCHEME_ANDROID_RESOURCE.equals(scheme)) { 604 // Note: left here to avoid breaking compatibility. May be removed 605 // with sufficient testing. 606 OpenResourceIdResult r = getResourceId(uri); 607 try { 608 InputStream stream = r.r.openRawResource(r.id); 609 return stream; 610 } catch (Resources.NotFoundException ex) { 611 throw new FileNotFoundException("Resource does not exist: " + uri); 612 } 613 } else if (SCHEME_FILE.equals(scheme)) { 614 // Note: left here to avoid breaking compatibility. May be removed 615 // with sufficient testing. 616 return new FileInputStream(uri.getPath()); 617 } else { 618 AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r", null); 619 try { 620 return fd != null ? fd.createInputStream() : null; 621 } catch (IOException e) { 622 throw new FileNotFoundException("Unable to create stream"); 623 } 624 } 625 } 626 627 /** 628 * Synonym for {@link #openOutputStream(Uri, String) 629 * openOutputStream(uri, "w")}. 630 * @throws FileNotFoundException if the provided URI could not be opened. 631 */ 632 public final OutputStream openOutputStream(Uri uri) 633 throws FileNotFoundException { 634 return openOutputStream(uri, "w"); 635 } 636 637 /** 638 * Open a stream on to the content associated with a content URI. If there 639 * is no data associated with the URI, FileNotFoundException is thrown. 640 * 641 * <h5>Accepts the following URI schemes:</h5> 642 * <ul> 643 * <li>content ({@link #SCHEME_CONTENT})</li> 644 * <li>file ({@link #SCHEME_FILE})</li> 645 * </ul> 646 * 647 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information 648 * on these schemes. 649 * 650 * @param uri The desired URI. 651 * @param mode May be "w", "wa", "rw", or "rwt". 652 * @return OutputStream 653 * @throws FileNotFoundException if the provided URI could not be opened. 654 * @see #openAssetFileDescriptor(Uri, String) 655 */ 656 public final OutputStream openOutputStream(Uri uri, String mode) 657 throws FileNotFoundException { 658 AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode, null); 659 try { 660 return fd != null ? fd.createOutputStream() : null; 661 } catch (IOException e) { 662 throw new FileNotFoundException("Unable to create stream"); 663 } 664 } 665 666 /** 667 * Open a raw file descriptor to access data under a URI. This 668 * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the 669 * underlying {@link ContentProvider#openFile} 670 * ContentProvider.openFile()} method, so will <em>not</em> work with 671 * providers that return sub-sections of files. If at all possible, 672 * you should use {@link #openAssetFileDescriptor(Uri, String)}. You 673 * will receive a FileNotFoundException exception if the provider returns a 674 * sub-section of a file. 675 * 676 * <h5>Accepts the following URI schemes:</h5> 677 * <ul> 678 * <li>content ({@link #SCHEME_CONTENT})</li> 679 * <li>file ({@link #SCHEME_FILE})</li> 680 * </ul> 681 * 682 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information 683 * on these schemes. 684 * <p> 685 * If opening with the exclusive "r" or "w" modes, the returned 686 * ParcelFileDescriptor could be a pipe or socket pair to enable streaming 687 * of data. Opening with the "rw" mode implies a file on disk that supports 688 * seeking. If possible, always use an exclusive mode to give the underlying 689 * {@link ContentProvider} the most flexibility. 690 * <p> 691 * If you are writing a file, and need to communicate an error to the 692 * provider, use {@link ParcelFileDescriptor#closeWithError(String)}. 693 * 694 * @param uri The desired URI to open. 695 * @param mode The file mode to use, as per {@link ContentProvider#openFile 696 * ContentProvider.openFile}. 697 * @return Returns a new ParcelFileDescriptor pointing to the file. You 698 * own this descriptor and are responsible for closing it when done. 699 * @throws FileNotFoundException Throws FileNotFoundException if no 700 * file exists under the URI or the mode is invalid. 701 * @see #openAssetFileDescriptor(Uri, String) 702 */ 703 public final ParcelFileDescriptor openFileDescriptor(Uri uri, String mode) 704 throws FileNotFoundException { 705 return openFileDescriptor(uri, mode, null); 706 } 707 708 /** 709 * Open a raw file descriptor to access data under a URI. This 710 * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the 711 * underlying {@link ContentProvider#openFile} 712 * ContentProvider.openFile()} method, so will <em>not</em> work with 713 * providers that return sub-sections of files. If at all possible, 714 * you should use {@link #openAssetFileDescriptor(Uri, String)}. You 715 * will receive a FileNotFoundException exception if the provider returns a 716 * sub-section of a file. 717 * 718 * <h5>Accepts the following URI schemes:</h5> 719 * <ul> 720 * <li>content ({@link #SCHEME_CONTENT})</li> 721 * <li>file ({@link #SCHEME_FILE})</li> 722 * </ul> 723 * 724 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information 725 * on these schemes. 726 * <p> 727 * If opening with the exclusive "r" or "w" modes, the returned 728 * ParcelFileDescriptor could be a pipe or socket pair to enable streaming 729 * of data. Opening with the "rw" mode implies a file on disk that supports 730 * seeking. If possible, always use an exclusive mode to give the underlying 731 * {@link ContentProvider} the most flexibility. 732 * <p> 733 * If you are writing a file, and need to communicate an error to the 734 * provider, use {@link ParcelFileDescriptor#closeWithError(String)}. 735 * 736 * @param uri The desired URI to open. 737 * @param mode The file mode to use, as per {@link ContentProvider#openFile 738 * ContentProvider.openFile}. 739 * @param cancellationSignal A signal to cancel the operation in progress, 740 * or null if none. If the operation is canceled, then 741 * {@link OperationCanceledException} will be thrown. 742 * @return Returns a new ParcelFileDescriptor pointing to the file. You 743 * own this descriptor and are responsible for closing it when done. 744 * @throws FileNotFoundException Throws FileNotFoundException if no 745 * file exists under the URI or the mode is invalid. 746 * @see #openAssetFileDescriptor(Uri, String) 747 */ 748 public final ParcelFileDescriptor openFileDescriptor(Uri uri, 749 String mode, CancellationSignal cancellationSignal) throws FileNotFoundException { 750 AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode, cancellationSignal); 751 if (afd == null) { 752 return null; 753 } 754 755 if (afd.getDeclaredLength() < 0) { 756 // This is a full file! 757 return afd.getParcelFileDescriptor(); 758 } 759 760 // Client can't handle a sub-section of a file, so close what 761 // we got and bail with an exception. 762 try { 763 afd.close(); 764 } catch (IOException e) { 765 } 766 767 throw new FileNotFoundException("Not a whole file"); 768 } 769 770 /** 771 * Open a raw file descriptor to access data under a URI. This 772 * interacts with the underlying {@link ContentProvider#openAssetFile} 773 * method of the provider associated with the given URI, to retrieve any file stored there. 774 * 775 * <h5>Accepts the following URI schemes:</h5> 776 * <ul> 777 * <li>content ({@link #SCHEME_CONTENT})</li> 778 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li> 779 * <li>file ({@link #SCHEME_FILE})</li> 780 * </ul> 781 * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5> 782 * <p> 783 * A Uri object can be used to reference a resource in an APK file. The 784 * Uri should be one of the following formats: 785 * <ul> 786 * <li><code>android.resource://package_name/id_number</code><br/> 787 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml. 788 * For example <code>com.example.myapp</code><br/> 789 * <code>id_number</code> is the int form of the ID.<br/> 790 * The easiest way to construct this form is 791 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre> 792 * </li> 793 * <li><code>android.resource://package_name/type/name</code><br/> 794 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml. 795 * For example <code>com.example.myapp</code><br/> 796 * <code>type</code> is the string form of the resource type. For example, <code>raw</code> 797 * or <code>drawable</code>. 798 * <code>name</code> is the string form of the resource name. That is, whatever the file 799 * name was in your res directory, without the type extension. 800 * The easiest way to construct this form is 801 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre> 802 * </li> 803 * </ul> 804 * 805 * <p>Note that if this function is called for read-only input (mode is "r") 806 * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor} 807 * for you with a MIME type of "*\/*". This allows such callers to benefit 808 * from any built-in data conversion that a provider implements. 809 * 810 * @param uri The desired URI to open. 811 * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile 812 * ContentProvider.openAssetFile}. 813 * @return Returns a new ParcelFileDescriptor pointing to the file. You 814 * own this descriptor and are responsible for closing it when done. 815 * @throws FileNotFoundException Throws FileNotFoundException of no 816 * file exists under the URI or the mode is invalid. 817 */ 818 public final AssetFileDescriptor openAssetFileDescriptor(Uri uri, String mode) 819 throws FileNotFoundException { 820 return openAssetFileDescriptor(uri, mode, null); 821 } 822 823 /** 824 * Open a raw file descriptor to access data under a URI. This 825 * interacts with the underlying {@link ContentProvider#openAssetFile} 826 * method of the provider associated with the given URI, to retrieve any file stored there. 827 * 828 * <h5>Accepts the following URI schemes:</h5> 829 * <ul> 830 * <li>content ({@link #SCHEME_CONTENT})</li> 831 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li> 832 * <li>file ({@link #SCHEME_FILE})</li> 833 * </ul> 834 * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5> 835 * <p> 836 * A Uri object can be used to reference a resource in an APK file. The 837 * Uri should be one of the following formats: 838 * <ul> 839 * <li><code>android.resource://package_name/id_number</code><br/> 840 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml. 841 * For example <code>com.example.myapp</code><br/> 842 * <code>id_number</code> is the int form of the ID.<br/> 843 * The easiest way to construct this form is 844 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre> 845 * </li> 846 * <li><code>android.resource://package_name/type/name</code><br/> 847 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml. 848 * For example <code>com.example.myapp</code><br/> 849 * <code>type</code> is the string form of the resource type. For example, <code>raw</code> 850 * or <code>drawable</code>. 851 * <code>name</code> is the string form of the resource name. That is, whatever the file 852 * name was in your res directory, without the type extension. 853 * The easiest way to construct this form is 854 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre> 855 * </li> 856 * </ul> 857 * 858 * <p>Note that if this function is called for read-only input (mode is "r") 859 * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor} 860 * for you with a MIME type of "*\/*". This allows such callers to benefit 861 * from any built-in data conversion that a provider implements. 862 * 863 * @param uri The desired URI to open. 864 * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile 865 * ContentProvider.openAssetFile}. 866 * @param cancellationSignal A signal to cancel the operation in progress, or null if 867 * none. If the operation is canceled, then 868 * {@link OperationCanceledException} will be thrown. 869 * @return Returns a new ParcelFileDescriptor pointing to the file. You 870 * own this descriptor and are responsible for closing it when done. 871 * @throws FileNotFoundException Throws FileNotFoundException of no 872 * file exists under the URI or the mode is invalid. 873 */ 874 public final AssetFileDescriptor openAssetFileDescriptor(Uri uri, 875 String mode, CancellationSignal cancellationSignal) throws FileNotFoundException { 876 String scheme = uri.getScheme(); 877 if (SCHEME_ANDROID_RESOURCE.equals(scheme)) { 878 if (!"r".equals(mode)) { 879 throw new FileNotFoundException("Can't write resources: " + uri); 880 } 881 OpenResourceIdResult r = getResourceId(uri); 882 try { 883 return r.r.openRawResourceFd(r.id); 884 } catch (Resources.NotFoundException ex) { 885 throw new FileNotFoundException("Resource does not exist: " + uri); 886 } 887 } else if (SCHEME_FILE.equals(scheme)) { 888 ParcelFileDescriptor pfd = ParcelFileDescriptor.open( 889 new File(uri.getPath()), modeToMode(uri, mode)); 890 return new AssetFileDescriptor(pfd, 0, -1); 891 } else { 892 if ("r".equals(mode)) { 893 return openTypedAssetFileDescriptor(uri, "*/*", null, cancellationSignal); 894 } else { 895 IContentProvider unstableProvider = acquireUnstableProvider(uri); 896 if (unstableProvider == null) { 897 throw new FileNotFoundException("No content provider: " + uri); 898 } 899 IContentProvider stableProvider = null; 900 AssetFileDescriptor fd = null; 901 902 try { 903 ICancellationSignal remoteCancellationSignal = null; 904 if (cancellationSignal != null) { 905 cancellationSignal.throwIfCanceled(); 906 remoteCancellationSignal = unstableProvider.createCancellationSignal(); 907 cancellationSignal.setRemote(remoteCancellationSignal); 908 } 909 910 try { 911 fd = unstableProvider.openAssetFile( 912 mPackageName, uri, mode, remoteCancellationSignal); 913 if (fd == null) { 914 // The provider will be released by the finally{} clause 915 return null; 916 } 917 } catch (DeadObjectException e) { 918 // The remote process has died... but we only hold an unstable 919 // reference though, so we might recover!!! Let's try!!!! 920 // This is exciting!!1!!1!!!!1 921 unstableProviderDied(unstableProvider); 922 stableProvider = acquireProvider(uri); 923 if (stableProvider == null) { 924 throw new FileNotFoundException("No content provider: " + uri); 925 } 926 fd = stableProvider.openAssetFile( 927 mPackageName, uri, mode, remoteCancellationSignal); 928 if (fd == null) { 929 // The provider will be released by the finally{} clause 930 return null; 931 } 932 } 933 934 if (stableProvider == null) { 935 stableProvider = acquireProvider(uri); 936 } 937 releaseUnstableProvider(unstableProvider); 938 ParcelFileDescriptor pfd = new ParcelFileDescriptorInner( 939 fd.getParcelFileDescriptor(), stableProvider); 940 941 // Success! Don't release the provider when exiting, let 942 // ParcelFileDescriptorInner do that when it is closed. 943 stableProvider = null; 944 945 return new AssetFileDescriptor(pfd, fd.getStartOffset(), 946 fd.getDeclaredLength()); 947 948 } catch (RemoteException e) { 949 // Whatever, whatever, we'll go away. 950 throw new FileNotFoundException( 951 "Failed opening content provider: " + uri); 952 } catch (FileNotFoundException e) { 953 throw e; 954 } finally { 955 if (cancellationSignal != null) { 956 cancellationSignal.setRemote(null); 957 } 958 if (stableProvider != null) { 959 releaseProvider(stableProvider); 960 } 961 if (unstableProvider != null) { 962 releaseUnstableProvider(unstableProvider); 963 } 964 } 965 } 966 } 967 } 968 969 /** 970 * Open a raw file descriptor to access (potentially type transformed) 971 * data from a "content:" URI. This interacts with the underlying 972 * {@link ContentProvider#openTypedAssetFile} method of the provider 973 * associated with the given URI, to retrieve retrieve any appropriate 974 * data stream for the data stored there. 975 * 976 * <p>Unlike {@link #openAssetFileDescriptor}, this function only works 977 * with "content:" URIs, because content providers are the only facility 978 * with an associated MIME type to ensure that the returned data stream 979 * is of the desired type. 980 * 981 * <p>All text/* streams are encoded in UTF-8. 982 * 983 * @param uri The desired URI to open. 984 * @param mimeType The desired MIME type of the returned data. This can 985 * be a pattern such as *\/*, which will allow the content provider to 986 * select a type, though there is no way for you to determine what type 987 * it is returning. 988 * @param opts Additional provider-dependent options. 989 * @return Returns a new ParcelFileDescriptor from which you can read the 990 * data stream from the provider. Note that this may be a pipe, meaning 991 * you can't seek in it. The only seek you should do is if the 992 * AssetFileDescriptor contains an offset, to move to that offset before 993 * reading. You own this descriptor and are responsible for closing it when done. 994 * @throws FileNotFoundException Throws FileNotFoundException of no 995 * data of the desired type exists under the URI. 996 */ 997 public final AssetFileDescriptor openTypedAssetFileDescriptor( 998 Uri uri, String mimeType, Bundle opts) throws FileNotFoundException { 999 return openTypedAssetFileDescriptor(uri, mimeType, opts, null); 1000 } 1001 1002 /** 1003 * Open a raw file descriptor to access (potentially type transformed) 1004 * data from a "content:" URI. This interacts with the underlying 1005 * {@link ContentProvider#openTypedAssetFile} method of the provider 1006 * associated with the given URI, to retrieve retrieve any appropriate 1007 * data stream for the data stored there. 1008 * 1009 * <p>Unlike {@link #openAssetFileDescriptor}, this function only works 1010 * with "content:" URIs, because content providers are the only facility 1011 * with an associated MIME type to ensure that the returned data stream 1012 * is of the desired type. 1013 * 1014 * <p>All text/* streams are encoded in UTF-8. 1015 * 1016 * @param uri The desired URI to open. 1017 * @param mimeType The desired MIME type of the returned data. This can 1018 * be a pattern such as *\/*, which will allow the content provider to 1019 * select a type, though there is no way for you to determine what type 1020 * it is returning. 1021 * @param opts Additional provider-dependent options. 1022 * @param cancellationSignal A signal to cancel the operation in progress, 1023 * or null if none. If the operation is canceled, then 1024 * {@link OperationCanceledException} will be thrown. 1025 * @return Returns a new ParcelFileDescriptor from which you can read the 1026 * data stream from the provider. Note that this may be a pipe, meaning 1027 * you can't seek in it. The only seek you should do is if the 1028 * AssetFileDescriptor contains an offset, to move to that offset before 1029 * reading. You own this descriptor and are responsible for closing it when done. 1030 * @throws FileNotFoundException Throws FileNotFoundException of no 1031 * data of the desired type exists under the URI. 1032 */ 1033 public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri, 1034 String mimeType, Bundle opts, CancellationSignal cancellationSignal) 1035 throws FileNotFoundException { 1036 IContentProvider unstableProvider = acquireUnstableProvider(uri); 1037 if (unstableProvider == null) { 1038 throw new FileNotFoundException("No content provider: " + uri); 1039 } 1040 IContentProvider stableProvider = null; 1041 AssetFileDescriptor fd = null; 1042 1043 try { 1044 ICancellationSignal remoteCancellationSignal = null; 1045 if (cancellationSignal != null) { 1046 cancellationSignal.throwIfCanceled(); 1047 remoteCancellationSignal = unstableProvider.createCancellationSignal(); 1048 cancellationSignal.setRemote(remoteCancellationSignal); 1049 } 1050 1051 try { 1052 fd = unstableProvider.openTypedAssetFile( 1053 mPackageName, uri, mimeType, opts, remoteCancellationSignal); 1054 if (fd == null) { 1055 // The provider will be released by the finally{} clause 1056 return null; 1057 } 1058 } catch (DeadObjectException e) { 1059 // The remote process has died... but we only hold an unstable 1060 // reference though, so we might recover!!! Let's try!!!! 1061 // This is exciting!!1!!1!!!!1 1062 unstableProviderDied(unstableProvider); 1063 stableProvider = acquireProvider(uri); 1064 if (stableProvider == null) { 1065 throw new FileNotFoundException("No content provider: " + uri); 1066 } 1067 fd = stableProvider.openTypedAssetFile( 1068 mPackageName, uri, mimeType, opts, remoteCancellationSignal); 1069 if (fd == null) { 1070 // The provider will be released by the finally{} clause 1071 return null; 1072 } 1073 } 1074 1075 if (stableProvider == null) { 1076 stableProvider = acquireProvider(uri); 1077 } 1078 releaseUnstableProvider(unstableProvider); 1079 ParcelFileDescriptor pfd = new ParcelFileDescriptorInner( 1080 fd.getParcelFileDescriptor(), stableProvider); 1081 1082 // Success! Don't release the provider when exiting, let 1083 // ParcelFileDescriptorInner do that when it is closed. 1084 stableProvider = null; 1085 1086 return new AssetFileDescriptor(pfd, fd.getStartOffset(), 1087 fd.getDeclaredLength()); 1088 1089 } catch (RemoteException e) { 1090 // Whatever, whatever, we'll go away. 1091 throw new FileNotFoundException( 1092 "Failed opening content provider: " + uri); 1093 } catch (FileNotFoundException e) { 1094 throw e; 1095 } finally { 1096 if (cancellationSignal != null) { 1097 cancellationSignal.setRemote(null); 1098 } 1099 if (stableProvider != null) { 1100 releaseProvider(stableProvider); 1101 } 1102 if (unstableProvider != null) { 1103 releaseUnstableProvider(unstableProvider); 1104 } 1105 } 1106 } 1107 1108 /** 1109 * A resource identified by the {@link Resources} that contains it, and a resource id. 1110 * 1111 * @hide 1112 */ 1113 public class OpenResourceIdResult { 1114 public Resources r; 1115 public int id; 1116 } 1117 1118 /** 1119 * Resolves an android.resource URI to a {@link Resources} and a resource id. 1120 * 1121 * @hide 1122 */ 1123 public OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException { 1124 String authority = uri.getAuthority(); 1125 Resources r; 1126 if (TextUtils.isEmpty(authority)) { 1127 throw new FileNotFoundException("No authority: " + uri); 1128 } else { 1129 try { 1130 r = mContext.getPackageManager().getResourcesForApplication(authority); 1131 } catch (NameNotFoundException ex) { 1132 throw new FileNotFoundException("No package found for authority: " + uri); 1133 } 1134 } 1135 List<String> path = uri.getPathSegments(); 1136 if (path == null) { 1137 throw new FileNotFoundException("No path: " + uri); 1138 } 1139 int len = path.size(); 1140 int id; 1141 if (len == 1) { 1142 try { 1143 id = Integer.parseInt(path.get(0)); 1144 } catch (NumberFormatException e) { 1145 throw new FileNotFoundException("Single path segment is not a resource ID: " + uri); 1146 } 1147 } else if (len == 2) { 1148 id = r.getIdentifier(path.get(1), path.get(0), authority); 1149 } else { 1150 throw new FileNotFoundException("More than two path segments: " + uri); 1151 } 1152 if (id == 0) { 1153 throw new FileNotFoundException("No resource found for: " + uri); 1154 } 1155 OpenResourceIdResult res = new OpenResourceIdResult(); 1156 res.r = r; 1157 res.id = id; 1158 return res; 1159 } 1160 1161 /** @hide */ 1162 static public int modeToMode(Uri uri, String mode) throws FileNotFoundException { 1163 int modeBits; 1164 if ("r".equals(mode)) { 1165 modeBits = ParcelFileDescriptor.MODE_READ_ONLY; 1166 } else if ("w".equals(mode) || "wt".equals(mode)) { 1167 modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY 1168 | ParcelFileDescriptor.MODE_CREATE 1169 | ParcelFileDescriptor.MODE_TRUNCATE; 1170 } else if ("wa".equals(mode)) { 1171 modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY 1172 | ParcelFileDescriptor.MODE_CREATE 1173 | ParcelFileDescriptor.MODE_APPEND; 1174 } else if ("rw".equals(mode)) { 1175 modeBits = ParcelFileDescriptor.MODE_READ_WRITE 1176 | ParcelFileDescriptor.MODE_CREATE; 1177 } else if ("rwt".equals(mode)) { 1178 modeBits = ParcelFileDescriptor.MODE_READ_WRITE 1179 | ParcelFileDescriptor.MODE_CREATE 1180 | ParcelFileDescriptor.MODE_TRUNCATE; 1181 } else { 1182 throw new FileNotFoundException("Bad mode for " + uri + ": " 1183 + mode); 1184 } 1185 return modeBits; 1186 } 1187 1188 /** 1189 * Inserts a row into a table at the given URL. 1190 * 1191 * If the content provider supports transactions the insertion will be atomic. 1192 * 1193 * @param url The URL of the table to insert into. 1194 * @param values The initial values for the newly inserted row. The key is the column name for 1195 * the field. Passing an empty ContentValues will create an empty row. 1196 * @return the URL of the newly created row. 1197 */ 1198 public final Uri insert(Uri url, ContentValues values) 1199 { 1200 IContentProvider provider = acquireProvider(url); 1201 if (provider == null) { 1202 throw new IllegalArgumentException("Unknown URL " + url); 1203 } 1204 try { 1205 long startTime = SystemClock.uptimeMillis(); 1206 Uri createdRow = provider.insert(mPackageName, url, values); 1207 long durationMillis = SystemClock.uptimeMillis() - startTime; 1208 maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */); 1209 return createdRow; 1210 } catch (RemoteException e) { 1211 // Arbitrary and not worth documenting, as Activity 1212 // Manager will kill this process shortly anyway. 1213 return null; 1214 } finally { 1215 releaseProvider(provider); 1216 } 1217 } 1218 1219 /** 1220 * Applies each of the {@link ContentProviderOperation} objects and returns an array 1221 * of their results. Passes through OperationApplicationException, which may be thrown 1222 * by the call to {@link ContentProviderOperation#apply}. 1223 * If all the applications succeed then a {@link ContentProviderResult} array with the 1224 * same number of elements as the operations will be returned. It is implementation-specific 1225 * how many, if any, operations will have been successfully applied if a call to 1226 * apply results in a {@link OperationApplicationException}. 1227 * @param authority the authority of the ContentProvider to which this batch should be applied 1228 * @param operations the operations to apply 1229 * @return the results of the applications 1230 * @throws OperationApplicationException thrown if an application fails. 1231 * See {@link ContentProviderOperation#apply} for more information. 1232 * @throws RemoteException thrown if a RemoteException is encountered while attempting 1233 * to communicate with a remote provider. 1234 */ 1235 public ContentProviderResult[] applyBatch(String authority, 1236 ArrayList<ContentProviderOperation> operations) 1237 throws RemoteException, OperationApplicationException { 1238 ContentProviderClient provider = acquireContentProviderClient(authority); 1239 if (provider == null) { 1240 throw new IllegalArgumentException("Unknown authority " + authority); 1241 } 1242 try { 1243 return provider.applyBatch(operations); 1244 } finally { 1245 provider.release(); 1246 } 1247 } 1248 1249 /** 1250 * Inserts multiple rows into a table at the given URL. 1251 * 1252 * This function make no guarantees about the atomicity of the insertions. 1253 * 1254 * @param url The URL of the table to insert into. 1255 * @param values The initial values for the newly inserted rows. The key is the column name for 1256 * the field. Passing null will create an empty row. 1257 * @return the number of newly created rows. 1258 */ 1259 public final int bulkInsert(Uri url, ContentValues[] values) 1260 { 1261 IContentProvider provider = acquireProvider(url); 1262 if (provider == null) { 1263 throw new IllegalArgumentException("Unknown URL " + url); 1264 } 1265 try { 1266 long startTime = SystemClock.uptimeMillis(); 1267 int rowsCreated = provider.bulkInsert(mPackageName, url, values); 1268 long durationMillis = SystemClock.uptimeMillis() - startTime; 1269 maybeLogUpdateToEventLog(durationMillis, url, "bulkinsert", null /* where */); 1270 return rowsCreated; 1271 } catch (RemoteException e) { 1272 // Arbitrary and not worth documenting, as Activity 1273 // Manager will kill this process shortly anyway. 1274 return 0; 1275 } finally { 1276 releaseProvider(provider); 1277 } 1278 } 1279 1280 /** 1281 * Deletes row(s) specified by a content URI. 1282 * 1283 * If the content provider supports transactions, the deletion will be atomic. 1284 * 1285 * @param url The URL of the row to delete. 1286 * @param where A filter to apply to rows before deleting, formatted as an SQL WHERE clause 1287 (excluding the WHERE itself). 1288 * @return The number of rows deleted. 1289 */ 1290 public final int delete(Uri url, String where, String[] selectionArgs) 1291 { 1292 IContentProvider provider = acquireProvider(url); 1293 if (provider == null) { 1294 throw new IllegalArgumentException("Unknown URL " + url); 1295 } 1296 try { 1297 long startTime = SystemClock.uptimeMillis(); 1298 int rowsDeleted = provider.delete(mPackageName, url, where, selectionArgs); 1299 long durationMillis = SystemClock.uptimeMillis() - startTime; 1300 maybeLogUpdateToEventLog(durationMillis, url, "delete", where); 1301 return rowsDeleted; 1302 } catch (RemoteException e) { 1303 // Arbitrary and not worth documenting, as Activity 1304 // Manager will kill this process shortly anyway. 1305 return -1; 1306 } finally { 1307 releaseProvider(provider); 1308 } 1309 } 1310 1311 /** 1312 * Update row(s) in a content URI. 1313 * 1314 * If the content provider supports transactions the update will be atomic. 1315 * 1316 * @param uri The URI to modify. 1317 * @param values The new field values. The key is the column name for the field. 1318 A null value will remove an existing field value. 1319 * @param where A filter to apply to rows before updating, formatted as an SQL WHERE clause 1320 (excluding the WHERE itself). 1321 * @return the number of rows updated. 1322 * @throws NullPointerException if uri or values are null 1323 */ 1324 public final int update(Uri uri, ContentValues values, String where, 1325 String[] selectionArgs) { 1326 IContentProvider provider = acquireProvider(uri); 1327 if (provider == null) { 1328 throw new IllegalArgumentException("Unknown URI " + uri); 1329 } 1330 try { 1331 long startTime = SystemClock.uptimeMillis(); 1332 int rowsUpdated = provider.update(mPackageName, uri, values, where, selectionArgs); 1333 long durationMillis = SystemClock.uptimeMillis() - startTime; 1334 maybeLogUpdateToEventLog(durationMillis, uri, "update", where); 1335 return rowsUpdated; 1336 } catch (RemoteException e) { 1337 // Arbitrary and not worth documenting, as Activity 1338 // Manager will kill this process shortly anyway. 1339 return -1; 1340 } finally { 1341 releaseProvider(provider); 1342 } 1343 } 1344 1345 /** 1346 * Call a provider-defined method. This can be used to implement 1347 * read or write interfaces which are cheaper than using a Cursor and/or 1348 * do not fit into the traditional table model. 1349 * 1350 * @param method provider-defined method name to call. Opaque to 1351 * framework, but must be non-null. 1352 * @param arg provider-defined String argument. May be null. 1353 * @param extras provider-defined Bundle argument. May be null. 1354 * @return a result Bundle, possibly null. Will be null if the ContentProvider 1355 * does not implement call. 1356 * @throws NullPointerException if uri or method is null 1357 * @throws IllegalArgumentException if uri is not known 1358 */ 1359 public final Bundle call(Uri uri, String method, String arg, Bundle extras) { 1360 if (uri == null) { 1361 throw new NullPointerException("uri == null"); 1362 } 1363 if (method == null) { 1364 throw new NullPointerException("method == null"); 1365 } 1366 IContentProvider provider = acquireProvider(uri); 1367 if (provider == null) { 1368 throw new IllegalArgumentException("Unknown URI " + uri); 1369 } 1370 try { 1371 return provider.call(mPackageName, method, arg, extras); 1372 } catch (RemoteException e) { 1373 // Arbitrary and not worth documenting, as Activity 1374 // Manager will kill this process shortly anyway. 1375 return null; 1376 } finally { 1377 releaseProvider(provider); 1378 } 1379 } 1380 1381 /** 1382 * Returns the content provider for the given content URI. 1383 * 1384 * @param uri The URI to a content provider 1385 * @return The ContentProvider for the given URI, or null if no content provider is found. 1386 * @hide 1387 */ 1388 public final IContentProvider acquireProvider(Uri uri) { 1389 if (!SCHEME_CONTENT.equals(uri.getScheme())) { 1390 return null; 1391 } 1392 final String auth = uri.getAuthority(); 1393 if (auth != null) { 1394 return acquireProvider(mContext, auth); 1395 } 1396 return null; 1397 } 1398 1399 /** 1400 * Returns the content provider for the given content URI if the process 1401 * already has a reference on it. 1402 * 1403 * @param uri The URI to a content provider 1404 * @return The ContentProvider for the given URI, or null if no content provider is found. 1405 * @hide 1406 */ 1407 public final IContentProvider acquireExistingProvider(Uri uri) { 1408 if (!SCHEME_CONTENT.equals(uri.getScheme())) { 1409 return null; 1410 } 1411 final String auth = uri.getAuthority(); 1412 if (auth != null) { 1413 return acquireExistingProvider(mContext, auth); 1414 } 1415 return null; 1416 } 1417 1418 /** 1419 * @hide 1420 */ 1421 public final IContentProvider acquireProvider(String name) { 1422 if (name == null) { 1423 return null; 1424 } 1425 return acquireProvider(mContext, name); 1426 } 1427 1428 /** 1429 * Returns the content provider for the given content URI. 1430 * 1431 * @param uri The URI to a content provider 1432 * @return The ContentProvider for the given URI, or null if no content provider is found. 1433 * @hide 1434 */ 1435 public final IContentProvider acquireUnstableProvider(Uri uri) { 1436 if (!SCHEME_CONTENT.equals(uri.getScheme())) { 1437 return null; 1438 } 1439 String auth = uri.getAuthority(); 1440 if (auth != null) { 1441 return acquireUnstableProvider(mContext, uri.getAuthority()); 1442 } 1443 return null; 1444 } 1445 1446 /** 1447 * @hide 1448 */ 1449 public final IContentProvider acquireUnstableProvider(String name) { 1450 if (name == null) { 1451 return null; 1452 } 1453 return acquireUnstableProvider(mContext, name); 1454 } 1455 1456 /** 1457 * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider} 1458 * that services the content at uri, starting the provider if necessary. Returns 1459 * null if there is no provider associated wih the uri. The caller must indicate that they are 1460 * done with the provider by calling {@link ContentProviderClient#release} which will allow 1461 * the system to release the provider it it determines that there is no other reason for 1462 * keeping it active. 1463 * @param uri specifies which provider should be acquired 1464 * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider} 1465 * that services the content at uri or null if there isn't one. 1466 */ 1467 public final ContentProviderClient acquireContentProviderClient(Uri uri) { 1468 IContentProvider provider = acquireProvider(uri); 1469 if (provider != null) { 1470 return new ContentProviderClient(this, provider, true); 1471 } 1472 1473 return null; 1474 } 1475 1476 /** 1477 * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider} 1478 * with the authority of name, starting the provider if necessary. Returns 1479 * null if there is no provider associated wih the uri. The caller must indicate that they are 1480 * done with the provider by calling {@link ContentProviderClient#release} which will allow 1481 * the system to release the provider it it determines that there is no other reason for 1482 * keeping it active. 1483 * @param name specifies which provider should be acquired 1484 * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider} 1485 * with the authority of name or null if there isn't one. 1486 */ 1487 public final ContentProviderClient acquireContentProviderClient(String name) { 1488 IContentProvider provider = acquireProvider(name); 1489 if (provider != null) { 1490 return new ContentProviderClient(this, provider, true); 1491 } 1492 1493 return null; 1494 } 1495 1496 /** 1497 * Like {@link #acquireContentProviderClient(Uri)}, but for use when you do 1498 * not trust the stability of the target content provider. This turns off 1499 * the mechanism in the platform clean up processes that are dependent on 1500 * a content provider if that content provider's process goes away. Normally 1501 * you can safely assume that once you have acquired a provider, you can freely 1502 * use it as needed and it won't disappear, even if your process is in the 1503 * background. If using this method, you need to take care to deal with any 1504 * failures when communicating with the provider, and be sure to close it 1505 * so that it can be re-opened later. In particular, catching a 1506 * {@link android.os.DeadObjectException} from the calls there will let you 1507 * know that the content provider has gone away; at that point the current 1508 * ContentProviderClient object is invalid, and you should release it. You 1509 * can acquire a new one if you would like to try to restart the provider 1510 * and perform new operations on it. 1511 */ 1512 public final ContentProviderClient acquireUnstableContentProviderClient(Uri uri) { 1513 IContentProvider provider = acquireUnstableProvider(uri); 1514 if (provider != null) { 1515 return new ContentProviderClient(this, provider, false); 1516 } 1517 1518 return null; 1519 } 1520 1521 /** 1522 * Like {@link #acquireContentProviderClient(String)}, but for use when you do 1523 * not trust the stability of the target content provider. This turns off 1524 * the mechanism in the platform clean up processes that are dependent on 1525 * a content provider if that content provider's process goes away. Normally 1526 * you can safely assume that once you have acquired a provider, you can freely 1527 * use it as needed and it won't disappear, even if your process is in the 1528 * background. If using this method, you need to take care to deal with any 1529 * failures when communicating with the provider, and be sure to close it 1530 * so that it can be re-opened later. In particular, catching a 1531 * {@link android.os.DeadObjectException} from the calls there will let you 1532 * know that the content provider has gone away; at that point the current 1533 * ContentProviderClient object is invalid, and you should release it. You 1534 * can acquire a new one if you would like to try to restart the provider 1535 * and perform new operations on it. 1536 */ 1537 public final ContentProviderClient acquireUnstableContentProviderClient(String name) { 1538 IContentProvider provider = acquireUnstableProvider(name); 1539 if (provider != null) { 1540 return new ContentProviderClient(this, provider, false); 1541 } 1542 1543 return null; 1544 } 1545 1546 /** 1547 * Register an observer class that gets callbacks when data identified by a 1548 * given content URI changes. 1549 * 1550 * @param uri The URI to watch for changes. This can be a specific row URI, or a base URI 1551 * for a whole class of content. 1552 * @param notifyForDescendents If <code>true</code> changes to URIs beginning with <code>uri</code> 1553 * will also cause notifications to be sent. If <code>false</code> only changes to the exact URI 1554 * specified by <em>uri</em> will cause notifications to be sent. If true, than any URI values 1555 * at or below the specified URI will also trigger a match. 1556 * @param observer The object that receives callbacks when changes occur. 1557 * @see #unregisterContentObserver 1558 */ 1559 public final void registerContentObserver(Uri uri, boolean notifyForDescendents, 1560 ContentObserver observer) 1561 { 1562 registerContentObserver(uri, notifyForDescendents, observer, UserHandle.myUserId()); 1563 } 1564 1565 /** @hide - designated user version */ 1566 public final void registerContentObserver(Uri uri, boolean notifyForDescendents, 1567 ContentObserver observer, int userHandle) 1568 { 1569 try { 1570 getContentService().registerContentObserver(uri, notifyForDescendents, 1571 observer.getContentObserver(), userHandle); 1572 } catch (RemoteException e) { 1573 } 1574 } 1575 1576 /** 1577 * Unregisters a change observer. 1578 * 1579 * @param observer The previously registered observer that is no longer needed. 1580 * @see #registerContentObserver 1581 */ 1582 public final void unregisterContentObserver(ContentObserver observer) { 1583 try { 1584 IContentObserver contentObserver = observer.releaseContentObserver(); 1585 if (contentObserver != null) { 1586 getContentService().unregisterContentObserver( 1587 contentObserver); 1588 } 1589 } catch (RemoteException e) { 1590 } 1591 } 1592 1593 /** 1594 * Notify registered observers that a row was updated and attempt to sync changes 1595 * to the network. 1596 * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}. 1597 * By default, CursorAdapter objects will get this notification. 1598 * 1599 * @param uri The uri of the content that was changed. 1600 * @param observer The observer that originated the change, may be <code>null</null>. 1601 * The observer that originated the change will only receive the notification if it 1602 * has requested to receive self-change notifications by implementing 1603 * {@link ContentObserver#deliverSelfNotifications()} to return true. 1604 */ 1605 public void notifyChange(Uri uri, ContentObserver observer) { 1606 notifyChange(uri, observer, true /* sync to network */); 1607 } 1608 1609 /** 1610 * Notify registered observers that a row was updated. 1611 * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}. 1612 * By default, CursorAdapter objects will get this notification. 1613 * If syncToNetwork is true, this will attempt to schedule a local sync using the sync 1614 * adapter that's registered for the authority of the provided uri. No account will be 1615 * passed to the sync adapter, so all matching accounts will be synchronized. 1616 * 1617 * @param uri The uri of the content that was changed. 1618 * @param observer The observer that originated the change, may be <code>null</null>. 1619 * The observer that originated the change will only receive the notification if it 1620 * has requested to receive self-change notifications by implementing 1621 * {@link ContentObserver#deliverSelfNotifications()} to return true. 1622 * @param syncToNetwork If true, attempt to sync the change to the network. 1623 * @see #requestSync(android.accounts.Account, String, android.os.Bundle) 1624 */ 1625 public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) { 1626 notifyChange(uri, observer, syncToNetwork, UserHandle.getCallingUserId()); 1627 } 1628 1629 /** 1630 * Notify registered observers within the designated user(s) that a row was updated. 1631 * 1632 * @hide 1633 */ 1634 public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork, 1635 int userHandle) { 1636 try { 1637 getContentService().notifyChange( 1638 uri, observer == null ? null : observer.getContentObserver(), 1639 observer != null && observer.deliverSelfNotifications(), syncToNetwork, 1640 userHandle); 1641 } catch (RemoteException e) { 1642 } 1643 } 1644 1645 /** 1646 * Return list of all Uri permissions that have been granted <em>to</em> the 1647 * calling package, and which exactly match the requested flags. For 1648 * example, to return all Uris that the calling application has 1649 * <em>non-persistent</em> read access to: 1650 * 1651 * <pre class="prettyprint"> 1652 * getIncomingUriPermissionGrants(Intent.FLAG_GRANT_READ_URI_PERMISSION, 1653 * Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION); 1654 * </pre> 1655 * 1656 * @param modeFlags any combination of 1657 * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}, 1658 * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, or 1659 * {@link Intent#FLAG_PERSIST_GRANT_URI_PERMISSION}. 1660 * @param modeMask mask indicating which flags must match. 1661 */ 1662 public Uri[] getIncomingUriPermissionGrants(int modeFlags, int modeMask) { 1663 try { 1664 return ActivityManagerNative.getDefault() 1665 .getGrantedUriPermissions(null, getPackageName(), modeFlags, modeMask); 1666 } catch (RemoteException e) { 1667 return new Uri[0]; 1668 } 1669 } 1670 1671 /** 1672 * Return list of all Uri permissions that have been granted <em>from</em> the 1673 * calling package, and which exactly match the requested flags. For 1674 * example, to return all Uris that the calling application has granted 1675 * <em>non-persistent</em> read access to: 1676 * 1677 * <pre class="prettyprint"> 1678 * getOutgoingUriPermissionGrants(Intent.FLAG_GRANT_READ_URI_PERMISSION, 1679 * Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION); 1680 * </pre> 1681 * 1682 * @param modeFlags any combination of 1683 * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}, 1684 * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, or 1685 * {@link Intent#FLAG_PERSIST_GRANT_URI_PERMISSION}. 1686 * @param modeMask mask indicating which flags must match. 1687 */ 1688 public Uri[] getOutgoingUriPermissionGrants(int modeFlags, int modeMask) { 1689 try { 1690 return ActivityManagerNative.getDefault() 1691 .getGrantedUriPermissions(getPackageName(), null, modeFlags, modeMask); 1692 } catch (RemoteException e) { 1693 return new Uri[0]; 1694 } 1695 } 1696 1697 /** 1698 * Start an asynchronous sync operation. If you want to monitor the progress 1699 * of the sync you may register a SyncObserver. Only values of the following 1700 * types may be used in the extras bundle: 1701 * <ul> 1702 * <li>Integer</li> 1703 * <li>Long</li> 1704 * <li>Boolean</li> 1705 * <li>Float</li> 1706 * <li>Double</li> 1707 * <li>String</li> 1708 * <li>Account</li> 1709 * <li>null</li> 1710 * </ul> 1711 * 1712 * @param uri the uri of the provider to sync or null to sync all providers. 1713 * @param extras any extras to pass to the SyncAdapter. 1714 * @deprecated instead use 1715 * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)} 1716 */ 1717 @Deprecated 1718 public void startSync(Uri uri, Bundle extras) { 1719 Account account = null; 1720 if (extras != null) { 1721 String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT); 1722 if (!TextUtils.isEmpty(accountName)) { 1723 account = new Account(accountName, "com.google"); 1724 } 1725 extras.remove(SYNC_EXTRAS_ACCOUNT); 1726 } 1727 requestSync(account, uri != null ? uri.getAuthority() : null, extras); 1728 } 1729 1730 /** 1731 * Start an asynchronous sync operation. If you want to monitor the progress 1732 * of the sync you may register a SyncObserver. Only values of the following 1733 * types may be used in the extras bundle: 1734 * <ul> 1735 * <li>Integer</li> 1736 * <li>Long</li> 1737 * <li>Boolean</li> 1738 * <li>Float</li> 1739 * <li>Double</li> 1740 * <li>String</li> 1741 * <li>Account</li> 1742 * <li>null</li> 1743 * </ul> 1744 * 1745 * @param account which account should be synced 1746 * @param authority which authority should be synced 1747 * @param extras any extras to pass to the SyncAdapter. 1748 */ 1749 public static void requestSync(Account account, String authority, Bundle extras) { 1750 if (extras == null) { 1751 throw new IllegalArgumentException("Must specify extras."); 1752 } 1753 SyncRequest request = 1754 new SyncRequest.Builder() 1755 .setSyncAdapter(account, authority) 1756 .setExtras(extras) 1757 .syncOnce() 1758 .build(); 1759 requestSync(request); 1760 } 1761 1762 /** 1763 * Register a sync with the SyncManager. These requests are built using the 1764 * {@link SyncRequest.Builder}. 1765 * 1766 * @param request The immutable SyncRequest object containing the sync parameters. Use 1767 * {@link SyncRequest.Builder} to construct these. 1768 */ 1769 public static void requestSync(SyncRequest request) { 1770 try { 1771 getContentService().sync(request); 1772 } catch(RemoteException e) { 1773 // Shouldn't happen. 1774 } 1775 } 1776 1777 /** 1778 * Check that only values of the following types are in the Bundle: 1779 * <ul> 1780 * <li>Integer</li> 1781 * <li>Long</li> 1782 * <li>Boolean</li> 1783 * <li>Float</li> 1784 * <li>Double</li> 1785 * <li>String</li> 1786 * <li>Account</li> 1787 * <li>null</li> 1788 * </ul> 1789 * @param extras the Bundle to check 1790 */ 1791 public static void validateSyncExtrasBundle(Bundle extras) { 1792 try { 1793 for (String key : extras.keySet()) { 1794 Object value = extras.get(key); 1795 if (value == null) continue; 1796 if (value instanceof Long) continue; 1797 if (value instanceof Integer) continue; 1798 if (value instanceof Boolean) continue; 1799 if (value instanceof Float) continue; 1800 if (value instanceof Double) continue; 1801 if (value instanceof String) continue; 1802 if (value instanceof Account) continue; 1803 throw new IllegalArgumentException("unexpected value type: " 1804 + value.getClass().getName()); 1805 } 1806 } catch (IllegalArgumentException e) { 1807 throw e; 1808 } catch (RuntimeException exc) { 1809 throw new IllegalArgumentException("error unparceling Bundle", exc); 1810 } 1811 } 1812 1813 /** 1814 * Cancel any active or pending syncs that match the Uri. If the uri is null then 1815 * all syncs will be canceled. 1816 * 1817 * @param uri the uri of the provider to sync or null to sync all providers. 1818 * @deprecated instead use {@link #cancelSync(android.accounts.Account, String)} 1819 */ 1820 @Deprecated 1821 public void cancelSync(Uri uri) { 1822 cancelSync(null /* all accounts */, uri != null ? uri.getAuthority() : null); 1823 } 1824 1825 /** 1826 * Cancel any active or pending syncs that match account and authority. The account and 1827 * authority can each independently be set to null, which means that syncs with any account 1828 * or authority, respectively, will match. 1829 * 1830 * @param account filters the syncs that match by this account 1831 * @param authority filters the syncs that match by this authority 1832 */ 1833 public static void cancelSync(Account account, String authority) { 1834 try { 1835 getContentService().cancelSync(account, authority); 1836 } catch (RemoteException e) { 1837 } 1838 } 1839 1840 /** 1841 * Get information about the SyncAdapters that are known to the system. 1842 * @return an array of SyncAdapters that have registered with the system 1843 */ 1844 public static SyncAdapterType[] getSyncAdapterTypes() { 1845 try { 1846 return getContentService().getSyncAdapterTypes(); 1847 } catch (RemoteException e) { 1848 throw new RuntimeException("the ContentService should always be reachable", e); 1849 } 1850 } 1851 1852 /** 1853 * Check if the provider should be synced when a network tickle is received 1854 * <p>This method requires the caller to hold the permission 1855 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}. 1856 * 1857 * @param account the account whose setting we are querying 1858 * @param authority the provider whose setting we are querying 1859 * @return true if the provider should be synced when a network tickle is received 1860 */ 1861 public static boolean getSyncAutomatically(Account account, String authority) { 1862 try { 1863 return getContentService().getSyncAutomatically(account, authority); 1864 } catch (RemoteException e) { 1865 throw new RuntimeException("the ContentService should always be reachable", e); 1866 } 1867 } 1868 1869 /** 1870 * Set whether or not the provider is synced when it receives a network tickle. 1871 * <p>This method requires the caller to hold the permission 1872 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 1873 * 1874 * @param account the account whose setting we are querying 1875 * @param authority the provider whose behavior is being controlled 1876 * @param sync true if the provider should be synced when tickles are received for it 1877 */ 1878 public static void setSyncAutomatically(Account account, String authority, boolean sync) { 1879 try { 1880 getContentService().setSyncAutomatically(account, authority, sync); 1881 } catch (RemoteException e) { 1882 // exception ignored; if this is thrown then it means the runtime is in the midst of 1883 // being restarted 1884 } 1885 } 1886 1887 /** 1888 * Specifies that a sync should be requested with the specified the account, authority, 1889 * and extras at the given frequency. If there is already another periodic sync scheduled 1890 * with the account, authority and extras then a new periodic sync won't be added, instead 1891 * the frequency of the previous one will be updated. 1892 * <p> 1893 * These periodic syncs honor the "syncAutomatically" and "masterSyncAutomatically" settings. 1894 * Although these sync are scheduled at the specified frequency, it may take longer for it to 1895 * actually be started if other syncs are ahead of it in the sync operation queue. This means 1896 * that the actual start time may drift. 1897 * <p> 1898 * Periodic syncs are not allowed to have any of {@link #SYNC_EXTRAS_DO_NOT_RETRY}, 1899 * {@link #SYNC_EXTRAS_IGNORE_BACKOFF}, {@link #SYNC_EXTRAS_IGNORE_SETTINGS}, 1900 * {@link #SYNC_EXTRAS_INITIALIZE}, {@link #SYNC_EXTRAS_FORCE}, 1901 * {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL} set to true. 1902 * If any are supplied then an {@link IllegalArgumentException} will be thrown. 1903 * <p>As of API level 19 this function introduces a default flexibility of ~4% (up to a maximum 1904 * of one hour in the day) into the requested period. Use 1905 * {@link SyncRequest.Builder#syncPeriodic(long, long)} to set this flexibility manually. 1906 * 1907 * <p>This method requires the caller to hold the permission 1908 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 1909 * 1910 * @param account the account to specify in the sync 1911 * @param authority the provider to specify in the sync request 1912 * @param extras extra parameters to go along with the sync request 1913 * @param pollFrequency how frequently the sync should be performed, in seconds. 1914 * @throws IllegalArgumentException if an illegal extra was set or if any of the parameters 1915 * are null. 1916 */ 1917 public static void addPeriodicSync(Account account, String authority, Bundle extras, 1918 long pollFrequency) { 1919 validateSyncExtrasBundle(extras); 1920 if (account == null) { 1921 throw new IllegalArgumentException("account must not be null"); 1922 } 1923 if (authority == null) { 1924 throw new IllegalArgumentException("authority must not be null"); 1925 } 1926 if (extras.getBoolean(SYNC_EXTRAS_MANUAL, false) 1927 || extras.getBoolean(SYNC_EXTRAS_DO_NOT_RETRY, false) 1928 || extras.getBoolean(SYNC_EXTRAS_IGNORE_BACKOFF, false) 1929 || extras.getBoolean(SYNC_EXTRAS_IGNORE_SETTINGS, false) 1930 || extras.getBoolean(SYNC_EXTRAS_INITIALIZE, false) 1931 || extras.getBoolean(SYNC_EXTRAS_FORCE, false) 1932 || extras.getBoolean(SYNC_EXTRAS_EXPEDITED, false)) { 1933 throw new IllegalArgumentException("illegal extras were set"); 1934 } 1935 try { 1936 getContentService().addPeriodicSync(account, authority, extras, pollFrequency); 1937 } catch (RemoteException e) { 1938 // exception ignored; if this is thrown then it means the runtime is in the midst of 1939 // being restarted 1940 } 1941 } 1942 1943 /** 1944 * Remove a periodic sync. Has no affect if account, authority and extras don't match 1945 * an existing periodic sync. 1946 * <p>This method requires the caller to hold the permission 1947 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 1948 * 1949 * @param account the account of the periodic sync to remove 1950 * @param authority the provider of the periodic sync to remove 1951 * @param extras the extras of the periodic sync to remove 1952 */ 1953 public static void removePeriodicSync(Account account, String authority, Bundle extras) { 1954 validateSyncExtrasBundle(extras); 1955 if (account == null) { 1956 throw new IllegalArgumentException("account must not be null"); 1957 } 1958 if (authority == null) { 1959 throw new IllegalArgumentException("authority must not be null"); 1960 } 1961 try { 1962 getContentService().removePeriodicSync(account, authority, extras); 1963 } catch (RemoteException e) { 1964 throw new RuntimeException("the ContentService should always be reachable", e); 1965 } 1966 } 1967 1968 /** 1969 * Get the list of information about the periodic syncs for the given account and authority. 1970 * <p>This method requires the caller to hold the permission 1971 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}. 1972 * 1973 * @param account the account whose periodic syncs we are querying 1974 * @param authority the provider whose periodic syncs we are querying 1975 * @return a list of PeriodicSync objects. This list may be empty but will never be null. 1976 */ 1977 public static List<PeriodicSync> getPeriodicSyncs(Account account, String authority) { 1978 if (account == null) { 1979 throw new IllegalArgumentException("account must not be null"); 1980 } 1981 if (authority == null) { 1982 throw new IllegalArgumentException("authority must not be null"); 1983 } 1984 try { 1985 return getContentService().getPeriodicSyncs(account, authority); 1986 } catch (RemoteException e) { 1987 throw new RuntimeException("the ContentService should always be reachable", e); 1988 } 1989 } 1990 1991 /** 1992 * Check if this account/provider is syncable. 1993 * <p>This method requires the caller to hold the permission 1994 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}. 1995 * @return >0 if it is syncable, 0 if not, and <0 if the state isn't known yet. 1996 */ 1997 public static int getIsSyncable(Account account, String authority) { 1998 try { 1999 return getContentService().getIsSyncable(account, authority); 2000 } catch (RemoteException e) { 2001 throw new RuntimeException("the ContentService should always be reachable", e); 2002 } 2003 } 2004 2005 /** 2006 * Set whether this account/provider is syncable. 2007 * <p>This method requires the caller to hold the permission 2008 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 2009 * @param syncable >0 denotes syncable, 0 means not syncable, <0 means unknown 2010 */ 2011 public static void setIsSyncable(Account account, String authority, int syncable) { 2012 try { 2013 getContentService().setIsSyncable(account, authority, syncable); 2014 } catch (RemoteException e) { 2015 // exception ignored; if this is thrown then it means the runtime is in the midst of 2016 // being restarted 2017 } 2018 } 2019 2020 /** 2021 * Gets the master auto-sync setting that applies to all the providers and accounts. 2022 * If this is false then the per-provider auto-sync setting is ignored. 2023 * <p>This method requires the caller to hold the permission 2024 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}. 2025 * 2026 * @return the master auto-sync setting that applies to all the providers and accounts 2027 */ 2028 public static boolean getMasterSyncAutomatically() { 2029 try { 2030 return getContentService().getMasterSyncAutomatically(); 2031 } catch (RemoteException e) { 2032 throw new RuntimeException("the ContentService should always be reachable", e); 2033 } 2034 } 2035 2036 /** 2037 * Sets the master auto-sync setting that applies to all the providers and accounts. 2038 * If this is false then the per-provider auto-sync setting is ignored. 2039 * <p>This method requires the caller to hold the permission 2040 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 2041 * 2042 * @param sync the master auto-sync setting that applies to all the providers and accounts 2043 */ 2044 public static void setMasterSyncAutomatically(boolean sync) { 2045 try { 2046 getContentService().setMasterSyncAutomatically(sync); 2047 } catch (RemoteException e) { 2048 // exception ignored; if this is thrown then it means the runtime is in the midst of 2049 // being restarted 2050 } 2051 } 2052 2053 /** 2054 * Returns true if there is currently a sync operation for the given 2055 * account or authority in the pending list, or actively being processed. 2056 * <p>This method requires the caller to hold the permission 2057 * {@link android.Manifest.permission#READ_SYNC_STATS}. 2058 * @param account the account whose setting we are querying 2059 * @param authority the provider whose behavior is being queried 2060 * @return true if a sync is active for the given account or authority. 2061 */ 2062 public static boolean isSyncActive(Account account, String authority) { 2063 try { 2064 return getContentService().isSyncActive(account, authority); 2065 } catch (RemoteException e) { 2066 throw new RuntimeException("the ContentService should always be reachable", e); 2067 } 2068 } 2069 2070 /** 2071 * If a sync is active returns the information about it, otherwise returns null. 2072 * <p> 2073 * This method requires the caller to hold the permission 2074 * {@link android.Manifest.permission#READ_SYNC_STATS}. 2075 * <p> 2076 * @return the SyncInfo for the currently active sync or null if one is not active. 2077 * @deprecated 2078 * Since multiple concurrent syncs are now supported you should use 2079 * {@link #getCurrentSyncs()} to get the accurate list of current syncs. 2080 * This method returns the first item from the list of current syncs 2081 * or null if there are none. 2082 */ 2083 @Deprecated 2084 public static SyncInfo getCurrentSync() { 2085 try { 2086 final List<SyncInfo> syncs = getContentService().getCurrentSyncs(); 2087 if (syncs.isEmpty()) { 2088 return null; 2089 } 2090 return syncs.get(0); 2091 } catch (RemoteException e) { 2092 throw new RuntimeException("the ContentService should always be reachable", e); 2093 } 2094 } 2095 2096 /** 2097 * Returns a list with information about all the active syncs. This list will be empty 2098 * if there are no active syncs. 2099 * <p> 2100 * This method requires the caller to hold the permission 2101 * {@link android.Manifest.permission#READ_SYNC_STATS}. 2102 * <p> 2103 * @return a List of SyncInfo objects for the currently active syncs. 2104 */ 2105 public static List<SyncInfo> getCurrentSyncs() { 2106 try { 2107 return getContentService().getCurrentSyncs(); 2108 } catch (RemoteException e) { 2109 throw new RuntimeException("the ContentService should always be reachable", e); 2110 } 2111 } 2112 2113 /** 2114 * Returns the status that matches the authority. 2115 * @param account the account whose setting we are querying 2116 * @param authority the provider whose behavior is being queried 2117 * @return the SyncStatusInfo for the authority, or null if none exists 2118 * @hide 2119 */ 2120 public static SyncStatusInfo getSyncStatus(Account account, String authority) { 2121 try { 2122 return getContentService().getSyncStatus(account, authority); 2123 } catch (RemoteException e) { 2124 throw new RuntimeException("the ContentService should always be reachable", e); 2125 } 2126 } 2127 2128 /** 2129 * Return true if the pending status is true of any matching authorities. 2130 * <p>This method requires the caller to hold the permission 2131 * {@link android.Manifest.permission#READ_SYNC_STATS}. 2132 * @param account the account whose setting we are querying 2133 * @param authority the provider whose behavior is being queried 2134 * @return true if there is a pending sync with the matching account and authority 2135 */ 2136 public static boolean isSyncPending(Account account, String authority) { 2137 try { 2138 return getContentService().isSyncPending(account, authority); 2139 } catch (RemoteException e) { 2140 throw new RuntimeException("the ContentService should always be reachable", e); 2141 } 2142 } 2143 2144 /** 2145 * Request notifications when the different aspects of the SyncManager change. The 2146 * different items that can be requested are: 2147 * <ul> 2148 * <li> {@link #SYNC_OBSERVER_TYPE_PENDING} 2149 * <li> {@link #SYNC_OBSERVER_TYPE_ACTIVE} 2150 * <li> {@link #SYNC_OBSERVER_TYPE_SETTINGS} 2151 * </ul> 2152 * The caller can set one or more of the status types in the mask for any 2153 * given listener registration. 2154 * @param mask the status change types that will cause the callback to be invoked 2155 * @param callback observer to be invoked when the status changes 2156 * @return a handle that can be used to remove the listener at a later time 2157 */ 2158 public static Object addStatusChangeListener(int mask, final SyncStatusObserver callback) { 2159 if (callback == null) { 2160 throw new IllegalArgumentException("you passed in a null callback"); 2161 } 2162 try { 2163 ISyncStatusObserver.Stub observer = new ISyncStatusObserver.Stub() { 2164 public void onStatusChanged(int which) throws RemoteException { 2165 callback.onStatusChanged(which); 2166 } 2167 }; 2168 getContentService().addStatusChangeListener(mask, observer); 2169 return observer; 2170 } catch (RemoteException e) { 2171 throw new RuntimeException("the ContentService should always be reachable", e); 2172 } 2173 } 2174 2175 /** 2176 * Remove a previously registered status change listener. 2177 * @param handle the handle that was returned by {@link #addStatusChangeListener} 2178 */ 2179 public static void removeStatusChangeListener(Object handle) { 2180 if (handle == null) { 2181 throw new IllegalArgumentException("you passed in a null handle"); 2182 } 2183 try { 2184 getContentService().removeStatusChangeListener((ISyncStatusObserver.Stub) handle); 2185 } catch (RemoteException e) { 2186 // exception ignored; if this is thrown then it means the runtime is in the midst of 2187 // being restarted 2188 } 2189 } 2190 2191 /** 2192 * Returns sampling percentage for a given duration. 2193 * 2194 * Always returns at least 1%. 2195 */ 2196 private int samplePercentForDuration(long durationMillis) { 2197 if (durationMillis >= SLOW_THRESHOLD_MILLIS) { 2198 return 100; 2199 } 2200 return (int) (100 * durationMillis / SLOW_THRESHOLD_MILLIS) + 1; 2201 } 2202 2203 private void maybeLogQueryToEventLog(long durationMillis, 2204 Uri uri, String[] projection, 2205 String selection, String sortOrder) { 2206 if (!ENABLE_CONTENT_SAMPLE) return; 2207 int samplePercent = samplePercentForDuration(durationMillis); 2208 if (samplePercent < 100) { 2209 synchronized (mRandom) { 2210 if (mRandom.nextInt(100) >= samplePercent) { 2211 return; 2212 } 2213 } 2214 } 2215 2216 StringBuilder projectionBuffer = new StringBuilder(100); 2217 if (projection != null) { 2218 for (int i = 0; i < projection.length; ++i) { 2219 // Note: not using a comma delimiter here, as the 2220 // multiple arguments to EventLog.writeEvent later 2221 // stringify with a comma delimiter, which would make 2222 // parsing uglier later. 2223 if (i != 0) projectionBuffer.append('/'); 2224 projectionBuffer.append(projection[i]); 2225 } 2226 } 2227 2228 // ActivityThread.currentPackageName() only returns non-null if the 2229 // current thread is an application main thread. This parameter tells 2230 // us whether an event loop is blocked, and if so, which app it is. 2231 String blockingPackage = AppGlobals.getInitialPackage(); 2232 2233 EventLog.writeEvent( 2234 EventLogTags.CONTENT_QUERY_SAMPLE, 2235 uri.toString(), 2236 projectionBuffer.toString(), 2237 selection != null ? selection : "", 2238 sortOrder != null ? sortOrder : "", 2239 durationMillis, 2240 blockingPackage != null ? blockingPackage : "", 2241 samplePercent); 2242 } 2243 2244 private void maybeLogUpdateToEventLog( 2245 long durationMillis, Uri uri, String operation, String selection) { 2246 if (!ENABLE_CONTENT_SAMPLE) return; 2247 int samplePercent = samplePercentForDuration(durationMillis); 2248 if (samplePercent < 100) { 2249 synchronized (mRandom) { 2250 if (mRandom.nextInt(100) >= samplePercent) { 2251 return; 2252 } 2253 } 2254 } 2255 String blockingPackage = AppGlobals.getInitialPackage(); 2256 EventLog.writeEvent( 2257 EventLogTags.CONTENT_UPDATE_SAMPLE, 2258 uri.toString(), 2259 operation, 2260 selection != null ? selection : "", 2261 durationMillis, 2262 blockingPackage != null ? blockingPackage : "", 2263 samplePercent); 2264 } 2265 2266 private final class CursorWrapperInner extends CrossProcessCursorWrapper { 2267 private final IContentProvider mContentProvider; 2268 public static final String TAG="CursorWrapperInner"; 2269 2270 private final CloseGuard mCloseGuard = CloseGuard.get(); 2271 private boolean mProviderReleased; 2272 2273 CursorWrapperInner(Cursor cursor, IContentProvider icp) { 2274 super(cursor); 2275 mContentProvider = icp; 2276 mCloseGuard.open("close"); 2277 } 2278 2279 @Override 2280 public void close() { 2281 super.close(); 2282 ContentResolver.this.releaseProvider(mContentProvider); 2283 mProviderReleased = true; 2284 2285 if (mCloseGuard != null) { 2286 mCloseGuard.close(); 2287 } 2288 } 2289 2290 @Override 2291 protected void finalize() throws Throwable { 2292 try { 2293 if (mCloseGuard != null) { 2294 mCloseGuard.warnIfOpen(); 2295 } 2296 2297 if (!mProviderReleased && mContentProvider != null) { 2298 // Even though we are using CloseGuard, log this anyway so that 2299 // application developers always see the message in the log. 2300 Log.w(TAG, "Cursor finalized without prior close()"); 2301 ContentResolver.this.releaseProvider(mContentProvider); 2302 } 2303 } finally { 2304 super.finalize(); 2305 } 2306 } 2307 } 2308 2309 private final class ParcelFileDescriptorInner extends ParcelFileDescriptor { 2310 private final IContentProvider mContentProvider; 2311 private boolean mProviderReleased; 2312 2313 ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) { 2314 super(pfd); 2315 mContentProvider = icp; 2316 } 2317 2318 @Override 2319 public void close() throws IOException { 2320 super.close(); 2321 if (!mProviderReleased) { 2322 ContentResolver.this.releaseProvider(mContentProvider); 2323 mProviderReleased = true; 2324 } 2325 } 2326 } 2327 2328 /** @hide */ 2329 public static final String CONTENT_SERVICE_NAME = "content"; 2330 2331 /** @hide */ 2332 public static IContentService getContentService() { 2333 if (sContentService != null) { 2334 return sContentService; 2335 } 2336 IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME); 2337 if (false) Log.v("ContentService", "default service binder = " + b); 2338 sContentService = IContentService.Stub.asInterface(b); 2339 if (false) Log.v("ContentService", "default service = " + sContentService); 2340 return sContentService; 2341 } 2342 2343 /** @hide */ 2344 public String getPackageName() { 2345 return mPackageName; 2346 } 2347 2348 private static IContentService sContentService; 2349 private final Context mContext; 2350 final String mPackageName; 2351 private static final String TAG = "ContentResolver"; 2352} 2353