Merge "Make activities in untrusted embedding mode invisible behind overlay" into tm-dev

This commit is contained in:
Chris Li
2022-03-08 12:03:04 +00:00
committed by Android (Google) Code Review
4 changed files with 94 additions and 6 deletions

View File

@@ -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() {
@@ -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()) {
@@ -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();

View File

@@ -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;

View File

@@ -701,6 +701,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(),
errorCallbackToken,
convertStartFailureToThrowable(result, activityIntent));
} else {
effects |= TRANSACT_EFFECTS_LIFECYCLE;
}
break;
}

View File

@@ -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();