Merge "Some battery improvements:" into gingerbread
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 6e6e86f..72bf825 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1427,7 +1427,9 @@
      * <li> The function will be called between {@link #onStop} and
      * {@link #onDestroy}.
      * <li> A new instance of the activity will <em>always</em> be immediately
-     * created after this one's {@link #onDestroy()} is called.
+     * created after this one's {@link #onDestroy()} is called.  In particular,
+     * <em>no</em> messages will be dispatched during this time (when the returned
+     * object does not have an activity to be associated with).
      * <li> The object you return here will <em>always</em> be available from
      * the {@link #getLastNonConfigurationInstance()} method of the following
      * activity instance as described there.
@@ -1440,6 +1442,15 @@
      * may change based on the configuration, including any data loaded from
      * resources such as strings, layouts, or drawables.
      * 
+     * <p>The guarantee of no message handling during the switch to the next
+     * activity simplifies use with active objects.  For example if your retained
+     * state is an {@link android.os.AsyncTask} you are guaranteed that its
+     * call back functions (like {@link android.os.AsyncTask#onPostExecute}) will
+     * not be called from the call here until you execute the next instance's
+     * {@link #onCreate(Bundle)}.  (Note however that there is of course no such
+     * guarantee for {@link android.os.AsyncTask#doInBackground} since that is
+     * running in a separate thread.)
+     *
      * @return Return any Object holding the desired state to propagate to the
      * next activity instance.
      */
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 1e88c56..ba8014f2 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -397,7 +397,7 @@
         }
     }
 
-    public final class HistoryItem implements Parcelable {
+    public final static class HistoryItem implements Parcelable {
         public HistoryItem next;
         
         public long time;
@@ -482,6 +482,18 @@
             dest.writeInt(states);
         }
         
+        public void setTo(HistoryItem o) {
+            time = o.time;
+            cmd = o.cmd;
+            batteryLevel = o.batteryLevel;
+            batteryStatus = o.batteryStatus;
+            batteryHealth = o.batteryHealth;
+            batteryPlugType = o.batteryPlugType;
+            batteryTemperature = o.batteryTemperature;
+            batteryVoltage = o.batteryVoltage;
+            states = o.states;
+        }
+
         public void setTo(long time, byte cmd, HistoryItem o) {
             this.time = time;
             this.cmd = cmd;
@@ -526,6 +538,10 @@
         }
     }
     
+    public abstract boolean startIteratingHistoryLocked();
+
+    public abstract boolean getNextHistoryLocked(HistoryItem out);
+
     /**
      * Return the current history of battery state changes.
      */
@@ -1688,8 +1704,8 @@
      */
     @SuppressWarnings("unused")
     public void dumpLocked(PrintWriter pw) {
-        HistoryItem rec = getHistory();
-        if (rec != null) {
+        final HistoryItem rec = new HistoryItem();
+        if (startIteratingHistoryLocked()) {
             pw.println("Battery History:");
             long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
             int oldState = 0;
@@ -1698,7 +1714,7 @@
             int oldPlug = -1;
             int oldTemp = -1;
             int oldVolt = -1;
-            while (rec != null) {
+            while (getNextHistoryLocked(rec)) {
                 pw.print("  ");
                 TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
                 pw.print(" ");
@@ -1803,7 +1819,6 @@
                     pw.println();
                 }
                 oldState = rec.states;
-                rec = rec.next;
             }
             pw.println("");
         }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index c2d003e..6e5c47f 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -51,6 +51,7 @@
 import java.util.Iterator;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
 
 /**
  * All information we are collecting about things that can happen that impact
@@ -3834,6 +3835,22 @@
         }
     }
 
+    private HistoryItem mHistoryIterator;
+
+    public boolean startIteratingHistoryLocked() {
+        return (mHistoryIterator = mHistory) != null;
+    }
+
+    public boolean getNextHistoryLocked(HistoryItem out) {
+        HistoryItem cur = mHistoryIterator;
+        if (cur == null) {
+            return false;
+        }
+        out.setTo(cur);
+        mHistoryIterator = cur.next;
+        return true;
+    }
+
     @Override
     public HistoryItem getHistory() {
         return mHistory;
@@ -3960,7 +3977,7 @@
             }
             if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
                 if (mFile != null) {
-                    writeLocked();
+                    writeAsyncLocked();
                 }
             }
         }
@@ -4356,11 +4373,22 @@
     }
 
     public void shutdownLocked() {
-        writeLocked();
+        writeSyncLocked();
         mShuttingDown = true;
     }
     
-    public void writeLocked() {
+    Parcel mPendingWrite = null;
+    final ReentrantLock mWriteLock = new ReentrantLock();
+
+    public void writeAsyncLocked() {
+        writeLocked(false);
+    }
+
+    public void writeSyncLocked() {
+        writeLocked(true);
+    }
+
+    void writeLocked(boolean sync) {
         if (mFile == null) {
             Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
             return;
@@ -4370,23 +4398,51 @@
             return;
         }
         
+        Parcel out = Parcel.obtain();
+        writeSummaryToParcel(out);
+        mLastWriteTime = SystemClock.elapsedRealtime();
+
+        if (mPendingWrite != null) {
+            mPendingWrite.recycle();
+        }
+        mPendingWrite = out;
+
+        if (sync) {
+            commitPendingDataToDisk();
+        } else {
+            Thread thr = new Thread("BatteryStats-Write") {
+                @Override
+                public void run() {
+                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+                    commitPendingDataToDisk();
+                }
+            };
+            thr.start();
+        }
+    }
+
+    public void commitPendingDataToDisk() {
+        Parcel next;
+        synchronized (this) {
+            next = mPendingWrite;
+            mPendingWrite = null;
+
+            mWriteLock.lock();
+        }
+
         try {
             FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
-            Parcel out = Parcel.obtain();
-            writeSummaryToParcel(out);
-            stream.write(out.marshall());
-            out.recycle();
-
+            stream.write(next.marshall());
             stream.flush();
             stream.close();
             mFile.commit();
-
-            mLastWriteTime = SystemClock.elapsedRealtime();
-            return;
         } catch (IOException e) {
             Slog.w("BatteryStats", "Error writing battery statistics", e);
+            mFile.rollback();
+        } finally {
+            next.recycle();
+            mWriteLock.unlock();
         }
-        mFile.rollback();
     }
 
     static byte[] readFully(FileInputStream stream) throws java.io.IOException {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 9835098..d7a1ac25 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -8316,6 +8316,11 @@
             return;
         }
         
+        if (mDisplay == null) {
+            // Not yet initialized, nothing to do.
+            return;
+        }
+
         boolean recoveringMemory = false;
         if (mForceRemoves != null) {
             recoveringMemory = true;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index cf767ca..3172077 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1383,7 +1383,7 @@
         mBatteryStatsService = new BatteryStatsService(new File(
                 systemDir, "batterystats.bin").toString());
         mBatteryStatsService.getActiveStatistics().readLocked();
-        mBatteryStatsService.getActiveStatistics().writeLocked();
+        mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
         mOnBattery = mBatteryStatsService.getActiveStatistics().getIsOnBattery();
         mBatteryStatsService.getActiveStatistics().setCallback(this);
         
@@ -1536,7 +1536,7 @@
 
                 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
                     mLastWriteTime = now;
-                    mBatteryStatsService.getActiveStatistics().writeLocked();
+                    mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
                 }
             }
         }