am d8691d73: Merge "Allow all apps to call ContentResolver.getType()." into gingerbread

Merge commit 'd8691d73d158acd9ffc63748126e822afd656707' into gingerbread-plus-aosp

* commit 'd8691d73d158acd9ffc63748126e822afd656707':
  Allow all apps to call ContentResolver.getType().
This commit is contained in:
Dianne Hackborn
2010-09-27 12:45:31 -07:00
committed by Android Git Automerger
10 changed files with 161 additions and 26 deletions

View File

@@ -1272,6 +1272,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true; 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: { case NEW_URI_PERMISSION_OWNER_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor); data.enforceInterface(IActivityManager.descriptor);
String name = data.readString(); String name = data.readString();
@@ -2847,6 +2856,20 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle(); 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) public IBinder newUriPermissionOwner(String name)
throws RemoteException { throws RemoteException {
Parcel data = Parcel.obtain(); Parcel data = Parcel.obtain();

View File

@@ -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) { synchronized(mProviderMap) {
final ProviderClientRecord pr = mProviderMap.get(name); final ProviderClientRecord pr = mProviderMap.get(name);
if (pr != null) { if (pr != null) {
return pr.mProvider; 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; IActivityManager.ContentProviderHolder holder = null;
@@ -3337,6 +3345,22 @@ public final class ActivityThread {
return provider; 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) { public final boolean releaseProvider(IContentProvider provider) {
if(provider == null) { if(provider == null) {
return false; return false;
@@ -3345,7 +3369,7 @@ public final class ActivityThread {
synchronized(mProviderMap) { synchronized(mProviderMap) {
ProviderRefCount prc = mProviderRefCountMap.get(jBinder); ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if(prc == null) { 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; return false;
} else { } else {
prc.count--; prc.count--;

View File

@@ -1623,22 +1623,23 @@ class ContextImpl extends Context {
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
private static final class ApplicationContentResolver extends ContentResolver { private static final class ApplicationContentResolver extends ContentResolver {
public ApplicationContentResolver(Context context, public ApplicationContentResolver(Context context, ActivityThread mainThread) {
ActivityThread mainThread)
{
super(context); super(context);
mMainThread = mainThread; mMainThread = mainThread;
} }
@Override @Override
protected IContentProvider acquireProvider(Context context, String name) protected IContentProvider acquireProvider(Context context, String name) {
{
return mMainThread.acquireProvider(context, name); return mMainThread.acquireProvider(context, name);
} }
@Override @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); return mMainThread.releaseProvider(provider);
} }

View File

@@ -314,6 +314,8 @@ public interface IActivityManager extends IInterface {
public void crashApplication(int uid, int initialPid, String packageName, public void crashApplication(int uid, int initialPid, String packageName,
String message) throws RemoteException; String message) throws RemoteException;
public String getProviderMimeType(Uri uri) throws RemoteException;
public IBinder newUriPermissionOwner(String name) throws RemoteException; public IBinder newUriPermissionOwner(String name) throws RemoteException;
public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg, public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
Uri uri, int mode) throws RemoteException; Uri uri, int mode) throws RemoteException;
@@ -526,7 +528,8 @@ public interface IActivityManager extends IInterface {
int SET_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+111; int SET_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+111;
int IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+112; int IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+112;
int CRASH_APPLICATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+113; int CRASH_APPLICATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+113;
int NEW_URI_PERMISSION_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+114; int GET_PROVIDER_MIME_TYPE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+114;
int GRANT_URI_PERMISSION_FROM_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+115; int NEW_URI_PERMISSION_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+115;
int REVOKE_URI_PERMISSION_FROM_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+116; int GRANT_URI_PERMISSION_FROM_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+116;
int REVOKE_URI_PERMISSION_FROM_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+117;
} }

View File

@@ -544,6 +544,12 @@ public abstract class ContentProvider implements ComponentCallbacks {
* <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals: * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
* Processes and Threads</a>. * 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. * @param uri the URI to query.
* @return a MIME type string, or null if there is no type. * @return a MIME type string, or null if there is no type.
*/ */

View File

@@ -17,6 +17,7 @@
package android.content; package android.content;
import android.accounts.Account; import android.accounts.Account;
import android.app.ActivityManagerNative;
import android.app.ActivityThread; import android.app.ActivityThread;
import android.app.AppGlobals; import android.app.AppGlobals;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
@@ -176,6 +177,12 @@ public abstract class ContentResolver {
/** @hide */ /** @hide */
protected abstract IContentProvider acquireProvider(Context c, String name); 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 */ /** @hide */
public abstract boolean releaseProvider(IContentProvider icp); public abstract boolean releaseProvider(IContentProvider icp);
@@ -186,12 +193,9 @@ public abstract class ContentResolver {
* using the content:// scheme. * using the content:// scheme.
* @return A MIME type for the content, or null if the URL is invalid or the type is unknown * @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) public final String getType(Uri url) {
{ IContentProvider provider = acquireExistingProvider(url);
IContentProvider provider = acquireProvider(url); if (provider != null) {
if (provider == null) {
return null;
}
try { try {
return provider.getType(url); return provider.getType(url);
} catch (RemoteException e) { } catch (RemoteException e) {
@@ -203,6 +207,18 @@ public abstract class ContentResolver {
} }
} }
if (!SCHEME_CONTENT.equals(url.getScheme())) {
return null;
}
try {
String type = ActivityManagerNative.getDefault().getProviderMimeType(url);
return type;
} catch (RemoteException e) {
return null;
}
}
/** /**
* <p> * <p>
* Query the given URI, returning a {@link Cursor} over the result set. * Query the given URI, returning a {@link Cursor} over the result set.
@@ -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 * @param uri The URI to a content provider
* @return The ContentProvider for the given URI, or null if no content provider is found. * @return The ContentProvider for the given URI, or null if no content provider is found.
* @hide * @hide
*/ */
public final IContentProvider acquireProvider(Uri uri) public final IContentProvider acquireProvider(Uri uri) {
{
if (!SCHEME_CONTENT.equals(uri.getScheme())) { if (!SCHEME_CONTENT.equals(uri.getScheme())) {
return null; return null;
} }
@@ -735,6 +750,25 @@ public abstract class ContentResolver {
return null; return null;
} }
/**
* 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 * @hide
*/ */

View File

@@ -5595,6 +5595,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 // GLOBAL MANAGEMENT
// ========================================================= // =========================================================

View File

@@ -27,8 +27,8 @@ import java.util.HashSet;
* *
* CTS tests for this functionality can be run with "runtest cts-appsecurity". * CTS tests for this functionality can be run with "runtest cts-appsecurity".
* *
* Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/
* /src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java * src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
*/ */
class UriPermission { class UriPermission {
final int uid; final int uid;

View File

@@ -75,6 +75,12 @@ public class MockContentResolver extends ContentResolver {
/** @hide */ /** @hide */
@Override @Override
protected IContentProvider acquireProvider(Context context, String name) { 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 * Gets the content provider from the local map

View File

@@ -42,6 +42,12 @@ public class BridgeContentResolver extends ContentResolver {
return null; return null;
} }
@Override
public IContentProvider acquireExistingProvider(Context c, String name) {
// ignore
return null;
}
@Override @Override
public boolean releaseProvider(IContentProvider icp) { public boolean releaseProvider(IContentProvider icp) {
// ignore // ignore