Merge "Add self revocation public API"

This commit is contained in:
Thomas Vannet
2022-01-12 21:44:32 +00:00
committed by Android (Google) Code Review
13 changed files with 191 additions and 1 deletions

View File

@@ -10876,6 +10876,8 @@ package android.content {
method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void removeStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
method public abstract void revokeUriPermission(android.net.Uri, int);
method public abstract void revokeUriPermission(String, android.net.Uri, int);
method public void selfRevokePermission(@NonNull String);
method public void selfRevokePermissions(@NonNull java.util.Collection<java.lang.String>);
method public abstract void sendBroadcast(@RequiresPermission android.content.Intent);
method public abstract void sendBroadcast(@RequiresPermission android.content.Intent, @Nullable String);
method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);

View File

@@ -9604,6 +9604,7 @@ package android.permission {
method @Deprecated @BinderThread public void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
method @BinderThread public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String, @NonNull Runnable);
method @BinderThread public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.util.List<java.lang.String>>>);
method @BinderThread public void onSelfRevokePermissions(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull Runnable);
method @Deprecated @BinderThread public abstract void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @BinderThread public void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull android.permission.AdminPermissionControlParams, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @BinderThread public void onStageAndApplyRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);

View File

@@ -113,6 +113,7 @@ import java.nio.ByteOrder;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -2169,6 +2170,11 @@ class ContextImpl extends Context {
return checkPermission(permission, pid, uid);
}
@Override
public void selfRevokePermissions(@NonNull Collection<String> permissions) {
getSystemService(PermissionManager.class).selfRevokePermissions(permissions);
}
@Override
public int checkCallingPermission(String permission) {
if (permission == null) {

View File

@@ -94,8 +94,11 @@ import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
/**
* Interface to global information about an application environment. This is
@@ -6407,6 +6410,43 @@ public abstract class Context {
@Nullable String writePermission, int pid, int uid, @Intent.AccessUriMode int modeFlags,
@Nullable String message);
/**
* Triggers the asynchronous revocation of a permission.
*
* @param permName The name of the permission to be revoked.
* @see #selfRevokePermissions(Collection)
*/
public void selfRevokePermission(@NonNull String permName) {
selfRevokePermissions(Collections.singletonList(permName));
}
/**
* Triggers the revocation of one or more permissions for the calling package. A package is only
* able to revoke a permission under the following conditions:
* <ul>
* <li>Each permission in {@code permissions} must be granted to the calling package.
* <li>Each permission in {@code permissions} must be a runtime permission.
* </ul>
* <p>
* For every permission in {@code permissions}, the entire permission group it belongs to will
* be revoked. The revocation happens asynchronously and kills all processes running in the
* calling UID. It will be triggered once it is safe to do so. In particular, it will not be
* triggered as long as the package remains in the foreground, or has any active manifest
* components (e.g. when another app is accessing a content provider in the package).
* <p>
* If you want to revoke the permissions right away, you could call {@code System.exit()}, but
* this could affect other apps that are accessing your app at the moment. For example, apps
* accessing a content provider in your app will all crash.
*
* @param permissions Collection of permissions to be revoked.
* @see PackageManager#getGroupOfPlatformPermission(String, Executor, Consumer)
* @see PackageManager#getPlatformPermissionsForGroup(String, Executor, Consumer)
*/
public void selfRevokePermissions(@NonNull Collection<String> permissions) {
throw new AbstractMethodError("Must be overridden in implementing class");
}
/** @hide */
@IntDef(flag = true, prefix = { "CONTEXT_" }, value = {
CONTEXT_INCLUDE_CODE,

View File

@@ -53,6 +53,7 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Executor;
@@ -1014,6 +1015,11 @@ public class ContextWrapper extends Context {
message);
}
@Override
public void selfRevokePermissions(@NonNull Collection<String> permissions) {
mBase.selfRevokePermissions(permissions);
}
@Override
public Context createPackageContext(String packageName, int flags)
throws PackageManager.NameNotFoundException {

View File

@@ -56,4 +56,6 @@ oneway interface IPermissionController {
in AndroidFuture<String> callback);
void getUnusedAppCount(
in AndroidFuture callback);
void selfRevokePermissions(in String packageName, in List<String> permissions,
in AndroidFuture callback);
}

View File

@@ -76,6 +76,8 @@ interface IPermissionManager {
List<SplitPermissionInfoParcelable> getSplitPermissions();
void selfRevokePermissions(String packageName, in List<String> permissions);
void startOneTimePermissionSession(String packageName, int userId, long timeout,
int importanceToResetTimer, int importanceToKeepSessionAlive);

View File

@@ -817,4 +817,40 @@ public final class PermissionControllerManager {
}
});
}
/**
* Triggers the revocation of one or more permissions for a package, under the following
* conditions:
* <ul>
* <li>The package {@code packageName} must be under the same UID as the calling process
* (typically, the target package is the calling package).
* <li>Each permission in {@code permissions} must be granted to the package
* {@code packageName}.
* <li>Each permission in {@code permissions} must be a runtime permission.
* </ul>
* <p>
* For every permission in {@code permissions}, the entire permission group it belongs to will
* be revoked. This revocation happens asynchronously and kills all processes running in the
* same UID as {@code packageName}. It will be triggered once it is safe to do so.
*
* @param packageName The name of the package for which the permissions will be revoked.
* @param permissions List of permissions to be revoked.
*
* @see Context#selfRevokePermissions(Collection)
*
* @hide
*/
public void selfRevokePermissions(@NonNull String packageName,
@NonNull List<String> permissions) {
mRemoteService.postAsync(service -> {
AndroidFuture<Void> future = new AndroidFuture<>();
service.selfRevokePermissions(packageName, permissions, future);
return future;
}).whenComplete((result, err) -> {
if (err != null) {
Log.e(TAG, "Failed to self revoke " + String.join(",", permissions)
+ " for package " + packageName, err);
}
});
}
}

