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