summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Chris Göllner <chrisgollner@google.com> 2023-10-17 14:03:47 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-10-17 14:03:47 +0000
commitc30f220f2af81e189f8185b00979b216c4487439 (patch)
treee29522c5f537f5c2b4b94a1be3f7031c14bd61b4
parent3179901330c40e9be44ec31906489455831a0545 (diff)
parent0af6129bede625eb098327b47f9d789fda256d1a (diff)
Merge "[Media Projection] Add target uid to ContentRecordingSession" into main
-rw-r--r--core/java/android/view/ContentRecordingSession.java111
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java44
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java67
3 files changed, 165 insertions, 57 deletions
diff --git a/core/java/android/view/ContentRecordingSession.java b/core/java/android/view/ContentRecordingSession.java
index a89f79540c65..dc41b70d1683 100644
--- a/core/java/android/view/ContentRecordingSession.java
+++ b/core/java/android/view/ContentRecordingSession.java
@@ -52,6 +52,12 @@ public final class ContentRecordingSession implements Parcelable {
*/
public static final int RECORD_CONTENT_TASK = 1;
+ /** Full screen sharing (app is not selected). */
+ public static final int TARGET_UID_FULL_SCREEN = -1;
+
+ /** Can't report (e.g. side loaded app). */
+ public static final int TARGET_UID_UNKNOWN = -2;
+
/**
* Unique logical identifier of the {@link android.hardware.display.VirtualDisplay} that has
* recorded content rendered to its surface.
@@ -89,27 +95,36 @@ public final class ContentRecordingSession implements Parcelable {
*/
private boolean mWaitingForConsent = false;
+ /** UID of the package that is captured if selected. */
+ private int mTargetUid = TARGET_UID_UNKNOWN;
+
/**
* Default instance, with recording the display.
*/
private ContentRecordingSession() {
}
- /**
- * Returns an instance initialized for recording the indicated display.
- */
+ /** Returns an instance initialized for recording the indicated display. */
public static ContentRecordingSession createDisplaySession(int displayToMirror) {
- return new ContentRecordingSession().setDisplayToRecord(displayToMirror)
- .setContentToRecord(RECORD_CONTENT_DISPLAY);
+ return new ContentRecordingSession()
+ .setDisplayToRecord(displayToMirror)
+ .setContentToRecord(RECORD_CONTENT_DISPLAY)
+ .setTargetUid(TARGET_UID_FULL_SCREEN);
}
- /**
- * Returns an instance initialized for task recording.
- */
+ /** Returns an instance initialized for task recording. */
public static ContentRecordingSession createTaskSession(
@NonNull IBinder taskWindowContainerToken) {
- return new ContentRecordingSession().setContentToRecord(RECORD_CONTENT_TASK)
- .setTokenToRecord(taskWindowContainerToken);
+ return createTaskSession(taskWindowContainerToken, TARGET_UID_UNKNOWN);
+ }
+
+ /** Returns an instance initialized for task recording. */
+ public static ContentRecordingSession createTaskSession(
+ @NonNull IBinder taskWindowContainerToken, int targetUid) {
+ return new ContentRecordingSession()
+ .setContentToRecord(RECORD_CONTENT_TASK)
+ .setTokenToRecord(taskWindowContainerToken)
+ .setTargetUid(targetUid);
}
/**
@@ -175,13 +190,33 @@ public final class ContentRecordingSession implements Parcelable {
}
}
+ @IntDef(prefix = "TARGET_UID_", value = {
+ TARGET_UID_FULL_SCREEN,
+ TARGET_UID_UNKNOWN
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @DataClass.Generated.Member
+ public @interface TargetUid {}
+
+ @DataClass.Generated.Member
+ public static String targetUidToString(@TargetUid int value) {
+ switch (value) {
+ case TARGET_UID_FULL_SCREEN:
+ return "TARGET_UID_FULL_SCREEN";
+ case TARGET_UID_UNKNOWN:
+ return "TARGET_UID_UNKNOWN";
+ default: return Integer.toHexString(value);
+ }
+ }
+
@DataClass.Generated.Member
/* package-private */ ContentRecordingSession(
int virtualDisplayId,
@RecordContent int contentToRecord,
int displayToRecord,
@Nullable IBinder tokenToRecord,
- boolean waitingForConsent) {
+ boolean waitingForConsent,
+ int targetUid) {
this.mVirtualDisplayId = virtualDisplayId;
this.mContentToRecord = contentToRecord;
@@ -196,6 +231,7 @@ public final class ContentRecordingSession implements Parcelable {
this.mDisplayToRecord = displayToRecord;
this.mTokenToRecord = tokenToRecord;
this.mWaitingForConsent = waitingForConsent;
+ this.mTargetUid = targetUid;
// onConstructed(); // You can define this method to get a callback
}
@@ -251,6 +287,14 @@ public final class ContentRecordingSession implements Parcelable {
}
/**
+ * UID of the package that is captured if selected.
+ */
+ @DataClass.Generated.Member
+ public int getTargetUid() {
+ return mTargetUid;
+ }
+
+ /**
* Unique logical identifier of the {@link android.hardware.display.VirtualDisplay} that has
* recorded content rendered to its surface.
*/
@@ -314,6 +358,15 @@ public final class ContentRecordingSession implements Parcelable {
return this;
}
+ /**
+ * UID of the package that is captured if selected.
+ */
+ @DataClass.Generated.Member
+ public @NonNull ContentRecordingSession setTargetUid( int value) {
+ mTargetUid = value;
+ return this;
+ }
+
@Override
@DataClass.Generated.Member
public String toString() {
@@ -325,7 +378,8 @@ public final class ContentRecordingSession implements Parcelable {
"contentToRecord = " + recordContentToString(mContentToRecord) + ", " +
"displayToRecord = " + mDisplayToRecord + ", " +
"tokenToRecord = " + mTokenToRecord + ", " +
- "waitingForConsent = " + mWaitingForConsent +
+ "waitingForConsent = " + mWaitingForConsent + ", " +
+ "targetUid = " + mTargetUid +
" }";
}
@@ -346,7 +400,8 @@ public final class ContentRecordingSession implements Parcelable {
&& mContentToRecord == that.mContentToRecord
&& mDisplayToRecord == that.mDisplayToRecord
&& java.util.Objects.equals(mTokenToRecord, that.mTokenToRecord)
- && mWaitingForConsent == that.mWaitingForConsent;
+ && mWaitingForConsent == that.mWaitingForConsent
+ && mTargetUid == that.mTargetUid;
}
@Override
@@ -361,6 +416,7 @@ public final class ContentRecordingSession implements Parcelable {
_hash = 31 * _hash + mDisplayToRecord;
_hash = 31 * _hash + java.util.Objects.hashCode(mTokenToRecord);
_hash = 31 * _hash + Boolean.hashCode(mWaitingForConsent);
+ _hash = 31 * _hash + mTargetUid;
return _hash;
}
@@ -378,6 +434,7 @@ public final class ContentRecordingSession implements Parcelable {
dest.writeInt(mContentToRecord);
dest.writeInt(mDisplayToRecord);
if (mTokenToRecord != null) dest.writeStrongBinder(mTokenToRecord);
+ dest.writeInt(mTargetUid);
}
@Override
@@ -397,6 +454,7 @@ public final class ContentRecordingSession implements Parcelable {
int contentToRecord = in.readInt();
int displayToRecord = in.readInt();
IBinder tokenToRecord = (flg & 0x8) == 0 ? null : (IBinder) in.readStrongBinder();
+ int targetUid = in.readInt();
this.mVirtualDisplayId = virtualDisplayId;
this.mContentToRecord = contentToRecord;
@@ -412,6 +470,7 @@ public final class ContentRecordingSession implements Parcelable {
this.mDisplayToRecord = displayToRecord;
this.mTokenToRecord = tokenToRecord;
this.mWaitingForConsent = waitingForConsent;
+ this.mTargetUid = targetUid;
// onConstructed(); // You can define this method to get a callback
}
@@ -442,6 +501,7 @@ public final class ContentRecordingSession implements Parcelable {
private int mDisplayToRecord;
private @Nullable IBinder mTokenToRecord;
private boolean mWaitingForConsent;
+ private int mTargetUid;
private long mBuilderFieldsSet = 0L;
@@ -513,10 +573,21 @@ public final class ContentRecordingSession implements Parcelable {
return this;
}
+ /**
+ * UID of the package that is captured if selected.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setTargetUid(int value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x20;
+ mTargetUid = value;
+ return this;
+ }
+
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull ContentRecordingSession build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x20; // Mark builder used
+ mBuilderFieldsSet |= 0x40; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
mVirtualDisplayId = INVALID_DISPLAY;
@@ -533,17 +604,21 @@ public final class ContentRecordingSession implements Parcelable {
if ((mBuilderFieldsSet & 0x10) == 0) {
mWaitingForConsent = false;
}
+ if ((mBuilderFieldsSet & 0x20) == 0) {
+ mTargetUid = TARGET_UID_UNKNOWN;
+ }
ContentRecordingSession o = new ContentRecordingSession(
mVirtualDisplayId,
mContentToRecord,
mDisplayToRecord,
mTokenToRecord,
- mWaitingForConsent);
+ mWaitingForConsent,
+ mTargetUid);
return o;
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x20) != 0) {
+ if ((mBuilderFieldsSet & 0x40) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
@@ -551,10 +626,10 @@ public final class ContentRecordingSession implements Parcelable {
}
@DataClass.Generated(
- time = 1683628463074L,
+ time = 1697456140720L,
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 mVirtualDisplayId\nprivate @android.view.ContentRecordingSession.RecordContent int mContentToRecord\nprivate int mDisplayToRecord\nprivate @android.annotation.Nullable android.os.IBinder mTokenToRecord\nprivate boolean mWaitingForConsent\npublic static android.view.ContentRecordingSession createDisplaySession(int)\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)")
+ inputSignatures = "public static final int RECORD_CONTENT_DISPLAY\npublic static final int RECORD_CONTENT_TASK\npublic static final int TARGET_UID_FULL_SCREEN\npublic static final int TARGET_UID_UNKNOWN\nprivate int mVirtualDisplayId\nprivate @android.view.ContentRecordingSession.RecordContent int mContentToRecord\nprivate int mDisplayToRecord\nprivate @android.annotation.Nullable android.os.IBinder mTokenToRecord\nprivate boolean mWaitingForConsent\nprivate int mTargetUid\npublic static android.view.ContentRecordingSession createDisplaySession(int)\npublic static android.view.ContentRecordingSession createTaskSession(android.os.IBinder)\npublic static android.view.ContentRecordingSession createTaskSession(android.os.IBinder,int)\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() {}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9663f3aba7f1..88f72f9dbc90 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -8461,16 +8461,18 @@ public class WindowManagerService extends IWindowManager.Stub
return true;
}
// For a task session, find the activity identified by the launch cookie.
- final WindowContainerToken wct = getTaskWindowContainerTokenForLaunchCookie(
+ final WindowContainerInfo wci = getTaskWindowContainerInfoForLaunchCookie(
incomingSession.getTokenToRecord());
- if (wct == null) {
+ if (wci == null) {
Slog.w(TAG, "Handling a new recording session; unable to find the "
+ "WindowContainerToken");
return false;
}
// Replace the launch cookie in the session details with the task's
// WindowContainerToken.
- incomingSession.setTokenToRecord(wct.asBinder());
+ incomingSession.setTokenToRecord(wci.getToken().asBinder());
+ // Also replace the UNKNOWN target UID with the actual UID.
+ incomingSession.setTargetUid(wci.getUid());
mContentRecordingController.setContentRecordingSessionLocked(incomingSession,
WindowManagerService.this);
return true;
@@ -8798,21 +8800,41 @@ public class WindowManagerService extends IWindowManager.Stub
mAtmService.setFocusedTask(task.mTaskId, touchedActivity);
}
+ @VisibleForTesting
+ static class WindowContainerInfo {
+ private final int mUid;
+ @NonNull private final WindowContainerToken mToken;
+
+ private WindowContainerInfo(int uid, @NonNull WindowContainerToken token) {
+ this.mUid = uid;
+ this.mToken = token;
+ }
+
+ public int getUid() {
+ return mUid;
+ }
+
+ @NonNull
+ public WindowContainerToken getToken() {
+ return mToken;
+ }
+ }
+
/**
- * Retrieve the {@link WindowContainerToken} of the task that contains the activity started
- * with the given launch cookie.
+ * Retrieve the {@link WindowContainerInfo} of the task that contains the activity started with
+ * the given launch cookie.
*
* @param launchCookie the launch cookie set on the {@link ActivityOptions} when starting an
- * activity
+ * activity
* @return a token representing the task containing the activity started with the given launch
- * cookie, or {@code null} if the token couldn't be found.
+ * cookie, or {@code null} if the token couldn't be found.
*/
@VisibleForTesting
@Nullable
- WindowContainerToken getTaskWindowContainerTokenForLaunchCookie(@NonNull IBinder launchCookie) {
+ WindowContainerInfo getTaskWindowContainerInfoForLaunchCookie(@NonNull IBinder launchCookie) {
// Find the activity identified by the launch cookie.
- final ActivityRecord targetActivity = mRoot.getActivity(
- activity -> activity.mLaunchCookie == launchCookie);
+ final ActivityRecord targetActivity =
+ mRoot.getActivity(activity -> activity.mLaunchCookie == launchCookie);
if (targetActivity == null) {
Slog.w(TAG, "Unable to find the activity for this launch cookie");
return null;
@@ -8827,7 +8849,7 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.w(TAG, "Unable to find the WindowContainerToken for " + targetActivity.getName());
return null;
}
- return taskWindowContainerToken;
+ return new WindowContainerInfo(targetActivity.getUid(), taskWindowContainerToken);
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index e86fc366a631..eaeb8049b81a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -100,6 +100,9 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.AdoptShellPermissionsRule;
import com.android.internal.os.IResultReceiver;
import com.android.server.LocalServices;
+import com.android.server.wm.WindowManagerService.WindowContainerInfo;
+
+import com.google.common.truth.Expect;
import org.junit.Rule;
import org.junit.Test;
@@ -125,6 +128,9 @@ public class WindowManagerServiceTests extends WindowTestsBase {
InstrumentationRegistry.getInstrumentation().getUiAutomation(),
ADD_TRUSTED_DISPLAY);
+ @Rule
+ public Expect mExpect = Expect.create();
+
@Test
public void testIsRequestedOrientationMapped() {
mWm.setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled*/ true,
@@ -674,64 +680,68 @@ public class WindowManagerServiceTests extends WindowTestsBase {
@Test
public void testGetTaskWindowContainerTokenForLaunchCookie_nullCookie() {
- WindowContainerToken wct = mWm.getTaskWindowContainerTokenForLaunchCookie(null);
- assertThat(wct).isNull();
+ WindowContainerInfo wci = mWm.getTaskWindowContainerInfoForLaunchCookie(null);
+ assertThat(wci).isNull();
}
@Test
public void testGetTaskWindowContainerTokenForLaunchCookie_invalidCookie() {
Binder cookie = new Binder("test cookie");
- WindowContainerToken wct = mWm.getTaskWindowContainerTokenForLaunchCookie(cookie);
- assertThat(wct).isNull();
+ WindowContainerInfo wci = mWm.getTaskWindowContainerInfoForLaunchCookie(cookie);
+ assertThat(wci).isNull();
final ActivityRecord testActivity = new ActivityBuilder(mAtm)
.setCreateTask(true)
.build();
- wct = mWm.getTaskWindowContainerTokenForLaunchCookie(cookie);
- assertThat(wct).isNull();
+ wci = mWm.getTaskWindowContainerInfoForLaunchCookie(cookie);
+ assertThat(wci).isNull();
}
@Test
public void testGetTaskWindowContainerTokenForLaunchCookie_validCookie() {
final Binder cookie = new Binder("ginger cookie");
final WindowContainerToken launchRootTask = mock(WindowContainerToken.class);
- setupActivityWithLaunchCookie(cookie, launchRootTask);
+ final int uid = 123;
+ setupActivityWithLaunchCookie(cookie, launchRootTask, uid);
- WindowContainerToken wct = mWm.getTaskWindowContainerTokenForLaunchCookie(cookie);
- assertThat(wct).isEqualTo(launchRootTask);
+ WindowContainerInfo wci = mWm.getTaskWindowContainerInfoForLaunchCookie(cookie);
+ mExpect.that(wci.getToken()).isEqualTo(launchRootTask);
+ mExpect.that(wci.getUid()).isEqualTo(uid);
}
@Test
public void testGetTaskWindowContainerTokenForLaunchCookie_multipleCookies() {
final Binder cookie1 = new Binder("ginger cookie");
final WindowContainerToken launchRootTask1 = mock(WindowContainerToken.class);
- setupActivityWithLaunchCookie(cookie1, launchRootTask1);
+ final int uid1 = 123;
+ setupActivityWithLaunchCookie(cookie1, launchRootTask1, uid1);
setupActivityWithLaunchCookie(new Binder("choc chip cookie"),
- mock(WindowContainerToken.class));
+ mock(WindowContainerToken.class), /* uid= */ 456);
setupActivityWithLaunchCookie(new Binder("peanut butter cookie"),
- mock(WindowContainerToken.class));
+ mock(WindowContainerToken.class), /* uid= */ 789);
- WindowContainerToken wct = mWm.getTaskWindowContainerTokenForLaunchCookie(cookie1);
- assertThat(wct).isEqualTo(launchRootTask1);
+ WindowContainerInfo wci = mWm.getTaskWindowContainerInfoForLaunchCookie(cookie1);
+ mExpect.that(wci.getToken()).isEqualTo(launchRootTask1);
+ mExpect.that(wci.getUid()).isEqualTo(uid1);
}
@Test
public void testGetTaskWindowContainerTokenForLaunchCookie_multipleCookies_noneValid() {
setupActivityWithLaunchCookie(new Binder("ginger cookie"),
- mock(WindowContainerToken.class));
+ mock(WindowContainerToken.class), /* uid= */ 123);
setupActivityWithLaunchCookie(new Binder("choc chip cookie"),
- mock(WindowContainerToken.class));
+ mock(WindowContainerToken.class), /* uid= */ 456);
setupActivityWithLaunchCookie(new Binder("peanut butter cookie"),
- mock(WindowContainerToken.class));
+ mock(WindowContainerToken.class), /* uid= */ 789);
- WindowContainerToken wct = mWm.getTaskWindowContainerTokenForLaunchCookie(
+ WindowContainerInfo wci = mWm.getTaskWindowContainerInfoForLaunchCookie(
new Binder("some other cookie"));
- assertThat(wct).isNull();
+ assertThat(wci).isNull();
}
@Test
@@ -778,17 +788,18 @@ public class WindowManagerServiceTests extends WindowTestsBase {
}
@Test
- public void setContentRecordingSession_matchingTask_mutatesSessionWithWindowContainerToken() {
+ public void setContentRecordingSession_matchingTask_mutatesSessionWithWindowContainerInfo() {
WindowManagerInternal wmInternal = LocalServices.getService(WindowManagerInternal.class);
Task task = createTask(mDefaultDisplay);
ActivityRecord activityRecord = createActivityRecord(task);
- ContentRecordingSession session = ContentRecordingSession.createTaskSession(
- activityRecord.mLaunchCookie);
+ ContentRecordingSession session =
+ ContentRecordingSession.createTaskSession(activityRecord.mLaunchCookie);
wmInternal.setContentRecordingSession(session);
- assertThat(session.getTokenToRecord()).isEqualTo(
- task.mRemoteToken.toWindowContainerToken().asBinder());
+ mExpect.that(session.getTokenToRecord())
+ .isEqualTo(task.mRemoteToken.toWindowContainerToken().asBinder());
+ mExpect.that(session.getTargetUid()).isEqualTo(activityRecord.getUid());
}
@Test
@@ -1010,12 +1021,12 @@ public class WindowManagerServiceTests extends WindowTestsBase {
}
}
- private void setupActivityWithLaunchCookie(IBinder launchCookie, WindowContainerToken wct) {
+ private void setupActivityWithLaunchCookie(
+ IBinder launchCookie, WindowContainerToken wct, int uid) {
final WindowContainer.RemoteToken remoteToken = mock(WindowContainer.RemoteToken.class);
when(remoteToken.toWindowContainerToken()).thenReturn(wct);
- final ActivityRecord testActivity = new ActivityBuilder(mAtm)
- .setCreateTask(true)
- .build();
+ final ActivityRecord testActivity =
+ new ActivityBuilder(mAtm).setCreateTask(true).setUid(uid).build();
testActivity.mLaunchCookie = launchCookie;
testActivity.getTask().mRemoteToken = remoteToken;
}