Work on issue #5465917: Wakelock *overflow* held for very long times

- Fix ordering problem in sync manager that would cause its wake
  locks to slightly appear in the system process when they should
  be fully accounted against the app.
- Allow the system process to have more wake lock names in its
  battery stats.
- In the bug report output, print totals of the wake locks for each
  process, to make it easier to parse what is being printed for things
  like the system process with a huge number of individual wake locks.

Change-Id: I3cf39330f22f3c51c11e65e4124150d73a7da2dd
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 4225393..7d683a5 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -990,8 +990,8 @@
                 mBound = false;
                 mContext.unbindService(this);
             }
-            mSyncWakeLock.setWorkSource(null);
             mSyncWakeLock.release();
+            mSyncWakeLock.setWorkSource(null);
         }
 
         @Override
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index e344197..438c536 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1095,6 +1095,16 @@
         }
     }
 
+    private static long computeWakeLock(Timer timer, long batteryRealtime, int which) {
+        if (timer != null) {
+            // Convert from microseconds to milliseconds with rounding
+            long totalTimeMicros = timer.getTotalTimeLocked(batteryRealtime, which);
+            long totalTimeMillis = (totalTimeMicros + 500) / 1000;
+            return totalTimeMillis;
+        }
+        return 0;
+    }
+
     /**
      *
      * @param sb a StringBuilder object.
@@ -1109,9 +1119,7 @@
             long batteryRealtime, String name, int which, String linePrefix) {
         
         if (timer != null) {
-            // Convert from microseconds to milliseconds with rounding
-            long totalTimeMicros = timer.getTotalTimeLocked(batteryRealtime, which);
-            long totalTimeMillis = (totalTimeMicros + 500) / 1000;
+            long totalTimeMillis = computeWakeLock(timer, batteryRealtime, which);
             
             int count = timer.getCountLocked(which);
             if (totalTimeMillis != 0) {
@@ -1735,6 +1743,8 @@
 
             Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
             if (wakelocks.size() > 0) {
+                long totalFull = 0, totalPartial = 0, totalWindow = 0;
+                int count = 0;
                 for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
                     : wakelocks.entrySet()) {
                     Uid.Wakelock wl = ent.getValue();
@@ -1754,6 +1764,44 @@
                         // Only print out wake locks that were held
                         pw.println(sb.toString());
                         uidActivity = true;
+                        count++;
+                    }
+                    totalFull += computeWakeLock(wl.getWakeTime(WAKE_TYPE_FULL),
+                            batteryRealtime, which);
+                    totalPartial += computeWakeLock(wl.getWakeTime(WAKE_TYPE_PARTIAL),
+                            batteryRealtime, which);
+                    totalWindow += computeWakeLock(wl.getWakeTime(WAKE_TYPE_WINDOW),
+                            batteryRealtime, which);
+                }
+                if (count > 1) {
+                    if (totalFull != 0 || totalPartial != 0 || totalWindow != 0) {
+                        sb.setLength(0);
+                        sb.append(prefix);
+                        sb.append("    TOTAL wake: ");
+                        boolean needComma = false;
+                        if (totalFull != 0) {
+                            needComma = true;
+                            formatTimeMs(sb, totalFull);
+                            sb.append("full");
+                        }
+                        if (totalPartial != 0) {
+                            if (needComma) {
+                                sb.append(", ");
+                            }
+                            needComma = true;
+                            formatTimeMs(sb, totalPartial);
+                            sb.append("partial");
+                        }
+                        if (totalWindow != 0) {
+                            if (needComma) {
+                                sb.append(", ");
+                            }
+                            needComma = true;
+                            formatTimeMs(sb, totalWindow);
+                            sb.append("window");
+                        }
+                        sb.append(" realtime");
+                        pw.println(sb.toString());
                     }
                 }
             }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index e2a2566..3e96c81 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -98,6 +98,10 @@
     // in to one common name.
     private static final int MAX_WAKELOCKS_PER_UID = 30;
 
+    // The system process gets more.  It is special.  Oh so special.
+    // With, you know, special needs.  Like this.
+    private static final int MAX_WAKELOCKS_PER_UID_IN_SYSTEM = 50;
+
     private static final String BATCHED_WAKELOCK_NAME = "*overflow*";
 
     private static int sNumSpeedSteps;
@@ -2895,12 +2899,10 @@
                 String wakelockName = in.readString();
                 Uid.Wakelock wakelock = new Wakelock();
                 wakelock.readFromParcelLocked(unpluggables, in);
-                if (mWakelockStats.size() < MAX_WAKELOCKS_PER_UID) {
-                    // We will just drop some random set of wakelocks if
-                    // the previous run of the system was an older version
-                    // that didn't impose a limit.
-                    mWakelockStats.put(wakelockName, wakelock);
-                }
+                // We will just drop some random set of wakelocks if
+                // the previous run of the system was an older version
+                // that didn't impose a limit.
+                mWakelockStats.put(wakelockName, wakelock);
             }
 
             int numSensors = in.readInt();
@@ -3904,7 +3906,9 @@
         public StopwatchTimer getWakeTimerLocked(String name, int type) {
             Wakelock wl = mWakelockStats.get(name);
             if (wl == null) {
-                if (mWakelockStats.size() > MAX_WAKELOCKS_PER_UID) {
+                final int N = mWakelockStats.size();
+                if (N > MAX_WAKELOCKS_PER_UID && (mUid != Process.SYSTEM_UID
+                        || N > MAX_WAKELOCKS_PER_UID_IN_SYSTEM)) {
                     name = BATCHED_WAKELOCK_NAME;
                     wl = mWakelockStats.get(name);
                 }