Merge "Make activities in untrusted embedding mode invisible behind overlay" into tm-dev
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() {
|
||||
@@ -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();
|
||||
|
||||
@@ -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