ContentResolver.java revision da5a3e12f4f8f965c57d6f93c74190f43ea233f3
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.content; 18 19import android.accounts.Account; 20import android.app.ActivityManagerNative; 21import android.app.ActivityThread; 22import android.app.AppGlobals; 23import android.content.pm.PackageManager.NameNotFoundException; 24import android.content.res.AssetFileDescriptor; 25import android.content.res.Resources; 26import android.database.ContentObserver; 27import android.database.CrossProcessCursorWrapper; 28import android.database.Cursor; 29import android.database.IContentObserver; 30import android.net.Uri; 31import android.os.Bundle; 32import android.os.CancellationSignal; 33import android.os.DeadObjectException; 34import android.os.IBinder; 35import android.os.ICancellationSignal; 36import android.os.OperationCanceledException; 37import android.os.ParcelFileDescriptor; 38import android.os.RemoteException; 39import android.os.ServiceManager; 40import android.os.SystemClock; 41import android.os.UserHandle; 42import android.text.TextUtils; 43import android.util.EventLog; 44import android.util.Log; 45 46import dalvik.system.CloseGuard; 47 48import java.io.File; 49import java.io.FileInputStream; 50import java.io.FileNotFoundException; 51import java.io.IOException; 52import java.io.InputStream; 53import java.io.OutputStream; 54import java.util.ArrayList; 55import java.util.List; 56import java.util.Random; 57 58 59/** 60 * This class provides applications access to the content model. 61 * 62 * <div class="special reference"> 63 * <h3>Developer Guides</h3> 64 * <p>For more information about using a ContentResolver with content providers, read the 65 * <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> 66 * developer guide.</p> 67 */ 68public abstract class ContentResolver { 69 /** 70 * @deprecated instead use 71 * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)} 72 */ 73 @Deprecated 74 public static final String SYNC_EXTRAS_ACCOUNT = "account"; 75 76 /** 77 * If this extra is set to true, the sync request will be scheduled 78 * at the front of the sync request queue and without any delay 79 */ 80 public static final String SYNC_EXTRAS_EXPEDITED = "expedited"; 81 82 /** 83 * @deprecated instead use 84 * {@link #SYNC_EXTRAS_MANUAL} 85 */ 86 @Deprecated 87 public static final String SYNC_EXTRAS_FORCE = "force"; 88 89 /** 90 * If this extra is set to true then the sync settings (like getSyncAutomatically()) 91 * are ignored by the sync scheduler. 92 */ 93 public static final String SYNC_EXTRAS_IGNORE_SETTINGS = "ignore_settings"; 94 95 /** 96 * If this extra is set to true then any backoffs for the initial attempt (e.g. due to retries) 97 * are ignored by the sync scheduler. If this request fails and gets rescheduled then the 98 * retries will still honor the backoff. 99 */ 100 public static final String SYNC_EXTRAS_IGNORE_BACKOFF = "ignore_backoff"; 101 102 /** 103 * If this extra is set to true then the request will not be retried if it fails. 104 */ 105 public static final String SYNC_EXTRAS_DO_NOT_RETRY = "do_not_retry"; 106 107 /** 108 * Setting this extra is the equivalent of setting both {@link #SYNC_EXTRAS_IGNORE_SETTINGS} 109 * and {@link #SYNC_EXTRAS_IGNORE_BACKOFF} 110 */ 111 public static final String SYNC_EXTRAS_MANUAL = "force"; 112 113 /** 114 * Indicates that this sync is intended to only upload local changes to the server. 115 * For example, this will be set to true if the sync is initiated by a call to 116 * {@link ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)} 117 */ 118 public static final String SYNC_EXTRAS_UPLOAD = "upload"; 119 120 /** 121 * Indicates that the sync adapter should proceed with the delete operations, 122 * even if it determines that there are too many. 123 * See {@link SyncResult#tooManyDeletions} 124 */ 125 public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override"; 126 127 /** 128 * Indicates that the sync adapter should not proceed with the delete operations, 129 * if it determines that there are too many. 130 * See {@link SyncResult#tooManyDeletions} 131 */ 132 public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions"; 133 134 /* Extensions to API. TODO: Not clear if we will keep these as public flags. */ 135 /** {@hide} User-specified flag for expected upload size. */ 136 public static final String SYNC_EXTRAS_EXPECTED_UPLOAD = "expected_upload"; 137 138 /** {@hide} User-specified flag for expected download size. */ 139 public static final String SYNC_EXTRAS_EXPECTED_DOWNLOAD = "expected_download"; 140 141 /** {@hide} Priority of this sync with respect to other syncs scheduled for this application. */ 142 public static final String SYNC_EXTRAS_PRIORITY = "sync_priority"; 143 144 /** {@hide} Flag to allow sync to occur on metered network. */ 145 public static final String SYNC_EXTRAS_ALLOW_METERED = "allow_metered"; 146 147 /** 148 * Set by the SyncManager to request that the SyncAdapter initialize itself for 149 * the given account/authority pair. One required initialization step is to 150 * ensure that {@link #setIsSyncable(android.accounts.Account, String, int)} has been 151 * called with a >= 0 value. When this flag is set the SyncAdapter does not need to 152 * do a full sync, though it is allowed to do so. 153 */ 154 public static final String SYNC_EXTRAS_INITIALIZE = "initialize"; 155 156 /** @hide */ 157 public static final Intent ACTION_SYNC_CONN_STATUS_CHANGED = 158 new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED"); 159 160 public static final String SCHEME_CONTENT = "content"; 161 public static final String SCHEME_ANDROID_RESOURCE = "android.resource"; 162 public static final String SCHEME_FILE = "file"; 163 164 /** 165 * This is the Android platform's base MIME type for a content: URI 166 * containing a Cursor of a single item. Applications should use this 167 * as the base type along with their own sub-type of their content: URIs 168 * that represent a particular item. For example, hypothetical IMAP email 169 * client may have a URI 170 * <code>content://com.company.provider.imap/inbox/1</code> for a particular 171 * message in the inbox, whose MIME type would be reported as 172 * <code>CURSOR_ITEM_BASE_TYPE + "/vnd.company.imap-msg"</code> 173 * 174 * <p>Compare with {@link #CURSOR_DIR_BASE_TYPE}. 175 */ 176 public static final String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item"; 177 178 /** 179 * This is the Android platform's base MIME type for a content: URI 180 * containing a Cursor of zero or more items. Applications should use this 181 * as the base type along with their own sub-type of their content: URIs 182 * that represent a directory of items. For example, hypothetical IMAP email 183 * client may have a URI 184 * <code>content://com.company.provider.imap/inbox</code> for all of the 185 * messages in its inbox, whose MIME type would be reported as 186 * <code>CURSOR_DIR_BASE_TYPE + "/vnd.company.imap-msg"</code> 187 * 188 * <p>Note how the base MIME type varies between this and 189 * {@link #CURSOR_ITEM_BASE_TYPE} depending on whether there is 190 * one single item or multiple items in the data set, while the sub-type 191 * remains the same because in either case the data structure contained 192 * in the cursor is the same. 193 */ 194 public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir"; 195 196 /** @hide */ 197 public static final int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1; 198 /** @hide */ 199 public static final int SYNC_ERROR_AUTHENTICATION = 2; 200 /** @hide */ 201 public static final int SYNC_ERROR_IO = 3; 202 /** @hide */ 203 public static final int SYNC_ERROR_PARSE = 4; 204 /** @hide */ 205 public static final int SYNC_ERROR_CONFLICT = 5; 206 /** @hide */ 207 public static final int SYNC_ERROR_TOO_MANY_DELETIONS = 6; 208 /** @hide */ 209 public static final int SYNC_ERROR_TOO_MANY_RETRIES = 7; 210 /** @hide */ 211 public static final int SYNC_ERROR_INTERNAL = 8; 212 213 private static final String[] SYNC_ERROR_NAMES = new String[] { 214 "already-in-progress", 215 "authentication-error", 216 "io-error", 217 "parse-error", 218 "conflict", 219 "too-many-deletions", 220 "too-many-retries", 221 "internal-error", 222 }; 223 224 /** @hide */ 225 public static String syncErrorToString(int error) { 226 if (error < 1 || error > SYNC_ERROR_NAMES.length) { 227 return String.valueOf(error); 228 } 229 return SYNC_ERROR_NAMES[error - 1]; 230 } 231 232 /** @hide */ 233 public static int syncErrorStringToInt(String error) { 234 for (int i = 0, n = SYNC_ERROR_NAMES.length; i < n; i++) { 235 if (SYNC_ERROR_NAMES[i].equals(error)) { 236 return i + 1; 237 } 238 } 239 if (error != null) { 240 try { 241 return Integer.parseInt(error); 242 } catch (NumberFormatException e) { 243 Log.d(TAG, "error parsing sync error: " + error); 244 } 245 } 246 return 0; 247 } 248 249 public static final int SYNC_OBSERVER_TYPE_SETTINGS = 1<<0; 250 public static final int SYNC_OBSERVER_TYPE_PENDING = 1<<1; 251 public static final int SYNC_OBSERVER_TYPE_ACTIVE = 1<<2; 252 /** @hide */ 253 public static final int SYNC_OBSERVER_TYPE_STATUS = 1<<3; 254 /** @hide */ 255 public static final int SYNC_OBSERVER_TYPE_ALL = 0x7fffffff; 256 257 // Always log queries which take 500ms+; shorter queries are 258 // sampled accordingly. 259 private static final boolean ENABLE_CONTENT_SAMPLE = false; 260 private static final int SLOW_THRESHOLD_MILLIS = 500; 261 private final Random mRandom = new Random(); // guarded by itself 262 263 public ContentResolver(Context context) { 264 mContext = context != null ? context : ActivityThread.currentApplication(); 265 mPackageName = mContext.getBasePackageName(); 266 } 267 268 /** @hide */ 269 protected abstract IContentProvider acquireProvider(Context c, String name); 270 /** Providing a default implementation of this, to avoid having to change 271 * a lot of other things, but implementations of ContentResolver should 272 * implement it. @hide */ 273 protected IContentProvider acquireExistingProvider(Context c, String name) { 274 return acquireProvider(c, name); 275 } 276 /** @hide */ 277 public abstract boolean releaseProvider(IContentProvider icp); 278 /** @hide */ 279 protected abstract IContentProvider acquireUnstableProvider(Context c, String name); 280 /** @hide */ 281 public abstract boolean releaseUnstableProvider(IContentProvider icp); 282 /** @hide */ 283 public abstract void unstableProviderDied(IContentProvider icp); 284 285 /** 286 * Return the MIME type of the given content URL. 287 * 288 * @param url A Uri identifying content (either a list or specific type), 289 * using the content:// scheme. 290 * @return A MIME type for the content, or null if the URL is invalid or the type is unknown 291 */ 292 public final String getType(Uri url) { 293 // XXX would like to have an acquireExistingUnstableProvider for this. 294 IContentProvider provider = acquireExistingProvider(url); 295 if (provider != null) { 296 try { 297 return provider.getType(url); 298 } catch (RemoteException e) { 299 return null; 300 } catch (java.lang.Exception e) { 301 Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")"); 302 return null; 303 } finally { 304 releaseProvider(provider); 305 } 306 } 307 308 if (!SCHEME_CONTENT.equals(url.getScheme())) { 309 return null; 310 } 311 312 try { 313 String type = ActivityManagerNative.getDefault().getProviderMimeType( 314 url, UserHandle.myUserId()); 315 return type; 316 } catch (RemoteException e) { 317 // Arbitrary and not worth documenting, as Activity 318 // Manager will kill this process shortly anyway. 319 return null; 320 } catch (java.lang.Exception e) { 321 Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")"); 322 return null; 323 } 324 } 325 326 /** 327 * Query for the possible MIME types for the representations the given 328 * content URL can be returned when opened as as stream with 329 * {@link #openTypedAssetFileDescriptor}. Note that the types here are 330 * not necessarily a superset of the type returned by {@link #getType} -- 331 * many content providers can not return a raw stream for the structured 332 * data that they contain. 333 * 334 * @param url A Uri identifying content (either a list or specific type), 335 * using the content:// scheme. 336 * @param mimeTypeFilter The desired MIME type. This may be a pattern, 337 * such as *\/*, to query for all available MIME types that match the 338 * pattern. 339 * @return Returns an array of MIME type strings for all available 340 * data streams that match the given mimeTypeFilter. If there are none, 341 * null is returned. 342 */ 343 public String[] getStreamTypes(Uri url, String mimeTypeFilter) { 344 IContentProvider provider = acquireProvider(url); 345 if (provider == null) { 346 return null; 347 } 348 349 try { 350 return provider.getStreamTypes(url, mimeTypeFilter); 351 } catch (RemoteException e) { 352 // Arbitrary and not worth documenting, as Activity 353 // Manager will kill this process shortly anyway. 354 return null; 355 } finally { 356 releaseProvider(provider); 357 } 358 } 359 360 /** 361 * <p> 362 * Query the given URI, returning a {@link Cursor} over the result set. 363 * </p> 364 * <p> 365 * For best performance, the caller should follow these guidelines: 366 * <ul> 367 * <li>Provide an explicit projection, to prevent 368 * reading data from storage that aren't going to be used.</li> 369 * <li>Use question mark parameter markers such as 'phone=?' instead of 370 * explicit values in the {@code selection} parameter, so that queries 371 * that differ only by those values will be recognized as the same 372 * for caching purposes.</li> 373 * </ul> 374 * </p> 375 * 376 * @param uri The URI, using the content:// scheme, for the content to 377 * retrieve. 378 * @param projection A list of which columns to return. Passing null will 379 * return all columns, which is inefficient. 380 * @param selection A filter declaring which rows to return, formatted as an 381 * SQL WHERE clause (excluding the WHERE itself). Passing null will 382 * return all rows for the given URI. 383 * @param selectionArgs You may include ?s in selection, which will be 384 * replaced by the values from selectionArgs, in the order that they 385 * appear in the selection. The values will be bound as Strings. 386 * @param sortOrder How to order the rows, formatted as an SQL ORDER BY 387 * clause (excluding the ORDER BY itself). Passing null will use the 388 * default sort order, which may be unordered. 389 * @return A Cursor object, which is positioned before the first entry, or null 390 * @see Cursor 391 */ 392 public final Cursor query(Uri uri, String[] projection, 393 String selection, String[] selectionArgs, String sortOrder) { 394 return query(uri, projection, selection, selectionArgs, sortOrder, null); 395 } 396 397 /** 398 * <p> 399 * Query the given URI, returning a {@link Cursor} over the result set. 400 * </p> 401 * <p> 402 * For best performance, the caller should follow these guidelines: 403 * <ul> 404 * <li>Provide an explicit projection, to prevent 405 * reading data from storage that aren't going to be used.</li> 406 * <li>Use question mark parameter markers such as 'phone=?' instead of 407 * explicit values in the {@code selection} parameter, so that queries 408 * that differ only by those values will be recognized as the same 409 * for caching purposes.</li> 410 * </ul> 411 * </p> 412 * 413 * @param uri The URI, using the content:// scheme, for the content to 414 * retrieve. 415 * @param projection A list of which columns to return. Passing null will 416 * return all columns, which is inefficient. 417 * @param selection A filter declaring which rows to return, formatted as an 418 * SQL WHERE clause (excluding the WHERE itself). Passing null will 419 * return all rows for the given URI. 420 * @param selectionArgs You may include ?s in selection, which will be 421 * replaced by the values from selectionArgs, in the order that they 422 * appear in the selection. The values will be bound as Strings. 423 * @param sortOrder How to order the rows, formatted as an SQL ORDER BY 424 * clause (excluding the ORDER BY itself). Passing null will use the 425 * default sort order, which may be unordered. 426 * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 427 * If the operation is canceled, then {@link OperationCanceledException} will be thrown 428 * when the query is executed. 429 * @return A Cursor object, which is positioned before the first entry, or null 430 * @see Cursor 431 */ 432 public final Cursor query(final Uri uri, String[] projection, 433 String selection, String[] selectionArgs, String sortOrder, 434 CancellationSignal cancellationSignal) { 435 IContentProvider unstableProvider = acquireUnstableProvider(uri); 436 if (unstableProvider == null) { 437 return null; 438 } 439 IContentProvider stableProvider = null; 440 Cursor qCursor = null; 441 try { 442 long startTime = SystemClock.uptimeMillis(); 443 444 ICancellationSignal remoteCancellationSignal = null; 445 if (cancellationSignal != null) { 446 cancellationSignal.throwIfCanceled(); 447 remoteCancellationSignal = unstableProvider.createCancellationSignal(); 448 cancellationSignal.setRemote(remoteCancellationSignal); 449 } 450 try { 451 qCursor = unstableProvider.query(mPackageName, uri, projection, 452 selection, selectionArgs, sortOrder, remoteCancellationSignal); 453 } catch (DeadObjectException e) { 454 // The remote process has died... but we only hold an unstable 455 // reference though, so we might recover!!! Let's try!!!! 456 // This is exciting!!1!!1!!!!1 457 unstableProviderDied(unstableProvider); 458 stableProvider = acquireProvider(uri); 459 if (stableProvider == null) { 460 return null; 461 } 462 qCursor = stableProvider.query(mPackageName, uri, projection, 463 selection, selectionArgs, sortOrder, remoteCancellationSignal); 464 } 465 if (qCursor == null) { 466 return null; 467 } 468 469 // Force query execution. Might fail and throw a runtime exception here. 470 qCursor.getCount(); 471 long durationMillis = SystemClock.uptimeMillis() - startTime; 472 maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder); 473 474 // Wrap the cursor object into CursorWrapperInner object. 475 CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, 476 stableProvider != null ? stableProvider : acquireProvider(uri)); 477 stableProvider = null; 478 qCursor = null; 479 return wrapper; 480 } catch (RemoteException e) { 481 // Arbitrary and not worth documenting, as Activity 482 // Manager will kill this process shortly anyway. 483 return null; 484 } finally { 485 if (qCursor != null) { 486 qCursor.close(); 487 } 488 if (unstableProvider != null) { 489 releaseUnstableProvider(unstableProvider); 490 } 491 if (stableProvider != null) { 492 releaseProvider(stableProvider); 493 } 494 } 495 } 496 497 /** 498 * Open a stream on to the content associated with a content URI. If there 499 * is no data associated with the URI, FileNotFoundException is thrown. 500 * 501 * <h5>Accepts the following URI schemes:</h5> 502 * <ul> 503 * <li>content ({@link #SCHEME_CONTENT})</li> 504 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li> 505 * <li>file ({@link #SCHEME_FILE})</li> 506 * </ul> 507 * 508 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information 509 * on these schemes. 510 * 511 * @param uri The desired URI. 512 * @return InputStream 513 * @throws FileNotFoundException if the provided URI could not be opened. 514 * @see #openAssetFileDescriptor(Uri, String) 515 */ 516 public final InputStream openInputStream(Uri uri) 517 throws FileNotFoundException { 518 String scheme = uri.getScheme(); 519 if (SCHEME_ANDROID_RESOURCE.equals(scheme)) { 520 // Note: left here to avoid breaking compatibility. May be removed 521 // with sufficient testing. 522 OpenResourceIdResult r = getResourceId(uri); 523 try { 524 InputStream stream = r.r.openRawResource(r.id); 525 return stream; 526 } catch (Resources.NotFoundException ex) { 527 throw new FileNotFoundException("Resource does not exist: " + uri); 528 } 529 } else if (SCHEME_FILE.equals(scheme)) { 530 // Note: left here to avoid breaking compatibility. May be removed 531 // with sufficient testing. 532 return new FileInputStream(uri.getPath()); 533 } else { 534 AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r"); 535 try { 536 return fd != null ? fd.createInputStream() : null; 537 } catch (IOException e) { 538 throw new FileNotFoundException("Unable to create stream"); 539 } 540 } 541 } 542 543 /** 544 * Synonym for {@link #openOutputStream(Uri, String) 545 * openOutputStream(uri, "w")}. 546 * @throws FileNotFoundException if the provided URI could not be opened. 547 */ 548 public final OutputStream openOutputStream(Uri uri) 549 throws FileNotFoundException { 550 return openOutputStream(uri, "w"); 551 } 552 553 /** 554 * Open a stream on to the content associated with a content URI. If there 555 * is no data associated with the URI, FileNotFoundException is thrown. 556 * 557 * <h5>Accepts the following URI schemes:</h5> 558 * <ul> 559 * <li>content ({@link #SCHEME_CONTENT})</li> 560 * <li>file ({@link #SCHEME_FILE})</li> 561 * </ul> 562 * 563 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information 564 * on these schemes. 565 * 566 * @param uri The desired URI. 567 * @param mode May be "w", "wa", "rw", or "rwt". 568 * @return OutputStream 569 * @throws FileNotFoundException if the provided URI could not be opened. 570 * @see #openAssetFileDescriptor(Uri, String) 571 */ 572 public final OutputStream openOutputStream(Uri uri, String mode) 573 throws FileNotFoundException { 574 AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode); 575 try { 576 return fd != null ? fd.createOutputStream() : null; 577 } catch (IOException e) { 578 throw new FileNotFoundException("Unable to create stream"); 579 } 580 } 581 582 /** 583 * Open a raw file descriptor to access data under a URI. This 584 * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the 585 * underlying {@link ContentProvider#openFile} 586 * ContentProvider.openFile()} method, so will <em>not</em> work with 587 * providers that return sub-sections of files. If at all possible, 588 * you should use {@link #openAssetFileDescriptor(Uri, String)}. You 589 * will receive a FileNotFoundException exception if the provider returns a 590 * sub-section of a file. 591 * 592 * <h5>Accepts the following URI schemes:</h5> 593 * <ul> 594 * <li>content ({@link #SCHEME_CONTENT})</li> 595 * <li>file ({@link #SCHEME_FILE})</li> 596 * </ul> 597 * 598 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information 599 * on these schemes. 600 * 601 * @param uri The desired URI to open. 602 * @param mode The file mode to use, as per {@link ContentProvider#openFile 603 * ContentProvider.openFile}. 604 * @return Returns a new ParcelFileDescriptor pointing to the file. You 605 * own this descriptor and are responsible for closing it when done. 606 * @throws FileNotFoundException Throws FileNotFoundException if no 607 * file exists under the URI or the mode is invalid. 608 * @see #openAssetFileDescriptor(Uri, String) 609 */ 610 public final ParcelFileDescriptor openFileDescriptor(Uri uri, 611 String mode) throws FileNotFoundException { 612 AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode); 613 if (afd == null) { 614 return null; 615 } 616 617 if (afd.getDeclaredLength() < 0) { 618 // This is a full file! 619 return afd.getParcelFileDescriptor(); 620 } 621 622 // Client can't handle a sub-section of a file, so close what 623 // we got and bail with an exception. 624 try { 625 afd.close(); 626 } catch (IOException e) { 627 } 628 629 throw new FileNotFoundException("Not a whole file"); 630 } 631 632 /** 633 * Open a raw file descriptor to access data under a URI. This 634 * interacts with the underlying {@link ContentProvider#openAssetFile} 635 * method of the provider associated with the given URI, to retrieve any file stored there. 636 * 637 * <h5>Accepts the following URI schemes:</h5> 638 * <ul> 639 * <li>content ({@link #SCHEME_CONTENT})</li> 640 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li> 641 * <li>file ({@link #SCHEME_FILE})</li> 642 * </ul> 643 * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5> 644 * <p> 645 * A Uri object can be used to reference a resource in an APK file. The 646 * Uri should be one of the following formats: 647 * <ul> 648 * <li><code>android.resource://package_name/id_number</code><br/> 649 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml. 650 * For example <code>com.example.myapp</code><br/> 651 * <code>id_number</code> is the int form of the ID.<br/> 652 * The easiest way to construct this form is 653 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre> 654 * </li> 655 * <li><code>android.resource://package_name/type/name</code><br/> 656 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml. 657 * For example <code>com.example.myapp</code><br/> 658 * <code>type</code> is the string form of the resource type. For example, <code>raw</code> 659 * or <code>drawable</code>. 660 * <code>name</code> is the string form of the resource name. That is, whatever the file 661 * name was in your res directory, without the type extension. 662 * The easiest way to construct this form is 663 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre> 664 * </li> 665 * </ul> 666 * 667 * <p>Note that if this function is called for read-only input (mode is "r") 668 * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor} 669 * for you with a MIME type of "*\/*". This allows such callers to benefit 670 * from any built-in data conversion that a provider implements. 671 * 672 * @param uri The desired URI to open. 673 * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile 674 * ContentProvider.openAssetFile}. 675 * @return Returns a new ParcelFileDescriptor pointing to the file. You 676 * own this descriptor and are responsible for closing it when done. 677 * @throws FileNotFoundException Throws FileNotFoundException of no 678 * file exists under the URI or the mode is invalid. 679 */ 680 public final AssetFileDescriptor openAssetFileDescriptor(Uri uri, 681 String mode) throws FileNotFoundException { 682 String scheme = uri.getScheme(); 683 if (SCHEME_ANDROID_RESOURCE.equals(scheme)) { 684 if (!"r".equals(mode)) { 685 throw new FileNotFoundException("Can't write resources: " + uri); 686 } 687 OpenResourceIdResult r = getResourceId(uri); 688 try { 689 return r.r.openRawResourceFd(r.id); 690 } catch (Resources.NotFoundException ex) { 691 throw new FileNotFoundException("Resource does not exist: " + uri); 692 } 693 } else if (SCHEME_FILE.equals(scheme)) { 694 ParcelFileDescriptor pfd = ParcelFileDescriptor.open( 695 new File(uri.getPath()), modeToMode(uri, mode)); 696 return new AssetFileDescriptor(pfd, 0, -1); 697 } else { 698 if ("r".equals(mode)) { 699 return openTypedAssetFileDescriptor(uri, "*/*", null); 700 } else { 701 IContentProvider unstableProvider = acquireUnstableProvider(uri); 702 if (unstableProvider == null) { 703 throw new FileNotFoundException("No content provider: " + uri); 704 } 705 IContentProvider stableProvider = null; 706 AssetFileDescriptor fd = null; 707 708 try { 709 try { 710 fd = unstableProvider.openAssetFile(mPackageName, uri, mode); 711 if (fd == null) { 712 // The provider will be released by the finally{} clause 713 return null; 714 } 715 } catch (DeadObjectException e) { 716 // The remote process has died... but we only hold an unstable 717 // reference though, so we might recover!!! Let's try!!!! 718 // This is exciting!!1!!1!!!!1 719 unstableProviderDied(unstableProvider); 720 stableProvider = acquireProvider(uri); 721 if (stableProvider == null) { 722 throw new FileNotFoundException("No content provider: " + uri); 723 } 724 fd = stableProvider.openAssetFile(mPackageName, uri, mode); 725 if (fd == null) { 726 // The provider will be released by the finally{} clause 727 return null; 728 } 729 } 730 731 if (stableProvider == null) { 732 stableProvider = acquireProvider(uri); 733 } 734 releaseUnstableProvider(unstableProvider); 735 ParcelFileDescriptor pfd = new ParcelFileDescriptorInner( 736 fd.getParcelFileDescriptor(), stableProvider); 737 738 // Success! Don't release the provider when exiting, let 739 // ParcelFileDescriptorInner do that when it is closed. 740 stableProvider = null; 741 742 return new AssetFileDescriptor(pfd, fd.getStartOffset(), 743 fd.getDeclaredLength()); 744 745 } catch (RemoteException e) { 746 // Whatever, whatever, we'll go away. 747 throw new FileNotFoundException( 748 "Failed opening content provider: " + uri); 749 } catch (FileNotFoundException e) { 750 throw e; 751 } finally { 752 if (stableProvider != null) { 753 releaseProvider(stableProvider); 754 } 755 if (unstableProvider != null) { 756 releaseUnstableProvider(unstableProvider); 757 } 758 } 759 } 760 } 761 } 762 763 /** 764 * Open a raw file descriptor to access (potentially type transformed) 765 * data from a "content:" URI. This interacts with the underlying 766 * {@link ContentProvider#openTypedAssetFile} method of the provider 767 * associated with the given URI, to retrieve retrieve any appropriate 768 * data stream for the data stored there. 769 * 770 * <p>Unlike {@link #openAssetFileDescriptor}, this function only works 771 * with "content:" URIs, because content providers are the only facility 772 * with an associated MIME type to ensure that the returned data stream 773 * is of the desired type. 774 * 775 * <p>All text/* streams are encoded in UTF-8. 776 * 777 * @param uri The desired URI to open. 778 * @param mimeType The desired MIME type of the returned data. This can 779 * be a pattern such as *\/*, which will allow the content provider to 780 * select a type, though there is no way for you to determine what type 781 * it is returning. 782 * @param opts Additional provider-dependent options. 783 * @return Returns a new ParcelFileDescriptor from which you can read the 784 * data stream from the provider. Note that this may be a pipe, meaning 785 * you can't seek in it. The only seek you should do is if the 786 * AssetFileDescriptor contains an offset, to move to that offset before 787 * reading. You own this descriptor and are responsible for closing it when done. 788 * @throws FileNotFoundException Throws FileNotFoundException of no 789 * data of the desired type exists under the URI. 790 */ 791 public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri, 792 String mimeType, Bundle opts) throws FileNotFoundException { 793 IContentProvider unstableProvider = acquireUnstableProvider(uri); 794 if (unstableProvider == null) { 795 throw new FileNotFoundException("No content provider: " + uri); 796 } 797 IContentProvider stableProvider = null; 798 AssetFileDescriptor fd = null; 799 800 try { 801 try { 802 fd = unstableProvider.openTypedAssetFile(mPackageName, uri, mimeType, opts); 803 if (fd == null) { 804 // The provider will be released by the finally{} clause 805 return null; 806 } 807 } catch (DeadObjectException e) { 808 // The remote process has died... but we only hold an unstable 809 // reference though, so we might recover!!! Let's try!!!! 810 // This is exciting!!1!!1!!!!1 811 unstableProviderDied(unstableProvider); 812 stableProvider = acquireProvider(uri); 813 if (stableProvider == null) { 814 throw new FileNotFoundException("No content provider: " + uri); 815 } 816 fd = stableProvider.openTypedAssetFile(mPackageName, uri, mimeType, opts); 817 if (fd == null) { 818 // The provider will be released by the finally{} clause 819 return null; 820 } 821 } 822 823 if (stableProvider == null) { 824 stableProvider = acquireProvider(uri); 825 } 826 releaseUnstableProvider(unstableProvider); 827 ParcelFileDescriptor pfd = new ParcelFileDescriptorInner( 828 fd.getParcelFileDescriptor(), stableProvider); 829 830 // Success! Don't release the provider when exiting, let 831 // ParcelFileDescriptorInner do that when it is closed. 832 stableProvider = null; 833 834 return new AssetFileDescriptor(pfd, fd.getStartOffset(), 835 fd.getDeclaredLength()); 836 837 } catch (RemoteException e) { 838 // Whatever, whatever, we'll go away. 839 throw new FileNotFoundException( 840 "Failed opening content provider: " + uri); 841 } catch (FileNotFoundException e) { 842 throw e; 843 } finally { 844 if (stableProvider != null) { 845 releaseProvider(stableProvider); 846 } 847 if (unstableProvider != null) { 848 releaseUnstableProvider(unstableProvider); 849 } 850 } 851 } 852 853 /** 854 * A resource identified by the {@link Resources} that contains it, and a resource id. 855 * 856 * @hide 857 */ 858 public class OpenResourceIdResult { 859 public Resources r; 860 public int id; 861 } 862 863 /** 864 * Resolves an android.resource URI to a {@link Resources} and a resource id. 865 * 866 * @hide 867 */ 868 public OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException { 869 String authority = uri.getAuthority(); 870 Resources r; 871 if (TextUtils.isEmpty(authority)) { 872 throw new FileNotFoundException("No authority: " + uri); 873 } else { 874 try { 875 r = mContext.getPackageManager().getResourcesForApplication(authority); 876 } catch (NameNotFoundException ex) { 877 throw new FileNotFoundException("No package found for authority: " + uri); 878 } 879 } 880 List<String> path = uri.getPathSegments(); 881 if (path == null) { 882 throw new FileNotFoundException("No path: " + uri); 883 } 884 int len = path.size(); 885 int id; 886 if (len == 1) { 887 try { 888 id = Integer.parseInt(path.get(0)); 889 } catch (NumberFormatException e) { 890 throw new FileNotFoundException("Single path segment is not a resource ID: " + uri); 891 } 892 } else if (len == 2) { 893 id = r.getIdentifier(path.get(1), path.get(0), authority); 894 } else { 895 throw new FileNotFoundException("More than two path segments: " + uri); 896 } 897 if (id == 0) { 898 throw new FileNotFoundException("No resource found for: " + uri); 899 } 900 OpenResourceIdResult res = new OpenResourceIdResult(); 901 res.r = r; 902 res.id = id; 903 return res; 904 } 905 906 /** @hide */ 907 static public int modeToMode(Uri uri, String mode) throws FileNotFoundException { 908 int modeBits; 909 if ("r".equals(mode)) { 910 modeBits = ParcelFileDescriptor.MODE_READ_ONLY; 911 } else if ("w".equals(mode) || "wt".equals(mode)) { 912 modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY 913 | ParcelFileDescriptor.MODE_CREATE 914 | ParcelFileDescriptor.MODE_TRUNCATE; 915 } else if ("wa".equals(mode)) { 916 modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY 917 | ParcelFileDescriptor.MODE_CREATE 918 | ParcelFileDescriptor.MODE_APPEND; 919 } else if ("rw".equals(mode)) { 920 modeBits = ParcelFileDescriptor.MODE_READ_WRITE 921 | ParcelFileDescriptor.MODE_CREATE; 922 } else if ("rwt".equals(mode)) { 923 modeBits = ParcelFileDescriptor.MODE_READ_WRITE 924 | ParcelFileDescriptor.MODE_CREATE 925 | ParcelFileDescriptor.MODE_TRUNCATE; 926 } else { 927 throw new FileNotFoundException("Bad mode for " + uri + ": " 928 + mode); 929 } 930 return modeBits; 931 } 932 933 /** 934 * Inserts a row into a table at the given URL. 935 * 936 * If the content provider supports transactions the insertion will be atomic. 937 * 938 * @param url The URL of the table to insert into. 939 * @param values The initial values for the newly inserted row. The key is the column name for 940 * the field. Passing an empty ContentValues will create an empty row. 941 * @return the URL of the newly created row. 942 */ 943 public final Uri insert(Uri url, ContentValues values) 944 { 945 IContentProvider provider = acquireProvider(url); 946 if (provider == null) { 947 throw new IllegalArgumentException("Unknown URL " + url); 948 } 949 try { 950 long startTime = SystemClock.uptimeMillis(); 951 Uri createdRow = provider.insert(mPackageName, url, values); 952 long durationMillis = SystemClock.uptimeMillis() - startTime; 953 maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */); 954 return createdRow; 955 } catch (RemoteException e) { 956 // Arbitrary and not worth documenting, as Activity 957 // Manager will kill this process shortly anyway. 958 return null; 959 } finally { 960 releaseProvider(provider); 961 } 962 } 963 964 /** 965 * Applies each of the {@link ContentProviderOperation} objects and returns an array 966 * of their results. Passes through OperationApplicationException, which may be thrown 967 * by the call to {@link ContentProviderOperation#apply}. 968 * If all the applications succeed then a {@link ContentProviderResult} array with the 969 * same number of elements as the operations will be returned. It is implementation-specific 970 * how many, if any, operations will have been successfully applied if a call to 971 * apply results in a {@link OperationApplicationException}. 972 * @param authority the authority of the ContentProvider to which this batch should be applied 973 * @param operations the operations to apply 974 * @return the results of the applications 975 * @throws OperationApplicationException thrown if an application fails. 976 * See {@link ContentProviderOperation#apply} for more information. 977 * @throws RemoteException thrown if a RemoteException is encountered while attempting 978 * to communicate with a remote provider. 979 */ 980 public ContentProviderResult[] applyBatch(String authority, 981 ArrayList<ContentProviderOperation> operations) 982 throws RemoteException, OperationApplicationException { 983 ContentProviderClient provider = acquireContentProviderClient(authority); 984 if (provider == null) { 985 throw new IllegalArgumentException("Unknown authority " + authority); 986 } 987 try { 988 return provider.applyBatch(operations); 989 } finally { 990 provider.release(); 991 } 992 } 993 994 /** 995 * Inserts multiple rows into a table at the given URL. 996 * 997 * This function make no guarantees about the atomicity of the insertions. 998 * 999 * @param url The URL of the table to insert into. 1000 * @param values The initial values for the newly inserted rows. The key is the column name for 1001 * the field. Passing null will create an empty row. 1002 * @return the number of newly created rows. 1003 */ 1004 public final int bulkInsert(Uri url, ContentValues[] values) 1005 { 1006 IContentProvider provider = acquireProvider(url); 1007 if (provider == null) { 1008 throw new IllegalArgumentException("Unknown URL " + url); 1009 } 1010 try { 1011 long startTime = SystemClock.uptimeMillis(); 1012 int rowsCreated = provider.bulkInsert(mPackageName, url, values); 1013 long durationMillis = SystemClock.uptimeMillis() - startTime; 1014 maybeLogUpdateToEventLog(durationMillis, url, "bulkinsert", null /* where */); 1015 return rowsCreated; 1016 } catch (RemoteException e) { 1017 // Arbitrary and not worth documenting, as Activity 1018 // Manager will kill this process shortly anyway. 1019 return 0; 1020 } finally { 1021 releaseProvider(provider); 1022 } 1023 } 1024 1025 /** 1026 * Deletes row(s) specified by a content URI. 1027 * 1028 * If the content provider supports transactions, the deletion will be atomic. 1029 * 1030 * @param url The URL of the row to delete. 1031 * @param where A filter to apply to rows before deleting, formatted as an SQL WHERE clause 1032 (excluding the WHERE itself). 1033 * @return The number of rows deleted. 1034 */ 1035 public final int delete(Uri url, String where, String[] selectionArgs) 1036 { 1037 IContentProvider provider = acquireProvider(url); 1038 if (provider == null) { 1039 throw new IllegalArgumentException("Unknown URL " + url); 1040 } 1041 try { 1042 long startTime = SystemClock.uptimeMillis(); 1043 int rowsDeleted = provider.delete(mPackageName, url, where, selectionArgs); 1044 long durationMillis = SystemClock.uptimeMillis() - startTime; 1045 maybeLogUpdateToEventLog(durationMillis, url, "delete", where); 1046 return rowsDeleted; 1047 } catch (RemoteException e) { 1048 // Arbitrary and not worth documenting, as Activity 1049 // Manager will kill this process shortly anyway. 1050 return -1; 1051 } finally { 1052 releaseProvider(provider); 1053 } 1054 } 1055 1056 /** 1057 * Update row(s) in a content URI. 1058 * 1059 * If the content provider supports transactions the update will be atomic. 1060 * 1061 * @param uri The URI to modify. 1062 * @param values The new field values. The key is the column name for the field. 1063 A null value will remove an existing field value. 1064 * @param where A filter to apply to rows before updating, formatted as an SQL WHERE clause 1065 (excluding the WHERE itself). 1066 * @return the number of rows updated. 1067 * @throws NullPointerException if uri or values are null 1068 */ 1069 public final int update(Uri uri, ContentValues values, String where, 1070 String[] selectionArgs) { 1071 IContentProvider provider = acquireProvider(uri); 1072 if (provider == null) { 1073 throw new IllegalArgumentException("Unknown URI " + uri); 1074 } 1075 try { 1076 long startTime = SystemClock.uptimeMillis(); 1077 int rowsUpdated = provider.update(mPackageName, uri, values, where, selectionArgs); 1078 long durationMillis = SystemClock.uptimeMillis() - startTime; 1079 maybeLogUpdateToEventLog(durationMillis, uri, "update", where); 1080 return rowsUpdated; 1081 } catch (RemoteException e) { 1082 // Arbitrary and not worth documenting, as Activity 1083 // Manager will kill this process shortly anyway. 1084 return -1; 1085 } finally { 1086 releaseProvider(provider); 1087 } 1088 } 1089 1090 /** 1091 * Call a provider-defined method. This can be used to implement 1092 * read or write interfaces which are cheaper than using a Cursor and/or 1093 * do not fit into the traditional table model. 1094 * 1095 * @param method provider-defined method name to call. Opaque to 1096 * framework, but must be non-null. 1097 * @param arg provider-defined String argument. May be null. 1098 * @param extras provider-defined Bundle argument. May be null. 1099 * @return a result Bundle, possibly null. Will be null if the ContentProvider 1100 * does not implement call. 1101 * @throws NullPointerException if uri or method is null 1102 * @throws IllegalArgumentException if uri is not known 1103 */ 1104 public final Bundle call(Uri uri, String method, String arg, Bundle extras) { 1105 if (uri == null) { 1106 throw new NullPointerException("uri == null"); 1107 } 1108 if (method == null) { 1109 throw new NullPointerException("method == null"); 1110 } 1111 IContentProvider provider = acquireProvider(uri); 1112 if (provider == null) { 1113 throw new IllegalArgumentException("Unknown URI " + uri); 1114 } 1115 try { 1116 return provider.call(mPackageName, method, arg, extras); 1117 } catch (RemoteException e) { 1118 // Arbitrary and not worth documenting, as Activity 1119 // Manager will kill this process shortly anyway. 1120 return null; 1121 } finally { 1122 releaseProvider(provider); 1123 } 1124 } 1125 1126 /** 1127 * Returns the content provider for the given content URI. 1128 * 1129 * @param uri The URI to a content provider 1130 * @return The ContentProvider for the given URI, or null if no content provider is found. 1131 * @hide 1132 */ 1133 public final IContentProvider acquireProvider(Uri uri) { 1134 if (!SCHEME_CONTENT.equals(uri.getScheme())) { 1135 return null; 1136 } 1137 final String auth = uri.getAuthority(); 1138 if (auth != null) { 1139 return acquireProvider(mContext, auth); 1140 } 1141 return null; 1142 } 1143 1144 /** 1145 * Returns the content provider for the given content URI if the process 1146 * already has a reference on it. 1147 * 1148 * @param uri The URI to a content provider 1149 * @return The ContentProvider for the given URI, or null if no content provider is found. 1150 * @hide 1151 */ 1152 public final IContentProvider acquireExistingProvider(Uri uri) { 1153 if (!SCHEME_CONTENT.equals(uri.getScheme())) { 1154 return null; 1155 } 1156 final String auth = uri.getAuthority(); 1157 if (auth != null) { 1158 return acquireExistingProvider(mContext, auth); 1159 } 1160 return null; 1161 } 1162 1163 /** 1164 * @hide 1165 */ 1166 public final IContentProvider acquireProvider(String name) { 1167 if (name == null) { 1168 return null; 1169 } 1170 return acquireProvider(mContext, name); 1171 } 1172 1173 /** 1174 * Returns the content provider for the given content URI. 1175 * 1176 * @param uri The URI to a content provider 1177 * @return The ContentProvider for the given URI, or null if no content provider is found. 1178 * @hide 1179 */ 1180 public final IContentProvider acquireUnstableProvider(Uri uri) { 1181 if (!SCHEME_CONTENT.equals(uri.getScheme())) { 1182 return null; 1183 } 1184 String auth = uri.getAuthority(); 1185 if (auth != null) { 1186 return acquireUnstableProvider(mContext, uri.getAuthority()); 1187 } 1188 return null; 1189 } 1190 1191 /** 1192 * @hide 1193 */ 1194 public final IContentProvider acquireUnstableProvider(String name) { 1195 if (name == null) { 1196 return null; 1197 } 1198 return acquireUnstableProvider(mContext, name); 1199 } 1200 1201 /** 1202 * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider} 1203 * that services the content at uri, starting the provider if necessary. Returns 1204 * null if there is no provider associated wih the uri. The caller must indicate that they are 1205 * done with the provider by calling {@link ContentProviderClient#release} which will allow 1206 * the system to release the provider it it determines that there is no other reason for 1207 * keeping it active. 1208 * @param uri specifies which provider should be acquired 1209 * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider} 1210 * that services the content at uri or null if there isn't one. 1211 */ 1212 public final ContentProviderClient acquireContentProviderClient(Uri uri) { 1213 IContentProvider provider = acquireProvider(uri); 1214 if (provider != null) { 1215 return new ContentProviderClient(this, provider, true); 1216 } 1217 1218 return null; 1219 } 1220 1221 /** 1222 * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider} 1223 * with the authority of name, starting the provider if necessary. Returns 1224 * null if there is no provider associated wih the uri. The caller must indicate that they are 1225 * done with the provider by calling {@link ContentProviderClient#release} which will allow 1226 * the system to release the provider it it determines that there is no other reason for 1227 * keeping it active. 1228 * @param name specifies which provider should be acquired 1229 * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider} 1230 * with the authority of name or null if there isn't one. 1231 */ 1232 public final ContentProviderClient acquireContentProviderClient(String name) { 1233 IContentProvider provider = acquireProvider(name); 1234 if (provider != null) { 1235 return new ContentProviderClient(this, provider, true); 1236 } 1237 1238 return null; 1239 } 1240 1241 /** 1242 * Like {@link #acquireContentProviderClient(Uri)}, but for use when you do 1243 * not trust the stability of the target content provider. This turns off 1244 * the mechanism in the platform clean up processes that are dependent on 1245 * a content provider if that content provider's process goes away. Normally 1246 * you can safely assume that once you have acquired a provider, you can freely 1247 * use it as needed and it won't disappear, even if your process is in the 1248 * background. If using this method, you need to take care to deal with any 1249 * failures when communicating with the provider, and be sure to close it 1250 * so that it can be re-opened later. In particular, catching a 1251 * {@link android.os.DeadObjectException} from the calls there will let you 1252 * know that the content provider has gone away; at that point the current 1253 * ContentProviderClient object is invalid, and you should release it. You 1254 * can acquire a new one if you would like to try to restart the provider 1255 * and perform new operations on it. 1256 */ 1257 public final ContentProviderClient acquireUnstableContentProviderClient(Uri uri) { 1258 IContentProvider provider = acquireUnstableProvider(uri); 1259 if (provider != null) { 1260 return new ContentProviderClient(this, provider, false); 1261 } 1262 1263 return null; 1264 } 1265 1266 /** 1267 * Like {@link #acquireContentProviderClient(String)}, but for use when you do 1268 * not trust the stability of the target content provider. This turns off 1269 * the mechanism in the platform clean up processes that are dependent on 1270 * a content provider if that content provider's process goes away. Normally 1271 * you can safely assume that once you have acquired a provider, you can freely 1272 * use it as needed and it won't disappear, even if your process is in the 1273 * background. If using this method, you need to take care to deal with any 1274 * failures when communicating with the provider, and be sure to close it 1275 * so that it can be re-opened later. In particular, catching a 1276 * {@link android.os.DeadObjectException} from the calls there will let you 1277 * know that the content provider has gone away; at that point the current 1278 * ContentProviderClient object is invalid, and you should release it. You 1279 * can acquire a new one if you would like to try to restart the provider 1280 * and perform new operations on it. 1281 */ 1282 public final ContentProviderClient acquireUnstableContentProviderClient(String name) { 1283 IContentProvider provider = acquireUnstableProvider(name); 1284 if (provider != null) { 1285 return new ContentProviderClient(this, provider, false); 1286 } 1287 1288 return null; 1289 } 1290 1291 /** 1292 * Register an observer class that gets callbacks when data identified by a 1293 * given content URI changes. 1294 * 1295 * @param uri The URI to watch for changes. This can be a specific row URI, or a base URI 1296 * for a whole class of content. 1297 * @param notifyForDescendents If <code>true</code> changes to URIs beginning with <code>uri</code> 1298 * will also cause notifications to be sent. If <code>false</code> only changes to the exact URI 1299 * specified by <em>uri</em> will cause notifications to be sent. If true, than any URI values 1300 * at or below the specified URI will also trigger a match. 1301 * @param observer The object that receives callbacks when changes occur. 1302 * @see #unregisterContentObserver 1303 */ 1304 public final void registerContentObserver(Uri uri, boolean notifyForDescendents, 1305 ContentObserver observer) 1306 { 1307 registerContentObserver(uri, notifyForDescendents, observer, UserHandle.myUserId()); 1308 } 1309 1310 /** @hide - designated user version */ 1311 public final void registerContentObserver(Uri uri, boolean notifyForDescendents, 1312 ContentObserver observer, int userHandle) 1313 { 1314 try { 1315 getContentService().registerContentObserver(uri, notifyForDescendents, 1316 observer.getContentObserver(), userHandle); 1317 } catch (RemoteException e) { 1318 } 1319 } 1320 1321 /** 1322 * Unregisters a change observer. 1323 * 1324 * @param observer The previously registered observer that is no longer needed. 1325 * @see #registerContentObserver 1326 */ 1327 public final void unregisterContentObserver(ContentObserver observer) { 1328 try { 1329 IContentObserver contentObserver = observer.releaseContentObserver(); 1330 if (contentObserver != null) { 1331 getContentService().unregisterContentObserver( 1332 contentObserver); 1333 } 1334 } catch (RemoteException e) { 1335 } 1336 } 1337 1338 /** 1339 * Notify registered observers that a row was updated and attempt to sync changes 1340 * to the network. 1341 * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}. 1342 * By default, CursorAdapter objects will get this notification. 1343 * 1344 * @param uri The uri of the content that was changed. 1345 * @param observer The observer that originated the change, may be <code>null</null>. 1346 * The observer that originated the change will only receive the notification if it 1347 * has requested to receive self-change notifications by implementing 1348 * {@link ContentObserver#deliverSelfNotifications()} to return true. 1349 */ 1350 public void notifyChange(Uri uri, ContentObserver observer) { 1351 notifyChange(uri, observer, true /* sync to network */); 1352 } 1353 1354 /** 1355 * Notify registered observers that a row was updated. 1356 * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}. 1357 * By default, CursorAdapter objects will get this notification. 1358 * If syncToNetwork is true, this will attempt to schedule a local sync using the sync 1359 * adapter that's registered for the authority of the provided uri. No account will be 1360 * passed to the sync adapter, so all matching accounts will be synchronized. 1361 * 1362 * @param uri The uri of the content that was changed. 1363 * @param observer The observer that originated the change, may be <code>null</null>. 1364 * The observer that originated the change will only receive the notification if it 1365 * has requested to receive self-change notifications by implementing 1366 * {@link ContentObserver#deliverSelfNotifications()} to return true. 1367 * @param syncToNetwork If true, attempt to sync the change to the network. 1368 * @see #requestSync(android.accounts.Account, String, android.os.Bundle) 1369 */ 1370 public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) { 1371 notifyChange(uri, observer, syncToNetwork, UserHandle.getCallingUserId()); 1372 } 1373 1374 /** 1375 * Notify registered observers within the designated user(s) that a row was updated. 1376 * 1377 * @hide 1378 */ 1379 public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork, 1380 int userHandle) { 1381 try { 1382 getContentService().notifyChange( 1383 uri, observer == null ? null : observer.getContentObserver(), 1384 observer != null && observer.deliverSelfNotifications(), syncToNetwork, 1385 userHandle); 1386 } catch (RemoteException e) { 1387 } 1388 } 1389 1390 /** 1391 * Return list of all Uri permissions that have been granted <em>to</em> the 1392 * calling package, and which exactly match the requested flags. For 1393 * example, to return all Uris that the calling application has 1394 * <em>non-persistent</em> read access to: 1395 * 1396 * <pre class="prettyprint"> 1397 * getIncomingUriPermissionGrants(Intent.FLAG_GRANT_READ_URI_PERMISSION, 1398 * Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION); 1399 * </pre> 1400 * 1401 * @param modeFlags any combination of 1402 * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}, 1403 * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, or 1404 * {@link Intent#FLAG_PERSIST_GRANT_URI_PERMISSION}. 1405 * @param modeMask mask indicating which flags must match. 1406 */ 1407 public Uri[] getIncomingUriPermissionGrants(int modeFlags, int modeMask) { 1408 try { 1409 return ActivityManagerNative.getDefault() 1410 .getGrantedUriPermissions(null, getPackageName(), modeFlags, modeMask); 1411 } catch (RemoteException e) { 1412 return new Uri[0]; 1413 } 1414 } 1415 1416 /** 1417 * Return list of all Uri permissions that have been granted <em>from</em> the 1418 * calling package, and which exactly match the requested flags. For 1419 * example, to return all Uris that the calling application has granted 1420 * <em>non-persistent</em> read access to: 1421 * 1422 * <pre class="prettyprint"> 1423 * getOutgoingUriPermissionGrants(Intent.FLAG_GRANT_READ_URI_PERMISSION, 1424 * Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION); 1425 * </pre> 1426 * 1427 * @param modeFlags any combination of 1428 * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}, 1429 * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, or 1430 * {@link Intent#FLAG_PERSIST_GRANT_URI_PERMISSION}. 1431 * @param modeMask mask indicating which flags must match. 1432 */ 1433 public Uri[] getOutgoingUriPermissionGrants(int modeFlags, int modeMask) { 1434 try { 1435 return ActivityManagerNative.getDefault() 1436 .getGrantedUriPermissions(getPackageName(), null, modeFlags, modeMask); 1437 } catch (RemoteException e) { 1438 return new Uri[0]; 1439 } 1440 } 1441 1442 /** 1443 * Start an asynchronous sync operation. If you want to monitor the progress 1444 * of the sync you may register a SyncObserver. Only values of the following 1445 * types may be used in the extras bundle: 1446 * <ul> 1447 * <li>Integer</li> 1448 * <li>Long</li> 1449 * <li>Boolean</li> 1450 * <li>Float</li> 1451 * <li>Double</li> 1452 * <li>String</li> 1453 * <li>Account</li> 1454 * <li>null</li> 1455 * </ul> 1456 * 1457 * @param uri the uri of the provider to sync or null to sync all providers. 1458 * @param extras any extras to pass to the SyncAdapter. 1459 * @deprecated instead use 1460 * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)} 1461 */ 1462 @Deprecated 1463 public void startSync(Uri uri, Bundle extras) { 1464 Account account = null; 1465 if (extras != null) { 1466 String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT); 1467 if (!TextUtils.isEmpty(accountName)) { 1468 account = new Account(accountName, "com.google"); 1469 } 1470 extras.remove(SYNC_EXTRAS_ACCOUNT); 1471 } 1472 requestSync(account, uri != null ? uri.getAuthority() : null, extras); 1473 } 1474 1475 /** 1476 * Start an asynchronous sync operation. If you want to monitor the progress 1477 * of the sync you may register a SyncObserver. Only values of the following 1478 * types may be used in the extras bundle: 1479 * <ul> 1480 * <li>Integer</li> 1481 * <li>Long</li> 1482 * <li>Boolean</li> 1483 * <li>Float</li> 1484 * <li>Double</li> 1485 * <li>String</li> 1486 * <li>Account</li> 1487 * <li>null</li> 1488 * </ul> 1489 * 1490 * @param account which account should be synced 1491 * @param authority which authority should be synced 1492 * @param extras any extras to pass to the SyncAdapter. 1493 */ 1494 public static void requestSync(Account account, String authority, Bundle extras) { 1495 SyncRequest request = 1496 new SyncRequest.Builder() 1497 .setSyncAdapter(account, authority) 1498 .setExtras(extras) 1499 .syncOnce(0, 0) // Immediate sync. 1500 .build(); 1501 requestSync(request); 1502 } 1503 1504 /** 1505 * Register a sync with the SyncManager. These requests are built using the 1506 * {@link SyncRequest.Builder}. 1507 */ 1508 public static void requestSync(SyncRequest request) { 1509 try { 1510 getContentService().sync(request); 1511 } catch(RemoteException e) { 1512 // Shouldn't happen. 1513 } 1514 } 1515 1516 /** 1517 * Check that only values of the following types are in the Bundle: 1518 * <ul> 1519 * <li>Integer</li> 1520 * <li>Long</li> 1521 * <li>Boolean</li> 1522 * <li>Float</li> 1523 * <li>Double</li> 1524 * <li>String</li> 1525 * <li>Account</li> 1526 * <li>null</li> 1527 * </ul> 1528 * @param extras the Bundle to check 1529 */ 1530 public static void validateSyncExtrasBundle(Bundle extras) { 1531 try { 1532 for (String key : extras.keySet()) { 1533 Object value = extras.get(key); 1534 if (value == null) continue; 1535 if (value instanceof Long) continue; 1536 if (value instanceof Integer) continue; 1537 if (value instanceof Boolean) continue; 1538 if (value instanceof Float) continue; 1539 if (value instanceof Double) continue; 1540 if (value instanceof String) continue; 1541 if (value instanceof Account) continue; 1542 throw new IllegalArgumentException("unexpected value type: " 1543 + value.getClass().getName()); 1544 } 1545 } catch (IllegalArgumentException e) { 1546 throw e; 1547 } catch (RuntimeException exc) { 1548 throw new IllegalArgumentException("error unparceling Bundle", exc); 1549 } 1550 } 1551 1552 /** 1553 * Cancel any active or pending syncs that match the Uri. If the uri is null then 1554 * all syncs will be canceled. 1555 * 1556 * @param uri the uri of the provider to sync or null to sync all providers. 1557 * @deprecated instead use {@link #cancelSync(android.accounts.Account, String)} 1558 */ 1559 @Deprecated 1560 public void cancelSync(Uri uri) { 1561 cancelSync(null /* all accounts */, uri != null ? uri.getAuthority() : null); 1562 } 1563 1564 /** 1565 * Cancel any active or pending syncs that match account and authority. The account and 1566 * authority can each independently be set to null, which means that syncs with any account 1567 * or authority, respectively, will match. 1568 * 1569 * @param account filters the syncs that match by this account 1570 * @param authority filters the syncs that match by this authority 1571 */ 1572 public static void cancelSync(Account account, String authority) { 1573 try { 1574 getContentService().cancelSync(account, authority); 1575 } catch (RemoteException e) { 1576 } 1577 } 1578 1579 /** 1580 * Get information about the SyncAdapters that are known to the system. 1581 * @return an array of SyncAdapters that have registered with the system 1582 */ 1583 public static SyncAdapterType[] getSyncAdapterTypes() { 1584 try { 1585 return getContentService().getSyncAdapterTypes(); 1586 } catch (RemoteException e) { 1587 throw new RuntimeException("the ContentService should always be reachable", e); 1588 } 1589 } 1590 1591 /** 1592 * Check if the provider should be synced when a network tickle is received 1593 * <p>This method requires the caller to hold the permission 1594 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}. 1595 * 1596 * @param account the account whose setting we are querying 1597 * @param authority the provider whose setting we are querying 1598 * @return true if the provider should be synced when a network tickle is received 1599 */ 1600 public static boolean getSyncAutomatically(Account account, String authority) { 1601 try { 1602 return getContentService().getSyncAutomatically(account, authority); 1603 } catch (RemoteException e) { 1604 throw new RuntimeException("the ContentService should always be reachable", e); 1605 } 1606 } 1607 1608 /** 1609 * Set whether or not the provider is synced when it receives a network tickle. 1610 * <p>This method requires the caller to hold the permission 1611 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 1612 * 1613 * @param account the account whose setting we are querying 1614 * @param authority the provider whose behavior is being controlled 1615 * @param sync true if the provider should be synced when tickles are received for it 1616 */ 1617 public static void setSyncAutomatically(Account account, String authority, boolean sync) { 1618 try { 1619 getContentService().setSyncAutomatically(account, authority, sync); 1620 } catch (RemoteException e) { 1621 // exception ignored; if this is thrown then it means the runtime is in the midst of 1622 // being restarted 1623 } 1624 } 1625 1626 /** 1627 * Specifies that a sync should be requested with the specified the account, authority, 1628 * and extras at the given frequency. If there is already another periodic sync scheduled 1629 * with the account, authority and extras then a new periodic sync won't be added, instead 1630 * the frequency of the previous one will be updated. 1631 * <p> 1632 * These periodic syncs honor the "syncAutomatically" and "masterSyncAutomatically" settings. 1633 * Although these sync are scheduled at the specified frequency, it may take longer for it to 1634 * actually be started if other syncs are ahead of it in the sync operation queue. This means 1635 * that the actual start time may drift. 1636 * <p> 1637 * Periodic syncs are not allowed to have any of {@link #SYNC_EXTRAS_DO_NOT_RETRY}, 1638 * {@link #SYNC_EXTRAS_IGNORE_BACKOFF}, {@link #SYNC_EXTRAS_IGNORE_SETTINGS}, 1639 * {@link #SYNC_EXTRAS_INITIALIZE}, {@link #SYNC_EXTRAS_FORCE}, 1640 * {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL} set to true. 1641 * If any are supplied then an {@link IllegalArgumentException} will be thrown. 1642 * 1643 * <p>This method requires the caller to hold the permission 1644 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 1645 * 1646 * @param account the account to specify in the sync 1647 * @param authority the provider to specify in the sync request 1648 * @param extras extra parameters to go along with the sync request 1649 * @param pollFrequency how frequently the sync should be performed, in seconds. 1650 * @throws IllegalArgumentException if an illegal extra was set or if any of the parameters 1651 * are null. 1652 */ 1653 public static void addPeriodicSync(Account account, String authority, Bundle extras, 1654 long pollFrequency) { 1655 validateSyncExtrasBundle(extras); 1656 if (account == null) { 1657 throw new IllegalArgumentException("account must not be null"); 1658 } 1659 if (authority == null) { 1660 throw new IllegalArgumentException("authority must not be null"); 1661 } 1662 if (extras.getBoolean(SYNC_EXTRAS_MANUAL, false) 1663 || extras.getBoolean(SYNC_EXTRAS_DO_NOT_RETRY, false) 1664 || extras.getBoolean(SYNC_EXTRAS_IGNORE_BACKOFF, false) 1665 || extras.getBoolean(SYNC_EXTRAS_IGNORE_SETTINGS, false) 1666 || extras.getBoolean(SYNC_EXTRAS_INITIALIZE, false) 1667 || extras.getBoolean(SYNC_EXTRAS_FORCE, false) 1668 || extras.getBoolean(SYNC_EXTRAS_EXPEDITED, false)) { 1669 throw new IllegalArgumentException("illegal extras were set"); 1670 } 1671 try { 1672 getContentService().addPeriodicSync(account, authority, extras, pollFrequency); 1673 } catch (RemoteException e) { 1674 // exception ignored; if this is thrown then it means the runtime is in the midst of 1675 // being restarted 1676 } 1677 } 1678 1679 /** 1680 * Remove a periodic sync. Has no affect if account, authority and extras don't match 1681 * an existing periodic sync. 1682 * <p>This method requires the caller to hold the permission 1683 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 1684 * 1685 * @param account the account of the periodic sync to remove 1686 * @param authority the provider of the periodic sync to remove 1687 * @param extras the extras of the periodic sync to remove 1688 */ 1689 public static void removePeriodicSync(Account account, String authority, Bundle extras) { 1690 validateSyncExtrasBundle(extras); 1691 if (account == null) { 1692 throw new IllegalArgumentException("account must not be null"); 1693 } 1694 if (authority == null) { 1695 throw new IllegalArgumentException("authority must not be null"); 1696 } 1697 try { 1698 getContentService().removePeriodicSync(account, authority, extras); 1699 } catch (RemoteException e) { 1700 throw new RuntimeException("the ContentService should always be reachable", e); 1701 } 1702 } 1703 1704 /** 1705 * Remove the specified sync. This will remove any syncs that have been scheduled to run, but 1706 * will not cancel any running syncs. 1707 * <p>This method requires the caller to hold the permission</p> 1708 * If the request is for a periodic sync this will cancel future occurrences of the sync. 1709 * 1710 * It is possible to cancel a sync using a SyncRequest object that is different from the object 1711 * with which you requested the sync. Do so by building a SyncRequest with exactly the same 1712 * service/adapter, frequency, <b>and</b> extras bundle. 1713 * 1714 * @param request SyncRequest object containing information about sync to cancel. 1715 */ 1716 public static void cancelSync(SyncRequest request) { 1717 // TODO: Finish this implementation. 1718 } 1719 1720 /** 1721 * Get the list of information about the periodic syncs for the given account and authority. 1722 * <p>This method requires the caller to hold the permission 1723 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}. 1724 * 1725 * @param account the account whose periodic syncs we are querying 1726 * @param authority the provider whose periodic syncs we are querying 1727 * @return a list of PeriodicSync objects. This list may be empty but will never be null. 1728 */ 1729 public static List<PeriodicSync> getPeriodicSyncs(Account account, String authority) { 1730 if (account == null) { 1731 throw new IllegalArgumentException("account must not be null"); 1732 } 1733 if (authority == null) { 1734 throw new IllegalArgumentException("authority must not be null"); 1735 } 1736 try { 1737 return getContentService().getPeriodicSyncs(account, authority); 1738 } catch (RemoteException e) { 1739 throw new RuntimeException("the ContentService should always be reachable", e); 1740 } 1741 } 1742 1743 /** 1744 * Check if this account/provider is syncable. 1745 * <p>This method requires the caller to hold the permission 1746 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}. 1747 * @return >0 if it is syncable, 0 if not, and <0 if the state isn't known yet. 1748 */ 1749 public static int getIsSyncable(Account account, String authority) { 1750 try { 1751 return getContentService().getIsSyncable(account, authority); 1752 } catch (RemoteException e) { 1753 throw new RuntimeException("the ContentService should always be reachable", e); 1754 } 1755 } 1756 1757 /** 1758 * Set whether this account/provider is syncable. 1759 * <p>This method requires the caller to hold the permission 1760 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 1761 * @param syncable >0 denotes syncable, 0 means not syncable, <0 means unknown 1762 */ 1763 public static void setIsSyncable(Account account, String authority, int syncable) { 1764 try { 1765 getContentService().setIsSyncable(account, authority, syncable); 1766 } catch (RemoteException e) { 1767 // exception ignored; if this is thrown then it means the runtime is in the midst of 1768 // being restarted 1769 } 1770 } 1771 1772 /** 1773 * Gets the master auto-sync setting that applies to all the providers and accounts. 1774 * If this is false then the per-provider auto-sync setting is ignored. 1775 * <p>This method requires the caller to hold the permission 1776 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}. 1777 * 1778 * @return the master auto-sync setting that applies to all the providers and accounts 1779 */ 1780 public static boolean getMasterSyncAutomatically() { 1781 try { 1782 return getContentService().getMasterSyncAutomatically(); 1783 } catch (RemoteException e) { 1784 throw new RuntimeException("the ContentService should always be reachable", e); 1785 } 1786 } 1787 1788 /** 1789 * Sets the master auto-sync setting that applies to all the providers and accounts. 1790 * If this is false then the per-provider auto-sync setting is ignored. 1791 * <p>This method requires the caller to hold the permission 1792 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 1793 * 1794 * @param sync the master auto-sync setting that applies to all the providers and accounts 1795 */ 1796 public static void setMasterSyncAutomatically(boolean sync) { 1797 try { 1798 getContentService().setMasterSyncAutomatically(sync); 1799 } catch (RemoteException e) { 1800 // exception ignored; if this is thrown then it means the runtime is in the midst of 1801 // being restarted 1802 } 1803 } 1804 1805 /** 1806 * Returns true if there is currently a sync operation for the given 1807 * account or authority in the pending list, or actively being processed. 1808 * <p>This method requires the caller to hold the permission 1809 * {@link android.Manifest.permission#READ_SYNC_STATS}. 1810 * @param account the account whose setting we are querying 1811 * @param authority the provider whose behavior is being queried 1812 * @return true if a sync is active for the given account or authority. 1813 */ 1814 public static boolean isSyncActive(Account account, String authority) { 1815 try { 1816 return getContentService().isSyncActive(account, authority); 1817 } catch (RemoteException e) { 1818 throw new RuntimeException("the ContentService should always be reachable", e); 1819 } 1820 } 1821 1822 /** 1823 * If a sync is active returns the information about it, otherwise returns null. 1824 * <p> 1825 * This method requires the caller to hold the permission 1826 * {@link android.Manifest.permission#READ_SYNC_STATS}. 1827 * <p> 1828 * @return the SyncInfo for the currently active sync or null if one is not active. 1829 * @deprecated 1830 * Since multiple concurrent syncs are now supported you should use 1831 * {@link #getCurrentSyncs()} to get the accurate list of current syncs. 1832 * This method returns the first item from the list of current syncs 1833 * or null if there are none. 1834 */ 1835 @Deprecated 1836 public static SyncInfo getCurrentSync() { 1837 try { 1838 final List<SyncInfo> syncs = getContentService().getCurrentSyncs(); 1839 if (syncs.isEmpty()) { 1840 return null; 1841 } 1842 return syncs.get(0); 1843 } catch (RemoteException e) { 1844 throw new RuntimeException("the ContentService should always be reachable", e); 1845 } 1846 } 1847 1848 /** 1849 * Returns a list with information about all the active syncs. This list will be empty 1850 * if there are no active syncs. 1851 * <p> 1852 * This method requires the caller to hold the permission 1853 * {@link android.Manifest.permission#READ_SYNC_STATS}. 1854 * <p> 1855 * @return a List of SyncInfo objects for the currently active syncs. 1856 */ 1857 public static List<SyncInfo> getCurrentSyncs() { 1858 try { 1859 return getContentService().getCurrentSyncs(); 1860 } catch (RemoteException e) { 1861 throw new RuntimeException("the ContentService should always be reachable", e); 1862 } 1863 } 1864 1865 /** 1866 * Returns the status that matches the authority. 1867 * @param account the account whose setting we are querying 1868 * @param authority the provider whose behavior is being queried 1869 * @return the SyncStatusInfo for the authority, or null if none exists 1870 * @hide 1871 */ 1872 public static SyncStatusInfo getSyncStatus(Account account, String authority) { 1873 try { 1874 return getContentService().getSyncStatus(account, authority); 1875 } catch (RemoteException e) { 1876 throw new RuntimeException("the ContentService should always be reachable", e); 1877 } 1878 } 1879 1880 /** 1881 * Return true if the pending status is true of any matching authorities. 1882 * <p>This method requires the caller to hold the permission 1883 * {@link android.Manifest.permission#READ_SYNC_STATS}. 1884 * @param account the account whose setting we are querying 1885 * @param authority the provider whose behavior is being queried 1886 * @return true if there is a pending sync with the matching account and authority 1887 */ 1888 public static boolean isSyncPending(Account account, String authority) { 1889 try { 1890 return getContentService().isSyncPending(account, authority); 1891 } catch (RemoteException e) { 1892 throw new RuntimeException("the ContentService should always be reachable", e); 1893 } 1894 } 1895 1896 /** 1897 * Request notifications when the different aspects of the SyncManager change. The 1898 * different items that can be requested are: 1899 * <ul> 1900 * <li> {@link #SYNC_OBSERVER_TYPE_PENDING} 1901 * <li> {@link #SYNC_OBSERVER_TYPE_ACTIVE} 1902 * <li> {@link #SYNC_OBSERVER_TYPE_SETTINGS} 1903 * </ul> 1904 * The caller can set one or more of the status types in the mask for any 1905 * given listener registration. 1906 * @param mask the status change types that will cause the callback to be invoked 1907 * @param callback observer to be invoked when the status changes 1908 * @return a handle that can be used to remove the listener at a later time 1909 */ 1910 public static Object addStatusChangeListener(int mask, final SyncStatusObserver callback) { 1911 if (callback == null) { 1912 throw new IllegalArgumentException("you passed in a null callback"); 1913 } 1914 try { 1915 ISyncStatusObserver.Stub observer = new ISyncStatusObserver.Stub() { 1916 public void onStatusChanged(int which) throws RemoteException { 1917 callback.onStatusChanged(which); 1918 } 1919 }; 1920 getContentService().addStatusChangeListener(mask, observer); 1921 return observer; 1922 } catch (RemoteException e) { 1923 throw new RuntimeException("the ContentService should always be reachable", e); 1924 } 1925 } 1926 1927 /** 1928 * Remove a previously registered status change listener. 1929 * @param handle the handle that was returned by {@link #addStatusChangeListener} 1930 */ 1931 public static void removeStatusChangeListener(Object handle) { 1932 if (handle == null) { 1933 throw new IllegalArgumentException("you passed in a null handle"); 1934 } 1935 try { 1936 getContentService().removeStatusChangeListener((ISyncStatusObserver.Stub) handle); 1937 } catch (RemoteException e) { 1938 // exception ignored; if this is thrown then it means the runtime is in the midst of 1939 // being restarted 1940 } 1941 } 1942 1943 /** 1944 * Returns sampling percentage for a given duration. 1945 * 1946 * Always returns at least 1%. 1947 */ 1948 private int samplePercentForDuration(long durationMillis) { 1949 if (durationMillis >= SLOW_THRESHOLD_MILLIS) { 1950 return 100; 1951 } 1952 return (int) (100 * durationMillis / SLOW_THRESHOLD_MILLIS) + 1; 1953 } 1954 1955 private void maybeLogQueryToEventLog(long durationMillis, 1956 Uri uri, String[] projection, 1957 String selection, String sortOrder) { 1958 if (!ENABLE_CONTENT_SAMPLE) return; 1959 int samplePercent = samplePercentForDuration(durationMillis); 1960 if (samplePercent < 100) { 1961 synchronized (mRandom) { 1962 if (mRandom.nextInt(100) >= samplePercent) { 1963 return; 1964 } 1965 } 1966 } 1967 1968 StringBuilder projectionBuffer = new StringBuilder(100); 1969 if (projection != null) { 1970 for (int i = 0; i < projection.length; ++i) { 1971 // Note: not using a comma delimiter here, as the 1972 // multiple arguments to EventLog.writeEvent later 1973 // stringify with a comma delimiter, which would make 1974 // parsing uglier later. 1975 if (i != 0) projectionBuffer.append('/'); 1976 projectionBuffer.append(projection[i]); 1977 } 1978 } 1979 1980 // ActivityThread.currentPackageName() only returns non-null if the 1981 // current thread is an application main thread. This parameter tells 1982 // us whether an event loop is blocked, and if so, which app it is. 1983 String blockingPackage = AppGlobals.getInitialPackage(); 1984 1985 EventLog.writeEvent( 1986 EventLogTags.CONTENT_QUERY_SAMPLE, 1987 uri.toString(), 1988 projectionBuffer.toString(), 1989 selection != null ? selection : "", 1990 sortOrder != null ? sortOrder : "", 1991 durationMillis, 1992 blockingPackage != null ? blockingPackage : "", 1993 samplePercent); 1994 } 1995 1996 private void maybeLogUpdateToEventLog( 1997 long durationMillis, Uri uri, String operation, String selection) { 1998 if (!ENABLE_CONTENT_SAMPLE) return; 1999 int samplePercent = samplePercentForDuration(durationMillis); 2000 if (samplePercent < 100) { 2001 synchronized (mRandom) { 2002 if (mRandom.nextInt(100) >= samplePercent) { 2003 return; 2004 } 2005 } 2006 } 2007 String blockingPackage = AppGlobals.getInitialPackage(); 2008 EventLog.writeEvent( 2009 EventLogTags.CONTENT_UPDATE_SAMPLE, 2010 uri.toString(), 2011 operation, 2012 selection != null ? selection : "", 2013 durationMillis, 2014 blockingPackage != null ? blockingPackage : "", 2015 samplePercent); 2016 } 2017 2018 private final class CursorWrapperInner extends CrossProcessCursorWrapper { 2019 private final IContentProvider mContentProvider; 2020 public static final String TAG="CursorWrapperInner"; 2021 2022 private final CloseGuard mCloseGuard = CloseGuard.get(); 2023 private boolean mProviderReleased; 2024 2025 CursorWrapperInner(Cursor cursor, IContentProvider icp) { 2026 super(cursor); 2027 mContentProvider = icp; 2028 mCloseGuard.open("close"); 2029 } 2030 2031 @Override 2032 public void close() { 2033 super.close(); 2034 ContentResolver.this.releaseProvider(mContentProvider); 2035 mProviderReleased = true; 2036 2037 if (mCloseGuard != null) { 2038 mCloseGuard.close(); 2039 } 2040 } 2041 2042 @Override 2043 protected void finalize() throws Throwable { 2044 try { 2045 if (mCloseGuard != null) { 2046 mCloseGuard.warnIfOpen(); 2047 } 2048 2049 if (!mProviderReleased && mContentProvider != null) { 2050 // Even though we are using CloseGuard, log this anyway so that 2051 // application developers always see the message in the log. 2052 Log.w(TAG, "Cursor finalized without prior close()"); 2053 ContentResolver.this.releaseProvider(mContentProvider); 2054 } 2055 } finally { 2056 super.finalize(); 2057 } 2058 } 2059 } 2060 2061 private final class ParcelFileDescriptorInner extends ParcelFileDescriptor { 2062 private final IContentProvider mContentProvider; 2063 private boolean mProviderReleased; 2064 2065 ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) { 2066 super(pfd); 2067 mContentProvider = icp; 2068 } 2069 2070 @Override 2071 public void close() throws IOException { 2072 super.close(); 2073 if (!mProviderReleased) { 2074 ContentResolver.this.releaseProvider(mContentProvider); 2075 mProviderReleased = true; 2076 } 2077 } 2078 } 2079 2080 /** @hide */ 2081 public static final String CONTENT_SERVICE_NAME = "content"; 2082 2083 /** @hide */ 2084 public static IContentService getContentService() { 2085 if (sContentService != null) { 2086 return sContentService; 2087 } 2088 IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME); 2089 if (false) Log.v("ContentService", "default service binder = " + b); 2090 sContentService = IContentService.Stub.asInterface(b); 2091 if (false) Log.v("ContentService", "default service = " + sContentService); 2092 return sContentService; 2093 } 2094 2095 /** @hide */ 2096 public String getPackageName() { 2097 return mPackageName; 2098 } 2099 2100 private static IContentService sContentService; 2101 private final Context mContext; 2102 final String mPackageName; 2103 private static final String TAG = "ContentResolver"; 2104} 2105