From 1d00930552cc4f86e4bd6db3525d6df05f5b3b82 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 --- .../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 530fa4d6d4970..12424c0c6a6f5 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -3317,9 +3317,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); } @@ -4630,7 +4638,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 5938e7f095ea5..0b16a4d47a7d9 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -78,7 +78,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; @@ -2777,11 +2776,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 91cb037a386ed..d3a3cf5c6468e 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -172,13 +172,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 @@ -189,7 +182,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 {} @@ -616,14 +608,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 1ab7d7e0c81b6..a410eedf4c299 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 = createTaskFragmentWithActivity(task); + final TaskFragment taskFragment2 = createTaskFragmentWithActivity(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 4e796c55dda21..8fda1917d0b5e 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; @@ -475,23 +472,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