Merge "[Media Projection] Require valid token to set session" into tm-dev am: 55ecb4ec82

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18356863

Change-Id: Ife19064237c6f958e03ba3057cd2dd8bf58e1681
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Naomi Musgrave
2022-05-20 14:02:05 +00:00
committed by Automerger Merge Worker
8 changed files with 71 additions and 30 deletions

View File

@@ -32,7 +32,6 @@ import android.graphics.Region;
import android.os.Bundle;
import android.os.IRemoteCallback;
import android.os.ParcelFileDescriptor;
import android.view.ContentRecordingSession;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.IAppTransitionAnimationSpecsFuture;
@@ -873,17 +872,6 @@ interface IWindowManager
*/
void detachWindowContextFromWindowContainer(IBinder clientToken);
/**
* Updates the content recording session. If a different session is already in progress, then
* the pre-existing session is stopped, and the new incoming session takes over.
*
* The DisplayContent for the new session will begin recording when
* {@link RootWindowContainer#onDisplayChanged} is invoked for the new {@link VirtualDisplay}.
*
* @param incomingSession the nullable incoming content recording session
*/
void setContentRecordingSession(in ContentRecordingSession incomingSession);
/**
* Registers a listener, which is to be called whenever cross-window blur is enabled/disabled.
*

View File

@@ -21,6 +21,7 @@ import android.media.projection.IMediaProjectionCallback;
import android.media.projection.IMediaProjectionWatcherCallback;
import android.media.projection.MediaProjectionInfo;
import android.os.IBinder;
import android.view.ContentRecordingSession;
/** {@hide} */
interface IMediaProjectionManager {
@@ -33,4 +34,15 @@ interface IMediaProjectionManager {
void stopActiveProjection();
void addCallback(IMediaProjectionWatcherCallback callback);
void removeCallback(IMediaProjectionWatcherCallback callback);
/**
* Updates the content recording session. If a different session is already in progress, then
* the pre-existing session is stopped, and the new incoming session takes over. Only updates
* the session if the given projection is valid.
*
* @param incomingSession the nullable incoming content recording session
* @param projection the non-null projection the session describes
*/
void setContentRecordingSession(in ContentRecordingSession incomingSession,
in IMediaProjection projection);
}

View File

@@ -26,12 +26,11 @@ import android.hardware.display.VirtualDisplay;
import android.hardware.display.VirtualDisplayConfig;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.ArrayMap;
import android.util.Log;
import android.view.ContentRecordingSession;
import android.view.IWindowManager;
import android.view.Surface;
import android.view.WindowManagerGlobal;
import android.window.WindowContainerToken;
import java.util.Map;
@@ -53,6 +52,7 @@ public final class MediaProjection {
private final IMediaProjection mImpl;
private final Context mContext;
private final Map<Callback, CallbackRecord> mCallbacks;
@Nullable private IMediaProjectionManager mProjectionService = null;
/** @hide */
public MediaProjection(Context context, IMediaProjection impl) {
@@ -172,7 +172,6 @@ public final class MediaProjection {
@NonNull VirtualDisplayConfig.Builder virtualDisplayConfig,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
try {
final IWindowManager wmService = WindowManagerGlobal.getWindowManagerService();
final WindowContainerToken taskWindowContainerToken =
mImpl.getTaskRecordingWindowContainerToken();
Context windowContext = null;
@@ -199,7 +198,7 @@ public final class MediaProjection {
}
session.setDisplayId(virtualDisplay.getDisplay().getDisplayId());
// Successfully set up, so save the current session details.
wmService.setContentRecordingSession(session);
getProjectionService().setContentRecordingSession(session, mImpl);
return virtualDisplay;
} catch (RemoteException e) {
// Can not capture if WMS is not accessible, so bail out.
@@ -207,6 +206,14 @@ public final class MediaProjection {
}
}
private IMediaProjectionManager getProjectionService() {
if (mProjectionService == null) {
mProjectionService = IMediaProjectionManager.Stub.asInterface(
ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE));
}
return mProjectionService;
}
/**
* Stops projection.
*/

View File

@@ -45,14 +45,15 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;
import android.view.ContentRecordingSession;
import android.window.WindowContainerToken;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemService.TargetUser;
import com.android.server.Watchdog;
import com.android.server.wm.WindowManagerInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -381,6 +382,27 @@ public final class MediaProjectionManagerService extends SystemService
}
}
/**
* Updates the current content mirroring session.
*/
@Override
public void setContentRecordingSession(@Nullable ContentRecordingSession incomingSession,
@NonNull IMediaProjection projection) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
if (!isValidMediaProjection(projection)) {
throw new SecurityException("Invalid media projection");
}
LocalServices.getService(
WindowManagerInternal.class).setContentRecordingSession(
incomingSession);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
@Override // Binder call
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;

View File

@@ -207,7 +207,8 @@ final class ContentRecorder {
// Update the cached session state first, since updating the service will result in always
// returning to this instance to update recording state.
mContentRecordingSession = null;
mDisplayContent.mWmService.setContentRecordingSession(null);
mDisplayContent.mWmService.mContentRecordingController.setContentRecordingSessionLocked(
null, mDisplayContent.mWmService);
}
/**

View File

@@ -30,6 +30,7 @@ import android.hardware.display.DisplayManagerInternal;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Pair;
import android.view.ContentRecordingSession;
import android.view.Display;
import android.view.IInputFilter;
import android.view.IRemoteAnimationFinishedCallback;
@@ -869,4 +870,16 @@ public abstract class WindowManagerInternal {
*/
public abstract boolean isPointInsideWindow(
@NonNull IBinder windowToken, int displayId, float displayX, float displayY);
/**
* Updates the content recording session. If a different session is already in progress, then
* the pre-existing session is stopped, and the new incoming session takes over.
*
* The DisplayContent for the new session will begin recording when
* {@link RootWindowContainer#onDisplayChanged} is invoked for the new {@link VirtualDisplay}.
* Must be invoked for a valid MediaProjection session.
*
* @param incomingSession the nullable incoming content recording session
*/
public abstract void setContentRecordingSession(ContentRecordingSession incomingSession);
}

