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