Merge "Some small tweaks to improve memory management."
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 7207e29..227900e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -55,6 +55,7 @@
 import android.util.AttributeSet;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.view.ActionMode;
 import android.view.ContextMenu;
@@ -642,6 +643,7 @@
         Window.Callback, KeyEvent.Callback,
         OnCreateContextMenuListener, ComponentCallbacks2 {
     private static final String TAG = "Activity";
+    private static final boolean DEBUG_LIFECYCLE = false;
 
     /** Standard activity result: operation canceled. */
     public static final int RESULT_CANCELED    = 0;
@@ -865,6 +867,7 @@
      * @see #onPostCreate
      */
     protected void onCreate(Bundle savedInstanceState) {
+        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
         if (mLastNonConfigurationInstances != null) {
             mAllLoaderManagers = mLastNonConfigurationInstances.loaders;
         }
@@ -1013,6 +1016,7 @@
      * @see #onResume
      */
     protected void onStart() {
+        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
         mCalled = true;
         
         if (!mLoadersStarted) {
@@ -1073,6 +1077,7 @@
      * @see #onPause
      */
     protected void onResume() {
+        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
         getApplication().dispatchActivityResumed(this);
         mCalled = true;
     }
@@ -1131,6 +1136,7 @@
     final void performSaveInstanceState(Bundle outState) {
         onSaveInstanceState(outState);
         saveManagedDialogs(outState);
+        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState);
     }
 
     /**
@@ -1261,6 +1267,7 @@
      * @see #onStop
      */
     protected void onPause() {
+        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this);
         getApplication().dispatchActivityPaused(this);
         mCalled = true;
     }
@@ -1347,6 +1354,7 @@
      * @see #onDestroy
      */
     protected void onStop() {
+        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this);
         if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
         getApplication().dispatchActivityStopped(this);
         mCalled = true;
@@ -1381,6 +1389,7 @@
      * @see #isFinishing
      */
     protected void onDestroy() {
+        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onDestroy " + this);
         mCalled = true;
 
         // dismiss any dialogs we are managing.
@@ -1432,6 +1441,7 @@
      * @param newConfig The new device configuration.
      */
     public void onConfigurationChanged(Configuration newConfig) {
+        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onConfigurationChanged " + this + ": " + newConfig);
         mCalled = true;
 
         mFragments.dispatchConfigurationChanged(newConfig);
@@ -1613,11 +1623,13 @@
     }
 
     public void onLowMemory() {
+        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onLowMemory " + this);
         mCalled = true;
         mFragments.dispatchLowMemory();
     }
 
     public void onTrimMemory(int level) {
+        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onTrimMemory " + this + ": " + level);
         mCalled = true;
         mFragments.dispatchTrimMemory(level);
     }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 98c4e10..1489b2c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -138,6 +138,7 @@
     private static final boolean DEBUG_BACKUP = true;
     private static final boolean DEBUG_CONFIGURATION = false;
     private static final boolean DEBUG_SERVICE = false;
+    private static final boolean DEBUG_MEMORY_TRIM = false;
     private static final long MIN_TIME_BETWEEN_GCS = 5*1000;
     private static final Pattern PATTERN_SEMICOLON = Pattern.compile(";");
     private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003;
@@ -2779,9 +2780,21 @@
         performStopActivityInner(r, null, false, saveState);
     }
 
-    private static class StopInfo {
+    private static class StopInfo implements Runnable {
+        ActivityClientRecord activity;
+        Bundle state;
         Bitmap thumbnail;
         CharSequence description;
+
+        @Override public void run() {
+            // Tell activity manager we have been stopped.
+            try {
+                if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + activity);
+                ActivityManagerNative.getDefault().activityStopped(
+                    activity.token, state, thumbnail, description);
+            } catch (RemoteException ex) {
+            }
+        }
     }
 
     private static final class ProviderRefCount {
@@ -2911,12 +2924,14 @@
             QueuedWork.waitToFinish();
         }
 
-        // Tell activity manager we have been stopped.
-        try {
-            ActivityManagerNative.getDefault().activityStopped(
-                r.token, r.state, info.thumbnail, info.description);
-        } catch (RemoteException ex) {
-        }
+        // Schedule the call to tell the activity manager we have
+        // stopped.  We don't do this immediately, because we want to
+        // have a chance for any other pending work (in particular memory
+        // trim requests) to complete before you tell the activity
+        // manager to proceed and allow us to go fully into the background.
+        info.activity = r;
+        info.state = r.state;
+        mH.post(info);
     }
 
     final void performRestartActivity(IBinder token) {
@@ -3749,6 +3764,7 @@
     }
 
     final void handleTrimMemory(int level) {
+        if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Trimming memory to level: " + level);
         WindowManagerImpl.getDefault().trimMemory(level);
         ArrayList<ComponentCallbacks2> callbacks;
 
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index a45a87e..52bd860 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -432,23 +432,24 @@
      */
     public void trimMemory(int level) {
         if (HardwareRenderer.isAvailable()) {
-            // On low and medium end gfx devices
-            if (!ActivityManager.isHighEndGfx(getDefaultDisplay())) {
-                if (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE) {
-                    // Destroy all hardware surfaces and resources associated to
-                    // known windows
-                    synchronized (this) {
-                        if (mViews == null) return;
-                        int count = mViews.length;
-                        for (int i = 0; i < count; i++) {
-                            mRoots[i].terminateHardwareResources();
-                        }
+            // On low-end gfx devices we trim when memory is moderate;
+            // on high-end devices we do this when low.
+            if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
+                    || (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE
+                            && !ActivityManager.isHighEndGfx(getDefaultDisplay()))) {
+                // Destroy all hardware surfaces and resources associated to
+                // known windows
+                synchronized (this) {
+                    if (mViews == null) return;
+                    int count = mViews.length;
+                    for (int i = 0; i < count; i++) {
+                        mRoots[i].terminateHardwareResources();
                     }
-                    // Force a full memory flush
-                    HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
-                    mNeedsEglTerminate = true;
-                    return;
                 }
+                // Force a full memory flush
+                HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
+                mNeedsEglTerminate = true;
+                return;
             }
             HardwareRenderer.trimMemory(level);
         }
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index f496c4e..9c955bd 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -886,7 +886,9 @@
             // the existing GL resources for the html5 video will be destroyed
             // at native side.
             // Here we just need to clean up the Surface Texture which is static.
-            HTML5VideoInline.cleanupSurfaceTexture();
+            if (level >= TRIM_MEMORY_UI_HIDDEN) {
+                HTML5VideoInline.cleanupSurfaceTexture();
+            }
             WebViewClassic.nativeOnTrimMemory(level);
         }
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 42c42c9..78b441a 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -13444,7 +13444,7 @@
             // an earlier hidden adjustment that isn't really for us... if
             // so, use the new hidden adjustment.
             if (!recursed && app.hidden) {
-                app.curAdj = app.curRawAdj = hiddenAdj;
+                app.curAdj = app.curRawAdj = app.nonStoppingAdj = hiddenAdj;
             }
             return app.curRawAdj;
         }
@@ -13468,7 +13468,7 @@
             // below foreground, so it is not worth doing work for it.
             app.adjType = "fixed";
             app.adjSeq = mAdjSeq;
-            app.curRawAdj = app.maxAdj;
+            app.curRawAdj = app.nonStoppingAdj = app.maxAdj;
             app.foregroundActivities = false;
             app.keeping = true;
             app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
@@ -13545,6 +13545,8 @@
             app.adjType = "bg-empty";
         }
 
+        boolean hasStoppingActivities = false;
+
         // Examine all activities if not already foreground.
         if (!app.foregroundActivities && activitiesSize > 0) {
             for (int j = 0; j < activitiesSize; j++) {
@@ -13559,15 +13561,20 @@
                     app.hidden = false;
                     app.foregroundActivities = true;
                     break;
-                } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED
-                        || r.state == ActivityState.STOPPING) {
-                    // Only upgrade adjustment.
+                } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) {
                     if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                         adj = ProcessList.PERCEPTIBLE_APP_ADJ;
-                        app.adjType = "stopping";
+                        app.adjType = "pausing";
                     }
                     app.hidden = false;
                     app.foregroundActivities = true;
+                } else if (r.state == ActivityState.STOPPING) {
+                    // We will apply the actual adjustment later, because
+                    // we want to allow this process to immediately go through
+                    // any memory trimming that is in effect.
+                    app.hidden = false;
+                    app.foregroundActivities = true;
+                    hasStoppingActivities = true;
                 }
             }
         }
