Merge "Allow all apps to call ContentResolver.getType()." into gingerbread
This commit is contained in:
committed by
Android (Google) Code Review
commit
d8691d73d1
@@ -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();
|
||||
|
||||
@@ -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--;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -735,6 +750,25 @@ public abstract class ContentResolver {
|
||||
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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
// =========================================================
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -42,6 +42,12 @@ public class BridgeContentResolver extends ContentResolver {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IContentProvider acquireExistingProvider(Context c, String name) {
|
||||
// ignore
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean releaseProvider(IContentProvider icp) {
|
||||
// ignore
|
||||
|
||||
Reference in New Issue
Block a user