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