Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8a87a596 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Ensure task will be attached when starting activity from AppTask

ActivityManager#addAppTask can add a non-attached task into recents.
And then the caller can use ActivityManager.AppTask#startActivity
to launch activity in the task.

The specified task will be mInTask, but before putting activity in it,
the task must attach to hierarchy, otherwise it may cause NPE on random
places by the incomplete launch.

Bug: 227634021
Test: atest ActivityStarterTests#testStartActivityInner_inTask
Change-Id: I66242e2ffa94be19bad49354b5d9cccded17b25c
parent 5e230aef
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -1935,6 +1935,14 @@ class ActivityStarter {
        } else if (mSourceRecord != null) {
            return mSourceRecord.getTask();
        } else if (mInTask != null) {
            // The task is specified from AppTaskImpl, so it may not be attached yet.
            if (!mInTask.isAttached()) {
                // Clear reuse task so it can find a proper parent to add the task.
                if (mReuseTask == mInTask) {
                    mReuseTask = null;
                }
                return getOrCreateRootTask(mStartActivity, mLaunchFlags, mInTask, mOptions);
            }
            return mInTask;
        } else {
            final Task rootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, null /* task */,
+12 −0
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.UserHandle;

/**
@@ -53,6 +55,16 @@ class AppTaskImpl extends IAppTask.Stub {
        }
    }

    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        try {
            return super.onTransact(code, data, reply, flags);
        } catch (RuntimeException e) {
            throw ActivityTaskManagerService.logAndRethrowRuntimeExceptionOnTransact(TAG, e);
        }
    }

    @Override
    public void finishAndRemoveTask() {
        checkCaller();
+38 −72
Original line number Diff line number Diff line
@@ -1139,18 +1139,8 @@ public class ActivityStarterTests extends WindowTestsBase {
                true /* createdByOrganizer */);
        sourceRecord.getTask().addChild(taskFragment, POSITION_TOP);

        starter.startActivityInner(
                /* r */targetRecord,
                /* sourceRecord */ sourceRecord,
                /* voiceSession */null,
                /* voiceInteractor */ null,
                /* startFlags */ 0,
                /* doResume */true,
                /* options */null,
                /* inTask */null,
                /* inTaskFragment */ taskFragment,
                /* restrictedBgActivity */false,
                /* intentGrants */null);
        startActivityInner(starter, targetRecord, sourceRecord, null /* options */,
                null /* inTask */, taskFragment);

        assertFalse(taskFragment.hasChild());
    }
@@ -1167,18 +1157,8 @@ public class ActivityStarterTests extends WindowTestsBase {
        taskFragment.setTaskFragmentOrganizer(mock(TaskFragmentOrganizerToken.class), SYSTEM_UID,
                "system_uid");

        starter.startActivityInner(
                /* r */targetRecord,
                /* sourceRecord */ sourceRecord,
                /* voiceSession */null,
                /* voiceInteractor */ null,
                /* startFlags */ 0,
                /* doResume */true,
                /* options */null,
                /* inTask */null,
                /* inTaskFragment */ taskFragment,
                /* restrictedBgActivity */false,
                /* intentGrants */null);
        startActivityInner(starter, targetRecord, sourceRecord, null /* options */,
                null /* inTask */, taskFragment);

        assertTrue(taskFragment.hasChild());
    }
@@ -1195,18 +1175,8 @@ public class ActivityStarterTests extends WindowTestsBase {
        taskFragment.setTaskFragmentOrganizer(mock(TaskFragmentOrganizerToken.class),
                targetRecord.getUid(), "test_process_name");

        starter.startActivityInner(
                /* r */targetRecord,
                /* sourceRecord */ sourceRecord,
                /* voiceSession */null,
                /* voiceInteractor */ null,
                /* startFlags */ 0,
                /* doResume */true,
                /* options */null,
                /* inTask */null,
                /* inTaskFragment */ taskFragment,
                /* restrictedBgActivity */false,
                /* intentGrants */null);
        startActivityInner(starter, targetRecord, sourceRecord, null /* options */,
                null /* inTask */, taskFragment);

        assertTrue(taskFragment.hasChild());
    }
