Loading core/java/android/view/ContentRecordingSession.java +73 −22 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DataClass; import java.lang.annotation.Retention; Loading Loading @@ -72,10 +71,17 @@ public final class ContentRecordingSession implements Parcelable { * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then * represents the {@link android.window.WindowContainerToken} of the Task to record. */ @VisibleForTesting @Nullable private IBinder mTokenToRecord = null; /** * When {@code true}, no mirroring should take place until the user has re-granted access to * the consent token. When {@code false}, recording can begin immediately. * * <p>Only set on the server side to sanitize any input from the client process. */ private boolean mWaitingToRecord = false; /** * Default instance, with recording the display. */ Loading Loading @@ -109,9 +115,10 @@ public final class ContentRecordingSession implements Parcelable { } /** * Returns {@code true} when both sessions are for the same display. * Returns {@code true} when both sessions are on the same * {@link android.hardware.display.VirtualDisplay}. */ public static boolean isSameDisplay(ContentRecordingSession session, public static boolean isProjectionOnSameDisplay(ContentRecordingSession session, ContentRecordingSession incomingSession) { return session != null && incomingSession != null && session.getDisplayId() == incomingSession.getDisplayId(); Loading Loading @@ -156,7 +163,8 @@ public final class ContentRecordingSession implements Parcelable { /* package-private */ ContentRecordingSession( int displayId, @RecordContent int contentToRecord, @VisibleForTesting @Nullable IBinder tokenToRecord) { @Nullable IBinder tokenToRecord, boolean waitingToRecord) { this.mDisplayId = displayId; this.mContentToRecord = contentToRecord; Loading @@ -169,8 +177,7 @@ public final class ContentRecordingSession implements Parcelable { } this.mTokenToRecord = tokenToRecord; com.android.internal.util.AnnotationValidations.validate( VisibleForTesting.class, null, mTokenToRecord); this.mWaitingToRecord = waitingToRecord; // onConstructed(); // You can define this method to get a callback } Loading Loading @@ -200,10 +207,21 @@ public final class ContentRecordingSession implements Parcelable { * represents the {@link android.window.WindowContainerToken} of the Task to record. */ @DataClass.Generated.Member public @VisibleForTesting @Nullable IBinder getTokenToRecord() { public @Nullable IBinder getTokenToRecord() { return mTokenToRecord; } /** * When {@code true}, no mirroring should take place until the user has re-granted access to * the consent token. When {@code false}, recording can begin immediately. * * <p>Only set on the server side to sanitize any input from the client process. */ @DataClass.Generated.Member public boolean isWaitingToRecord() { return mWaitingToRecord; } /** * Unique logical identifier of the {@link android.hardware.display.VirtualDisplay} that has * recorded content rendered to its surface. Loading Loading @@ -240,10 +258,20 @@ public final class ContentRecordingSession implements Parcelable { * represents the {@link android.window.WindowContainerToken} of the Task to record. */ @DataClass.Generated.Member public @NonNull ContentRecordingSession setTokenToRecord(@VisibleForTesting @NonNull IBinder value) { public @NonNull ContentRecordingSession setTokenToRecord(@NonNull IBinder value) { mTokenToRecord = value; com.android.internal.util.AnnotationValidations.validate( VisibleForTesting.class, null, mTokenToRecord); return this; } /** * When {@code true}, no mirroring should take place until the user has re-granted access to * the consent token. When {@code false}, recording can begin immediately. * * <p>Only set on the server side to sanitize any input from the client process. */ @DataClass.Generated.Member public @NonNull ContentRecordingSession setWaitingToRecord( boolean value) { mWaitingToRecord = value; return this; } Loading @@ -256,7 +284,8 @@ public final class ContentRecordingSession implements Parcelable { return "ContentRecordingSession { " + "displayId = " + mDisplayId + ", " + "contentToRecord = " + recordContentToString(mContentToRecord) + ", " + "tokenToRecord = " + mTokenToRecord + "tokenToRecord = " + mTokenToRecord + ", " + "waitingToRecord = " + mWaitingToRecord + " }"; } Loading @@ -275,7 +304,8 @@ public final class ContentRecordingSession implements Parcelable { return true && mDisplayId == that.mDisplayId && mContentToRecord == that.mContentToRecord && java.util.Objects.equals(mTokenToRecord, that.mTokenToRecord); && java.util.Objects.equals(mTokenToRecord, that.mTokenToRecord) && mWaitingToRecord == that.mWaitingToRecord; } @Override Loading @@ -288,6 +318,7 @@ public final class ContentRecordingSession implements Parcelable { _hash = 31 * _hash + mDisplayId; _hash = 31 * _hash + mContentToRecord; _hash = 31 * _hash + java.util.Objects.hashCode(mTokenToRecord); _hash = 31 * _hash + Boolean.hashCode(mWaitingToRecord); return _hash; } Loading @@ -298,6 +329,7 @@ public final class ContentRecordingSession implements Parcelable { // void parcelFieldName(Parcel dest, int flags) { ... } byte flg = 0; if (mWaitingToRecord) flg |= 0x8; if (mTokenToRecord != null) flg |= 0x4; dest.writeByte(flg); dest.writeInt(mDisplayId); Loading @@ -317,6 +349,7 @@ public final class ContentRecordingSession implements Parcelable { // static FieldType unparcelFieldName(Parcel in) { ... } byte flg = in.readByte(); boolean waitingToRecord = (flg & 0x8) != 0; int displayId = in.readInt(); int contentToRecord = in.readInt(); IBinder tokenToRecord = (flg & 0x4) == 0 ? null : (IBinder) in.readStrongBinder(); Loading @@ -333,8 +366,7 @@ public final class ContentRecordingSession implements Parcelable { } this.mTokenToRecord = tokenToRecord; com.android.internal.util.AnnotationValidations.validate( VisibleForTesting.class, null, mTokenToRecord); this.mWaitingToRecord = waitingToRecord; // onConstructed(); // You can define this method to get a callback } Loading Loading @@ -362,7 +394,8 @@ public final class ContentRecordingSession implements Parcelable { private int mDisplayId; private @RecordContent int mContentToRecord; private @VisibleForTesting @Nullable IBinder mTokenToRecord; private @Nullable IBinder mTokenToRecord; private boolean mWaitingToRecord; private long mBuilderFieldsSet = 0L; Loading Loading @@ -400,17 +433,31 @@ public final class ContentRecordingSession implements Parcelable { * represents the {@link android.window.WindowContainerToken} of the Task to record. */ @DataClass.Generated.Member public @NonNull Builder setTokenToRecord(@VisibleForTesting @NonNull IBinder value) { public @NonNull Builder setTokenToRecord(@NonNull IBinder value) { checkNotUsed(); mBuilderFieldsSet |= 0x4; mTokenToRecord = value; return this; } /** * When {@code true}, no mirroring should take place until the user has re-granted access to * the consent token. When {@code false}, recording can begin immediately. * * <p>Only set on the server side to sanitize any input from the client process. */ @DataClass.Generated.Member public @NonNull Builder setWaitingToRecord(boolean value) { checkNotUsed(); mBuilderFieldsSet |= 0x8; mWaitingToRecord = value; return this; } /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull ContentRecordingSession build() { checkNotUsed(); mBuilderFieldsSet |= 0x8; // Mark builder used mBuilderFieldsSet |= 0x10; // Mark builder used if ((mBuilderFieldsSet & 0x1) == 0) { mDisplayId = INVALID_DISPLAY; Loading @@ -421,15 +468,19 @@ public final class ContentRecordingSession implements Parcelable { if ((mBuilderFieldsSet & 0x4) == 0) { mTokenToRecord = null; } if ((mBuilderFieldsSet & 0x8) == 0) { mWaitingToRecord = false; } ContentRecordingSession o = new ContentRecordingSession( mDisplayId, mContentToRecord, mTokenToRecord); mTokenToRecord, mWaitingToRecord); return o; } private void checkNotUsed() { if ((mBuilderFieldsSet & 0x8) != 0) { if ((mBuilderFieldsSet & 0x10) != 0) { throw new IllegalStateException( "This Builder should not be reused. Use a new Builder instance instead"); } Loading @@ -437,10 +488,10 @@ public final class ContentRecordingSession implements Parcelable { } @DataClass.Generated( time = 1645803878639L, time = 1678817765846L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/view/ContentRecordingSession.java", inputSignatures = "public static final int RECORD_CONTENT_DISPLAY\npublic static final int RECORD_CONTENT_TASK\nprivate int mDisplayId\nprivate @android.view.ContentRecordingSession.RecordContent int mContentToRecord\nprivate @com.android.internal.annotations.VisibleForTesting @android.annotation.Nullable android.os.IBinder mTokenToRecord\npublic static android.view.ContentRecordingSession createDisplaySession(android.os.IBinder)\npublic static android.view.ContentRecordingSession createTaskSession(android.os.IBinder)\npublic static boolean isValid(android.view.ContentRecordingSession)\npublic static boolean isSameDisplay(android.view.ContentRecordingSession,android.view.ContentRecordingSession)\nclass ContentRecordingSession extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genToString=true, genSetters=true, genEqualsHashCode=true)") inputSignatures = "public static final int RECORD_CONTENT_DISPLAY\npublic static final int RECORD_CONTENT_TASK\nprivate int mDisplayId\nprivate @android.view.ContentRecordingSession.RecordContent int mContentToRecord\nprivate @android.annotation.Nullable android.os.IBinder mTokenToRecord\nprivate boolean mWaitingToRecord\npublic static android.view.ContentRecordingSession createDisplaySession(android.os.IBinder)\npublic static android.view.ContentRecordingSession createTaskSession(android.os.IBinder)\npublic static boolean isValid(android.view.ContentRecordingSession)\npublic static boolean isProjectionOnSameDisplay(android.view.ContentRecordingSession,android.view.ContentRecordingSession)\nclass ContentRecordingSession extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genToString=true, genSetters=true, genEqualsHashCode=true)") @Deprecated private void __metadata() {} Loading core/java/com/android/internal/protolog/ProtoLogGroup.java +1 −1 Original line number Diff line number Diff line Loading @@ -85,7 +85,7 @@ public enum ProtoLogGroup implements IProtoLogGroup { Consts.TAG_WM), WM_DEBUG_WINDOW_INSETS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), WM_DEBUG_CONTENT_RECORDING(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, WM_DEBUG_CONTENT_RECORDING(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, Consts.TAG_WM), WM_DEBUG_WALLPAPER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), WM_DEBUG_BACK_PREVIEW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, Loading core/tests/coretests/src/android/view/ContentRecordingSessionTest.java +7 −5 Original line number Diff line number Diff line Loading @@ -89,20 +89,22 @@ public class ContentRecordingSessionTest { } @Test public void testIsSameDisplay() { assertThat(ContentRecordingSession.isSameDisplay(null, null)).isFalse(); public void testIsProjectionOnSameDisplay() { assertThat(ContentRecordingSession.isProjectionOnSameDisplay(null, null)).isFalse(); ContentRecordingSession session = ContentRecordingSession.createDisplaySession( WINDOW_TOKEN); session.setDisplayId(DEFAULT_DISPLAY); assertThat(ContentRecordingSession.isSameDisplay(session, null)).isFalse(); assertThat(ContentRecordingSession.isProjectionOnSameDisplay(session, null)).isFalse(); ContentRecordingSession incomingSession = ContentRecordingSession.createDisplaySession( WINDOW_TOKEN); incomingSession.setDisplayId(DEFAULT_DISPLAY); assertThat(ContentRecordingSession.isSameDisplay(session, incomingSession)).isTrue(); assertThat(ContentRecordingSession.isProjectionOnSameDisplay(session, incomingSession)).isTrue(); incomingSession.setDisplayId(DEFAULT_DISPLAY + 1); assertThat(ContentRecordingSession.isSameDisplay(session, incomingSession)).isFalse(); assertThat(ContentRecordingSession.isProjectionOnSameDisplay(session, incomingSession)).isFalse(); } @Test Loading data/etc/services.core.protolog.json +152 −146 File changed.Preview size limit exceeded, changes collapsed. Show changes services/core/java/com/android/server/wm/ContentRecorder.java +37 −30 Original line number Diff line number Diff line Loading @@ -143,14 +143,15 @@ final class ContentRecorder implements WindowContainerListener { // Recording has already begun, but update recording since the display is now on. if (mRecordedWindowContainer == null) { ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Unexpectedly null window container; unable to update recording for " + "display %d", "Content Recording: Unexpectedly null window container; unable to update " + "recording for display %d", mDisplayContent.getDisplayId()); return; } ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Display %d was already recording, so apply transformations if necessary", "Content Recording: Display %d was already recording, so apply " + "transformations if necessary", mDisplayContent.getDisplayId()); // Retrieve the size of the region to record, and continue with the update // if the bounds or orientation has changed. Loading @@ -161,8 +162,8 @@ final class ContentRecorder implements WindowContainerListener { Point surfaceSize = fetchSurfaceSizeIfPresent(); if (surfaceSize != null) { ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Going ahead with updating recording for display %d to new " + "bounds %s and/or orientation %d.", "Content Recording: Going ahead with updating recording for display " + "%d to new bounds %s and/or orientation %d.", mDisplayContent.getDisplayId(), recordedContentBounds, recordedContentOrientation); updateMirroredSurface(mDisplayContent.mWmService.mTransactionFactory.get(), Loading @@ -171,8 +172,9 @@ final class ContentRecorder implements WindowContainerListener { // If the surface removed, do nothing. We will handle this via onDisplayChanged // (the display will be off if the surface is removed). ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Unable to update recording for display %d to new bounds %s" + " and/or orientation %d, since the surface is not available.", "Content Recording: Unable to update recording for display %d to new " + "bounds %s and/or orientation %d, since the surface is not " + "available.", mDisplayContent.getDisplayId(), recordedContentBounds, recordedContentOrientation); } Loading @@ -189,8 +191,8 @@ final class ContentRecorder implements WindowContainerListener { return; } ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Display %d has content (%b) so pause recording", mDisplayContent.getDisplayId(), mDisplayContent.getLastHasContent()); "Content Recording: Display %d has content (%b) so pause recording", mDisplayContent.getDisplayId(), mDisplayContent.getLastHasContent()); // If the display is not on and it is a virtual display, then it no longer has an // associated surface to write output to. // If the display now has content, stop mirroring to it. Loading Loading @@ -231,7 +233,8 @@ final class ContentRecorder implements WindowContainerListener { */ private void stopMediaProjection() { ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Stop MediaProjection on virtual display %d", mDisplayContent.getDisplayId()); "Content Recording: Stop MediaProjection on virtual display %d", mDisplayContent.getDisplayId()); if (mMediaProjectionManager != null) { mMediaProjectionManager.stopActiveProjection(); } Loading Loading @@ -283,13 +286,14 @@ final class ContentRecorder implements WindowContainerListener { final Point surfaceSize = fetchSurfaceSizeIfPresent(); if (surfaceSize == null) { ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Unable to start recording for display %d since the surface is not " + "available.", "Content Recording: Unable to start recording for display %d since the " + "surface is not available.", mDisplayContent.getDisplayId()); return; } ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Display %d has no content and is on, so start recording for state %d", "Content Recording: Display %d has no content and is on, so start recording for " + "state %d", mDisplayContent.getDisplayId(), mDisplayContent.getDisplay().getState()); // Create a mirrored hierarchy for the SurfaceControl of the DisplayArea to capture. Loading Loading @@ -349,7 +353,7 @@ final class ContentRecorder implements WindowContainerListener { if (tokenToRecord == null) { handleStartRecordingFailed(); ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Unable to start recording due to null token for display %d", "Content Recording: Unable to start recording due to null token for display %d", mDisplayContent.getDisplayId()); return null; } Loading @@ -359,13 +363,14 @@ final class ContentRecorder implements WindowContainerListener { mDisplayContent.mWmService.mWindowContextListenerController.getContainer( tokenToRecord); if (wc == null) { // Fall back to screenrecording using the data sent to DisplayManager // Fall back to mirroring using the data sent to DisplayManager mDisplayContent.mWmService.mDisplayManagerInternal.setWindowManagerMirroring( mDisplayContent.getDisplayId(), false); handleStartRecordingFailed(); ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Unable to retrieve window container to start recording for " + "display %d", mDisplayContent.getDisplayId()); "Content Recording: Unable to retrieve window container to start " + "recording for display %d", mDisplayContent.getDisplayId()); return null; } // TODO(206461622) Migrate to using the RootDisplayArea Loading @@ -375,7 +380,7 @@ final class ContentRecorder implements WindowContainerListener { KEY_RECORD_TASK_FEATURE, false)) { handleStartRecordingFailed(); ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Unable to record task since feature is disabled %d", "Content Recording: Unable to record task since feature is disabled %d", mDisplayContent.getDisplayId()); return null; } Loading @@ -383,8 +388,9 @@ final class ContentRecorder implements WindowContainerListener { if (taskToRecord == null) { handleStartRecordingFailed(); ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Unable to retrieve task to start recording for " + "display %d", mDisplayContent.getDisplayId()); "Content Recording: Unable to retrieve task to start recording for " + "display %d", mDisplayContent.getDisplayId()); } else { taskToRecord.registerWindowContainerListener(this); } Loading @@ -394,7 +400,8 @@ final class ContentRecorder implements WindowContainerListener { // capture for the entire display. handleStartRecordingFailed(); ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Unable to start recording due to invalid region for display %d", "Content Recording: Unable to start recording due to invalid region for " + "display %d", mDisplayContent.getDisplayId()); return null; } Loading Loading @@ -488,8 +495,8 @@ final class ContentRecorder implements WindowContainerListener { // State of virtual display will change to 'ON' when the surface is set. // will get event DISPLAY_DEVICE_EVENT_CHANGED ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Provided surface for recording on display %d is not present, so do not" + " update the surface", "Content Recording: Provided surface for recording on display %d is not " + "present, so do not update the surface", mDisplayContent.getDisplayId()); return null; } Loading @@ -500,7 +507,7 @@ final class ContentRecorder implements WindowContainerListener { @Override public void onRemoved() { ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Recorded task is removed, so stop recording on display %d", "Content Recording: Recorded task is removed, so stop recording on display %d", mDisplayContent.getDisplayId()); unregisterListener(); Loading Loading @@ -551,8 +558,8 @@ final class ContentRecorder implements WindowContainerListener { mIMediaProjectionManager.stopActiveProjection(); } catch (RemoteException e) { ProtoLog.e(WM_DEBUG_CONTENT_RECORDING, "Unable to tell MediaProjectionManagerService to stop the active " + "projection: %s", "Content Recording: Unable to tell MediaProjectionManagerService to stop " + "the active projection: %s", e); } } Loading @@ -568,8 +575,8 @@ final class ContentRecorder implements WindowContainerListener { height); } catch (RemoteException e) { ProtoLog.e(WM_DEBUG_CONTENT_RECORDING, "Unable to tell MediaProjectionManagerService about resizing the active " + "projection: %s", "Content Recording: Unable to tell MediaProjectionManagerService about " + "resizing the active projection: %s", e); } } Loading @@ -585,8 +592,8 @@ final class ContentRecorder implements WindowContainerListener { isVisible); } catch (RemoteException e) { ProtoLog.e(WM_DEBUG_CONTENT_RECORDING, "Unable to tell MediaProjectionManagerService about visibility change on " + "the active projection: %s", "Content Recording: Unable to tell MediaProjectionManagerService about " + "visibility change on the active projection: %s", e); } } Loading Loading
core/java/android/view/ContentRecordingSession.java +73 −22 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DataClass; import java.lang.annotation.Retention; Loading Loading @@ -72,10 +71,17 @@ public final class ContentRecordingSession implements Parcelable { * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then * represents the {@link android.window.WindowContainerToken} of the Task to record. */ @VisibleForTesting @Nullable private IBinder mTokenToRecord = null; /** * When {@code true}, no mirroring should take place until the user has re-granted access to * the consent token. When {@code false}, recording can begin immediately. * * <p>Only set on the server side to sanitize any input from the client process. */ private boolean mWaitingToRecord = false; /** * Default instance, with recording the display. */ Loading Loading @@ -109,9 +115,10 @@ public final class ContentRecordingSession implements Parcelable { } /** * Returns {@code true} when both sessions are for the same display. * Returns {@code true} when both sessions are on the same * {@link android.hardware.display.VirtualDisplay}. */ public static boolean isSameDisplay(ContentRecordingSession session, public static boolean isProjectionOnSameDisplay(ContentRecordingSession session, ContentRecordingSession incomingSession) { return session != null && incomingSession != null && session.getDisplayId() == incomingSession.getDisplayId(); Loading Loading @@ -156,7 +163,8 @@ public final class ContentRecordingSession implements Parcelable { /* package-private */ ContentRecordingSession( int displayId, @RecordContent int contentToRecord, @VisibleForTesting @Nullable IBinder tokenToRecord) { @Nullable IBinder tokenToRecord, boolean waitingToRecord) { this.mDisplayId = displayId; this.mContentToRecord = contentToRecord; Loading @@ -169,8 +177,7 @@ public final class ContentRecordingSession implements Parcelable { } this.mTokenToRecord = tokenToRecord; com.android.internal.util.AnnotationValidations.validate( VisibleForTesting.class, null, mTokenToRecord); this.mWaitingToRecord = waitingToRecord; // onConstructed(); // You can define this method to get a callback } Loading Loading @@ -200,10 +207,21 @@ public final class ContentRecordingSession implements Parcelable { * represents the {@link android.window.WindowContainerToken} of the Task to record. */ @DataClass.Generated.Member public @VisibleForTesting @Nullable IBinder getTokenToRecord() { public @Nullable IBinder getTokenToRecord() { return mTokenToRecord; } /** * When {@code true}, no mirroring should take place until the user has re-granted access to * the consent token. When {@code false}, recording can begin immediately. * * <p>Only set on the server side to sanitize any input from the client process. */ @DataClass.Generated.Member public boolean isWaitingToRecord() { return mWaitingToRecord; } /** * Unique logical identifier of the {@link android.hardware.display.VirtualDisplay} that has * recorded content rendered to its surface. Loading Loading @@ -240,10 +258,20 @@ public final class ContentRecordingSession implements Parcelable { * represents the {@link android.window.WindowContainerToken} of the Task to record. */ @DataClass.Generated.Member public @NonNull ContentRecordingSession setTokenToRecord(@VisibleForTesting @NonNull IBinder value) { public @NonNull ContentRecordingSession setTokenToRecord(@NonNull IBinder value) { mTokenToRecord = value; com.android.internal.util.AnnotationValidations.validate( VisibleForTesting.class, null, mTokenToRecord); return this; } /** * When {@code true}, no mirroring should take place until the user has re-granted access to * the consent token. When {@code false}, recording can begin immediately. * * <p>Only set on the server side to sanitize any input from the client process. */ @DataClass.Generated.Member public @NonNull ContentRecordingSession setWaitingToRecord( boolean value) { mWaitingToRecord = value; return this; } Loading @@ -256,7 +284,8 @@ public final class ContentRecordingSession implements Parcelable { return "ContentRecordingSession { " + "displayId = " + mDisplayId + ", " + "contentToRecord = " + recordContentToString(mContentToRecord) + ", " + "tokenToRecord = " + mTokenToRecord + "tokenToRecord = " + mTokenToRecord + ", " + "waitingToRecord = " + mWaitingToRecord + " }"; } Loading @@ -275,7 +304,8 @@ public final class ContentRecordingSession implements Parcelable { return true && mDisplayId == that.mDisplayId && mContentToRecord == that.mContentToRecord && java.util.Objects.equals(mTokenToRecord, that.mTokenToRecord); && java.util.Objects.equals(mTokenToRecord, that.mTokenToRecord) && mWaitingToRecord == that.mWaitingToRecord; } @Override Loading @@ -288,6 +318,7 @@ public final class ContentRecordingSession implements Parcelable { _hash = 31 * _hash + mDisplayId; _hash = 31 * _hash + mContentToRecord; _hash = 31 * _hash + java.util.Objects.hashCode(mTokenToRecord); _hash = 31 * _hash + Boolean.hashCode(mWaitingToRecord); return _hash; } Loading @@ -298,6 +329,7 @@ public final class ContentRecordingSession implements Parcelable { // void parcelFieldName(Parcel dest, int flags) { ... } byte flg = 0; if (mWaitingToRecord) flg |= 0x8; if (mTokenToRecord != null) flg |= 0x4; dest.writeByte(flg); dest.writeInt(mDisplayId); Loading @@ -317,6 +349,7 @@ public final class ContentRecordingSession implements Parcelable { // static FieldType unparcelFieldName(Parcel in) { ... } byte flg = in.readByte(); boolean waitingToRecord = (flg & 0x8) != 0; int displayId = in.readInt(); int contentToRecord = in.readInt(); IBinder tokenToRecord = (flg & 0x4) == 0 ? null : (IBinder) in.readStrongBinder(); Loading @@ -333,8 +366,7 @@ public final class ContentRecordingSession implements Parcelable { } this.mTokenToRecord = tokenToRecord; com.android.internal.util.AnnotationValidations.validate( VisibleForTesting.class, null, mTokenToRecord); this.mWaitingToRecord = waitingToRecord; // onConstructed(); // You can define this method to get a callback } Loading Loading @@ -362,7 +394,8 @@ public final class ContentRecordingSession implements Parcelable { private int mDisplayId; private @RecordContent int mContentToRecord; private @VisibleForTesting @Nullable IBinder mTokenToRecord; private @Nullable IBinder mTokenToRecord; private boolean mWaitingToRecord; private long mBuilderFieldsSet = 0L; Loading Loading @@ -400,17 +433,31 @@ public final class ContentRecordingSession implements Parcelable { * represents the {@link android.window.WindowContainerToken} of the Task to record. */ @DataClass.Generated.Member public @NonNull Builder setTokenToRecord(@VisibleForTesting @NonNull IBinder value) { public @NonNull Builder setTokenToRecord(@NonNull IBinder value) { checkNotUsed(); mBuilderFieldsSet |= 0x4; mTokenToRecord = value; return this; } /** * When {@code true}, no mirroring should take place until the user has re-granted access to * the consent token. When {@code false}, recording can begin immediately. * * <p>Only set on the server side to sanitize any input from the client process. */ @DataClass.Generated.Member public @NonNull Builder setWaitingToRecord(boolean value) { checkNotUsed(); mBuilderFieldsSet |= 0x8; mWaitingToRecord = value; return this; } /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull ContentRecordingSession build() { checkNotUsed(); mBuilderFieldsSet |= 0x8; // Mark builder used mBuilderFieldsSet |= 0x10; // Mark builder used if ((mBuilderFieldsSet & 0x1) == 0) { mDisplayId = INVALID_DISPLAY; Loading @@ -421,15 +468,19 @@ public final class ContentRecordingSession implements Parcelable { if ((mBuilderFieldsSet & 0x4) == 0) { mTokenToRecord = null; } if ((mBuilderFieldsSet & 0x8) == 0) { mWaitingToRecord = false; } ContentRecordingSession o = new ContentRecordingSession( mDisplayId, mContentToRecord, mTokenToRecord); mTokenToRecord, mWaitingToRecord); return o; } private void checkNotUsed() { if ((mBuilderFieldsSet & 0x8) != 0) { if ((mBuilderFieldsSet & 0x10) != 0) { throw new IllegalStateException( "This Builder should not be reused. Use a new Builder instance instead"); } Loading @@ -437,10 +488,10 @@ public final class ContentRecordingSession implements Parcelable { } @DataClass.Generated( time = 1645803878639L, time = 1678817765846L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/view/ContentRecordingSession.java", inputSignatures = "public static final int RECORD_CONTENT_DISPLAY\npublic static final int RECORD_CONTENT_TASK\nprivate int mDisplayId\nprivate @android.view.ContentRecordingSession.RecordContent int mContentToRecord\nprivate @com.android.internal.annotations.VisibleForTesting @android.annotation.Nullable android.os.IBinder mTokenToRecord\npublic static android.view.ContentRecordingSession createDisplaySession(android.os.IBinder)\npublic static android.view.ContentRecordingSession createTaskSession(android.os.IBinder)\npublic static boolean isValid(android.view.ContentRecordingSession)\npublic static boolean isSameDisplay(android.view.ContentRecordingSession,android.view.ContentRecordingSession)\nclass ContentRecordingSession extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genToString=true, genSetters=true, genEqualsHashCode=true)") inputSignatures = "public static final int RECORD_CONTENT_DISPLAY\npublic static final int RECORD_CONTENT_TASK\nprivate int mDisplayId\nprivate @android.view.ContentRecordingSession.RecordContent int mContentToRecord\nprivate @android.annotation.Nullable android.os.IBinder mTokenToRecord\nprivate boolean mWaitingToRecord\npublic static android.view.ContentRecordingSession createDisplaySession(android.os.IBinder)\npublic static android.view.ContentRecordingSession createTaskSession(android.os.IBinder)\npublic static boolean isValid(android.view.ContentRecordingSession)\npublic static boolean isProjectionOnSameDisplay(android.view.ContentRecordingSession,android.view.ContentRecordingSession)\nclass ContentRecordingSession extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genToString=true, genSetters=true, genEqualsHashCode=true)") @Deprecated private void __metadata() {} Loading
core/java/com/android/internal/protolog/ProtoLogGroup.java +1 −1 Original line number Diff line number Diff line Loading @@ -85,7 +85,7 @@ public enum ProtoLogGroup implements IProtoLogGroup { Consts.TAG_WM), WM_DEBUG_WINDOW_INSETS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), WM_DEBUG_CONTENT_RECORDING(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, WM_DEBUG_CONTENT_RECORDING(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, Consts.TAG_WM), WM_DEBUG_WALLPAPER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), WM_DEBUG_BACK_PREVIEW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, Loading
core/tests/coretests/src/android/view/ContentRecordingSessionTest.java +7 −5 Original line number Diff line number Diff line Loading @@ -89,20 +89,22 @@ public class ContentRecordingSessionTest { } @Test public void testIsSameDisplay() { assertThat(ContentRecordingSession.isSameDisplay(null, null)).isFalse(); public void testIsProjectionOnSameDisplay() { assertThat(ContentRecordingSession.isProjectionOnSameDisplay(null, null)).isFalse(); ContentRecordingSession session = ContentRecordingSession.createDisplaySession( WINDOW_TOKEN); session.setDisplayId(DEFAULT_DISPLAY); assertThat(ContentRecordingSession.isSameDisplay(session, null)).isFalse(); assertThat(ContentRecordingSession.isProjectionOnSameDisplay(session, null)).isFalse(); ContentRecordingSession incomingSession = ContentRecordingSession.createDisplaySession( WINDOW_TOKEN); incomingSession.setDisplayId(DEFAULT_DISPLAY); assertThat(ContentRecordingSession.isSameDisplay(session, incomingSession)).isTrue(); assertThat(ContentRecordingSession.isProjectionOnSameDisplay(session, incomingSession)).isTrue(); incomingSession.setDisplayId(DEFAULT_DISPLAY + 1); assertThat(ContentRecordingSession.isSameDisplay(session, incomingSession)).isFalse(); assertThat(ContentRecordingSession.isProjectionOnSameDisplay(session, incomingSession)).isFalse(); } @Test Loading
data/etc/services.core.protolog.json +152 −146 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/core/java/com/android/server/wm/ContentRecorder.java +37 −30 Original line number Diff line number Diff line Loading @@ -143,14 +143,15 @@ final class ContentRecorder implements WindowContainerListener { // Recording has already begun, but update recording since the display is now on. if (mRecordedWindowContainer == null) { ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Unexpectedly null window container; unable to update recording for " + "display %d", "Content Recording: Unexpectedly null window container; unable to update " + "recording for display %d", mDisplayContent.getDisplayId()); return; } ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Display %d was already recording, so apply transformations if necessary", "Content Recording: Display %d was already recording, so apply " + "transformations if necessary", mDisplayContent.getDisplayId()); // Retrieve the size of the region to record, and continue with the update // if the bounds or orientation has changed. Loading @@ -161,8 +162,8 @@ final class ContentRecorder implements WindowContainerListener { Point surfaceSize = fetchSurfaceSizeIfPresent(); if (surfaceSize != null) { ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Going ahead with updating recording for display %d to new " + "bounds %s and/or orientation %d.", "Content Recording: Going ahead with updating recording for display " + "%d to new bounds %s and/or orientation %d.", mDisplayContent.getDisplayId(), recordedContentBounds, recordedContentOrientation); updateMirroredSurface(mDisplayContent.mWmService.mTransactionFactory.get(), Loading @@ -171,8 +172,9 @@ final class ContentRecorder implements WindowContainerListener { // If the surface removed, do nothing. We will handle this via onDisplayChanged // (the display will be off if the surface is removed). ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Unable to update recording for display %d to new bounds %s" + " and/or orientation %d, since the surface is not available.", "Content Recording: Unable to update recording for display %d to new " + "bounds %s and/or orientation %d, since the surface is not " + "available.", mDisplayContent.getDisplayId(), recordedContentBounds, recordedContentOrientation); } Loading @@ -189,8 +191,8 @@ final class ContentRecorder implements WindowContainerListener { return; } ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Display %d has content (%b) so pause recording", mDisplayContent.getDisplayId(), mDisplayContent.getLastHasContent()); "Content Recording: Display %d has content (%b) so pause recording", mDisplayContent.getDisplayId(), mDisplayContent.getLastHasContent()); // If the display is not on and it is a virtual display, then it no longer has an // associated surface to write output to. // If the display now has content, stop mirroring to it. Loading Loading @@ -231,7 +233,8 @@ final class ContentRecorder implements WindowContainerListener { */ private void stopMediaProjection() { ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Stop MediaProjection on virtual display %d", mDisplayContent.getDisplayId()); "Content Recording: Stop MediaProjection on virtual display %d", mDisplayContent.getDisplayId()); if (mMediaProjectionManager != null) { mMediaProjectionManager.stopActiveProjection(); } Loading Loading @@ -283,13 +286,14 @@ final class ContentRecorder implements WindowContainerListener { final Point surfaceSize = fetchSurfaceSizeIfPresent(); if (surfaceSize == null) { ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Unable to start recording for display %d since the surface is not " + "available.", "Content Recording: Unable to start recording for display %d since the " + "surface is not available.", mDisplayContent.getDisplayId()); return; } ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Display %d has no content and is on, so start recording for state %d", "Content Recording: Display %d has no content and is on, so start recording for " + "state %d", mDisplayContent.getDisplayId(), mDisplayContent.getDisplay().getState()); // Create a mirrored hierarchy for the SurfaceControl of the DisplayArea to capture. Loading Loading @@ -349,7 +353,7 @@ final class ContentRecorder implements WindowContainerListener { if (tokenToRecord == null) { handleStartRecordingFailed(); ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Unable to start recording due to null token for display %d", "Content Recording: Unable to start recording due to null token for display %d", mDisplayContent.getDisplayId()); return null; } Loading @@ -359,13 +363,14 @@ final class ContentRecorder implements WindowContainerListener { mDisplayContent.mWmService.mWindowContextListenerController.getContainer( tokenToRecord); if (wc == null) { // Fall back to screenrecording using the data sent to DisplayManager // Fall back to mirroring using the data sent to DisplayManager mDisplayContent.mWmService.mDisplayManagerInternal.setWindowManagerMirroring( mDisplayContent.getDisplayId(), false); handleStartRecordingFailed(); ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Unable to retrieve window container to start recording for " + "display %d", mDisplayContent.getDisplayId()); "Content Recording: Unable to retrieve window container to start " + "recording for display %d", mDisplayContent.getDisplayId()); return null; } // TODO(206461622) Migrate to using the RootDisplayArea Loading @@ -375,7 +380,7 @@ final class ContentRecorder implements WindowContainerListener { KEY_RECORD_TASK_FEATURE, false)) { handleStartRecordingFailed(); ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Unable to record task since feature is disabled %d", "Content Recording: Unable to record task since feature is disabled %d", mDisplayContent.getDisplayId()); return null; } Loading @@ -383,8 +388,9 @@ final class ContentRecorder implements WindowContainerListener { if (taskToRecord == null) { handleStartRecordingFailed(); ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Unable to retrieve task to start recording for " + "display %d", mDisplayContent.getDisplayId()); "Content Recording: Unable to retrieve task to start recording for " + "display %d", mDisplayContent.getDisplayId()); } else { taskToRecord.registerWindowContainerListener(this); } Loading @@ -394,7 +400,8 @@ final class ContentRecorder implements WindowContainerListener { // capture for the entire display. handleStartRecordingFailed(); ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Unable to start recording due to invalid region for display %d", "Content Recording: Unable to start recording due to invalid region for " + "display %d", mDisplayContent.getDisplayId()); return null; } Loading Loading @@ -488,8 +495,8 @@ final class ContentRecorder implements WindowContainerListener { // State of virtual display will change to 'ON' when the surface is set. // will get event DISPLAY_DEVICE_EVENT_CHANGED ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Provided surface for recording on display %d is not present, so do not" + " update the surface", "Content Recording: Provided surface for recording on display %d is not " + "present, so do not update the surface", mDisplayContent.getDisplayId()); return null; } Loading @@ -500,7 +507,7 @@ final class ContentRecorder implements WindowContainerListener { @Override public void onRemoved() { ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Recorded task is removed, so stop recording on display %d", "Content Recording: Recorded task is removed, so stop recording on display %d", mDisplayContent.getDisplayId()); unregisterListener(); Loading Loading @@ -551,8 +558,8 @@ final class ContentRecorder implements WindowContainerListener { mIMediaProjectionManager.stopActiveProjection(); } catch (RemoteException e) { ProtoLog.e(WM_DEBUG_CONTENT_RECORDING, "Unable to tell MediaProjectionManagerService to stop the active " + "projection: %s", "Content Recording: Unable to tell MediaProjectionManagerService to stop " + "the active projection: %s", e); } } Loading @@ -568,8 +575,8 @@ final class ContentRecorder implements WindowContainerListener { height); } catch (RemoteException e) { ProtoLog.e(WM_DEBUG_CONTENT_RECORDING, "Unable to tell MediaProjectionManagerService about resizing the active " + "projection: %s", "Content Recording: Unable to tell MediaProjectionManagerService about " + "resizing the active projection: %s", e); } } Loading @@ -585,8 +592,8 @@ final class ContentRecorder implements WindowContainerListener { isVisible); } catch (RemoteException e) { ProtoLog.e(WM_DEBUG_CONTENT_RECORDING, "Unable to tell MediaProjectionManagerService about visibility change on " + "the active projection: %s", "Content Recording: Unable to tell MediaProjectionManagerService about " + "visibility change on the active projection: %s", e); } } Loading