View File

@@ -2956,16 +2956,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
/**
* Updates the current content mirroring session.
*/
@Override
public void setContentRecordingSession(@Nullable ContentRecordingSession incomingSession) {
synchronized (mGlobalLock) {
mContentRecordingController.setContentRecordingSessionLocked(incomingSession, this);
}
}
// TODO(multi-display): remove when no default display use case.
void prepareAppTransitionNone() {
if (!checkCallingPermission(MANAGE_APP_TOKENS, "prepareAppTransition()")) {
@@ -8242,6 +8232,14 @@ public class WindowManagerService extends IWindowManager.Stub
return w.getBounds().contains((int) displayX, (int) displayY);
}
}
@Override
public void setContentRecordingSession(@Nullable ContentRecordingSession incomingSession) {
synchronized (mGlobalLock) {
mContentRecordingController.setContentRecordingSessionLocked(incomingSession,
WindowManagerService.this);
}
}
}
void registerAppFreezeListener(AppFreezeListener listener) {

View File

@@ -2441,7 +2441,7 @@ public class DisplayContentTests extends WindowTestsBase {
ContentRecordingSession session = ContentRecordingSession.createDisplaySession(
tokenToMirror);
session.setDisplayId(displayId);
mWm.setContentRecordingSession(session);
mWm.mContentRecordingController.setContentRecordingSessionLocked(session, mWm);
actualDC.updateRecording();
// THEN mirroring is not started, since a null surface indicates the VirtualDisplay is off.
@@ -2470,7 +2470,7 @@ public class DisplayContentTests extends WindowTestsBase {
ContentRecordingSession session = ContentRecordingSession.createDisplaySession(
tokenToMirror);
session.setDisplayId(displayId);
mWm.setContentRecordingSession(session);
mWm.mContentRecordingController.setContentRecordingSessionLocked(session, mWm);
mWm.mRoot.onDisplayAdded(displayId);
// WHEN getting the DisplayContent for the new virtual display.