blob: 9221fbb50c96e17085ad7e0e48db4e623aabc2fb [file] [log] [blame]
Fred Quintana6a8d5332009-05-07 17:35:38 -07001/*
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
Fred Quintana718d8a22009-04-29 17:53:20 -070017package android.content;
18
Jeff Sharkey73ed5092015-06-12 09:49:31 -070019import android.annotation.NonNull;
20import android.annotation.Nullable;
Jeff Sharkey7aa76012013-09-30 14:26:27 -070021import android.content.res.AssetFileDescriptor;
Jeff Sharkey60cfad82016-01-05 17:30:57 -070022import android.database.CrossProcessCursorWrapper;
Fred Quintana718d8a22009-04-29 17:53:20 -070023import android.database.Cursor;
24import android.net.Uri;
Dianne Hackborn23fdaf62010-08-06 12:16:55 -070025import android.os.Bundle;
Jeff Browna7771df2012-05-07 20:06:46 -070026import android.os.CancellationSignal;
Dianne Hackborn6ae8d182012-05-23 13:12:42 -070027import android.os.DeadObjectException;
Jeff Sharkey7aa76012013-09-30 14:26:27 -070028import android.os.Handler;
Jeff Browna7771df2012-05-07 20:06:46 -070029import android.os.ICancellationSignal;
Jeff Sharkey7aa76012013-09-30 14:26:27 -070030import android.os.Looper;
Fred Quintana718d8a22009-04-29 17:53:20 -070031import android.os.ParcelFileDescriptor;
Jeff Sharkey7aa76012013-09-30 14:26:27 -070032import android.os.RemoteException;
33import android.util.Log;
34
35import com.android.internal.annotations.GuardedBy;
Jeff Sharkey60cfad82016-01-05 17:30:57 -070036import com.android.internal.annotations.VisibleForTesting;
Jeff Sharkey73ed5092015-06-12 09:49:31 -070037import com.android.internal.util.Preconditions;
Fred Quintana718d8a22009-04-29 17:53:20 -070038
Jeff Sharkey5545f562013-09-21 13:57:33 -070039import dalvik.system.CloseGuard;
40
Fred Quintana718d8a22009-04-29 17:53:20 -070041import java.io.FileNotFoundException;
Fred Quintana03d94902009-05-22 14:23:31 -070042import java.util.ArrayList;
Jeff Sharkey60cfad82016-01-05 17:30:57 -070043import java.util.concurrent.atomic.AtomicBoolean;
Fred Quintana718d8a22009-04-29 17:53:20 -070044
45/**
Jeff Sharkey60cfad82016-01-05 17:30:57 -070046 * The public interface object used to interact with a specific
47 * {@link ContentProvider}.
48 * <p>
49 * Instances can be obtained by calling
50 * {@link ContentResolver#acquireContentProviderClient} or
51 * {@link ContentResolver#acquireUnstableContentProviderClient}. Instances must
52 * be released using {@link #close()} in order to indicate to the system that
53 * the underlying {@link ContentProvider} is no longer needed and can be killed
54 * to free up resources.
55 * <p>
56 * Note that you should generally create a new ContentProviderClient instance
57 * for each thread that will be performing operations. Unlike
Dianne Hackborn6ae8d182012-05-23 13:12:42 -070058 * {@link ContentResolver}, the methods here such as {@link #query} and
Jeff Sharkey60cfad82016-01-05 17:30:57 -070059 * {@link #openFile} are not thread safe -- you must not call {@link #close()}
60 * on the ContentProviderClient those calls are made from until you are finished
61 * with the data they have returned.
Fred Quintana718d8a22009-04-29 17:53:20 -070062 */
Jeff Sharkey60cfad82016-01-05 17:30:57 -070063public class ContentProviderClient implements AutoCloseable {
Jeff Sharkey7aa76012013-09-30 14:26:27 -070064 private static final String TAG = "ContentProviderClient";
65
66 @GuardedBy("ContentProviderClient.class")
67 private static Handler sAnrHandler;
68
Fred Quintana718d8a22009-04-29 17:53:20 -070069 private final ContentResolver mContentResolver;
Jeff Sharkey7aa76012013-09-30 14:26:27 -070070 private final IContentProvider mContentProvider;
Dianne Hackborn35654b62013-01-14 17:38:02 -080071 private final String mPackageName;
Dianne Hackborn652b6d12012-05-09 18:18:40 -070072 private final boolean mStable;
Fred Quintana718d8a22009-04-29 17:53:20 -070073
Jeff Sharkey60cfad82016-01-05 17:30:57 -070074 private final AtomicBoolean mClosed = new AtomicBoolean();
75 private final CloseGuard mCloseGuard = CloseGuard.get();
Jeff Sharkey5545f562013-09-21 13:57:33 -070076
Jeff Sharkey7aa76012013-09-30 14:26:27 -070077 private long mAnrTimeout;
78 private NotRespondingRunnable mAnrRunnable;
79
Jeff Sharkey7aa76012013-09-30 14:26:27 -070080 /** {@hide} */
Jeff Sharkey60cfad82016-01-05 17:30:57 -070081 @VisibleForTesting
82 public ContentProviderClient(
Jeff Sharkey7aa76012013-09-30 14:26:27 -070083 ContentResolver contentResolver, IContentProvider contentProvider, boolean stable) {
Fred Quintana718d8a22009-04-29 17:53:20 -070084 mContentResolver = contentResolver;
Jeff Sharkey7aa76012013-09-30 14:26:27 -070085 mContentProvider = contentProvider;
Dianne Hackborn35654b62013-01-14 17:38:02 -080086 mPackageName = contentResolver.mPackageName;
Jeff Sharkey60cfad82016-01-05 17:30:57 -070087
Dianne Hackborn652b6d12012-05-09 18:18:40 -070088 mStable = stable;
Jeff Sharkey7aa76012013-09-30 14:26:27 -070089
Jeff Sharkey60cfad82016-01-05 17:30:57 -070090 mCloseGuard.open("close");
Fred Quintana718d8a22009-04-29 17:53:20 -070091 }
92
Jeff Sharkey7aa76012013-09-30 14:26:27 -070093 /** {@hide} */
94 public void setDetectNotResponding(long timeoutMillis) {
95 synchronized (ContentProviderClient.class) {
96 mAnrTimeout = timeoutMillis;
97
98 if (timeoutMillis > 0) {
99 if (mAnrRunnable == null) {
100 mAnrRunnable = new NotRespondingRunnable();
101 }
102 if (sAnrHandler == null) {
103 sAnrHandler = new Handler(Looper.getMainLooper(), null, true /* async */);
104 }
105 } else {
106 mAnrRunnable = null;
107 }
108 }
109 }
110
111 private void beforeRemote() {
112 if (mAnrRunnable != null) {
113 sAnrHandler.postDelayed(mAnrRunnable, mAnrTimeout);
114 }
115 }
116
117 private void afterRemote() {
118 if (mAnrRunnable != null) {
119 sAnrHandler.removeCallbacks(mAnrRunnable);
120 }
121 }
122
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700123 /** See {@link ContentProvider#query ContentProvider.query} */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700124 public @Nullable Cursor query(@NonNull Uri url, @Nullable String[] projection,
125 @Nullable String selection, @Nullable String[] selectionArgs,
126 @Nullable String sortOrder) throws RemoteException {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700127 return query(url, projection, selection, selectionArgs, sortOrder, null);
Jeff Brown75ea64f2012-01-25 19:37:13 -0800128 }
129
130 /** See {@link ContentProvider#query ContentProvider.query} */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700131 public @Nullable Cursor query(@NonNull Uri url, @Nullable String[] projection,
132 @Nullable String selection, @Nullable String[] selectionArgs,
133 @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal)
134 throws RemoteException {
135 Preconditions.checkNotNull(url, "url");
136
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700137 beforeRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700138 try {
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700139 ICancellationSignal remoteCancellationSignal = null;
140 if (cancellationSignal != null) {
141 cancellationSignal.throwIfCanceled();
142 remoteCancellationSignal = mContentProvider.createCancellationSignal();
143 cancellationSignal.setRemote(remoteCancellationSignal);
144 }
Jeff Sharkey60cfad82016-01-05 17:30:57 -0700145 final Cursor cursor = mContentProvider.query(mPackageName, url, projection, selection,
146 selectionArgs, sortOrder, remoteCancellationSignal);
Jeff Sharkey703fe242016-01-07 18:52:26 -0700147 if (cursor == null) {
148 return null;
149 }
150
Makoto Onukie798ba12016-02-05 11:43:47 -0800151 if ("com.google.android.gms".equals(mPackageName)) {
Jeff Sharkey8b0db042016-01-07 09:47:20 -0700152 // They're casting to a concrete subclass, sigh
153 return cursor;
154 } else {
155 return new CursorWrapperInner(cursor);
156 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700157 } catch (DeadObjectException e) {
158 if (!mStable) {
159 mContentResolver.unstableProviderDied(mContentProvider);
160 }
161 throw e;
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700162 } finally {
163 afterRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700164 }
Fred Quintana718d8a22009-04-29 17:53:20 -0700165 }
166
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700167 /** See {@link ContentProvider#getType ContentProvider.getType} */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700168 public @Nullable String getType(@NonNull Uri url) throws RemoteException {
169 Preconditions.checkNotNull(url, "url");
170
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700171 beforeRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700172 try {
173 return mContentProvider.getType(url);
174 } catch (DeadObjectException e) {
175 if (!mStable) {
176 mContentResolver.unstableProviderDied(mContentProvider);
177 }
178 throw e;
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700179 } finally {
180 afterRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700181 }
Fred Quintana718d8a22009-04-29 17:53:20 -0700182 }
183
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700184 /** See {@link ContentProvider#getStreamTypes ContentProvider.getStreamTypes} */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700185 public @Nullable String[] getStreamTypes(@NonNull Uri url, @NonNull String mimeTypeFilter)
186 throws RemoteException {
187 Preconditions.checkNotNull(url, "url");
188 Preconditions.checkNotNull(mimeTypeFilter, "mimeTypeFilter");
189
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700190 beforeRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700191 try {
192 return mContentProvider.getStreamTypes(url, mimeTypeFilter);
193 } catch (DeadObjectException e) {
194 if (!mStable) {
195 mContentResolver.unstableProviderDied(mContentProvider);
196 }
197 throw e;
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700198 } finally {
199 afterRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700200 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700201 }
202
Dianne Hackborn38ed2a42013-09-06 16:17:22 -0700203 /** See {@link ContentProvider#canonicalize} */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700204 public final @Nullable Uri canonicalize(@NonNull Uri url) throws RemoteException {
205 Preconditions.checkNotNull(url, "url");
206
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700207 beforeRemote();
Dianne Hackborn38ed2a42013-09-06 16:17:22 -0700208 try {
209 return mContentProvider.canonicalize(mPackageName, url);
210 } catch (DeadObjectException e) {
211 if (!mStable) {
212 mContentResolver.unstableProviderDied(mContentProvider);
213 }
214 throw e;
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700215 } finally {
216 afterRemote();
Dianne Hackborn38ed2a42013-09-06 16:17:22 -0700217 }
218 }
219
220 /** See {@link ContentProvider#uncanonicalize} */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700221 public final @Nullable Uri uncanonicalize(@NonNull Uri url) throws RemoteException {
222 Preconditions.checkNotNull(url, "url");
223
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700224 beforeRemote();
Dianne Hackborn38ed2a42013-09-06 16:17:22 -0700225 try {
226 return mContentProvider.uncanonicalize(mPackageName, url);
227 } catch (DeadObjectException e) {
228 if (!mStable) {
229 mContentResolver.unstableProviderDied(mContentProvider);
230 }
231 throw e;
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700232 } finally {
233 afterRemote();
Dianne Hackborn38ed2a42013-09-06 16:17:22 -0700234 }
235 }
236
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700237 /** See {@link ContentProvider#insert ContentProvider.insert} */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700238 public @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues initialValues)
239 throws RemoteException {
240 Preconditions.checkNotNull(url, "url");
241
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700242 beforeRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700243 try {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800244 return mContentProvider.insert(mPackageName, url, initialValues);
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700245 } catch (DeadObjectException e) {
246 if (!mStable) {
247 mContentResolver.unstableProviderDied(mContentProvider);
248 }
249 throw e;
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700250 } finally {
251 afterRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700252 }
Fred Quintana718d8a22009-04-29 17:53:20 -0700253 }
254
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700255 /** See {@link ContentProvider#bulkInsert ContentProvider.bulkInsert} */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700256 public int bulkInsert(@NonNull Uri url, @NonNull ContentValues[] initialValues)
257 throws RemoteException {
258 Preconditions.checkNotNull(url, "url");
259 Preconditions.checkNotNull(initialValues, "initialValues");
260
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700261 beforeRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700262 try {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800263 return mContentProvider.bulkInsert(mPackageName, url, initialValues);
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700264 } catch (DeadObjectException e) {
265 if (!mStable) {
266 mContentResolver.unstableProviderDied(mContentProvider);
267 }
268 throw e;
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700269 } finally {
270 afterRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700271 }
Fred Quintana718d8a22009-04-29 17:53:20 -0700272 }
273
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700274 /** See {@link ContentProvider#delete ContentProvider.delete} */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700275 public int delete(@NonNull Uri url, @Nullable String selection,
276 @Nullable String[] selectionArgs) throws RemoteException {
277 Preconditions.checkNotNull(url, "url");
278
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700279 beforeRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700280 try {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800281 return mContentProvider.delete(mPackageName, url, selection, selectionArgs);
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700282 } catch (DeadObjectException e) {
283 if (!mStable) {
284 mContentResolver.unstableProviderDied(mContentProvider);
285 }
286 throw e;
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700287 } finally {
288 afterRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700289 }
Fred Quintana718d8a22009-04-29 17:53:20 -0700290 }
291
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700292 /** See {@link ContentProvider#update ContentProvider.update} */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700293 public int update(@NonNull Uri url, @Nullable ContentValues values, @Nullable String selection,
294 @Nullable String[] selectionArgs) throws RemoteException {
295 Preconditions.checkNotNull(url, "url");
296
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700297 beforeRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700298 try {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800299 return mContentProvider.update(mPackageName, url, values, selection, selectionArgs);
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700300 } catch (DeadObjectException e) {
301 if (!mStable) {
302 mContentResolver.unstableProviderDied(mContentProvider);
303 }
304 throw e;
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700305 } finally {
306 afterRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700307 }
Fred Quintana718d8a22009-04-29 17:53:20 -0700308 }
309
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700310 /**
311 * See {@link ContentProvider#openFile ContentProvider.openFile}. Note that
312 * this <em>does not</em>
313 * take care of non-content: URIs such as file:. It is strongly recommended
314 * you use the {@link ContentResolver#openFileDescriptor
315 * ContentResolver.openFileDescriptor} API instead.
316 */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700317 public @Nullable ParcelFileDescriptor openFile(@NonNull Uri url, @NonNull String mode)
Fred Quintana718d8a22009-04-29 17:53:20 -0700318 throws RemoteException, FileNotFoundException {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700319 return openFile(url, mode, null);
320 }
321
322 /**
323 * See {@link ContentProvider#openFile ContentProvider.openFile}. Note that
324 * this <em>does not</em>
325 * take care of non-content: URIs such as file:. It is strongly recommended
326 * you use the {@link ContentResolver#openFileDescriptor
327 * ContentResolver.openFileDescriptor} API instead.
328 */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700329 public @Nullable ParcelFileDescriptor openFile(@NonNull Uri url, @NonNull String mode,
330 @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
331 Preconditions.checkNotNull(url, "url");
332 Preconditions.checkNotNull(mode, "mode");
333
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700334 beforeRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700335 try {
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700336 ICancellationSignal remoteSignal = null;
337 if (signal != null) {
338 signal.throwIfCanceled();
339 remoteSignal = mContentProvider.createCancellationSignal();
340 signal.setRemote(remoteSignal);
341 }
Dianne Hackbornff170242014-11-19 10:59:01 -0800342 return mContentProvider.openFile(mPackageName, url, mode, remoteSignal, null);
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700343 } catch (DeadObjectException e) {
344 if (!mStable) {
345 mContentResolver.unstableProviderDied(mContentProvider);
346 }
347 throw e;
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700348 } finally {
349 afterRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700350 }
Fred Quintana718d8a22009-04-29 17:53:20 -0700351 }
352
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700353 /**
354 * See {@link ContentProvider#openAssetFile ContentProvider.openAssetFile}.
355 * Note that this <em>does not</em>
356 * take care of non-content: URIs such as file:. It is strongly recommended
357 * you use the {@link ContentResolver#openAssetFileDescriptor
358 * ContentResolver.openAssetFileDescriptor} API instead.
359 */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700360 public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri url, @NonNull String mode)
Fred Quintana718d8a22009-04-29 17:53:20 -0700361 throws RemoteException, FileNotFoundException {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700362 return openAssetFile(url, mode, null);
363 }
364
365 /**
366 * See {@link ContentProvider#openAssetFile ContentProvider.openAssetFile}.
367 * Note that this <em>does not</em>
368 * take care of non-content: URIs such as file:. It is strongly recommended
369 * you use the {@link ContentResolver#openAssetFileDescriptor
370 * ContentResolver.openAssetFileDescriptor} API instead.
371 */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700372 public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri url, @NonNull String mode,
373 @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
374 Preconditions.checkNotNull(url, "url");
375 Preconditions.checkNotNull(mode, "mode");
376
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700377 beforeRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700378 try {
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700379 ICancellationSignal remoteSignal = null;
380 if (signal != null) {
381 signal.throwIfCanceled();
382 remoteSignal = mContentProvider.createCancellationSignal();
383 signal.setRemote(remoteSignal);
384 }
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700385 return mContentProvider.openAssetFile(mPackageName, url, mode, remoteSignal);
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700386 } catch (DeadObjectException e) {
387 if (!mStable) {
388 mContentResolver.unstableProviderDied(mContentProvider);
389 }
390 throw e;
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700391 } finally {
392 afterRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700393 }
Fred Quintana718d8a22009-04-29 17:53:20 -0700394 }
395
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700396 /** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700397 public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri,
398 @NonNull String mimeType, @Nullable Bundle opts)
399 throws RemoteException, FileNotFoundException {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700400 return openTypedAssetFileDescriptor(uri, mimeType, opts, null);
401 }
402
403 /** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700404 public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri,
405 @NonNull String mimeType, @Nullable Bundle opts, @Nullable CancellationSignal signal)
406 throws RemoteException, FileNotFoundException {
407 Preconditions.checkNotNull(uri, "uri");
408 Preconditions.checkNotNull(mimeType, "mimeType");
409
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700410 beforeRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700411 try {
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700412 ICancellationSignal remoteSignal = null;
413 if (signal != null) {
414 signal.throwIfCanceled();
415 remoteSignal = mContentProvider.createCancellationSignal();
416 signal.setRemote(remoteSignal);
417 }
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700418 return mContentProvider.openTypedAssetFile(
419 mPackageName, uri, mimeType, opts, remoteSignal);
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700420 } catch (DeadObjectException e) {
421 if (!mStable) {
422 mContentResolver.unstableProviderDied(mContentProvider);
423 }
424 throw e;
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700425 } finally {
426 afterRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700427 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700428 }
429
430 /** See {@link ContentProvider#applyBatch ContentProvider.applyBatch} */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700431 public @NonNull ContentProviderResult[] applyBatch(
432 @NonNull ArrayList<ContentProviderOperation> operations)
433 throws RemoteException, OperationApplicationException {
434 Preconditions.checkNotNull(operations, "operations");
435
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700436 beforeRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700437 try {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800438 return mContentProvider.applyBatch(mPackageName, operations);
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700439 } catch (DeadObjectException e) {
440 if (!mStable) {
441 mContentResolver.unstableProviderDied(mContentProvider);
442 }
443 throw e;
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700444 } finally {
445 afterRemote();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700446 }
Fred Quintana6a8d5332009-05-07 17:35:38 -0700447 }
448
Dianne Hackborn7d19e022012-08-07 19:12:33 -0700449 /** See {@link ContentProvider#call(String, String, Bundle)} */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700450 public @Nullable Bundle call(@NonNull String method, @Nullable String arg,
451 @Nullable Bundle extras) throws RemoteException {
452 Preconditions.checkNotNull(method, "method");
453
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700454 beforeRemote();
Dianne Hackborn7d19e022012-08-07 19:12:33 -0700455 try {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800456 return mContentProvider.call(mPackageName, method, arg, extras);
Dianne Hackborn7d19e022012-08-07 19:12:33 -0700457 } catch (DeadObjectException e) {
458 if (!mStable) {
459 mContentResolver.unstableProviderDied(mContentProvider);
460 }
461 throw e;
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700462 } finally {
463 afterRemote();
Dianne Hackborn7d19e022012-08-07 19:12:33 -0700464 }
465 }
466
Fred Quintana718d8a22009-04-29 17:53:20 -0700467 /**
Jeff Sharkey60cfad82016-01-05 17:30:57 -0700468 * Closes this client connection, indicating to the system that the
469 * underlying {@link ContentProvider} is no longer needed.
Fred Quintana718d8a22009-04-29 17:53:20 -0700470 */
Jeff Sharkey60cfad82016-01-05 17:30:57 -0700471 @Override
472 public void close() {
473 closeInternal();
474 }
475
476 /**
477 * @deprecated replaced by {@link #close()}.
478 */
479 @Deprecated
Fred Quintana718d8a22009-04-29 17:53:20 -0700480 public boolean release() {
Jeff Sharkey60cfad82016-01-05 17:30:57 -0700481 return closeInternal();
482 }
483
484 private boolean closeInternal() {
485 mCloseGuard.close();
486 if (mClosed.compareAndSet(false, true)) {
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700487 if (mStable) {
488 return mContentResolver.releaseProvider(mContentProvider);
489 } else {
490 return mContentResolver.releaseUnstableProvider(mContentProvider);
491 }
Jeff Sharkey60cfad82016-01-05 17:30:57 -0700492 } else {
493 return false;
Dianne Hackborn652b6d12012-05-09 18:18:40 -0700494 }
Fred Quintana718d8a22009-04-29 17:53:20 -0700495 }
496
Jeff Sharkey5545f562013-09-21 13:57:33 -0700497 @Override
498 protected void finalize() throws Throwable {
Jeff Sharkey60cfad82016-01-05 17:30:57 -0700499 try {
500 mCloseGuard.warnIfOpen();
501 close();
502 } finally {
503 super.finalize();
Jeff Sharkey5545f562013-09-21 13:57:33 -0700504 }
505 }
506
Fred Quintana718d8a22009-04-29 17:53:20 -0700507 /**
508 * Get a reference to the {@link ContentProvider} that is associated with this
509 * client. If the {@link ContentProvider} is running in a different process then
510 * null will be returned. This can be used if you know you are running in the same
511 * process as a provider, and want to get direct access to its implementation details.
512 *
513 * @return If the associated {@link ContentProvider} is local, returns it.
514 * Otherwise returns null.
515 */
Jeff Sharkey73ed5092015-06-12 09:49:31 -0700516 public @Nullable ContentProvider getLocalContentProvider() {
Fred Quintana718d8a22009-04-29 17:53:20 -0700517 return ContentProvider.coerceToLocalContentProvider(mContentProvider);
518 }
Jeff Sharkeyaeb16e22013-08-27 18:26:48 -0700519
520 /** {@hide} */
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700521 public static void releaseQuietly(ContentProviderClient client) {
Jeff Sharkeyaeb16e22013-08-27 18:26:48 -0700522 if (client != null) {
Jeff Sharkey3f4c2052013-09-09 16:51:06 -0700523 try {
524 client.release();
525 } catch (Exception ignored) {
526 }
Jeff Sharkeyaeb16e22013-08-27 18:26:48 -0700527 }
528 }
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700529
530 private class NotRespondingRunnable implements Runnable {
531 @Override
532 public void run() {
533 Log.w(TAG, "Detected provider not responding: " + mContentProvider);
534 mContentResolver.appNotRespondingViaProvider(mContentProvider);
535 }
536 }
Jeff Sharkey60cfad82016-01-05 17:30:57 -0700537
538 private final class CursorWrapperInner extends CrossProcessCursorWrapper {
539 private final CloseGuard mCloseGuard = CloseGuard.get();
540
541 CursorWrapperInner(Cursor cursor) {
542 super(cursor);
543 mCloseGuard.open("close");
544 }
545
546 @Override
547 public void close() {
548 mCloseGuard.close();
549 super.close();
550 }
551
552 @Override
553 protected void finalize() throws Throwable {
554 try {
555 mCloseGuard.warnIfOpen();
556 close();
557 } finally {
558 super.finalize();
559 }
560 }
561 }
Fred Quintana718d8a22009-04-29 17:53:20 -0700562}