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

Commit ae0d0731 authored by Vladimir Komsiyski's avatar Vladimir Komsiyski
Browse files

Clean up launched mediaProjectionKeyguardRestrictions flag

Fix the MP unit tests:
 - There's a duplicate one in StopControllerTest and ServiceTest
 - It doesn't need to properly acquire the role, a mock that the
   role is held is enough

#codehealth

Bug: 348335290
Test: presubmit
Flag: EXEMPT cleanup
Change-Id: I350f50164cb7843bcdd36693f0c0f99e3a31869c
parent ab4eafb6
Loading
Loading
Loading
Loading
+0 −7
Original line number Diff line number Diff line
@@ -17,13 +17,6 @@ flag {
     bug: "305170199"
}

flag {
     namespace: "virtual_devices"
     name: "media_projection_keyguard_restrictions"
     description: "Auto-stop MP when the device locks"
     bug: "348335290"
}

flag {
    namespace: "virtual_devices"
    name: "virtual_display_insets"
+21 −11
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.telecom.TelecomManager;
import android.telephony.TelephonyCallback;
@@ -38,6 +39,7 @@ import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.SystemConfig;

import java.util.List;
import java.util.function.Consumer;

/**
@@ -60,21 +62,35 @@ public class MediaProjectionStopController {
    private final TelephonyManager mTelephonyManager;
    private final AppOpsManager mAppOpsManager;
    private final PackageManager mPackageManager;
    private final RoleManager mRoleManager;
    private final RoleHolderProvider mRoleHolderProvider;
    private final ContentResolver mContentResolver;

    private boolean mIsInCall;
    private long mLastCallStartTimeMillis;


    @VisibleForTesting
    interface RoleHolderProvider {
        List<String> getRoleHoldersAsUser(String roleName, UserHandle user);
    }

    public MediaProjectionStopController(Context context, Consumer<Integer> stopReasonConsumer) {
        this(context, stopReasonConsumer,
                (roleName, user) -> context.getSystemService(RoleManager.class)
                        .getRoleHoldersAsUser(roleName, user));
    }

    @VisibleForTesting
    MediaProjectionStopController(Context context, Consumer<Integer> stopReasonConsumer,
            RoleHolderProvider roleHolderProvider) {
        mStopReasonConsumer = stopReasonConsumer;
        mKeyguardManager = context.getSystemService(KeyguardManager.class);
        mTelecomManager = context.getSystemService(TelecomManager.class);
        mTelephonyManager = context.getSystemService(TelephonyManager.class);
        mAppOpsManager = context.getSystemService(AppOpsManager.class);
        mPackageManager = context.getPackageManager();
        mRoleManager = context.getSystemService(RoleManager.class);
        mContentResolver = context.getContentResolver();
        mRoleHolderProvider = roleHolderProvider;
    }

    /**
@@ -146,8 +162,9 @@ public class MediaProjectionStopController {
            Slog.v(TAG, "Continuing MediaProjection for package with OP_PROJECT_MEDIA AppOp ");
            return true;
        }
        if (mRoleManager.getRoleHoldersAsUser(AssociationRequest.DEVICE_PROFILE_APP_STREAMING,
                projectionGrant.userHandle).contains(projectionGrant.packageName)) {
        if (mRoleHolderProvider.getRoleHoldersAsUser(
                AssociationRequest.DEVICE_PROFILE_APP_STREAMING, projectionGrant.userHandle)
                .contains(projectionGrant.packageName)) {
            Slog.v(TAG, "Continuing MediaProjection for package holding app streaming role.");
            return true;
        }
@@ -177,10 +194,6 @@ public class MediaProjectionStopController {
     */
    public boolean isStartForbidden(
            MediaProjectionManagerService.MediaProjection projectionGrant) {
        if (!android.companion.virtualdevice.flags.Flags.mediaProjectionKeyguardRestrictions()) {
            return false;
        }

        if (!mKeyguardManager.isKeyguardLocked()) {
            return false;
        }
@@ -194,9 +207,6 @@ public class MediaProjectionStopController {
    @VisibleForTesting
    void onKeyguardLockedStateChanged(boolean isKeyguardLocked) {
        if (!isKeyguardLocked) return;
        if (!android.companion.virtualdevice.flags.Flags.mediaProjectionKeyguardRestrictions()) {
            return;
        }
        mStopReasonConsumer.accept(STOP_REASON_KEYGUARD);
    }

+0 −107
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -53,15 +52,11 @@ import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions.LaunchCookie;
import android.app.AppOpsManager;
import android.app.Instrumentation;
import android.app.KeyguardManager;
import android.app.role.RoleManager;
import android.companion.AssociationRequest;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -76,11 +71,9 @@ import android.media.projection.StopReason;
import android.os.Binder;
import android.os.IBinder;
import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.test.TestLooper;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
@@ -99,7 +92,6 @@ import com.android.server.testutils.OffsettableClock;
import com.android.server.wm.WindowManagerInternal;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -110,7 +102,6 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

@@ -292,8 +283,6 @@ public class MediaProjectionManagerServiceTest {
        assertThat(stoppedCallback2).isFalse();
    }

    @EnableFlags(android.companion.virtualdevice.flags
            .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
    @Test
    public void testCreateProjection_keyguardLocked() throws Exception {
        MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
@@ -308,8 +297,6 @@ public class MediaProjectionManagerServiceTest {
        assertThat(mIMediaProjectionCallback.mLatch.await(5, TimeUnit.SECONDS)).isTrue();
    }

    @EnableFlags(android.companion.virtualdevice.flags
            .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
    @Test
    public void testCreateProjection_keyguardLocked_packageAllowlisted()
            throws NameNotFoundException {
@@ -325,8 +312,6 @@ public class MediaProjectionManagerServiceTest {
        assertThat(mService.getActiveProjectionInfo()).isNotNull();
    }

    @EnableFlags(android.companion.virtualdevice.flags
            .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
    @Test
    public void testCreateProjection_keyguardLocked_AppOpMediaProjection()
            throws NameNotFoundException {
@@ -347,50 +332,6 @@ public class MediaProjectionManagerServiceTest {
        assertThat(mService.getActiveProjectionInfo()).isNotNull();
    }

    @EnableFlags(android.companion.virtualdevice.flags
            .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
    @Test
    public void testCreateProjection_keyguardLocked_RoleHeld() {
        runWithRole(
                AssociationRequest.DEVICE_PROFILE_APP_STREAMING,
                () -> {
                    try {
                        mAppInfo.privateFlags |= PRIVATE_FLAG_PRIVILEGED;
                        doReturn(mAppInfo)
                                .when(mPackageManager)
                                .getApplicationInfoAsUser(
                                        anyString(),
                                        any(ApplicationInfoFlags.class),
                                        any(UserHandle.class));
                        MediaProjectionManagerService.MediaProjection projection =
                                mService.createProjectionInternal(
                                        Process.myUid(),
                                        mContext.getPackageName(),
                                        TYPE_MIRRORING,
                                        /* isPermanentGrant= */ false,
                                        UserHandle.CURRENT,
                                        DEFAULT_DISPLAY);
                        doReturn(true).when(mKeyguardManager).isKeyguardLocked();
                        doReturn(PackageManager.PERMISSION_DENIED)
                                .when(mPackageManager)
                                .checkPermission(RECORD_SENSITIVE_CONTENT, projection.packageName);

                        projection.start(mIMediaProjectionCallback);
                        projection.notifyVirtualDisplayCreated(10);

                        // The projection was started because it was allowed to capture the
                        // keyguard.
                        assertWithMessage("Failed to run projection")
                                .that(mService.getActiveProjectionInfo())
                                .isNotNull();
                    } catch (NameNotFoundException e) {
                        throw new RuntimeException(e);
                    }
                });
    }

    @EnableFlags(android.companion.virtualdevice.flags
            .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
    @Test
    public void testCreateProjection_keyguardLocked_screenshareProtectionsDisabled()
            throws NameNotFoundException {
@@ -416,8 +357,6 @@ public class MediaProjectionManagerServiceTest {
        }
    }

    @EnableFlags(android.companion.virtualdevice.flags
            .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
    @Test
    public void testCreateProjection_keyguardLocked_noDisplayCreated()
            throws NameNotFoundException {
@@ -509,8 +448,6 @@ public class MediaProjectionManagerServiceTest {
        assertThat(secondProjection).isNotEqualTo(projection);
    }

    @EnableFlags(android.companion.virtualdevice.flags
            .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
    @Test
    public void testReuseProjection_keyguardNotLocked_startConsentDialog()
            throws NameNotFoundException {
@@ -527,8 +464,6 @@ public class MediaProjectionManagerServiceTest {
        verify(mContext).startActivityAsUser(any(), any());
    }

    @EnableFlags(android.companion.virtualdevice.flags
            .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
    @Test
    public void testReuseProjection_keyguardLocked_noConsentDialog() throws NameNotFoundException {
        MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
@@ -1302,48 +1237,6 @@ public class MediaProjectionManagerServiceTest {
        return mService.getProjectionInternal(UID, PACKAGE_NAME);
    }

    /**
     * Run the provided block giving the current context's package the provided role.
     */
    @SuppressWarnings("SameParameterValue")
    private void runWithRole(String role, Runnable block) {
        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
        String packageName = mContext.getPackageName();
        UserHandle user = instrumentation.getTargetContext().getUser();
        RoleManager roleManager = Objects.requireNonNull(
                mContext.getSystemService(RoleManager.class));
        try {
            CountDownLatch latch = new CountDownLatch(1);
            instrumentation.getUiAutomation().adoptShellPermissionIdentity(
                    Manifest.permission.MANAGE_ROLE_HOLDERS,
                    Manifest.permission.BYPASS_ROLE_QUALIFICATION);

            roleManager.setBypassingRoleQualification(true);
            roleManager.addRoleHolderAsUser(role, packageName,
                    /* flags= */ RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user,
                    mContext.getMainExecutor(), success -> {
                        if (success) {
                            latch.countDown();
                        } else {
                            Assert.fail("Couldn't set role for test (failure) " + role);
                        }
                    });
            assertWithMessage("Couldn't set role for test (timeout) : " + role)
                    .that(latch.await(1, TimeUnit.SECONDS)).isTrue();
            block.run();

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            roleManager.removeRoleHolderAsUser(role, packageName,
                    /* flags= */ RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user,
                    mContext.getMainExecutor(), (aBool) -> {});
            roleManager.setBypassingRoleQualification(false);
            instrumentation.getUiAutomation()
                    .dropShellPermissionIdentity();
        }
    }

    private static class FakeIMediaProjectionCallback extends IMediaProjectionCallback.Stub {
        CountDownLatch mLatch = new CountDownLatch(1);
        @Override
+11 −75
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ import static android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_
import static android.view.Display.INVALID_DISPLAY;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -37,13 +36,10 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.Instrumentation;
import android.app.KeyguardManager;
import android.app.role.RoleManager;
import android.companion.AssociationRequest;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -69,7 +65,6 @@ import com.android.server.SystemConfig;
import com.android.server.wm.WindowManagerInternal;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -79,9 +74,7 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.List;
import java.util.function.Consumer;

/**
@@ -123,6 +116,8 @@ public class MediaProjectionStopControllerTest {
    private KeyguardManager mKeyguardManager;
    @Mock
    private TelecomManager mTelecomManager;
    @Mock
    private MediaProjectionStopController.RoleHolderProvider mRoleManager;

    private AppOpsManager mAppOpsManager;
    @Mock
@@ -145,7 +140,7 @@ public class MediaProjectionStopControllerTest {
        mContext.addMockSystemService(TelecomManager.class, mTelecomManager);
        mContext.setMockPackageManager(mPackageManager);

        mStopController = new MediaProjectionStopController(mContext, mStopConsumer);
        mStopController = new MediaProjectionStopController(mContext, mStopConsumer, mRoleManager);
        mService = new MediaProjectionManagerService(mContext,
                mMediaProjectionMetricsLoggerInjector);

@@ -170,8 +165,6 @@ public class MediaProjectionStopControllerTest {
    }

    @Test
    @EnableFlags(
            android.companion.virtualdevice.flags.Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
    public void testMediaProjectionNotRestricted() throws Exception {
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);

@@ -180,8 +173,6 @@ public class MediaProjectionStopControllerTest {
    }

    @Test
    @EnableFlags(
            android.companion.virtualdevice.flags.Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
    public void testMediaProjectionRestricted() throws Exception {
        MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
        mediaProjection.notifyVirtualDisplayCreated(1);
@@ -239,21 +230,13 @@ public class MediaProjectionStopControllerTest {

    @Test
    public void testExemptFromStoppingHasAppStreamingRole() throws Exception {
        runWithRole(
                AssociationRequest.DEVICE_PROFILE_APP_STREAMING,
                () -> {
                    try {
                        MediaProjectionManagerService.MediaProjection mediaProjection =
                                createMediaProjection();
                        doReturn(PackageManager.PERMISSION_DENIED).when(
                                mPackageManager).checkPermission(
        MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
        doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
                RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
        doReturn(List.of(mediaProjection.packageName)).when(mRoleManager).getRoleHoldersAsUser(
                eq(AssociationRequest.DEVICE_PROFILE_APP_STREAMING), any(UserHandle.class));
        assertThat(mStopController.isExemptFromStopping(mediaProjection,
                MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                });
    }

    @Test
@@ -316,8 +299,6 @@ public class MediaProjectionStopControllerTest {
    }

    @Test
    @EnableFlags(
            android.companion.virtualdevice.flags.Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
    public void testKeyguardLockedStateChanged_unlocked() {
        mStopController.onKeyguardLockedStateChanged(false);

@@ -325,8 +306,6 @@ public class MediaProjectionStopControllerTest {
    }

    @Test
    @EnableFlags(
            android.companion.virtualdevice.flags.Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
    public void testKeyguardLockedStateChanged_locked() {
        mStopController.onKeyguardLockedStateChanged(true);

@@ -438,47 +417,4 @@ public class MediaProjectionStopControllerTest {
                MediaProjectionManager.TYPE_SCREEN_CAPTURE, false, mContext.getUser(),
                INVALID_DISPLAY);
    }

    /**
     * Run the provided block giving the current context's package the provided role.
     */
    @SuppressWarnings("SameParameterValue")
    private void runWithRole(String role, Runnable block) {
        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
        String packageName = mContext.getPackageName();
        UserHandle user = instrumentation.getTargetContext().getUser();
        RoleManager roleManager = Objects.requireNonNull(
                mContext.getSystemService(RoleManager.class));
        try {
            CountDownLatch latch = new CountDownLatch(1);
            instrumentation.getUiAutomation().adoptShellPermissionIdentity(
                    Manifest.permission.MANAGE_ROLE_HOLDERS,
                    Manifest.permission.BYPASS_ROLE_QUALIFICATION);

            roleManager.setBypassingRoleQualification(true);
            roleManager.addRoleHolderAsUser(role, packageName,
                    /* flags= */ RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user,
                    mContext.getMainExecutor(), success -> {
                        if (success) {
                            latch.countDown();
                        } else {
                            Assert.fail("Couldn't set role for test (failure) " + role);
                        }
                    });
            assertWithMessage("Couldn't set role for test (timeout) : " + role)
                    .that(latch.await(1, TimeUnit.SECONDS)).isTrue();
            block.run();

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            roleManager.removeRoleHolderAsUser(role, packageName,
                    /* flags= */ RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user,
                    mContext.getMainExecutor(), (aBool) -> {
                    });
            roleManager.setBypassingRoleQualification(false);
            instrumentation.getUiAutomation()
                    .dropShellPermissionIdentity();
        }
    }
}