1 /* 2 * Copyright (C) 2009 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.annotation.DurationMillisLong; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.RequiresPermission; 23 import android.annotation.SystemApi; 24 import android.compat.annotation.UnsupportedAppUsage; 25 import android.content.res.AssetFileDescriptor; 26 import android.database.CrossProcessCursorWrapper; 27 import android.database.Cursor; 28 import android.net.Uri; 29 import android.os.Binder; 30 import android.os.Build; 31 import android.os.Bundle; 32 import android.os.CancellationSignal; 33 import android.os.DeadObjectException; 34 import android.os.Handler; 35 import android.os.ICancellationSignal; 36 import android.os.Looper; 37 import android.os.ParcelFileDescriptor; 38 import android.os.RemoteException; 39 import android.util.Log; 40 41 import com.android.internal.annotations.GuardedBy; 42 import com.android.internal.annotations.VisibleForTesting; 43 44 import dalvik.system.CloseGuard; 45 46 import libcore.io.IoUtils; 47 48 import java.io.FileNotFoundException; 49 import java.util.ArrayList; 50 import java.util.Objects; 51 import java.util.concurrent.atomic.AtomicBoolean; 52 53 /** 54 * The public interface object used to interact with a specific 55 * {@link ContentProvider}. 56 * <p> 57 * Instances can be obtained by calling 58 * {@link ContentResolver#acquireContentProviderClient} or 59 * {@link ContentResolver#acquireUnstableContentProviderClient}. Instances must 60 * be released using {@link #close()} in order to indicate to the system that 61 * the underlying {@link ContentProvider} is no longer needed and can be killed 62 * to free up resources. 63 * <p> 64 * Note that you should generally create a new ContentProviderClient instance 65 * for each thread that will be performing operations. Unlike 66 * {@link ContentResolver}, the methods here such as {@link #query} and 67 * {@link #openFile} are not thread safe -- you must not call {@link #close()} 68 * on the ContentProviderClient those calls are made from until you are finished 69 * with the data they have returned. 70 */ 71 public class ContentProviderClient implements ContentInterface, AutoCloseable { 72 private static final String TAG = "ContentProviderClient"; 73 74 @GuardedBy("ContentProviderClient.class") 75 private static Handler sAnrHandler; 76 77 private final ContentResolver mContentResolver; 78 @UnsupportedAppUsage 79 private final IContentProvider mContentProvider; 80 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 81 private final String mPackageName; 82 private final @NonNull AttributionSource mAttributionSource; 83 84 private final String mAuthority; 85 private final boolean mStable; 86 87 private final AtomicBoolean mClosed = new AtomicBoolean(); 88 private final CloseGuard mCloseGuard = CloseGuard.get(); 89 90 private long mAnrTimeout; 91 private NotRespondingRunnable mAnrRunnable; 92 93 /** {@hide} */ 94 @VisibleForTesting ContentProviderClient(ContentResolver contentResolver, IContentProvider contentProvider, boolean stable)95 public ContentProviderClient(ContentResolver contentResolver, IContentProvider contentProvider, 96 boolean stable) { 97 // Only used for testing, so use a fake authority 98 this(contentResolver, contentProvider, "unknown", stable); 99 } 100 101 /** {@hide} */ ContentProviderClient(ContentResolver contentResolver, IContentProvider contentProvider, String authority, boolean stable)102 public ContentProviderClient(ContentResolver contentResolver, IContentProvider contentProvider, 103 String authority, boolean stable) { 104 mContentResolver = contentResolver; 105 mContentProvider = contentProvider; 106 mPackageName = contentResolver.mPackageName; 107 mAttributionSource = contentResolver.getAttributionSource(); 108 109 mAuthority = authority; 110 mStable = stable; 111 112 mCloseGuard.open("ContentProviderClient.close"); 113 } 114 115 /** 116 * Configure this client to automatically detect and kill the remote 117 * provider when an "application not responding" event is detected. 118 * 119 * @param timeoutMillis the duration for which a pending call is allowed 120 * block before the remote provider is considered to be 121 * unresponsive. Set to {@code 0} to allow pending calls to block 122 * indefinitely with no action taken. 123 * @hide 124 */ 125 @SystemApi 126 @RequiresPermission(android.Manifest.permission.REMOVE_TASKS) setDetectNotResponding(@urationMillisLong long timeoutMillis)127 public void setDetectNotResponding(@DurationMillisLong long timeoutMillis) { 128 synchronized (ContentProviderClient.class) { 129 mAnrTimeout = timeoutMillis; 130 131 if (timeoutMillis > 0) { 132 if (mAnrRunnable == null) { 133 mAnrRunnable = new NotRespondingRunnable(); 134 } 135 if (sAnrHandler == null) { 136 sAnrHandler = new Handler(Looper.getMainLooper(), null, true /* async */); 137 } 138 139 // If the remote process hangs, we're going to kill it, so we're 140 // technically okay doing blocking calls. 141 Binder.allowBlocking(mContentProvider.asBinder()); 142 } else { 143 mAnrRunnable = null; 144 145 // If we're no longer watching for hangs, revert back to default 146 // blocking behavior. 147 Binder.defaultBlocking(mContentProvider.asBinder()); 148 } 149 } 150 } 151 beforeRemote()152 private void beforeRemote() { 153 if (mAnrRunnable != null) { 154 sAnrHandler.postDelayed(mAnrRunnable, mAnrTimeout); 155 } 156 } 157 afterRemote()158 private void afterRemote() { 159 if (mAnrRunnable != null) { 160 sAnrHandler.removeCallbacks(mAnrRunnable); 161 } 162 } 163 164 /** See {@link ContentProvider#query ContentProvider.query} */ query(@onNull Uri url, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder)165 public @Nullable Cursor query(@NonNull Uri url, @Nullable String[] projection, 166 @Nullable String selection, @Nullable String[] selectionArgs, 167 @Nullable String sortOrder) throws RemoteException { 168 return query(url, projection, selection, selectionArgs, sortOrder, null); 169 } 170 171 /** See {@link ContentProvider#query ContentProvider.query} */ query(@onNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal)172 public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection, 173 @Nullable String selection, @Nullable String[] selectionArgs, 174 @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) 175 throws RemoteException { 176 Bundle queryArgs = 177 ContentResolver.createSqlQueryBundle(selection, selectionArgs, sortOrder); 178 return query(uri, projection, queryArgs, cancellationSignal); 179 } 180 181 /** See {@link ContentProvider#query ContentProvider.query} */ 182 @Override query(@onNull Uri uri, @Nullable String[] projection, Bundle queryArgs, @Nullable CancellationSignal cancellationSignal)183 public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection, 184 Bundle queryArgs, @Nullable CancellationSignal cancellationSignal) 185 throws RemoteException { 186 Objects.requireNonNull(uri, "url"); 187 188 beforeRemote(); 189 try { 190 ICancellationSignal remoteCancellationSignal = null; 191 if (cancellationSignal != null) { 192 cancellationSignal.throwIfCanceled(); 193 remoteCancellationSignal = mContentProvider.createCancellationSignal(); 194 cancellationSignal.setRemote(remoteCancellationSignal); 195 } 196 final Cursor cursor = mContentProvider.query( 197 mAttributionSource, uri, projection, queryArgs, 198 remoteCancellationSignal); 199 if (cursor == null) { 200 return null; 201 } 202 return new CursorWrapperInner(cursor); 203 } catch (DeadObjectException e) { 204 if (!mStable) { 205 mContentResolver.unstableProviderDied(mContentProvider); 206 } 207 throw e; 208 } finally { 209 afterRemote(); 210 } 211 } 212 213 /** See {@link ContentProvider#getType ContentProvider.getType} */ 214 @Override getType(@onNull Uri url)215 public @Nullable String getType(@NonNull Uri url) throws RemoteException { 216 Objects.requireNonNull(url, "url"); 217 218 beforeRemote(); 219 try { 220 return mContentProvider.getType(mAttributionSource, url); 221 } catch (DeadObjectException e) { 222 if (!mStable) { 223 mContentResolver.unstableProviderDied(mContentProvider); 224 } 225 throw e; 226 } finally { 227 afterRemote(); 228 } 229 } 230 231 /** See {@link ContentProvider#getStreamTypes ContentProvider.getStreamTypes} */ 232 @Override getStreamTypes(@onNull Uri url, @NonNull String mimeTypeFilter)233 public @Nullable String[] getStreamTypes(@NonNull Uri url, @NonNull String mimeTypeFilter) 234 throws RemoteException { 235 Objects.requireNonNull(url, "url"); 236 Objects.requireNonNull(mimeTypeFilter, "mimeTypeFilter"); 237 238 beforeRemote(); 239 try { 240 return mContentProvider.getStreamTypes(mAttributionSource, url, mimeTypeFilter); 241 } catch (DeadObjectException e) { 242 if (!mStable) { 243 mContentResolver.unstableProviderDied(mContentProvider); 244 } 245 throw e; 246 } finally { 247 afterRemote(); 248 } 249 } 250 251 /** See {@link ContentProvider#canonicalize} */ 252 @Override canonicalize(@onNull Uri url)253 public final @Nullable Uri canonicalize(@NonNull Uri url) throws RemoteException { 254 Objects.requireNonNull(url, "url"); 255 256 beforeRemote(); 257 try { 258 return mContentProvider.canonicalize(mAttributionSource, url); 259 } catch (DeadObjectException e) { 260 if (!mStable) { 261 mContentResolver.unstableProviderDied(mContentProvider); 262 } 263 throw e; 264 } finally { 265 afterRemote(); 266 } 267 } 268 269 /** See {@link ContentProvider#uncanonicalize} */ 270 @Override uncanonicalize(@onNull Uri url)271 public final @Nullable Uri uncanonicalize(@NonNull Uri url) throws RemoteException { 272 Objects.requireNonNull(url, "url"); 273 274 beforeRemote(); 275 try { 276 return mContentProvider.uncanonicalize(mAttributionSource, url); 277 } catch (DeadObjectException e) { 278 if (!mStable) { 279 mContentResolver.unstableProviderDied(mContentProvider); 280 } 281 throw e; 282 } finally { 283 afterRemote(); 284 } 285 } 286 287 /** See {@link ContentProvider#refresh} */ 288 @Override refresh(Uri url, @Nullable Bundle extras, @Nullable CancellationSignal cancellationSignal)289 public boolean refresh(Uri url, @Nullable Bundle extras, 290 @Nullable CancellationSignal cancellationSignal) throws RemoteException { 291 Objects.requireNonNull(url, "url"); 292 293 beforeRemote(); 294 try { 295 ICancellationSignal remoteCancellationSignal = null; 296 if (cancellationSignal != null) { 297 cancellationSignal.throwIfCanceled(); 298 remoteCancellationSignal = mContentProvider.createCancellationSignal(); 299 cancellationSignal.setRemote(remoteCancellationSignal); 300 } 301 return mContentProvider.refresh(mAttributionSource, url, extras, 302 remoteCancellationSignal); 303 } catch (DeadObjectException e) { 304 if (!mStable) { 305 mContentResolver.unstableProviderDied(mContentProvider); 306 } 307 throw e; 308 } finally { 309 afterRemote(); 310 } 311 } 312 313 /** {@hide} */ 314 @Override checkUriPermission(@onNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags)315 public int checkUriPermission(@NonNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags) 316 throws RemoteException { 317 Objects.requireNonNull(uri, "uri"); 318 319 beforeRemote(); 320 try { 321 return mContentProvider.checkUriPermission(mAttributionSource, uri, uid, 322 modeFlags); 323 } catch (DeadObjectException e) { 324 if (!mStable) { 325 mContentResolver.unstableProviderDied(mContentProvider); 326 } 327 throw e; 328 } finally { 329 afterRemote(); 330 } 331 } 332 333 /** See {@link ContentProvider#insert ContentProvider.insert} */ insert(@onNull Uri url, @Nullable ContentValues initialValues)334 public @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues initialValues) 335 throws RemoteException { 336 return insert(url, initialValues, null); 337 } 338 339 /** See {@link ContentProvider#insert ContentProvider.insert} */ 340 @Override insert(@onNull Uri url, @Nullable ContentValues initialValues, @Nullable Bundle extras)341 public @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues initialValues, 342 @Nullable Bundle extras) throws RemoteException { 343 Objects.requireNonNull(url, "url"); 344 345 beforeRemote(); 346 try { 347 return mContentProvider.insert(mAttributionSource, url, initialValues, 348 extras); 349 } catch (DeadObjectException e) { 350 if (!mStable) { 351 mContentResolver.unstableProviderDied(mContentProvider); 352 } 353 throw e; 354 } finally { 355 afterRemote(); 356 } 357 } 358 359 /** See {@link ContentProvider#bulkInsert ContentProvider.bulkInsert} */ 360 @Override bulkInsert(@onNull Uri url, @NonNull ContentValues[] initialValues)361 public int bulkInsert(@NonNull Uri url, @NonNull ContentValues[] initialValues) 362 throws RemoteException { 363 Objects.requireNonNull(url, "url"); 364 Objects.requireNonNull(initialValues, "initialValues"); 365 366 beforeRemote(); 367 try { 368 return mContentProvider.bulkInsert(mAttributionSource, url, initialValues); 369 } catch (DeadObjectException e) { 370 if (!mStable) { 371 mContentResolver.unstableProviderDied(mContentProvider); 372 } 373 throw e; 374 } finally { 375 afterRemote(); 376 } 377 } 378 379 /** See {@link ContentProvider#delete ContentProvider.delete} */ delete(@onNull Uri url, @Nullable String selection, @Nullable String[] selectionArgs)380 public int delete(@NonNull Uri url, @Nullable String selection, 381 @Nullable String[] selectionArgs) throws RemoteException { 382 return delete(url, ContentResolver.createSqlQueryBundle(selection, selectionArgs)); 383 } 384 385 /** See {@link ContentProvider#delete ContentProvider.delete} */ 386 @Override delete(@onNull Uri url, @Nullable Bundle extras)387 public int delete(@NonNull Uri url, @Nullable Bundle extras) throws RemoteException { 388 Objects.requireNonNull(url, "url"); 389 390 beforeRemote(); 391 try { 392 return mContentProvider.delete(mAttributionSource, url, extras); 393 } catch (DeadObjectException e) { 394 if (!mStable) { 395 mContentResolver.unstableProviderDied(mContentProvider); 396 } 397 throw e; 398 } finally { 399 afterRemote(); 400 } 401 } 402 403 /** See {@link ContentProvider#update ContentProvider.update} */ update(@onNull Uri url, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs)404 public int update(@NonNull Uri url, @Nullable ContentValues values, @Nullable String selection, 405 @Nullable String[] selectionArgs) throws RemoteException { 406 return update(url, values, ContentResolver.createSqlQueryBundle(selection, selectionArgs)); 407 } 408 409 /** See {@link ContentProvider#update ContentProvider.update} */ 410 @Override update(@onNull Uri url, @Nullable ContentValues values, @Nullable Bundle extras)411 public int update(@NonNull Uri url, @Nullable ContentValues values, @Nullable Bundle extras) 412 throws RemoteException { 413 Objects.requireNonNull(url, "url"); 414 415 beforeRemote(); 416 try { 417 return mContentProvider.update(mAttributionSource, url, values, extras); 418 } catch (DeadObjectException e) { 419 if (!mStable) { 420 mContentResolver.unstableProviderDied(mContentProvider); 421 } 422 throw e; 423 } finally { 424 afterRemote(); 425 } 426 } 427 428 /** 429 * See {@link ContentProvider#openFile ContentProvider.openFile}. Note that 430 * this <em>does not</em> 431 * take care of non-content: URIs such as file:. It is strongly recommended 432 * you use the {@link ContentResolver#openFileDescriptor 433 * ContentResolver.openFileDescriptor} API instead. 434 */ openFile(@onNull Uri url, @NonNull String mode)435 public @Nullable ParcelFileDescriptor openFile(@NonNull Uri url, @NonNull String mode) 436 throws RemoteException, FileNotFoundException { 437 return openFile(url, mode, null); 438 } 439 440 /** 441 * See {@link ContentProvider#openFile ContentProvider.openFile}. Note that 442 * this <em>does not</em> 443 * take care of non-content: URIs such as file:. It is strongly recommended 444 * you use the {@link ContentResolver#openFileDescriptor 445 * ContentResolver.openFileDescriptor} API instead. 446 */ 447 @Override openFile(@onNull Uri url, @NonNull String mode, @Nullable CancellationSignal signal)448 public @Nullable ParcelFileDescriptor openFile(@NonNull Uri url, @NonNull String mode, 449 @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException { 450 Objects.requireNonNull(url, "url"); 451 Objects.requireNonNull(mode, "mode"); 452 453 beforeRemote(); 454 try { 455 ICancellationSignal remoteSignal = null; 456 if (signal != null) { 457 signal.throwIfCanceled(); 458 remoteSignal = mContentProvider.createCancellationSignal(); 459 signal.setRemote(remoteSignal); 460 } 461 return mContentProvider.openFile(mAttributionSource, url, mode, remoteSignal); 462 } catch (DeadObjectException e) { 463 if (!mStable) { 464 mContentResolver.unstableProviderDied(mContentProvider); 465 } 466 throw e; 467 } finally { 468 afterRemote(); 469 } 470 } 471 472 /** 473 * See {@link ContentProvider#openAssetFile ContentProvider.openAssetFile}. 474 * Note that this <em>does not</em> 475 * take care of non-content: URIs such as file:. It is strongly recommended 476 * you use the {@link ContentResolver#openAssetFileDescriptor 477 * ContentResolver.openAssetFileDescriptor} API instead. 478 */ openAssetFile(@onNull Uri url, @NonNull String mode)479 public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri url, @NonNull String mode) 480 throws RemoteException, FileNotFoundException { 481 return openAssetFile(url, mode, null); 482 } 483 484 /** 485 * See {@link ContentProvider#openAssetFile ContentProvider.openAssetFile}. 486 * Note that this <em>does not</em> 487 * take care of non-content: URIs such as file:. It is strongly recommended 488 * you use the {@link ContentResolver#openAssetFileDescriptor 489 * ContentResolver.openAssetFileDescriptor} API instead. 490 */ 491 @Override openAssetFile(@onNull Uri url, @NonNull String mode, @Nullable CancellationSignal signal)492 public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri url, @NonNull String mode, 493 @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException { 494 Objects.requireNonNull(url, "url"); 495 Objects.requireNonNull(mode, "mode"); 496 497 beforeRemote(); 498 try { 499 ICancellationSignal remoteSignal = null; 500 if (signal != null) { 501 signal.throwIfCanceled(); 502 remoteSignal = mContentProvider.createCancellationSignal(); 503 signal.setRemote(remoteSignal); 504 } 505 return mContentProvider.openAssetFile(mAttributionSource, url, mode, 506 remoteSignal); 507 } catch (DeadObjectException e) { 508 if (!mStable) { 509 mContentResolver.unstableProviderDied(mContentProvider); 510 } 511 throw e; 512 } finally { 513 afterRemote(); 514 } 515 } 516 517 /** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */ openTypedAssetFileDescriptor(@onNull Uri uri, @NonNull String mimeType, @Nullable Bundle opts)518 public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri, 519 @NonNull String mimeType, @Nullable Bundle opts) 520 throws RemoteException, FileNotFoundException { 521 return openTypedAssetFileDescriptor(uri, mimeType, opts, null); 522 } 523 524 /** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */ openTypedAssetFileDescriptor(@onNull Uri uri, @NonNull String mimeType, @Nullable Bundle opts, @Nullable CancellationSignal signal)525 public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri, 526 @NonNull String mimeType, @Nullable Bundle opts, @Nullable CancellationSignal signal) 527 throws RemoteException, FileNotFoundException { 528 return openTypedAssetFile(uri, mimeType, opts, signal); 529 } 530 531 @Override openTypedAssetFile(@onNull Uri uri, @NonNull String mimeTypeFilter, @Nullable Bundle opts, @Nullable CancellationSignal signal)532 public final @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri, 533 @NonNull String mimeTypeFilter, @Nullable Bundle opts, 534 @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException { 535 Objects.requireNonNull(uri, "uri"); 536 Objects.requireNonNull(mimeTypeFilter, "mimeTypeFilter"); 537 538 beforeRemote(); 539 try { 540 ICancellationSignal remoteSignal = null; 541 if (signal != null) { 542 signal.throwIfCanceled(); 543 remoteSignal = mContentProvider.createCancellationSignal(); 544 signal.setRemote(remoteSignal); 545 } 546 return mContentProvider.openTypedAssetFile( 547 mAttributionSource, uri, mimeTypeFilter, opts, remoteSignal); 548 } catch (DeadObjectException e) { 549 if (!mStable) { 550 mContentResolver.unstableProviderDied(mContentProvider); 551 } 552 throw e; 553 } finally { 554 afterRemote(); 555 } 556 } 557 558 /** See {@link ContentProvider#applyBatch ContentProvider.applyBatch} */ applyBatch( @onNull ArrayList<ContentProviderOperation> operations)559 public @NonNull ContentProviderResult[] applyBatch( 560 @NonNull ArrayList<ContentProviderOperation> operations) 561 throws RemoteException, OperationApplicationException { 562 return applyBatch(mAuthority, operations); 563 } 564 565 /** See {@link ContentProvider#applyBatch ContentProvider.applyBatch} */ 566 @Override applyBatch(@onNull String authority, @NonNull ArrayList<ContentProviderOperation> operations)567 public @NonNull ContentProviderResult[] applyBatch(@NonNull String authority, 568 @NonNull ArrayList<ContentProviderOperation> operations) 569 throws RemoteException, OperationApplicationException { 570 Objects.requireNonNull(operations, "operations"); 571 572 beforeRemote(); 573 try { 574 return mContentProvider.applyBatch(mAttributionSource, authority, 575 operations); 576 } catch (DeadObjectException e) { 577 if (!mStable) { 578 mContentResolver.unstableProviderDied(mContentProvider); 579 } 580 throw e; 581 } finally { 582 afterRemote(); 583 } 584 } 585 586 /** See {@link ContentProvider#call(String, String, Bundle)} */ call(@onNull String method, @Nullable String arg, @Nullable Bundle extras)587 public @Nullable Bundle call(@NonNull String method, @Nullable String arg, 588 @Nullable Bundle extras) throws RemoteException { 589 return call(mAuthority, method, arg, extras); 590 } 591 592 /** See {@link ContentProvider#call(String, String, Bundle)} */ 593 @Override call(@onNull String authority, @NonNull String method, @Nullable String arg, @Nullable Bundle extras)594 public @Nullable Bundle call(@NonNull String authority, @NonNull String method, 595 @Nullable String arg, @Nullable Bundle extras) throws RemoteException { 596 Objects.requireNonNull(authority, "authority"); 597 Objects.requireNonNull(method, "method"); 598 599 beforeRemote(); 600 try { 601 return mContentProvider.call(mAttributionSource, authority, method, arg, 602 extras); 603 } catch (DeadObjectException e) { 604 if (!mStable) { 605 mContentResolver.unstableProviderDied(mContentProvider); 606 } 607 throw e; 608 } finally { 609 afterRemote(); 610 } 611 } 612 613 /** 614 * Closes this client connection, indicating to the system that the 615 * underlying {@link ContentProvider} is no longer needed. 616 */ 617 @Override close()618 public void close() { 619 closeInternal(); 620 } 621 622 /** 623 * @deprecated replaced by {@link #close()}. 624 */ 625 @Deprecated release()626 public boolean release() { 627 return closeInternal(); 628 } 629 closeInternal()630 private boolean closeInternal() { 631 mCloseGuard.close(); 632 if (mClosed.compareAndSet(false, true)) { 633 // We can't do ANR checks after we cease to exist! Reset any 634 // blocking behavior changes we might have made. 635 setDetectNotResponding(0); 636 637 if (mStable) { 638 return mContentResolver.releaseProvider(mContentProvider); 639 } else { 640 return mContentResolver.releaseUnstableProvider(mContentProvider); 641 } 642 } else { 643 return false; 644 } 645 } 646 647 @Override finalize()648 protected void finalize() throws Throwable { 649 try { 650 if (mCloseGuard != null) { 651 mCloseGuard.warnIfOpen(); 652 } 653 654 close(); 655 } finally { 656 super.finalize(); 657 } 658 } 659 660 /** 661 * Get a reference to the {@link ContentProvider} that is associated with this 662 * client. If the {@link ContentProvider} is running in a different process then 663 * null will be returned. This can be used if you know you are running in the same 664 * process as a provider, and want to get direct access to its implementation details. 665 * 666 * @return If the associated {@link ContentProvider} is local, returns it. 667 * Otherwise returns null. 668 */ getLocalContentProvider()669 public @Nullable ContentProvider getLocalContentProvider() { 670 return ContentProvider.coerceToLocalContentProvider(mContentProvider); 671 } 672 673 /** {@hide} */ 674 @Deprecated closeQuietly(ContentProviderClient client)675 public static void closeQuietly(ContentProviderClient client) { 676 IoUtils.closeQuietly(client); 677 } 678 679 /** {@hide} */ 680 @Deprecated releaseQuietly(ContentProviderClient client)681 public static void releaseQuietly(ContentProviderClient client) { 682 IoUtils.closeQuietly(client); 683 } 684 685 private class NotRespondingRunnable implements Runnable { 686 @Override run()687 public void run() { 688 Log.w(TAG, "Detected provider not responding: " + mContentProvider); 689 mContentResolver.appNotRespondingViaProvider(mContentProvider); 690 } 691 } 692 693 private final class CursorWrapperInner extends CrossProcessCursorWrapper { 694 private final CloseGuard mCloseGuard = CloseGuard.get(); 695 CursorWrapperInner(Cursor cursor)696 CursorWrapperInner(Cursor cursor) { 697 super(cursor); 698 mCloseGuard.open("CursorWrapperInner.close"); 699 } 700 701 @Override close()702 public void close() { 703 mCloseGuard.close(); 704 super.close(); 705 } 706 707 @Override finalize()708 protected void finalize() throws Throwable { 709 try { 710 if (mCloseGuard != null) { 711 mCloseGuard.warnIfOpen(); 712 } 713 714 close(); 715 } finally { 716 super.finalize(); 717 } 718 } 719 } 720 } 721