Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1f70abe9 authored by Kenneth Ford's avatar Kenneth Ford
Browse files

Allow top focused activities to call requestState

Previously you could only modify the device state
if you held the CONTROL_DEVICE_STATE permission. This
change allows top focused activities to do the same

Bug: 192671754
Test: atest DeviceStateManagerTests
Change-Id: Iba0c1800a1fb17024020e657b76a54eec9c89348
parent 7dde391f
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1133,10 +1133,10 @@ package android.hardware.camera2 {
package android.hardware.devicestate {

  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 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);
    field public static final int MAXIMUM_DEVICE_STATE = 255; // 0xff
    field public static final int MINIMUM_DEVICE_STATE = 0; // 0x0
+8 −6
Original line number Diff line number Diff line
@@ -86,12 +86,13 @@ public final class DeviceStateManager {
     * However, this behavior can be changed by setting flags on the {@link DeviceStateRequest}.
     *
     * @throws IllegalArgumentException if the requested state is unsupported.
     * @throws SecurityException if the {@link android.Manifest.permission#CONTROL_DEVICE_STATE}
     * permission is not held.
     * @throws SecurityException if the caller is neither the current top-focused activity nor if
     * the {@link android.Manifest.permission#CONTROL_DEVICE_STATE} permission is held.
     *
     * @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,
            @Nullable @CallbackExecutor Executor executor,
            @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
     * {@link #requestState(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}.
     *
     * @throws SecurityException if the {@link android.Manifest.permission#CONTROL_DEVICE_STATE}
     * permission is not held.
     * @throws SecurityException if the caller is neither the current top-focused activity nor if
     * 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) {
        mGlobal.cancelRequest(request);
    }
+27 −6
Original line number Diff line number Diff line
@@ -48,9 +48,12 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
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.PrintWriter;
@@ -101,6 +104,9 @@ public final class DeviceStateManagerService extends SystemService {
    private final BinderService mBinderService;
    @NonNull
    private final OverrideRequestController mOverrideRequestController;
    @VisibleForTesting
    @NonNull
    public ActivityTaskManagerInternal mActivityTaskManagerInternal;

    // All supported device states keyed by identifier.
    @GuardedBy("mLock")
@@ -153,6 +159,7 @@ public final class DeviceStateManagerService extends SystemService {
        mDeviceStatePolicy = policy;
        mDeviceStatePolicy.getDeviceStateProvider().setListener(new DeviceStateProviderListener());
        mBinderService = new BinderService();
        mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
    }

    @Override
@@ -778,14 +785,21 @@ public final class DeviceStateManagerService extends SystemService {

        @Override // Binder call
        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,
                    "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) {
                throw new IllegalArgumentException("Request token must not be null.");
            }

            final int callingPid = Binder.getCallingPid();
            final long callingIdentity = Binder.clearCallingIdentity();
            try {
                requestStateInternal(state, flags, callingPid, token);
@@ -796,14 +810,21 @@ public final class DeviceStateManagerService extends SystemService {

        @Override // Binder call
        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,
                    "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) {
                throw new IllegalArgumentException("Request token must not be null.");
            }

            final int callingPid = Binder.getCallingPid();
            final long callingIdentity = Binder.clearCallingIdentity();
            try {
                cancelRequestInternal(callingPid, token);
+16 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.devicestate;

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.assertFalse;
import static org.testng.Assert.assertNotNull;
@@ -35,6 +36,11 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry;
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 org.junit.Before;
@@ -63,6 +69,8 @@ public final class DeviceStateManagerServiceTest {
    private static final DeviceState UNSUPPORTED_DEVICE_STATE =
            new DeviceState(255, "UNSUPPORTED", 0 /* flags */);

    private static final int FAKE_PROCESS_ID = 100;

    private TestDeviceStatePolicy mPolicy;
    private TestDeviceStateProvider mProvider;
    private DeviceStateManagerService mService;
@@ -72,6 +80,14 @@ public final class DeviceStateManagerServiceTest {
        mProvider = new TestDeviceStateProvider();
        mPolicy = new TestDeviceStatePolicy(mProvider);
        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.
    }