Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0085752b authored by Sudheer Shanka's avatar Sudheer Shanka
Browse files

Log if there is malformed data in the proc file.

Bug: 63041570
Test: bit FrameworkCoreTests:com.android.internal.os.KernelUidCpuFreqTimeReaderTest
Change-Id: I0aa5b33a33770a1ec220d7772a57b2dae38725b0
parent 93c2838e
Loading
Loading
Loading
Loading
+26 −3
Original line number Diff line number Diff line
@@ -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;

@@ -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<>();

@@ -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++;
@@ -104,18 +110,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) {
+93 −0
Original line number Diff line number Diff line
@@ -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];
@@ -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) {