Merge "Added a new api ContentProvider#getTypeAnonymous" into udc-dev am: 3d907cca3c

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21480928

Change-Id: I91cbf92e757254d2ae483ba5ba4e69af44e39fb5
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Ashish Kumar Gaurav
2023-02-20 11:47:43 +00:00
committed by Automerger Merge Worker
11 changed files with 316 additions and 128 deletions

View File

@@ -9848,6 +9848,7 @@ package android.content {
method @Nullable public final String getReadPermission();
method @Nullable public String[] getStreamTypes(@NonNull android.net.Uri, @NonNull String);
method @Nullable public abstract String getType(@NonNull android.net.Uri);
method @Nullable public String getTypeAnonymous(@NonNull android.net.Uri);
method @Nullable public final String getWritePermission();
method @Nullable public abstract android.net.Uri insert(@NonNull android.net.Uri, @Nullable android.content.ContentValues);
method @Nullable public android.net.Uri insert(@NonNull android.net.Uri, @Nullable android.content.ContentValues, @Nullable android.os.Bundle);

View File

@@ -347,7 +347,7 @@ interface IActivityManager {
String getProviderMimeType(in Uri uri, int userId);
oneway void getProviderMimeTypeAsync(in Uri uri, int userId, in RemoteCallback resultCallback);
oneway void getMimeTypeFilterAsync(in Uri uri, int userId, in RemoteCallback resultCallback);
// Cause the specified process to dump the specified heap.
boolean dumpHeap(in String process, int userId, boolean managed, boolean mallocInfo,
boolean runGc, in String path, in ParcelFileDescriptor fd,

View File

@@ -18,14 +18,15 @@ package android.content;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.myUserHandle;
import static android.os.Trace.TRACE_TAG_DATABASE;
import static com.android.internal.util.FrameworkStatsLog.GET_TYPE_ACCESSED_WITHOUT_PERMISSION;
import static com.android.internal.util.FrameworkStatsLog.GET_TYPE_ACCESSED_WITHOUT_PERMISSION__LOCATION__PROVIDER_CHECK_URI_PERMISSION;
import static com.android.internal.util.FrameworkStatsLog.GET_TYPE_ACCESSED_WITHOUT_PERMISSION__LOCATION__PROVIDER_ERROR;
import static com.android.internal.util.FrameworkStatsLog.GET_TYPE_ACCESSED_WITHOUT_PERMISSION__LOCATION__PROVIDER_FRAMEWORK_PERMISSION;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -300,17 +301,32 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
}
@Override
public String getType(Uri uri) {
public String getType(AttributionSource attributionSource, Uri uri) {
// getCallingPackage() isn't available in getType(), as the javadoc states.
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
traceBegin(TRACE_TAG_DATABASE, "getType: ", uri.getAuthority());
try {
final String type = mInterface.getType(uri);
if (type != null) {
logGetTypeData(Binder.getCallingUid(), uri, type);
if (checkGetTypePermission(attributionSource, uri)
== PermissionChecker.PERMISSION_GRANTED) {
final String type = mInterface.getType(uri);
if (type != null) {
logGetTypeData(Binder.getCallingUid(), uri, type, true);
}
return type;
} else {
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
final String type = getTypeAnonymous(uri);
if (type != null) {
logGetTypeData(callingUid, uri, type, false);
}
return type;
} finally {
Binder.restoreCallingIdentity(origId);
}
}
return type;
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
} finally {
@@ -319,59 +335,62 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
}
// Utility function to log the getTypeData calls
private void logGetTypeData(int callingUid, Uri uri, String type) {
private void logGetTypeData(int callingUid, Uri uri, String type,
boolean permissionCheckPassed) {
final int enumFrameworkPermission =
GET_TYPE_ACCESSED_WITHOUT_PERMISSION__LOCATION__PROVIDER_FRAMEWORK_PERMISSION;
final int enumCheckUriPermission =
GET_TYPE_ACCESSED_WITHOUT_PERMISSION__LOCATION__PROVIDER_CHECK_URI_PERMISSION;
final int enumError = GET_TYPE_ACCESSED_WITHOUT_PERMISSION__LOCATION__PROVIDER_ERROR;
try {
final AttributionSource attributionSource = new AttributionSource.Builder(
callingUid).build();
try {
if (enforceReadPermission(attributionSource, uri)
!= PermissionChecker.PERMISSION_GRANTED) {
FrameworkStatsLog.write(GET_TYPE_ACCESSED_WITHOUT_PERMISSION,
enumFrameworkPermission,
callingUid, uri.getAuthority(), type);
} else {
final ProviderInfo cpi = mContext.getPackageManager()
.resolveContentProvider(uri.getAuthority(),
if (permissionCheckPassed) {
// Just for logging for mediaProvider cases
final ProviderInfo cpi = mContext.getPackageManager()
.resolveContentProvider(uri.getAuthority(),
PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA));
final int callingUserId = UserHandle.getUserId(callingUid);
final Uri userUri = (mSingleUser
&& !UserHandle.isSameUser(mMyUid, callingUid))
? maybeAddUserId(uri, callingUserId) : uri;
if (cpi.forceUriPermissions
&& mInterface.checkUriPermission(uri,
callingUid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
!= PermissionChecker.PERMISSION_GRANTED
&& getContext().checkUriPermission(userUri, Binder.getCallingPid(),
callingUid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
!= PackageManager.PERMISSION_GRANTED) {
FrameworkStatsLog.write(GET_TYPE_ACCESSED_WITHOUT_PERMISSION,
enumCheckUriPermission,
callingUid, uri.getAuthority(), type);
}
final int callingUserId = UserHandle.getUserId(callingUid);
final Uri userUri = (mSingleUser
&& !UserHandle.isSameUser(mMyUid, callingUid))
? maybeAddUserId(uri, callingUserId) : uri;
try {
if (cpi.forceUriPermissions
&& mInterface.checkUriPermission(uri,
callingUid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
!= PermissionChecker.PERMISSION_GRANTED
&& getContext().checkUriPermission(userUri, Binder.getCallingPid(),
callingUid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
!= PackageManager.PERMISSION_GRANTED) {
FrameworkStatsLog.write(GET_TYPE_ACCESSED_WITHOUT_PERMISSION,
enumCheckUriPermission,
callingUid, uri.getAuthority(), type);
}
} catch (SecurityException e) {
FrameworkStatsLog.write(GET_TYPE_ACCESSED_WITHOUT_PERMISSION,
enumFrameworkPermission,
callingUid, uri.getAuthority(), type);
} catch (RemoteException e) {
//does nothing
}
} catch (Exception e) {
} else {
FrameworkStatsLog.write(GET_TYPE_ACCESSED_WITHOUT_PERMISSION,
enumError,
enumFrameworkPermission,
callingUid, uri.getAuthority(), type);
}
}
@Override
public void getTypeAsync(Uri uri, RemoteCallback callback) {
public void getTypeAsync(AttributionSource attributionSource,
Uri uri, RemoteCallback callback) {
final Bundle result = new Bundle();
try {
result.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getType(uri));
result.putString(ContentResolver.REMOTE_CALLBACK_RESULT,
getType(attributionSource, uri));
} catch (Exception e) {
result.putParcelable(ContentResolver.REMOTE_CALLBACK_ERROR,
new ParcelableException(e));
}
callback.sendResult(result);
}
@Override
public void getTypeAnonymousAsync(Uri uri, RemoteCallback callback) {
final Bundle result = new Bundle();
try {
result.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getTypeAnonymous(uri));
} catch (Exception e) {
result.putParcelable(ContentResolver.REMOTE_CALLBACK_ERROR,
new ParcelableException(e));
@@ -795,6 +814,23 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
}
return PermissionChecker.PERMISSION_GRANTED;
}
@PermissionCheckerManager.PermissionResult
private int checkGetTypePermission(@NonNull AttributionSource attributionSource,
Uri uri) {
final int callingUid = Binder.getCallingUid();
if (UserHandle.getAppId(callingUid) == SYSTEM_UID
|| checkPermission(Manifest.permission.GET_ANY_PROVIDER_TYPE, attributionSource)
== PermissionChecker.PERMISSION_GRANTED) {
// Allowing System Uid and apps with permission to get any type, to access all types
return PermissionChecker.PERMISSION_GRANTED;
}
try {
return enforceReadPermission(attributionSource, uri);
} catch (SecurityException e) {
return PermissionChecker.PERMISSION_HARD_DENIED;
}
}
}
boolean checkUser(int pid, int uid, Context context) {
@@ -1625,11 +1661,15 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
* <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
* and Threads</a>.
*
* <p>Note that there are no permissions needed for an application to
* <p>Note that by default 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.
* this method regardless of their access permissions. </p>
*
* <p>If your mime type reveals details that should be protected,
* then you should protect this method by implementing {@link #getTypeAnonymous}.
* Implementing {@link #getTypeAnonymous} ensures your {@link #getType} can be
* only accessed by caller's having associated readPermission for the URI. </p>
*
* @param uri the URI to query.
* @return a MIME type string, or {@code null} if there is no type.
@@ -1637,6 +1677,24 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
@Override
public abstract @Nullable String getType(@NonNull Uri uri);
/**
* Implement this to handle requests for MIME type of URIs, that does not need to
* reveal any internal information which should be protected by any permission.
*
* <p>If your mime type reveals details that should be protected, then you should protect those
* by implementing those in {@link #getType}, and in this function, only return types of
* URIs which can be obtained by anyone without any access.
*
* Implementing ths function will make sure {@link #getType} is protected by readPermission.
* This function by default works as the {@link #getType}</p>
*
* @param uri the URI to query.
* @return a MIME type string, or {@code null} if type needs to be protected.
*/
public @Nullable String getTypeAnonymous(@NonNull Uri uri) {
return getType(uri);
}
/**
* Implement this to support canonicalization of URIs that refer to your
* content provider. A canonical URI is one that can be transported across

View File

@@ -140,8 +140,10 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
case GET_TYPE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
AttributionSource attributionSource = AttributionSource.CREATOR
.createFromParcel(data);
Uri url = Uri.CREATOR.createFromParcel(data);
String type = getType(url);
String type = getType(attributionSource, url);
reply.writeNoException();
reply.writeString(type);
@@ -150,9 +152,19 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
case GET_TYPE_ASYNC_TRANSACTION: {
data.enforceInterface(IContentProvider.descriptor);
AttributionSource attributionSource = AttributionSource.CREATOR
.createFromParcel(data);
Uri url = Uri.CREATOR.createFromParcel(data);
RemoteCallback callback = RemoteCallback.CREATOR.createFromParcel(data);
getTypeAsync(url, callback);
getTypeAsync(attributionSource, url, callback);
return true;
}
case GET_TYPE_ANONYMOUS_ASYNC_TRANSACTION: {
data.enforceInterface(IContentProvider.descriptor);
Uri url = Uri.CREATOR.createFromParcel(data);
RemoteCallback callback = RemoteCallback.CREATOR.createFromParcel(data);
getTypeAnonymousAsync(url, callback);
return true;
}
@@ -502,13 +514,13 @@ final class ContentProviderProxy implements IContentProvider
}
@Override
public String getType(Uri url) throws RemoteException
public String getType(AttributionSource attributionSource, Uri url) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
attributionSource.writeToParcel(data, 0);
url.writeToParcel(data, 0);
mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0);
@@ -523,7 +535,25 @@ final class ContentProviderProxy implements IContentProvider
}
@Override
/* oneway */ public void getTypeAsync(Uri uri, RemoteCallback callback) throws RemoteException {
/* oneway */ public void getTypeAsync(AttributionSource attributionSource,
Uri uri, RemoteCallback callback) throws RemoteException {
Parcel data = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
attributionSource.writeToParcel(data, 0);
uri.writeToParcel(data, 0);
callback.writeToParcel(data, 0);
mRemote.transact(IContentProvider.GET_TYPE_ASYNC_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
} finally {
data.recycle();
}
}
@Override
/* oneway */ public void getTypeAnonymousAsync(Uri uri, RemoteCallback callback)
throws RemoteException {
Parcel data = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
@@ -531,7 +561,7 @@ final class ContentProviderProxy implements IContentProvider
uri.writeToParcel(data, 0);
callback.writeToParcel(data, 0);
mRemote.transact(IContentProvider.GET_TYPE_ASYNC_TRANSACTION, data, null,
mRemote.transact(IContentProvider.GET_TYPE_ANONYMOUS_ASYNC_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
} finally {
data.recycle();

View File

@@ -920,8 +920,13 @@ public abstract class ContentResolver implements ContentInterface {
return null;
}
// XXX would like to have an acquireExistingUnstableProvider for this.
IContentProvider provider = acquireExistingProvider(url);
IContentProvider provider = null;
try {
provider = acquireProvider(url);
} catch (Exception e) {
// if unable to acquire the provider, then it should try to get the type
// using getTypeAnonymous via ActivityManagerService
}
if (provider != null) {
try {
final StringResultListener resultListener = new StringResultListener();
@@ -949,7 +954,7 @@ public abstract class ContentResolver implements ContentInterface {
try {
final StringResultListener resultListener = new StringResultListener();
ActivityManager.getService().getProviderMimeTypeAsync(
ActivityManager.getService().getMimeTypeFilterAsync(
ContentProvider.getUriWithoutUserId(url),
resolveUserId(url),
new RemoteCallback(resultListener));

View File

@@ -18,6 +18,7 @@ package android.content;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppGlobals;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
@@ -44,14 +45,42 @@ public interface IContentProvider extends IInterface {
@Nullable String[] projection,
@Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal)
throws RemoteException;
String getType(Uri url) throws RemoteException;
/**
* getType function with AttributionSource
*/
String getType(@NonNull AttributionSource attributionSource,
Uri url) throws RemoteException;
/**
* one way getType function with AttributionSource
*/
void getTypeAsync(@NonNull AttributionSource attributionSource,
Uri url, RemoteCallback callback) throws RemoteException;
/**
* @deprecated -- use getType with AttributionSource
*/
@Deprecated
default String getType(Uri url) throws RemoteException {
return getType(new AttributionSource(Binder.getCallingUid(),
AppGlobals.getPackageManager().getPackagesForUid(Binder.getCallingUid())[0],
null), url);
}
/**
* A oneway version of getType. The functionality is exactly the same, except that the
* call returns immediately, and the resulting type is returned when available via
* a binder callback.
*
* @deprecated -- use getTypeAsync with AttributionSource
*/
void getTypeAsync(Uri uri, RemoteCallback callback) throws RemoteException;
@Deprecated
default void getTypeAsync(Uri uri, RemoteCallback callback) throws RemoteException {
getTypeAsync(new AttributionSource(Binder.getCallingUid(),
AppGlobals.getPackageManager().getPackagesForUid(Binder.getCallingUid())[0],
null), uri, callback);
}
/** oneway version of getTypeAnonymous*/
void getTypeAnonymousAsync(Uri uri, RemoteCallback callback) throws RemoteException;
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
@@ -185,4 +214,7 @@ public interface IContentProvider extends IInterface {
int GET_TYPE_ASYNC_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 28;
int CANONICALIZE_ASYNC_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 29;
int UNCANONICALIZE_ASYNC_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 30;
int GET_TYPE_ANONYMOUS_ASYNC_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 31;
}

View File

@@ -7604,6 +7604,13 @@
<permission android:name="android.permission.LOG_PROCESS_ACTIVITIES"
android:protectionLevel="signature|privileged" />
<!-- @hide Allows an application to get type of any provider uri.
<p>Not for use by third-party applications.
<p>Protection level: signature
-->
<permission android:name="android.permission.GET_ANY_PROVIDER_TYPE"
android:protectionLevel="signature" />
<!-- Attribution for Geofencing service. -->
<attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
<!-- Attribution for Country Detector. -->

View File

@@ -191,7 +191,6 @@ import android.app.ApplicationStartInfo;
import android.app.ApplicationThreadConstants;
import android.app.BackgroundStartPrivileges;
import android.app.BroadcastOptions;
import android.app.ComponentOptions;
import android.app.ContentProviderHolder;
import android.app.ForegroundServiceDelegationOptions;
import android.app.IActivityController;
@@ -7031,6 +7030,17 @@ public class ActivityManagerService extends IActivityManager.Stub
mCpHelper.getProviderMimeTypeAsync(uri, userId, resultCallback);
}
/**
* Filters calls to getType based on permission. If the caller has required permission,
* then it returns the contentProvider#getType.
* Else, it returns the contentProvider#getTypeAnonymous, which does not
* reveal any internal information which should be protected by any permission.
*/
@Override
public void getMimeTypeFilterAsync(Uri uri, int userId, RemoteCallback resultCallback) {
mCpHelper.getMimeTypeFilterAsync(uri, userId, resultCallback);
}
// =========================================================
// GLOBAL MANAGEMENT
// =========================================================

View File

@@ -15,6 +15,7 @@
*/
package com.android.server.am;
import static android.Manifest.permission.GET_ANY_PROVIDER_TYPE;
import static android.content.ContentProvider.isAuthorityRedirectedForCloneProfile;
import static android.os.Process.PROC_CHAR;
import static android.os.Process.PROC_OUT_LONG;
@@ -23,8 +24,6 @@ import static android.os.Process.PROC_SPACE_TERM;
import static android.os.Process.SYSTEM_UID;
import static com.android.internal.util.FrameworkStatsLog.GET_TYPE_ACCESSED_WITHOUT_PERMISSION;
import static com.android.internal.util.FrameworkStatsLog.GET_TYPE_ACCESSED_WITHOUT_PERMISSION__LOCATION__AM_CHECK_URI_PERMISSION;
import static com.android.internal.util.FrameworkStatsLog.GET_TYPE_ACCESSED_WITHOUT_PERMISSION__LOCATION__AM_ERROR;
import static com.android.internal.util.FrameworkStatsLog.GET_TYPE_ACCESSED_WITHOUT_PERMISSION__LOCATION__AM_FRAMEWORK_PERMISSION;
import static com.android.internal.util.FrameworkStatsLog.PROVIDER_ACQUISITION_EVENT_REPORTED;
import static com.android.internal.util.FrameworkStatsLog.PROVIDER_ACQUISITION_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_NORMAL;
@@ -52,7 +51,6 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.IContentProvider;
import android.content.Intent;
import android.content.PermissionChecker;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -1019,9 +1017,6 @@ public class ContentProviderHelper {
mService.mHandler.postDelayed(providerNotResponding, 1000);
try {
final String type = holder.provider.getType(uri);
if (type != null) {
backgroundLogging(callingUid, callingPid, userId, uri, holder, type);
}
return type;
} finally {
mService.mHandler.removeCallbacks(providerNotResponding);
@@ -1079,10 +1074,6 @@ public class ContentProviderHelper {
Binder.restoreCallingIdentity(identity);
}
resultCallback.sendResult(result);
final String type = result.getPairValue();
if (type != null) {
backgroundLogging(callingUid, callingPid, userId, uri, holder, type);
}
}));
} else {
resultCallback.sendResult(Bundle.EMPTY);
@@ -1093,65 +1084,82 @@ public class ContentProviderHelper {
}
}
private void backgroundLogging(int callingUid, int callingPid, int userId, Uri uri,
ContentProviderHolder holder, String type) {
// Push the logging code in a different handlerThread.
/**
* Filters calls to getType based on permission. If the caller has required permission,
* then it returns the contentProvider#getType.
* Else, it returns the contentProvider#getTypeAnonymous, which does not
* reveal any internal information which should be protected by any permission.
*/
void getMimeTypeFilterAsync(Uri uri, int userId, RemoteCallback resultCallback) {
mService.enforceNotIsolatedCaller("getProviderMimeTypeAsync");
final String name = uri.getAuthority();
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int safeUserId = mService.mUserController.unsafeConvertIncomingUser(userId);
final long ident = canClearIdentity(callingPid, callingUid, safeUserId)
? Binder.clearCallingIdentity() : 0;
final ContentProviderHolder holder;
try {
mService.mHandler.post(new Runnable() {
@Override
public void run() {
logGetTypeData(callingUid, callingPid, userId,
uri, holder, type);
holder = getContentProviderExternalUnchecked(name, null /* token */, callingUid,
"*getmimetype*", safeUserId);
} finally {
if (ident != 0) {
Binder.restoreCallingIdentity(ident);
}
}
try {
if (isHolderVisibleToCaller(holder, callingUid, safeUserId)) {
if (checkGetAnyTypePermission(callingUid, callingPid)) {
final AttributionSource attributionSource =
new AttributionSource.Builder(callingUid).build();
holder.provider.getTypeAsync(attributionSource,
uri, new RemoteCallback(result -> {
final long identity = Binder.clearCallingIdentity();
try {
removeContentProviderExternalUnchecked(name, null, safeUserId);
} finally {
Binder.restoreCallingIdentity(identity);
}
resultCallback.sendResult(result);
}));
} else {
holder.provider.getTypeAnonymousAsync(uri, new RemoteCallback(result -> {
final long identity = Binder.clearCallingIdentity();
try {
removeContentProviderExternalUnchecked(name, null, safeUserId);
} finally {
Binder.restoreCallingIdentity(identity);
}
resultCallback.sendResult(result);
final String type = result.getPairValue();
if (type != null) {
logGetTypeData(callingUid, uri, type);
}
}));
}
});
} catch (Exception e) {
// To ensure logging does not break the getType calls.
} else {
resultCallback.sendResult(Bundle.EMPTY);
}
} catch (RemoteException e) {
Log.w(TAG, "Content provider dead retrieving " + uri, e);
resultCallback.sendResult(Bundle.EMPTY);
}
}
// Utility function to log the getTypeData calls
private void logGetTypeData(int callingUid, int callingPid, int userId, Uri uri,
ContentProviderHolder holder, String type) {
try {
boolean checkUser = true;
final String authority = uri.getAuthority();
if (isAuthorityRedirectedForCloneProfile(authority)) {
UserManagerInternal umInternal =
LocalServices.getService(UserManagerInternal.class);
UserInfo userInfo = umInternal.getUserInfo(userId);
if (userInfo != null && userInfo.isCloneProfile()) {
userId = umInternal.getProfileParentId(userId);
checkUser = false;
}
}
final ProviderInfo cpi = holder.info;
final AttributionSource attributionSource =
new AttributionSource.Builder(callingUid).build();
final String permissionCheck =
checkContentProviderPermission(cpi, callingPid, callingUid,
userId, checkUser, null);
final boolean grantCheck = mService.checkUriPermission(uri, callingPid, callingUid,
Intent.FLAG_GRANT_READ_URI_PERMISSION , userId, null)
== PackageManager.PERMISSION_GRANTED;
if (!grantCheck && permissionCheck != null) {
FrameworkStatsLog.write(GET_TYPE_ACCESSED_WITHOUT_PERMISSION,
GET_TYPE_ACCESSED_WITHOUT_PERMISSION__LOCATION__AM_FRAMEWORK_PERMISSION,
callingUid, authority, type);
} else if (!grantCheck && cpi.forceUriPermissions
&& holder.provider.checkUriPermission(attributionSource,
uri, callingUid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
!= PermissionChecker.PERMISSION_GRANTED) {
FrameworkStatsLog.write(GET_TYPE_ACCESSED_WITHOUT_PERMISSION,
GET_TYPE_ACCESSED_WITHOUT_PERMISSION__LOCATION__AM_CHECK_URI_PERMISSION,
callingUid, authority, type);
}
} catch (Exception e) {
FrameworkStatsLog.write(GET_TYPE_ACCESSED_WITHOUT_PERMISSION,
GET_TYPE_ACCESSED_WITHOUT_PERMISSION__LOCATION__AM_ERROR, callingUid,
uri.getAuthority(), type);
private boolean checkGetAnyTypePermission(int callingUid, int callingPid) {
if (mService.checkPermission(GET_ANY_PROVIDER_TYPE, callingPid, callingUid)
== PackageManager.PERMISSION_GRANTED) {
return true;
}
return false;
}
// Utility function to log the getTypeData calls
private void logGetTypeData(int callingUid, Uri uri, String type) {
FrameworkStatsLog.write(GET_TYPE_ACCESSED_WITHOUT_PERMISSION,
GET_TYPE_ACCESSED_WITHOUT_PERMISSION__LOCATION__AM_FRAMEWORK_PERMISSION,
callingUid, uri.getAuthority(), type);
}
private boolean canClearIdentity(int callingPid, int callingUid, int userId) {

View File

@@ -80,15 +80,21 @@ public class MockContentProvider extends ContentProvider {
}
@Override
public String getType(Uri url) throws RemoteException {
public String getType(@NonNull AttributionSource attributionSource,
Uri url) throws RemoteException {
return MockContentProvider.this.getType(url);
}
@Override
public void getTypeAsync(Uri uri, RemoteCallback callback) throws RemoteException {
public void getTypeAsync(@NonNull AttributionSource attributionSource,
Uri uri, RemoteCallback callback) throws RemoteException {
MockContentProvider.this.getTypeAsync(uri, callback);
}
@Override
public void getTypeAnonymousAsync(Uri uri, RemoteCallback callback) throws RemoteException {
MockContentProvider.this.getTypeAnonymousAsync(uri, callback);
}
@Override
public Uri insert(@NonNull AttributionSource attributionSource, Uri url,
ContentValues initialValues, Bundle extras) throws RemoteException {
@@ -246,6 +252,23 @@ public class MockContentProvider extends ContentProvider {
});
}
@Override
public String getTypeAnonymous(Uri uri) {
throw new UnsupportedOperationException("unimplemented mock method");
}
/**
* @hide
*/
@SuppressWarnings("deprecation")
public void getTypeAnonymousAsync(Uri uri, RemoteCallback remoteCallback) {
AsyncTask.SERIAL_EXECUTOR.execute(() -> {
final Bundle bundle = new Bundle();
bundle.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getTypeAnonymous(uri));
remoteCallback.sendResult(bundle);
});
}
@Override
public Uri insert(Uri uri, ContentValues values) {
throw new UnsupportedOperationException("unimplemented mock method");

View File

@@ -61,16 +61,30 @@ public class MockIContentProvider implements IContentProvider {
}
@Override
public String getType(Uri url) {
public String getType(@NonNull AttributionSource attributionSource, Uri url) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@Override
@SuppressWarnings("deprecation")
public void getTypeAsync(Uri uri, RemoteCallback remoteCallback) {
public void getTypeAsync(@NonNull AttributionSource attributionSource,
Uri uri, RemoteCallback remoteCallback) {
AsyncTask.SERIAL_EXECUTOR.execute(() -> {
final Bundle bundle = new Bundle();
bundle.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getType(uri));
bundle.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getType(attributionSource,
uri));
remoteCallback.sendResult(bundle);
});
}
public String getTypeAnonymous(Uri url) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@Override
@SuppressWarnings("deprecation")
public void getTypeAnonymousAsync(Uri uri, RemoteCallback remoteCallback) {
AsyncTask.SERIAL_EXECUTOR.execute(() -> {
final Bundle bundle = new Bundle();
bundle.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getTypeAnonymous(uri));
remoteCallback.sendResult(bundle);
});
}