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

Commit 48d0c57f authored by Vadim Caen's avatar Vadim Caen
Browse files

Check AppOp using noteOp instead os isOpActive

isOpActive is only true if startOp was called, which is not the case for
mediaprojection session.

Bug: 367301791
Test: com.android.server.media.projection.MediaProjectionManagerServiceTest#testCreateProjection_keyguardLocked_AppOpMediaProjection
Flag: android.companion.virtualdevice.flags.media_projection_keyguard_restrictions
Change-Id: I908ea1eabbb4e477f3849a6d05f498bfa7bd2099
parent 634d93a1
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
@@ -195,10 +195,9 @@ public final class MediaProjectionManagerService extends SystemService
                    == PackageManager.PERMISSION_GRANTED) {
                return true;
            }
            boolean operationActive = mAppOps.isOperationActive(AppOpsManager.OP_PROJECT_MEDIA,
                    mProjectionGrant.uid,
                    mProjectionGrant.packageName);
            if (operationActive) {
            if (AppOpsManager.MODE_ALLOWED == mAppOps.noteOpNoThrow(AppOpsManager.OP_PROJECT_MEDIA,
                    mProjectionGrant.uid, mProjectionGrant.packageName, /* attributionTag= */ null,
                    "recording lockscreen")) {
                // Some tools use media projection by granting the OP_PROJECT_MEDIA app
                // op via a shell command. Those tools can be granted keyguard capture
                return true;
+21 −5
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -91,6 +92,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
@@ -174,8 +176,8 @@ public class MediaProjectionManagerServiceTest {
    private PackageManager mPackageManager;
    @Mock
    private KeyguardManager mKeyguardManager;
    @Mock
    AppOpsManager mAppOpsManager;

    private AppOpsManager mAppOpsManager;
    @Mock
    private IMediaProjectionWatcherCallback mWatcherCallback;
    @Mock
@@ -193,6 +195,7 @@ public class MediaProjectionManagerServiceTest {
        LocalServices.removeServiceForTest(WindowManagerInternal.class);
        LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);

        mAppOpsManager = mockAppOpsManager();
        mContext.addMockSystemService(AppOpsManager.class, mAppOpsManager);
        mContext.addMockSystemService(KeyguardManager.class, mKeyguardManager);
        mContext.setMockPackageManager(mPackageManager);
@@ -206,6 +209,17 @@ public class MediaProjectionManagerServiceTest {
        mService = new MediaProjectionManagerService(mContext);
    }

    private static AppOpsManager mockAppOpsManager() {
        return mock(AppOpsManager.class, invocationOnMock -> {
            if (invocationOnMock.getMethod().getName().startsWith("noteOp")) {
                // Mockito will return 0 for non-stubbed method which corresponds to MODE_ALLOWED
                // and is not what we want.
                return AppOpsManager.MODE_IGNORED;
            }
            return Answers.RETURNS_DEFAULTS.answer(invocationOnMock);
        });
    }

    @After
    public void tearDown() {
        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
@@ -305,8 +319,10 @@ public class MediaProjectionManagerServiceTest {
    public void testCreateProjection_keyguardLocked_AppOpMediaProjection()
            throws NameNotFoundException {
        MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
        doReturn(true).when(mAppOpsManager).isOperationActive(eq(AppOpsManager.OP_PROJECT_MEDIA),
                eq(projection.uid), eq(projection.packageName));
        doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager)
                .noteOpNoThrow(eq(AppOpsManager.OP_PROJECT_MEDIA),
                        eq(projection.uid), eq(projection.packageName), nullable(String.class),
                        nullable(String.class));
        doReturn(true).when(mKeyguardManager).isKeyguardLocked();

        doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
@@ -1159,7 +1175,7 @@ public class MediaProjectionManagerServiceTest {
        doReturn(mAppInfo).when(mPackageManager).getApplicationInfoAsUser(anyString(),
                any(ApplicationInfoFlags.class), any(UserHandle.class));
        return service.createProjectionInternal(UID, PACKAGE_NAME,
                TYPE_MIRRORING, /* isPermanentGrant= */ true, UserHandle.CURRENT);
                TYPE_MIRRORING, /* isPermanentGrant= */ false, UserHandle.CURRENT);
    }

    // Set up preconditions for starting a projection, with no foreground service requirements.