1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server; 18 19 import static android.view.flags.Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION; 20 21 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 22 23 import static com.google.common.truth.Truth.assertThat; 24 25 import static org.mockito.ArgumentMatchers.any; 26 import static org.mockito.Mockito.atLeast; 27 import static org.mockito.Mockito.never; 28 import static org.mockito.Mockito.verify; 29 30 import android.content.pm.PackageManagerInternal; 31 import android.media.projection.MediaProjectionInfo; 32 import android.media.projection.MediaProjectionManager; 33 import android.os.Binder; 34 import android.os.Process; 35 import android.platform.test.annotations.RequiresFlagsEnabled; 36 import android.platform.test.flag.junit.CheckFlagsRule; 37 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 38 import android.provider.Settings; 39 import android.testing.AndroidTestingRunner; 40 import android.testing.TestableContext; 41 import android.util.ArraySet; 42 43 import androidx.test.filters.SmallTest; 44 45 import com.android.server.wm.SensitiveContentPackages.PackageInfo; 46 import com.android.server.wm.WindowManagerInternal; 47 48 import org.junit.Before; 49 import org.junit.Rule; 50 import org.junit.Test; 51 import org.junit.runner.RunWith; 52 import org.mockito.ArgumentCaptor; 53 import org.mockito.Captor; 54 import org.mockito.Mock; 55 import org.mockito.MockitoAnnotations; 56 57 import java.util.Set; 58 59 @SmallTest 60 @RunWith(AndroidTestingRunner.class) 61 @RequiresFlagsEnabled(FLAG_SENSITIVE_CONTENT_APP_PROTECTION) 62 /** 63 * Test {@link SensitiveContentProtectionManagerService} for sensitive on screen content 64 * protection, the service protects sensitive content during screen share. 65 */ 66 public class SensitiveContentProtectionManagerServiceContentTest { 67 private final PackageInfo mPackageInfo = 68 new PackageInfo("test.package", 12345, new Binder()); 69 private final String mScreenRecorderPackage = "test.screen.recorder.package"; 70 private final String mExemptedScreenRecorderPackage = "test.exempted.screen.recorder.package"; 71 private SensitiveContentProtectionManagerService mSensitiveContentProtectionManagerService; 72 private MediaProjectionManager.Callback mMediaPorjectionCallback; 73 74 @Mock private WindowManagerInternal mWindowManager; 75 @Mock private MediaProjectionManager mProjectionManager; 76 @Mock private PackageManagerInternal mPackageManagerInternal; 77 private MediaProjectionInfo mMediaProjectionInfo; 78 79 @Captor 80 private ArgumentCaptor<MediaProjectionManager.Callback> mMediaProjectionCallbackCaptor; 81 @Captor 82 private ArgumentCaptor<ArraySet<PackageInfo>> mPackageInfoCaptor; 83 84 @Rule 85 public final TestableContext mContext = 86 new TestableContext(getInstrumentation().getTargetContext(), null); 87 @Rule 88 public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); 89 90 @Before setUp()91 public void setUp() { 92 MockitoAnnotations.initMocks(this); 93 mSensitiveContentProtectionManagerService = 94 new SensitiveContentProtectionManagerService(mContext); 95 mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager, 96 mPackageManagerInternal, new ArraySet<>(Set.of(mExemptedScreenRecorderPackage))); 97 verify(mProjectionManager).addCallback(mMediaProjectionCallbackCaptor.capture(), any()); 98 mMediaPorjectionCallback = mMediaProjectionCallbackCaptor.getValue(); 99 mMediaProjectionInfo = 100 new MediaProjectionInfo(mScreenRecorderPackage, Process.myUserHandle(), null); 101 } 102 103 @Test testExemptedRecorderPackageForScreenCapture()104 public void testExemptedRecorderPackageForScreenCapture() { 105 MediaProjectionInfo exemptedRecorderPackage = new MediaProjectionInfo( 106 mExemptedScreenRecorderPackage, Process.myUserHandle(), null); 107 mMediaPorjectionCallback.onStart(exemptedRecorderPackage); 108 mSensitiveContentProtectionManagerService.setSensitiveContentProtection( 109 mPackageInfo.getWindowToken(), mPackageInfo.getPkg(), mPackageInfo.getUid(), true); 110 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 111 } 112 113 @Test testBlockAppWindowForScreenCapture()114 public void testBlockAppWindowForScreenCapture() { 115 mMediaPorjectionCallback.onStart(mMediaProjectionInfo); 116 mSensitiveContentProtectionManagerService.setSensitiveContentProtection( 117 mPackageInfo.getWindowToken(), mPackageInfo.getPkg(), mPackageInfo.getUid(), true); 118 verify(mWindowManager, atLeast(1)) 119 .addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 120 assertThat(mPackageInfoCaptor.getValue()).containsExactly(mPackageInfo); 121 } 122 123 @Test testUnblockAppWindowForScreenCapture()124 public void testUnblockAppWindowForScreenCapture() { 125 mMediaPorjectionCallback.onStart(mMediaProjectionInfo); 126 mSensitiveContentProtectionManagerService.setSensitiveContentProtection( 127 mPackageInfo.getWindowToken(), mPackageInfo.getPkg(), mPackageInfo.getUid(), false); 128 verify(mWindowManager).removeBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 129 assertThat(mPackageInfoCaptor.getValue()).containsExactly(mPackageInfo); 130 } 131 132 @Test testAppWindowIsUnblockedBeforeScreenCapture()133 public void testAppWindowIsUnblockedBeforeScreenCapture() { 134 // when screen sharing is not active, no app window should be blocked. 135 mSensitiveContentProtectionManagerService.setSensitiveContentProtection( 136 mPackageInfo.getWindowToken(), mPackageInfo.getPkg(), mPackageInfo.getUid(), true); 137 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 138 } 139 140 @Test testAppWindowsAreUnblockedOnScreenCaptureEnd()141 public void testAppWindowsAreUnblockedOnScreenCaptureEnd() { 142 mMediaPorjectionCallback.onStart(mMediaProjectionInfo); 143 mSensitiveContentProtectionManagerService.setSensitiveContentProtection( 144 mPackageInfo.getWindowToken(), mPackageInfo.getPkg(), mPackageInfo.getUid(), true); 145 // when screen sharing ends, all blocked app windows should be cleared. 146 mMediaPorjectionCallback.onStop(mMediaProjectionInfo); 147 verify(mWindowManager).clearBlockedApps(); 148 } 149 150 @Test testAutofillServicePackageExemption()151 public void testAutofillServicePackageExemption() { 152 String testAutofillService = mScreenRecorderPackage + "/com.example.SampleAutofillService"; 153 int userId = Process.myUserHandle().getIdentifier(); 154 Settings.Secure.putStringForUser(mContext.getContentResolver(), 155 Settings.Secure.AUTOFILL_SERVICE, testAutofillService , userId); 156 157 mMediaPorjectionCallback.onStart(mMediaProjectionInfo); 158 mSensitiveContentProtectionManagerService.setSensitiveContentProtection( 159 mPackageInfo.getWindowToken(), mPackageInfo.getPkg(), mPackageInfo.getUid(), true); 160 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 161 } 162 163 @Test testDeveloperOptionDisableFeature()164 public void testDeveloperOptionDisableFeature() { 165 mockDisabledViaDeveloperOption(); 166 mMediaProjectionCallbackCaptor.getValue().onStart(mMediaProjectionInfo); 167 mSensitiveContentProtectionManagerService.setSensitiveContentProtection( 168 mPackageInfo.getWindowToken(), mPackageInfo.getPkg(), mPackageInfo.getUid(), true); 169 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 170 } 171 mockDisabledViaDeveloperOption()172 private void mockDisabledViaDeveloperOption() { 173 Settings.Global.putInt( 174 mContext.getContentResolver(), 175 Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 176 1); 177 } 178 } 179