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