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