Battery stats: track actually running time

Use the uptime while creating the battery stats history to
generate a new event indicating when the CPU is actually running.
We can do this in combination with the new event reporting when
the CPU comes awake, looking at the difference between the
uptime and elapsed time at that point to determine when it last
when to sleep.

Also use this information to generate a new set of aggregated
states, the uptime caused by each wake reason.

Finally use new radio down timestamp to adjust the times we
compute for radio use.  Note that this information is not (yet)
being used to adjust how these are recorded in the history.

Change-Id: I723b3b526c8e7d64de0cac9d1193e04132d5a3e4
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 9de3efe..41ffdc1 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -103,6 +103,7 @@
     private long mNextNonWakeup;
     int mBroadcastRefCount = 0;
     PowerManager.WakeLock mWakeLock;
+    boolean mLastWakeLockUnimportantForLogging;
     ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
     final AlarmHandler mHandler = new AlarmHandler();
     ClockReceiver mClockReceiver;
@@ -1345,17 +1346,21 @@
      */
     void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, boolean first) {
         try {
-            mWakeLock.setUnimportantForLogging(pi == mTimeTickSender);
+            final boolean unimportant = pi == mTimeTickSender;
+            mWakeLock.setUnimportantForLogging(unimportant);
             if (ws != null) {
-                if (first) {
+                if (first || mLastWakeLockUnimportantForLogging) {
                     mWakeLock.setHistoryTag(pi.getTag(
                             type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP
                                     ? "*walarm*:" : "*alarm*:"));
                 } else {
                     mWakeLock.setHistoryTag(null);
                 }
+                mLastWakeLockUnimportantForLogging = unimportant;
                 mWakeLock.setWorkSource(ws);
                 return;
+            } else {
+                mLastWakeLockUnimportantForLogging = false;
             }
 
             final int uid = ActivityManagerNative.getDefault()
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index a09d605..5273cec 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -348,7 +348,7 @@
      */
     private void notifyInterfaceClassActivity(int type, boolean active, long tsNanos) {
         try {
-            getBatteryStats().noteDataConnectionActive(type, active);
+            getBatteryStats().noteDataConnectionActive(type, active, tsNanos);
         } catch (RemoteException e) {
         }
 
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index fa4a9d1..0ddb827 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -248,10 +248,10 @@
         }
     }
 
-    public void noteDataConnectionActive(int type, boolean active) {
+    public void noteDataConnectionActive(int type, boolean active, long timestampNs) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteDataConnectionActive(type, active);
+            mStats.noteDataConnectionActive(type, active, timestampNs);
         }
     }
 
@@ -570,9 +570,12 @@
                 int num;
                 while ((num=nativeWaitWakeup(mIrqs, mReasons)) >= 0) {
                     synchronized (mStats) {
-                        for (int i=0; i<num; i++) {
-                            //Slog.i(TAG, "Wakeup: irq #" + mIrqs[i] + " reason=" + mReasons[i]);
-                            mStats.noteWakeupReasonLocked(mIrqs[i], mReasons[i]);
+                        if (num > 0) {
+                            for (int i=0; i<num; i++) {
+                                mStats.noteWakeupReasonLocked(mReasons[i]);
+                            }
+                        } else {
+                            mStats.noteWakeupReasonLocked("unknown");
                         }
                     }
                 }
@@ -653,7 +656,7 @@
                     dumpHelp(pw);
                     return;
                 } else if ("-a".equals(arg)) {
-                    // fall through
+                    flags |= BatteryStats.DUMP_VERBOSE;
                 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
                     pw.println("Unknown option: " + arg);
                     dumpHelp(pw);
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index 22cc519..da4cc48 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -139,16 +139,21 @@
             }
             endpos++;
         }
-        if (i == 0) {
+        // For now we are not separating out the first irq.
+        // This is because in practice there are always multiple
+        // lines of wakeup reasons, so it is better to just treat
+        // them all together as a single string.
+        if (false && i == 0) {
             firstirq = irq;
         } else {
-            int len = snprintf(mergedreasonpos, remainreasonlen, ":%d", irq);
+            int len = snprintf(mergedreasonpos, remainreasonlen,
+                    i == 0 ? "%d" : ":%d", irq);
             if (len >= 0 && len < remainreasonlen) {
                 mergedreasonpos += len;
                 remainreasonlen -= len;
             }
         }
-        int len = snprintf(mergedreasonpos, remainreasonlen, i == 0 ? "%s" : ":%s", pos);
+        int len = snprintf(mergedreasonpos, remainreasonlen, ":%s", pos);
         if (len >= 0 && len < remainreasonlen) {
             mergedreasonpos += len;
             remainreasonlen -= len;