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