Close ActivityView and ActivityContainer cleanly.

- Do not call IActivityContainer.release() from
ActivityView.finalize() if it has already been called from
ActivityView.release(). Eliminates IBinder finalized Exception.

- Call ActivityRecord.makeFinishing() before calling ActivityStack.
destroyActivityLocked(). Forces call to scheduleDestroyActivity()
and eventually removeFromHistory(). Otherwise removeFromHistory()
is never called and window manager AppWindowTokens become orphans.

- Defer call to ActivityContainer.detachLocked() until all
activities have finished or timed out. Fixes problem where Display
is removed while activities are still launching.

- Call ActivityStackSupervisor.deleteActivityContainer() when all
activities have finished or timed out. Fixes orphaned
ActivityContainers.

Fixes bug 15450798.
Fixes bug 15484154.
Fixes bug 15383479.
Fixes bug 15316558.
Fixes bug 15168560.
Fixes bug 15143914.

Change-Id: Id3c641976b6f825458690f9ee063c07818b56f23
This commit is contained in:
Craig Mautner
2014-06-11 13:44:50 -07:00
parent e33010a261
commit 4a9f129874
3 changed files with 78 additions and 41 deletions

View File

@@ -354,9 +354,11 @@ public class ActivityView extends ViewGroup {
private static class ActivityContainerWrapper { private static class ActivityContainerWrapper {
private final IActivityContainer mIActivityContainer; private final IActivityContainer mIActivityContainer;
private final CloseGuard mGuard = CloseGuard.get(); private final CloseGuard mGuard = CloseGuard.get();
boolean mOpened; // Protected by mGuard.
ActivityContainerWrapper(IActivityContainer container) { ActivityContainerWrapper(IActivityContainer container) {
mIActivityContainer = container; mIActivityContainer = container;
mOpened = true;
mGuard.open("release"); mGuard.open("release");
} }
@@ -424,12 +426,17 @@ public class ActivityView extends ViewGroup {
} }
void release() { void release() {
synchronized (mGuard) {
if (mOpened) {
if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: release called"); if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: release called");
try { try {
mIActivityContainer.release(); mIActivityContainer.release();
mGuard.close(); mGuard.close();
} catch (RemoteException e) { } catch (RemoteException e) {
} }
mOpened = false;
}
}
} }
@Override @Override

View File

@@ -32,12 +32,11 @@ import static com.android.server.am.ActivityManagerService.VALIDATE_TOKENS;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE; import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_APP; import static com.android.server.am.ActivityStackSupervisor.DEBUG_APP;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_CONTAINERS;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_SAVED_STATE; 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.DEBUG_STATES;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; 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.internal.os.BatteryStatsImpl;
import com.android.server.Watchdog; import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService.ItemMatcher; import com.android.server.am.ActivityManagerService.ItemMatcher;
@@ -1275,7 +1274,7 @@ final class ActivityStack {
ActivityRecord parent = mActivityContainer.mParentActivity; ActivityRecord parent = mActivityContainer.mParentActivity;
if ((parent != null && parent.state != ActivityState.RESUMED) || if ((parent != null && parent.state != ActivityState.RESUMED) ||
!mActivityContainer.isAttached()) { !mActivityContainer.isAttachedLocked()) {
// Do not resume this stack if its parent is not resumed. // 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. // TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st.
return false; return false;
@@ -2539,11 +2538,14 @@ final class ActivityStack {
|| prevState == ActivityState.INITIALIZING) { || prevState == ActivityState.INITIALIZING) {
// If this activity is already stopped, we can just finish // If this activity is already stopped, we can just finish
// it right now. // it right now.
boolean activityRemoved = destroyActivityLocked(r, true, r.makeFinishing();
oomAdj, "finish-imm"); boolean activityRemoved = destroyActivityLocked(r, true, oomAdj, "finish-imm");
if (activityRemoved) { if (activityRemoved) {
mStackSupervisor.resumeTopActivitiesLocked(); mStackSupervisor.resumeTopActivitiesLocked();
} }
if (DEBUG_CONTAINERS) Slog.d(TAG,
"destroyActivityLocked: finishCurrentActivityLocked r=" + r +
" destroy returned removed=" + activityRemoved);
return activityRemoved ? null : r; return activityRemoved ? null : r;
} }
@@ -2912,6 +2914,7 @@ final class ActivityStack {
if (r != null) { if (r != null) {
mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r); mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
} }
if (DEBUG_CONTAINERS) Slog.d(TAG, "activityDestroyedLocked: r=" + r);
if (isInStackLocked(token) != null) { if (isInStackLocked(token) != null) {
if (r.state == ActivityState.DESTROYING) { if (r.state == ActivityState.DESTROYING) {
@@ -3669,7 +3672,7 @@ final class ActivityStack {
mStacks.remove(this); mStacks.remove(this);
mStacks.add(0, this); mStacks.add(0, this);
} }
mActivityContainer.onTaskListEmpty(); mActivityContainer.onTaskListEmptyLocked();
} }
} }

View File

@@ -105,6 +105,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
static final boolean DEBUG_SAVED_STATE = DEBUG || false; static final boolean DEBUG_SAVED_STATE = DEBUG || false;
static final boolean DEBUG_STATES = DEBUG || false; static final boolean DEBUG_STATES = DEBUG || false;
static final boolean DEBUG_IDLE = DEBUG || false; static final boolean DEBUG_IDLE = DEBUG || false;
static final boolean DEBUG_CONTAINERS = DEBUG || false;
public static final int HOME_STACK_ID = 0; public static final int HOME_STACK_ID = 0;
@@ -127,6 +128,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
static final int HANDLE_DISPLAY_REMOVED = FIRST_SUPERVISOR_STACK_MSG + 7; static final int HANDLE_DISPLAY_REMOVED = FIRST_SUPERVISOR_STACK_MSG + 7;
static final int CONTAINER_CALLBACK_VISIBILITY = FIRST_SUPERVISOR_STACK_MSG + 8; static final int CONTAINER_CALLBACK_VISIBILITY = FIRST_SUPERVISOR_STACK_MSG + 8;
static final int CONTAINER_CALLBACK_TASK_LIST_EMPTY = FIRST_SUPERVISOR_STACK_MSG + 9; static final int CONTAINER_CALLBACK_TASK_LIST_EMPTY = FIRST_SUPERVISOR_STACK_MSG + 9;
static final int CONTAINER_TASK_LIST_EMPTY_TIMEOUT = FIRST_SUPERVISOR_STACK_MSG + 10;
private final static String VIRTUAL_DISPLAY_BASE_NAME = "ActivityViewVirtualDisplay"; private final static String VIRTUAL_DISPLAY_BASE_NAME = "ActivityViewVirtualDisplay";
@@ -224,7 +226,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
// TODO: Add listener for removal of references. // TODO: Add listener for removal of references.
/** Mapping from (ActivityStack/TaskStack).mStackId to their current state */ /** Mapping from (ActivityStack/TaskStack).mStackId to their current state */
SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>(); private SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>();
/** Mapping from displayId to display current state */ /** Mapping from displayId to display current state */
private final SparseArray<ActivityDisplay> mActivityDisplays = private final SparseArray<ActivityDisplay> mActivityDisplays =
@@ -2161,8 +2163,10 @@ public final class ActivityStackSupervisor implements DisplayListener {
ActivityContainer createActivityContainer(ActivityRecord parentActivity, ActivityContainer createActivityContainer(ActivityRecord parentActivity,
IActivityContainerCallback callback) { IActivityContainerCallback callback) {
ActivityContainer activityContainer = new VirtualActivityContainer(parentActivity, callback); ActivityContainer activityContainer =
new VirtualActivityContainer(parentActivity, callback);
mActivityContainers.put(activityContainer.mStackId, activityContainer); mActivityContainers.put(activityContainer.mStackId, activityContainer);
if (DEBUG_CONTAINERS) Slog.d(TAG, "createActivityContainer: " + activityContainer);
parentActivity.mChildContainers.add(activityContainer); parentActivity.mChildContainers.add(activityContainer);
return activityContainer; return activityContainer;
} }
@@ -2171,6 +2175,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
final ArrayList<ActivityContainer> childStacks = parentActivity.mChildContainers; final ArrayList<ActivityContainer> childStacks = parentActivity.mChildContainers;
for (int containerNdx = childStacks.size() - 1; containerNdx >= 0; --containerNdx) { for (int containerNdx = childStacks.size() - 1; containerNdx >= 0; --containerNdx) {
ActivityContainer container = childStacks.remove(containerNdx); ActivityContainer container = childStacks.remove(containerNdx);
if (DEBUG_CONTAINERS) Slog.d(TAG, "removeChildActivityContainers: removing " +
container);
container.release(); container.release();
} }
} }
@@ -2178,11 +2184,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
void deleteActivityContainer(IActivityContainer container) { void deleteActivityContainer(IActivityContainer container) {
ActivityContainer activityContainer = (ActivityContainer)container; ActivityContainer activityContainer = (ActivityContainer)container;
if (activityContainer != null) { if (activityContainer != null) {
activityContainer.mStack.finishAllActivitiesLocked(); if (DEBUG_CONTAINERS) Slog.d(TAG, "deleteActivityContainer: ",
final ActivityRecord parent = activityContainer.mParentActivity; new RuntimeException("here").fillInStackTrace());
if (parent != null) {
parent.mChildContainers.remove(activityContainer);
}
final int stackId = activityContainer.mStackId; final int stackId = activityContainer.mStackId;
mActivityContainers.remove(stackId); mActivityContainers.remove(stackId);
mWindowManager.removeStack(stackId); mWindowManager.removeStack(stackId);
@@ -2950,6 +2953,13 @@ public final class ActivityStackSupervisor implements DisplayListener {
} }
} }
} break; } break;
case CONTAINER_TASK_LIST_EMPTY_TIMEOUT: {
synchronized (mService) {
Slog.w(TAG, "Timeout waiting for all activities in task to finish. " +
msg.obj);
((ActivityContainer) msg.obj).onTaskListEmptyLocked();
}
} break;
} }
} }
} }
@@ -3006,9 +3016,11 @@ public final class ActivityStackSupervisor implements DisplayListener {
@Override @Override
public int getDisplayId() { public int getDisplayId() {
synchronized (mService) {
if (mActivityDisplay != null) { if (mActivityDisplay != null) {
return mActivityDisplay.mDisplayId; return mActivityDisplay.mDisplayId;
} }
}
return -1; return -1;
} }
@@ -3016,11 +3028,13 @@ public final class ActivityStackSupervisor implements DisplayListener {
public boolean injectEvent(InputEvent event) { public boolean injectEvent(InputEvent event) {
final long origId = Binder.clearCallingIdentity(); final long origId = Binder.clearCallingIdentity();
try { try {
synchronized (mService) {
if (mActivityDisplay != null) { if (mActivityDisplay != null) {
return mInputManagerInternal.injectInputEvent(event, return mInputManagerInternal.injectInputEvent(event,
mActivityDisplay.mDisplayId, mActivityDisplay.mDisplayId,
InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
} }
}
return false; return false;
} finally { } finally {
Binder.restoreCallingIdentity(origId); Binder.restoreCallingIdentity(origId);
@@ -3029,10 +3043,16 @@ public final class ActivityStackSupervisor implements DisplayListener {
@Override @Override
public void release() { public void release() {
synchronized (mService) {
if (mContainerState == CONTAINER_STATE_FINISHING) {
return;
}
mContainerState = CONTAINER_STATE_FINISHING; mContainerState = CONTAINER_STATE_FINISHING;
final Message msg =
mHandler.obtainMessage(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
mHandler.sendMessageDelayed(msg, 1000);
mStack.finishAllActivitiesLocked(); mStack.finishAllActivitiesLocked();
detachLocked(); }
mWindowManager.removeStack(mStackId);
} }
private void detachLocked() { private void detachLocked() {
@@ -3123,17 +3143,19 @@ public final class ActivityStackSupervisor implements DisplayListener {
return ActivityStackSupervisor.this; return ActivityStackSupervisor.this;
} }
boolean isAttached() { boolean isAttachedLocked() {
return mActivityDisplay != null; return mActivityDisplay != null;
} }
void getBounds(Point outBounds) { void getBounds(Point outBounds) {
synchronized (mService) {
if (mActivityDisplay != null) { if (mActivityDisplay != null) {
mActivityDisplay.getBounds(outBounds); mActivityDisplay.getBounds(outBounds);
} else { } else {
outBounds.set(0, 0); outBounds.set(0, 0);
} }
} }
}
// TODO: Make sure every change to ActivityRecord.visible results in a call to this. // TODO: Make sure every change to ActivityRecord.visible results in a call to this.
void setVisible(boolean visible) { void setVisible(boolean visible) {
@@ -3154,7 +3176,12 @@ public final class ActivityStackSupervisor implements DisplayListener {
return true; return true;
} }
void onTaskListEmpty() { void onTaskListEmptyLocked() {
mHandler.removeMessages(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
if (!mStack.isHomeStack()) {
detachLocked();
deleteActivityContainer(this);
}
mHandler.obtainMessage(CONTAINER_CALLBACK_TASK_LIST_EMPTY, this).sendToTarget(); mHandler.obtainMessage(CONTAINER_CALLBACK_TASK_LIST_EMPTY, this).sendToTarget();
} }
@@ -3173,7 +3200,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
mParentActivity = parent; mParentActivity = parent;
mCallback = callback; mCallback = callback;
mContainerState = CONTAINER_STATE_NO_SURFACE; mContainerState = CONTAINER_STATE_NO_SURFACE;
mIdString = "VirtualActivtyContainer{" + mStackId + ", parent=" + mParentActivity + "}"; mIdString = "VirtualActivityContainer{" + mStackId + ", parent=" + mParentActivity + "}";
} }
@Override @Override
@@ -3219,22 +3246,22 @@ public final class ActivityStackSupervisor implements DisplayListener {
} }
} }
setSurfaceIfReady(); setSurfaceIfReadyLocked();
if (DEBUG_STACK) Slog.d(TAG, "setSurface: " + this + " to display=" if (DEBUG_STACK) Slog.d(TAG, "setSurface: " + this + " to display="
+ virtualActivityDisplay); + virtualActivityDisplay);
} }
@Override @Override
boolean isAttached() { boolean isAttachedLocked() {
return mSurface != null && super.isAttached(); return mSurface != null && super.isAttachedLocked();
} }
@Override @Override
void setDrawn() { void setDrawn() {
synchronized (mService) { synchronized (mService) {
mDrawn = true; mDrawn = true;
setSurfaceIfReady(); setSurfaceIfReadyLocked();
} }
} }
@@ -3244,8 +3271,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
return false; return false;
} }
private void setSurfaceIfReady() { private void setSurfaceIfReadyLocked() {
if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReady: mDrawn=" + mDrawn + if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReadyLocked: mDrawn=" + mDrawn +
" mContainerState=" + mContainerState + " mSurface=" + mSurface); " mContainerState=" + mContainerState + " mSurface=" + mSurface);
if (mDrawn && mSurface != null && mContainerState == CONTAINER_STATE_NO_SURFACE) { if (mDrawn && mSurface != null && mContainerState == CONTAINER_STATE_NO_SURFACE) {
((VirtualActivityDisplay) mActivityDisplay).setSurface(mSurface); ((VirtualActivityDisplay) mActivityDisplay).setSurface(mSurface);