diff options
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(); |