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

Commit c9472b61 authored by Sudheer Shanka's avatar Sudheer Shanka Committed by Android (Google) Code Review
Browse files

Merge "Use cpu freq times to calculate power consumed by an uid."

parents cded5ffd b8ad5943
Loading
Loading
Loading
Loading
+20 −16
Original line number Diff line number Diff line
@@ -3667,9 +3667,12 @@ public abstract class BatteryStats implements Parcelable {
                        0 /* old cpu power, keep for compatibility */);
            }

            // If the cpuFreqs is null, then don't bother checking for cpu freq times.
            if (cpuFreqs != null) {
                final long[] cpuFreqTimeMs = u.getCpuFreqTimes(which);
            // If total cpuFreqTimes is null, then we don't need to check for screenOffCpuFreqTimes.
            if (cpuFreqTimeMs != null) {
                // If total cpuFreqTimes is null, then we don't need to check for
                // screenOffCpuFreqTimes.
                if (cpuFreqTimeMs != null && cpuFreqTimeMs.length == cpuFreqs.length) {
                    sb.setLength(0);
                    for (int i = 0; i < cpuFreqTimeMs.length; ++i) {
                        sb.append((i == 0 ? "" : ",") + cpuFreqTimeMs[i]);
@@ -3687,6 +3690,7 @@ public abstract class BatteryStats implements Parcelable {
                    dumpLine(pw, uid, category, CPU_TIMES_AT_FREQ_DATA, UID_TIMES_TYPE_ALL,
                            cpuFreqTimeMs.length, sb.toString());
                }
            }

            final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats
                    = u.getProcessStats();
+114 −41
Original line number Diff line number Diff line
@@ -119,7 +119,7 @@ public class BatteryStatsImpl extends BatteryStats {
    private static final int MAGIC = 0xBA757475; // 'BATSTATS'
    // Current on-disk Parcel version
    private static final int VERSION = 164 + (USE_OLD_HISTORY ? 1000 : 0);
    private static final int VERSION = 165 + (USE_OLD_HISTORY ? 1000 : 0);
    // Maximum number of items we will record in the history.
    private static final int MAX_HISTORY_ITEMS;
@@ -232,7 +232,7 @@ public class BatteryStatsImpl extends BatteryStats {
            switch (msg.what) {
                case MSG_UPDATE_WAKELOCKS:
                    synchronized (BatteryStatsImpl.this) {
                        updateCpuTimeLocked(false /* updateCpuFreqData */);
                        updateCpuTimeLocked();
                    }
                    if (cb != null) {
                        cb.batteryNeedsCpuUpdate();
@@ -1082,6 +1082,10 @@ public class BatteryStatsImpl extends BatteryStats {
            }
        }
        public int getSize() {
            return mCounts == null ? 0 : mCounts.length;
        }
        /**
         * Clear state of this counter.
         */
@@ -3530,7 +3534,7 @@ public class BatteryStatsImpl extends BatteryStats {
                Slog.d(TAG, "Updating cpu time because screen is now " + (screenOff ? "off" : "on")
                        + " and battery is " + (unplugged ? "on" : "off"));
            }
            updateCpuTimeLocked(true /* updateCpuFreqData */);
            updateCpuTimeLocked();
            mOnBatteryTimeBase.setRunning(unplugged, uptime, realtime);
            mOnBatteryScreenOffTimeBase.setRunning(unplugged && screenOff, uptime, realtime);
@@ -10246,6 +10250,7 @@ public class BatteryStatsImpl extends BatteryStats {
    // Used in updateCpuTimeLocked().
    long mTempTotalCpuUserTimeUs;
    long mTempTotalCpuSystemTimeUs;
    long[][] mWakeLockAllocationsUs;
    /**
     * Reads the newest memory stats from the kernel.
@@ -10279,7 +10284,7 @@ public class BatteryStatsImpl extends BatteryStats {
     * and we are on battery with screen off, we give more of the cpu time to those apps holding
     * wakelocks. If the screen is on, we just assign the actual cpu time an app used.
     */
    public void updateCpuTimeLocked(boolean updateCpuFreqData) {
    public void updateCpuTimeLocked() {
        if (mPowerProfile == null) {
            return;
        }
@@ -10288,6 +10293,10 @@ public class BatteryStatsImpl extends BatteryStats {
            Slog.d(TAG, "!Cpu updating!");
        }
        if (mCpuFreqs == null) {
            mCpuFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile);
        }
        // Calculate the wakelocks we have to distribute amongst. The system is excluded as it is
        // usually holding the wakelock on behalf of an app.
        // And Only distribute cpu power to wakelocks if the screen is off and we're on battery.
@@ -10320,12 +10329,15 @@ public class BatteryStatsImpl extends BatteryStats {
        }
        mUserInfoProvider.refreshUserIds();
        final SparseLongArray updatedUids = new SparseLongArray();
        final SparseLongArray updatedUids = mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()
                ? null : new SparseLongArray();
        readKernelUidCpuTimesLocked(partialTimersToConsider, updatedUids);
        // updatedUids=null means /proc/uid_time_in_state provides snapshots of per-cluster cpu
        // freqs, so no need to approximate these values.
        if (updatedUids != null) {
            updateClusterSpeedTimes(updatedUids);
        if (updateCpuFreqData) {
            readKernelUidCpuFreqTimesLocked();
        }
        readKernelUidCpuFreqTimesLocked(partialTimersToConsider);
    }
    /**
@@ -10526,17 +10538,17 @@ public class BatteryStatsImpl extends BatteryStats {
    /**
     * Take a snapshot of the cpu times spent by each uid in each freq and update the
     * corresponding counters.
     *
     * @param partialTimers The wakelock holders among which the cpu freq times will be distributed.
     */
    @VisibleForTesting
    public void readKernelUidCpuFreqTimesLocked() {
        mKernelUidCpuFreqTimeReader.readDelta(new KernelUidCpuFreqTimeReader.Callback() {
            @Override
            public void onCpuFreqs(long[] cpuFreqs) {
                mCpuFreqs = cpuFreqs;
            }
            @Override
            public void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs) {
    public void readKernelUidCpuFreqTimesLocked(@Nullable ArrayList<StopwatchTimer> partialTimers) {
        final boolean perClusterTimesAvailable =
                mKernelUidCpuFreqTimeReader.perClusterTimesAvailable();
        final int numWakelocks = partialTimers == null ? 0 : partialTimers.size();
        final int numClusters = mPowerProfile.getNumCpuClusters();
        mWakeLockAllocationsUs = null;
        mKernelUidCpuFreqTimeReader.readDelta((uid, cpuFreqTimeMs) -> {
            uid = mapUid(uid);
            if (Process.isIsolated(uid)) {
                mKernelUidCpuFreqTimeReader.removeUid(uid);
@@ -10549,17 +10561,86 @@ public class BatteryStatsImpl extends BatteryStats {
                return;
            }
            final Uid u = getUidStatsLocked(uid);
                if (u.mCpuFreqTimeMs == null) {
            if (u.mCpuFreqTimeMs == null || u.mCpuFreqTimeMs.getSize() != cpuFreqTimeMs.length) {
                u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase);
            }
            u.mCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs);
                if (u.mScreenOffCpuFreqTimeMs == null) {
            if (u.mScreenOffCpuFreqTimeMs == null ||
                    u.mScreenOffCpuFreqTimeMs.getSize() != cpuFreqTimeMs.length) {
                u.mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray(
                        mOnBatteryScreenOffTimeBase);
            }
            u.mScreenOffCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs);
            if (perClusterTimesAvailable) {
                if (u.mCpuClusterSpeedTimesUs == null ||
                        u.mCpuClusterSpeedTimesUs.length != numClusters) {
                    u.mCpuClusterSpeedTimesUs = new LongSamplingCounter[numClusters][];
                }
                if (numWakelocks > 0 && mWakeLockAllocationsUs == null) {
                    mWakeLockAllocationsUs = new long[numClusters][];
                }
                int freqIndex = 0;
                for (int cluster = 0; cluster < numClusters; ++cluster) {
                    final int speedsInCluster = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
                    if (u.mCpuClusterSpeedTimesUs[cluster] == null ||
                            u.mCpuClusterSpeedTimesUs[cluster].length != speedsInCluster) {
                        u.mCpuClusterSpeedTimesUs[cluster]
                                = new LongSamplingCounter[speedsInCluster];
                    }
                    if (numWakelocks > 0 && mWakeLockAllocationsUs[cluster] == null) {
                        mWakeLockAllocationsUs[cluster] = new long[speedsInCluster];
                    }
                    final LongSamplingCounter[] cpuTimesUs = u.mCpuClusterSpeedTimesUs[cluster];
                    for (int speed = 0; speed < speedsInCluster; ++speed) {
                        if (cpuTimesUs[speed] == null) {
                            cpuTimesUs[speed] = new LongSamplingCounter(mOnBatteryTimeBase);
                        }
                        final long appAllocationUs;
                        if (mWakeLockAllocationsUs != null) {
                            appAllocationUs =
                                    (cpuFreqTimeMs[freqIndex] * 1000 * WAKE_LOCK_WEIGHT) / 100;
                            mWakeLockAllocationsUs[cluster][speed] +=
                                    (cpuFreqTimeMs[freqIndex] * 1000 - appAllocationUs);
                        } else {
                            appAllocationUs = cpuFreqTimeMs[freqIndex] * 1000;
                        }
                        cpuTimesUs[speed].addCountLocked(appAllocationUs);
                        freqIndex++;
                    }
                }
            }
        });
        if (mWakeLockAllocationsUs != null) {
            for (int i = 0; i < numWakelocks; ++i) {
                final Uid u = partialTimers.get(i).mUid;
                if (u.mCpuClusterSpeedTimesUs == null ||
                        u.mCpuClusterSpeedTimesUs.length != numClusters) {
                    u.mCpuClusterSpeedTimesUs = new LongSamplingCounter[numClusters][];
                }
                for (int cluster = 0; cluster < numClusters; ++cluster) {
                    final int speedsInCluster = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
                    if (u.mCpuClusterSpeedTimesUs[cluster] == null ||
                            u.mCpuClusterSpeedTimesUs[cluster].length != speedsInCluster) {
                        u.mCpuClusterSpeedTimesUs[cluster]
                                = new LongSamplingCounter[speedsInCluster];
                    }
                    final LongSamplingCounter[] cpuTimeUs = u.mCpuClusterSpeedTimesUs[cluster];
                    for (int speed = 0; speed < speedsInCluster; ++speed) {
                        if (cpuTimeUs[speed] == null) {
                            cpuTimeUs[speed] = new LongSamplingCounter(mOnBatteryTimeBase);
                        }
                        final long allocationUs =
                                mWakeLockAllocationsUs[cluster][speed] / (numWakelocks - i);
                        cpuTimeUs[speed].addCountLocked(allocationUs);
                        mWakeLockAllocationsUs[cluster][speed] -= allocationUs;
                    }
                }
            }
        }
    }
    boolean setChargingLocked(boolean charging) {
@@ -11668,8 +11749,6 @@ public class BatteryStatsImpl extends BatteryStats {
            }
        }
        mCpuFreqs = in.createLongArray();
        final int NU = in.readInt();
        if (NU > 10000) {
            throw new ParcelFormatException("File corrupt: too many uids " + NU);
@@ -12062,8 +12141,6 @@ public class BatteryStatsImpl extends BatteryStats {
            }
        }
        out.writeLongArray(mCpuFreqs);
        final int NU = mUidStats.size();
        out.writeInt(NU);
        for (int iu = 0; iu < NU; iu++) {
@@ -12528,8 +12605,6 @@ public class BatteryStatsImpl extends BatteryStats {
        mFlashlightTurnedOnTimers.clear();
        mCameraTurnedOnTimers.clear();
        mCpuFreqs = in.createLongArray();
        int numUids = in.readInt();
        mUidStats.clear();
        for (int i = 0; i < numUids; i++) {
@@ -12689,8 +12764,6 @@ public class BatteryStatsImpl extends BatteryStats {
            }
        }
        out.writeLongArray(mCpuFreqs);
        if (inclUids) {
            int size = mUidStats.size();
            out.writeInt(size);
+86 −15
Original line number Diff line number Diff line
@@ -16,8 +16,12 @@

package com.android.internal.os;

import static com.android.internal.util.Preconditions.checkNotNull;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.SystemClock;
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -46,7 +50,6 @@ public class KernelUidCpuFreqTimeReader {
    private static final String UID_TIMES_PROC_FILE = "/proc/uid_time_in_state";

    public interface Callback {
        void onCpuFreqs(long[] cpuFreqs);
        void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs);
    }

@@ -62,18 +65,51 @@ public class KernelUidCpuFreqTimeReader {
    private static final int TOTAL_READ_ERROR_COUNT = 5;
    private int mReadErrorCounter;
    private boolean mProcFileAvailable;
    private boolean mPerClusterTimesAvailable;

    public void readDelta(@Nullable Callback callback) {
    public boolean perClusterTimesAvailable() {
        return mPerClusterTimesAvailable;
    }

    public long[] readFreqs(@NonNull PowerProfile powerProfile) {
        checkNotNull(powerProfile);

        if (mCpuFreqs != null) {
            // No need to read cpu freqs more than once.
            return mCpuFreqs;
        }
        if (!mProcFileAvailable && mReadErrorCounter >= TOTAL_READ_ERROR_COUNT) {
            return null;
        }
        try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) {
            mProcFileAvailable = true;
            return readFreqs(reader, powerProfile);
        } catch (IOException e) {
            mReadErrorCounter++;
            Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e);
            return null;
        }
    }

    @VisibleForTesting
    public long[] readFreqs(BufferedReader reader, PowerProfile powerProfile)
            throws IOException {
        final String line = reader.readLine();
        if (line == null) {
            return null;
        }
        return readCpuFreqs(line, powerProfile);
    }

    public void readDelta(@Nullable Callback callback) {
        if (!mProcFileAvailable) {
            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++;
            Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e);
        }
    }
@@ -99,7 +135,6 @@ public class KernelUidCpuFreqTimeReader {
        if (line == null) {
            return;
        }
        readCpuFreqs(line, callback);
        while ((line = reader.readLine()) != null) {
            final int index = line.indexOf(' ');
            final int uid = Integer.parseInt(line.substring(0, index - 1), 10);
@@ -151,18 +186,54 @@ public class KernelUidCpuFreqTimeReader {
        }
    }

    private void readCpuFreqs(String line, Callback callback) {
        if (mCpuFreqs == null) {
    private long[] readCpuFreqs(String line, PowerProfile powerProfile) {
        final String[] freqStr = line.split(" ");
            // First item would be "uid:" which needs to be ignored
        // First item would be "uid: " which needs to be ignored.
        mCpuFreqsCount = freqStr.length - 1;
        mCpuFreqs = new long[mCpuFreqsCount];
        for (int i = 0; i < mCpuFreqsCount; ++i) {
            mCpuFreqs[i] = Long.parseLong(freqStr[i + 1], 10);
        }

        // Check if the freqs in the proc file correspond to per-cluster freqs.
        final IntArray numClusterFreqs = extractClusterInfoFromProcFileFreqs();
        final int numClusters = powerProfile.getNumCpuClusters();
        if (numClusterFreqs.size() == numClusters) {
            mPerClusterTimesAvailable = true;
            for (int i = 0; i < numClusters; ++i) {
                if (numClusterFreqs.get(i) != powerProfile.getNumSpeedStepsInCpuCluster(i)) {
                    mPerClusterTimesAvailable = false;
                    break;
                }
            }
        } else {
            mPerClusterTimesAvailable = false;
        }
        Slog.i(TAG, "mPerClusterTimesAvailable=" + mPerClusterTimesAvailable);

        return mCpuFreqs;
    }

    /**
     * Extracts no. of cpu clusters and no. of freqs in each of these clusters from the freqs
     * read from the proc file.
     *
     * We need to assume that freqs in each cluster are strictly increasing.
     * For e.g. if the freqs read from proc file are: 12, 34, 15, 45, 12, 15, 52. Then it means
     * there are 3 clusters: (12, 34), (15, 45), (12, 15, 52)
     *
     * @return an IntArray filled with no. of freqs in each cluster.
     */
    private IntArray extractClusterInfoFromProcFileFreqs() {
        final IntArray numClusterFreqs = new IntArray();
        int freqsFound = 0;
        for (int i = 0; i < mCpuFreqsCount; ++i) {
            freqsFound++;
            if (i + 1 == mCpuFreqsCount || mCpuFreqs[i + 1] <= mCpuFreqs[i]) {
                numClusterFreqs.add(freqsFound);
                freqsFound = 0;
            }
        if (callback != null) {
            callback.onCpuFreqs(mCpuFreqs);
        }
        return numClusterFreqs;
    }
}
+316 −33

File changed.

Preview size limit exceeded, changes collapsed.

+90 −10
Original line number Diff line number Diff line
@@ -16,6 +16,11 @@

package com.android.internal.os;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -32,6 +37,7 @@ import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import java.io.BufferedReader;
import java.util.Arrays;

/**
 * Test class for {@link KernelUidCpuFreqTimeReader}.
@@ -47,12 +53,17 @@ import java.io.BufferedReader;
 *     ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
 * Run: adb shell am instrument -e class com.android.internal.os.KernelUidCpuFreqTimeReaderTest -w \
 *     com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
 *
 * or
 *
 * bit FrameworksCoreTests:com.android.internal.os.KernelUidCpuFreqTimeReaderTest
 */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class KernelUidCpuFreqTimeReaderTest {
    @Mock private BufferedReader mBufferedReader;
    @Mock private KernelUidCpuFreqTimeReader.Callback mCallback;
    @Mock private PowerProfile mPowerProfile;

    private KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader;

@@ -62,6 +73,69 @@ public class KernelUidCpuFreqTimeReaderTest {
        mKernelUidCpuFreqTimeReader = new KernelUidCpuFreqTimeReader();
    }

    @Test
    public void testReadFreqs_perClusterTimesNotAvailable() throws Exception {
        final long[][] freqs = {
                {1, 12, 123, 1234},
                {1, 12, 123, 23, 123, 1234, 12345, 123456},
                {1, 12, 123, 23, 123, 1234, 12345, 123456, 12, 123, 12345},
                {1, 12, 123, 23, 2345, 234567}
        };
        final int[] numClusters = {2, 2, 3, 1};
        final int[][] numFreqs = {{3, 6}, {4, 5}, {3, 5, 4}, {3}};
        for (int i = 0; i < freqs.length; ++i) {
            setCpuClusterFreqs(numClusters[i], numFreqs[i]);
            when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs[i]));
            long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(
                    mBufferedReader, mPowerProfile);
            assertArrayEquals(freqs[i], actualFreqs);
            verifyZeroInteractions(mCallback);
            final String errMsg = String.format("Freqs=%s, nClusters=%d, nFreqs=%s",
                    Arrays.toString(freqs[i]), numClusters[i], Arrays.toString(numFreqs[i]));
            assertFalse(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable());

            // Verify that a second call won't read the proc file again
            Mockito.reset(mBufferedReader);
            actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile);
            assertArrayEquals(freqs[i], actualFreqs);
            assertFalse(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable());

            // Prepare for next iteration
            Mockito.reset(mBufferedReader, mPowerProfile);
        }
    }

    @Test
    public void testReadFreqs_perClusterTimesAvailable() throws Exception {
        final long[][] freqs = {
                {1, 12, 123, 1234},
                {1, 12, 123, 23, 123, 1234, 12345, 123456},
                {1, 12, 123, 23, 123, 1234, 12345, 123456, 12, 123, 12345, 1234567}
        };
        final int[] numClusters = {1, 2, 3};
        final int[][] numFreqs = {{4}, {3, 5}, {3, 5, 4}};
        for (int i = 0; i < freqs.length; ++i) {
            setCpuClusterFreqs(numClusters[i], numFreqs[i]);
            when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs[i]));
            long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(
                    mBufferedReader, mPowerProfile);
            assertArrayEquals(freqs[i], actualFreqs);
            verifyZeroInteractions(mCallback);
            final String errMsg = String.format("Freqs=%s, nClusters=%d, nFreqs=%s",
                    Arrays.toString(freqs[i]), numClusters[i], Arrays.toString(numFreqs[i]));
            assertTrue(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable());

            // Verify that a second call won't read the proc file again
            Mockito.reset(mBufferedReader);
            actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile);
            assertArrayEquals(freqs[i], actualFreqs);
            assertTrue(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable());

            // Prepare for next iteration
            Mockito.reset(mBufferedReader, mPowerProfile);
        }
    }

    @Test
    public void testReadDelta() throws Exception {
        final long[] freqs = {1, 12, 123, 1234, 12345, 123456};
@@ -72,10 +146,13 @@ public class KernelUidCpuFreqTimeReaderTest {
                times[i][j] = uids[i] * freqs[j] * 10;
            }
        }
        when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs));
        long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mBufferedReader, mPowerProfile);

        assertArrayEquals(freqs, actualFreqs);
        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]);
        }
@@ -92,7 +169,6 @@ public class KernelUidCpuFreqTimeReaderTest {
        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) {
            verify(mCallback).onUidCpuFreqTime(uids[i], subtract(newTimes1[i], times[i]));
        }
@@ -103,7 +179,6 @@ public class KernelUidCpuFreqTimeReaderTest {
        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
@@ -117,7 +192,6 @@ public class KernelUidCpuFreqTimeReaderTest {
        when(mBufferedReader.readLine())
                .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes2));
        mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, null);
        verifyZeroInteractions(mCallback);

        // Verify that the readDelta call will only return deltas when
        // the previous call had null callback.
@@ -131,7 +205,6 @@ public class KernelUidCpuFreqTimeReaderTest {
        when(mBufferedReader.readLine())
                .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes3));
        mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
        verify(mCallback).onCpuFreqs(freqs);
        for (int i = 0; i < uids.length; ++i) {
            verify(mCallback).onUidCpuFreqTime(uids[i], subtract(newTimes3[i], newTimes2[i]));
        }
@@ -148,10 +221,13 @@ public class KernelUidCpuFreqTimeReaderTest {
                times[i][j] = uids[i] * freqs[j] * 10;
            }
        }
        when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs));
        long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mBufferedReader, mPowerProfile);

        assertArrayEquals(freqs, actualFreqs);
        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]);
        }
@@ -169,7 +245,6 @@ public class KernelUidCpuFreqTimeReaderTest {
        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;
@@ -186,7 +261,6 @@ public class KernelUidCpuFreqTimeReaderTest {
        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.
@@ -202,7 +276,6 @@ public class KernelUidCpuFreqTimeReaderTest {
        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;
@@ -219,7 +292,6 @@ public class KernelUidCpuFreqTimeReaderTest {
        when(mBufferedReader.readLine())
                .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes2));
        mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
        verify(mCallback).onCpuFreqs(freqs);
        verifyNoMoreInteractions(mCallback);
    }

@@ -254,4 +326,12 @@ public class KernelUidCpuFreqTimeReaderTest {
        lines[uids.length] = null;
        return lines;
    }

    private void setCpuClusterFreqs(int numClusters, int... clusterFreqs) {
        assertEquals(numClusters, clusterFreqs.length);
        when(mPowerProfile.getNumCpuClusters()).thenReturn(numClusters);
        for (int i = 0; i < numClusters; ++i) {
            when(mPowerProfile.getNumSpeedStepsInCpuCluster(i)).thenReturn(clusterFreqs[i]);
        }
    }
}
Loading