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