summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Andrii Kulian <akulian@google.com> 2022-02-17 19:19:43 -0800
committer Chris Li <lihongyu@google.com> 2022-03-08 14:02:27 +0800
commitff3321d15422214bc7d16c8c963b718a27c1063f (patch)
tree06395a2e6e4f9688eed4fa5e30caf5438d4c3ff0
parent714fe08825273d228e89923b28fe977d1f076ff1 (diff)
Make activities in untrusted embedding mode invisible behind overlay
Activities embedded in untrusted mode must be made invisible when there is another activity on top in the same task that belongs to a different UID. Also make sure the input mode is set to "drop when obscured" for untrusted embedded activities. Bug: 197364677 Test: TaskFragmentTrustedModeTest Change-Id: I3f8e252fb2d8e5bffdc11b37c42cc41d116c8fa3
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java83
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java13
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java2
4 files changed, 94 insertions, 6 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index e66f309d2ccc..e9fb4d40ed0d 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -278,6 +278,7 @@ import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.gui.DropInputMode;
import android.hardware.HardwareBuffer;
import android.net.Uri;
import android.os.Binder;
@@ -782,6 +783,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
boolean startingDisplayed;
boolean startingMoved;
+ /** The last set {@link DropInputMode} for this activity surface. */
+ @DropInputMode
+ private int mLastDropInputMode = DropInputMode.NONE;
+
/**
* If it is non-null, it requires all activities who have the same starting data to be drawn
* to remove the starting window.
@@ -1548,6 +1553,60 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
rootTask.setHasBeenVisible(true);
}
}
+
+ // Update the input mode if the embedded mode is changed.
+ updateUntrustedEmbeddingInputProtection();
+ }
+
+ @Override
+ void setSurfaceControl(SurfaceControl sc) {
+ super.setSurfaceControl(sc);
+ if (sc != null) {
+ mLastDropInputMode = DropInputMode.NONE;
+ updateUntrustedEmbeddingInputProtection();
+ }
+ }
+
+ /**
+ * Sets to drop input when obscured to activity if it is embedded in untrusted mode.
+ *
+ * Although the untrusted embedded activity should be invisible when behind other overlay,
+ * theoretically even if this activity is the top most, app can still move surface of activity
+ * below it to the top. As a result, we want to update the input mode to drop when obscured for
+ * all untrusted activities.
+ */
+ private void updateUntrustedEmbeddingInputProtection() {
+ final SurfaceControl sc = getSurfaceControl();
+ if (sc == null) {
+ return;
+ }
+ if (isEmbeddedInUntrustedMode()) {
+ // Set drop input to OBSCURED when untrusted embedded.
+ setDropInputMode(DropInputMode.OBSCURED);
+ } else {
+ // Reset drop input mode when this activity is not embedded in untrusted mode.
+ setDropInputMode(DropInputMode.NONE);
+ }
+ }
+
+ @VisibleForTesting
+ void setDropInputMode(@DropInputMode int mode) {
+ if (mLastDropInputMode != mode && getSurfaceControl() != null) {
+ mLastDropInputMode = mode;
+ mWmService.mTransactionFactory.get()
+ .setDropInputMode(getSurfaceControl(), mode)
+ .apply();
+ }
+ }
+
+ private boolean isEmbeddedInUntrustedMode() {
+ final TaskFragment organizedTaskFragment = getOrganizedTaskFragment();
+ if (organizedTaskFragment == null) {
+ // Not embedded.
+ return false;
+ }
+ // Check if trusted.
+ return !organizedTaskFragment.isAllowedToEmbedActivityInTrustedMode(this);
}
void updateAnimatingActivityRegistry() {
@@ -5428,6 +5487,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return false;
}
+ // Untrusted embedded activity can be visible only if there is no other overlay window.
+ if (hasOverlayOverUntrustedModeEmbedded()) {
+ return false;
+ }
+
// Check if the activity is on a sleeping display, canTurnScreenOn will also check
// keyguard visibility
if (mDisplayContent.isSleeping()) {
@@ -5437,6 +5501,25 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
+ /**
+ * Checks if there are any activities or other containers that belong to the same task on top of
+ * this activity when embedded in untrusted mode.
+ */
+ boolean hasOverlayOverUntrustedModeEmbedded() {
+ if (!isEmbeddedInUntrustedMode() || getRootTask() == null) {
+ // The activity is not embedded in untrusted mode.
+ return false;
+ }
+
+ // Check if there are any activities with different UID over the activity that is embedded
+ // in untrusted mode. Traverse bottom to top with boundary so that it will only check
+ // activities above this activity.
+ final ActivityRecord differentUidOverlayActivity = getRootTask().getActivity(
+ a -> a.getUid() != getUid(), this /* boundary */, false /* includeBoundary */,
+ false /* traverseTopToBottom */);
+ return differentUidOverlayActivity != null;
+ }
+
void updateVisibilityIgnoringKeyguard(boolean behindFullscreenActivity) {
visibleIgnoringKeyguard = (!behindFullscreenActivity || mLaunchTaskBehind)
&& showToCurrentUser();
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index afc3087f4ee9..3411104dbff0 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -516,12 +516,13 @@ class TaskFragment extends WindowContainer<WindowContainer> {
* @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord)
*/
boolean isAllowedToEmbedActivity(@NonNull ActivityRecord a) {
- if ((a.info.flags & FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING)
- == FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING) {
- return true;
- }
+ return isAllowedToEmbedActivityInUntrustedMode(a)
+ || isAllowedToEmbedActivityInTrustedMode(a);
+ }
- return isAllowedToEmbedActivityInTrustedMode(a);
+ boolean isAllowedToEmbedActivityInUntrustedMode(@NonNull ActivityRecord a) {
+ return (a.info.flags & FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING)
+ == FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
}
/**
@@ -531,7 +532,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
* <li>the activity has declared the organizer host as trusted explicitly via known
* certificate.</li>
*/
- private boolean isAllowedToEmbedActivityInTrustedMode(@NonNull ActivityRecord a) {
+ boolean isAllowedToEmbedActivityInTrustedMode(@NonNull ActivityRecord a) {
if (UserHandle.getAppId(mTaskFragmentOrganizerUid) == SYSTEM_UID) {
// The system is trusted to embed other apps securely and for all users.
return true;
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index ce27d739e1b1..81344ac31108 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -701,6 +701,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(),
errorCallbackToken,
convertStartFailureToThrowable(result, activityIntent));
+ } else {
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
}
break;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 2ea7fdaf6348..eb6395b46120 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -36,6 +36,7 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -422,6 +423,7 @@ public class AppTransitionTests extends WindowTestsBase {
public void testActivityRecordReparentToTaskFragment() {
final ActivityRecord activity = createActivityRecord(mDc);
final SurfaceControl activityLeash = mock(SurfaceControl.class);
+ doNothing().when(activity).setDropInputMode(anyInt());
activity.setVisibility(true);
activity.setSurfaceControl(activityLeash);
final Task task = activity.getTask();