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

Commit 7afe8542 authored by Vladimir Komsiyski's avatar Vladimir Komsiyski Committed by Android (Google) Code Review
Browse files

Merge "Clean up launched mediaProjectionKeyguardRestrictions flag" into main

parents 02baf60e ae0d0731
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();
        }
    }
}