summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author mrulhania <mrulhania@google.com> 2024-02-10 13:16:42 -0800
committer mrulhania <mrulhania@google.com> 2024-02-22 12:31:51 -0800
commita296a14c0ff5f8900f6616eddee7f6d5c7c9f9f9 (patch)
treeccf3bd6cd12f70ee0db3aaa9b9cced941e655ca5
parent5190facc795974ed4477ea4a32442d7e3d4bd10a (diff)
Add sensitive content protection during screen share
If a view is deemed sensitive either by system heuristics or explicitly set by the developer, The window would be blocked from being projected (screen share) until it has a sensitive view attached. Bug: 324348549 Test: CtsSensitiveContentProtectionTestCases Change-Id: I22abdbe487793e88b6ab6375f6a1f2e1f3407b03
-rw-r--r--core/java/android/view/View.java106
-rw-r--r--core/java/android/view/ViewRootImpl.java34
2 files changed, 139 insertions, 1 deletions
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 028448ccf871..a83f20be6f43 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -35,6 +35,7 @@ import static android.view.flags.Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API
import static android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY;
import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API;
import static android.view.flags.Flags.enableUseMeasureCacheDuringForceLayout;
+import static android.view.flags.Flags.sensitiveContentAppProtection;
import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision;
import static android.view.flags.Flags.toolkitSetFrameRateReadOnly;
import static android.view.flags.Flags.viewVelocityApi;
@@ -132,6 +133,7 @@ import android.os.vibrator.Flags;
import android.sysprop.DisplayProperties;
import android.text.InputType;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.FloatProperty;
@@ -3695,6 +3697,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* 1 PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT
* 1 PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT
* 11 PFLAG4_CONTENT_SENSITIVITY_MASK
+ * 1 PFLAG4_IS_COUNTED_AS_SENSITIVE
* |-------|-------|-------|-------|
*/
@@ -3820,6 +3823,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private static final int PFLAG4_CONTENT_SENSITIVITY_MASK =
(CONTENT_SENSITIVITY_AUTO | CONTENT_SENSITIVITY_SENSITIVE
| CONTENT_SENSITIVITY_NOT_SENSITIVE) << PFLAG4_CONTENT_SENSITIVITY_SHIFT;
+
+ /**
+ * Whether this view has been counted as a sensitive view or not.
+ *
+ * @see AttachInfo#mSensitiveViewsCount
+ */
+ private static final int PFLAG4_IS_COUNTED_AS_SENSITIVE = 0x4000000;
/* End of masks for mPrivateFlags4 */
/** @hide */
@@ -10369,6 +10379,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags4 &= ~PFLAG4_CONTENT_SENSITIVITY_MASK;
mPrivateFlags4 |= ((mode << PFLAG4_CONTENT_SENSITIVITY_SHIFT)
& PFLAG4_CONTENT_SENSITIVITY_MASK);
+ if (sensitiveContentAppProtection()) {
+ updateSensitiveViewsCountIfNeeded(isAggregatedVisible());
+ }
}
/**
@@ -10400,13 +10413,44 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API)
public final boolean isContentSensitive() {
- if (getContentSensitivity() == CONTENT_SENSITIVITY_SENSITIVE) {
+ final int contentSensitivity = getContentSensitivity();
+ if (contentSensitivity == CONTENT_SENSITIVITY_SENSITIVE) {
return true;
+ } else if (contentSensitivity == CONTENT_SENSITIVITY_NOT_SENSITIVE) {
+ return false;
+ } else if (sensitiveContentAppProtection()) {
+ return SensitiveAutofillHintsHelper
+ .containsSensitiveAutofillHint(getAutofillHints());
}
return false;
}
/**
+ * Helper used to track sensitive views when they are added or removed from the window
+ * based on whether it's laid out and visible.
+ *
+ * <p>This method is called from many places (visibility changed, view laid out, view attached
+ * or detached to/from window, etc...)
+ */
+ private void updateSensitiveViewsCountIfNeeded(boolean appeared) {
+ if (!sensitiveContentAppProtection() || mAttachInfo == null) {
+ return;
+ }
+
+ if (appeared && isContentSensitive()) {
+ if ((mPrivateFlags4 & PFLAG4_IS_COUNTED_AS_SENSITIVE) == 0) {
+ mPrivateFlags4 |= PFLAG4_IS_COUNTED_AS_SENSITIVE;
+ mAttachInfo.increaseSensitiveViewsCount();
+ }
+ } else {
+ if ((mPrivateFlags4 & PFLAG4_IS_COUNTED_AS_SENSITIVE) != 0) {
+ mPrivateFlags4 &= ~PFLAG4_IS_COUNTED_AS_SENSITIVE;
+ mAttachInfo.decreaseSensitiveViewsCount();
+ }
+ }
+ }
+
+ /**
* Gets the mode for determining whether this view is important for content capture.
*
* <p>See {@link #setImportantForContentCapture(int)} and
@@ -13436,6 +13480,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
} else {
mAutofillHints = autofillHints;
}
+ if (sensitiveContentAppProtection()) {
+ if (getContentSensitivity() == CONTENT_SENSITIVITY_AUTO) {
+ updateSensitiveViewsCountIfNeeded(isAggregatedVisible());
+ }
+ }
}
/**
@@ -16660,6 +16709,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible);
+ updateSensitiveViewsCountIfNeeded(isVisible);
if (!getSystemGestureExclusionRects().isEmpty()) {
postUpdate(this::updateSystemGestureExclusionRects);
@@ -22649,6 +22699,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
notifyAppearedOrDisappearedForContentCaptureIfNeeded(false);
+ updateSensitiveViewsCountIfNeeded(false);
mAttachInfo = null;
if (mOverlay != null) {
@@ -31796,6 +31847,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
ScrollCaptureInternal mScrollCaptureInternal;
/**
+ * sensitive views attached to the window
+ */
+ int mSensitiveViewsCount;
+
+ /**
* Creates a new set of attachment information with the specified
* events handler and thread.
*
@@ -31814,6 +31870,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mTreeObserver = new ViewTreeObserver(context);
}
+ void increaseSensitiveViewsCount() {
+ if (mSensitiveViewsCount == 0) {
+ mViewRootImpl.notifySensitiveContentAppProtection(true);
+ }
+ mSensitiveViewsCount++;
+ }
+
+ void decreaseSensitiveViewsCount() {
+ mSensitiveViewsCount--;
+ if (mSensitiveViewsCount == 0) {
+ mViewRootImpl.notifySensitiveContentAppProtection(false);
+ }
+ if (mSensitiveViewsCount < 0) {
+ Log.wtf(VIEW_LOG_TAG, "mSensitiveViewsCount is negative" + mSensitiveViewsCount);
+ mSensitiveViewsCount = 0;
+ }
+ }
+
@Nullable
ContentCaptureManager getContentCaptureManager(@NonNull Context context) {
if (mContentCaptureManager != null) {
@@ -32427,6 +32501,36 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
+ private static class SensitiveAutofillHintsHelper {
+ /**
+ * List of autofill hints deemed sensitive for screen protection during screen share.
+ */
+ private static final ArraySet<String> SENSITIVE_CONTENT_AUTOFILL_HINTS = new ArraySet<>();
+ static {
+ SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_USERNAME);
+ SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_PASSWORD_AUTO);
+ SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_PASSWORD);
+ }
+
+ /**
+ * Whether View's autofill hints contains a sensitive autofill hint.
+ *
+ * @see #SENSITIVE_CONTENT_AUTOFILL_HINTS
+ */
+ static boolean containsSensitiveAutofillHint(@Nullable String[] autofillHints) {
+ if (autofillHints == null) {
+ return false;
+ }
+
+ int size = autofillHints.length;
+ for (int i = 0; i < size; i++) {
+ if (SENSITIVE_CONTENT_AUTOFILL_HINTS.contains(autofillHints[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
/**
* Returns the current scroll capture hint for this view.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1e79786d7554..5eba3ea4f4e5 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -57,6 +57,7 @@ import static android.view.ViewRootImplProto.WIDTH;
import static android.view.ViewRootImplProto.WINDOW_ATTRIBUTES;
import static android.view.ViewRootImplProto.WIN_FRAME;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
+import static android.view.flags.Flags.sensitiveContentAppProtection;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
@@ -165,6 +166,7 @@ import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
@@ -923,6 +925,8 @@ public final class ViewRootImpl implements ViewParent,
private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
+ private final ISensitiveContentProtectionManager mSensitiveContentProtectionService;
+
static final class SystemUiVisibilityInfo {
int globalVisibility;
int localValue;
@@ -1195,6 +1199,13 @@ public final class ViewRootImpl implements ViewParent,
mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher(context);
+ if (sensitiveContentAppProtection()) {
+ mSensitiveContentProtectionService =
+ ISensitiveContentProtectionManager.Stub.asInterface(
+ ServiceManager.getService(Context.SENSITIVE_CONTENT_PROTECTION_SERVICE));
+ } else {
+ mSensitiveContentProtectionService = null;
+ }
}
public static void addFirstDrawHandler(Runnable callback) {
@@ -4145,6 +4156,29 @@ public final class ViewRootImpl implements ViewParent,
mWmsRequestSyncGroup.add(this, null /* runnable */);
}
+ /**
+ * Helper used to notify the service to block projection when a sensitive
+ * view (the view displays sensitive content) is attached to the window.
+ * The window manager service is also notified to unblock projection when
+ * no attached view (to the window) displays sensitive content.
+ *
+ * <ol>
+ * <li>It should only notify service to block projection when first sensitive view is
+ * attached to the window.
+ * <li>It should only notify service to unblock projection when all sensitive view are
+ * removed from the window.
+ * </ol>
+ */
+ void notifySensitiveContentAppProtection(boolean showSensitiveContent) {
+ try {
+ // The window would be blocked during screen share if it shows sensitive content.
+ mSensitiveContentProtectionService.setSensitiveContentProtection(
+ getWindowToken(), mContext.getPackageName(), showSensitiveContent);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Unable to protect sensitive content during screen share", ex);
+ }
+ }
+
private void notifyContentCaptureEvents() {
if (!isContentCaptureEnabled()) {
if (DEBUG_CONTENT_CAPTURE) {