Merge changes from topics "otpsessionkilleddelay", "selfrevokeperperm"

* changes:
  Update self-revocation doc: revoke by permission, not group
  Add killed delay param to startOneTimePermissionSession
This commit is contained in:
Thomas Vannet
2022-02-04 03:54:10 +00:00
committed by Android (Google) Code Review
10 changed files with 125 additions and 90 deletions

View File

@@ -9948,7 +9948,8 @@ package android.permission {
method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion();
method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
method @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, int, int);
method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, int, int);
method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, long, int, int);
method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void stopOneTimePermissionSession(@NonNull String);
field @RequiresPermission(android.Manifest.permission.START_REVIEW_PERMISSION_DECISIONS) public static final String ACTION_REVIEW_PERMISSION_DECISIONS = "android.permission.action.REVIEW_PERMISSION_DECISIONS";
field public static final int PERMISSION_GRANTED = 0; // 0x0

View File

@@ -6504,15 +6504,26 @@ public abstract class Context {
* <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).
* Background permissions which have no corresponding foreground permission still granted once
* the revocation is effective will also be revoked.
* <p>
* 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.
* <p>
* Note that the settings UI shows a permission group as granted as long as at least one
* permission in the group is granted. If you want the user to observe the revocation in the
* settings, you should revoke every permission in the target group. To learn the current list
* of permissions in a group, you may use
* {@link PackageManager#getGroupOfPlatformPermission(String, Executor, Consumer)} and
* {@link PackageManager#getPlatformPermissionsForGroup(String, Executor, Consumer)}. This list
* of permissions may evolve over time, so it is recommended to check whether it contains any
* permission you wish to retain before trying to revoke an entire group.
*
* @param permissions Collection of permissions to be revoked.
* @see PackageManager#getGroupOfPlatformPermission(String, Executor, Consumer)

View File

@@ -79,7 +79,8 @@ interface IPermissionManager {
void revokeOwnPermissionsOnKill(String packageName, in List<String> permissions);
void startOneTimePermissionSession(String packageName, int userId, long timeout,
int importanceToResetTimer, int importanceToKeepSessionAlive);
long revokeAfterKilledDelay, int importanceToResetTimer,
int importanceToKeepSessionAlive);
void stopOneTimePermissionSession(String packageName, int userId);

View File

@@ -907,21 +907,23 @@ public final class PermissionControllerManager {
* <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.
* Background permissions which have no corresponding foreground permission still granted once
* the revocation is effective will also be revoked.
* <p>
* 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 called when the revocation request has been completed.
*
* @see Context#revokeOwnPermissionsOnKill(Collection)
* @see Context#revokeOwnPermissionsOnKill(java.util.Collection)
*
* @hide
*/
public void revokeOwnPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions, AndroidFuture<Void> callback) {
@NonNull List<String> permissions) {
mRemoteService.postAsync(service -> {
AndroidFuture<Void> callback = new AndroidFuture<>();
service.revokeOwnPermissionsOnKill(packageName, permissions, callback);
return callback;
}).whenComplete((result, err) -> {

View File

@@ -291,7 +291,7 @@ public abstract class PermissionControllerService extends Service {
/**
* Called when a package is considered inactive based on the criteria given by
* {@link PermissionManager#startOneTimePermissionSession(String, long, int, int)}.
* {@link PermissionManager#startOneTimePermissionSession(String, long, long, int, int)}.
* This method is called at the end of a one-time permission session
*
* @param packageName The package that has been inactive
@@ -329,9 +329,11 @@ public abstract class PermissionControllerService extends Service {
* 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.
* Background permissions which have no corresponding foreground permission still granted once
* the revocation is effective will also be revoked.
* <p>
* 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.

View File

@@ -20,6 +20,7 @@ import static android.os.Build.VERSION_CODES.S;
import android.Manifest;
import android.annotation.CheckResult;
import android.annotation.DurationMillisLong;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1281,6 +1282,22 @@ public final class PermissionManager {
}
}
/**
* Starts a one-time permission session for a given package.
* @see #startOneTimePermissionSession(String, long, long, int, int)
* @hide
* @deprecated Use {@link #startOneTimePermissionSession(String, long, long, int, int)} instead
*/
@Deprecated
@SystemApi
@RequiresPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS)
public void startOneTimePermissionSession(@NonNull String packageName, long timeoutMillis,
@ActivityManager.RunningAppProcessInfo.Importance int importanceToResetTimer,
@ActivityManager.RunningAppProcessInfo.Importance int importanceToKeepSessionAlive) {
startOneTimePermissionSession(packageName, timeoutMillis, -1,
importanceToResetTimer, importanceToKeepSessionAlive);
}
/**
* Starts a one-time permission session for a given package. A one-time permission session is
* ended if app becomes inactive. Inactivity is defined as the package's uid importance level
@@ -1301,25 +1318,33 @@ public final class PermissionManager {
* {@link PermissionControllerService#onOneTimePermissionSessionTimeout(String)} is invoked.
* </p>
* <p>
* Note that if there is currently an active session for a package a new one isn't created and
* the existing one isn't changed.
* Note that if there is currently an active session for a package a new one isn't created but
* each parameter of the existing one will be updated to the more aggressive of both sessions.
* This means that durations will be set to the shortest parameter and importances will be set
* to the lowest one.
* </p>
* @param packageName The package to start a one-time permission session for
* @param timeoutMillis Number of milliseconds for an app to be in an inactive state
* @param revokeAfterKilledDelayMillis Number of milliseconds to wait before revoking on the
* event an app is terminated. Set to -1 to use default
* value for the device.
* @param importanceToResetTimer The least important level to uid must be to reset the timer
* @param importanceToKeepSessionAlive The least important level the uid must be to keep the
* session alive
* session alive
*
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS)
public void startOneTimePermissionSession(@NonNull String packageName, long timeoutMillis,
public void startOneTimePermissionSession(@NonNull String packageName,
@DurationMillisLong long timeoutMillis,
@DurationMillisLong long revokeAfterKilledDelayMillis,
@ActivityManager.RunningAppProcessInfo.Importance int importanceToResetTimer,
@ActivityManager.RunningAppProcessInfo.Importance int importanceToKeepSessionAlive) {
try {
mPermissionManager.startOneTimePermissionSession(packageName, mContext.getUserId(),
timeoutMillis, importanceToResetTimer, importanceToKeepSessionAlive);
timeoutMillis, revokeAfterKilledDelayMillis, importanceToResetTimer,
importanceToKeepSessionAlive);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}

View File

@@ -108,14 +108,18 @@ public class OneTimePermissionUserManager {
* </p>
* @param packageName The package to start a one-time permission session for
* @param timeoutMillis Number of milliseconds for an app to be in an inactive state
* @param revokeAfterKilledDelayMillis Number of milliseconds to wait after the process dies
* before ending the session. Set to -1 to use default value
* for the device.
* @param importanceToResetTimer The least important level to uid must be to reset the timer
* @param importanceToKeepSessionAlive The least important level the uid must be to keep the
* session alive
* session alive
*
* @hide
*/
void startPackageOneTimeSession(@NonNull String packageName, long timeoutMillis,
int importanceToResetTimer, int importanceToKeepSessionAlive) {
long revokeAfterKilledDelayMillis, int importanceToResetTimer,
int importanceToKeepSessionAlive) {
int uid;
try {
uid = mContext.getPackageManager().getPackageUid(packageName, 0);
@@ -126,11 +130,15 @@ public class OneTimePermissionUserManager {
synchronized (mLock) {
PackageInactivityListener listener = mListeners.get(uid);
if (listener == null) {
listener = new PackageInactivityListener(uid, packageName, timeoutMillis,
if (listener != null) {
listener.updateSessionParameters(timeoutMillis, revokeAfterKilledDelayMillis,
importanceToResetTimer, importanceToKeepSessionAlive);
mListeners.put(uid, listener);
return;
}
listener = new PackageInactivityListener(uid, packageName, timeoutMillis,
revokeAfterKilledDelayMillis, importanceToResetTimer,
importanceToKeepSessionAlive);
mListeners.put(uid, listener);
}
}
@@ -158,18 +166,6 @@ public class OneTimePermissionUserManager {
}
}
/**
* The delay to wait before revoking on the event an app is terminated. Recommended to be long
* enough so that apps don't lose permission on an immediate restart
*/
private long getKilledDelayMillis(boolean isSelfRevokedPermissionSession) {
if (isSelfRevokedPermissionSession) {
return 0;
}
return DeviceConfig.getLong(DeviceConfig.NAMESPACE_PERMISSIONS,
PROPERTY_KILLED_DELAY_CONFIG_KEY, DEFAULT_KILLED_DELAY_MILLIS);
}
/**
* Register to listen for Uids being uninstalled. This must be done outside of the
* PermissionManagerService lock.
@@ -178,18 +174,6 @@ public class OneTimePermissionUserManager {
mContext.registerReceiver(mUninstallListener, new IntentFilter(Intent.ACTION_UID_REMOVED));
}
void setSelfRevokedPermissionSession(int uid) {
synchronized (mLock) {
PackageInactivityListener listener = mListeners.get(uid);
if (listener == null) {
Log.e(LOG_TAG, "Could not set session for uid " + uid
+ " as self-revoke session: session not found");
return;
}
listener.setSelfRevokedPermissionSession();
}
}
/**
* A class which watches a package for inactivity and notifies the permission controller when
* the package becomes inactive
@@ -200,11 +184,11 @@ public class OneTimePermissionUserManager {
private final int mUid;
private final @NonNull String mPackageName;
private final long mTimeout;
private final int mImportanceToResetTimer;
private final int mImportanceToKeepSessionAlive;
private long mTimeout;
private long mRevokeAfterKilledDelay;
private int mImportanceToResetTimer;
private int mImportanceToKeepSessionAlive;
private boolean mIsSelfRevokedPermissionSession;
private boolean mIsAlarmSet;
private boolean mIsFinished;
@@ -218,16 +202,23 @@ public class OneTimePermissionUserManager {
private final Object mToken = new Object();
private PackageInactivityListener(int uid, @NonNull String packageName, long timeout,
int importanceToResetTimer, int importanceToKeepSessionAlive) {
long revokeAfterkilledDelay, int importanceToResetTimer,
int importanceToKeepSessionAlive) {
Log.i(LOG_TAG,
"Start tracking " + packageName + ". uid=" + uid + " timeout=" + timeout
+ " killedDelay=" + revokeAfterkilledDelay
+ " importanceToResetTimer=" + importanceToResetTimer
+ " importanceToKeepSessionAlive=" + importanceToKeepSessionAlive);
mUid = uid;
mPackageName = packageName;
mTimeout = timeout;
mRevokeAfterKilledDelay = revokeAfterkilledDelay == -1
? DeviceConfig.getLong(
DeviceConfig.NAMESPACE_PERMISSIONS, PROPERTY_KILLED_DELAY_CONFIG_KEY,
DEFAULT_KILLED_DELAY_MILLIS)
: revokeAfterkilledDelay;
mImportanceToResetTimer = importanceToResetTimer;
mImportanceToKeepSessionAlive = importanceToKeepSessionAlive;
@@ -247,6 +238,28 @@ public class OneTimePermissionUserManager {
onImportanceChanged(mUid, mActivityManager.getPackageImportance(packageName));
}
public void updateSessionParameters(long timeoutMillis, long revokeAfterKilledDelayMillis,
int importanceToResetTimer, int importanceToKeepSessionAlive) {
synchronized (mInnerLock) {
mTimeout = Math.min(mTimeout, timeoutMillis);
mRevokeAfterKilledDelay = Math.min(mRevokeAfterKilledDelay,
revokeAfterKilledDelayMillis == -1
? DeviceConfig.getLong(
DeviceConfig.NAMESPACE_PERMISSIONS,
PROPERTY_KILLED_DELAY_CONFIG_KEY, DEFAULT_KILLED_DELAY_MILLIS)
: revokeAfterKilledDelayMillis);
mImportanceToResetTimer = Math.min(importanceToResetTimer, mImportanceToResetTimer);
mImportanceToKeepSessionAlive = Math.min(importanceToKeepSessionAlive,
mImportanceToKeepSessionAlive);
Log.v(LOG_TAG,
"Updated params for " + mPackageName + ". timeout=" + mTimeout
+ " killedDelay=" + mRevokeAfterKilledDelay
+ " importanceToResetTimer=" + mImportanceToResetTimer
+ " importanceToKeepSessionAlive=" + mImportanceToKeepSessionAlive);
onImportanceChanged(mUid, mActivityManager.getPackageImportance(mPackageName));
}
}
private void onImportanceChanged(int uid, int importance) {
if (uid != mUid) {
return;
@@ -271,7 +284,7 @@ public class OneTimePermissionUserManager {
}
onImportanceChanged(mUid, imp);
}
}, mToken, getKilledDelayMillis(mIsSelfRevokedPermissionSession));
}, mToken, mRevokeAfterKilledDelay);
return;
}
if (importance > mImportanceToResetTimer) {
@@ -306,14 +319,6 @@ public class OneTimePermissionUserManager {
}
}
/**
* Marks the session as a self-revoke session, which does not delay the revocation when
* the app is restarting.
*/
public void setSelfRevokedPermissionSession() {
mIsSelfRevokedPermissionSession = true;
}
/**
* Set the alarm which will callback when the package is inactive
*/

View File

@@ -68,7 +68,6 @@ import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.TriFunction;
import com.android.server.LocalServices;
@@ -388,7 +387,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@Override
public void startOneTimePermissionSession(String packageName, @UserIdInt int userId,
long timeoutMillis, int importanceToResetTimer, int importanceToKeepSessionAlive) {
long timeoutMillis, long revokeAfterKilledDelayMillis, int importanceToResetTimer,
int importanceToKeepSessionAlive) {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS,
"Must hold " + Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS
@@ -398,7 +398,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final long token = Binder.clearCallingIdentity();
try {
getOneTimePermissionUserManager(userId).startPackageOneTimeSession(packageName,
timeoutMillis, importanceToResetTimer, importanceToKeepSessionAlive);
timeoutMillis, revokeAfterKilledDelayMillis, importanceToResetTimer,
importanceToKeepSessionAlive);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -563,16 +564,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@Override
public void revokeOwnPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions) {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
AndroidFuture<Void> future = new AndroidFuture<>();
future.whenComplete((result, err) -> {
if (err == null) {
getOneTimePermissionUserManager(callingUserId)
.setSelfRevokedPermissionSession(callingUid);
}
});
mPermissionManagerServiceImpl.revokeOwnPermissionsOnKill(packageName, permissions, future);
mPermissionManagerServiceImpl.revokeOwnPermissionsOnKill(packageName, permissions);
}
@Override

View File

@@ -108,7 +108,6 @@ import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.os.RoSystemProperties;
@@ -1592,8 +1591,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
@Override
public void revokeOwnPermissionsOnKill(String packageName, List<String> permissions,
AndroidFuture<Void> callback) {
public void revokeOwnPermissionsOnKill(String packageName, List<String> permissions) {
final int callingUid = Binder.getCallingUid();
int callingUserId = UserHandle.getUserId(callingUid);
int targetPackageUid = mPackageManagerInt.getPackageUid(packageName, 0, callingUserId);
@@ -1608,8 +1606,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
+ permName + " because it does not hold that permission");
}
}
mPermissionControllerManager.revokeOwnPermissionsOnKill(packageName, permissions,
callback);
mPermissionControllerManager.revokeOwnPermissionsOnKill(packageName, permissions);
}
private boolean mayManageRolePermission(int uid) {

View File

@@ -27,7 +27,6 @@ import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.permission.IOnPermissionsChangeListener;
import android.permission.PermissionManagerInternal;
import com.android.internal.infra.AndroidFuture;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.io.FileDescriptor;
@@ -338,16 +337,16 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
* <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.
* Background permissions which have no corresponding foreground permission still granted once
* the revocation is effective will also be revoked.
* <p>
* 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 called when the revocation request has been completed.
*/
void revokeOwnPermissionsOnKill(String packageName, List<String> permissions,
AndroidFuture<Void> callback);
void revokeOwnPermissionsOnKill(String packageName, List<String> permissions);
/**
* Get whether you should show UI with rationale for requesting a permission. You should do this