Loading services/core/java/com/android/server/wm/ActivityRecord.java +83 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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() { Loading Loading @@ -5443,6 +5502,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()) { Loading @@ -5452,6 +5516,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(); Loading services/core/java/com/android/server/wm/TaskFragment.java +7 −6 Original line number Diff line number Diff line Loading @@ -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; } /** Loading @@ -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; Loading services/core/java/com/android/server/wm/WindowOrganizerController.java +2 −0 Original line number Diff line number Diff line Loading @@ -701,6 +701,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(), errorCallbackToken, convertStartFailureToThrowable(result, activityIntent)); } else { effects |= TRANSACT_EFFECTS_LIFECYCLE; } break; } Loading services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +2 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading
services/core/java/com/android/server/wm/ActivityRecord.java +83 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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() { Loading Loading @@ -5443,6 +5502,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()) { Loading @@ -5452,6 +5516,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(); Loading
services/core/java/com/android/server/wm/TaskFragment.java +7 −6 Original line number Diff line number Diff line Loading @@ -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; } /** Loading @@ -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; Loading
services/core/java/com/android/server/wm/WindowOrganizerController.java +2 −0 Original line number Diff line number Diff line Loading @@ -701,6 +701,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(), errorCallbackToken, convertStartFailureToThrowable(result, activityIntent)); } else { effects |= TRANSACT_EFFECTS_LIFECYCLE; } break; } Loading
services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +2 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading