Merge "Make SnapshotStartingWindow and its child surface trusted"
This commit is contained in:
committed by
Android (Google) Code Review
commit
a15ff93eb5
@@ -36,6 +36,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATIO
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
|
||||
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
|
||||
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
|
||||
|
||||
import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
|
||||
@@ -129,6 +130,7 @@ class TaskSnapshotSurface implements StartingSurface {
|
||||
private SurfaceControl mChildSurfaceControl;
|
||||
private final IWindowSession mSession;
|
||||
private final WindowManagerService mService;
|
||||
private final int mDisplayId;
|
||||
private final Rect mTaskBounds;
|
||||
private final Rect mFrame = new Rect();
|
||||
private final Rect mSystemBarInsets = new Rect();
|
||||
@@ -151,10 +153,15 @@ class TaskSnapshotSurface implements StartingSurface {
|
||||
|
||||
static TaskSnapshotSurface create(WindowManagerService service, ActivityRecord activity,
|
||||
TaskSnapshot snapshot) {
|
||||
return create(service, activity, snapshot, WindowManagerGlobal.getWindowSession());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static TaskSnapshotSurface create(WindowManagerService service, ActivityRecord activity,
|
||||
TaskSnapshot snapshot, IWindowSession session) {
|
||||
|
||||
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
|
||||
final Window window = new Window();
|
||||
final IWindowSession session = WindowManagerGlobal.getWindowSession();
|
||||
window.setSession(session);
|
||||
final SurfaceControl surfaceControl = new SurfaceControl();
|
||||
final ClientWindowFrames tmpFrames = new ClientWindowFrames();
|
||||
@@ -215,7 +222,10 @@ class TaskSnapshotSurface implements StartingSurface {
|
||||
layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
|
||||
| FLAG_NOT_FOCUSABLE
|
||||
| FLAG_NOT_TOUCHABLE;
|
||||
layoutParams.privateFlags = windowPrivateFlags & PRIVATE_FLAG_INHERITS;
|
||||
// Setting as trusted overlay to let touches pass through. This is safe because this
|
||||
// window is controlled by the system.
|
||||
layoutParams.privateFlags = (windowPrivateFlags & PRIVATE_FLAG_INHERITS)
|
||||
| PRIVATE_FLAG_TRUSTED_OVERLAY;
|
||||
layoutParams.token = activity.token;
|
||||
layoutParams.width = LayoutParams.MATCH_PARENT;
|
||||
layoutParams.height = LayoutParams.MATCH_PARENT;
|
||||
@@ -239,11 +249,11 @@ class TaskSnapshotSurface implements StartingSurface {
|
||||
insetsState = getInsetsStateWithVisibilityOverride(topFullscreenOpaqueWindow);
|
||||
|
||||
}
|
||||
int displayId = activity.getDisplayContent().getDisplayId();
|
||||
try {
|
||||
final int res = session.addToDisplay(window, layoutParams,
|
||||
View.GONE, activity.getDisplayContent().getDisplayId(), mTmpInsetsState,
|
||||
tmpFrames.frame, tmpFrames.displayCutout, null /* outInputChannel */,
|
||||
mTmpInsetsState, mTempControls);
|
||||
View.GONE, displayId, mTmpInsetsState, tmpFrames.frame, tmpFrames.displayCutout,
|
||||
null /* outInputChannel */, mTmpInsetsState, mTempControls);
|
||||
if (res < 0) {
|
||||
Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
|
||||
return null;
|
||||
@@ -251,10 +261,10 @@ class TaskSnapshotSurface implements StartingSurface {
|
||||
} catch (RemoteException e) {
|
||||
// Local call.
|
||||
}
|
||||
final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
|
||||
surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, appearance,
|
||||
windowFlags, windowPrivateFlags, taskBounds, currentOrientation, activityType,
|
||||
insetsState);
|
||||
final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, displayId,
|
||||
window, surfaceControl, snapshot, layoutParams.getTitle(), taskDescription,
|
||||
appearance, windowFlags, windowPrivateFlags, taskBounds, currentOrientation,
|
||||
activityType, insetsState);
|
||||
window.setOuter(snapshotSurface);
|
||||
try {
|
||||
session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, -1,
|
||||
@@ -271,11 +281,13 @@ class TaskSnapshotSurface implements StartingSurface {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
TaskSnapshotSurface(WindowManagerService service, Window window, SurfaceControl surfaceControl,
|
||||
TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
|
||||
int appearance, int windowFlags, int windowPrivateFlags, Rect taskBounds,
|
||||
int currentOrientation, int activityType, InsetsState insetsState) {
|
||||
TaskSnapshotSurface(WindowManagerService service, int displayId, Window window,
|
||||
SurfaceControl surfaceControl, TaskSnapshot snapshot, CharSequence title,
|
||||
TaskDescription taskDescription, int appearance, int windowFlags,
|
||||
int windowPrivateFlags, Rect taskBounds, int currentOrientation, int activityType,
|
||||
InsetsState insetsState) {
|
||||
mService = service;
|
||||
mDisplayId = displayId;
|
||||
mSurface = service.mSurfaceFactory.get();
|
||||
mHandler = new Handler(mService.mH.getLooper());
|
||||
mSession = WindowManagerGlobal.getWindowSession();
|
||||
@@ -368,8 +380,9 @@ class TaskSnapshotSurface implements StartingSurface {
|
||||
- ((float) mFrame.width() / mFrame.height())) > 0.01f;
|
||||
|
||||
// Keep a reference to it such that it doesn't get destroyed when finalized.
|
||||
final String name = mTitle + " - task-snapshot-surface";
|
||||
mChildSurfaceControl = mService.mSurfaceControlFactory.apply(session)
|
||||
.setName(mTitle + " - task-snapshot-surface")
|
||||
.setName(name)
|
||||
.setBufferSize(buffer.getWidth(), buffer.getHeight())
|
||||
.setFormat(buffer.getFormat())
|
||||
.setParent(mSurfaceControl)
|
||||
@@ -401,6 +414,11 @@ class TaskSnapshotSurface implements StartingSurface {
|
||||
mSnapshotMatrix.setRectToRect(mTmpSnapshotSize, mTmpDstFrame, Matrix.ScaleToFit.FILL);
|
||||
mTransaction.setMatrix(mChildSurfaceControl, mSnapshotMatrix, mTmpFloat9);
|
||||
|
||||
// This is the way to tell the input system to exclude this surface from occlusion
|
||||
// detection since we don't have a window for it. We do this because this window is
|
||||
// generated by the system as well as its content (the snapshot of the app).
|
||||
InputMonitor.setTrustedOverlayInputInfo(mChildSurfaceControl, mTransaction, mDisplayId,
|
||||
name);
|
||||
mTransaction.apply();
|
||||
surface.attachAndQueueBufferWithColorSpace(buffer, mSnapshot.getColorSpace());
|
||||
surface.release();
|
||||
|
||||
@@ -88,6 +88,7 @@ import org.mockito.quality.Strictness;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* JUnit test rule to correctly setting up system services like {@link WindowManagerService}
|
||||
@@ -112,6 +113,7 @@ public class SystemServicesTestRule implements TestRule {
|
||||
private WindowState.PowerManagerWrapper mPowerManagerWrapper;
|
||||
private InputManagerService mImService;
|
||||
private InputChannel mInputChannel;
|
||||
private Supplier<Surface> mSurfaceFactory = () -> mock(Surface.class);
|
||||
/**
|
||||
* Spied {@link SurfaceControl.Transaction} class than can be used to verify calls.
|
||||
*/
|
||||
@@ -286,7 +288,7 @@ public class SystemServicesTestRule implements TestRule {
|
||||
DisplayThread.getHandler().post(StrictMode::allowThreadDiskWritesMask);
|
||||
mWmService = WindowManagerService.main(
|
||||
mContext, mImService, false, false, mWMPolicy, mAtmService, StubTransaction::new,
|
||||
() -> mock(Surface.class), (unused) -> new MockSurfaceControlBuilder());
|
||||
() -> mSurfaceFactory.get(), (unused) -> new MockSurfaceControlBuilder());
|
||||
spyOn(mWmService);
|
||||
spyOn(mWmService.mRoot);
|
||||
// Invoked during {@link ActivityStack} creation.
|
||||
@@ -396,6 +398,10 @@ public class SystemServicesTestRule implements TestRule {
|
||||
return mPowerManagerWrapper;
|
||||
}
|
||||
|
||||
void setSurfaceFactory(Supplier<Surface> factory) {
|
||||
mSurfaceFactory = factory;
|
||||
}
|
||||
|
||||
void cleanupWindowManagerHandlers() {
|
||||
final WindowManagerService wm = getWindowManagerService();
|
||||
if (wm == null) {
|
||||
|
||||
@@ -20,17 +20,23 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
|
||||
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.eq;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.TaskDescription;
|
||||
import android.app.ActivityManager.TaskSnapshot;
|
||||
import android.content.ComponentName;
|
||||
@@ -41,14 +47,18 @@ import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.HardwareBuffer;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.view.Display;
|
||||
import android.view.IWindowSession;
|
||||
import android.view.InsetsState;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.server.wm.TaskSnapshotSurface.Window;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@@ -67,9 +77,6 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
|
||||
|
||||
private void setupSurface(int width, int height, Rect contentInsets, int sysuiVis,
|
||||
int windowFlags, Rect taskBounds) {
|
||||
final HardwareBuffer buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888,
|
||||
1, HardwareBuffer.USAGE_CPU_READ_RARELY);
|
||||
|
||||
// Previously when constructing TaskSnapshots for this test, scale was 1.0f, so to mimic
|
||||
// this behavior set the taskSize to be the same as the taskBounds width and height. The
|
||||
// taskBounds passed here are assumed to be the same task bounds as when the snapshot was
|
||||
@@ -79,16 +86,24 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
|
||||
assertEquals(height, taskBounds.height());
|
||||
Point taskSize = new Point(taskBounds.width(), taskBounds.height());
|
||||
|
||||
final TaskSnapshot snapshot = new TaskSnapshot(
|
||||
final TaskSnapshot snapshot = createTaskSnapshot(width, height, taskSize, contentInsets);
|
||||
mSurface = new TaskSnapshotSurface(mWm, Display.DEFAULT_DISPLAY, new Window(),
|
||||
new SurfaceControl(), snapshot, "Test", createTaskDescription(Color.WHITE,
|
||||
Color.RED, Color.BLUE), sysuiVis, windowFlags, 0, taskBounds, ORIENTATION_PORTRAIT,
|
||||
ACTIVITY_TYPE_STANDARD, new InsetsState());
|
||||
}
|
||||
|
||||
private ActivityManager.TaskSnapshot createTaskSnapshot(int width, int height, Point taskSize,
|
||||
Rect contentInsets) {
|
||||
final HardwareBuffer buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888,
|
||||
1, HardwareBuffer.USAGE_CPU_READ_RARELY);
|
||||
return new TaskSnapshot(
|
||||
System.currentTimeMillis(),
|
||||
new ComponentName("", ""), buffer,
|
||||
ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
|
||||
Surface.ROTATION_0, taskSize, contentInsets, false,
|
||||
true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN,
|
||||
0 /* systemUiVisibility */, false /* isTranslucent */);
|
||||
mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test",
|
||||
createTaskDescription(Color.WHITE, Color.RED, Color.BLUE), sysuiVis, windowFlags, 0,
|
||||
taskBounds, ORIENTATION_PORTRAIT, ACTIVITY_TYPE_STANDARD, new InsetsState());
|
||||
}
|
||||
|
||||
private static TaskDescription createTaskDescription(int background, int statusBar,
|
||||
@@ -105,6 +120,35 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
|
||||
new Rect(0, 0, width, height));
|
||||
}
|
||||
|
||||
private boolean isTrustedOverlay(WindowManager.LayoutParams params) {
|
||||
return (params.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mSystemServicesTestRule.setSurfaceFactory(() -> {
|
||||
Surface surface = mock(Surface.class);
|
||||
when(surface.isValid()).thenReturn(true);
|
||||
return surface;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createSurface_asTrustedOverlay() throws Exception {
|
||||
Point task = new Point(200, 100);
|
||||
ActivityRecord activityRecord = createActivityRecord(mDisplayContent);
|
||||
createWindow(null, TYPE_BASE_APPLICATION, activityRecord, "window");
|
||||
TaskSnapshot taskSnapshot = createTaskSnapshot(task.x, task.y, task, new Rect());
|
||||
IWindowSession session = mock(IWindowSession.class);
|
||||
|
||||
TaskSnapshotSurface surface = TaskSnapshotSurface.create(mWm, activityRecord, taskSnapshot,
|
||||
session);
|
||||
|
||||
assertThat(surface).isNotNull();
|
||||
verify(session).addToDisplay(any(), argThat(this::isTrustedOverlay), anyInt(), anyInt(),
|
||||
any(), any(), any(), any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fillEmptyBackground_fillHorizontally() {
|
||||
setupSurface(200, 100);
|
||||
|
||||
Reference in New Issue
Block a user