Merge "Add self revocation public API"
This commit is contained in:
committed by
Android (Google) Code Review
commit
4c09f45a59
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user