PageRenderTime 27ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/core/java/android/content/ContentProviderClient.java

https://gitlab.com/drgroovestarr/frameworks_base
Java | 595 lines | 434 code | 65 blank | 96 comment | 47 complexity | 049ef36a702ae4b4bda0ece9405ee51b MD5 | raw file
  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. package android.content;
  17. import android.annotation.NonNull;
  18. import android.annotation.Nullable;
  19. import android.content.res.AssetFileDescriptor;
  20. import android.database.CrossProcessCursorWrapper;
  21. import android.database.Cursor;
  22. import android.net.Uri;
  23. import android.os.Bundle;
  24. import android.os.CancellationSignal;
  25. import android.os.DeadObjectException;
  26. import android.os.Handler;
  27. import android.os.ICancellationSignal;
  28. import android.os.Looper;
  29. import android.os.ParcelFileDescriptor;
  30. import android.os.RemoteException;
  31. import android.util.Log;
  32. import com.android.internal.annotations.GuardedBy;
  33. import com.android.internal.annotations.VisibleForTesting;
  34. import com.android.internal.util.Preconditions;
  35. import dalvik.system.CloseGuard;
  36. import java.io.FileNotFoundException;
  37. import java.util.ArrayList;
  38. import java.util.concurrent.atomic.AtomicBoolean;
  39. /**
  40. * The public interface object used to interact with a specific
  41. * {@link ContentProvider}.
  42. * <p>
  43. * Instances can be obtained by calling
  44. * {@link ContentResolver#acquireContentProviderClient} or
  45. * {@link ContentResolver#acquireUnstableContentProviderClient}. Instances must
  46. * be released using {@link #close()} in order to indicate to the system that
  47. * the underlying {@link ContentProvider} is no longer needed and can be killed
  48. * to free up resources.
  49. * <p>
  50. * Note that you should generally create a new ContentProviderClient instance
  51. * for each thread that will be performing operations. Unlike
  52. * {@link ContentResolver}, the methods here such as {@link #query} and
  53. * {@link #openFile} are not thread safe -- you must not call {@link #close()}
  54. * on the ContentProviderClient those calls are made from until you are finished
  55. * with the data they have returned.
  56. */
  57. public class ContentProviderClient implements AutoCloseable {
  58. private static final String TAG = "ContentProviderClient";
  59. @GuardedBy("ContentProviderClient.class")
  60. private static Handler sAnrHandler;
  61. private final ContentResolver mContentResolver;
  62. private final IContentProvider mContentProvider;
  63. private final String mPackageName;
  64. private final boolean mStable;
  65. private final AtomicBoolean mClosed = new AtomicBoolean();
  66. private final CloseGuard mCloseGuard = CloseGuard.get();
  67. private long mAnrTimeout;
  68. private NotRespondingRunnable mAnrRunnable;
  69. /** {@hide} */
  70. @VisibleForTesting
  71. public ContentProviderClient(
  72. ContentResolver contentResolver, IContentProvider contentProvider, boolean stable) {
  73. mContentResolver = contentResolver;
  74. mContentProvider = contentProvider;
  75. mPackageName = contentResolver.mPackageName;
  76. mStable = stable;
  77. mCloseGuard.open("close");
  78. }
  79. /** {@hide} */
  80. public void setDetectNotResponding(long timeoutMillis) {
  81. synchronized (ContentProviderClient.class) {
  82. mAnrTimeout = timeoutMillis;
  83. if (timeoutMillis > 0) {
  84. if (mAnrRunnable == null) {
  85. mAnrRunnable = new NotRespondingRunnable();
  86. }
  87. if (sAnrHandler == null) {
  88. sAnrHandler = new Handler(Looper.getMainLooper(), null, true /* async */);
  89. }
  90. } else {
  91. mAnrRunnable = null;
  92. }
  93. }
  94. }
  95. private void beforeRemote() {
  96. if (mAnrRunnable != null) {
  97. sAnrHandler.postDelayed(mAnrRunnable, mAnrTimeout);
  98. }
  99. }
  100. private void afterRemote() {
  101. if (mAnrRunnable != null) {
  102. sAnrHandler.removeCallbacks(mAnrRunnable);
  103. }
  104. }
  105. /** See {@link ContentProvider#query ContentProvider.query} */
  106. public @Nullable Cursor query(@NonNull Uri url, @Nullable String[] projection,
  107. @Nullable String selection, @Nullable String[] selectionArgs,
  108. @Nullable String sortOrder) throws RemoteException {
  109. return query(url, projection, selection, selectionArgs, sortOrder, null);
  110. }
  111. /** See {@link ContentProvider#query ContentProvider.query} */
  112. public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
  113. @Nullable String selection, @Nullable String[] selectionArgs,
  114. @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal)
  115. throws RemoteException {
  116. Bundle queryArgs =
  117. ContentResolver.createSqlQueryBundle(selection, selectionArgs, sortOrder);
  118. return query(uri, projection, queryArgs, cancellationSignal);
  119. }
  120. /** See {@link ContentProvider#query ContentProvider.query} */
  121. public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
  122. Bundle queryArgs, @Nullable CancellationSignal cancellationSignal)
  123. throws RemoteException {
  124. Preconditions.checkNotNull(uri, "url");
  125. beforeRemote();
  126. try {
  127. ICancellationSignal remoteCancellationSignal = null;
  128. if (cancellationSignal != null) {
  129. cancellationSignal.throwIfCanceled();
  130. remoteCancellationSignal = mContentProvider.createCancellationSignal();
  131. cancellationSignal.setRemote(remoteCancellationSignal);
  132. }
  133. final Cursor cursor = mContentProvider.query(
  134. mPackageName, uri, projection, queryArgs, remoteCancellationSignal);
  135. if (cursor == null) {
  136. return null;
  137. }
  138. return new CursorWrapperInner(cursor);
  139. } catch (DeadObjectException e) {
  140. if (!mStable) {
  141. mContentResolver.unstableProviderDied(mContentProvider);
  142. }
  143. throw e;
  144. } finally {
  145. afterRemote();
  146. }
  147. }
  148. /** See {@link ContentProvider#getType ContentProvider.getType} */
  149. public @Nullable String getType(@NonNull Uri url) throws RemoteException {
  150. Preconditions.checkNotNull(url, "url");
  151. beforeRemote();
  152. try {
  153. return mContentProvider.getType(url);
  154. } catch (DeadObjectException e) {
  155. if (!mStable) {
  156. mContentResolver.unstableProviderDied(mContentProvider);
  157. }
  158. throw e;
  159. } finally {
  160. afterRemote();
  161. }
  162. }
  163. /** See {@link ContentProvider#getStreamTypes ContentProvider.getStreamTypes} */
  164. public @Nullable String[] getStreamTypes(@NonNull Uri url, @NonNull String mimeTypeFilter)
  165. throws RemoteException {
  166. Preconditions.checkNotNull(url, "url");
  167. Preconditions.checkNotNull(mimeTypeFilter, "mimeTypeFilter");
  168. beforeRemote();
  169. try {
  170. return mContentProvider.getStreamTypes(url, mimeTypeFilter);
  171. } catch (DeadObjectException e) {
  172. if (!mStable) {
  173. mContentResolver.unstableProviderDied(mContentProvider);
  174. }
  175. throw e;
  176. } finally {
  177. afterRemote();
  178. }
  179. }
  180. /** See {@link ContentProvider#canonicalize} */
  181. public final @Nullable Uri canonicalize(@NonNull Uri url) throws RemoteException {
  182. Preconditions.checkNotNull(url, "url");
  183. beforeRemote();
  184. try {
  185. return mContentProvider.canonicalize(mPackageName, url);
  186. } catch (DeadObjectException e) {
  187. if (!mStable) {
  188. mContentResolver.unstableProviderDied(mContentProvider);
  189. }
  190. throw e;
  191. } finally {
  192. afterRemote();
  193. }
  194. }
  195. /** See {@link ContentProvider#uncanonicalize} */
  196. public final @Nullable Uri uncanonicalize(@NonNull Uri url) throws RemoteException {
  197. Preconditions.checkNotNull(url, "url");
  198. beforeRemote();
  199. try {
  200. return mContentProvider.uncanonicalize(mPackageName, url);
  201. } catch (DeadObjectException e) {
  202. if (!mStable) {
  203. mContentResolver.unstableProviderDied(mContentProvider);
  204. }
  205. throw e;
  206. } finally {
  207. afterRemote();
  208. }
  209. }
  210. /** See {@link ContentProvider#refresh} */
  211. public boolean refresh(Uri url, @Nullable Bundle args,
  212. @Nullable CancellationSignal cancellationSignal) throws RemoteException {
  213. Preconditions.checkNotNull(url, "url");
  214. beforeRemote();
  215. try {
  216. ICancellationSignal remoteCancellationSignal = null;
  217. if (cancellationSignal != null) {
  218. cancellationSignal.throwIfCanceled();
  219. remoteCancellationSignal = mContentProvider.createCancellationSignal();
  220. cancellationSignal.setRemote(remoteCancellationSignal);
  221. }
  222. return mContentProvider.refresh(mPackageName, url, args, remoteCancellationSignal);
  223. } catch (DeadObjectException e) {
  224. if (!mStable) {
  225. mContentResolver.unstableProviderDied(mContentProvider);
  226. }
  227. throw e;
  228. } finally {
  229. afterRemote();
  230. }
  231. }
  232. /** See {@link ContentProvider#insert ContentProvider.insert} */
  233. public @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues initialValues)
  234. throws RemoteException {
  235. Preconditions.checkNotNull(url, "url");
  236. beforeRemote();
  237. try {
  238. return mContentProvider.insert(mPackageName, url, initialValues);
  239. } catch (DeadObjectException e) {
  240. if (!mStable) {
  241. mContentResolver.unstableProviderDied(mContentProvider);
  242. }
  243. throw e;
  244. } finally {
  245. afterRemote();
  246. }
  247. }
  248. /** See {@link ContentProvider#bulkInsert ContentProvider.bulkInsert} */
  249. public int bulkInsert(@NonNull Uri url, @NonNull ContentValues[] initialValues)
  250. throws RemoteException {
  251. Preconditions.checkNotNull(url, "url");
  252. Preconditions.checkNotNull(initialValues, "initialValues");
  253. beforeRemote();
  254. try {
  255. return mContentProvider.bulkInsert(mPackageName, url, initialValues);
  256. } catch (DeadObjectException e) {
  257. if (!mStable) {
  258. mContentResolver.unstableProviderDied(mContentProvider);
  259. }
  260. throw e;
  261. } finally {
  262. afterRemote();
  263. }
  264. }
  265. /** See {@link ContentProvider#delete ContentProvider.delete} */
  266. public int delete(@NonNull Uri url, @Nullable String selection,
  267. @Nullable String[] selectionArgs) throws RemoteException {
  268. Preconditions.checkNotNull(url, "url");
  269. beforeRemote();
  270. try {
  271. return mContentProvider.delete(mPackageName, url, selection, selectionArgs);
  272. } catch (DeadObjectException e) {
  273. if (!mStable) {
  274. mContentResolver.unstableProviderDied(mContentProvider);
  275. }
  276. throw e;
  277. } finally {
  278. afterRemote();
  279. }
  280. }
  281. /** See {@link ContentProvider#update ContentProvider.update} */
  282. public int update(@NonNull Uri url, @Nullable ContentValues values, @Nullable String selection,
  283. @Nullable String[] selectionArgs) throws RemoteException {
  284. Preconditions.checkNotNull(url, "url");
  285. beforeRemote();
  286. try {
  287. return mContentProvider.update(mPackageName, url, values, selection, selectionArgs);
  288. } catch (DeadObjectException e) {
  289. if (!mStable) {
  290. mContentResolver.unstableProviderDied(mContentProvider);
  291. }
  292. throw e;
  293. } finally {
  294. afterRemote();
  295. }
  296. }
  297. /**
  298. * See {@link ContentProvider#openFile ContentProvider.openFile}. Note that
  299. * this <em>does not</em>
  300. * take care of non-content: URIs such as file:. It is strongly recommended
  301. * you use the {@link ContentResolver#openFileDescriptor
  302. * ContentResolver.openFileDescriptor} API instead.
  303. */
  304. public @Nullable ParcelFileDescriptor openFile(@NonNull Uri url, @NonNull String mode)
  305. throws RemoteException, FileNotFoundException {
  306. return openFile(url, mode, null);
  307. }
  308. /**
  309. * See {@link ContentProvider#openFile ContentProvider.openFile}. Note that
  310. * this <em>does not</em>
  311. * take care of non-content: URIs such as file:. It is strongly recommended
  312. * you use the {@link ContentResolver#openFileDescriptor
  313. * ContentResolver.openFileDescriptor} API instead.
  314. */
  315. public @Nullable ParcelFileDescriptor openFile(@NonNull Uri url, @NonNull String mode,
  316. @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
  317. Preconditions.checkNotNull(url, "url");
  318. Preconditions.checkNotNull(mode, "mode");
  319. beforeRemote();
  320. try {
  321. ICancellationSignal remoteSignal = null;
  322. if (signal != null) {
  323. signal.throwIfCanceled();
  324. remoteSignal = mContentProvider.createCancellationSignal();
  325. signal.setRemote(remoteSignal);
  326. }
  327. return mContentProvider.openFile(mPackageName, url, mode, remoteSignal, null);
  328. } catch (DeadObjectException e) {
  329. if (!mStable) {
  330. mContentResolver.unstableProviderDied(mContentProvider);
  331. }
  332. throw e;
  333. } finally {
  334. afterRemote();
  335. }
  336. }
  337. /**
  338. * See {@link ContentProvider#openAssetFile ContentProvider.openAssetFile}.
  339. * Note that this <em>does not</em>
  340. * take care of non-content: URIs such as file:. It is strongly recommended
  341. * you use the {@link ContentResolver#openAssetFileDescriptor
  342. * ContentResolver.openAssetFileDescriptor} API instead.
  343. */
  344. public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri url, @NonNull String mode)
  345. throws RemoteException, FileNotFoundException {
  346. return openAssetFile(url, mode, null);
  347. }
  348. /**
  349. * See {@link ContentProvider#openAssetFile ContentProvider.openAssetFile}.
  350. * Note that this <em>does not</em>
  351. * take care of non-content: URIs such as file:. It is strongly recommended
  352. * you use the {@link ContentResolver#openAssetFileDescriptor
  353. * ContentResolver.openAssetFileDescriptor} API instead.
  354. */
  355. public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri url, @NonNull String mode,
  356. @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
  357. Preconditions.checkNotNull(url, "url");
  358. Preconditions.checkNotNull(mode, "mode");
  359. beforeRemote();
  360. try {
  361. ICancellationSignal remoteSignal = null;
  362. if (signal != null) {
  363. signal.throwIfCanceled();
  364. remoteSignal = mContentProvider.createCancellationSignal();
  365. signal.setRemote(remoteSignal);
  366. }
  367. return mContentProvider.openAssetFile(mPackageName, url, mode, remoteSignal);
  368. } catch (DeadObjectException e) {
  369. if (!mStable) {
  370. mContentResolver.unstableProviderDied(mContentProvider);
  371. }
  372. throw e;
  373. } finally {
  374. afterRemote();
  375. }
  376. }
  377. /** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */
  378. public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri,
  379. @NonNull String mimeType, @Nullable Bundle opts)
  380. throws RemoteException, FileNotFoundException {
  381. return openTypedAssetFileDescriptor(uri, mimeType, opts, null);
  382. }
  383. /** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */
  384. public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri,
  385. @NonNull String mimeType, @Nullable Bundle opts, @Nullable CancellationSignal signal)
  386. throws RemoteException, FileNotFoundException {
  387. Preconditions.checkNotNull(uri, "uri");
  388. Preconditions.checkNotNull(mimeType, "mimeType");
  389. beforeRemote();
  390. try {
  391. ICancellationSignal remoteSignal = null;
  392. if (signal != null) {
  393. signal.throwIfCanceled();
  394. remoteSignal = mContentProvider.createCancellationSignal();
  395. signal.setRemote(remoteSignal);
  396. }
  397. return mContentProvider.openTypedAssetFile(
  398. mPackageName, uri, mimeType, opts, remoteSignal);
  399. } catch (DeadObjectException e) {
  400. if (!mStable) {
  401. mContentResolver.unstableProviderDied(mContentProvider);
  402. }
  403. throw e;
  404. } finally {
  405. afterRemote();
  406. }
  407. }
  408. /** See {@link ContentProvider#applyBatch ContentProvider.applyBatch} */
  409. public @NonNull ContentProviderResult[] applyBatch(
  410. @NonNull ArrayList<ContentProviderOperation> operations)
  411. throws RemoteException, OperationApplicationException {
  412. Preconditions.checkNotNull(operations, "operations");
  413. beforeRemote();
  414. try {
  415. return mContentProvider.applyBatch(mPackageName, operations);
  416. } catch (DeadObjectException e) {
  417. if (!mStable) {
  418. mContentResolver.unstableProviderDied(mContentProvider);
  419. }
  420. throw e;
  421. } finally {
  422. afterRemote();
  423. }
  424. }
  425. /** See {@link ContentProvider#call(String, String, Bundle)} */
  426. public @Nullable Bundle call(@NonNull String method, @Nullable String arg,
  427. @Nullable Bundle extras) throws RemoteException {
  428. Preconditions.checkNotNull(method, "method");
  429. beforeRemote();
  430. try {
  431. return mContentProvider.call(mPackageName, method, arg, extras);
  432. } catch (DeadObjectException e) {
  433. if (!mStable) {
  434. mContentResolver.unstableProviderDied(mContentProvider);
  435. }
  436. throw e;
  437. } finally {
  438. afterRemote();
  439. }
  440. }
  441. /**
  442. * Closes this client connection, indicating to the system that the
  443. * underlying {@link ContentProvider} is no longer needed.
  444. */
  445. @Override
  446. public void close() {
  447. closeInternal();
  448. }
  449. /**
  450. * @deprecated replaced by {@link #close()}.
  451. */
  452. @Deprecated
  453. public boolean release() {
  454. return closeInternal();
  455. }
  456. private boolean closeInternal() {
  457. mCloseGuard.close();
  458. if (mClosed.compareAndSet(false, true)) {
  459. if (mStable) {
  460. return mContentResolver.releaseProvider(mContentProvider);
  461. } else {
  462. return mContentResolver.releaseUnstableProvider(mContentProvider);
  463. }
  464. } else {
  465. return false;
  466. }
  467. }
  468. @Override
  469. protected void finalize() throws Throwable {
  470. try {
  471. if (mCloseGuard != null) {
  472. mCloseGuard.warnIfOpen();
  473. }
  474. close();
  475. } finally {
  476. super.finalize();
  477. }
  478. }
  479. /**
  480. * Get a reference to the {@link ContentProvider} that is associated with this
  481. * client. If the {@link ContentProvider} is running in a different process then
  482. * null will be returned. This can be used if you know you are running in the same
  483. * process as a provider, and want to get direct access to its implementation details.
  484. *
  485. * @return If the associated {@link ContentProvider} is local, returns it.
  486. * Otherwise returns null.
  487. */
  488. public @Nullable ContentProvider getLocalContentProvider() {
  489. return ContentProvider.coerceToLocalContentProvider(mContentProvider);
  490. }
  491. /** {@hide} */
  492. public static void releaseQuietly(ContentProviderClient client) {
  493. if (client != null) {
  494. try {
  495. client.release();
  496. } catch (Exception ignored) {
  497. }
  498. }
  499. }
  500. private class NotRespondingRunnable implements Runnable {
  501. @Override
  502. public void run() {
  503. Log.w(TAG, "Detected provider not responding: " + mContentProvider);
  504. mContentResolver.appNotRespondingViaProvider(mContentProvider);
  505. }
  506. }
  507. private final class CursorWrapperInner extends CrossProcessCursorWrapper {
  508. private final CloseGuard mCloseGuard = CloseGuard.get();
  509. CursorWrapperInner(Cursor cursor) {
  510. super(cursor);
  511. mCloseGuard.open("close");
  512. }
  513. @Override
  514. public void close() {
  515. mCloseGuard.close();
  516. super.close();
  517. }
  518. @Override
  519. protected void finalize() throws Throwable {
  520. try {
  521. if (mCloseGuard != null) {
  522. mCloseGuard.warnIfOpen();
  523. }
  524. close();
  525. } finally {
  526. super.finalize();
  527. }
  528. }
  529. }
  530. }