View File

@@ -324,6 +324,27 @@ public abstract class PermissionControllerService extends Service {
@NonNull Consumer<String> callback) {
throw new AbstractMethodError("Must be overridden in implementing class");
}
/**
* Triggers the revocation of one or more permissions for a package. This should only be called
* at the request of {@code packageName}.
* <p>
* For every permission in {@code permissions}, the entire permission group it belongs to will
* be revoked. This revocation happens asynchronously and kills all processes running in the
* same UID as {@code packageName}. It will be triggered once it is safe to do so.
*
* @param packageName The name of the package for which the permissions will be revoked.
* @param permissions List of permissions to be revoked.
* @param callback Callback waiting for operation to be complete.
*
* @see PermissionManager#selfRevokePermissions(java.util.Collection)
*/
@BinderThread
public void onSelfRevokePermissions(@NonNull String packageName,
@NonNull List<String> permissions, @NonNull Runnable callback) {
throw new AbstractMethodError("Must be overridden in implementing class");
}
/**
* Get a user-readable sentence, describing the set of privileges that are to be granted to a
* companion app managing a device of the given profile.
@@ -646,6 +667,20 @@ public abstract class PermissionControllerService extends Service {
callback.completeExceptionally(t);
}
}
@Override
public void selfRevokePermissions(@NonNull String packageName,
@NonNull List<String> permissions, @NonNull AndroidFuture callback) {
try {
enforceSomePermissionsGrantedToCaller(
Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
Objects.requireNonNull(callback);
onSelfRevokePermissions(packageName, permissions,
() -> callback.complete(null));
} catch (Throwable t) {
callback.completeExceptionally(t);
}
}
};
}
}

View File

@@ -68,6 +68,7 @@ import com.android.internal.annotations.Immutable;
import com.android.internal.util.CollectionUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -560,6 +561,19 @@ public final class PermissionManager {
}
}
/**
* @see Context#selfRevokePermissions(Collection)
* @hide
*/
public void selfRevokePermissions(@NonNull Collection<String> permissions) {
try {
mPermissionManager.selfRevokePermissions(mContext.getPackageName(),
new ArrayList<String>(permissions));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Gets the state flags associated with a permission.
*

View File

@@ -386,7 +386,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@Override
public void startOneTimePermissionSession(String packageName, @UserIdInt int userId,
long timeoutMillis, int importanceToResetTimer, int importanceToKeepSessionAlive) {
mContext.enforceCallingPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS,
mContext.enforceCallingOrSelfPermission(
Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS,
"Must hold " + Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS
+ " to register permissions as one time.");
Objects.requireNonNull(packageName);
@@ -556,6 +557,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
packageName, userId);
}
@Override
public void selfRevokePermissions(@NonNull String packageName,
@NonNull List<String> permissions) {
mPermissionManagerServiceImpl.selfRevokePermissions(packageName, permissions);
}
@Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permissionName,
int userId) {

View File

@@ -1591,6 +1591,25 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
}
@Override
public void selfRevokePermissions(String packageName, List<String> permissions) {
final int callingUid = Binder.getCallingUid();
int callingUserId = UserHandle.getUserId(callingUid);
int targetPackageUid = mPackageManagerInt.getPackageUid(packageName, 0, callingUserId);
if (targetPackageUid != callingUid) {
throw new SecurityException("uid " + callingUid
+ " cannot revoke permissions for package " + packageName + " with uid "
+ targetPackageUid);
}
for (String permName : permissions) {
if (!checkCallingOrSelfPermission(permName)) {
throw new SecurityException("uid " + callingUid + " cannot revoke permission "
+ permName + " because it does not hold that permission");
}
}
mPermissionControllerManager.selfRevokePermissions(packageName, permissions);
}
private boolean mayManageRolePermission(int uid) {
final PackageManager packageManager = mContext.getPackageManager();
final String[] packageNames = packageManager.getPackagesForUid(uid);

View File

@@ -326,6 +326,26 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
*/
void revokePostNotificationPermissionWithoutKillForTest(String packageName, int userId);
/**
* Triggers the revocation of one or more permissions for a package, under the following
* conditions:
* <ul>
* <li>The package {@code packageName} must be under the same UID as the calling process
* (typically, the target package is the calling package).
* <li>Each permission in {@code permissions} must be granted to the package
* {@code packageName}.
* <li>Each permission in {@code permissions} must be a runtime permission.
* </ul>
* <p>
* For every permission in {@code permissions}, the entire permission group it belongs to will
* be revoked. This revocation happens asynchronously and kills all processes running in the
* same UID as {@code packageName}. It will be triggered once it is safe to do so.
*
* @param packageName The name of the package for which the permissions will be revoked.
* @param permissions List of permissions to be revoked.
*/
void selfRevokePermissions(String packageName, List<String> permissions);
/**
* Get whether you should show UI with rationale for requesting a permission. You should do this
* only if you do not have the permission and the context in which the permission is requested