diff options
| author | 2011-01-21 13:34:36 -0800 | |
|---|---|---|
| committer | 2011-01-21 13:42:26 -0800 | |
| commit | 4eba96bb314d8ff773ea33d6cb3179f25751ecce (patch) | |
| tree | cac35a94f631043414175614e8045bb5edb3612e | |
| parent | d8b9d7cd1b2327b02e41edcddf94e64d481419d1 (diff) | |
Fix issue #3377999: Activities need to be stopped when sleeping
This is a band-aid over the existing kludgy stopping mechanism
where the semantics of stop are different in the activity manager
than in the clients.
This change is intended to be as unobtrusive as possible, only
impacting the sleep case. I have a different change that
completely reworks how we stop activities to simply this all
a lot by unifying the semantics between the server and client.
However, it is too late in HC for such an extensive change. Later
I'll revert this one and put in the better solution.
Change-Id: Id77f2db1ec83469cdd888acb8fbc4679daa7766e
| -rw-r--r-- | core/java/android/app/Activity.java | 1 | ||||
| -rw-r--r-- | core/java/android/app/ActivityManagerNative.java | 19 | ||||
| -rw-r--r-- | core/java/android/app/ActivityThread.java | 45 | ||||
| -rw-r--r-- | core/java/android/app/ApplicationThreadNative.java | 20 | ||||
| -rw-r--r-- | core/java/android/app/IActivityManager.java | 3 | ||||
| -rw-r--r-- | core/java/android/app/IApplicationThread.java | 3 | ||||
| -rwxr-xr-x | services/java/com/android/server/am/ActivityManagerService.java | 43 | ||||
| -rw-r--r-- | services/java/com/android/server/am/ActivityRecord.java | 26 | ||||
| -rw-r--r-- | services/java/com/android/server/am/ActivityStack.java | 139 |
9 files changed, 269 insertions, 30 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 22971a24beeb..055984f9fa32 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -4392,6 +4392,7 @@ public class Activity extends ContextThemeWrapper mFragments.dispatchPause(); mCalled = false; onPause(); + mResumed = false; if (!mCalled && getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.GINGERBREAD) { throw new SuperNotCalledException( diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 34788a5df4ca..c095c069918b 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -376,6 +376,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case ACTIVITY_SLEPT_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IBinder token = data.readStrongBinder(); + activitySlept(token); + reply.writeNoException(); + return true; + } + case ACTIVITY_DESTROYED_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder token = data.readStrongBinder(); @@ -1719,6 +1727,17 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); reply.recycle(); } + public void activitySlept(IBinder token) throws RemoteException + { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(token); + mRemote.transact(ACTIVITY_SLEPT_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY); + reply.readException(); + data.recycle(); + reply.recycle(); + } public void activityDestroyed(IBinder token) throws RemoteException { Parcel data = Parcel.obtain(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 2389f01cd54f..e400a1f16fcf 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -421,6 +421,10 @@ public final class ActivityThread { token); } + public final void scheduleSleeping(IBinder token, boolean sleeping) { + queueOrSendMessage(H.SLEEPING, token, sleeping ? 1 : 0); + } + public final void scheduleResumeActivity(IBinder token, boolean isForward) { queueOrSendMessage(H.RESUME_ACTIVITY, token, isForward ? 1 : 0); } @@ -929,6 +933,7 @@ public final class ActivityThread { public static final int SCHEDULE_CRASH = 134; public static final int DUMP_HEAP = 135; public static final int DUMP_ACTIVITY = 136; + public static final int SLEEPING = 137; String codeToString(int code) { if (DEBUG_MESSAGES) { switch (code) { @@ -969,6 +974,7 @@ public final class ActivityThread { case SCHEDULE_CRASH: return "SCHEDULE_CRASH"; case DUMP_HEAP: return "DUMP_HEAP"; case DUMP_ACTIVITY: return "DUMP_ACTIVITY"; + case SLEEPING: return "SLEEPING"; } } return "(unknown)"; @@ -1101,6 +1107,9 @@ public final class ActivityThread { case DUMP_ACTIVITY: handleDumpActivity((DumpComponentInfo)msg.obj); break; + case SLEEPING: + handleSleeping((IBinder)msg.obj, msg.arg1 != 0); + break; } if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what); } @@ -2615,6 +2624,42 @@ public final class ActivityThread { } } + private final void handleSleeping(IBinder token, boolean sleeping) { + ActivityClientRecord r = mActivities.get(token); + + if (r == null) { + Log.w(TAG, "handleWindowVisibility: no activity for token " + token); + return; + } + + if (sleeping) { + if (!r.stopped) { + try { + // Now we are idle. + r.activity.performStop(); + } catch (Exception e) { + if (!mInstrumentation.onException(r.activity, e)) { + throw new RuntimeException( + "Unable to stop activity " + + r.intent.getComponent().toShortString() + + ": " + e.toString(), e); + } + } + r.stopped = true; + } + // Tell activity manager we slept. + try { + ActivityManagerNative.getDefault().activitySlept(r.token); + } catch (RemoteException ex) { + } + } else { + if (r.stopped && r.activity.mVisibleFromServer) { + r.activity.performRestart(); + r.stopped = false; + } + } + } + private final void deliverResults(ActivityClientRecord r, List<ResultInfo> results) { final int N = results.size(); for (int i=0; i<N; i++) { diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index d28e8533ce6a..ef929333823c 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -97,6 +97,15 @@ public abstract class ApplicationThreadNative extends Binder return true; } + case SCHEDULE_SLEEPING_TRANSACTION: + { + data.enforceInterface(IApplicationThread.descriptor); + IBinder b = data.readStrongBinder(); + boolean sleeping = data.readInt() != 0; + scheduleSleeping(b, sleeping); + return true; + } + case SCHEDULE_RESUME_ACTIVITY_TRANSACTION: { data.enforceInterface(IApplicationThread.descriptor); @@ -503,6 +512,17 @@ class ApplicationThreadProxy implements IApplicationThread { data.recycle(); } + public final void scheduleSleeping(IBinder token, + boolean sleeping) throws RemoteException { + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(IApplicationThread.descriptor); + data.writeStrongBinder(token); + data.writeInt(sleeping ? 1 : 0); + mRemote.transact(SCHEDULE_SLEEPING_TRANSACTION, data, null, + IBinder.FLAG_ONEWAY); + data.recycle(); + } + public final void scheduleResumeActivity(IBinder token, boolean isForward) throws RemoteException { Parcel data = Parcel.obtain(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index abffbdb296f3..5d4380b3c18c 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -124,6 +124,8 @@ public interface IActivityManager extends IInterface { public void activityStopped(IBinder token, Bundle state, Bitmap thumbnail, CharSequence description) throws RemoteException; /* oneway */ + public void activitySlept(IBinder token) throws RemoteException; + /* oneway */ public void activityDestroyed(IBinder token) throws RemoteException; public String getCallingPackage(IBinder token) throws RemoteException; public ComponentName getCallingActivity(IBinder token) throws RemoteException; @@ -553,4 +555,5 @@ public interface IActivityManager extends IInterface { int DUMP_HEAP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+119; int START_ACTIVITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+120; int START_ACTIVITIES_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+121; + int ACTIVITY_SLEPT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+122; } diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index ecd199c4993c..16c3c5cf1985 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -48,6 +48,7 @@ public interface IApplicationThread extends IInterface { void scheduleStopActivity(IBinder token, boolean showWindow, int configChanges) throws RemoteException; void scheduleWindowVisibility(IBinder token, boolean showWindow) throws RemoteException; + void scheduleSleeping(IBinder token, boolean sleeping) throws RemoteException; void scheduleResumeActivity(IBinder token, boolean isForward) throws RemoteException; void scheduleSendResult(IBinder token, List<ResultInfo> results) throws RemoteException; void scheduleLaunchActivity(Intent intent, IBinder token, int ident, @@ -137,7 +138,7 @@ public interface IApplicationThread extends IInterface { int SCHEDULE_LOW_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+23; int SCHEDULE_ACTIVITY_CONFIGURATION_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+24; int SCHEDULE_RELAUNCH_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+25; - + int SCHEDULE_SLEEPING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+26; int PROFILER_CONTROL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+27; int SET_SCHEDULING_GROUP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+28; int SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+29; diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 9e9a4f21a2d3..6bb19b04736e 100755 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -5858,16 +5858,18 @@ public final class ActivityManagerService extends ActivityManagerNative return pfd; } + // Actually is sleeping or shutting down or whatever else in the future + // is an inactive state. + public boolean isSleeping() { + return mSleeping || mShuttingDown; + } + public void goingToSleep() { synchronized(this) { mSleeping = true; mWindowManager.setEventDispatching(false); - if (mMainStack.mResumedActivity != null) { - mMainStack.pauseIfSleepingLocked(); - } else { - Slog.w(TAG, "goingToSleep with no resumed activity!"); - } + mMainStack.stopIfSleepingLocked(); // Initialize the wake times of all processes. checkExcessivePowerUsageLocked(false); @@ -5891,7 +5893,7 @@ public final class ActivityManagerService extends ActivityManagerNative mWindowManager.setEventDispatching(false); if (mMainStack.mResumedActivity != null) { - mMainStack.pauseIfSleepingLocked(); + mMainStack.stopIfSleepingLocked(); final long endTime = System.currentTimeMillis() + timeout; while (mMainStack.mResumedActivity != null || mMainStack.mPausingActivity != null) { @@ -5915,13 +5917,30 @@ public final class ActivityManagerService extends ActivityManagerNative return timedout; } + public final void activitySlept(IBinder token) { + if (localLOGV) Slog.v( + TAG, "Activity slept: token=" + token); + + ActivityRecord r = null; + + final long origId = Binder.clearCallingIdentity(); + + synchronized (this) { + int index = mMainStack.indexOfTokenLocked(token); + if (index >= 0) { + r = (ActivityRecord)mMainStack.mHistory.get(index); + mMainStack.activitySleptLocked(r); + } + } + + Binder.restoreCallingIdentity(origId); + } + public void wakingUp() { synchronized(this) { - if (mMainStack.mGoingToSleep.isHeld()) { - mMainStack.mGoingToSleep.release(); - } mWindowManager.setEventDispatching(true); mSleeping = false; + mMainStack.awakeFromSleepingLocked(); mMainStack.resumeTopActivityLocked(null); } } @@ -7520,6 +7539,11 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(" Activities waiting to stop:"); dumpHistoryList(pw, mMainStack.mStoppingActivities, " ", "Stop", false); } + if (mMainStack.mGoingToSleepActivities.size() > 0) { + pw.println(" "); + pw.println(" Activities waiting to sleep:"); + dumpHistoryList(pw, mMainStack.mGoingToSleepActivities, " ", "Sleep", false); + } if (mMainStack.mFinishingActivities.size() > 0) { pw.println(" "); pw.println(" Activities waiting to finish:"); @@ -7531,6 +7555,7 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(" mResumedActivity: " + mMainStack.mResumedActivity); pw.println(" mFocusedActivity: " + mFocusedActivity); pw.println(" mLastPausedActivity: " + mMainStack.mLastPausedActivity); + pw.println(" mSleepTimeout: " + mMainStack.mSleepTimeout); if (dumpAll && mRecentTasks.size() > 0) { pw.println(" "); diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index e29da1ce5ee1..3dc3965f3486 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -102,6 +102,7 @@ class ActivityRecord extends IApplicationToken.Stub { boolean inHistory; // are we in the history stack? int launchMode; // the launch mode activity attribute. boolean visible; // does this activity's window need to be shown? + boolean sleeping; // have we told the activity to sleep? boolean waitingVisible; // true if waiting for a new act to become vis boolean nowVisible; // is this activity's window visible? boolean thumbnailNeeded;// has someone requested a thumbnail? @@ -168,9 +169,10 @@ class ActivityRecord extends IApplicationToken.Stub { pw.print(" launchMode="); pw.println(launchMode); pw.print(prefix); pw.print("fullscreen="); pw.print(fullscreen); pw.print(" visible="); pw.print(visible); - pw.print(" frozenBeforeDestroy="); pw.print(frozenBeforeDestroy); - pw.print(" thumbnailNeeded="); pw.print(thumbnailNeeded); + pw.print(" sleeping="); pw.print(sleeping); pw.print(" idle="); pw.println(idle); + pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy); + pw.print(" thumbnailNeeded="); pw.println(thumbnailNeeded); if (launchTime != 0 || startTime != 0) { pw.print(prefix); pw.print("launchTime="); TimeUtils.formatDuration(launchTime, pw); pw.print(" startTime="); @@ -597,7 +599,25 @@ class ActivityRecord extends IApplicationToken.Stub { public boolean isInterestingToUserLocked() { return visible || nowVisible || state == ActivityState.PAUSING || state == ActivityState.RESUMED; - } + } + + public void setSleeping(boolean _sleeping) { + if (sleeping == _sleeping) { + return; + } + if (app != null && app.thread != null) { + try { + app.thread.scheduleSleeping(this, _sleeping); + if (sleeping && !stack.mGoingToSleepActivities.contains(this)) { + stack.mGoingToSleepActivities.add(this); + } + sleeping = _sleeping; + } catch (RemoteException e) { + Slog.w(ActivityStack.TAG, "Exception thrown when sleeping: " + + intent.getComponent(), e); + } + } + } public String toString() { if (stringName != null) { diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index dd6ddd6e95b7..37619288d995 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -92,6 +92,9 @@ public class ActivityStack { // next activity. static final int PAUSE_TIMEOUT = 500; + // How long we can hold the sleep wake lock before giving up. + static final int SLEEP_TIMEOUT = 5*1000; + // How long we can hold the launch wake lock before giving up. static final int LAUNCH_TIMEOUT = 10*1000; @@ -158,6 +161,12 @@ public class ActivityStack { = new ArrayList<ActivityRecord>(); /** + * List of activities that are in the process of going to sleep. + */ + final ArrayList<ActivityRecord> mGoingToSleepActivities + = new ArrayList<ActivityRecord>(); + + /** * Animations that for the current transition have requested not to * be considered for the transition animation. */ @@ -238,9 +247,15 @@ public class ActivityStack { long mInitialStartTime = 0; + /** + * Set when we have taken too long waiting to go to sleep. + */ + boolean mSleepTimeout = false; + int mThumbnailWidth = -1; int mThumbnailHeight = -1; + static final int SLEEP_TIMEOUT_MSG = 8; static final int PAUSE_TIMEOUT_MSG = 9; static final int IDLE_TIMEOUT_MSG = 10; static final int IDLE_NOW_MSG = 11; @@ -255,6 +270,13 @@ public class ActivityStack { public void handleMessage(Message msg) { switch (msg.what) { + case SLEEP_TIMEOUT_MSG: { + if (mService.isSleeping()) { + Slog.w(TAG, "Sleep timeout! Sleeping now."); + mSleepTimeout = true; + checkReadyForSleepLocked(); + } + } break; case PAUSE_TIMEOUT_MSG: { IBinder token = (IBinder)msg.obj; // We don't at this point know if the activity is fullscreen, @@ -514,6 +536,7 @@ public class ActivityStack { mService.mHomeProcess = app; } mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName()); + r.sleeping = false; app.thread.scheduleLaunchActivity(new Intent(r.intent), r, System.identityHashCode(r), r.info, r.icicle, results, newIntents, !andResume, @@ -575,7 +598,7 @@ public class ActivityStack { mService.addRecentTaskLocked(r.task); } completeResumeLocked(r); - pauseIfSleepingLocked(); + checkReadyForSleepLocked(); } else { // This activity is not starting in the resumed state... which // should look like we asked it to pause+stop (but remain visible), @@ -631,8 +654,8 @@ public class ActivityStack { "activity", r.intent.getComponent(), false); } - void pauseIfSleepingLocked() { - if (mService.mSleeping || mService.mShuttingDown) { + void stopIfSleepingLocked() { + if (mService.isSleeping()) { if (!mGoingToSleep.isHeld()) { mGoingToSleep.acquire(); if (mLaunchingActivity.isHeld()) { @@ -640,16 +663,90 @@ public class ActivityStack { mService.mHandler.removeMessages(LAUNCH_TIMEOUT_MSG); } } + mHandler.removeMessages(SLEEP_TIMEOUT_MSG); + Message msg = mHandler.obtainMessage(SLEEP_TIMEOUT_MSG); + mHandler.sendMessageDelayed(msg, SLEEP_TIMEOUT); + checkReadyForSleepLocked(); + } + } - // If we are not currently pausing an activity, get the current - // one to pause. If we are pausing one, we will just let that stuff - // run and release the wake lock when all done. - if (mPausingActivity == null) { - if (DEBUG_PAUSE) Slog.v(TAG, "Sleep needs to pause..."); + void awakeFromSleepingLocked() { + mHandler.removeMessages(SLEEP_TIMEOUT_MSG); + mSleepTimeout = false; + if (mGoingToSleep.isHeld()) { + mGoingToSleep.release(); + } + // Ensure activities are no longer sleeping. + for (int i=mHistory.size()-1; i>=0; i--) { + ActivityRecord r = (ActivityRecord)mHistory.get(i); + r.setSleeping(false); + } + mGoingToSleepActivities.clear(); + } + + void activitySleptLocked(ActivityRecord r) { + mGoingToSleepActivities.remove(r); + checkReadyForSleepLocked(); + } + + void checkReadyForSleepLocked() { + if (!mService.isSleeping()) { + // Do not care. + return; + } + + if (!mSleepTimeout) { + if (mResumedActivity != null) { + // Still have something resumed; can't sleep until it is paused. + if (DEBUG_PAUSE) Slog.v(TAG, "Sleep needs to pause " + mResumedActivity); if (DEBUG_USER_LEAVING) Slog.v(TAG, "Sleep => pause with userLeaving=false"); startPausingLocked(false, true); + return; + } + if (mPausingActivity != null) { + // Still waiting for something to pause; can't sleep yet. + if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivity); + return; + } + + if (mStoppingActivities.size() > 0) { + // Still need to tell some activities to stop; can't sleep yet. + if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to stop " + + mStoppingActivities.size() + " activities"); + Message msg = Message.obtain(); + msg.what = IDLE_NOW_MSG; + mHandler.sendMessage(msg); + return; + } + + ensureActivitiesVisibleLocked(null, 0); + + // Make sure any stopped but visible activities are now sleeping. + // This ensures that the activity's onStop() is called. + for (int i=mHistory.size()-1; i>=0; i--) { + ActivityRecord r = (ActivityRecord)mHistory.get(i); + if (r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED) { + r.setSleeping(true); + } + } + + if (mGoingToSleepActivities.size() > 0) { + // Still need to tell some activities to sleep; can't sleep yet. + if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to sleep " + + mGoingToSleepActivities.size() + " activities"); + return; } } + + mHandler.removeMessages(SLEEP_TIMEOUT_MSG); + + if (mGoingToSleep.isHeld()) { + mGoingToSleep.release(); + } + if (mService.mShuttingDown) { + mService.notifyAll(); + } + } public final Bitmap screenshotActivities(ActivityRecord who) { @@ -813,6 +910,8 @@ public class ActivityStack { Message msg = Message.obtain(); msg.what = IDLE_NOW_MSG; mHandler.sendMessage(msg); + } else { + checkReadyForSleepLocked(); } } } else { @@ -822,15 +921,10 @@ public class ActivityStack { mPausingActivity = null; } - if (!mService.mSleeping && !mService.mShuttingDown) { + if (!mService.isSleeping()) { resumeTopActivityLocked(prev); } else { - if (mGoingToSleep.isHeld()) { - mGoingToSleep.release(); - } - if (mService.mShuttingDown) { - mService.notifyAll(); - } + checkReadyForSleepLocked(); } if (prev != null) { @@ -985,6 +1079,7 @@ public class ActivityStack { TAG, "Making visible and scheduling visibility: " + r); try { mService.mWindowManager.setAppVisibility(r, true); + r.sleeping = false; r.app.thread.scheduleWindowVisibility(r, true); r.stopFreezingScreenLocked(false); } catch (Exception e) { @@ -1114,6 +1209,8 @@ public class ActivityStack { // The activity may be waiting for stop, but that is no longer // appropriate for it. mStoppingActivities.remove(next); + mGoingToSleepActivities.remove(next); + next.sleeping = false; mWaitingVisibleActivities.remove(next); if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next); @@ -1315,10 +1412,11 @@ public class ActivityStack { System.identityHashCode(next), next.task.taskId, next.shortComponentName); + next.sleeping = false; next.app.thread.scheduleResumeActivity(next, mService.isNextTransitionForward()); - pauseIfSleepingLocked(); + checkReadyForSleepLocked(); } catch (Exception e) { // Whoops, need to restart this activity! @@ -2831,6 +2929,9 @@ public class ActivityStack { mService.mWindowManager.setAppVisibility(r, false); } r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags); + if (mService.isSleeping()) { + r.setSleeping(true); + } } catch (Exception e) { // Maybe just ignore exceptions here... if the process // has crashed, our death notification will clean things @@ -2874,7 +2975,7 @@ public class ActivityStack { mService.mWindowManager.setAppVisibility(s, false); } } - if (!s.waitingVisible && remove) { + if ((!s.waitingVisible || mService.isSleeping()) && remove) { if (localLOGV) Slog.v(TAG, "Ready to stop: " + s); if (stops == null) { stops = new ArrayList<ActivityRecord>(); @@ -3198,6 +3299,8 @@ public class ActivityStack { Message msg = Message.obtain(); msg.what = IDLE_NOW_MSG; mHandler.sendMessage(msg); + } else { + checkReadyForSleepLocked(); } } r.state = ActivityState.STOPPING; @@ -3207,6 +3310,7 @@ public class ActivityStack { // make sure the record is cleaned out of other places. mStoppingActivities.remove(r); + mGoingToSleepActivities.remove(r); mWaitingVisibleActivities.remove(r); if (mResumedActivity == r) { mResumedActivity = null; @@ -3434,6 +3538,7 @@ public class ActivityStack { void removeHistoryRecordsForAppLocked(ProcessRecord app) { removeHistoryRecordsForAppLocked(mLRUActivities, app); removeHistoryRecordsForAppLocked(mStoppingActivities, app); + removeHistoryRecordsForAppLocked(mGoingToSleepActivities, app); removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app); removeHistoryRecordsForAppLocked(mFinishingActivities, app); } |