summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2010-09-26 18:34:53 -0700
committerDianne Hackborn <hackbod@google.com>2010-09-26 21:31:47 -0700
commit8313fc7e94e46e5cc09f457a15a771a325b9f74f (patch)
treed68bf554b0d92a64cde72e58178e60d4d30b521d
parent08c09b0f84b23627b4cd02e1b9a642952fbd2e7f (diff)
downloadframeworks_base-8313fc7e94e46e5cc09f457a15a771a325b9f74f.zip
frameworks_base-8313fc7e94e46e5cc09f457a15a771a325b9f74f.tar.gz
frameworks_base-8313fc7e94e46e5cc09f457a15a771a325b9f74f.tar.bz2
Allow all apps to call ContentResolver.getType().
I can't find the bug number for this, but it is needed for some things we are doing where the app building an intent may not have access to the URI in the data field. This is for HC, but doing in GB to avoid introducing integration issues. Change-Id: I0cac971854198b18775d2a73deb80f23431bfbe2
-rw-r--r--core/java/android/app/ActivityManagerNative.java23
-rw-r--r--core/java/android/app/ActivityThread.java28
-rw-r--r--core/java/android/app/ContextImpl.java15
-rw-r--r--core/java/android/app/IActivityManager.java9
-rw-r--r--core/java/android/content/ContentProvider.java6
-rw-r--r--core/java/android/content/ContentResolver.java58
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java32
-rw-r--r--services/java/com/android/server/am/UriPermission.java4
-rw-r--r--test-runner/src/android/test/mock/MockContentResolver.java6
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java6
10 files changed, 161 insertions, 26 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index a180837..89812ab 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1272,6 +1272,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case GET_PROVIDER_MIME_TYPE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ Uri uri = Uri.CREATOR.createFromParcel(data);
+ String type = getProviderMimeType(uri);
+ reply.writeNoException();
+ reply.writeString(type);
+ return true;
+ }
+
case NEW_URI_PERMISSION_OWNER_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
String name = data.readString();
@@ -2847,6 +2856,20 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
+ public String getProviderMimeType(Uri uri)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ uri.writeToParcel(data, 0);
+ mRemote.transact(GET_PROVIDER_MIME_TYPE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ String res = reply.readString();
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
+
public IBinder newUriPermissionOwner(String name)
throws RemoteException {
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 6d1bf96..a10a823 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3287,12 +3287,20 @@ public final class ActivityThread {
}
}
- private final IContentProvider getProvider(Context context, String name) {
+ private final IContentProvider getExistingProvider(Context context, String name) {
synchronized(mProviderMap) {
final ProviderClientRecord pr = mProviderMap.get(name);
if (pr != null) {
return pr.mProvider;
}
+ return null;
+ }
+ }
+
+ private final IContentProvider getProvider(Context context, String name) {
+ IContentProvider existing = getExistingProvider(context, name);
+ if (existing != null) {
+ return existing;
}
IActivityManager.ContentProviderHolder holder = null;
@@ -3337,6 +3345,22 @@ public final class ActivityThread {
return provider;
}
+ public final IContentProvider acquireExistingProvider(Context c, String name) {
+ IContentProvider provider = getExistingProvider(c, name);
+ if(provider == null)
+ return null;
+ IBinder jBinder = provider.asBinder();
+ synchronized(mProviderMap) {
+ ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
+ if(prc == null) {
+ mProviderRefCountMap.put(jBinder, new ProviderRefCount(1));
+ } else {
+ prc.count++;
+ } //end else
+ } //end synchronized
+ return provider;
+ }
+
public final boolean releaseProvider(IContentProvider provider) {
if(provider == null) {
return false;
@@ -3345,7 +3369,7 @@ public final class ActivityThread {
synchronized(mProviderMap) {
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if(prc == null) {
- if(localLOGV) Slog.v(TAG, "releaseProvider::Weird shouldnt be here");
+ if(localLOGV) Slog.v(TAG, "releaseProvider::Weird shouldn't be here");
return false;
} else {
prc.count--;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 09ef710..1bbf9ea 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1626,22 +1626,23 @@ class ContextImpl extends Context {
// ----------------------------------------------------------------------
private static final class ApplicationContentResolver extends ContentResolver {
- public ApplicationContentResolver(Context context,
- ActivityThread mainThread)
- {
+ public ApplicationContentResolver(Context context, ActivityThread mainThread) {
super(context);
mMainThread = mainThread;
}
@Override
- protected IContentProvider acquireProvider(Context context, String name)
- {
+ protected IContentProvider acquireProvider(Context context, String name) {
return mMainThread.acquireProvider(context, name);
}
@Override
- public boolean releaseProvider(IContentProvider provider)
- {
+ protected IContentProvider acquireExistingProvider(Context context, String name) {
+ return mMainThread.acquireExistingProvider(context, name);
+ }
+
+ @Override
+ public boolean releaseProvider(IContentProvider provider) {
return mMainThread.releaseProvider(provider);
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index f9bd461..28af0d3 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -313,6 +313,8 @@ public interface IActivityManager extends IInterface {
public void crashApplication(int uid, int initialPid, String packageName,
String message) throws RemoteException;
+
+ public String getProviderMimeType(Uri uri) throws RemoteException;
public IBinder newUriPermissionOwner(String name) throws RemoteException;
public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
@@ -526,7 +528,8 @@ public interface IActivityManager extends IInterface {
int SET_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+111;
int IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+112;
int CRASH_APPLICATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+113;
- int NEW_URI_PERMISSION_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+114;
- int GRANT_URI_PERMISSION_FROM_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+115;
- int REVOKE_URI_PERMISSION_FROM_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+116;
+ int GET_PROVIDER_MIME_TYPE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+114;
+ int NEW_URI_PERMISSION_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+115;
+ int GRANT_URI_PERMISSION_FROM_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+116;
+ int REVOKE_URI_PERMISSION_FROM_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+117;
}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index dc4e9c4..1d6e8b8 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -544,6 +544,12 @@ public abstract class ContentProvider implements ComponentCallbacks {
* <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
* Processes and Threads</a>.
*
+ * <p>Note that there are no permissions needed for an application to
+ * access this information; if your content provider requires read and/or
+ * write permissions, or is not exported, all applications can still call
+ * this method regardless of their access permissions. This allows them
+ * to retrieve the MIME type for a URI when dispatching intents.
+ *
* @param uri the URI to query.
* @return a MIME type string, or null if there is no type.
*/
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 69f7611..81ff414 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -17,6 +17,7 @@
package android.content;
import android.accounts.Account;
+import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -176,6 +177,12 @@ public abstract class ContentResolver {
/** @hide */
protected abstract IContentProvider acquireProvider(Context c, String name);
+ /** Providing a default implementation of this, to avoid having to change
+ * a lot of other things, but implementations of ContentResolver should
+ * implement it. @hide */
+ protected IContentProvider acquireExistingProvider(Context c, String name) {
+ return acquireProvider(c, name);
+ }
/** @hide */
public abstract boolean releaseProvider(IContentProvider icp);
@@ -186,20 +193,29 @@ public abstract class ContentResolver {
* using the content:// scheme.
* @return A MIME type for the content, or null if the URL is invalid or the type is unknown
*/
- public final String getType(Uri url)
- {
- IContentProvider provider = acquireProvider(url);
- if (provider == null) {
+ public final String getType(Uri url) {
+ IContentProvider provider = acquireExistingProvider(url);
+ if (provider != null) {
+ try {
+ return provider.getType(url);
+ } catch (RemoteException e) {
+ return null;
+ } catch (java.lang.Exception e) {
+ return null;
+ } finally {
+ releaseProvider(provider);
+ }
+ }
+
+ if (!SCHEME_CONTENT.equals(url.getScheme())) {
return null;
}
+
try {
- return provider.getType(url);
+ String type = ActivityManagerNative.getDefault().getProviderMimeType(url);
+ return type;
} catch (RemoteException e) {
return null;
- } catch (java.lang.Exception e) {
- return null;
- } finally {
- releaseProvider(provider);
}
}
@@ -717,14 +733,13 @@ public abstract class ContentResolver {
}
/**
- * Returns the content provider for the given content URI..
+ * Returns the content provider for the given content URI.
*
* @param uri The URI to a content provider
* @return The ContentProvider for the given URI, or null if no content provider is found.
* @hide
*/
- public final IContentProvider acquireProvider(Uri uri)
- {
+ public final IContentProvider acquireProvider(Uri uri) {
if (!SCHEME_CONTENT.equals(uri.getScheme())) {
return null;
}
@@ -736,6 +751,25 @@ public abstract class ContentResolver {
}
/**
+ * Returns the content provider for the given content URI if the process
+ * already has a reference on it.
+ *
+ * @param uri The URI to a content provider
+ * @return The ContentProvider for the given URI, or null if no content provider is found.
+ * @hide
+ */
+ public final IContentProvider acquireExistingProvider(Uri uri) {
+ if (!SCHEME_CONTENT.equals(uri.getScheme())) {
+ return null;
+ }
+ String auth = uri.getAuthority();
+ if (auth != null) {
+ return acquireExistingProvider(mContext, uri.getAuthority());
+ }
+ return null;
+ }
+
+ /**
* @hide
*/
public final IContentProvider acquireProvider(String name) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 223d77d..22cd8ff 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -5592,6 +5592,38 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ /**
+ * Allows app to retrieve the MIME type of a URI without having permission
+ * to access its content provider.
+ *
+ * CTS tests for this functionality can be run with "runtest cts-appsecurity".
+ *
+ * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/
+ * src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
+ */
+ public String getProviderMimeType(Uri uri) {
+ final String name = uri.getAuthority();
+ final long ident = Binder.clearCallingIdentity();
+ ContentProviderHolder holder = null;
+
+ try {
+ holder = getContentProviderExternal(name);
+ if (holder != null) {
+ return holder.provider.getType(uri);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Content provider dead retrieving " + uri, e);
+ return null;
+ } finally {
+ if (holder != null) {
+ removeContentProviderExternal(name);
+ }
+ Binder.restoreCallingIdentity(ident);
+ }
+
+ return null;
+ }
+
// =========================================================
// GLOBAL MANAGEMENT
// =========================================================
diff --git a/services/java/com/android/server/am/UriPermission.java b/services/java/com/android/server/am/UriPermission.java
index 0cb6943..e3347cb 100644
--- a/services/java/com/android/server/am/UriPermission.java
+++ b/services/java/com/android/server/am/UriPermission.java
@@ -27,8 +27,8 @@ import java.util.HashSet;
*
* CTS tests for this functionality can be run with "runtest cts-appsecurity".
*
- * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert
- * /src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
+ * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/
+ * src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
*/
class UriPermission {
final int uid;
diff --git a/test-runner/src/android/test/mock/MockContentResolver.java b/test-runner/src/android/test/mock/MockContentResolver.java
index ab511f8..26eb8e4 100644
--- a/test-runner/src/android/test/mock/MockContentResolver.java
+++ b/test-runner/src/android/test/mock/MockContentResolver.java
@@ -75,6 +75,12 @@ public class MockContentResolver extends ContentResolver {
/** @hide */
@Override
protected IContentProvider acquireProvider(Context context, String name) {
+ return acquireExistingProvider(context, name);
+ }
+
+ /** @hide */
+ @Override
+ protected IContentProvider acquireExistingProvider(Context context, String name) {
/*
* Gets the content provider from the local map
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java
index cfab90a..d89dba9 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java
@@ -43,6 +43,12 @@ public class BridgeContentResolver extends ContentResolver {
}
@Override
+ public IContentProvider acquireExistingProvider(Context c, String name) {
+ // ignore
+ return null;
+ }
+
+ @Override
public boolean releaseProvider(IContentProvider icp) {
// ignore
return false;