Provide alternative find-task method without ActivityRecord

Restructure the task looks-up methods to allow finding tasks
without passing in an ActivityRecord. This opens the opportunity
of looking reusable tasks before building an ActivityRecord, which
is the first step of stand-in activity replacement.

Bug: 175354896
Test: presubmit
Change-Id: Ic769790f0e5cbc921e144e1bb3d696519fc13555
This commit is contained in:
Louis Chang
2020-12-17 15:32:22 +08:00
parent 465e654ae4
commit 4bce80f1f3
5 changed files with 91 additions and 115 deletions

View File

@@ -49,12 +49,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
"-2062338592": {
"message": "Looking for task of %s",
"level": "DEBUG",
"group": "WM_DEBUG_TASKS",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
"-2054442123": {
"message": "Setting Intent of %s to %s",
"level": "VERBOSE",
@@ -475,6 +469,12 @@
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/Transition.java"
},
"-1559645910": {
"message": "Looking for task of type=%s, taskAffinity=%s, intent=%s, info=%s, preferredTDA=%s",
"level": "DEBUG",
"group": "WM_DEBUG_TASKS",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
"-1558137010": {
"message": "Config is relaunching invisible activity %s called by %s",
"level": "VERBOSE",
@@ -1531,6 +1531,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
"-373110070": {
"message": "Skipping task: (mismatch activity\/task) %s",
"level": "DEBUG",
"group": "WM_DEBUG_TASKS",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
"-354571697": {
"message": "Existence Changed in transition %d: %s",
"level": "VERBOSE",

View File

@@ -547,19 +547,16 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
return activityType == ACTIVITY_TYPE_STANDARD || activityType == ACTIVITY_TYPE_UNDEFINED;
}
public boolean hasCompatibleActivityType(ConfigurationContainer other) {
/*@WindowConfiguration.ActivityType*/ int thisType = getActivityType();
/*@WindowConfiguration.ActivityType*/ int otherType = other.getActivityType();
if (thisType == otherType) {
public static boolean isCompatibleActivityType(int currentType, int otherType) {
if (currentType == otherType) {
return true;
}
if (thisType == ACTIVITY_TYPE_ASSISTANT) {
if (currentType == ACTIVITY_TYPE_ASSISTANT) {
// Assistant activities are only compatible with themselves...
return false;
}
// Otherwise we are compatible if us or other is not currently defined.
return thisType == ACTIVITY_TYPE_UNDEFINED || otherType == ACTIVITY_TYPE_UNDEFINED;
return currentType == ACTIVITY_TYPE_UNDEFINED || otherType == ACTIVITY_TYPE_UNDEFINED;
}
/**

View File

@@ -306,52 +306,54 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
static class FindTaskResult implements Function<Task, Boolean> {
ActivityRecord mRecord;
boolean mIdealMatch;
ActivityRecord mIdealRecord;
ActivityRecord mCandidateRecord;
private ActivityRecord mTarget;
private Intent intent;
private ActivityInfo info;
private int mActivityType;
private String mTaskAffinity;
private Intent mIntent;
private ActivityInfo mInfo;
private ComponentName cls;
private int userId;
private boolean isDocument;
private Uri documentData;
void init(int activityType, String taskAffinity, Intent intent, ActivityInfo info) {
mActivityType = activityType;
mTaskAffinity = taskAffinity;
mIntent = intent;
mInfo = info;
mIdealRecord = null;
mCandidateRecord = null;
}
/**
* Returns the top activity in any existing task matching the given Intent in the input
* result. Returns null if no such task is found.
*/
void process(ActivityRecord target, Task parent) {
mTarget = target;
intent = target.intent;
info = target.info;
cls = intent.getComponent();
if (info.targetActivity != null) {
cls = new ComponentName(info.packageName, info.targetActivity);
void process(WindowContainer parent) {
cls = mIntent.getComponent();
if (mInfo.targetActivity != null) {
cls = new ComponentName(mInfo.packageName, mInfo.targetActivity);
}
userId = UserHandle.getUserId(info.applicationInfo.uid);
isDocument = intent != null & intent.isDocument();
userId = UserHandle.getUserId(mInfo.applicationInfo.uid);
isDocument = mIntent != null & mIntent.isDocument();
// If documentData is non-null then it must match the existing task data.
documentData = isDocument ? intent.getData() : null;
documentData = isDocument ? mIntent.getData() : null;
ProtoLog.d(WM_DEBUG_TASKS, "Looking for task of %s in %s", target,
ProtoLog.d(WM_DEBUG_TASKS, "Looking for task of %s in %s", mInfo,
parent);
parent.forAllLeafTasks(this);
}
void clear() {
mRecord = null;
mIdealMatch = false;
}
void setTo(FindTaskResult result) {
mRecord = result.mRecord;
mIdealMatch = result.mIdealMatch;
}
@Override
public Boolean apply(Task task) {
if (!ConfigurationContainer.isCompatibleActivityType(mActivityType,
task.getActivityType())) {
ProtoLog.d(WM_DEBUG_TASKS, "Skipping task: (mismatch activity/task) %s", task);
return false;
}
if (task.voiceSession != null) {
// We never match voice sessions; those always run independently.
ProtoLog.d(WM_DEBUG_TASKS, "Skipping %s: voice session", task);
@@ -370,7 +372,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
ProtoLog.d(WM_DEBUG_TASKS, "Skipping %s: mismatch root %s", task, r);
return false;
}
if (!r.hasCompatibleActivityType(mTarget)) {
if (!ConfigurationContainer.isCompatibleActivityType(r.getActivityType(),
mActivityType)) {
ProtoLog.d(WM_DEBUG_TASKS, "Skipping %s: mismatch activity type", task);
return false;
}
@@ -391,35 +394,33 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
ProtoLog.d(WM_DEBUG_TASKS, "Comparing existing cls=%s /aff=%s to new cls=%s /aff=%s",
r.getTask().rootAffinity, intent.getComponent().flattenToShortString(),
info.taskAffinity, (task.realActivity != null
r.getTask().rootAffinity, mIntent.getComponent().flattenToShortString(),
mInfo.taskAffinity, (task.realActivity != null
? task.realActivity.flattenToShortString() : ""));
// TODO Refactor to remove duplications. Check if logic can be simplified.
if (task.realActivity != null && task.realActivity.compareTo(cls) == 0
&& Objects.equals(documentData, taskDocumentData)) {
ProtoLog.d(WM_DEBUG_TASKS, "Found matching class!");
//dump();
ProtoLog.d(WM_DEBUG_TASKS, "For Intent %s bringing to top: %s", intent, r.intent);
mRecord = r;
mIdealMatch = true;
ProtoLog.d(WM_DEBUG_TASKS, "For Intent %s bringing to top: %s", mIntent, r.intent);
mIdealRecord = r;
return true;
} else if (affinityIntent != null && affinityIntent.getComponent() != null
&& affinityIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) {
ProtoLog.d(WM_DEBUG_TASKS, "Found matching class!");
ProtoLog.d(WM_DEBUG_TASKS, "For Intent %s bringing to top: %s", intent, r.intent);
mRecord = r;
mIdealMatch = true;
ProtoLog.d(WM_DEBUG_TASKS, "For Intent %s bringing to top: %s", mIntent, r.intent);
mIdealRecord = r;
return true;
} else if (!isDocument && !taskIsDocument
&& mRecord == null && task.rootAffinity != null) {
if (task.rootAffinity.equals(mTarget.taskAffinity)) {
&& mIdealRecord == null && mCandidateRecord == null
&& task.rootAffinity != null) {
if (task.rootAffinity.equals(mTaskAffinity)) {
ProtoLog.d(WM_DEBUG_TASKS, "Found matching affinity candidate!");
// It is possible for multiple tasks to have the same root affinity especially
// if they are in separate stacks. We save off this candidate, but keep looking
// to see if there is a better candidate.
mRecord = r;
mIdealMatch = false;
mCandidateRecord = r;
}
} else {
ProtoLog.d(WM_DEBUG_TASKS, "Not a match: %s", task);
@@ -2234,38 +2235,48 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
@Nullable
ActivityRecord findTask(ActivityRecord r, TaskDisplayArea preferredTaskDisplayArea) {
ProtoLog.d(WM_DEBUG_TASKS, "Looking for task of %s", r);
mTmpFindTaskResult.clear();
return findTask(r.getActivityType(), r.taskAffinity, r.intent, r.info,
preferredTaskDisplayArea);
}
@Nullable
ActivityRecord findTask(int activityType, String taskAffinity, Intent intent, ActivityInfo info,
TaskDisplayArea preferredTaskDisplayArea) {
ProtoLog.d(WM_DEBUG_TASKS, "Looking for task of type=%s, taskAffinity=%s, intent=%s"
+ ", info=%s, preferredTDA=%s", activityType, taskAffinity, intent, info,
preferredTaskDisplayArea);
mTmpFindTaskResult.init(activityType, taskAffinity, intent, info);
// Looking up task on preferred display area first
ActivityRecord candidateActivity = null;
if (preferredTaskDisplayArea != null) {
preferredTaskDisplayArea.findTaskLocked(r, true /* isPreferredDisplay */,
mTmpFindTaskResult);
if (mTmpFindTaskResult.mIdealMatch) {
return mTmpFindTaskResult.mRecord;
mTmpFindTaskResult.process(preferredTaskDisplayArea);
if (mTmpFindTaskResult.mIdealRecord != null) {
return mTmpFindTaskResult.mIdealRecord;
} else if (mTmpFindTaskResult.mCandidateRecord != null) {
candidateActivity = mTmpFindTaskResult.mCandidateRecord;
}
}
final ActivityRecord task = getItemFromTaskDisplayAreas(taskDisplayArea -> {
final ActivityRecord idealMatchActivity = getItemFromTaskDisplayAreas(taskDisplayArea -> {
if (taskDisplayArea == preferredTaskDisplayArea) {
return null;
}
taskDisplayArea.findTaskLocked(r, false /* isPreferredDisplay */,
mTmpFindTaskResult);
if (mTmpFindTaskResult.mIdealMatch) {
return mTmpFindTaskResult.mRecord;
mTmpFindTaskResult.process(taskDisplayArea);
if (mTmpFindTaskResult.mIdealRecord != null) {
return mTmpFindTaskResult.mIdealRecord;
}
return null;
});
if (task != null) {
return task;
if (idealMatchActivity != null) {
return idealMatchActivity;
}
if (WM_DEBUG_TASKS.isEnabled() && mTmpFindTaskResult.mRecord == null) {
if (WM_DEBUG_TASKS.isEnabled() && candidateActivity == null) {
ProtoLog.d(WM_DEBUG_TASKS, "No task found");
}
return mTmpFindTaskResult.mRecord;
return candidateActivity;
}
/**

View File

@@ -35,7 +35,6 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
import static com.android.server.wm.ActivityTaskManagerService.TAG_ROOT_TASK;
import static com.android.server.wm.DisplayContent.alwaysCreateRootTask;
import static com.android.server.wm.Task.ActivityState.RESUMED;
@@ -131,9 +130,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
*/
Task mPreferredTopFocusableRootTask;
private final RootWindowContainer.FindTaskResult
mTmpFindTaskResult = new RootWindowContainer.FindTaskResult();
/**
* If this is the same as {@link #getFocusedRootTask} then the activity on the top of the
* focused root task has been resumed. If root tasks are changing position this will hold the
@@ -1391,43 +1387,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
return someActivityPaused[0] > 0;
}
/**
* Find task for putting the Activity in.
*/
void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplayArea,
RootWindowContainer.FindTaskResult result) {
mTmpFindTaskResult.clear();
for (int i = mChildren.size() - 1; i >= 0; --i) {
final Task rootTask = mChildren.get(i).asTask();
if (rootTask == null) {
continue;
}
if (!r.hasCompatibleActivityType(rootTask) && rootTask.isLeafTask()) {
ProtoLog.d(WM_DEBUG_TASKS, "Skipping rootTask: (mismatch activity/rootTask) "
+ "%s", rootTask);
continue;
}
mTmpFindTaskResult.process(r, rootTask);
// It is possible to have tasks in multiple root tasks with the same root affinity, so
// we should keep looking after finding an affinity match to see if there is a
// better match in another root task. Also, task affinity isn't a good enough reason
// to target a display which isn't the source of the intent, so skip any affinity
// matches not on the specified display.
if (mTmpFindTaskResult.mRecord != null) {
if (mTmpFindTaskResult.mIdealMatch) {
result.setTo(mTmpFindTaskResult);
return;
} else if (isPreferredDisplayArea) {
// Note: since the traversing through the root tasks is top down, the floating
// tasks should always have lower priority than any affinity-matching tasks
// in the fullscreen root tasks
result.setTo(mTmpFindTaskResult);
}
}
}
}
void onSplitScreenModeDismissed() {
// The focused task could be a non-resizeable fullscreen root task that is on top of the
// other split-screen tasks, therefore had to dismiss split-screen, make sure the current

View File

@@ -314,11 +314,12 @@ public class ActivityStackTests extends WindowTestsBase {
final RootWindowContainer.FindTaskResult result =
new RootWindowContainer.FindTaskResult();
result.process(r, task);
result.init(r.getActivityType(), r.taskAffinity, r.intent, r.info);
result.process(task);
assertEquals(r, task.getTopNonFinishingActivity(false /* includeOverlays */));
assertEquals(taskOverlay, task.getTopNonFinishingActivity(true /* includeOverlays */));
assertNotNull(result.mRecord);
assertNotNull(result.mIdealRecord);
}
@Test
@@ -340,15 +341,17 @@ public class ActivityStackTests extends WindowTestsBase {
final ActivityRecord r1 = new ActivityBuilder(mAtm).setComponent(
target).setTargetActivity(targetActivity).build();
RootWindowContainer.FindTaskResult result = new RootWindowContainer.FindTaskResult();
result.process(r1, parentTask);
assertThat(result.mRecord).isNotNull();
result.init(r1.getActivityType(), r1.taskAffinity, r1.intent, r1.info);
result.process(parentTask);
assertThat(result.mIdealRecord).isNotNull();
// Using alias activity to find task.
final ActivityRecord r2 = new ActivityBuilder(mAtm).setComponent(
alias).setTargetActivity(targetActivity).build();
result = new RootWindowContainer.FindTaskResult();
result.process(r2, parentTask);
assertThat(result.mRecord).isNotNull();
result.init(r2.getActivityType(), r2.taskAffinity, r2.intent, r2.info);
result.process(parentTask);
assertThat(result.mIdealRecord).isNotNull();
}
@Test