diff options
5 files changed, 99 insertions, 10 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 5a1eed8897b6..5b697ee89602 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2700,7 +2700,8 @@ class ActivityStarter { || mPreferredDisplayId != DEFAULT_DISPLAY) { final boolean onTop = aOptions == null || !aOptions.getAvoidMoveToFront(); final ActivityStack stack = - mRootActivityContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams); + mRootActivityContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams, + mRequest.realCallingPid, mRequest.realCallingUid); return stack; } // Otherwise handle adjacent launch. @@ -2818,11 +2819,24 @@ class ActivityStarter { return this; } + /** + * Sets the pid of the caller who originally started the activity. + * + * Normally, the pid/uid would be the calling pid from the binder call. + * However, in case of a {@link PendingIntent}, the pid/uid pair of the caller is considered + * the original entity that created the pending intent, in contrast to setRealCallingPid/Uid, + * which represents the entity who invoked pending intent via {@link PendingIntent#send}. + */ ActivityStarter setCallingPid(int pid) { mRequest.callingPid = pid; return this; } + /** + * Sets the uid of the caller who originally started the activity. + * + * @see #setCallingPid + */ ActivityStarter setCallingUid(int uid) { mRequest.callingUid = uid; return this; @@ -2833,11 +2847,25 @@ class ActivityStarter { return this; } + /** + * Sets the pid of the caller who requested to launch the activity. + * + * The pid/uid represents the caller who launches the activity in this request. + * It will almost same as setCallingPid/Uid except when processing {@link PendingIntent}: + * the pid/uid will be the caller who called {@link PendingIntent#send()}. + * + * @see #setCallingPid + */ ActivityStarter setRealCallingPid(int pid) { mRequest.realCallingPid = pid; return this; } + /** + * Sets the uid of the caller who requested to launch the activity. + * + * @see #setRealCallingPid + */ ActivityStarter setRealCallingUid(int uid) { mRequest.realCallingUid = uid; return this; diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java index 2e3094a6b554..d895e271e8fc 100644 --- a/services/core/java/com/android/server/wm/RootActivityContainer.java +++ b/services/core/java/com/android/server/wm/RootActivityContainer.java @@ -1667,7 +1667,8 @@ class RootActivityContainer extends ConfigurationContainer <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop) { - return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */); + return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */, + -1 /* no realCallingPid */, -1 /* no realCallingUid */); } /** @@ -1676,13 +1677,16 @@ class RootActivityContainer extends ConfigurationContainer * @param r The activity we are trying to launch. Can be null. * @param options The activity options used to the launch. Can be null. * @param candidateTask The possible task the activity might be launched in. Can be null. - * @params launchParams The resolved launch params to use. + * @param launchParams The resolved launch params to use. + * @param realCallingPid The pid from {@link ActivityStarter#setRealCallingPid} + * @param realCallingUid The uid from {@link ActivityStarter#setRealCallingUid} * * @return The stack to use for the launch or INVALID_STACK_ID. */ <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop, - @Nullable LaunchParamsController.LaunchParams launchParams) { + @Nullable LaunchParamsController.LaunchParams launchParams, int realCallingPid, + int realCallingUid) { int taskId = INVALID_TASK_ID; int displayId = INVALID_DISPLAY; //Rect bounds = null; @@ -1713,7 +1717,14 @@ class RootActivityContainer extends ConfigurationContainer if (launchParams != null && launchParams.mPreferredDisplayId != INVALID_DISPLAY) { displayId = launchParams.mPreferredDisplayId; } - if (displayId != INVALID_DISPLAY && canLaunchOnDisplay(r, displayId)) { + final boolean canLaunchOnDisplayFromStartRequest = + realCallingPid != 0 && realCallingUid > 0 && r != null + && mStackSupervisor.canPlaceEntityOnDisplay(displayId, realCallingPid, + realCallingUid, r.info); + // Checking if the activity's launch caller, or the realCallerId of the activity from + // start request (i.e. PendingIntent caller) is allowed to launch on the display. + if (displayId != INVALID_DISPLAY && (canLaunchOnDisplay(r, displayId) + || canLaunchOnDisplayFromStartRequest)) { if (r != null) { stack = (T) getValidLaunchStackOnDisplay(displayId, r, candidateTask, options, launchParams); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 3d944671ef25..07d9f803d9fa 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -341,7 +341,7 @@ public class ActivityStarterTests extends ActivityTestsBase { doReturn(stack).when(mRootActivityContainer) .getLaunchStack(any(), any(), any(), anyBoolean()); doReturn(stack).when(mRootActivityContainer) - .getLaunchStack(any(), any(), any(), anyBoolean(), any()); + .getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt()); } // Set up mock package manager internal and make sure no unmocked methods are called diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index ecf3acd32d4f..e1c6cf2eb58f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -204,6 +204,8 @@ class ActivityTestsBase { private ActivityStack mStack; private int mActivityFlags; private int mLaunchMode; + private int mLaunchedFromPid; + private int mLaunchedFromUid; ActivityBuilder(ActivityTaskManagerService service) { mService = service; @@ -254,6 +256,16 @@ class ActivityTestsBase { return this; } + ActivityBuilder setLaunchedFromPid(int pid) { + mLaunchedFromPid = pid; + return this; + } + + ActivityBuilder setLaunchedFromUid(int uid) { + mLaunchedFromUid = uid; + return this; + } + ActivityRecord build() { if (mComponent == null) { final int id = sCurrentActivityId++; @@ -281,10 +293,11 @@ class ActivityTestsBase { aInfo.launchMode = mLaunchMode; final ActivityRecord activity = new ActivityRecord(mService, null /* caller */, - 0 /* launchedFromPid */, 0, null, intent, null, - aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */, - 0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */, - mService.mStackSupervisor, null /* options */, null /* sourceRecord */); + mLaunchedFromPid /* launchedFromPid */, mLaunchedFromUid /* launchedFromUid */, + null, intent, null, aInfo /*aInfo*/, new Configuration(), null /* resultTo */, + null /* resultWho */, 0 /* reqCode */, false /*componentSpecified*/, + false /* rootVoiceInteraction */, mService.mStackSupervisor, + null /* options */, null /* sourceRecord */); spyOn(activity); activity.mAppWindowToken = mock(AppWindowToken.class); doCallRealMethod().when(activity.mAppWindowToken).getOrientationIgnoreVisibility(); diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index 8d2c3dd80538..baf1b0821982 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -25,6 +25,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.TYPE_VIRTUAL; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; @@ -61,6 +62,7 @@ import android.content.res.Resources; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.util.Pair; +import android.view.DisplayInfo; import androidx.test.filters.MediumTest; @@ -817,6 +819,41 @@ public class RootActivityContainerTests extends ActivityTestsBase { } /** + * Test that {@link RootActivityContainer#getLaunchStack} with the real caller id will get the + * expected stack when requesting the activity launch on the secondary display. + */ + @Test + public void testGetLaunchStackWithRealCallerId() { + // Create a non-system owned virtual display. + final DisplayInfo info = new DisplayInfo(); + mSupervisor.mService.mContext.getDisplay().getDisplayInfo(info); + info.type = TYPE_VIRTUAL; + info.ownerUid = 100; + final TestActivityDisplay secondaryDisplay = createNewActivityDisplay(info); + mRootActivityContainer.addChild(secondaryDisplay, POSITION_TOP); + + // Create an activity with specify the original launch pid / uid. + final ActivityRecord r = new ActivityBuilder(mService).setLaunchedFromPid(200) + .setLaunchedFromUid(200).build(); + + // Simulate ActivityStarter to find a launch stack for requesting the activity to launch + // on the secondary display with realCallerId. + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchDisplayId(secondaryDisplay.mDisplayId); + options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); + doReturn(true).when(mSupervisor).canPlaceEntityOnDisplay(secondaryDisplay.mDisplayId, + 300 /* test realCallerPid */, 300 /* test realCallerUid */, r.info); + final ActivityStack result = mRootActivityContainer.getLaunchStack(r, options, + null /* task */, true /* onTop */, null, 300 /* test realCallerPid */, + 300 /* test realCallerUid */); + + // Assert that the stack is returned as expected. + assertNotNull(result); + assertEquals("The display ID of the stack should same as secondary display ", + secondaryDisplay.mDisplayId, result.mDisplayId); + } + + /** * Mock {@link RootActivityContainerTests#resolveHomeActivity} for returning consistent activity * info for test cases (the original implementation will resolve from the real package manager). */ |