@@ -13625,7 +13632,7 @@
         // this gives us a baseline and makes sure we don't get into an
         // infinite recursion.
         app.adjSeq = mAdjSeq;
-        app.curRawAdj = adj;
+        app.curRawAdj = app.nonStoppingAdj = adj;
 
         if (mBackupTarget != null && app == mBackupTarget.app) {
             // If possible we want to avoid killing apps while they're being backed up
@@ -13882,6 +13889,28 @@
             }
         }
 
+        if (adj == ProcessList.SERVICE_ADJ) {
+            if (doingAll) {
+                app.serviceb = mNewNumServiceProcs > (mNumServiceProcs/3);
+                mNewNumServiceProcs++;
+            }
+            if (app.serviceb) {
+                adj = ProcessList.SERVICE_B_ADJ;
+            }
+        } else {
+            app.serviceb = false;
+        }
+
+        app.nonStoppingAdj = adj;
+
+        if (hasStoppingActivities) {
+            // Only upgrade adjustment.
+            if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+                app.adjType = "stopping";
+            }
+        }
+
         app.curRawAdj = adj;
         
         //Slog.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
@@ -13915,18 +13944,6 @@
             }
         }
 
-        if (adj == ProcessList.SERVICE_ADJ) {
-            if (doingAll) {
-                app.serviceb = mNewNumServiceProcs > (mNumServiceProcs/3);
-                mNewNumServiceProcs++;
-            }
-            if (app.serviceb) {
-                adj = ProcessList.SERVICE_B_ADJ;
-            }
-        } else {
-            app.serviceb = false;
-        }
-
         app.curAdj = adj;
         app.curSchedGroup = schedGroup;
 
