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
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -701,6 +701,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(),
|
||||
errorCallbackToken,
|
||||
convertStartFailureToThrowable(result, activityIntent));
|
||||
} else {
|
||||
effects |= TRANSACT_EFFECTS_LIFECYCLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user