Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions core/java/android/provider/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -14127,6 +14127,32 @@ public static boolean putFloatForUser(ContentResolver cr, String name, float val
*/
public static final String DISABLE_SECURE_WINDOWS = "disable_secure_windows";

/**
* Whether user-initiated screenshots should capture secure windows.
*
* <p>When this setting is set to a non-zero value, screenshots capture content in windows
* with {@link android.view.WindowManager.LayoutParams#FLAG_SECURE}. Every other
* FLAG_SECURE behaviour, such as recents thumbnails and casting, is left unchanged.
*
* @hide
*/
public static final String FORCE_SCREENSHOT_SECURE_WINDOWS =
"force_screenshot_secure_windows";

/**
* Whether the built-in screen recorder should capture secure windows.
*
* <p>When this setting is set to a non-zero value, recordings started from the system
* screen recorder capture content in windows with
* {@link android.view.WindowManager.LayoutParams#FLAG_SECURE}. Recordings made by other
* apps through {@link android.media.projection.MediaProjection} are left unchanged, as is
* every other FLAG_SECURE behaviour.
*
* @hide
*/
public static final String FORCE_SCREEN_RECORD_SECURE_WINDOWS =
"force_screen_record_secure_windows";

/**
* Controls if the adaptive authentication feature should be disabled, which
* will attempt to lock the device after a number of consecutive authentication
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,8 @@ public class SettingsBackupTest {
Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
Settings.Secure.ENABLED_PRINT_SERVICES,
Settings.Secure.FORCE_SCREEN_RECORD_SECURE_WINDOWS,
Settings.Secure.FORCE_SCREENSHOT_SECURE_WINDOWS,
Settings.Secure.GLOBAL_ACTIONS_PANEL_AVAILABLE,
Settings.Secure.GLOBAL_ACTIONS_PANEL_DEBUG_ENABLED,
Settings.Secure.INCALL_BACK_BUTTON_BEHAVIOR,
Expand Down
1 change: 1 addition & 0 deletions packages/SystemUI/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT"/>
<uses-permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT"/>
<uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.RECORD_SENSITIVE_CONTENT"/>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.MediaStore;
import android.provider.Settings;
import android.text.format.DateUtils;
import android.util.DisplayMetrics;
import android.util.Log;
Expand Down Expand Up @@ -189,12 +190,16 @@ private void prepare() throws IOException, RemoteException, RuntimeException {
mMediaRecorder.prepare();
// Create surface
mInputSurface = mMediaRecorder.getSurface();
int displayFlags = DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
if (shouldCaptureSecureWindows()) {
displayFlags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
}
mVirtualDisplay = mMediaProjection.createVirtualDisplay(
"Recording Display",
videoParameters.mWidth,
videoParameters.mHeight,
metrics.densityDpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
displayFlags,
mInputSurface,
new VirtualDisplay.Callback() {
@Override
Expand All @@ -215,6 +220,11 @@ public void onStopped() {

}

private boolean shouldCaptureSecureWindows() {
return Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.FORCE_SCREEN_RECORD_SECURE_WINDOWS, 0) != 0;
}

/**
* Find the highest supported screen resolution and refresh rate for the given dimensions on
* this device, up to actual size and given rate.
Expand Down
31 changes: 28 additions & 3 deletions services/core/java/com/android/server/wm/WindowManagerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
import static android.view.flags.Flags.sensitiveContentAppProtection;
import static android.window.ScreenCapture.ScreenCaptureParams.CAPTURE_MODE_REQUIRE_OPTIMIZED;
import static android.window.ScreenCapture.ScreenCaptureParams.PROTECTED_CONTENT_POLICY_THROW_EXCEPTION;
import static android.window.ScreenCapture.ScreenCaptureParams.SECURE_CONTENT_POLICY_CAPTURE;
import static android.window.ScreenCapture.ScreenCaptureParams.SECURE_CONTENT_POLICY_THROW_EXCEPTION;
import static android.window.WindowProviderService.isWindowProviderService;

Expand Down Expand Up @@ -844,6 +845,8 @@ final class SettingsObserver extends ContentObserver {
Settings.Secure.getUriFor(Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS);
private final Uri mDisableSecureWindowsUri =
Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS);
private final Uri mForceScreenshotSecureWindowsUri =
Settings.Secure.getUriFor(Settings.Secure.FORCE_SCREENSHOT_SECURE_WINDOWS);
private final Uri mMagnifyImeEnabledUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MAGNIFY_NAV_AND_IME);
private final Uri mPolicyControlUri =
Expand Down Expand Up @@ -878,6 +881,8 @@ public SettingsObserver() {
UserHandle.USER_ALL);
resolver.registerContentObserver(mDisableSecureWindowsUri, false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(mForceScreenshotSecureWindowsUri, false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(mMagnifyImeEnabledUri, false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(mPolicyControlUri, false, this, UserHandle.USER_ALL);
Expand Down Expand Up @@ -941,6 +946,11 @@ public void onChange(boolean selfChange, Uri uri) {
return;
}

if (mForceScreenshotSecureWindowsUri.equals(uri)) {
updateForceScreenshotSecureWindows();
return;
}

if (mMagnifyImeEnabledUri.equals(uri)) {
updateMagnifyIme();
}
Expand Down Expand Up @@ -969,6 +979,7 @@ public void onChange(boolean selfChange, Uri uri) {
void loadSettings() {
updateMaximumObscuringOpacityForTouch();
updateDisableSecureWindows();
updateForceScreenshotSecureWindows();
updateMagnifyIme();
}

Expand Down Expand Up @@ -1079,6 +1090,15 @@ void updateDisableSecureWindows() {
}
}

void updateForceScreenshotSecureWindows() {
// Get the value of the current user. The Settings toggle writes the value to the
// user that changed it.
mForceScreenshotSecureWindows = Settings.Secure.getIntForUser(
mContext.getContentResolver(),
Settings.Secure.FORCE_SCREENSHOT_SECURE_WINDOWS, /* def= */ 0,
UserHandle.USER_CURRENT) != 0;
}

void updateMagnifyIme() {
boolean enabledMagnifyIme = Settings.Secure.getIntForUser(
mContext.getContentResolver(),
Expand Down Expand Up @@ -1284,6 +1304,7 @@ public void onAppTransitionFinishedLocked(IBinder token) {
private final ScreenRecordingCallbackController mScreenRecordingCallbackController;

private volatile boolean mDisableSecureWindows = false;
private volatile boolean mForceScreenshotSecureWindows = false;

/** Creates an instance of the WindowManagerService for the system server. */
public static WindowManagerService main(@NonNull final Context context,
Expand Down Expand Up @@ -11095,10 +11116,14 @@ ScreenCaptureInternal.LayerCaptureArgs getCaptureArgs(
}
}

return new ScreenCaptureInternal.LayerCaptureArgs.Builder(
final ScreenCaptureInternal.LayerCaptureArgs.Builder builder =
new ScreenCaptureInternal.LayerCaptureArgs.Builder(
displaySurfaceControl, captureArgs)
.setSourceCrop(mTmpRect)
.build();
.setSourceCrop(mTmpRect);
if (mForceScreenshotSecureWindows) {
builder.setSecureContentPolicy(SECURE_CONTENT_POLICY_CAPTURE);
}
return builder.build();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.ContentResolver;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
Expand Down Expand Up @@ -132,6 +133,7 @@
import android.window.ConfigurationChangeSetting;
import android.window.IDisplayEngagementModeCallback;
import android.window.InputTransferToken;
import android.window.ScreenCapture;
import android.window.ScreenCaptureInternal;
import android.window.WindowContainerToken;

Expand Down Expand Up @@ -1566,6 +1568,31 @@ public void testCaptureDisplay() {
assertEquals(validRect, resultingArgs.mSourceCrop);
}

@Test
public void testCaptureDisplay_forceScreenshotSecureWindows() {
Rect displayBounds = new Rect(0, 0, 100, 200);
spyOn(mDisplayContent);
when(mDisplayContent.getBounds()).thenReturn(displayBounds);
ContentResolver cr = useFakeSettingsProvider();

// secureContentPolicy should be REDACT (default) when setting is disabled
Settings.Secure.putInt(cr, Settings.Secure.FORCE_SCREENSHOT_SECURE_WINDOWS, 0);
mWm.mSettingsObserver.onChange(false,
Settings.Secure.getUriFor(Settings.Secure.FORCE_SCREENSHOT_SECURE_WINDOWS));
ScreenCaptureInternal.LayerCaptureArgs resultingArgs =
mWm.getCaptureArgs(DEFAULT_DISPLAY, null);
assertEquals(ScreenCapture.ScreenCaptureParams.SECURE_CONTENT_POLICY_REDACT,
resultingArgs.mSecureContentPolicy);

// secureContentPolicy should be CAPTURE when setting is enabled
Settings.Secure.putInt(cr, Settings.Secure.FORCE_SCREENSHOT_SECURE_WINDOWS, 1);
mWm.mSettingsObserver.onChange(false,
Settings.Secure.getUriFor(Settings.Secure.FORCE_SCREENSHOT_SECURE_WINDOWS));
resultingArgs = mWm.getCaptureArgs(DEFAULT_DISPLAY, null);
assertEquals(ScreenCapture.ScreenCaptureParams.SECURE_CONTENT_POLICY_CAPTURE,
resultingArgs.mSecureContentPolicy);
}

@Test
public void testGrantInputChannel_sanitizeSpyWindowForApplications() {
final Session session = mock(Session.class);
Expand Down