@@ -14138,7 +14155,7 @@
                 }
                 // If a process has held a wake lock for more
                 // than 50% of the time during this period,
-                // that sounds pad.  Kill!
+                // that sounds bad.  Kill!
                 if (doWakeKills && realtimeSince > 0
                         && ((wtimeUsed*100)/realtimeSince) >= 50) {
                     synchronized (stats) {
@@ -14186,23 +14203,6 @@
         computeOomAdjLocked(app, hiddenAdj, TOP_APP, false, doingAll);
 
         if (app.curRawAdj != app.setRawAdj) {
-            if (false) {
-                // Removing for now.  Forcing GCs is not so useful anymore
-                // with Dalvik, and the new memory level hint facility is
-                // better for what we need to do these days.
-                if (app.curRawAdj > ProcessList.FOREGROUND_APP_ADJ
-                        && app.setRawAdj <= ProcessList.FOREGROUND_APP_ADJ) {
-                    // If this app is transitioning from foreground to
-                    // non-foreground, have it do a gc.
-                    scheduleAppGcLocked(app);
-                } else if (app.curRawAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
-                        && app.setRawAdj < ProcessList.HIDDEN_APP_MIN_ADJ) {
-                    // Likewise do a gc when an app is moving in to the
-                    // background (such as a service stopping).
-                    scheduleAppGcLocked(app);
-                }
-            }
-
             if (wasKeeping && !app.keeping) {
                 // This app is no longer something we want to keep.  Note
                 // its current wake lock time to later know to kill it if
@@ -14319,6 +14319,7 @@
         if (factor < 1) factor = 1;
         int step = 0;
         int numHidden = 0;
+        int numTrimming = 0;
         
         // First update the OOM adjustment for each of the
         // application processes based on their current state.
@@ -14363,6 +14364,11 @@
                     app.killedBackground = true;
                     Process.killProcessQuiet(app.pid);
                 }
+                if (app.nonStoppingAdj >= ProcessList.HOME_APP_ADJ
+                        && app.nonStoppingAdj != ProcessList.SERVICE_B_ADJ
+                        && !app.killedBackground) {
+                    numTrimming++;
+                }
             }
         }
 
@@ -14376,7 +14382,7 @@
         // memory they want.
         if (numHidden <= (ProcessList.MAX_HIDDEN_APPS/2)) {
             final int N = mLruProcesses.size();
-            factor = numHidden/3;
+            factor = numTrimming/3;
             int minFactor = 2;
             if (mHomeProcess != null) minFactor++;
             if (mPreviousProcess != null) minFactor++;
@@ -14393,8 +14399,8 @@
             int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
             for (i=0; i<N; i++) {
                 ProcessRecord app = mLruProcesses.get(i);
-                if (app.curAdj >= ProcessList.HOME_APP_ADJ
-                        && app.curAdj != ProcessList.SERVICE_B_ADJ
+                if (app.nonStoppingAdj >= ProcessList.HOME_APP_ADJ
+                        && app.nonStoppingAdj != ProcessList.SERVICE_B_ADJ
                         && !app.killedBackground) {
                     if (app.trimMemoryLevel < curLevel && app.thread != null) {
                         try {
@@ -14426,7 +14432,7 @@
                                 break;
                         }
                     }
-                } else if (app.curAdj == ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+                } else if (app.nonStoppingAdj == ProcessList.HEAVY_WEIGHT_APP_ADJ) {
                     if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
                             && app.thread != null) {
                         try {
@@ -14437,7 +14443,7 @@
                     }
                     app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
                 } else {
-                    if ((app.curAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi)
+                    if ((app.nonStoppingAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi)
                             && app.pendingUiClean) {
                         // If this application is now in the background and it
                         // had done UI, then give it the special trim level to
@@ -14464,7 +14470,7 @@
             final int N = mLruProcesses.size();
             for (i=0; i<N; i++) {
                 ProcessRecord app = mLruProcesses.get(i);
-                if ((app.curAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi)
+                if ((app.nonStoppingAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi)
                         && app.pendingUiClean) {
                     if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
                             && app.thread != null) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index a01ed25..6596e1f 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -97,6 +97,11 @@
     // next activity.
     static final int PAUSE_TIMEOUT = 500;
 
+    // How long we wait for the activity to tell us it has stopped before
+    // giving up.  This is a good amount of time because we really need this
+    // from the application in order to get its saved state.
+    static final int STOP_TIMEOUT = 10*1000;
+
     // How long we can hold the sleep wake lock before giving up.
     static final int SLEEP_TIMEOUT = 5*1000;
 
@@ -280,6 +285,7 @@
     static final int DESTROY_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 5;
     static final int RESUME_TOP_ACTIVITY_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 6;
     static final int LAUNCH_TICK_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 7;
+    static final int STOP_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 8;
     
     final Handler mHandler = new Handler() {
         //public Handler() {
@@ -364,6 +370,17 @@
                         resumeTopActivityLocked(null);
                     }
                 } break;
+                case STOP_TIMEOUT_MSG: {
+                    ActivityRecord r = (ActivityRecord)msg.obj;
+                    // We don't at this point know if the activity is fullscreen,
+                    // so we need to be conservative and assume it isn't.
+                    Slog.w(TAG, "Activity stop timeout for " + r);
+                    synchronized (mService) {
+                        if (r.isInHistory()) {
+                            activityStoppedLocked(r, null, null, null);
+                        }
+                    }
+                } break;
             }
         }
     };
@@ -1000,31 +1017,38 @@
     final void activityStoppedLocked(ActivityRecord r, Bundle icicle, Bitmap thumbnail,
             CharSequence description) {
         if (DEBUG_SAVED_STATE) Slog.i(TAG, "Saving icicle of " + r + ": " + icicle);
-        r.icicle = icicle;
-        r.haveState = true;
-        r.updateThumbnail(thumbnail, description);
-        r.stopped = true;
-        if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r + " (stop complete)");
-        r.state = ActivityState.STOPPED;
-        if (!r.finishing) {
-            if (r.configDestroy) {
-                destroyActivityLocked(r, true, false, "stop-config");
-                resumeTopActivityLocked(null);
-            } else {
-                // Now that this process has stopped, we may want to consider
-                // it to be the previous app to try to keep around in case
-                // the user wants to return to it.
-                ProcessRecord fgApp = null;
-                if (mResumedActivity != null) {
-                    fgApp = mResumedActivity.app;
-                } else if (mPausingActivity != null) {
-                    fgApp = mPausingActivity.app;
-                }
-                if (r.app != null && fgApp != null && r.app != fgApp
-                        && r.lastVisibleTime > mService.mPreviousProcessVisibleTime
-                        && r.app != mService.mHomeProcess) {
-                    mService.mPreviousProcess = r.app;
-                    mService.mPreviousProcessVisibleTime = r.lastVisibleTime;
+        if (icicle != null) {
+            // If icicle is null, this is happening due to a timeout, so we
+            // haven't really saved the state.
+            r.icicle = icicle;
+            r.haveState = true;
+            r.updateThumbnail(thumbnail, description);
+        }
+        if (!r.stopped) {
+            if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r + " (stop complete)");
+            mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
+            r.stopped = true;
+            r.state = ActivityState.STOPPED;
+            if (!r.finishing) {
+                if (r.configDestroy) {
+                    destroyActivityLocked(r, true, false, "stop-config");
+                    resumeTopActivityLocked(null);
+                } else {
+                    // Now that this process has stopped, we may want to consider
+                    // it to be the previous app to try to keep around in case
+                    // the user wants to return to it.
+                    ProcessRecord fgApp = null;
+                    if (mResumedActivity != null) {
+                        fgApp = mResumedActivity.app;
+                    } else if (mPausingActivity != null) {
+                        fgApp = mPausingActivity.app;
+                    }
+                    if (r.app != null && fgApp != null && r.app != fgApp
+                            && r.lastVisibleTime > mService.mPreviousProcessVisibleTime
+                            && r.app != mService.mHomeProcess) {
+                        mService.mPreviousProcess = r.app;
+                        mService.mPreviousProcessVisibleTime = r.lastVisibleTime;
+                    }
                 }
             }
         }
@@ -3228,6 +3252,9 @@
                 if (mService.isSleeping()) {
                     r.setSleeping(true);
                 }
+                Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG);
+                msg.obj = r;
+                mHandler.sendMessageDelayed(msg, STOP_TIMEOUT);
             } catch (Exception e) {
                 // Maybe just ignore exceptions here...  if the process
                 // has crashed, our death notification will clean things
@@ -3694,6 +3721,7 @@
 
         // Get rid of any pending idle timeouts.
         mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
+        mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
         mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
         mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
         r.finishLaunchTickingLocked();
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index b64261d..4529ecc 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -63,6 +63,7 @@
     int hiddenAdj;              // If hidden, this is the adjustment to use
     int curRawAdj;              // Current OOM unlimited adjustment for this process
     int setRawAdj;              // Last set OOM unlimited adjustment for this process
+    int nonStoppingAdj;         // Adjustment not counting any stopping activities
     int curAdj;                 // Current OOM adjustment for this process
     int setAdj;                 // Last set OOM adjustment for this process
     int curSchedGroup;          // Currently desired scheduling class
@@ -199,6 +200,7 @@
                 pw.print(" hidden="); pw.print(hiddenAdj);
                 pw.print(" curRaw="); pw.print(curRawAdj);
                 pw.print(" setRaw="); pw.print(setRawAdj);
+                pw.print(" nonStopping="); pw.print(nonStoppingAdj);
                 pw.print(" cur="); pw.print(curAdj);
                 pw.print(" set="); pw.println(setAdj);
         pw.print(prefix); pw.print("curSchedGroup="); pw.print(curSchedGroup);