Merge "Get wakelock stats from SystemSuspend"
am: dff4801d6b

Change-Id: I96bda190d2935e3a21391e831d23f50526c8fc93
diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
index 3ac58e0..d53fada 100644
--- a/core/java/com/android/internal/os/KernelWakelockReader.java
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -27,6 +27,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.io.File;
 import java.io.FileInputStream;
 import java.util.Iterator;
 
@@ -38,6 +39,7 @@
     private static int sKernelWakelockUpdateVersion = 0;
     private static final String sWakelockFile = "/proc/wakelocks";
     private static final String sWakeupSourceFile = "/d/wakeup_sources";
+    private static final String sSysClassWakeupDir = "/sys/class/wakeup";
 
     private static final int[] PROC_WAKELOCKS_FORMAT = new int[] {
         Process.PROC_TAB_TERM|Process.PROC_OUT_STRING|                // 0: name
@@ -71,99 +73,108 @@
      * @return the updated data.
      */
     public final KernelWakelockStats readKernelWakelockStats(KernelWakelockStats staleStats) {
-        byte[] buffer = new byte[32*1024];
-        int len = 0;
-        boolean wakeup_sources;
-        final long startTime = SystemClock.uptimeMillis();
+        boolean useSystemSuspend = (new File(sSysClassWakeupDir)).exists();
 
-        final int oldMask = StrictMode.allowThreadDiskReadsMask();
-        try {
-            FileInputStream is;
-            try {
-                is = new FileInputStream(sWakelockFile);
-                wakeup_sources = false;
-            } catch (java.io.FileNotFoundException e) {
+        if (useSystemSuspend) {
+            WakeLockInfo[] wlStats = null;
+            if (mSuspendControlService == null) {
                 try {
-                    is = new FileInputStream(sWakeupSourceFile);
-                    wakeup_sources = true;
-                } catch (java.io.FileNotFoundException e2) {
-                    Slog.wtf(TAG, "neither " + sWakelockFile + " nor " +
-                            sWakeupSourceFile + " exists");
+                    mSuspendControlService = ISuspendControlService.Stub.asInterface(
+                        ServiceManager.getServiceOrThrow("suspend_control"));
+                } catch (ServiceNotFoundException e) {
+                    Slog.wtf(TAG, "Required service suspend_control not available", e);
                     return null;
                 }
             }
 
-            int cnt;
-            while ((cnt = is.read(buffer, len, buffer.length - len)) > 0) {
-                len += cnt;
+            try {
+                wlStats = mSuspendControlService.getWakeLockStats();
+                updateVersion(staleStats);
+                updateWakelockStats(wlStats, staleStats);
+            } catch (RemoteException e) {
+                Slog.wtf(TAG, "Failed to obtain wakelock stats from ISuspendControlService", e);
+                return null;
             }
 
-            is.close();
-        } catch (java.io.IOException e) {
-            Slog.wtf(TAG, "failed to read kernel wakelocks", e);
-            return null;
-        } finally {
-            StrictMode.setThreadPolicyMask(oldMask);
-        }
+            return removeOldStats(staleStats);
 
-        final long readTime = SystemClock.uptimeMillis() - startTime;
-        if (readTime > 100) {
-            Slog.w(TAG, "Reading wakelock stats took " + readTime + "ms");
-        }
+        } else {
+            byte[] buffer = new byte[32*1024];
+            int len = 0;
+            boolean wakeup_sources;
+            final long startTime = SystemClock.uptimeMillis();
 
-        if (len > 0) {
-            if (len >= buffer.length) {
-                Slog.wtf(TAG, "Kernel wake locks exceeded buffer size " + buffer.length);
+            final int oldMask = StrictMode.allowThreadDiskReadsMask();
+            try {
+                FileInputStream is;
+                try {
+                    is = new FileInputStream(sWakelockFile);
+                    wakeup_sources = false;
+                } catch (java.io.FileNotFoundException e) {
+                    try {
+                        is = new FileInputStream(sWakeupSourceFile);
+                        wakeup_sources = true;
+                    } catch (java.io.FileNotFoundException e2) {
+                        Slog.wtf(TAG, "neither " + sWakelockFile + " nor " +
+                                sWakeupSourceFile + " exists");
+                        return null;
+                    }
+                }
+
+                int cnt;
+                while ((cnt = is.read(buffer, len, buffer.length - len)) > 0) {
+                    len += cnt;
+                }
+
+                is.close();
+            } catch (java.io.IOException e) {
+                Slog.wtf(TAG, "failed to read kernel wakelocks", e);
+                return null;
+            } finally {
+                StrictMode.setThreadPolicyMask(oldMask);
             }
-            int i;
-            for (i=0; i<len; i++) {
-                if (buffer[i] == '\0') {
-                    len = i;
-                    break;
+
+            final long readTime = SystemClock.uptimeMillis() - startTime;
+            if (readTime > 100) {
+                Slog.w(TAG, "Reading wakelock stats took " + readTime + "ms");
+            }
+
+            if (len > 0) {
+                if (len >= buffer.length) {
+                    Slog.wtf(TAG, "Kernel wake locks exceeded buffer size " + buffer.length);
+                }
+                int i;
+                for (i=0; i<len; i++) {
+                    if (buffer[i] == '\0') {
+                        len = i;
+                        break;
+                    }
                 }
             }
+
+            updateVersion(staleStats);
+            parseProcWakelocks(buffer, len, wakeup_sources, staleStats);
+            return removeOldStats(staleStats);
         }
-
-        updateVersion(staleStats);
-
-        parseProcWakelocks(buffer, len, wakeup_sources, staleStats);
-
-        if (mSuspendControlService == null) {
-            try {
-                mSuspendControlService = ISuspendControlService.Stub.asInterface(
-                    ServiceManager.getServiceOrThrow("suspend_control"));
-            } catch (ServiceNotFoundException e) {
-                Slog.wtf(TAG, "Required service suspend_control not available", e);
-            }
-        }
-
-        try {
-            WakeLockInfo[] wlStats = mSuspendControlService.getWakeLockStats();
-            getNativeWakelockStats(wlStats, staleStats);
-        } catch (RemoteException e) {
-            Slog.wtf(TAG, "Failed to obtain wakelock stats from ISuspendControlService", e);
-        }
-
-        return removeOldStats(staleStats);
     }
 
     /**
-     * Reads native wakelock stats from SystemSuspend and updates staleStats with the new
-     * information.
+     * Updates statleStats with stats from  SystemSuspend.
      * @param staleStats Existing object to update.
      * @return the updated stats.
      */
     @VisibleForTesting
-    public KernelWakelockStats getNativeWakelockStats(WakeLockInfo[] wlStats,
+    public KernelWakelockStats updateWakelockStats(WakeLockInfo[] wlStats,
                                                       final KernelWakelockStats staleStats) {
         for (WakeLockInfo info : wlStats) {
             if (!staleStats.containsKey(info.name)) {
                 staleStats.put(info.name, new KernelWakelockStats.Entry((int) info.activeCount,
-                        info.totalTime, sKernelWakelockUpdateVersion));
+                        info.totalTime * 1000 /* ms to us */, sKernelWakelockUpdateVersion));
             } else {
                 KernelWakelockStats.Entry kwlStats = staleStats.get(info.name);
                 kwlStats.mCount = (int) info.activeCount;
-                kwlStats.mTotalTime = info.totalTime;
+                // Convert milliseconds to microseconds
+                kwlStats.mTotalTime = info.totalTime * 1000;
                 kwlStats.mVersion = sKernelWakelockUpdateVersion;
             }
         }
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
index 008085e..a935737 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
@@ -68,12 +68,7 @@
     private WakeLockInfo createWakeLockInfo(String name, int activeCount, long totalTime) {
         WakeLockInfo info = new WakeLockInfo();
         info.name = name;
-        info.pid = 1;
         info.activeCount = activeCount;
-        info.isActive = true;
-        info.activeSince = 0;
-        info.lastChange = 0;
-        info.maxTime = 0;
         info.totalTime = totalTime;
         return info;
     }
@@ -89,7 +84,7 @@
                                                         byte[] buffer, WakeLockInfo[] wlStats) {
         mReader.updateVersion(staleStats);
         mReader.parseProcWakelocks(buffer, buffer.length, true, staleStats);
-        mReader.getNativeWakelockStats(wlStats, staleStats);
+        mReader.updateWakelockStats(wlStats, staleStats);
         return mReader.removeOldStats(staleStats);
     }
 
@@ -101,7 +96,7 @@
         mReader = new KernelWakelockReader();
     }
 
-// ------------------------- Kernel Wakelock Stats Test ------------------------
+// ------------------------- Legacy Wakelock Stats Test ------------------------
     @SmallTest
     public void testParseEmptyFile() throws Exception {
         KernelWakelockStats staleStats = mReader.parseProcWakelocks(new byte[0], 0, true,
@@ -196,10 +191,10 @@
         assertFalse(staleStats.containsKey("Fakelock"));
     }
 
-// -------------------- Native (SystemSuspend) Wakelock Stats Test -------------------
+// -------------------- SystemSuspend Wakelock Stats Test -------------------
     @SmallTest
     public void testEmptyWakeLockInfoList() {
-        KernelWakelockStats staleStats = mReader.getNativeWakelockStats(new WakeLockInfo[0],
+        KernelWakelockStats staleStats = mReader.updateWakelockStats(new WakeLockInfo[0],
                 new KernelWakelockStats());
 
         assertTrue(staleStats.isEmpty());
@@ -208,9 +203,9 @@
     @SmallTest
     public void testOneWakeLockInfo() {
         WakeLockInfo[] wlStats = new WakeLockInfo[1];
-        wlStats[0] = createWakeLockInfo("WakeLock", 20, 10000);
+        wlStats[0] = createWakeLockInfo("WakeLock", 20, 1000);   // Milliseconds
 
-        KernelWakelockStats staleStats = mReader.getNativeWakelockStats(wlStats,
+        KernelWakelockStats staleStats = mReader.updateWakelockStats(wlStats,
                 new KernelWakelockStats());
 
         assertEquals(1, staleStats.size());
@@ -219,16 +214,16 @@
 
         KernelWakelockStats.Entry entry = staleStats.get("WakeLock");
         assertEquals(20, entry.mCount);
-        assertEquals(10000, entry.mTotalTime);
+        assertEquals(1000 * 1000, entry.mTotalTime);   // Microseconds
     }
 
     @SmallTest
     public void testTwoWakeLockInfos() {
         WakeLockInfo[] wlStats = new WakeLockInfo[2];
-        wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000);
-        wlStats[1] = createWakeLockInfo("WakeLock2", 20, 2000);
+        wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000); // Milliseconds
+        wlStats[1] = createWakeLockInfo("WakeLock2", 20, 2000); // Milliseconds
 
-        KernelWakelockStats staleStats = mReader.getNativeWakelockStats(wlStats,
+        KernelWakelockStats staleStats = mReader.updateWakelockStats(wlStats,
                 new KernelWakelockStats());
 
         assertEquals(2, staleStats.size());
@@ -238,17 +233,17 @@
 
         KernelWakelockStats.Entry entry1 = staleStats.get("WakeLock1");
         assertEquals(10, entry1.mCount);
-        assertEquals(1000, entry1.mTotalTime);
+        assertEquals(1000 * 1000, entry1.mTotalTime); // Microseconds
 
         KernelWakelockStats.Entry entry2 = staleStats.get("WakeLock2");
         assertEquals(20, entry2.mCount);
-        assertEquals(2000, entry2.mTotalTime);
+        assertEquals(2000 * 1000, entry2.mTotalTime); // Microseconds
     }
 
     @SmallTest
     public void testWakeLockInfosBecomeStale() {
         WakeLockInfo[] wlStats = new WakeLockInfo[1];
-        wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000);
+        wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000); // Milliseconds
 
         KernelWakelockStats staleStats = new KernelWakelockStats();
 
@@ -259,9 +254,9 @@
         assertTrue(staleStats.containsKey("WakeLock1"));
         KernelWakelockStats.Entry entry = staleStats.get("WakeLock1");
         assertEquals(10, entry.mCount);
-        assertEquals(1000, entry.mTotalTime);
+        assertEquals(1000 * 1000, entry.mTotalTime);  // Microseconds
 
-        wlStats[0] = createWakeLockInfo("WakeLock2", 20, 2000);
+        wlStats[0] = createWakeLockInfo("WakeLock2", 20, 2000); // Milliseconds
 
         readKernelWakelockStats(staleStats, new byte[0], wlStats);
 
@@ -271,146 +266,6 @@
         assertTrue(staleStats.containsKey("WakeLock2"));
         entry = staleStats.get("WakeLock2");
         assertEquals(20, entry.mCount);
-        assertEquals(2000, entry.mTotalTime);
-    }
-
-// -------------------- Aggregate  Wakelock Stats Tests --------------------
-    @SmallTest
-    public void testAggregateStatsEmpty() throws Exception {
-        KernelWakelockStats staleStats = new KernelWakelockStats();
-
-        byte[] buffer = new byte[0];
-        WakeLockInfo[] wlStats = new WakeLockInfo[0];
-
-        readKernelWakelockStats(staleStats, buffer, wlStats);
-
-        assertTrue(staleStats.isEmpty());
-    }
-
-    @SmallTest
-    public void testAggregateStatsNoNativeWakelocks() throws Exception {
-        KernelWakelockStats staleStats = new KernelWakelockStats();
-
-        byte[] buffer = new ProcFileBuilder()
-                .addLine("Wakelock", 34, 123) // Milliseconds
-                .getBytes();
-        WakeLockInfo[] wlStats = new WakeLockInfo[0];
-
-        readKernelWakelockStats(staleStats, buffer, wlStats);
-
-        assertEquals(1, staleStats.size());
-
-        assertTrue(staleStats.containsKey("Wakelock"));
-
-        KernelWakelockStats.Entry entry = staleStats.get("Wakelock");
-        assertEquals(34, entry.mCount);
-        assertEquals(1000 * 123, entry.mTotalTime);  // Microseconds
-    }
-
-    @SmallTest
-    public void testAggregateStatsNoKernelWakelocks() throws Exception {
-        KernelWakelockStats staleStats = new KernelWakelockStats();
-
-        byte[] buffer = new byte[0];
-        WakeLockInfo[] wlStats = new WakeLockInfo[1];
-        wlStats[0] = createWakeLockInfo("WakeLock", 10, 1000);
-
-        readKernelWakelockStats(staleStats, buffer, wlStats);
-
-        assertEquals(1, staleStats.size());
-
-        assertTrue(staleStats.containsKey("WakeLock"));
-
-        KernelWakelockStats.Entry entry = staleStats.get("WakeLock");
-        assertEquals(10, entry.mCount);
-        assertEquals(1000, entry.mTotalTime);
-    }
-
-    @SmallTest
-    public void testAggregateStatsBothKernelAndNativeWakelocks() throws Exception {
-        KernelWakelockStats staleStats = new KernelWakelockStats();
-
-        byte[] buffer = new ProcFileBuilder()
-                .addLine("WakeLock1", 34, 123)  // Milliseconds
-                .getBytes();
-        WakeLockInfo[] wlStats = new WakeLockInfo[1];
-        wlStats[0] = createWakeLockInfo("WakeLock2", 10, 1000);
-
-        readKernelWakelockStats(staleStats, buffer, wlStats);
-
-        assertEquals(2, staleStats.size());
-
-        assertTrue(staleStats.containsKey("WakeLock1"));
-        KernelWakelockStats.Entry entry1 = staleStats.get("WakeLock1");
-        assertEquals(34, entry1.mCount);
-        assertEquals(123 * 1000, entry1.mTotalTime);  // Microseconds
-
-        assertTrue(staleStats.containsKey("WakeLock2"));
-        KernelWakelockStats.Entry entry2 = staleStats.get("WakeLock2");
-        assertEquals(10, entry2.mCount);
-        assertEquals(1000, entry2.mTotalTime);
-    }
-
-    @SmallTest
-    public void testAggregateStatsUpdate() throws Exception {
-        KernelWakelockStats staleStats = new KernelWakelockStats();
-
-        byte[] buffer = new ProcFileBuilder()
-                .addLine("WakeLock1", 34, 123)  // Milliseconds
-                .addLine("WakeLock2", 46, 345)  // Milliseconds
-                .getBytes();
-        WakeLockInfo[] wlStats = new WakeLockInfo[2];
-        wlStats[0] = createWakeLockInfo("WakeLock3", 10, 1000);
-        wlStats[1] = createWakeLockInfo("WakeLock4", 20, 2000);
-
-        readKernelWakelockStats(staleStats, buffer, wlStats);
-
-        assertEquals(4, staleStats.size());
-
-        assertTrue(staleStats.containsKey("WakeLock1"));
-        assertTrue(staleStats.containsKey("WakeLock2"));
-        assertTrue(staleStats.containsKey("WakeLock3"));
-        assertTrue(staleStats.containsKey("WakeLock4"));
-
-        KernelWakelockStats.Entry entry1 = staleStats.get("WakeLock1");
-        assertEquals(34, entry1.mCount);
-        assertEquals(123 * 1000, entry1.mTotalTime); // Microseconds
-
-        KernelWakelockStats.Entry entry2 = staleStats.get("WakeLock2");
-        assertEquals(46, entry2.mCount);
-        assertEquals(345 * 1000, entry2.mTotalTime); // Microseconds
-
-        KernelWakelockStats.Entry entry3 = staleStats.get("WakeLock3");
-        assertEquals(10, entry3.mCount);
-        assertEquals(1000, entry3.mTotalTime);
-
-        KernelWakelockStats.Entry entry4 = staleStats.get("WakeLock4");
-        assertEquals(20, entry4.mCount);
-        assertEquals(2000, entry4.mTotalTime);
-
-        buffer = new ProcFileBuilder()
-                .addLine("WakeLock1", 45, 789)  // Milliseconds
-                .addLine("WakeLock1", 56, 123)  // Milliseconds
-                .getBytes();
-        wlStats = new WakeLockInfo[1];
-        wlStats[0] = createWakeLockInfo("WakeLock4", 40, 4000);
-
-        readKernelWakelockStats(staleStats, buffer, wlStats);
-
-        assertEquals(2, staleStats.size());
-
-        assertTrue(staleStats.containsKey("WakeLock1"));
-        assertTrue(staleStats.containsKey("WakeLock4"));
-
-        assertFalse(staleStats.containsKey("WakeLock2"));
-        assertFalse(staleStats.containsKey("WakeLock3"));
-
-        entry1 = staleStats.get("WakeLock1");
-        assertEquals(45 + 56, entry1.mCount);
-        assertEquals((789 + 123) * 1000, entry1.mTotalTime);  // Microseconds
-
-        entry2 = staleStats.get("WakeLock4");
-        assertEquals(40, entry2.mCount);
-        assertEquals(4000, entry4.mTotalTime);
+        assertEquals(2000 * 1000, entry.mTotalTime); // Micro seconds
     }
 }