diff options
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; |