@@ -1231,18 +1201,8 @@ public class ActivityStarterTests extends WindowTestsBase {
        doReturn(true).when(signingDetails).hasAncestorOrSelfWithDigest(any());
        doReturn(signingDetails).when(androidPackage).getSigningDetails();

        starter.startActivityInner(
                /* r */targetRecord,
                /* sourceRecord */ sourceRecord,
                /* voiceSession */null,
                /* voiceInteractor */ null,
                /* startFlags */ 0,
                /* doResume */true,
                /* options */null,
                /* inTask */null,
                /* inTaskFragment */ taskFragment,
                /* restrictedBgActivity */false,
                /* intentGrants */null);
        startActivityInner(starter, targetRecord, sourceRecord, null /* options */,
                null /* inTask */, taskFragment);

        assertTrue(taskFragment.hasChild());
    }
@@ -1258,22 +1218,29 @@ public class ActivityStarterTests extends WindowTestsBase {

        targetRecord.info.flags |= ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;

        starter.startActivityInner(
                /* r */targetRecord,
                /* sourceRecord */ sourceRecord,
                /* voiceSession */null,
                /* voiceInteractor */ null,
                /* startFlags */ 0,
                /* doResume */true,
                /* options */null,
                /* inTask */null,
                /* inTaskFragment */ taskFragment,
                /* restrictedBgActivity */false,
                /* intentGrants */null);
        startActivityInner(starter, targetRecord, sourceRecord, null /* options */,
                null /* inTask */, taskFragment);

        assertTrue(taskFragment.hasChild());
    }

    @Test
    public void testStartActivityInner_inTask() {
        final ActivityStarter starter = prepareStarter(0, false);
        // Simulate an app uses AppTask to create a non-attached task, and then it requests to
        // start activity in the task.
        final Task inTask = new TaskBuilder(mSupervisor).setTaskDisplayArea(null).setTaskId(123)
                .build();
        inTask.inRecents = true;
        assertFalse(inTask.isAttached());
        final ActivityRecord target = new ActivityBuilder(mAtm).build();
        startActivityInner(starter, target, null /* source */, null /* options */, inTask,
                null /* inTaskFragment */);

        assertTrue(inTask.isAttached());
        assertEquals(inTask, target.getTask());
    }

    @Test
    public void testLaunchCookie_newAndExistingTask() {
        final ActivityStarter starter = prepareStarter(0, false);
@@ -1322,21 +1289,20 @@ public class ActivityStarterTests extends WindowTestsBase {

        // Start the target launch-into-pip activity from a source
        final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build();
        starter.startActivityInner(
                /* r */ targetRecord,
                /* sourceRecord */ sourceRecord,
                /* voiceSession */ null,
                /* voiceInteractor */ null,
                /* startFlags */ 0,
                /* doResume */ true,
                /* options */ opts,
                /* inTask */ null,
                /* inTaskFragment */ null,
                /* restrictedBgActivity */ false,
                /* intentGrants */ null);
        startActivityInner(starter, targetRecord, sourceRecord, opts,
                null /* inTask */, null /* inTaskFragment */);

        // Verify the ActivityRecord#getLaunchIntoPipHostActivity points to sourceRecord.
        assertThat(targetRecord.getLaunchIntoPipHostActivity()).isNotNull();
        assertEquals(targetRecord.getLaunchIntoPipHostActivity(), sourceRecord);
    }

    private static void startActivityInner(ActivityStarter starter, ActivityRecord target,
            ActivityRecord source, ActivityOptions options, Task inTask,
            TaskFragment inTaskFragment) {
        starter.startActivityInner(target, source, null /* voiceSession */,
                null /* voiceInteractor */, 0 /* startFlags */, true /* doResume */,
                options, inTask, inTaskFragment, false /* restrictedBgActivity */,
                null /* intentGrants */);
    }
}