From 8b3209a300d25d6c0dab148f93f20a80b6d1ae46 Mon Sep 17 00:00:00 2001 From: Louis Chang Date: Thu, 24 Nov 2022 07:29:41 +0000 Subject: [PATCH] Allow starting activity for result on another TaskFragment ...but still in the same Task. This is only possible when enabling ActivityEmbedding. Meanwhile, the result should be sent immediately if the result-to activity is in the RESUMED state. Bug: 253387076 Test: atest TaskFragmentTest ActivityRecordTests Change-Id: I9049e8cb2329836ac2661aa6ead679ffc838c3b8 Merged-In: I9049e8cb2329836ac2661aa6ead679ffc838c3b8 --- .../com/android/server/wm/ActivityRecord.java | 16 +++++++++++---- .../android/server/wm/ActivityStarter.java | 6 ------ .../com/android/server/wm/TaskFragment.java | 16 --------------- .../server/wm/ActivityRecordTests.java | 19 ++++++++++++++++++ .../android/server/wm/TaskFragmentTest.java | 20 ------------------- 5 files changed, 31 insertions(+), 46 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 66992aa79fc27..d499858024f24 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -3327,9 +3327,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(resultGrants, resultTo.getUriPermissionsLocked()); } - if (mForceSendResultForMediaProjection) { - resultTo.sendResult(this.getUid(), resultWho, requestCode, resultCode, - resultData, resultGrants, true /* forceSendForMediaProjection */); + if (mForceSendResultForMediaProjection || resultTo.isState(RESUMED)) { + // Sending the result to the resultTo activity asynchronously to prevent the + // resultTo activity getting results before this Activity paused. + final ActivityRecord resultToActivity = resultTo; + mAtmService.mH.post(() -> { + synchronized (mAtmService.mGlobalLock) { + resultToActivity.sendResult(this.getUid(), resultWho, requestCode, + resultCode, resultData, resultGrants, + mForceSendResultForMediaProjection); + } + }); } else { resultTo.addResultLocked(this, resultWho, requestCode, resultCode, resultData); } @@ -4640,7 +4648,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A false /* forceSendForMediaProjection */); } - private void sendResult(int callingUid, String resultWho, int requestCode, int resultCode, + void sendResult(int callingUid, String resultWho, int requestCode, int resultCode, Intent data, NeededUriGrants dataGrants, boolean forceSendForMediaProjection) { if (callingUid > 0) { mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(dataGrants, diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index a3554cd32ba22..d2422f378d814 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -83,7 +83,6 @@ import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT; import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED; import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION; import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK; -import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT; import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST; import static com.android.server.wm.WindowContainer.POSITION_TOP; @@ -3069,11 +3068,6 @@ class ActivityStarter { errMsg = "The app:" + mCallingUid + "is not trusted to " + mStartActivity; break; } - case EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT: { - errMsg = "Cannot embed activity across TaskFragments for result, resultTo: " - + mStartActivity.resultTo; - break; - } default: errMsg = "Unhandled embed result:" + result; } diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 7cac01faf1a0c..eac41eac1d03a 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -170,13 +170,6 @@ class TaskFragment extends WindowContainer { * indicate that an Activity can't be embedded because the Activity is started on a new task. */ static final int EMBEDDING_DISALLOWED_NEW_TASK = 3; - /** - * An embedding check result of - * {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}: - * indicate that an Activity can't be embedded because the Activity is started on a new - * TaskFragment, e.g. start an Activity on a new TaskFragment for result. - */ - static final int EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT = 4; /** * Embedding check results of {@link #isAllowedToEmbedActivity(ActivityRecord)} or @@ -187,7 +180,6 @@ class TaskFragment extends WindowContainer { EMBEDDING_DISALLOWED_UNTRUSTED_HOST, EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION, EMBEDDING_DISALLOWED_NEW_TASK, - EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT, }) @interface EmbeddingCheckResult {} @@ -614,14 +606,6 @@ class TaskFragment extends WindowContainer { return EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION; } - // Cannot embed activity across TaskFragments for activity result. - // If the activity that started for result is finishing, it's likely that this start mode - // is used to place an activity in the same task. Since the finishing activity won't be - // able to get the results, so it's OK to embed in a different TaskFragment. - if (a.resultTo != null && !a.resultTo.finishing && a.resultTo.getTaskFragment() != this) { - return EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT; - } - return EMBEDDING_ALLOWED; } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index d3e638f10c54a..53e0b2b7a615d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -1206,6 +1206,25 @@ public class ActivityRecordTests extends WindowTestsBase { } } + @Test + public void testFinishActivityIfPossible_sendResultImmediatelyIfResumed() { + final Task task = new TaskBuilder(mSupervisor).build(); + final TaskFragment taskFragment1 = createTaskFragmentWithParentTask(task); + final TaskFragment taskFragment2 = createTaskFragmentWithParentTask(task); + final ActivityRecord resultToActivity = taskFragment1.getTopMostActivity(); + final ActivityRecord targetActivity = taskFragment2.getTopMostActivity(); + resultToActivity.setState(RESUMED, "test"); + targetActivity.setState(RESUMED, "test"); + targetActivity.resultTo = resultToActivity; + + clearInvocations(mAtm.getLifecycleManager()); + targetActivity.finishIfPossible(0, new Intent(), null, "test", false /* oomAdj */); + waitUntilHandlersIdle(); + + verify(resultToActivity).sendResult(anyInt(), eq(null), anyInt(), anyInt(), any(), eq(null), + anyBoolean()); + } + /** * Verify that complete finish request for non-finishing activity is invalid. */ diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java index 97e5755fec02f..38a712ed04355 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java @@ -24,7 +24,6 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; -import static android.os.Process.FIRST_APPLICATION_UID; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; @@ -33,9 +32,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.ActivityRecord.State.RESUMED; -import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED; import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION; -import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT; import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST; import static com.android.server.wm.WindowContainer.POSITION_TOP; @@ -477,23 +474,6 @@ public class TaskFragmentTest extends WindowTestsBase { doReturn(true).when(taskFragment).smallerThanMinDimension(any()); assertEquals(EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION, taskFragment.isAllowedToEmbedActivity(activity)); - - // Not allow to start activity across TaskFragments for result. - final TaskFragment newTaskFragment = new TaskFragmentBuilder(mAtm) - .setParentTask(taskFragment.getTask()) - .build(); - final ActivityRecord newActivity = new ActivityBuilder(mAtm) - .setUid(FIRST_APPLICATION_UID) - .build(); - doReturn(true).when(newTaskFragment).isAllowedToEmbedActivityInTrustedMode(any(), anyInt()); - doReturn(false).when(newTaskFragment).smallerThanMinDimension(any()); - newActivity.resultTo = activity; - assertEquals(EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT, - newTaskFragment.isAllowedToEmbedActivity(newActivity)); - - // Allow embedding if the resultTo activity is finishing. - activity.finishing = true; - assertEquals(EMBEDDING_ALLOWED, newTaskFragment.isAllowedToEmbedActivity(newActivity)); } @Test