diff options
author | Craig Mautner <cmautner@google.com> | 2014-04-17 18:39:38 -0700 |
---|---|---|
committer | Craig Mautner <cmautner@google.com> | 2014-04-21 15:28:42 -0700 |
commit | f4c909bcb87d6f103c9f9e8255fa61bd86f4de67 (patch) | |
tree | 4bda1df837e743ddf10e33424de390571603907e /services | |
parent | 72eec7f6c9509fb86f46fbdb619523efacb8d02e (diff) | |
download | frameworks_base-f4c909bcb87d6f103c9f9e8255fa61bd86f4de67.zip frameworks_base-f4c909bcb87d6f103c9f9e8255fa61bd86f4de67.tar.gz frameworks_base-f4c909bcb87d6f103c9f9e8255fa61bd86f4de67.tar.bz2 |
Fix ActivityView lifecycle
Major changes to maintain the VirtualDisplay across repeated
attach/detach cycles of an ActivityView. This keeps the activities
and VirtualDisplays in the ActivityView from getting into bad states.
Fixes bug 14107002.
Change-Id: Idc2aaf85ac496eab0eeb436736cb10a2020040e8
Diffstat (limited to 'services')
4 files changed, 165 insertions, 117 deletions
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 98cbe7d..d09ee96 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -7078,6 +7078,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (r == null) { return null; } + if (callback == null) { + throw new IllegalArgumentException("callback must not be null"); + } return mStackSupervisor.createActivityContainer(r, callback); } } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index a27288a..5a9e690 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -139,7 +139,7 @@ final class ActivityRecord { boolean forceNewConfig; // force re-create with new config next time int launchCount; // count of launches since last state long lastLaunchTime; // time of last lauch of this activity - ArrayList<ActivityStack> mChildContainers = new ArrayList<ActivityStack>(); + ArrayList<ActivityContainer> mChildContainers = new ArrayList<ActivityContainer>(); String stringName; // for caching of toString(). diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 42e1a37..f4f39e2 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -36,6 +36,8 @@ import static com.android.server.am.ActivityStackSupervisor.DEBUG_SAVED_STATE; import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES; import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; +import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.CONTAINER_STATE_HAS_SURFACE; + import com.android.internal.os.BatteryStatsImpl; import com.android.server.Watchdog; import com.android.server.am.ActivityManagerService.ItemMatcher; @@ -1028,9 +1030,9 @@ final class ActivityStack { private void setVisibile(ActivityRecord r, boolean visible) { r.visible = visible; mWindowManager.setAppVisibility(r.appToken, visible); - final ArrayList<ActivityStack> containers = r.mChildContainers; + final ArrayList<ActivityContainer> containers = r.mChildContainers; for (int containerNdx = containers.size() - 1; containerNdx >= 0; --containerNdx) { - ActivityContainer container = containers.get(containerNdx).mActivityContainer; + ActivityContainer container = containers.get(containerNdx); container.setVisible(visible); } } @@ -1271,7 +1273,8 @@ final class ActivityStack { if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen(""); ActivityRecord parent = mActivityContainer.mParentActivity; - if (parent != null && parent.state != ActivityState.RESUMED) { + if ((parent != null && parent.state != ActivityState.RESUMED) || + mActivityContainer.mContainerState != CONTAINER_STATE_HAS_SURFACE) { // Do not resume this stack if its parent is not resumed. // TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st. return false; @@ -2552,6 +2555,20 @@ final class ActivityStack { return r; } + void finishAllActivitiesLocked() { + for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { + final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; + for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { + final ActivityRecord r = activities.get(activityNdx); + if (r.finishing) { + continue; + } + Slog.d(TAG, "finishAllActivitiesLocked: finishing " + r); + finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false); + } + } + } + final boolean navigateUpToLocked(IBinder token, Intent destIntent, int resultCode, Intent resultData) { final ActivityRecord srec = ActivityRecord.forToken(token); @@ -2787,7 +2804,6 @@ final class ActivityStack { } if (activityRemoved) { mStackSupervisor.resumeTopActivitiesLocked(); - } } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index efa3ad49..a316336 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -95,7 +95,6 @@ import com.android.server.wm.WindowManagerService; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; -import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -224,11 +223,11 @@ public final class ActivityStackSupervisor implements DisplayListener { // TODO: Add listener for removal of references. /** Mapping from (ActivityStack/TaskStack).mStackId to their current state */ - SparseArray<WeakReference<ActivityContainer>> mActivityContainers = - new SparseArray<WeakReference<ActivityContainer>>(); + SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>(); /** Mapping from displayId to display current state */ - private SparseArray<ActivityDisplay> mActivityDisplays = new SparseArray<ActivityDisplay>(); + private final SparseArray<ActivityDisplay> mActivityDisplays = + new SparseArray<ActivityDisplay>(); InputManagerInternal mInputManagerInternal; @@ -260,7 +259,7 @@ public final class ActivityStackSupervisor implements DisplayListener { mActivityDisplays.put(displayId, activityDisplay); } - createStackOnDisplay(null, HOME_STACK_ID, Display.DEFAULT_DISPLAY); + createStackOnDisplay(HOME_STACK_ID, Display.DEFAULT_DISPLAY); mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID); mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); @@ -1378,7 +1377,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } // Need to create an app stack for this user. - int stackId = createStackOnDisplay(null, getNextStackId(), Display.DEFAULT_DISPLAY); + int stackId = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY); if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r + " stackId=" + stackId); mFocusedStack = getStack(stackId); @@ -2127,14 +2126,9 @@ public final class ActivityStackSupervisor implements DisplayListener { } ActivityStack getStack(int stackId) { - WeakReference<ActivityContainer> weakReference = mActivityContainers.get(stackId); - if (weakReference != null) { - ActivityContainer activityContainer = weakReference.get(); - if (activityContainer != null) { - return activityContainer.mStack; - } else { - mActivityContainers.remove(stackId); - } + ActivityContainer activityContainer = mActivityContainers.get(stackId); + if (activityContainer != null) { + return activityContainer.mStack; } return null; } @@ -2164,49 +2158,26 @@ public final class ActivityStackSupervisor implements DisplayListener { return null; } - ActivityContainer createActivityContainer(ActivityRecord parentActivity, int stackId, - IActivityContainerCallback callback) { - ActivityContainer activityContainer = new ActivityContainer(parentActivity, stackId, - callback); - mActivityContainers.put(stackId, new WeakReference<ActivityContainer>(activityContainer)); - if (parentActivity != null) { - parentActivity.mChildContainers.add(activityContainer.mStack); - } - return activityContainer; - } - ActivityContainer createActivityContainer(ActivityRecord parentActivity, IActivityContainerCallback callback) { - return createActivityContainer(parentActivity, getNextStackId(), callback); + ActivityContainer activityContainer = new VirtualActivityContainer(parentActivity, callback); + mActivityContainers.put(activityContainer.mStackId, activityContainer); + parentActivity.mChildContainers.add(activityContainer); + return activityContainer; } void removeChildActivityContainers(ActivityRecord parentActivity) { - for (int ndx = mActivityContainers.size() - 1; ndx >= 0; --ndx) { - final ActivityContainer container = mActivityContainers.valueAt(ndx).get(); - if (container == null) { - mActivityContainers.removeAt(ndx); - continue; - } - if (container.mParentActivity != parentActivity) { - continue; - } - - ActivityStack stack = container.mStack; - ActivityRecord top = stack.topRunningNonDelayedActivityLocked(null); - if (top != null) { - // TODO: Make sure the next activity doesn't start up when top is destroyed. - stack.destroyActivityLocked(top, true, true, "stack parent destroyed"); - } - mActivityContainers.removeAt(ndx); - container.detachLocked(); + final ArrayList<ActivityContainer> childStacks = parentActivity.mChildContainers; + for (int containerNdx = childStacks.size() - 1; containerNdx >= 0; --containerNdx) { + ActivityContainer container = childStacks.remove(containerNdx); + container.release(); } } void deleteActivityContainer(IActivityContainer container) { ActivityContainer activityContainer = (ActivityContainer)container; if (activityContainer != null) { - activityContainer.mStack.destroyActivitiesLocked(null, true, - "deleteActivityContainer"); + activityContainer.mStack.finishAllActivitiesLocked(); final ActivityRecord parent = activityContainer.mParentActivity; if (parent != null) { parent.mChildContainers.remove(activityContainer); @@ -2217,14 +2188,14 @@ public final class ActivityStackSupervisor implements DisplayListener { } } - private int createStackOnDisplay(ActivityRecord parentActivity, int stackId, int displayId) { + private int createStackOnDisplay(int stackId, int displayId) { ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); if (activityDisplay == null) { return -1; } - ActivityContainer activityContainer = - createActivityContainer(parentActivity, stackId, null); + ActivityContainer activityContainer = new ActivityContainer(stackId); + mActivityContainers.put(stackId, activityContainer); activityContainer.attachToDisplayLocked(activityDisplay); return stackId; } @@ -2306,9 +2277,9 @@ public final class ActivityStackSupervisor implements DisplayListener { } boolean shutdownLocked(int timeout) { - boolean timedout = false; goingToSleepLocked(); + boolean timedout = false; final long endTime = System.currentTimeMillis() + timeout; while (true) { boolean cantShutdown = false; @@ -2967,24 +2938,26 @@ public final class ActivityStackSupervisor implements DisplayListener { class ActivityContainer extends IActivityContainer.Stub { final int mStackId; - final IActivityContainerCallback mCallback; + IActivityContainerCallback mCallback = null; final ActivityStack mStack; - final ActivityRecord mParentActivity; - final String mIdString; + ActivityRecord mParentActivity = null; + String mIdString; boolean mVisible = true; /** Display this ActivityStack is currently on. Null if not attached to a Display. */ ActivityDisplay mActivityDisplay; - ActivityContainer(ActivityRecord parentActivity, int stackId, - IActivityContainerCallback callback) { + final static int CONTAINER_STATE_HAS_SURFACE = 0; + final static int CONTAINER_STATE_NO_SURFACE = 1; + final static int CONTAINER_STATE_FINISHING = 2; + int mContainerState = CONTAINER_STATE_HAS_SURFACE; + + ActivityContainer(int stackId) { synchronized (mService) { mStackId = stackId; mStack = new ActivityStack(this); - mParentActivity = parentActivity; - mCallback = callback; - mIdString = "ActivtyContainer{" + mStackId + ", parent=" + mParentActivity + "}"; + mIdString = "ActivtyContainer{" + mStackId + "}"; if (DEBUG_STACK) Slog.d(TAG, "Creating " + this); } } @@ -3034,6 +3007,14 @@ public final class ActivityStackSupervisor implements DisplayListener { } } + @Override + public void release() { + mContainerState = CONTAINER_STATE_FINISHING; + mStack.finishAllActivitiesLocked(); + detachLocked(); + mWindowManager.removeStack(mStackId); + } + private void detachLocked() { if (DEBUG_STACK) Slog.d(TAG, "detachLocked: " + this + " from display=" + mActivityDisplay + " Callers=" + Debug.getCallers(2)); @@ -3047,13 +3028,6 @@ public final class ActivityStackSupervisor implements DisplayListener { } @Override - public void detachFromDisplay() { - synchronized (mService) { - detachLocked(); - } - } - - @Override public final int startActivity(Intent intent) { mService.enforceNotIsolatedCaller("ActivityContainer.startActivity"); int userId = mService.handleIncomingUser(Binder.getCallingPid(), @@ -3086,23 +3060,8 @@ public final class ActivityStackSupervisor implements DisplayListener { } @Override - public void attachToSurface(Surface surface, int width, int height, int density) { + public void setSurface(Surface surface, int width, int height, int density) { mService.enforceNotIsolatedCaller("ActivityContainer.attachToSurface"); - - final long origId = Binder.clearCallingIdentity(); - try { - synchronized (mService) { - ActivityDisplay activityDisplay = - new ActivityDisplay(surface, width, height, density); - mActivityDisplays.put(activityDisplay.mDisplayId, activityDisplay); - attachToDisplayLocked(activityDisplay); - mStack.resumeTopActivityLocked(null); - } - if (DEBUG_STACK) Slog.d(TAG, "attachToSurface: " + this + " to display=" - + mActivityDisplay); - } finally { - Binder.restoreCallingIdentity(origId); - } } ActivityStackSupervisor getOuter() { @@ -3137,46 +3096,87 @@ public final class ActivityStackSupervisor implements DisplayListener { } } + private class VirtualActivityContainer extends ActivityContainer { + Surface mSurface; + + VirtualActivityContainer(ActivityRecord parent, IActivityContainerCallback callback) { + super(getNextStackId()); + mParentActivity = parent; + mCallback = callback; + mContainerState = CONTAINER_STATE_NO_SURFACE; + mIdString = "VirtualActivtyContainer{" + mStackId + ", parent=" + mParentActivity + "}"; + } + + @Override + public void setSurface(Surface surface, int width, int height, int density) { + super.setSurface(surface, width, height, density); + + synchronized (mService) { + final long origId = Binder.clearCallingIdentity(); + try { + setSurfaceLocked(surface, width, height, density); + } finally { + Binder.restoreCallingIdentity(origId); + } + } + } + + private void setSurfaceLocked(Surface surface, int width, int height, int density) { + if (mContainerState == CONTAINER_STATE_FINISHING) { + return; + } + VirtualActivityDisplay virtualActivityDisplay = + (VirtualActivityDisplay) mActivityDisplay; + if (virtualActivityDisplay == null) { + virtualActivityDisplay = + new VirtualActivityDisplay(surface, width, height, density); + mActivityDisplay = virtualActivityDisplay; + mActivityDisplays.put(virtualActivityDisplay.mDisplayId, virtualActivityDisplay); + attachToDisplayLocked(virtualActivityDisplay); + } + + if (mSurface != null) { + mSurface.release(); + mSurface = null; + } + + if (surface != null) { + mContainerState = CONTAINER_STATE_HAS_SURFACE; + mSurface = surface; + mStack.resumeTopActivityLocked(null); + } else { + mContainerState = CONTAINER_STATE_NO_SURFACE; + if (mStack.mPausingActivity == null && mStack.mResumedActivity != null) { + mStack.startPausingLocked(false, true); + } + } + if (DEBUG_STACK) Slog.d(TAG, "setSurface: " + this + " to display=" + + virtualActivityDisplay); + + virtualActivityDisplay.setSurface(surface); + } + } + /** Exactly one of these classes per Display in the system. Capable of holding zero or more * attached {@link ActivityStack}s */ - final class ActivityDisplay { + class ActivityDisplay { /** Actual Display this object tracks. */ int mDisplayId; Display mDisplay; DisplayInfo mDisplayInfo = new DisplayInfo(); - Surface mSurface; /** All of the stacks on this display. Order matters, topmost stack is in front of all other * stacks, bottommost behind. Accessed directly by ActivityManager package classes */ final ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>(); - /** If this display is for an ActivityView then the VirtualDisplay created for it is stored - * here. */ - VirtualDisplay mVirtualDisplay; + ActivityDisplay() { + } ActivityDisplay(int displayId) { init(mDisplayManager.getDisplay(displayId)); } - ActivityDisplay(Surface surface, int width, int height, int density) { - DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance(); - long ident = Binder.clearCallingIdentity(); - try { - mVirtualDisplay = dm.createVirtualDisplay(mService.mContext, - VIRTUAL_DISPLAY_BASE_NAME, width, height, density, surface, - DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC | - DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY); - } finally { - Binder.restoreCallingIdentity(ident); - } - - init(mVirtualDisplay.getDisplay()); - mSurface = surface; - - mWindowManager.handleDisplayAdded(mDisplayId); - } - - private void init(Display display) { + void init(Display display) { mDisplay = display; mDisplayId = display.getDisplayId(); mDisplay.getDisplayInfo(mDisplayInfo); @@ -3192,11 +3192,6 @@ public final class ActivityStackSupervisor implements DisplayListener { if (DEBUG_STACK) Slog.v(TAG, "detachActivitiesLocked: detaching " + stack + " from displayId=" + mDisplayId); mStacks.remove(stack); - if (mStacks.isEmpty() && mVirtualDisplay != null) { - mVirtualDisplay.release(); - mVirtualDisplay = null; - } - mSurface.release(); } void getBounds(Point bounds) { @@ -3207,8 +3202,42 @@ public final class ActivityStackSupervisor implements DisplayListener { @Override public String toString() { - return "ActivityDisplay={" + mDisplayId + (mVirtualDisplay == null ? "" : "V") - + " numStacks=" + mStacks.size() + "}"; + return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}"; + } + } + + class VirtualActivityDisplay extends ActivityDisplay { + VirtualDisplay mVirtualDisplay; + + VirtualActivityDisplay(Surface surface, int width, int height, int density) { + DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance(); + mVirtualDisplay = dm.createVirtualDisplay(mService.mContext, VIRTUAL_DISPLAY_BASE_NAME, + width, height, density, surface, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC | + DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY); + + init(mVirtualDisplay.getDisplay()); + + mWindowManager.handleDisplayAdded(mDisplayId); + } + + void setSurface(Surface surface) { + if (mVirtualDisplay != null) { + mVirtualDisplay.setSurface(surface); + } + } + + @Override + void detachActivitiesLocked(ActivityStack stack) { + super.detachActivitiesLocked(stack); + if (mVirtualDisplay != null) { + mVirtualDisplay.release(); + mVirtualDisplay = null; + } + } + + @Override + public String toString() { + return "VirtualActivityDisplay={" + mDisplayId + "}"; } } } |