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