Merge changes from topic "top-focused-DevStMan" into sc-v2-dev am: c810e5c6dd

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

Change-Id: I353f3d5ff6c4ad4b3780cb729e62920d6eb2ce7f
This commit is contained in:
Kenneth Ford
2021-08-21 03:12:22 +00:00
committed by Automerger Merge Worker
4 changed files with 53 additions and 14 deletions

View File

@@ -1133,10 +1133,10 @@ package android.hardware.camera2 {
package android.hardware.devicestate { package android.hardware.devicestate {
public final class DeviceStateManager { public final class DeviceStateManager {
method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void cancelRequest(@NonNull android.hardware.devicestate.DeviceStateRequest); method @RequiresPermission(value=android.Manifest.permission.CONTROL_DEVICE_STATE, conditional=true) public void cancelRequest(@NonNull android.hardware.devicestate.DeviceStateRequest);
method @NonNull public int[] getSupportedStates(); method @NonNull public int[] getSupportedStates();
method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback); method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback);
method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void requestState(@NonNull android.hardware.devicestate.DeviceStateRequest, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.devicestate.DeviceStateRequest.Callback); method @RequiresPermission(value=android.Manifest.permission.CONTROL_DEVICE_STATE, conditional=true) public void requestState(@NonNull android.hardware.devicestate.DeviceStateRequest, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.devicestate.DeviceStateRequest.Callback);
method public void unregisterCallback(@NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback); method public void unregisterCallback(@NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback);
field public static final int MAXIMUM_DEVICE_STATE = 255; // 0xff field public static final int MAXIMUM_DEVICE_STATE = 255; // 0xff
field public static final int MINIMUM_DEVICE_STATE = 0; // 0x0 field public static final int MINIMUM_DEVICE_STATE = 0; // 0x0

View File

@@ -86,12 +86,13 @@ public final class DeviceStateManager {
* However, this behavior can be changed by setting flags on the {@link DeviceStateRequest}. * However, this behavior can be changed by setting flags on the {@link DeviceStateRequest}.
* *
* @throws IllegalArgumentException if the requested state is unsupported. * @throws IllegalArgumentException if the requested state is unsupported.
* @throws SecurityException if the {@link android.Manifest.permission#CONTROL_DEVICE_STATE} * @throws SecurityException if the caller is neither the current top-focused activity nor if
* permission is not held. * the {@link android.Manifest.permission#CONTROL_DEVICE_STATE} permission is held.
* *
* @see DeviceStateRequest * @see DeviceStateRequest
*/ */
@RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) @RequiresPermission(value = android.Manifest.permission.CONTROL_DEVICE_STATE,
conditional = true)
public void requestState(@NonNull DeviceStateRequest request, public void requestState(@NonNull DeviceStateRequest request,
@Nullable @CallbackExecutor Executor executor, @Nullable @CallbackExecutor Executor executor,
@Nullable DeviceStateRequest.Callback callback) { @Nullable DeviceStateRequest.Callback callback) {
@@ -105,10 +106,11 @@ public final class DeviceStateManager {
* This method is noop if the {@code request} has not been submitted with a call to * This method is noop if the {@code request} has not been submitted with a call to
* {@link #requestState(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}. * {@link #requestState(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}.
* *
* @throws SecurityException if the {@link android.Manifest.permission#CONTROL_DEVICE_STATE} * @throws SecurityException if the caller is neither the current top-focused activity nor if
* permission is not held. * the {@link android.Manifest.permission#CONTROL_DEVICE_STATE} permission is held.
*/ */
@RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) @RequiresPermission(value = android.Manifest.permission.CONTROL_DEVICE_STATE,
conditional = true)
public void cancelRequest(@NonNull DeviceStateRequest request) { public void cancelRequest(@NonNull DeviceStateRequest request) {
mGlobal.cancelRequest(request); mGlobal.cancelRequest(request);
} }

View File

@@ -48,9 +48,12 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils; import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
import com.android.server.ServiceThread; import com.android.server.ServiceThread;
import com.android.server.SystemService; import com.android.server.SystemService;
import com.android.server.policy.DeviceStatePolicyImpl; import com.android.server.policy.DeviceStatePolicyImpl;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowProcessController;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.PrintWriter; import java.io.PrintWriter;
@@ -101,6 +104,9 @@ public final class DeviceStateManagerService extends SystemService {
private final BinderService mBinderService; private final BinderService mBinderService;
@NonNull @NonNull
private final OverrideRequestController mOverrideRequestController; private final OverrideRequestController mOverrideRequestController;
@VisibleForTesting
@NonNull
public ActivityTaskManagerInternal mActivityTaskManagerInternal;
// All supported device states keyed by identifier. // All supported device states keyed by identifier.
@GuardedBy("mLock") @GuardedBy("mLock")
@@ -153,6 +159,7 @@ public final class DeviceStateManagerService extends SystemService {
mDeviceStatePolicy = policy; mDeviceStatePolicy = policy;
mDeviceStatePolicy.getDeviceStateProvider().setListener(new DeviceStateProviderListener()); mDeviceStatePolicy.getDeviceStateProvider().setListener(new DeviceStateProviderListener());
mBinderService = new BinderService(); mBinderService = new BinderService();
mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
} }
@Override @Override
@@ -778,14 +785,21 @@ public final class DeviceStateManagerService extends SystemService {
@Override // Binder call @Override // Binder call
public void requestState(IBinder token, int state, int flags) { public void requestState(IBinder token, int state, int flags) {
final int callingPid = Binder.getCallingPid();
// 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
final WindowProcessController topApp = mActivityTaskManagerInternal.getTopApp();
if (topApp.getPid() != callingPid) {
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 focused app.");
}
if (token == null) { if (token == null) {
throw new IllegalArgumentException("Request token must not be null."); throw new IllegalArgumentException("Request token must not be null.");
} }
final int callingPid = Binder.getCallingPid();
final long callingIdentity = Binder.clearCallingIdentity(); final long callingIdentity = Binder.clearCallingIdentity();
try { try {
requestStateInternal(state, flags, callingPid, token); requestStateInternal(state, flags, callingPid, token);
@@ -796,14 +810,21 @@ public final class DeviceStateManagerService extends SystemService {
@Override // Binder call @Override // Binder call
public void cancelRequest(IBinder token) { public void cancelRequest(IBinder token) {
final int callingPid = Binder.getCallingPid();
// 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
final WindowProcessController topApp = mActivityTaskManagerInternal.getTopApp();
if (topApp.getPid() != callingPid) {
getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE, getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE,
"Permission required to clear requested device state."); "Permission required to cancel device state, "
+ "or the call must come from the top focused app.");
}
if (token == null) { if (token == null) {
throw new IllegalArgumentException("Request token must not be null."); throw new IllegalArgumentException("Request token must not be null.");
} }
final int callingPid = Binder.getCallingPid();
final long callingIdentity = Binder.clearCallingIdentity(); final long callingIdentity = Binder.clearCallingIdentity();
try { try {
cancelRequestInternal(callingPid, token); cancelRequestInternal(callingPid, token);

View File

@@ -18,6 +18,7 @@ package com.android.server.devicestate;
import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE; import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNotNull;
@@ -35,6 +36,11 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry; import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4;
import static org.mockito.Mockito.mock;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowProcessController;
import junit.framework.Assert; import junit.framework.Assert;
import org.junit.Before; import org.junit.Before;
@@ -63,6 +69,8 @@ public final class DeviceStateManagerServiceTest {
private static final DeviceState UNSUPPORTED_DEVICE_STATE = private static final DeviceState UNSUPPORTED_DEVICE_STATE =
new DeviceState(255, "UNSUPPORTED", 0 /* flags */); new DeviceState(255, "UNSUPPORTED", 0 /* flags */);
private static final int FAKE_PROCESS_ID = 100;
private TestDeviceStatePolicy mPolicy; private TestDeviceStatePolicy mPolicy;
private TestDeviceStateProvider mProvider; private TestDeviceStateProvider mProvider;
private DeviceStateManagerService mService; private DeviceStateManagerService mService;
@@ -72,6 +80,14 @@ public final class DeviceStateManagerServiceTest {
mProvider = new TestDeviceStateProvider(); mProvider = new TestDeviceStateProvider();
mPolicy = new TestDeviceStatePolicy(mProvider); mPolicy = new TestDeviceStatePolicy(mProvider);
mService = new DeviceStateManagerService(InstrumentationRegistry.getContext(), mPolicy); mService = new DeviceStateManagerService(InstrumentationRegistry.getContext(), mPolicy);
// Necessary to allow us to check for top app process id in tests
mService.mActivityTaskManagerInternal = mock(ActivityTaskManagerInternal.class);
WindowProcessController windowProcessController = mock(WindowProcessController.class);
when(mService.mActivityTaskManagerInternal.getTopApp())
.thenReturn(windowProcessController);
when(windowProcessController.getPid()).thenReturn(FAKE_PROCESS_ID);
flushHandler(); // Flush the handler to ensure the initial values are committed. flushHandler(); // Flush the handler to ensure the initial values are committed.
} }