summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java37
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java91
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java11
3 files changed, 127 insertions, 12 deletions
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 7c57dc17e802..72878cfeaa12 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -458,6 +458,22 @@ class TaskFragment extends WindowContainer<WindowContainer> {
&& organizer.asBinder().equals(mTaskFragmentOrganizer.asBinder());
}
+ /**
+ * Returns the process of organizer if this TaskFragment is organized and the activity lives in
+ * a different process than the organizer.
+ */
+ @Nullable
+ private WindowProcessController getOrganizerProcessIfDifferent(@Nullable ActivityRecord r) {
+ if ((r == null || mTaskFragmentOrganizerProcessName == null)
+ || (mTaskFragmentOrganizerProcessName.equals(r.processName)
+ && mTaskFragmentOrganizerUid == r.getUid())) {
+ // No organizer or the process is the same.
+ return null;
+ }
+ return mAtmService.getProcessController(mTaskFragmentOrganizerProcessName,
+ mTaskFragmentOrganizerUid);
+ }
+
void setAnimationParams(@NonNull TaskFragmentAnimationParams animationParams) {
mAnimationParams = animationParams;
}
@@ -815,6 +831,16 @@ class TaskFragment extends WindowContainer<WindowContainer> {
setResumedActivity(record, reason + " - onActivityStateChanged");
mTaskSupervisor.mRecentTasks.add(record.getTask());
}
+
+ // Update the process state for the organizer process if the activity is in a different
+ // process in case the organizer process may not have activity state change in its process.
+ final WindowProcessController hostProcess = getOrganizerProcessIfDifferent(record);
+ if (hostProcess != null) {
+ mTaskSupervisor.onProcessActivityStateChanged(hostProcess, false /* forceBatch */);
+ hostProcess.updateProcessInfo(false /* updateServiceConnectionActivities */,
+ true /* activityChange */, true /* updateOomAdj */,
+ false /* addPendingTopUid */);
+ }
}
/**
@@ -1942,6 +1968,11 @@ class TaskFragment extends WindowContainer<WindowContainer> {
addingActivity.inHistory = true;
task.onDescendantActivityAdded(taskHadActivity, activityType, addingActivity);
}
+
+ final WindowProcessController hostProcess = getOrganizerProcessIfDifferent(addingActivity);
+ if (hostProcess != null) {
+ hostProcess.addEmbeddedActivity(addingActivity);
+ }
}
@Override
@@ -2757,14 +2788,18 @@ class TaskFragment extends WindowContainer<WindowContainer> {
void removeChild(WindowContainer child, boolean removeSelfIfPossible) {
super.removeChild(child);
+ final ActivityRecord r = child.asActivityRecord();
if (BackNavigationController.isScreenshotEnabled()) {
//TODO(b/207481538) Remove once the infrastructure to support per-activity screenshot is
// implemented
- ActivityRecord r = child.asActivityRecord();
if (r != null) {
mBackScreenshots.remove(r.mActivityComponent.flattenToString());
}
}
+ final WindowProcessController hostProcess = getOrganizerProcessIfDifferent(r);
+ if (hostProcess != null) {
+ hostProcess.removeEmbeddedActivity(r);
+ }
if (removeSelfIfPossible && shouldRemoveSelfOnLastChildRemoval() && !hasChild()) {
removeImmediately("removeLastChild " + child);
}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 834b708f3f9a..8685723a5807 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -69,6 +69,7 @@ import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -228,8 +229,17 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
* in another process. This is used to check if the process is currently showing anything
* visible to the user.
*/
+ private static final int REMOTE_ACTIVITY_FLAG_HOST_ACTIVITY = 1;
+ /** The activity in a different process is embedded in a task created by this process. */
+ private static final int REMOTE_ACTIVITY_FLAG_EMBEDDED_ACTIVITY = 1 << 1;
+
+ /**
+ * Activities that run on different processes while this process shows something in these
+ * activities or the appearance of the activities are controlled by this process. The value of
+ * map is an array of size 1 to store the kinds of remote.
+ */
@Nullable
- private final ArrayList<ActivityRecord> mHostActivities = new ArrayList<>();
+ private ArrayMap<ActivityRecord, int[]> mRemoteActivities;
/** Whether our process is currently running a {@link RecentsAnimation} */
private boolean mRunningRecentsAnimation;
@@ -857,7 +867,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return true;
}
}
- if (isEmbedded()) {
+ if (hasEmbeddedWindow()) {
return true;
}
}
@@ -868,9 +878,13 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
* @return {@code true} if this process is rendering content on to a window shown by
* another process.
*/
- private boolean isEmbedded() {
- for (int i = mHostActivities.size() - 1; i >= 0; --i) {
- final ActivityRecord r = mHostActivities.get(i);
+ private boolean hasEmbeddedWindow() {
+ if (mRemoteActivities == null) return false;
+ for (int i = mRemoteActivities.size() - 1; i >= 0; --i) {
+ if ((mRemoteActivities.valueAt(i)[0] & REMOTE_ACTIVITY_FLAG_HOST_ACTIVITY) == 0) {
+ continue;
+ }
+ final ActivityRecord r = mRemoteActivities.keyAt(i);
if (r.isInterestingToUserLocked()) {
return true;
}
@@ -1038,15 +1052,46 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
/** Adds an activity that hosts UI drawn by the current process. */
void addHostActivity(ActivityRecord r) {
- if (mHostActivities.contains(r)) {
- return;
- }
- mHostActivities.add(r);
+ final int[] flags = getRemoteActivityFlags(r);
+ flags[0] |= REMOTE_ACTIVITY_FLAG_HOST_ACTIVITY;
}
/** Removes an activity that hosts UI drawn by the current process. */
void removeHostActivity(ActivityRecord r) {
- mHostActivities.remove(r);
+ removeRemoteActivityFlags(r, REMOTE_ACTIVITY_FLAG_HOST_ACTIVITY);
+ }
+
+ /** Adds an embedded activity in a different process to this process that organizes it. */
+ void addEmbeddedActivity(ActivityRecord r) {
+ final int[] flags = getRemoteActivityFlags(r);
+ flags[0] |= REMOTE_ACTIVITY_FLAG_EMBEDDED_ACTIVITY;
+ }
+
+ /** Removes an embedded activity which was added by {@link #addEmbeddedActivity}. */
+ void removeEmbeddedActivity(ActivityRecord r) {
+ removeRemoteActivityFlags(r, REMOTE_ACTIVITY_FLAG_EMBEDDED_ACTIVITY);
+ }
+
+ private int[] getRemoteActivityFlags(ActivityRecord r) {
+ if (mRemoteActivities == null) {
+ mRemoteActivities = new ArrayMap<>();
+ }
+ int[] flags = mRemoteActivities.get(r);
+ if (flags == null) {
+ mRemoteActivities.put(r, flags = new int[1]);
+ }
+ return flags;
+ }
+
+ private void removeRemoteActivityFlags(ActivityRecord r, int flags) {
+ if (mRemoteActivities == null) return;
+ final int index = mRemoteActivities.indexOfKey(r);
+ if (index < 0) return;
+ final int[] currentFlags = mRemoteActivities.valueAt(index);
+ currentFlags[0] &= ~flags;
+ if (currentFlags[0] == 0) {
+ mRemoteActivities.removeAt(index);
+ }
}
public interface ComputeOomAdjCallback {
@@ -1121,6 +1166,16 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
}
}
+ if (mRemoteActivities != null) {
+ // Make this process have visible state if its organizer embeds visible activities of
+ // other process, so this process can be responsive for the organizer events.
+ for (int i = mRemoteActivities.size() - 1; i >= 0; i--) {
+ if ((mRemoteActivities.valueAt(i)[0] & REMOTE_ACTIVITY_FLAG_EMBEDDED_ACTIVITY) != 0
+ && mRemoteActivities.keyAt(i).isVisibleRequested()) {
+ stateFlags |= ACTIVITY_STATE_FLAG_IS_VISIBLE;
+ }
+ }
+ }
stateFlags |= minTaskLayer & ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;
if (visible) {
@@ -1795,7 +1850,21 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
pw.print(prefix); pw.print(" - "); pw.println(mActivities.get(i));
}
}
-
+ if (mRemoteActivities != null && !mRemoteActivities.isEmpty()) {
+ pw.print(prefix); pw.println("Remote Activities:");
+ for (int i = mRemoteActivities.size() - 1; i >= 0; i--) {
+ pw.print(prefix); pw.print(" - ");
+ pw.print(mRemoteActivities.keyAt(i)); pw.print(" flags=");
+ final int flags = mRemoteActivities.valueAt(i)[0];
+ if ((flags & REMOTE_ACTIVITY_FLAG_HOST_ACTIVITY) != 0) {
+ pw.print("host ");
+ }
+ if ((flags & REMOTE_ACTIVITY_FLAG_EMBEDDED_ACTIVITY) != 0) {
+ pw.print("embedded");
+ }
+ pw.println();
+ }
+ }
if (mRecentTasks.size() > 0) {
pw.println(prefix + "Recent Tasks:");
for (int i = 0; i < mRecentTasks.size(); i++) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 378e8bed3524..99ab715ab987 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -398,6 +398,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
public void testOnActivityReparentedToTask_activityNotInOrganizerProcess_useTemporaryToken() {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
+ final WindowProcessController organizerProc = mSystemServicesTestRule.addProcess(
+ "pkg.organizer", DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME, pid, uid);
mTaskFragment.setTaskFragmentOrganizer(mOrganizer.getOrganizerToken(), uid,
DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME);
mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
@@ -436,6 +438,15 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// The temporary token can only be used once.
assertNull(mController.getReparentActivityFromTemporaryToken(mIOrganizer,
change.getActivityToken()));
+
+ // The organizer process should also have visible state by the visible activity in a
+ // different process.
+ activity.setVisibleRequested(true);
+ activity.setState(ActivityRecord.State.RESUMED, "test");
+ assertTrue(organizerProc.hasVisibleActivities());
+ activity.setVisibleRequested(false);
+ activity.setState(ActivityRecord.State.STOPPED, "test");
+ assertFalse(organizerProc.hasVisibleActivities());
}
@Test