From d7960d19c1e5dfdbe8c793472ce792e8526c0e40 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 29 Jan 2013 18:55:48 -0800 Subject: [PATCH] Improve revoking access to content providers. Providers can now hook into the revoked query and insert calls, and the default implementation of query is a little better. Change-Id: I29592a579aaf4a98686c6cf43e57f73275c58922 --- .../java/android/content/ContentProvider.java | 56 +++++++++++++++---- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 4b977ab5fe1df..e66efd525ba88 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -191,11 +191,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 { String selection, String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal) { if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { - // The read is not allowed... to fake it out, we replace the given - // selection statement with a dummy one that will always be false. - // This way we will get a cursor back that has the correct structure - // but contains no rows. - selection = "'A' = 'B'"; + return rejectQuery(uri, projection, selection, selectionArgs, sortOrder, + CancellationSignal.fromTransport(cancellationSignal)); } return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder, CancellationSignal.fromTransport(cancellationSignal)); @@ -209,12 +206,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { @Override public Uri insert(String callingPkg, Uri uri, ContentValues initialValues) { if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { - // If not allowed, we need to return some reasonable URI. Maybe the - // content provider should be responsible for this, but for now we - // will just return the base URI with a dummy '0' tagged on to it. - // You shouldn't be able to read if you can't write, anyway, so it - // shouldn't matter much what is returned. - return uri.buildUpon().appendPath("0").build(); + return rejectInsert(uri, initialValues); } return ContentProvider.this.insert(uri, initialValues); } @@ -591,6 +583,31 @@ public abstract class ContentProvider implements ComponentCallbacks2 { public void onTrimMemory(int level) { } + /** + * @hide + * Implementation when a caller has performed a query on the content + * provider, but that call has been rejected for the operation given + * to {@link #setAppOps(int, int)}. The default implementation + * rewrites the selection argument to include a condition + * that is never true (so will always result in an empty cursor) + * and calls through to {@link #query(android.net.Uri, String[], String, String[], + * String, android.os.CancellationSignal)} with that. + */ + public Cursor rejectQuery(Uri uri, String[] projection, + String selection, String[] selectionArgs, String sortOrder, + CancellationSignal cancellationSignal) { + // The read is not allowed... to fake it out, we replace the given + // selection statement with a dummy one that will always be false. + // This way we will get a cursor back that has the correct structure + // but contains no rows. + if (selection == null) { + selection = "'A' = 'B'"; + } else { + selection = "'A' = 'B' AND (" + selection + ")"; + } + return query(uri, projection, selection, selectionArgs, sortOrder, cancellationSignal); + } + /** * Implement this to handle query requests from clients. * This method can be called from multiple threads, as described in @@ -738,6 +755,23 @@ public abstract class ContentProvider implements ComponentCallbacks2 { */ public abstract String getType(Uri uri); + /** + * @hide + * Implementation when a caller has performed an insert on the content + * provider, but that call has been rejected for the operation given + * to {@link #setAppOps(int, int)}. The default implementation simply + * returns a dummy URI that is the base URI with a 0 path element + * appended. + */ + public Uri rejectInsert(Uri uri, ContentValues values) { + // If not allowed, we need to return some reasonable URI. Maybe the + // content provider should be responsible for this, but for now we + // will just return the base URI with a dummy '0' tagged on to it. + // You shouldn't be able to read if you can't write, anyway, so it + // shouldn't matter much what is returned. + return uri.buildUpon().appendPath("0").build(); + } + /** * Implement this to handle requests to insert a new row. * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}