Loading core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java +26 −3 Original line number Diff line number Diff line Loading @@ -17,8 +17,10 @@ package com.android.internal.os; import android.annotation.Nullable; import android.os.SystemClock; import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -50,6 +52,8 @@ public class KernelUidCpuFreqTimeReader { private long[] mCpuFreqs; private int mCpuFreqsCount; private long mLastTimeReadMs; private long mNowTimeMs; private SparseArray<long[]> mLastUidCpuFreqTimeMs = new SparseArray<>(); Loading @@ -64,7 +68,9 @@ public class KernelUidCpuFreqTimeReader { return; } try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) { mNowTimeMs = SystemClock.elapsedRealtime(); readDelta(reader, callback); mLastTimeReadMs = mNowTimeMs; mProcFileAvailable = true; } catch (IOException e) { mReadErrorCounter++; Loading Loading @@ -115,18 +121,35 @@ public class KernelUidCpuFreqTimeReader { return; } final long[] deltaUidTimeMs = new long[size]; final long[] curUidTimeMs = new long[size]; boolean notify = false; for (int i = 0; i < size; ++i) { // Times read will be in units of 10ms final long totalTimeMs = Long.parseLong(timesStr[i], 10) * 10; deltaUidTimeMs[i] = totalTimeMs - uidTimeMs[i]; uidTimeMs[i] = totalTimeMs; // If there is malformed data for any uid, then we just log about it and ignore // the data for that uid. if (deltaUidTimeMs[i] < 0 || totalTimeMs < 0) { final StringBuilder sb = new StringBuilder("Malformed cpu freq data for UID=") .append(uid).append("\n"); sb.append("data=").append("(").append(uidTimeMs[i]).append(",") .append(totalTimeMs).append(")").append("\n"); sb.append("times=").append("(") .append(TimeUtils.formatForLogging(mLastTimeReadMs)).append(",") .append(TimeUtils.formatForLogging(mNowTimeMs)).append(")"); Slog.wtf(TAG, sb.toString()); return; } curUidTimeMs[i] = totalTimeMs; notify = notify || (deltaUidTimeMs[i] > 0); } if (callback != null && notify) { if (notify) { System.arraycopy(curUidTimeMs, 0, uidTimeMs, 0, size); if (callback != null) { callback.onUidCpuFreqTime(uid, deltaUidTimeMs); } } } private void readCpuFreqs(String line, Callback callback) { if (mCpuFreqs == null) { Loading core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java +93 −0 Original line number Diff line number Diff line Loading @@ -98,6 +98,14 @@ public class KernelUidCpuFreqTimeReaderTest { } verifyNoMoreInteractions(mCallback); // Verify that there won't be a callback if the proc file values didn't change. Mockito.reset(mCallback, mBufferedReader); when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); verifyNoMoreInteractions(mCallback); // Verify that calling with a null callback doesn't result in any crashes Mockito.reset(mCallback, mBufferedReader); final long[][] newTimes2 = new long[uids.length][freqs.length]; Loading Loading @@ -130,6 +138,91 @@ public class KernelUidCpuFreqTimeReaderTest { verifyNoMoreInteractions(mCallback); } @Test public void testReadDelta_malformedData() throws Exception { final long[] freqs = {1, 12, 123, 1234, 12345, 123456}; final int[] uids = {1, 22, 333, 4444, 5555}; final long[][] times = new long[uids.length][freqs.length]; for (int i = 0; i < uids.length; ++i) { for (int j = 0; j < freqs.length; ++j) { times[i][j] = uids[i] * freqs[j] * 10; } } when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, times)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); for (int i = 0; i < uids.length; ++i) { verify(mCallback).onUidCpuFreqTime(uids[i], times[i]); } verifyNoMoreInteractions(mCallback); // Verify that there is no callback if any value in the proc file is -ve. Mockito.reset(mCallback, mBufferedReader); final long[][] newTimes1 = new long[uids.length][freqs.length]; for (int i = 0; i < uids.length; ++i) { for (int j = 0; j < freqs.length; ++j) { newTimes1[i][j] = (times[i][j] + uids[i] + freqs[j]) * 10; } } newTimes1[uids.length - 1][freqs.length - 1] *= -1; when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); for (int i = 0; i < uids.length; ++i) { if (i == uids.length - 1) { continue; } verify(mCallback).onUidCpuFreqTime(uids[i], subtract(newTimes1[i], times[i])); } verifyNoMoreInteractions(mCallback); // Verify that the internal state was not modified when the proc file had -ve value. Mockito.reset(mCallback, mBufferedReader); for (int i = 0; i < freqs.length; ++i) { newTimes1[uids.length - 1][i] = times[uids.length - 1][i]; } when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); verifyNoMoreInteractions(mCallback); // Verify that there is no callback if the values in the proc file are decreased. Mockito.reset(mCallback, mBufferedReader); final long[][] newTimes2 = new long[uids.length][freqs.length]; for (int i = 0; i < uids.length; ++i) { for (int j = 0; j < freqs.length; ++j) { newTimes2[i][j] = (newTimes1[i][j] + uids[i] * freqs[j]) * 10; } } newTimes2[uids.length - 1][freqs.length - 1] = newTimes1[uids.length - 1][freqs.length - 1] - 222; when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes2)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); for (int i = 0; i < uids.length; ++i) { if (i == uids.length - 1) { continue; } verify(mCallback).onUidCpuFreqTime(uids[i], subtract(newTimes2[i], newTimes1[i])); } verifyNoMoreInteractions(mCallback); // Verify that the internal state was not modified when the proc file had decreasing values. Mockito.reset(mCallback, mBufferedReader); for (int i = 0; i < freqs.length; ++i) { newTimes2[uids.length - 1][i] = newTimes1[uids.length - 1][i]; } when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes2)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); verifyNoMoreInteractions(mCallback); } private long[] subtract(long[] a1, long[] a2) { long[] val = new long[a1.length]; for (int i = 0; i < val.length; ++i) { Loading Loading
core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java +26 −3 Original line number Diff line number Diff line Loading @@ -17,8 +17,10 @@ package com.android.internal.os; import android.annotation.Nullable; import android.os.SystemClock; import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -50,6 +52,8 @@ public class KernelUidCpuFreqTimeReader { private long[] mCpuFreqs; private int mCpuFreqsCount; private long mLastTimeReadMs; private long mNowTimeMs; private SparseArray<long[]> mLastUidCpuFreqTimeMs = new SparseArray<>(); Loading @@ -64,7 +68,9 @@ public class KernelUidCpuFreqTimeReader { return; } try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) { mNowTimeMs = SystemClock.elapsedRealtime(); readDelta(reader, callback); mLastTimeReadMs = mNowTimeMs; mProcFileAvailable = true; } catch (IOException e) { mReadErrorCounter++; Loading Loading @@ -115,18 +121,35 @@ public class KernelUidCpuFreqTimeReader { return; } final long[] deltaUidTimeMs = new long[size]; final long[] curUidTimeMs = new long[size]; boolean notify = false; for (int i = 0; i < size; ++i) { // Times read will be in units of 10ms final long totalTimeMs = Long.parseLong(timesStr[i], 10) * 10; deltaUidTimeMs[i] = totalTimeMs - uidTimeMs[i]; uidTimeMs[i] = totalTimeMs; // If there is malformed data for any uid, then we just log about it and ignore // the data for that uid. if (deltaUidTimeMs[i] < 0 || totalTimeMs < 0) { final StringBuilder sb = new StringBuilder("Malformed cpu freq data for UID=") .append(uid).append("\n"); sb.append("data=").append("(").append(uidTimeMs[i]).append(",") .append(totalTimeMs).append(")").append("\n"); sb.append("times=").append("(") .append(TimeUtils.formatForLogging(mLastTimeReadMs)).append(",") .append(TimeUtils.formatForLogging(mNowTimeMs)).append(")"); Slog.wtf(TAG, sb.toString()); return; } curUidTimeMs[i] = totalTimeMs; notify = notify || (deltaUidTimeMs[i] > 0); } if (callback != null && notify) { if (notify) { System.arraycopy(curUidTimeMs, 0, uidTimeMs, 0, size); if (callback != null) { callback.onUidCpuFreqTime(uid, deltaUidTimeMs); } } } private void readCpuFreqs(String line, Callback callback) { if (mCpuFreqs == null) { Loading
core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java +93 −0 Original line number Diff line number Diff line Loading @@ -98,6 +98,14 @@ public class KernelUidCpuFreqTimeReaderTest { } verifyNoMoreInteractions(mCallback); // Verify that there won't be a callback if the proc file values didn't change. Mockito.reset(mCallback, mBufferedReader); when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); verifyNoMoreInteractions(mCallback); // Verify that calling with a null callback doesn't result in any crashes Mockito.reset(mCallback, mBufferedReader); final long[][] newTimes2 = new long[uids.length][freqs.length]; Loading Loading @@ -130,6 +138,91 @@ public class KernelUidCpuFreqTimeReaderTest { verifyNoMoreInteractions(mCallback); } @Test public void testReadDelta_malformedData() throws Exception { final long[] freqs = {1, 12, 123, 1234, 12345, 123456}; final int[] uids = {1, 22, 333, 4444, 5555}; final long[][] times = new long[uids.length][freqs.length]; for (int i = 0; i < uids.length; ++i) { for (int j = 0; j < freqs.length; ++j) { times[i][j] = uids[i] * freqs[j] * 10; } } when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, times)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); for (int i = 0; i < uids.length; ++i) { verify(mCallback).onUidCpuFreqTime(uids[i], times[i]); } verifyNoMoreInteractions(mCallback); // Verify that there is no callback if any value in the proc file is -ve. Mockito.reset(mCallback, mBufferedReader); final long[][] newTimes1 = new long[uids.length][freqs.length]; for (int i = 0; i < uids.length; ++i) { for (int j = 0; j < freqs.length; ++j) { newTimes1[i][j] = (times[i][j] + uids[i] + freqs[j]) * 10; } } newTimes1[uids.length - 1][freqs.length - 1] *= -1; when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); for (int i = 0; i < uids.length; ++i) { if (i == uids.length - 1) { continue; } verify(mCallback).onUidCpuFreqTime(uids[i], subtract(newTimes1[i], times[i])); } verifyNoMoreInteractions(mCallback); // Verify that the internal state was not modified when the proc file had -ve value. Mockito.reset(mCallback, mBufferedReader); for (int i = 0; i < freqs.length; ++i) { newTimes1[uids.length - 1][i] = times[uids.length - 1][i]; } when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); verifyNoMoreInteractions(mCallback); // Verify that there is no callback if the values in the proc file are decreased. Mockito.reset(mCallback, mBufferedReader); final long[][] newTimes2 = new long[uids.length][freqs.length]; for (int i = 0; i < uids.length; ++i) { for (int j = 0; j < freqs.length; ++j) { newTimes2[i][j] = (newTimes1[i][j] + uids[i] * freqs[j]) * 10; } } newTimes2[uids.length - 1][freqs.length - 1] = newTimes1[uids.length - 1][freqs.length - 1] - 222; when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes2)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); for (int i = 0; i < uids.length; ++i) { if (i == uids.length - 1) { continue; } verify(mCallback).onUidCpuFreqTime(uids[i], subtract(newTimes2[i], newTimes1[i])); } verifyNoMoreInteractions(mCallback); // Verify that the internal state was not modified when the proc file had decreasing values. Mockito.reset(mCallback, mBufferedReader); for (int i = 0; i < freqs.length; ++i) { newTimes2[uids.length - 1][i] = newTimes1[uids.length - 1][i]; } when(mBufferedReader.readLine()) .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes2)); mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback); verify(mCallback).onCpuFreqs(freqs); verifyNoMoreInteractions(mCallback); } private long[] subtract(long[] a1, long[] a2) { long[] val = new long[a1.length]; for (int i = 0; i < val.length; ++i) { Loading