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
This commit is contained in:
Riddle Hsu
2022-04-01 18:40:59 +08:00
parent 5e230aef5e
commit 8a87a596a2
3 changed files with 58 additions and 72 deletions

View File

@@ -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 */,

View File

@@ -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();

View File

@@ -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 */);
}
}