blob: 612f1af807a9ef0944e1dc4991f9ff2ef4733dbf [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.content;
18
Dianne Hackborn334d9ae2013-02-26 15:02:06 -080019import static android.content.pm.PackageManager.GET_PROVIDERS;
Jeff Sharkey110a6b62012-03-12 11:12:41 -070020import static android.content.pm.PackageManager.PERMISSION_GRANTED;
21
Dianne Hackborn35654b62013-01-14 17:38:02 -080022import android.app.AppOpsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070024import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.pm.ProviderInfo;
26import android.content.res.AssetFileDescriptor;
27import android.content.res.Configuration;
28import android.database.Cursor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.database.SQLException;
30import android.net.Uri;
Dianne Hackborn23fdaf62010-08-06 12:16:55 -070031import android.os.AsyncTask;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.os.Binder;
Brad Fitzpatrick1877d012010-03-04 17:48:13 -080033import android.os.Bundle;
Jeff Browna7771df2012-05-07 20:06:46 -070034import android.os.CancellationSignal;
35import android.os.ICancellationSignal;
36import android.os.OperationCanceledException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.os.ParcelFileDescriptor;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070038import android.os.Process;
Jeff Brown75ea64f2012-01-25 19:37:13 -080039import android.os.RemoteException;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070040import android.os.UserHandle;
Vasu Nori0c9e14a2010-08-04 13:31:48 -070041import android.util.Log;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042
43import java.io.File;
Marco Nelissen18cb2872011-11-15 11:19:53 -080044import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import java.io.FileNotFoundException;
Dianne Hackborn23fdaf62010-08-06 12:16:55 -070046import java.io.IOException;
Marco Nelissen18cb2872011-11-15 11:19:53 -080047import java.io.PrintWriter;
Fred Quintana03d94902009-05-22 14:23:31 -070048import java.util.ArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049
50/**
51 * Content providers are one of the primary building blocks of Android applications, providing
52 * content to applications. They encapsulate data and provide it to applications through the single
53 * {@link ContentResolver} interface. A content provider is only required if you need to share
54 * data between multiple applications. For example, the contacts data is used by multiple
55 * applications and must be stored in a content provider. If you don't need to share data amongst
56 * multiple applications you can use a database directly via
57 * {@link android.database.sqlite.SQLiteDatabase}.
58 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059 * <p>When a request is made via
60 * a {@link ContentResolver} the system inspects the authority of the given URI and passes the
61 * request to the content provider registered with the authority. The content provider can interpret
62 * the rest of the URI however it wants. The {@link UriMatcher} class is helpful for parsing
63 * URIs.</p>
64 *
65 * <p>The primary methods that need to be implemented are:
66 * <ul>
Dan Egnor6fcc0f0732010-07-27 16:32:17 -070067 * <li>{@link #onCreate} which is called to initialize the provider</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068 * <li>{@link #query} which returns data to the caller</li>
69 * <li>{@link #insert} which inserts new data into the content provider</li>
70 * <li>{@link #update} which updates existing data in the content provider</li>
71 * <li>{@link #delete} which deletes data from the content provider</li>
72 * <li>{@link #getType} which returns the MIME type of data in the content provider</li>
73 * </ul></p>
74 *
Dan Egnor6fcc0f0732010-07-27 16:32:17 -070075 * <p class="caution">Data access methods (such as {@link #insert} and
76 * {@link #update}) may be called from many threads at once, and must be thread-safe.
77 * Other methods (such as {@link #onCreate}) are only called from the application
78 * main thread, and must avoid performing lengthy operations. See the method
79 * descriptions for their expected thread behavior.</p>
80 *
81 * <p>Requests to {@link ContentResolver} are automatically forwarded to the appropriate
82 * ContentProvider instance, so subclasses don't have to worry about the details of
83 * cross-process calls.</p>
Joe Fernandez558459f2011-10-13 16:47:36 -070084 *
85 * <div class="special reference">
86 * <h3>Developer Guides</h3>
87 * <p>For more information about using content providers, read the
88 * <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
89 * developer guide.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 */
Dianne Hackbornc68c9132011-07-29 01:25:18 -070091public abstract class ContentProvider implements ComponentCallbacks2 {
Vasu Nori0c9e14a2010-08-04 13:31:48 -070092 private static final String TAG = "ContentProvider";
93
Daisuke Miyakawa8280c2b2009-10-22 08:36:42 +090094 /*
95 * Note: if you add methods to ContentProvider, you must add similar methods to
96 * MockContentProvider.
97 */
98
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 private Context mContext = null;
Dianne Hackborn2af632f2009-07-08 14:56:37 -0700100 private int mMyUid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 private String mReadPermission;
102 private String mWritePermission;
Dianne Hackborn2af632f2009-07-08 14:56:37 -0700103 private PathPermission[] mPathPermissions;
Dianne Hackbornb424b632010-08-18 15:59:05 -0700104 private boolean mExported;
Dianne Hackborn7e6f9762013-02-26 13:35:11 -0800105 private boolean mNoPerms;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106
107 private Transport mTransport = new Transport();
108
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700109 /**
110 * Construct a ContentProvider instance. Content providers must be
111 * <a href="{@docRoot}guide/topics/manifest/provider-element.html">declared
112 * in the manifest</a>, accessed with {@link ContentResolver}, and created
113 * automatically by the system, so applications usually do not create
114 * ContentProvider instances directly.
115 *
116 * <p>At construction time, the object is uninitialized, and most fields and
117 * methods are unavailable. Subclasses should initialize themselves in
118 * {@link #onCreate}, not the constructor.
119 *
120 * <p>Content providers are created on the application main thread at
121 * application launch time. The constructor must not perform lengthy
122 * operations, or application startup will be delayed.
123 */
Daisuke Miyakawa8280c2b2009-10-22 08:36:42 +0900124 public ContentProvider() {
125 }
126
127 /**
128 * Constructor just for mocking.
129 *
130 * @param context A Context object which should be some mock instance (like the
131 * instance of {@link android.test.mock.MockContext}).
132 * @param readPermission The read permision you want this instance should have in the
133 * test, which is available via {@link #getReadPermission()}.
134 * @param writePermission The write permission you want this instance should have
135 * in the test, which is available via {@link #getWritePermission()}.
136 * @param pathPermissions The PathPermissions you want this instance should have
137 * in the test, which is available via {@link #getPathPermissions()}.
138 * @hide
139 */
140 public ContentProvider(
141 Context context,
142 String readPermission,
143 String writePermission,
144 PathPermission[] pathPermissions) {
145 mContext = context;
146 mReadPermission = readPermission;
147 mWritePermission = writePermission;
148 mPathPermissions = pathPermissions;
149 }
150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 /**
152 * Given an IContentProvider, try to coerce it back to the real
153 * ContentProvider object if it is running in the local process. This can
154 * be used if you know you are running in the same process as a provider,
155 * and want to get direct access to its implementation details. Most
156 * clients should not nor have a reason to use it.
157 *
158 * @param abstractInterface The ContentProvider interface that is to be
159 * coerced.
Christopher Tate2bc6eb82013-01-03 12:04:08 -0800160 * @return If the IContentProvider is non-{@code null} and local, returns its actual
161 * ContentProvider instance. Otherwise returns {@code null}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 * @hide
163 */
164 public static ContentProvider coerceToLocalContentProvider(
165 IContentProvider abstractInterface) {
166 if (abstractInterface instanceof Transport) {
167 return ((Transport)abstractInterface).getContentProvider();
168 }
169 return null;
170 }
171
172 /**
173 * Binder object that deals with remoting.
174 *
175 * @hide
176 */
177 class Transport extends ContentProviderNative {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800178 AppOpsManager mAppOpsManager = null;
Dianne Hackborn961321f2013-02-05 17:22:41 -0800179 int mReadOp = AppOpsManager.OP_NONE;
180 int mWriteOp = AppOpsManager.OP_NONE;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800181
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 ContentProvider getContentProvider() {
183 return ContentProvider.this;
184 }
185
Jeff Brownd2183652011-10-09 12:39:53 -0700186 @Override
187 public String getProviderName() {
188 return getContentProvider().getClass().getName();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 }
190
Jeff Brown75ea64f2012-01-25 19:37:13 -0800191 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -0800192 public Cursor query(String callingPkg, Uri uri, String[] projection,
Jeff Brown75ea64f2012-01-25 19:37:13 -0800193 String selection, String[] selectionArgs, String sortOrder,
Jeff Brown4c1241d2012-02-02 17:05:00 -0800194 ICancellationSignal cancellationSignal) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800195 if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornd7960d12013-01-29 18:55:48 -0800196 return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
197 CancellationSignal.fromTransport(cancellationSignal));
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800198 }
Jeff Brown75ea64f2012-01-25 19:37:13 -0800199 return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder,
Jeff Brown4c1241d2012-02-02 17:05:00 -0800200 CancellationSignal.fromTransport(cancellationSignal));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 }
202
Jeff Brown75ea64f2012-01-25 19:37:13 -0800203 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 public String getType(Uri uri) {
205 return ContentProvider.this.getType(uri);
206 }
207
Jeff Brown75ea64f2012-01-25 19:37:13 -0800208 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -0800209 public Uri insert(String callingPkg, Uri uri, ContentValues initialValues) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800210 if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornd7960d12013-01-29 18:55:48 -0800211 return rejectInsert(uri, initialValues);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800212 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 return ContentProvider.this.insert(uri, initialValues);
214 }
215
Jeff Brown75ea64f2012-01-25 19:37:13 -0800216 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -0800217 public int bulkInsert(String callingPkg, Uri uri, ContentValues[] initialValues) {
218 if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
219 return 0;
220 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 return ContentProvider.this.bulkInsert(uri, initialValues);
222 }
223
Jeff Brown75ea64f2012-01-25 19:37:13 -0800224 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -0800225 public ContentProviderResult[] applyBatch(String callingPkg,
226 ArrayList<ContentProviderOperation> operations)
Fred Quintana89437372009-05-15 15:10:40 -0700227 throws OperationApplicationException {
228 for (ContentProviderOperation operation : operations) {
229 if (operation.isReadOperation()) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800230 if (enforceReadPermission(callingPkg, operation.getUri())
231 != AppOpsManager.MODE_ALLOWED) {
232 throw new OperationApplicationException("App op not allowed", 0);
233 }
Fred Quintana89437372009-05-15 15:10:40 -0700234 }
235
236 if (operation.isWriteOperation()) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800237 if (enforceWritePermission(callingPkg, operation.getUri())
238 != AppOpsManager.MODE_ALLOWED) {
239 throw new OperationApplicationException("App op not allowed", 0);
240 }
Fred Quintana89437372009-05-15 15:10:40 -0700241 }
242 }
243 return ContentProvider.this.applyBatch(operations);
Fred Quintana6a8d5332009-05-07 17:35:38 -0700244 }
245
Jeff Brown75ea64f2012-01-25 19:37:13 -0800246 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -0800247 public int delete(String callingPkg, Uri uri, String selection, String[] selectionArgs) {
248 if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
249 return 0;
250 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 return ContentProvider.this.delete(uri, selection, selectionArgs);
252 }
253
Jeff Brown75ea64f2012-01-25 19:37:13 -0800254 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -0800255 public int update(String callingPkg, Uri uri, ContentValues values, String selection,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256 String[] selectionArgs) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800257 if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
258 return 0;
259 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 return ContentProvider.this.update(uri, values, selection, selectionArgs);
261 }
262
Jeff Brown75ea64f2012-01-25 19:37:13 -0800263 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -0800264 public ParcelFileDescriptor openFile(String callingPkg, Uri uri, String mode)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 throws FileNotFoundException {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800266 enforceFilePermission(callingPkg, uri, mode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 return ContentProvider.this.openFile(uri, mode);
268 }
269
Jeff Brown75ea64f2012-01-25 19:37:13 -0800270 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -0800271 public AssetFileDescriptor openAssetFile(String callingPkg, Uri uri, String mode)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 throws FileNotFoundException {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800273 enforceFilePermission(callingPkg, uri, mode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 return ContentProvider.this.openAssetFile(uri, mode);
275 }
276
Jeff Brown75ea64f2012-01-25 19:37:13 -0800277 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -0800278 public Bundle call(String callingPkg, String method, String arg, Bundle extras) {
Dianne Hackborn961321f2013-02-05 17:22:41 -0800279 return ContentProvider.this.callFromPackage(callingPkg, method, arg, extras);
Brad Fitzpatrick1877d012010-03-04 17:48:13 -0800280 }
281
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700282 @Override
283 public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
284 return ContentProvider.this.getStreamTypes(uri, mimeTypeFilter);
285 }
286
287 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -0800288 public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
289 Bundle opts) throws FileNotFoundException {
290 enforceFilePermission(callingPkg, uri, "r");
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700291 return ContentProvider.this.openTypedAssetFile(uri, mimeType, opts);
292 }
293
Jeff Brown75ea64f2012-01-25 19:37:13 -0800294 @Override
Jeff Brown4c1241d2012-02-02 17:05:00 -0800295 public ICancellationSignal createCancellationSignal() throws RemoteException {
296 return CancellationSignal.createTransport();
Jeff Brown75ea64f2012-01-25 19:37:13 -0800297 }
298
Dianne Hackborn35654b62013-01-14 17:38:02 -0800299 private void enforceFilePermission(String callingPkg, Uri uri, String mode)
300 throws FileNotFoundException, SecurityException {
301 if (mode != null && mode.startsWith("rw")) {
302 if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
303 throw new FileNotFoundException("App op not allowed");
304 }
305 } else {
306 if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
307 throw new FileNotFoundException("App op not allowed");
308 }
309 }
310 }
311
312 private int enforceReadPermission(String callingPkg, Uri uri) throws SecurityException {
313 enforceReadPermissionInner(uri);
Dianne Hackborn961321f2013-02-05 17:22:41 -0800314 if (mReadOp != AppOpsManager.OP_NONE) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800315 return mAppOpsManager.noteOp(mReadOp, Binder.getCallingUid(), callingPkg);
316 }
317 return AppOpsManager.MODE_ALLOWED;
318 }
319
320 private void enforceReadPermissionInner(Uri uri) throws SecurityException {
Dianne Hackborn2af632f2009-07-08 14:56:37 -0700321 final Context context = getContext();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 final int pid = Binder.getCallingPid();
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700323 final int uid = Binder.getCallingUid();
Jeff Sharkeye5d49332012-03-13 12:13:17 -0700324 String missingPerm = null;
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700325
Dianne Hackborn0d8af782012-08-17 16:51:54 -0700326 if (UserHandle.isSameApp(uid, mMyUid)) {
Jeff Sharkeye5d49332012-03-13 12:13:17 -0700327 return;
328 }
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700329
Jeff Sharkeye5d49332012-03-13 12:13:17 -0700330 if (mExported) {
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700331 final String componentPerm = getReadPermission();
Jeff Sharkeye5d49332012-03-13 12:13:17 -0700332 if (componentPerm != null) {
333 if (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED) {
334 return;
335 } else {
336 missingPerm = componentPerm;
337 }
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700338 }
339
340 // track if unprotected read is allowed; any denied
341 // <path-permission> below removes this ability
342 boolean allowDefaultRead = (componentPerm == null);
343
344 final PathPermission[] pps = getPathPermissions();
345 if (pps != null) {
346 final String path = uri.getPath();
347 for (PathPermission pp : pps) {
348 final String pathPerm = pp.getReadPermission();
349 if (pathPerm != null && pp.match(path)) {
350 if (context.checkPermission(pathPerm, pid, uid) == PERMISSION_GRANTED) {
Jeff Sharkeye5d49332012-03-13 12:13:17 -0700351 return;
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700352 } else {
353 // any denied <path-permission> means we lose
354 // default <provider> access.
355 allowDefaultRead = false;
Jeff Sharkeye5d49332012-03-13 12:13:17 -0700356 missingPerm = pathPerm;
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700357 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -0700358 }
359 }
360 }
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700361
362 // if we passed <path-permission> checks above, and no default
363 // <provider> permission, then allow access.
Jeff Sharkeye5d49332012-03-13 12:13:17 -0700364 if (allowDefaultRead) return;
Dianne Hackborn2af632f2009-07-08 14:56:37 -0700365 }
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700366
367 // last chance, check against any uri grants
368 if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
369 == PERMISSION_GRANTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 return;
371 }
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700372
Jeff Sharkeye5d49332012-03-13 12:13:17 -0700373 final String failReason = mExported
374 ? " requires " + missingPerm + ", or grantUriPermission()"
375 : " requires the provider be exported, or grantUriPermission()";
376 throw new SecurityException("Permission Denial: reading "
377 + ContentProvider.this.getClass().getName() + " uri " + uri + " from pid=" + pid
378 + ", uid=" + uid + failReason);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 }
380
Dianne Hackborn35654b62013-01-14 17:38:02 -0800381 private int enforceWritePermission(String callingPkg, Uri uri) throws SecurityException {
382 enforceWritePermissionInner(uri);
Dianne Hackborn961321f2013-02-05 17:22:41 -0800383 if (mWriteOp != AppOpsManager.OP_NONE) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800384 return mAppOpsManager.noteOp(mWriteOp, Binder.getCallingUid(), callingPkg);
385 }
386 return AppOpsManager.MODE_ALLOWED;
387 }
388
389 private void enforceWritePermissionInner(Uri uri) throws SecurityException {
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700390 final Context context = getContext();
391 final int pid = Binder.getCallingPid();
Dianne Hackborn2af632f2009-07-08 14:56:37 -0700392 final int uid = Binder.getCallingUid();
Jeff Sharkeye5d49332012-03-13 12:13:17 -0700393 String missingPerm = null;
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700394
Dianne Hackborn0d8af782012-08-17 16:51:54 -0700395 if (UserHandle.isSameApp(uid, mMyUid)) {
Jeff Sharkeye5d49332012-03-13 12:13:17 -0700396 return;
397 }
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700398
Jeff Sharkeye5d49332012-03-13 12:13:17 -0700399 if (mExported) {
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700400 final String componentPerm = getWritePermission();
Jeff Sharkeye5d49332012-03-13 12:13:17 -0700401 if (componentPerm != null) {
402 if (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED) {
403 return;
404 } else {
405 missingPerm = componentPerm;
406 }
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700407 }
408
409 // track if unprotected write is allowed; any denied
410 // <path-permission> below removes this ability
411 boolean allowDefaultWrite = (componentPerm == null);
412
413 final PathPermission[] pps = getPathPermissions();
414 if (pps != null) {
415 final String path = uri.getPath();
416 for (PathPermission pp : pps) {
417 final String pathPerm = pp.getWritePermission();
418 if (pathPerm != null && pp.match(path)) {
419 if (context.checkPermission(pathPerm, pid, uid) == PERMISSION_GRANTED) {
Jeff Sharkeye5d49332012-03-13 12:13:17 -0700420 return;
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700421 } else {
422 // any denied <path-permission> means we lose
423 // default <provider> access.
424 allowDefaultWrite = false;
Jeff Sharkeye5d49332012-03-13 12:13:17 -0700425 missingPerm = pathPerm;
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700426 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -0700427 }
428 }
429 }
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700430
431 // if we passed <path-permission> checks above, and no default
432 // <provider> permission, then allow access.
Jeff Sharkeye5d49332012-03-13 12:13:17 -0700433 if (allowDefaultWrite) return;
Dianne Hackborn2af632f2009-07-08 14:56:37 -0700434 }
Jeff Sharkey110a6b62012-03-12 11:12:41 -0700435
436 // last chance, check against any uri grants
437 if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
438 == PERMISSION_GRANTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 return;
440 }
Jeff Sharkeye5d49332012-03-13 12:13:17 -0700441
442 final String failReason = mExported
443 ? " requires " + missingPerm + ", or grantUriPermission()"
444 : " requires the provider be exported, or grantUriPermission()";
445 throw new SecurityException("Permission Denial: writing "
446 + ContentProvider.this.getClass().getName() + " uri " + uri + " from pid=" + pid
447 + ", uid=" + uid + failReason);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 }
449 }
450
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 /**
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700452 * Retrieves the Context this provider is running in. Only available once
Christopher Tate2bc6eb82013-01-03 12:04:08 -0800453 * {@link #onCreate} has been called -- this will return {@code null} in the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 * constructor.
455 */
456 public final Context getContext() {
457 return mContext;
458 }
459
460 /**
461 * Change the permission required to read data from the content
462 * provider. This is normally set for you from its manifest information
463 * when the provider is first created.
464 *
465 * @param permission Name of the permission required for read-only access.
466 */
467 protected final void setReadPermission(String permission) {
468 mReadPermission = permission;
469 }
470
471 /**
472 * Return the name of the permission required for read-only access to
473 * this content provider. This method can be called from multiple
474 * threads, as described in
Scott Main7aee61f2011-02-08 11:25:01 -0800475 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
476 * and Threads</a>.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477 */
478 public final String getReadPermission() {
479 return mReadPermission;
480 }
481
482 /**
483 * Change the permission required to read and write data in the content
484 * provider. This is normally set for you from its manifest information
485 * when the provider is first created.
486 *
487 * @param permission Name of the permission required for read/write access.
488 */
489 protected final void setWritePermission(String permission) {
490 mWritePermission = permission;
491 }
492
493 /**
494 * Return the name of the permission required for read/write access to
495 * this content provider. This method can be called from multiple
496 * threads, as described in
Scott Main7aee61f2011-02-08 11:25:01 -0800497 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
498 * and Threads</a>.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 */
500 public final String getWritePermission() {
501 return mWritePermission;
502 }
503
504 /**
Dianne Hackborn2af632f2009-07-08 14:56:37 -0700505 * Change the path-based permission required to read and/or write data in
506 * the content provider. This is normally set for you from its manifest
507 * information when the provider is first created.
508 *
509 * @param permissions Array of path permission descriptions.
510 */
511 protected final void setPathPermissions(PathPermission[] permissions) {
512 mPathPermissions = permissions;
513 }
514
515 /**
516 * Return the path-based permissions required for read and/or write access to
517 * this content provider. This method can be called from multiple
518 * threads, as described in
Scott Main7aee61f2011-02-08 11:25:01 -0800519 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
520 * and Threads</a>.
Dianne Hackborn2af632f2009-07-08 14:56:37 -0700521 */
522 public final PathPermission[] getPathPermissions() {
523 return mPathPermissions;
524 }
525
Dianne Hackborn35654b62013-01-14 17:38:02 -0800526 /** @hide */
527 public final void setAppOps(int readOp, int writeOp) {
Dianne Hackborn7e6f9762013-02-26 13:35:11 -0800528 if (!mNoPerms) {
529 mTransport.mAppOpsManager = (AppOpsManager)mContext.getSystemService(
530 Context.APP_OPS_SERVICE);
531 mTransport.mReadOp = readOp;
532 mTransport.mWriteOp = writeOp;
533 }
Dianne Hackborn35654b62013-01-14 17:38:02 -0800534 }
535
Dianne Hackborn961321f2013-02-05 17:22:41 -0800536 /** @hide */
537 public AppOpsManager getAppOpsManager() {
538 return mTransport.mAppOpsManager;
539 }
540
Dianne Hackborn2af632f2009-07-08 14:56:37 -0700541 /**
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700542 * Implement this to initialize your content provider on startup.
543 * This method is called for all registered content providers on the
544 * application main thread at application launch time. It must not perform
545 * lengthy operations, or application startup will be delayed.
546 *
547 * <p>You should defer nontrivial initialization (such as opening,
548 * upgrading, and scanning databases) until the content provider is used
549 * (via {@link #query}, {@link #insert}, etc). Deferred initialization
550 * keeps application startup fast, avoids unnecessary work if the provider
551 * turns out not to be needed, and stops database errors (such as a full
552 * disk) from halting application launch.
553 *
Dan Egnor17876aa2010-07-28 12:28:04 -0700554 * <p>If you use SQLite, {@link android.database.sqlite.SQLiteOpenHelper}
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700555 * is a helpful utility class that makes it easy to manage databases,
556 * and will automatically defer opening until first use. If you do use
557 * SQLiteOpenHelper, make sure to avoid calling
558 * {@link android.database.sqlite.SQLiteOpenHelper#getReadableDatabase} or
559 * {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase}
560 * from this method. (Instead, override
561 * {@link android.database.sqlite.SQLiteOpenHelper#onOpen} to initialize the
562 * database when it is first opened.)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 *
564 * @return true if the provider was successfully loaded, false otherwise
565 */
566 public abstract boolean onCreate();
567
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700568 /**
569 * {@inheritDoc}
570 * This method is always called on the application main thread, and must
571 * not perform lengthy operations.
572 *
573 * <p>The default content provider implementation does nothing.
574 * Override this method to take appropriate action.
575 * (Content providers do not usually care about things like screen
576 * orientation, but may want to know about locale changes.)
577 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 public void onConfigurationChanged(Configuration newConfig) {
579 }
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700580
581 /**
582 * {@inheritDoc}
583 * This method is always called on the application main thread, and must
584 * not perform lengthy operations.
585 *
586 * <p>The default content provider implementation does nothing.
587 * Subclasses may override this method to take appropriate action.
588 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589 public void onLowMemory() {
590 }
591
Dianne Hackbornc68c9132011-07-29 01:25:18 -0700592 public void onTrimMemory(int level) {
593 }
594
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 /**
Dianne Hackbornd7960d12013-01-29 18:55:48 -0800596 * @hide
597 * Implementation when a caller has performed a query on the content
598 * provider, but that call has been rejected for the operation given
599 * to {@link #setAppOps(int, int)}. The default implementation
600 * rewrites the <var>selection</var> argument to include a condition
601 * that is never true (so will always result in an empty cursor)
602 * and calls through to {@link #query(android.net.Uri, String[], String, String[],
603 * String, android.os.CancellationSignal)} with that.
604 */
605 public Cursor rejectQuery(Uri uri, String[] projection,
606 String selection, String[] selectionArgs, String sortOrder,
607 CancellationSignal cancellationSignal) {
608 // The read is not allowed... to fake it out, we replace the given
609 // selection statement with a dummy one that will always be false.
610 // This way we will get a cursor back that has the correct structure
611 // but contains no rows.
612 if (selection == null) {
613 selection = "'A' = 'B'";
614 } else {
615 selection = "'A' = 'B' AND (" + selection + ")";
616 }
617 return query(uri, projection, selection, selectionArgs, sortOrder, cancellationSignal);
618 }
619
620 /**
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700621 * Implement this to handle query requests from clients.
622 * This method can be called from multiple threads, as described in
Scott Main7aee61f2011-02-08 11:25:01 -0800623 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
624 * and Threads</a>.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800625 * <p>
626 * Example client call:<p>
627 * <pre>// Request a specific record.
628 * Cursor managedCursor = managedQuery(
Alan Jones81a476f2009-05-21 12:32:17 +1000629 ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630 projection, // Which columns to return.
631 null, // WHERE clause.
Alan Jones81a476f2009-05-21 12:32:17 +1000632 null, // WHERE clause value substitution
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 People.NAME + " ASC"); // Sort order.</pre>
634 * Example implementation:<p>
635 * <pre>// SQLiteQueryBuilder is a helper class that creates the
636 // proper SQL syntax for us.
637 SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
638
639 // Set the table we're querying.
640 qBuilder.setTables(DATABASE_TABLE_NAME);
641
642 // If the query ends in a specific record number, we're
643 // being asked for a specific record, so set the
644 // WHERE clause in our query.
645 if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){
646 qBuilder.appendWhere("_id=" + uri.getPathLeafId());
647 }
648
649 // Make the query.
650 Cursor c = qBuilder.query(mDb,
651 projection,
652 selection,
653 selectionArgs,
654 groupBy,
655 having,
656 sortOrder);
657 c.setNotificationUri(getContext().getContentResolver(), uri);
658 return c;</pre>
659 *
660 * @param uri The URI to query. This will be the full URI sent by the client;
Alan Jones81a476f2009-05-21 12:32:17 +1000661 * if the client is requesting a specific record, the URI will end in a record number
662 * that the implementation should parse and add to a WHERE or HAVING clause, specifying
663 * that _id value.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 * @param projection The list of columns to put into the cursor. If
Christopher Tate2bc6eb82013-01-03 12:04:08 -0800665 * {@code null} all columns are included.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 * @param selection A selection criteria to apply when filtering rows.
Christopher Tate2bc6eb82013-01-03 12:04:08 -0800667 * If {@code null} then all rows are included.
Alan Jones81a476f2009-05-21 12:32:17 +1000668 * @param selectionArgs You may include ?s in selection, which will be replaced by
669 * the values from selectionArgs, in order that they appear in the selection.
670 * The values will be bound as Strings.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 * @param sortOrder How the rows in the cursor should be sorted.
Christopher Tate2bc6eb82013-01-03 12:04:08 -0800672 * If {@code null} then the provider is free to define the sort order.
673 * @return a Cursor or {@code null}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 */
675 public abstract Cursor query(Uri uri, String[] projection,
676 String selection, String[] selectionArgs, String sortOrder);
677
Fred Quintana5bba6322009-10-05 14:21:12 -0700678 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -0800679 * Implement this to handle query requests from clients with support for cancellation.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800680 * This method can be called from multiple threads, as described in
681 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
682 * and Threads</a>.
683 * <p>
684 * Example client call:<p>
685 * <pre>// Request a specific record.
686 * Cursor managedCursor = managedQuery(
687 ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2),
688 projection, // Which columns to return.
689 null, // WHERE clause.
690 null, // WHERE clause value substitution
691 People.NAME + " ASC"); // Sort order.</pre>
692 * Example implementation:<p>
693 * <pre>// SQLiteQueryBuilder is a helper class that creates the
694 // proper SQL syntax for us.
695 SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
696
697 // Set the table we're querying.
698 qBuilder.setTables(DATABASE_TABLE_NAME);
699
700 // If the query ends in a specific record number, we're
701 // being asked for a specific record, so set the
702 // WHERE clause in our query.
703 if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){
704 qBuilder.appendWhere("_id=" + uri.getPathLeafId());
705 }
706
707 // Make the query.
708 Cursor c = qBuilder.query(mDb,
709 projection,
710 selection,
711 selectionArgs,
712 groupBy,
713 having,
714 sortOrder);
715 c.setNotificationUri(getContext().getContentResolver(), uri);
716 return c;</pre>
717 * <p>
718 * If you implement this method then you must also implement the version of
Jeff Brown4c1241d2012-02-02 17:05:00 -0800719 * {@link #query(Uri, String[], String, String[], String)} that does not take a cancellation
720 * signal to ensure correct operation on older versions of the Android Framework in
721 * which the cancellation signal overload was not available.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800722 *
723 * @param uri The URI to query. This will be the full URI sent by the client;
724 * if the client is requesting a specific record, the URI will end in a record number
725 * that the implementation should parse and add to a WHERE or HAVING clause, specifying
726 * that _id value.
727 * @param projection The list of columns to put into the cursor. If
Christopher Tate2bc6eb82013-01-03 12:04:08 -0800728 * {@code null} all columns are included.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800729 * @param selection A selection criteria to apply when filtering rows.
Christopher Tate2bc6eb82013-01-03 12:04:08 -0800730 * If {@code null} then all rows are included.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800731 * @param selectionArgs You may include ?s in selection, which will be replaced by
732 * the values from selectionArgs, in order that they appear in the selection.
733 * The values will be bound as Strings.
734 * @param sortOrder How the rows in the cursor should be sorted.
Christopher Tate2bc6eb82013-01-03 12:04:08 -0800735 * If {@code null} then the provider is free to define the sort order.
736 * @param cancellationSignal A signal to cancel the operation in progress, or {@code null} if none.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800737 * If the operation is canceled, then {@link OperationCanceledException} will be thrown
738 * when the query is executed.
Christopher Tate2bc6eb82013-01-03 12:04:08 -0800739 * @return a Cursor or {@code null}.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800740 */
741 public Cursor query(Uri uri, String[] projection,
742 String selection, String[] selectionArgs, String sortOrder,
Jeff Brown4c1241d2012-02-02 17:05:00 -0800743 CancellationSignal cancellationSignal) {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800744 return query(uri, projection, selection, selectionArgs, sortOrder);
745 }
746
747 /**
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700748 * Implement this to handle requests for the MIME type of the data at the
749 * given URI. The returned MIME type should start with
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 * <code>vnd.android.cursor.item</code> for a single record,
751 * or <code>vnd.android.cursor.dir/</code> for multiple items.
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700752 * This method can be called from multiple threads, as described in
Scott Main7aee61f2011-02-08 11:25:01 -0800753 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
754 * and Threads</a>.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800755 *
Dianne Hackborncca1f0e2010-09-26 18:34:53 -0700756 * <p>Note that there are no permissions needed for an application to
757 * access this information; if your content provider requires read and/or
758 * write permissions, or is not exported, all applications can still call
759 * this method regardless of their access permissions. This allows them
760 * to retrieve the MIME type for a URI when dispatching intents.
761 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 * @param uri the URI to query.
Christopher Tate2bc6eb82013-01-03 12:04:08 -0800763 * @return a MIME type string, or {@code null} if there is no type.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 */
765 public abstract String getType(Uri uri);
766
767 /**
Dianne Hackbornd7960d12013-01-29 18:55:48 -0800768 * @hide
769 * Implementation when a caller has performed an insert on the content
770 * provider, but that call has been rejected for the operation given
771 * to {@link #setAppOps(int, int)}. The default implementation simply
772 * returns a dummy URI that is the base URI with a 0 path element
773 * appended.
774 */
775 public Uri rejectInsert(Uri uri, ContentValues values) {
776 // If not allowed, we need to return some reasonable URI. Maybe the
777 // content provider should be responsible for this, but for now we
778 // will just return the base URI with a dummy '0' tagged on to it.
779 // You shouldn't be able to read if you can't write, anyway, so it
780 // shouldn't matter much what is returned.
781 return uri.buildUpon().appendPath("0").build();
782 }
783
784 /**
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700785 * Implement this to handle requests to insert a new row.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
787 * after inserting.
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700788 * This method can be called from multiple threads, as described in
Scott Main7aee61f2011-02-08 11:25:01 -0800789 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
790 * and Threads</a>.
Christopher Tate2bc6eb82013-01-03 12:04:08 -0800791 * @param uri The content:// URI of the insertion request. This must not be {@code null}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 * @param values A set of column_name/value pairs to add to the database.
Christopher Tate2bc6eb82013-01-03 12:04:08 -0800793 * This must not be {@code null}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 * @return The URI for the newly inserted item.
795 */
796 public abstract Uri insert(Uri uri, ContentValues values);
797
798 /**
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700799 * Override this to handle requests to insert a set of new rows, or the
800 * default implementation will iterate over the values and call
801 * {@link #insert} on each of them.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
803 * after inserting.
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700804 * This method can be called from multiple threads, as described in
Scott Main7aee61f2011-02-08 11:25:01 -0800805 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
806 * and Threads</a>.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 *
808 * @param uri The content:// URI of the insertion request.
809 * @param values An array of sets of column_name/value pairs to add to the database.
Christopher Tate2bc6eb82013-01-03 12:04:08 -0800810 * This must not be {@code null}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 * @return The number of values that were inserted.
812 */
813 public int bulkInsert(Uri uri, ContentValues[] values) {
814 int numValues = values.length;
815 for (int i = 0; i < numValues; i++) {
816 insert(uri, values[i]);
817 }
818 return numValues;
819 }
820
821 /**
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700822 * Implement this to handle requests to delete one or more rows.
823 * The implementation should apply the selection clause when performing
824 * deletion, allowing the operation to affect multiple rows in a directory.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800825 * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyDelete()}
826 * after deleting.
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700827 * This method can be called from multiple threads, as described in
Scott Main7aee61f2011-02-08 11:25:01 -0800828 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
829 * and Threads</a>.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830 *
831 * <p>The implementation is responsible for parsing out a row ID at the end
832 * of the URI, if a specific row is being deleted. That is, the client would
833 * pass in <code>content://contacts/people/22</code> and the implementation is
834 * responsible for parsing the record number (22) when creating a SQL statement.
835 *
836 * @param uri The full URI to query, including a row ID (if a specific record is requested).
837 * @param selection An optional restriction to apply to rows when deleting.
838 * @return The number of rows affected.
839 * @throws SQLException
840 */
841 public abstract int delete(Uri uri, String selection, String[] selectionArgs);
842
843 /**
Dan Egnor17876aa2010-07-28 12:28:04 -0700844 * Implement this to handle requests to update one or more rows.
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700845 * The implementation should update all rows matching the selection
846 * to set the columns according to the provided values map.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
848 * after updating.
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700849 * This method can be called from multiple threads, as described in
Scott Main7aee61f2011-02-08 11:25:01 -0800850 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
851 * and Threads</a>.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 *
853 * @param uri The URI to query. This can potentially have a record ID if this
854 * is an update request for a specific record.
Christopher Tate2bc6eb82013-01-03 12:04:08 -0800855 * @param values A set of column_name/value pairs to update in the database.
856 * This must not be {@code null}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 * @param selection An optional filter to match rows to update.
858 * @return the number of rows affected.
859 */
860 public abstract int update(Uri uri, ContentValues values, String selection,
861 String[] selectionArgs);
862
863 /**
Dan Egnor17876aa2010-07-28 12:28:04 -0700864 * Override this to handle requests to open a file blob.
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700865 * The default implementation always throws {@link FileNotFoundException}.
866 * This method can be called from multiple threads, as described in
Scott Main7aee61f2011-02-08 11:25:01 -0800867 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
868 * and Threads</a>.
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700869 *
Dan Egnor17876aa2010-07-28 12:28:04 -0700870 * <p>This method returns a ParcelFileDescriptor, which is returned directly
871 * to the caller. This way large data (such as images and documents) can be
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700872 * returned without copying the content.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 *
874 * <p>The returned ParcelFileDescriptor is owned by the caller, so it is
875 * their responsibility to close it when done. That is, the implementation
876 * of this method should create a new ParcelFileDescriptor for each call.
877 *
Dianne Hackborna53ee352013-02-20 12:47:02 -0800878 * <p class="note">For use in Intents, you will want to implement {@link #getType}
879 * to return the appropriate MIME type for the data returned here with
880 * the same URI. This will allow intent resolution to automatically determine the data MIME
881 * type and select the appropriate matching targets as part of its operation.</p>
882 *
883 * <p class="note">For better interoperability with other applications, it is recommended
884 * that for any URIs that can be opened, you also support queries on them
885 * containing at least the columns specified by {@link android.provider.OpenableColumns}.
886 * You may also want to support other common columns if you have additional meta-data
887 * to supply, such as {@link android.provider.MediaStore.MediaColumns#DATE_ADDED}
888 * in {@link android.provider.MediaStore.MediaColumns}.</p>
889 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890 * @param uri The URI whose file is to be opened.
891 * @param mode Access mode for the file. May be "r" for read-only access,
892 * "rw" for read and write access, or "rwt" for read and write access
893 * that truncates any existing file.
894 *
895 * @return Returns a new ParcelFileDescriptor which you can use to access
896 * the file.
897 *
898 * @throws FileNotFoundException Throws FileNotFoundException if there is
899 * no file associated with the given URI or the mode is invalid.
900 * @throws SecurityException Throws SecurityException if the caller does
901 * not have permission to access the file.
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700902 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800903 * @see #openAssetFile(Uri, String)
904 * @see #openFileHelper(Uri, String)
Dianne Hackborna53ee352013-02-20 12:47:02 -0800905 * @see #getType(android.net.Uri)
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700906 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800907 public ParcelFileDescriptor openFile(Uri uri, String mode)
908 throws FileNotFoundException {
909 throw new FileNotFoundException("No files supported by provider at "
910 + uri);
911 }
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700912
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 /**
914 * This is like {@link #openFile}, but can be implemented by providers
915 * that need to be able to return sub-sections of files, often assets
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700916 * inside of their .apk.
917 * This method can be called from multiple threads, as described in
Scott Main7aee61f2011-02-08 11:25:01 -0800918 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
919 * and Threads</a>.
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700920 *
921 * <p>If you implement this, your clients must be able to deal with such
Dan Egnor17876aa2010-07-28 12:28:04 -0700922 * file slices, either directly with
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700923 * {@link ContentResolver#openAssetFileDescriptor}, or by using the higher-level
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 * {@link ContentResolver#openInputStream ContentResolver.openInputStream}
925 * or {@link ContentResolver#openOutputStream ContentResolver.openOutputStream}
926 * methods.
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700927 *
928 * <p class="note">If you are implementing this to return a full file, you
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 * should create the AssetFileDescriptor with
930 * {@link AssetFileDescriptor#UNKNOWN_LENGTH} to be compatible with
Dan Egnor6fcc0f0732010-07-27 16:32:17 -0700931 * applications that can not handle sub-sections of files.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 *
Dianne Hackborna53ee352013-02-20 12:47:02 -0800933 * <p class="note">For use in Intents, you will want to implement {@link #getType}
934 * to return the appropriate MIME type for the data returned here with
935 * the same URI. This will allow intent resolution to automatically determine the data MIME
936 * type and select the appropriate matching targets as part of its operation.</p>
937 *
938 * <p class="note">For better interoperability with other applications, it is recommended
939 * that for any URIs that can be opened, you also support queries on them
940 * containing at least the columns specified by {@link android.provider.OpenableColumns}.</p>
941 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 * @param uri The URI whose file is to be opened.
943 * @param mode Access mode for the file. May be "r" for read-only access,
944 * "w" for write-only access (erasing whatever data is currently in
945 * the file), "wa" for write-only access to append to any existing data,
946 * "rw" for read and write access on any existing data, and "rwt" for read
947 * and write access that truncates any existing file.
948 *
949 * @return Returns a new AssetFileDescriptor which you can use to access
950 * the file.
951 *
952 * @throws FileNotFoundException Throws FileNotFoundException if there is
953 * no file associated with the given URI or the mode is invalid.
954 * @throws SecurityException Throws SecurityException if the caller does
955 * not have permission to access the file.
956 *
957 * @see #openFile(Uri, String)
958 * @see #openFileHelper(Uri, String)
Dianne Hackborna53ee352013-02-20 12:47:02 -0800959 * @see #getType(android.net.Uri)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800960 */
961 public AssetFileDescriptor openAssetFile(Uri uri, String mode)
962 throws FileNotFoundException {
963 ParcelFileDescriptor fd = openFile(uri, mode);
964 return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null;
965 }
966
967 /**
968 * Convenience for subclasses that wish to implement {@link #openFile}
969 * by looking up a column named "_data" at the given URI.
970 *
971 * @param uri The URI to be opened.
972 * @param mode The file mode. May be "r" for read-only access,
973 * "w" for write-only access (erasing whatever data is currently in
974 * the file), "wa" for write-only access to append to any existing data,
975 * "rw" for read and write access on any existing data, and "rwt" for read
976 * and write access that truncates any existing file.
977 *
978 * @return Returns a new ParcelFileDescriptor that can be used by the
979 * client to access the file.
980 */
981 protected final ParcelFileDescriptor openFileHelper(Uri uri,
982 String mode) throws FileNotFoundException {
983 Cursor c = query(uri, new String[]{"_data"}, null, null, null);
984 int count = (c != null) ? c.getCount() : 0;
985 if (count != 1) {
986 // If there is not exactly one result, throw an appropriate
987 // exception.
988 if (c != null) {
989 c.close();
990 }
991 if (count == 0) {
992 throw new FileNotFoundException("No entry for " + uri);
993 }
994 throw new FileNotFoundException("Multiple items at " + uri);
995 }
996
997 c.moveToFirst();
998 int i = c.getColumnIndex("_data");
999 String path = (i >= 0 ? c.getString(i) : null);
1000 c.close();
1001 if (path == null) {
1002 throw new FileNotFoundException("Column _data not found.");
1003 }
1004
1005 int modeBits = ContentResolver.modeToMode(uri, mode);
1006 return ParcelFileDescriptor.open(new File(path), modeBits);
1007 }
1008
1009 /**
Dianne Hackborn23fdaf62010-08-06 12:16:55 -07001010 * Called by a client to determine the types of data streams that this
1011 * content provider supports for the given URI. The default implementation
Christopher Tate2bc6eb82013-01-03 12:04:08 -08001012 * returns {@code null}, meaning no types. If your content provider stores data
Dianne Hackborn23fdaf62010-08-06 12:16:55 -07001013 * of a particular type, return that MIME type if it matches the given
1014 * mimeTypeFilter. If it can perform type conversions, return an array
1015 * of all supported MIME types that match mimeTypeFilter.
1016 *
1017 * @param uri The data in the content provider being queried.
1018 * @param mimeTypeFilter The type of data the client desires. May be
1019 * a pattern, such as *\/* to retrieve all possible data types.
Christopher Tate2bc6eb82013-01-03 12:04:08 -08001020 * @return Returns {@code null} if there are no possible data streams for the
Dianne Hackborn23fdaf62010-08-06 12:16:55 -07001021 * given mimeTypeFilter. Otherwise returns an array of all available
1022 * concrete MIME types.
1023 *
1024 * @see #getType(Uri)
1025 * @see #openTypedAssetFile(Uri, String, Bundle)
Dianne Hackborn1040dc42010-08-26 22:11:06 -07001026 * @see ClipDescription#compareMimeTypes(String, String)
Dianne Hackborn23fdaf62010-08-06 12:16:55 -07001027 */
1028 public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
1029 return null;
1030 }
1031
1032 /**
1033 * Called by a client to open a read-only stream containing data of a
1034 * particular MIME type. This is like {@link #openAssetFile(Uri, String)},
1035 * except the file can only be read-only and the content provider may
1036 * perform data conversions to generate data of the desired type.
1037 *
1038 * <p>The default implementation compares the given mimeType against the
Dianne Hackborna53ee352013-02-20 12:47:02 -08001039 * result of {@link #getType(Uri)} and, if they match, simply calls
Dianne Hackborn23fdaf62010-08-06 12:16:55 -07001040 * {@link #openAssetFile(Uri, String)}.
1041 *
Dianne Hackborn1040dc42010-08-26 22:11:06 -07001042 * <p>See {@link ClipData} for examples of the use and implementation
Dianne Hackborn23fdaf62010-08-06 12:16:55 -07001043 * of this method.
1044 *
Dianne Hackborna53ee352013-02-20 12:47:02 -08001045 * <p class="note">For better interoperability with other applications, it is recommended
1046 * that for any URIs that can be opened, you also support queries on them
1047 * containing at least the columns specified by {@link android.provider.OpenableColumns}.
1048 * You may also want to support other common columns if you have additional meta-data
1049 * to supply, such as {@link android.provider.MediaStore.MediaColumns#DATE_ADDED}
1050 * in {@link android.provider.MediaStore.MediaColumns}.</p>
1051 *
Dianne Hackborn23fdaf62010-08-06 12:16:55 -07001052 * @param uri The data in the content provider being queried.
1053 * @param mimeTypeFilter The type of data the client desires. May be
1054 * a pattern, such as *\/*, if the caller does not have specific type
1055 * requirements; in this case the content provider will pick its best
1056 * type matching the pattern.
1057 * @param opts Additional options from the client. The definitions of
1058 * these are specific to the content provider being called.
1059 *
1060 * @return Returns a new AssetFileDescriptor from which the client can
1061 * read data of the desired type.
1062 *
1063 * @throws FileNotFoundException Throws FileNotFoundException if there is
1064 * no file associated with the given URI or the mode is invalid.
1065 * @throws SecurityException Throws SecurityException if the caller does
1066 * not have permission to access the data.
1067 * @throws IllegalArgumentException Throws IllegalArgumentException if the
1068 * content provider does not support the requested MIME type.
1069 *
1070 * @see #getStreamTypes(Uri, String)
1071 * @see #openAssetFile(Uri, String)
Dianne Hackborn1040dc42010-08-26 22:11:06 -07001072 * @see ClipDescription#compareMimeTypes(String, String)
Dianne Hackborn23fdaf62010-08-06 12:16:55 -07001073 */
1074 public AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts)
1075 throws FileNotFoundException {
Dianne Hackborn02dfd262010-08-13 12:34:58 -07001076 if ("*/*".equals(mimeTypeFilter)) {
1077 // If they can take anything, the untyped open call is good enough.
1078 return openAssetFile(uri, "r");
1079 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -07001080 String baseType = getType(uri);
Dianne Hackborn1040dc42010-08-26 22:11:06 -07001081 if (baseType != null && ClipDescription.compareMimeTypes(baseType, mimeTypeFilter)) {
Dianne Hackborn02dfd262010-08-13 12:34:58 -07001082 // Use old untyped open call if this provider has a type for this
1083 // URI and it matches the request.
Dianne Hackborn23fdaf62010-08-06 12:16:55 -07001084 return openAssetFile(uri, "r");
1085 }
1086 throw new FileNotFoundException("Can't open " + uri + " as type " + mimeTypeFilter);
1087 }
1088
1089 /**
1090 * Interface to write a stream of data to a pipe. Use with
1091 * {@link ContentProvider#openPipeHelper}.
1092 */
1093 public interface PipeDataWriter<T> {
1094 /**
1095 * Called from a background thread to stream data out to a pipe.
1096 * Note that the pipe is blocking, so this thread can block on
1097 * writes for an arbitrary amount of time if the client is slow
1098 * at reading.
1099 *
1100 * @param output The pipe where data should be written. This will be
1101 * closed for you upon returning from this function.
1102 * @param uri The URI whose data is to be written.
1103 * @param mimeType The desired type of data to be written.
1104 * @param opts Options supplied by caller.
1105 * @param args Your own custom arguments.
1106 */
1107 public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String mimeType,
1108 Bundle opts, T args);
1109 }
1110
1111 /**
1112 * A helper function for implementing {@link #openTypedAssetFile}, for
1113 * creating a data pipe and background thread allowing you to stream
1114 * generated data back to the client. This function returns a new
1115 * ParcelFileDescriptor that should be returned to the caller (the caller
1116 * is responsible for closing it).
1117 *
1118 * @param uri The URI whose data is to be written.
1119 * @param mimeType The desired type of data to be written.
1120 * @param opts Options supplied by caller.
1121 * @param args Your own custom arguments.
1122 * @param func Interface implementing the function that will actually
1123 * stream the data.
1124 * @return Returns a new ParcelFileDescriptor holding the read side of
1125 * the pipe. This should be returned to the caller for reading; the caller
1126 * is responsible for closing it when done.
1127 */
1128 public <T> ParcelFileDescriptor openPipeHelper(final Uri uri, final String mimeType,
1129 final Bundle opts, final T args, final PipeDataWriter<T> func)
1130 throws FileNotFoundException {
1131 try {
1132 final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
1133
1134 AsyncTask<Object, Object, Object> task = new AsyncTask<Object, Object, Object>() {
1135 @Override
1136 protected Object doInBackground(Object... params) {
1137 func.writeDataToPipe(fds[1], uri, mimeType, opts, args);
1138 try {
1139 fds[1].close();
1140 } catch (IOException e) {
1141 Log.w(TAG, "Failure closing pipe", e);
1142 }
1143 return null;
1144 }
1145 };
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -08001146 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Object[])null);
Dianne Hackborn23fdaf62010-08-06 12:16:55 -07001147
1148 return fds[0];
1149 } catch (IOException e) {
1150 throw new FileNotFoundException("failure making pipe");
1151 }
1152 }
1153
1154 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 * Returns true if this instance is a temporary content provider.
1156 * @return true if this instance is a temporary content provider
1157 */
1158 protected boolean isTemporary() {
1159 return false;
1160 }
1161
1162 /**
1163 * Returns the Binder object for this provider.
1164 *
1165 * @return the Binder object for this provider
1166 * @hide
1167 */
1168 public IContentProvider getIContentProvider() {
1169 return mTransport;
1170 }
1171
1172 /**
Dianne Hackborn334d9ae2013-02-26 15:02:06 -08001173 * Like {@link #attachInfo(Context, android.content.pm.ProviderInfo)}, but for use
1174 * when directly instantiating the provider for testing.
1175 * @hide
1176 */
1177 public void attachInfoForTesting(Context context, ProviderInfo info) {
1178 attachInfo(context, info, true);
1179 }
1180
1181 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 * After being instantiated, this is called to tell the content provider
1183 * about itself.
1184 *
1185 * @param context The context this provider is running in
1186 * @param info Registered information about this content provider
1187 */
1188 public void attachInfo(Context context, ProviderInfo info) {
Dianne Hackborn334d9ae2013-02-26 15:02:06 -08001189 attachInfo(context, info, false);
1190 }
1191
1192 private void attachInfo(Context context, ProviderInfo info, boolean testing) {
Dianne Hackborn23fdaf62010-08-06 12:16:55 -07001193 /*
1194 * We may be using AsyncTask from binder threads. Make it init here
1195 * so its static handler is on the main thread.
1196 */
1197 AsyncTask.init();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198
Dianne Hackborn334d9ae2013-02-26 15:02:06 -08001199 mNoPerms = testing;
1200
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001201 /*
1202 * Only allow it to be set once, so after the content service gives
1203 * this to us clients can't change it.
1204 */
1205 if (mContext == null) {
1206 mContext = context;
Dianne Hackborn2af632f2009-07-08 14:56:37 -07001207 mMyUid = Process.myUid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001208 if (info != null) {
1209 setReadPermission(info.readPermission);
1210 setWritePermission(info.writePermission);
Dianne Hackborn2af632f2009-07-08 14:56:37 -07001211 setPathPermissions(info.pathPermissions);
Dianne Hackbornb424b632010-08-18 15:59:05 -07001212 mExported = info.exported;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213 }
1214 ContentProvider.this.onCreate();
1215 }
1216 }
Fred Quintanace31b232009-05-04 16:01:15 -07001217
1218 /**
Dan Egnor17876aa2010-07-28 12:28:04 -07001219 * Override this to handle requests to perform a batch of operations, or the
1220 * default implementation will iterate over the operations and call
1221 * {@link ContentProviderOperation#apply} on each of them.
1222 * If all calls to {@link ContentProviderOperation#apply} succeed
1223 * then a {@link ContentProviderResult} array with as many
1224 * elements as there were operations will be returned. If any of the calls
Dan Egnor6fcc0f0732010-07-27 16:32:17 -07001225 * fail, it is up to the implementation how many of the others take effect.
1226 * This method can be called from multiple threads, as described in
Scott Main7aee61f2011-02-08 11:25:01 -08001227 * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
1228 * and Threads</a>.
Dan Egnor6fcc0f0732010-07-27 16:32:17 -07001229 *
Fred Quintanace31b232009-05-04 16:01:15 -07001230 * @param operations the operations to apply
1231 * @return the results of the applications
Dan Egnor6fcc0f0732010-07-27 16:32:17 -07001232 * @throws OperationApplicationException thrown if any operation fails.
1233 * @see ContentProviderOperation#apply
Fred Quintanace31b232009-05-04 16:01:15 -07001234 */
Fred Quintana03d94902009-05-22 14:23:31 -07001235 public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
Fred Quintanace31b232009-05-04 16:01:15 -07001236 throws OperationApplicationException {
Fred Quintana03d94902009-05-22 14:23:31 -07001237 final int numOperations = operations.size();
1238 final ContentProviderResult[] results = new ContentProviderResult[numOperations];
1239 for (int i = 0; i < numOperations; i++) {
1240 results[i] = operations.get(i).apply(this, results, i);
Fred Quintanace31b232009-05-04 16:01:15 -07001241 }
1242 return results;
1243 }
Brad Fitzpatrick1877d012010-03-04 17:48:13 -08001244
1245 /**
Dianne Hackborn961321f2013-02-05 17:22:41 -08001246 * @hide
1247 * Front-end to {@link #call(String, String, android.os.Bundle)} that provides the name
1248 * of the calling package.
1249 */
1250 public Bundle callFromPackage(String callingPackag, String method, String arg, Bundle extras) {
1251 return call(method, arg, extras);
1252 }
1253
1254 /**
Manuel Roman2c96a0c2010-08-05 16:39:49 -07001255 * Call a provider-defined method. This can be used to implement
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001256 * interfaces that are cheaper and/or unnatural for a table-like
1257 * model.
Brad Fitzpatrick1877d012010-03-04 17:48:13 -08001258 *
Christopher Tate2bc6eb82013-01-03 12:04:08 -08001259 * @param method method name to call. Opaque to framework, but should not be {@code null}.
1260 * @param arg provider-defined String argument. May be {@code null}.
1261 * @param extras provider-defined Bundle argument. May be {@code null}.
1262 * @return provider-defined return value. May be {@code null}, which is also
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001263 * the default for providers which don't implement any call methods.
Brad Fitzpatrick1877d012010-03-04 17:48:13 -08001264 */
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001265 public Bundle call(String method, String arg, Bundle extras) {
Brad Fitzpatrick1877d012010-03-04 17:48:13 -08001266 return null;
1267 }
Vasu Nori0c9e14a2010-08-04 13:31:48 -07001268
1269 /**
Manuel Roman2c96a0c2010-08-05 16:39:49 -07001270 * Implement this to shut down the ContentProvider instance. You can then
1271 * invoke this method in unit tests.
1272 *
Vasu Nori0c9e14a2010-08-04 13:31:48 -07001273 * <p>
Manuel Roman2c96a0c2010-08-05 16:39:49 -07001274 * Android normally handles ContentProvider startup and shutdown
1275 * automatically. You do not need to start up or shut down a
1276 * ContentProvider. When you invoke a test method on a ContentProvider,
1277 * however, a ContentProvider instance is started and keeps running after
1278 * the test finishes, even if a succeeding test instantiates another
1279 * ContentProvider. A conflict develops because the two instances are
1280 * usually running against the same underlying data source (for example, an
1281 * sqlite database).
1282 * </p>
Vasu Nori0c9e14a2010-08-04 13:31:48 -07001283 * <p>
Manuel Roman2c96a0c2010-08-05 16:39:49 -07001284 * Implementing shutDown() avoids this conflict by providing a way to
1285 * terminate the ContentProvider. This method can also prevent memory leaks
1286 * from multiple instantiations of the ContentProvider, and it can ensure
1287 * unit test isolation by allowing you to completely clean up the test
1288 * fixture before moving on to the next test.
1289 * </p>
Vasu Nori0c9e14a2010-08-04 13:31:48 -07001290 */
1291 public void shutdown() {
1292 Log.w(TAG, "implement ContentProvider shutdown() to make sure all database " +
1293 "connections are gracefully shutdown");
1294 }
Marco Nelissen18cb2872011-11-15 11:19:53 -08001295
1296 /**
1297 * Print the Provider's state into the given stream. This gets invoked if
Jeff Sharkey5554b702012-04-11 18:30:51 -07001298 * you run "adb shell dumpsys activity provider &lt;provider_component_name&gt;".
Marco Nelissen18cb2872011-11-15 11:19:53 -08001299 *
Marco Nelissen18cb2872011-11-15 11:19:53 -08001300 * @param fd The raw file descriptor that the dump is being sent to.
1301 * @param writer The PrintWriter to which you should dump your state. This will be
1302 * closed for you after you return.
1303 * @param args additional arguments to the dump request.
Marco Nelissen18cb2872011-11-15 11:19:53 -08001304 */
1305 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
1306 writer.println("nothing to dump");
1307 }
Brad Fitzpatrick1877d012010-03-04 17:48:13 -08001308}