diff options
10 files changed, 127 insertions, 39 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 7c78f09f0057..69ed5aeda7de 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -10635,12 +10635,14 @@ package android.permission { method @BinderThread public abstract void onGetRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.OutputStream, @NonNull Runnable); method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public void onGetUnusedAppCount(@NonNull java.util.function.IntConsumer); method @BinderThread public abstract void onGrantOrUpgradeDefaultRuntimePermissions(@NonNull Runnable); - method @BinderThread public void onOneTimePermissionSessionTimeout(@NonNull String); + method @Deprecated @BinderThread public void onOneTimePermissionSessionTimeout(@NonNull String); + method @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS) @BinderThread public void onOneTimePermissionSessionTimeout(@NonNull String, int); method @Deprecated @BinderThread public void onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>); 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 onRevokeSelfPermissionsOnKill(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull Runnable); + method @Deprecated @BinderThread public void onRevokeSelfPermissionsOnKill(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull Runnable); + method @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS) @BinderThread public void onRevokeSelfPermissionsOnKill(@NonNull String, @NonNull java.util.List<java.lang.String>, int, @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); diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl index e3f02e73a41f..1cb7930928d0 100644 --- a/core/java/android/permission/IPermissionController.aidl +++ b/core/java/android/permission/IPermissionController.aidl @@ -43,7 +43,7 @@ oneway interface IPermissionController { void setRuntimePermissionGrantStateByDeviceAdminFromParams(String callerPackageName, in AdminPermissionControlParams params, in AndroidFuture callback); void grantOrUpgradeDefaultRuntimePermissions(in AndroidFuture callback); - void notifyOneTimePermissionSessionTimeout(String packageName); + void notifyOneTimePermissionSessionTimeout(String packageName, int deviceId); void updateUserSensitiveForApp(int uid, in AndroidFuture callback); void getPrivilegesDescriptionStringForProfile( in String deviceProfileName, @@ -60,5 +60,5 @@ oneway interface IPermissionController { in String packageName, in AndroidFuture callback); void revokeSelfPermissionsOnKill(in String packageName, in List<String> permissions, - in AndroidFuture callback); + int deviceId, in AndroidFuture callback); } diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl index 18ede44dca20..7cecfdca851a 100644 --- a/core/java/android/permission/IPermissionManager.aidl +++ b/core/java/android/permission/IPermissionManager.aidl @@ -78,7 +78,7 @@ interface IPermissionManager { List<SplitPermissionInfoParcelable> getSplitPermissions(); @EnforcePermission("MANAGE_ONE_TIME_PERMISSION_SESSIONS") - void startOneTimePermissionSession(String packageName, int userId, long timeout, + void startOneTimePermissionSession(String packageName, int deviceId, int userId, long timeout, long revokeAfterKilledDelay); @EnforcePermission("MANAGE_ONE_TIME_PERMISSION_SESSIONS") diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java index 84a197a96531..ba7591814a7b 100644 --- a/core/java/android/permission/PermissionControllerManager.java +++ b/core/java/android/permission/PermissionControllerManager.java @@ -764,13 +764,14 @@ public final class PermissionControllerManager { * inactive. * * @param packageName The package which became inactive - * + * @param deviceId The device ID refers either the primary device i.e. the phone or + * a virtual device. See {@link Context#DEVICE_ID_DEFAULT} * @hide */ @RequiresPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) - public void notifyOneTimePermissionSessionTimeout(@NonNull String packageName) { - mRemoteService.run( - service -> service.notifyOneTimePermissionSessionTimeout(packageName)); + public void notifyOneTimePermissionSessionTimeout(@NonNull String packageName, int deviceId) { + mRemoteService.run(service -> service.notifyOneTimePermissionSessionTimeout( + packageName, deviceId)); } /** @@ -930,12 +931,14 @@ public final class PermissionControllerManager { @NonNull List<String> permissions) { mRemoteService.postAsync(service -> { AndroidFuture<Void> callback = new AndroidFuture<>(); - service.revokeSelfPermissionsOnKill(packageName, permissions, callback); + service.revokeSelfPermissionsOnKill(packageName, permissions, mContext.getDeviceId(), + callback); return callback; }).whenComplete((result, err) -> { if (err != null) { Log.e(TAG, "Failed to self revoke " + String.join(",", permissions) - + " for package " + packageName, err); + + " for package " + packageName + ", and device " + mContext.getDeviceId(), + err); } }); } diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java index 11005a6d265b..9fe2599dd39b 100644 --- a/core/java/android/permission/PermissionControllerService.java +++ b/core/java/android/permission/PermissionControllerService.java @@ -30,6 +30,7 @@ import static com.android.internal.util.Preconditions.checkStringNotEmpty; import android.Manifest; import android.annotation.BinderThread; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; @@ -37,6 +38,7 @@ import android.app.Service; import android.app.admin.DevicePolicyManager.PermissionGrantState; import android.compat.annotation.ChangeId; import android.compat.annotation.Disabled; +import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -46,6 +48,7 @@ import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.UserHandle; import android.permission.PermissionControllerManager.CountPermissionAppsFlag; +import android.permission.flags.Flags; import android.util.ArrayMap; import android.util.Log; @@ -296,13 +299,32 @@ public abstract class PermissionControllerService extends Service { * This method is called at the end of a one-time permission session * * @param packageName The package that has been inactive + * + * @deprecated Implement {@link #onOneTimePermissionSessionTimeout(String, int)} instead. */ + @Deprecated @BinderThread public void onOneTimePermissionSessionTimeout(@NonNull String packageName) { throw new AbstractMethodError("Must be overridden in implementing class"); } /** + * Called when a package is considered inactive based on the criteria given by + * {@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 + * @param deviceId The device ID refers either the primary device i.e. the phone or + * a virtual device. See {@link Context#DEVICE_ID_DEFAULT} + */ + @BinderThread + @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS) + public void onOneTimePermissionSessionTimeout(@NonNull String packageName, + int deviceId) { + onOneTimePermissionSessionTimeout(packageName); + } + + /** * Get the platform permissions which belong to a particular permission group * * @param permissionGroupName The permission group whose permissions are desired @@ -341,13 +363,42 @@ public abstract class PermissionControllerService extends Service { * @param callback Callback waiting for operation to be complete. * * @see android.content.Context#revokeSelfPermissionsOnKill(java.util.Collection) + * + * @deprecated Implement {@link #onRevokeSelfPermissionsOnKill(String, List, int, Runnable)} + * instead. */ + @Deprecated @BinderThread public void onRevokeSelfPermissionsOnKill(@NonNull String packageName, @NonNull List<String> permissions, @NonNull Runnable callback) { throw new AbstractMethodError("Must be overridden in implementing class"); } + /** + * Triggers the revocation of one or more permissions for a package and device. + * This should only be called at the request of {@code packageName}. + * <p> + * 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 deviceId The device ID refers either the primary device i.e. the phone or + * a virtual device. See {@link Context#DEVICE_ID_DEFAULT} + * @param callback Callback waiting for operation to be complete. + * + * @see android.content.Context#revokeSelfPermissionsOnKill(java.util.Collection) + */ + @BinderThread + @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS) + public void onRevokeSelfPermissionsOnKill(@NonNull String packageName, + @NonNull List<String> permissions, int deviceId, @NonNull Runnable callback) { + onRevokeSelfPermissionsOnKill(packageName, permissions, callback); + } + // TODO(b/272129940): Remove this API and device profile role description when we drop T // support. /** @@ -613,12 +664,12 @@ public abstract class PermissionControllerService extends Service { } @Override - public void notifyOneTimePermissionSessionTimeout(String packageName) { + public void notifyOneTimePermissionSessionTimeout(String packageName, int deviceId) { enforceSomePermissionsGrantedToCaller( Manifest.permission.REVOKE_RUNTIME_PERMISSIONS); packageName = Preconditions.checkNotNull(packageName, "packageName cannot be null"); - onOneTimePermissionSessionTimeout(packageName); + onOneTimePermissionSessionTimeout(packageName, deviceId); } @Override @@ -710,7 +761,8 @@ public abstract class PermissionControllerService extends Service { @Override public void revokeSelfPermissionsOnKill(@NonNull String packageName, - @NonNull List<String> permissions, @NonNull AndroidFuture callback) { + @NonNull List<String> permissions, int deviceId, + @NonNull AndroidFuture callback) { try { Objects.requireNonNull(callback); @@ -721,7 +773,7 @@ public abstract class PermissionControllerService extends Service { enforceSomePermissionsGrantedToCaller( Manifest.permission.REVOKE_RUNTIME_PERMISSIONS); } - onRevokeSelfPermissionsOnKill(packageName, permissions, + onRevokeSelfPermissionsOnKill(packageName, permissions, deviceId, () -> callback.complete(null)); } catch (Throwable t) { callback.completeExceptionally(t); diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 7d3921049712..e10ea10e2a29 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -214,6 +214,12 @@ public final class PermissionManager { public static final boolean DEBUG_TRACE_PERMISSION_UPDATES = false; /** + * Additional debug log for virtual device permissions. + * @hide + */ + public static final boolean DEBUG_DEVICE_PERMISSIONS = false; + + /** * Intent extra: List of PermissionGroupUsages * <p> * Type: {@code List<PermissionGroupUsage>} @@ -1392,8 +1398,8 @@ public final class PermissionManager { @ActivityManager.RunningAppProcessInfo.Importance int importanceToResetTimer, @ActivityManager.RunningAppProcessInfo.Importance int importanceToKeepSessionAlive) { try { - mPermissionManager.startOneTimePermissionSession(packageName, mContext.getUserId(), - timeoutMillis, revokeAfterKilledDelayMillis); + mPermissionManager.startOneTimePermissionSession(packageName, mContext.getDeviceId(), + mContext.getUserId(), timeoutMillis, revokeAfterKilledDelayMillis); } catch (RemoteException e) { e.rethrowFromSystemServer(); } diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 15620b7023e2..11ae9c35898b 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -206,6 +206,7 @@ <uses-permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" /> <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS" /> <uses-permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS" /> + <uses-permission android:name="android.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS" /> <uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" /> <uses-permission android:name="android.permission.WHITELIST_RESTRICTED_PERMISSIONS" /> <!-- Permission required for processes that don't own the focused window to switch diff --git a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java index 3296c1f284af..150ca9ba2853 100644 --- a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java +++ b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java @@ -91,13 +91,14 @@ public class OneTimePermissionUserManager { mHandler = context.getMainThreadHandler(); } - void startPackageOneTimeSession(@NonNull String packageName, long timeoutMillis, + void startPackageOneTimeSession(@NonNull String packageName, int deviceId, long timeoutMillis, long revokeAfterKilledDelayMillis) { int uid; try { uid = mContext.getPackageManager().getPackageUid(packageName, 0); } catch (PackageManager.NameNotFoundException e) { - Log.e(LOG_TAG, "Unknown package name " + packageName, e); + Log.e(LOG_TAG, + "Unknown package name " + packageName + ", device ID " + deviceId, e); return; } @@ -107,7 +108,7 @@ public class OneTimePermissionUserManager { listener.updateSessionParameters(timeoutMillis, revokeAfterKilledDelayMillis); return; } - listener = new PackageInactivityListener(uid, packageName, timeoutMillis, + listener = new PackageInactivityListener(uid, packageName, deviceId, timeoutMillis, revokeAfterKilledDelayMillis); mListeners.put(uid, listener); } @@ -159,6 +160,7 @@ public class OneTimePermissionUserManager { private final int mUid; private final @NonNull String mPackageName; + private final int mDeviceId; private long mTimeout; private long mRevokeAfterKilledDelay; @@ -191,14 +193,15 @@ public class OneTimePermissionUserManager { } }; - private PackageInactivityListener(int uid, @NonNull String packageName, long timeout, - long revokeAfterkilledDelay) { + private PackageInactivityListener(int uid, @NonNull String packageName, int deviceId, + long timeout, long revokeAfterkilledDelay) { Log.i(LOG_TAG, "Start tracking " + packageName + ". uid=" + uid + " timeout=" + timeout + " killedDelay=" + revokeAfterkilledDelay); mUid = uid; mPackageName = packageName; + mDeviceId = deviceId; mTimeout = timeout; mRevokeAfterKilledDelay = revokeAfterkilledDelay == -1 ? DeviceConfig.getLong( @@ -232,7 +235,8 @@ public class OneTimePermissionUserManager { PROPERTY_KILLED_DELAY_CONFIG_KEY, DEFAULT_KILLED_DELAY_MILLIS) : revokeAfterKilledDelayMillis); Log.v(LOG_TAG, - "Updated params for " + mPackageName + ". timeout=" + mTimeout + "Updated params for " + mPackageName + ", device ID " + mDeviceId + + ". timeout=" + mTimeout + " killedDelay=" + mRevokeAfterKilledDelay); updateUidState(); } @@ -260,7 +264,7 @@ public class OneTimePermissionUserManager { private void updateUidState(int state) { Log.v(LOG_TAG, "Updating state for " + mPackageName + " (" + mUid + ")." - + " state=" + state); + + " device ID=" + mDeviceId + ", state=" + state); synchronized (mInnerLock) { // Remove any pending inactivity callback mHandler.removeCallbacksAndMessages(mToken); @@ -283,7 +287,7 @@ public class OneTimePermissionUserManager { if (DEBUG) { Log.d(LOG_TAG, "No longer gone after delayed revocation. " + "Rechecking for " + mPackageName + " (" + mUid - + ")."); + + "). device ID " + mDeviceId); } updateUidState(currentState); }, mToken, mRevokeAfterKilledDelay); @@ -292,7 +296,7 @@ public class OneTimePermissionUserManager { if (mTimerStart == TIMER_INACTIVE) { if (DEBUG) { Log.d(LOG_TAG, "Start the timer for " - + mPackageName + " (" + mUid + ")."); + + mPackageName + " (" + mUid + "). device ID " + mDeviceId); } mTimerStart = System.currentTimeMillis(); setAlarmLocked(); @@ -329,7 +333,8 @@ public class OneTimePermissionUserManager { } if (DEBUG) { - Log.d(LOG_TAG, "Scheduling alarm for " + mPackageName + " (" + mUid + ")."); + Log.d(LOG_TAG, "Scheduling alarm for " + mPackageName + " (" + mUid + ")." + + " device ID " + mDeviceId); } long revokeTime = mTimerStart + mTimeout; if (revokeTime > System.currentTimeMillis()) { @@ -349,7 +354,8 @@ public class OneTimePermissionUserManager { private void cancelAlarmLocked() { if (mIsAlarmSet) { if (DEBUG) { - Log.d(LOG_TAG, "Canceling alarm for " + mPackageName + " (" + mUid + ")."); + Log.d(LOG_TAG, "Canceling alarm for " + mPackageName + " (" + mUid + ")." + + " device ID " + mDeviceId); } mAlarmManager.cancel(this); mIsAlarmSet = false; @@ -366,17 +372,17 @@ public class OneTimePermissionUserManager { } if (DEBUG) { Log.d(LOG_TAG, "onPackageInactiveLocked stack trace for " - + mPackageName + " (" + mUid + ").", new RuntimeException()); + + mPackageName + " (" + mUid + "). device ID " + mDeviceId, + new RuntimeException()); } mIsFinished = true; cancelAlarmLocked(); mHandler.post( () -> { Log.i(LOG_TAG, "One time session expired for " - + mPackageName + " (" + mUid + ")."); - + + mPackageName + " (" + mUid + "). deviceID " + mDeviceId); mPermissionControllerManager.notifyOneTimePermissionSessionTimeout( - mPackageName); + mPackageName, mDeviceId); }); try { mIActivityManager.unregisterUidObserver(mObserver); @@ -391,7 +397,8 @@ public class OneTimePermissionUserManager { @Override public void onAlarm() { if (DEBUG) { - Log.d(LOG_TAG, "Alarm received for " + mPackageName + " (" + mUid + ")."); + Log.d(LOG_TAG, "Alarm received for " + mPackageName + " (" + mUid + ")." + + " device ID " + mDeviceId); } synchronized (mInnerLock) { if (!mIsAlarmSet) { diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 44eb28fc43f7..9610d051db95 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -404,15 +404,15 @@ public class PermissionManagerService extends IPermissionManager.Stub { @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) @Override - public void startOneTimePermissionSession(String packageName, @UserIdInt int userId, - long timeoutMillis, long revokeAfterKilledDelayMillis) { + public void startOneTimePermissionSession(String packageName, int deviceId, + @UserIdInt int userId, long timeoutMillis, long revokeAfterKilledDelayMillis) { startOneTimePermissionSession_enforcePermission(); Objects.requireNonNull(packageName); final long token = Binder.clearCallingIdentity(); try { getOneTimePermissionUserManager(userId).startPackageOneTimeSession(packageName, - timeoutMillis, revokeAfterKilledDelayMillis); + deviceId, timeoutMillis, revokeAfterKilledDelayMillis); } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt index b2733d4ddb50..240585c000fd 100644 --- a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt +++ b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt @@ -16,6 +16,7 @@ package com.android.server.permission.access.permission +import android.permission.PermissionManager import android.util.Slog import com.android.modules.utils.BinaryXmlPullParser import com.android.modules.utils.BinaryXmlSerializer @@ -164,9 +165,18 @@ class DevicePermissionPolicy : SchemePolicy() { deviceId: String, userId: Int, permissionName: String - ): Int = - state.userStates[userId]?.appIdDevicePermissionFlags?.get(appId)?.get(deviceId) - ?.getWithDefault(permissionName, 0) ?: 0 + ): Int { + val flags = state.userStates[userId]?.appIdDevicePermissionFlags?.get(appId)?.get(deviceId) + ?.getWithDefault(permissionName, 0) ?: 0 + if (PermissionManager.DEBUG_DEVICE_PERMISSIONS) { + Slog.i( + LOG_TAG, "getPermissionFlags: appId=$appId, userId=$userId," + + " deviceId=$deviceId, permissionName=$permissionName," + + " flags=${PermissionFlags.toString(flags)}" + ) + } + return flags + } fun MutateStateScope.setPermissionFlags( appId: Int, @@ -202,6 +212,13 @@ class DevicePermissionPolicy : SchemePolicy() { val devicePermissionFlags = appIdDevicePermissionFlags.mutateOrPut(appId) { MutableIndexedReferenceMap() } + if (PermissionManager.DEBUG_DEVICE_PERMISSIONS) { + Slog.i( + LOG_TAG, "setPermissionFlags(): appId=$appId, userId=$userId," + + " deviceId=$deviceId, permissionName=$permissionName," + + " newFlags=${PermissionFlags.toString(newFlags)}" + ) + } val permissionFlags = devicePermissionFlags.mutateOrPut(deviceId) { MutableIndexedMap() } permissionFlags.putWithDefault(permissionName, newFlags, 0) if (permissionFlags.isEmpty()) { |