Loading core/java/android/hardware/devicestate/feature/flags.aconfig +12 −0 Original line number Diff line number Diff line Loading @@ -18,3 +18,15 @@ flag { bug: "336640888" is_fixed_read_only: true } flag { name: "device_state_requester_cancel_state" is_exported: true namespace: "windowing_sdk" description: "Removes foreground requirement if process attempting to cancel a state request is the requester" bug: "354772125" is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } } No newline at end of file services/core/java/com/android/server/devicestate/DeviceStateManagerService.java +35 −20 Original line number Diff line number Diff line Loading @@ -50,8 +50,7 @@ import android.hardware.devicestate.DeviceStateManager; import android.hardware.devicestate.DeviceStateManagerInternal; import android.hardware.devicestate.IDeviceStateManager; import android.hardware.devicestate.IDeviceStateManagerCallback; import android.hardware.devicestate.feature.flags.FeatureFlags; import android.hardware.devicestate.feature.flags.FeatureFlagsImpl; import android.hardware.devicestate.feature.flags.Flags; import android.os.Binder; import android.os.Handler; import android.os.IBinder; Loading Loading @@ -190,9 +189,6 @@ public final class DeviceStateManagerService extends SystemService { @Nullable private OverrideRequest mRearDisplayPendingOverrideRequest; @NonNull private final FeatureFlags mFlags; @VisibleForTesting interface SystemPropertySetter { void setDebugTracingDeviceStateProperty(String value); Loading Loading @@ -253,7 +249,6 @@ public final class DeviceStateManagerService extends SystemService { @NonNull SystemPropertySetter systemPropertySetter) { super(context); mSystemPropertySetter = systemPropertySetter; mFlags = new FeatureFlagsImpl(); // We use the DisplayThread because this service indirectly drives // display (on/off) and window (position) events through its callbacks. DisplayThread displayThread = DisplayThread.get(); Loading @@ -279,7 +274,7 @@ public final class DeviceStateManagerService extends SystemService { publishBinderService(Context.DEVICE_STATE_SERVICE, mBinderService); publishLocalService(DeviceStateManagerInternal.class, new LocalService()); if (!mFlags.deviceStatePropertyMigration()) { if (!Flags.deviceStatePropertyMigration()) { synchronized (mLock) { readStatesAvailableForRequestFromApps(); mFoldedDeviceStates = readFoldedStates(); Loading Loading @@ -848,7 +843,7 @@ public final class DeviceStateManagerService extends SystemService { OverrideRequest request = new OverrideRequest(token, callingPid, callingUid, deviceState.get(), flags, OVERRIDE_REQUEST_TYPE_EMULATED_STATE); if (mFlags.deviceStatePropertyMigration()) { if (Flags.deviceStatePropertyMigration()) { // If we don't have the CONTROL_DEVICE_STATE permission, we want to show the overlay if (!hasControlDeviceStatePermission && deviceState.get().hasProperty( PROPERTY_FEATURE_REAR_DISPLAY)) { Loading Loading @@ -988,16 +983,16 @@ public final class DeviceStateManagerService extends SystemService { * @param callingPid Process ID that is requesting this state change * @param state state that is being requested. */ private void assertCanRequestDeviceState(int callingPid, int callingUid, int state) { private void enforceRequestDeviceStatePermitted(int callingPid, int callingUid, int state) { final boolean isTopApp = isTopApp(callingPid); final boolean isForegroundApp = isForegroundApp(callingPid, callingUid); final boolean isStateAvailableForAppRequests = isStateAvailableForAppRequests(state); final boolean canRequestState = isTopApp final boolean isAllowedToRequestState = isTopApp && isForegroundApp && isStateAvailableForAppRequests; if (!canRequestState) { if (!isAllowedToRequestState) { getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE, "Permission required to request device state, " + "or the call must come from the top app " Loading @@ -1006,19 +1001,29 @@ public final class DeviceStateManagerService extends SystemService { } /** * Checks if the process can control the device state. If the calling process ID is * not the top app, then check if this process holds the CONTROL_DEVICE_STATE permission. * Checks if the process can cancel a device state request. If the calling process ID is not * both the top app and foregrounded nor does the process ID and userID match the IDs that made * the device state request, then check if this process holds the CONTROL_DEVICE_STATE * permission. * * @param callingPid Process ID that is requesting this state change * @param callingUid UID that is requesting this state change */ private void assertCanControlDeviceState(int callingPid, int callingUid) { private void enforceCancelDeviceStatePermitted(int callingPid, int callingUid) { final boolean isTopApp = isTopApp(callingPid); final boolean isForegroundApp = isForegroundApp(callingPid, callingUid); final boolean canControlState = isTopApp && isForegroundApp; boolean isAllowedToControlState = isTopApp && isForegroundApp; if (Flags.deviceStateRequesterCancelState()) { synchronized (mLock) { isAllowedToControlState = isAllowedToControlState || doCallingIdsMatchOverrideRequestIdsLocked( callingPid, callingUid); } } if (!canControlState) { if (!isAllowedToControlState) { getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE, "Permission required to request device state, " + "or the call must come from the top app."); Loading Loading @@ -1052,9 +1057,19 @@ public final class DeviceStateManagerService extends SystemService { return topApp != null && topApp.getPid() == callingPid; } /** * Returns if the provided {@code callingPid} and {@code callingUid} match the same id's that * requested the current device state override. */ @GuardedBy("mLock") private boolean doCallingIdsMatchOverrideRequestIdsLocked(int callingPid, int callingUid) { OverrideRequest request = mActiveOverride.orElse(null); return request != null && request.getPid() == callingPid && request.getUid() == callingUid; } private boolean isStateAvailableForAppRequests(int state) { synchronized (mLock) { if (mFlags.deviceStatePropertyMigration()) { if (Flags.deviceStatePropertyMigration()) { Optional<DeviceState> deviceState = getStateLocked(state); return deviceState.isPresent() && deviceState.get().hasProperty( PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST); Loading Loading @@ -1122,7 +1137,7 @@ public final class DeviceStateManagerService extends SystemService { */ @GuardedBy("mLock") private boolean isDeviceOpeningLocked(int newBaseState) { if (mFlags.deviceStatePropertyMigration()) { if (Flags.deviceStatePropertyMigration()) { final DeviceState currentBaseState = mBaseState.orElse(INVALID_DEVICE_STATE); final DeviceState newDeviceBaseState = getStateLocked(newBaseState).orElse( INVALID_DEVICE_STATE); Loading Loading @@ -1293,7 +1308,7 @@ public final class DeviceStateManagerService extends SystemService { // Allow top processes to request a device state change // If the calling process ID is not the top app, then we check if this process // holds a permission to CONTROL_DEVICE_STATE assertCanRequestDeviceState(callingPid, callingUid, state); enforceRequestDeviceStatePermitted(callingPid, callingUid, state); if (token == null) { throw new IllegalArgumentException("Request token must not be null."); Loading @@ -1318,7 +1333,7 @@ public final class DeviceStateManagerService extends SystemService { // Allow top processes to cancel a device state change // If the calling process ID is not the top app, then we check if this process // holds a permission to CONTROL_DEVICE_STATE assertCanControlDeviceState(callingPid, callingUid); enforceCancelDeviceStatePermitted(callingPid, callingUid); final long callingIdentity = Binder.clearCallingIdentity(); try { Loading Loading
core/java/android/hardware/devicestate/feature/flags.aconfig +12 −0 Original line number Diff line number Diff line Loading @@ -18,3 +18,15 @@ flag { bug: "336640888" is_fixed_read_only: true } flag { name: "device_state_requester_cancel_state" is_exported: true namespace: "windowing_sdk" description: "Removes foreground requirement if process attempting to cancel a state request is the requester" bug: "354772125" is_fixed_read_only: true metadata { purpose: PURPOSE_BUGFIX } } No newline at end of file
services/core/java/com/android/server/devicestate/DeviceStateManagerService.java +35 −20 Original line number Diff line number Diff line Loading @@ -50,8 +50,7 @@ import android.hardware.devicestate.DeviceStateManager; import android.hardware.devicestate.DeviceStateManagerInternal; import android.hardware.devicestate.IDeviceStateManager; import android.hardware.devicestate.IDeviceStateManagerCallback; import android.hardware.devicestate.feature.flags.FeatureFlags; import android.hardware.devicestate.feature.flags.FeatureFlagsImpl; import android.hardware.devicestate.feature.flags.Flags; import android.os.Binder; import android.os.Handler; import android.os.IBinder; Loading Loading @@ -190,9 +189,6 @@ public final class DeviceStateManagerService extends SystemService { @Nullable private OverrideRequest mRearDisplayPendingOverrideRequest; @NonNull private final FeatureFlags mFlags; @VisibleForTesting interface SystemPropertySetter { void setDebugTracingDeviceStateProperty(String value); Loading Loading @@ -253,7 +249,6 @@ public final class DeviceStateManagerService extends SystemService { @NonNull SystemPropertySetter systemPropertySetter) { super(context); mSystemPropertySetter = systemPropertySetter; mFlags = new FeatureFlagsImpl(); // We use the DisplayThread because this service indirectly drives // display (on/off) and window (position) events through its callbacks. DisplayThread displayThread = DisplayThread.get(); Loading @@ -279,7 +274,7 @@ public final class DeviceStateManagerService extends SystemService { publishBinderService(Context.DEVICE_STATE_SERVICE, mBinderService); publishLocalService(DeviceStateManagerInternal.class, new LocalService()); if (!mFlags.deviceStatePropertyMigration()) { if (!Flags.deviceStatePropertyMigration()) { synchronized (mLock) { readStatesAvailableForRequestFromApps(); mFoldedDeviceStates = readFoldedStates(); Loading Loading @@ -848,7 +843,7 @@ public final class DeviceStateManagerService extends SystemService { OverrideRequest request = new OverrideRequest(token, callingPid, callingUid, deviceState.get(), flags, OVERRIDE_REQUEST_TYPE_EMULATED_STATE); if (mFlags.deviceStatePropertyMigration()) { if (Flags.deviceStatePropertyMigration()) { // If we don't have the CONTROL_DEVICE_STATE permission, we want to show the overlay if (!hasControlDeviceStatePermission && deviceState.get().hasProperty( PROPERTY_FEATURE_REAR_DISPLAY)) { Loading Loading @@ -988,16 +983,16 @@ public final class DeviceStateManagerService extends SystemService { * @param callingPid Process ID that is requesting this state change * @param state state that is being requested. */ private void assertCanRequestDeviceState(int callingPid, int callingUid, int state) { private void enforceRequestDeviceStatePermitted(int callingPid, int callingUid, int state) { final boolean isTopApp = isTopApp(callingPid); final boolean isForegroundApp = isForegroundApp(callingPid, callingUid); final boolean isStateAvailableForAppRequests = isStateAvailableForAppRequests(state); final boolean canRequestState = isTopApp final boolean isAllowedToRequestState = isTopApp && isForegroundApp && isStateAvailableForAppRequests; if (!canRequestState) { if (!isAllowedToRequestState) { getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE, "Permission required to request device state, " + "or the call must come from the top app " Loading @@ -1006,19 +1001,29 @@ public final class DeviceStateManagerService extends SystemService { } /** * Checks if the process can control the device state. If the calling process ID is * not the top app, then check if this process holds the CONTROL_DEVICE_STATE permission. * Checks if the process can cancel a device state request. If the calling process ID is not * both the top app and foregrounded nor does the process ID and userID match the IDs that made * the device state request, then check if this process holds the CONTROL_DEVICE_STATE * permission. * * @param callingPid Process ID that is requesting this state change * @param callingUid UID that is requesting this state change */ private void assertCanControlDeviceState(int callingPid, int callingUid) { private void enforceCancelDeviceStatePermitted(int callingPid, int callingUid) { final boolean isTopApp = isTopApp(callingPid); final boolean isForegroundApp = isForegroundApp(callingPid, callingUid); final boolean canControlState = isTopApp && isForegroundApp; boolean isAllowedToControlState = isTopApp && isForegroundApp; if (Flags.deviceStateRequesterCancelState()) { synchronized (mLock) { isAllowedToControlState = isAllowedToControlState || doCallingIdsMatchOverrideRequestIdsLocked( callingPid, callingUid); } } if (!canControlState) { if (!isAllowedToControlState) { getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE, "Permission required to request device state, " + "or the call must come from the top app."); Loading Loading @@ -1052,9 +1057,19 @@ public final class DeviceStateManagerService extends SystemService { return topApp != null && topApp.getPid() == callingPid; } /** * Returns if the provided {@code callingPid} and {@code callingUid} match the same id's that * requested the current device state override. */ @GuardedBy("mLock") private boolean doCallingIdsMatchOverrideRequestIdsLocked(int callingPid, int callingUid) { OverrideRequest request = mActiveOverride.orElse(null); return request != null && request.getPid() == callingPid && request.getUid() == callingUid; } private boolean isStateAvailableForAppRequests(int state) { synchronized (mLock) { if (mFlags.deviceStatePropertyMigration()) { if (Flags.deviceStatePropertyMigration()) { Optional<DeviceState> deviceState = getStateLocked(state); return deviceState.isPresent() && deviceState.get().hasProperty( PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST); Loading Loading @@ -1122,7 +1137,7 @@ public final class DeviceStateManagerService extends SystemService { */ @GuardedBy("mLock") private boolean isDeviceOpeningLocked(int newBaseState) { if (mFlags.deviceStatePropertyMigration()) { if (Flags.deviceStatePropertyMigration()) { final DeviceState currentBaseState = mBaseState.orElse(INVALID_DEVICE_STATE); final DeviceState newDeviceBaseState = getStateLocked(newBaseState).orElse( INVALID_DEVICE_STATE); Loading Loading @@ -1293,7 +1308,7 @@ public final class DeviceStateManagerService extends SystemService { // Allow top processes to request a device state change // If the calling process ID is not the top app, then we check if this process // holds a permission to CONTROL_DEVICE_STATE assertCanRequestDeviceState(callingPid, callingUid, state); enforceRequestDeviceStatePermitted(callingPid, callingUid, state); if (token == null) { throw new IllegalArgumentException("Request token must not be null."); Loading @@ -1318,7 +1333,7 @@ public final class DeviceStateManagerService extends SystemService { // Allow top processes to cancel a device state change // If the calling process ID is not the top app, then we check if this process // holds a permission to CONTROL_DEVICE_STATE assertCanControlDeviceState(callingPid, callingUid); enforceCancelDeviceStatePermitted(callingPid, callingUid); final long callingIdentity = Binder.clearCallingIdentity(); try { Loading