Add foreground check for controlling or requesting device state am: 50f9e8baef am: c7b3333690

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23121839

Change-Id: I077a6c8bdcf2b8bee836b2985fab002d5331d6ab
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Kevin Chyn
2023-05-12 02:06:38 +00:00
committed by Automerger Merge Worker

View File

@@ -17,6 +17,7 @@
package com.android.server.devicestate; package com.android.server.devicestate;
import static android.Manifest.permission.CONTROL_DEVICE_STATE; import static android.Manifest.permission.CONTROL_DEVICE_STATE;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE; import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE; import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE;
@@ -73,6 +74,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.WeakHashMap; import java.util.WeakHashMap;
@@ -162,7 +164,7 @@ public final class DeviceStateManagerService extends SystemService {
@GuardedBy("mLock") @GuardedBy("mLock")
private final SparseArray<ProcessRecord> mProcessRecords = new SparseArray<>(); private final SparseArray<ProcessRecord> mProcessRecords = new SparseArray<>();
private Set<Integer> mDeviceStatesAvailableForAppRequests; private Set<Integer> mDeviceStatesAvailableForAppRequests = new HashSet<>();
private Set<Integer> mFoldedDeviceStates; private Set<Integer> mFoldedDeviceStates;
@@ -879,8 +881,16 @@ public final class DeviceStateManagerService extends SystemService {
* @param callingPid Process ID that is requesting this state change * @param callingPid Process ID that is requesting this state change
* @param state state that is being requested. * @param state state that is being requested.
*/ */
private void assertCanRequestDeviceState(int callingPid, int state) { private void assertCanRequestDeviceState(int callingPid, int callingUid, int state) {
if (!isTopApp(callingPid) || !isStateAvailableForAppRequests(state)) { final boolean isTopApp = isTopApp(callingPid);
final boolean isForegroundApp = isForegroundApp(callingPid, callingUid);
final boolean isStateAvailableForAppRequests = isStateAvailableForAppRequests(state);
final boolean canRequestState = isTopApp
&& isForegroundApp
&& isStateAvailableForAppRequests;
if (!canRequestState) {
getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE, getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE,
"Permission required to request device state, " "Permission required to request device state, "
+ "or the call must come from the top app " + "or the call must come from the top app "
@@ -893,15 +903,43 @@ public final class DeviceStateManagerService extends SystemService {
* not the top app, then check if this process holds the CONTROL_DEVICE_STATE permission. * not the top app, then check if this process holds the CONTROL_DEVICE_STATE permission.
* *
* @param callingPid Process ID that is requesting this state change * @param callingPid Process ID that is requesting this state change
* @param callingUid UID that is requesting this state change
*/ */
private void assertCanControlDeviceState(int callingPid) { private void assertCanControlDeviceState(int callingPid, int callingUid) {
if (!isTopApp(callingPid)) { final boolean isTopApp = isTopApp(callingPid);
final boolean isForegroundApp = isForegroundApp(callingPid, callingUid);
final boolean canControlState = isTopApp && isForegroundApp;
if (!canControlState) {
getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE, getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE,
"Permission required to request device state, " "Permission required to request device state, "
+ "or the call must come from the top app."); + "or the call must come from the top app.");
} }
} }
/**
* Checks if the caller is in the foreground. Note that callers may be the top app as returned
* from {@link #isTopApp(int)}, but not be in the foreground. For example, keyguard may be on
* top of the top app.
*/
private boolean isForegroundApp(int callingPid, int callingUid) {
try {
final List<ActivityManager.RunningAppProcessInfo> procs =
ActivityManager.getService().getRunningAppProcesses();
for (int i = 0; i < procs.size(); i++) {
ActivityManager.RunningAppProcessInfo proc = procs.get(i);
if (proc.pid == callingPid && proc.uid == callingUid
&& proc.importance <= IMPORTANCE_FOREGROUND) {
return true;
}
}
} catch (RemoteException e) {
Slog.w(TAG, "am.getRunningAppProcesses() failed", e);
}
return false;
}
private boolean isTopApp(int callingPid) { private boolean isTopApp(int callingPid) {
final WindowProcessController topApp = mActivityTaskManagerInternal.getTopApp(); final WindowProcessController topApp = mActivityTaskManagerInternal.getTopApp();
return topApp != null && topApp.getPid() == callingPid; return topApp != null && topApp.getPid() == callingPid;
@@ -918,7 +956,6 @@ public final class DeviceStateManagerService extends SystemService {
*/ */
@GuardedBy("mLock") @GuardedBy("mLock")
private void readStatesAvailableForRequestFromApps() { private void readStatesAvailableForRequestFromApps() {
mDeviceStatesAvailableForAppRequests = new HashSet<>();
String[] availableAppStatesConfigIdentifiers = getContext().getResources() String[] availableAppStatesConfigIdentifiers = getContext().getResources()
.getStringArray(R.array.config_deviceStatesAvailableForAppRequests); .getStringArray(R.array.config_deviceStatesAvailableForAppRequests);
for (int i = 0; i < availableAppStatesConfigIdentifiers.length; i++) { for (int i = 0; i < availableAppStatesConfigIdentifiers.length; i++) {
@@ -1118,7 +1155,7 @@ public final class DeviceStateManagerService extends SystemService {
// Allow top processes to request a device state change // 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 // If the calling process ID is not the top app, then we check if this process
// holds a permission to CONTROL_DEVICE_STATE // holds a permission to CONTROL_DEVICE_STATE
assertCanRequestDeviceState(callingPid, state); assertCanRequestDeviceState(callingPid, callingUid, state);
if (token == null) { if (token == null) {
throw new IllegalArgumentException("Request token must not be null."); throw new IllegalArgumentException("Request token must not be null.");
@@ -1139,10 +1176,11 @@ public final class DeviceStateManagerService extends SystemService {
@Override // Binder call @Override // Binder call
public void cancelStateRequest() { public void cancelStateRequest() {
final int callingPid = Binder.getCallingPid(); final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
// Allow top processes to cancel a device state change // 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 // If the calling process ID is not the top app, then we check if this process
// holds a permission to CONTROL_DEVICE_STATE // holds a permission to CONTROL_DEVICE_STATE
assertCanControlDeviceState(callingPid); assertCanControlDeviceState(callingPid, callingUid);
final long callingIdentity = Binder.clearCallingIdentity(); final long callingIdentity = Binder.clearCallingIdentity();
try { try {