Merge "More unit tests for classes needed in reading uid times per cpu freq." into oc-dev
am: aff7c3c71e
Change-Id: Ie7691a19ef61668afd9200c9a3c77fa9fc5368f1
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index b9d3a30..25d5fae 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -967,14 +967,15 @@
}
}
+ @VisibleForTesting
public static class LongSamplingCounterArray extends LongCounterArray implements TimeBaseObs {
final TimeBase mTimeBase;
- long[] mCounts;
- long[] mLoadedCounts;
- long[] mUnpluggedCounts;
- long[] mPluggedCounts;
+ public long[] mCounts;
+ public long[] mLoadedCounts;
+ public long[] mUnpluggedCounts;
+ public long[] mPluggedCounts;
- LongSamplingCounterArray(TimeBase timeBase, Parcel in) {
+ private LongSamplingCounterArray(TimeBase timeBase, Parcel in) {
mTimeBase = timeBase;
mPluggedCounts = in.createLongArray();
mCounts = copyArray(mPluggedCounts, mCounts);
@@ -983,12 +984,12 @@
timeBase.add(this);
}
- LongSamplingCounterArray(TimeBase timeBase) {
+ public LongSamplingCounterArray(TimeBase timeBase) {
mTimeBase = timeBase;
timeBase.add(this);
}
- public void writeToParcel(Parcel out) {
+ private void writeToParcel(Parcel out) {
out.writeLongArray(mCounts);
out.writeLongArray(mLoadedCounts);
out.writeLongArray(mUnpluggedCounts);
@@ -1024,7 +1025,7 @@
+ " mPluggedCounts=" + Arrays.toString(mPluggedCounts));
}
- void addCountLocked(long[] counts) {
+ public void addCountLocked(long[] counts) {
if (counts == null) {
return;
}
@@ -1039,7 +1040,7 @@
/**
* Clear state of this counter.
*/
- void reset(boolean detachIfReset) {
+ public void reset(boolean detachIfReset) {
fillArray(mCounts, 0);
fillArray(mLoadedCounts, 0);
fillArray(mPluggedCounts, 0);
@@ -1049,21 +1050,60 @@
}
}
- void detach() {
+ public void detach() {
mTimeBase.remove(this);
}
- void writeSummaryFromParcelLocked(Parcel out) {
+ private void writeSummaryToParcelLocked(Parcel out) {
out.writeLongArray(mCounts);
}
- void readSummaryFromParcelLocked(Parcel in) {
+ private void readSummaryFromParcelLocked(Parcel in) {
mCounts = in.createLongArray();
mLoadedCounts = copyArray(mCounts, mLoadedCounts);
mUnpluggedCounts = copyArray(mCounts, mUnpluggedCounts);
mPluggedCounts = copyArray(mCounts, mPluggedCounts);
}
+ public static void writeToParcel(Parcel out, LongSamplingCounterArray counterArray) {
+ if (counterArray != null) {
+ out.writeInt(1);
+ counterArray.writeToParcel(out);
+ } else {
+ out.writeInt(0);
+ }
+ }
+
+ public static LongSamplingCounterArray readFromParcel(Parcel in, TimeBase timeBase) {
+ if (in.readInt() != 0) {
+ return new LongSamplingCounterArray(timeBase, in);
+ } else {
+ return null;
+ }
+ }
+
+ public static void writeSummaryToParcelLocked(Parcel out,
+ LongSamplingCounterArray counterArray) {
+ if (counterArray != null) {
+ out.writeInt(1);
+ counterArray.writeSummaryToParcelLocked(out);
+ } else {
+ out.writeInt(0);
+ }
+ }
+
+ public static LongSamplingCounterArray readSummaryFromParcelLocked(Parcel in,
+ TimeBase timeBase) {
+ if (in.readInt() != 0) {
+ final LongSamplingCounterArray counterArray
+ = new LongSamplingCounterArray(timeBase);
+ counterArray.readSummaryFromParcelLocked(in);
+ return counterArray;
+ } else {
+ return null;
+ }
+ }
+
private void fillArray(long[] a, long val) {
if (a != null) {
Arrays.fill(a, val);
@@ -6927,18 +6967,8 @@
out.writeInt(0);
}
- if (mCpuFreqTimeMs != null) {
- out.writeInt(1);
- mCpuFreqTimeMs.writeToParcel(out);
- } else {
- out.writeInt(0);
- }
- if (mScreenOffCpuFreqTimeMs != null) {
- out.writeInt(1);
- mScreenOffCpuFreqTimeMs.writeToParcel(out);
- } else {
- out.writeInt(0);
- }
+ LongSamplingCounterArray.writeToParcel(out, mCpuFreqTimeMs);
+ LongSamplingCounterArray.writeToParcel(out, mScreenOffCpuFreqTimeMs);
if (mMobileRadioApWakeupCount != null) {
out.writeInt(1);
@@ -7187,17 +7217,9 @@
mCpuClusterSpeed = null;
}
- if (in.readInt() != 0) {
- mCpuFreqTimeMs = new LongSamplingCounterArray(mBsi.mOnBatteryTimeBase, in);
- } else {
- mCpuFreqTimeMs = null;
- }
- if (in.readInt() != 0) {
- mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray(
- mBsi.mOnBatteryScreenOffTimeBase, in);
- } else {
- mScreenOffCpuFreqTimeMs = null;
- }
+ mCpuFreqTimeMs = LongSamplingCounterArray.readFromParcel(in, mBsi.mOnBatteryTimeBase);
+ mScreenOffCpuFreqTimeMs = LongSamplingCounterArray.readFromParcel(
+ in, mBsi.mOnBatteryScreenOffTimeBase);
if (in.readInt() != 0) {
mMobileRadioApWakeupCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
@@ -11355,19 +11377,10 @@
u.mCpuClusterSpeed = null;
}
- if (in.readInt() != 0) {
- u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase);
- u.mCpuFreqTimeMs.readSummaryFromParcelLocked(in);
- } else {
- u.mCpuFreqTimeMs = null;
- }
- if (in.readInt() != 0) {
- u.mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray(
- mOnBatteryScreenOffTimeBase);
- u.mScreenOffCpuFreqTimeMs.readSummaryFromParcelLocked(in);
- } else {
- u.mScreenOffCpuFreqTimeMs = null;
- }
+ u.mCpuFreqTimeMs = LongSamplingCounterArray.readSummaryFromParcelLocked(
+ in, mOnBatteryTimeBase);
+ u.mScreenOffCpuFreqTimeMs = LongSamplingCounterArray.readSummaryFromParcelLocked(
+ in, mOnBatteryScreenOffTimeBase);
if (in.readInt() != 0) {
u.mMobileRadioApWakeupCount = new LongSamplingCounter(mOnBatteryTimeBase);
@@ -11765,18 +11778,8 @@
out.writeInt(0);
}
- if (u.mCpuFreqTimeMs != null) {
- out.writeInt(1);
- u.mCpuFreqTimeMs.writeSummaryFromParcelLocked(out);
- } else {
- out.writeInt(0);
- }
- if (u.mScreenOffCpuFreqTimeMs != null) {
- out.writeInt(1);
- u.mScreenOffCpuFreqTimeMs.writeSummaryFromParcelLocked(out);
- } else {
- out.writeInt(0);
- }
+ LongSamplingCounterArray.writeSummaryToParcelLocked(out, u.mCpuFreqTimeMs);
+ LongSamplingCounterArray.writeSummaryToParcelLocked(out, u.mScreenOffCpuFreqTimeMs);
if (u.mMobileRadioApWakeupCount != null) {
out.writeInt(1);
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
index ad8221b..620acae 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
@@ -18,6 +18,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import android.support.test.filters.SmallTest;
@@ -27,6 +28,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.io.BufferedReader;
@@ -70,18 +72,70 @@
times[i][j] = uids[i] * freqs[j] * 10;
}
}
- final String[] uidsTimesLines = getUidTimesLines(uids, times);
- final String[] lines = new String[uidsTimesLines.length + 1];
- System.arraycopy(uidsTimesLines, 0, lines, 0, uidsTimesLines.length);
- lines[uidsTimesLines.length] = null;
when(mBufferedReader.readLine())
- .thenReturn(getFreqsLine(freqs), lines);
+ .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 a second call will only return deltas.
+ 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;
+ }
+ }
+ 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]));
+ }
+ 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];
+ 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;
+ }
+ }
+ 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.
+ Mockito.reset(mCallback, mBufferedReader);
+ final long[][] newTimes3 = new long[uids.length][freqs.length];
+ for (int i = 0; i < uids.length; ++i) {
+ for (int j = 0; j < freqs.length; ++j) {
+ newTimes3[i][j] = (newTimes2[i][j] * (uids[i] + freqs[j])) * 10;
+ }
+ }
+ 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]));
+ }
+ verifyNoMoreInteractions(mCallback);
+ }
+
+ private long[] subtract(long[] a1, long[] a2) {
+ long[] val = new long[a1.length];
+ for (int i = 0; i < val.length; ++i) {
+ val[i] = a1[i] - a2[i];
+ }
+ return val;
}
private String getFreqsLine(long[] freqs) {
@@ -94,7 +148,7 @@
}
private String[] getUidTimesLines(int[] uids, long[][] times) {
- final String[] lines = new String[uids.length];
+ final String[] lines = new String[uids.length + 1];
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < uids.length; ++i) {
sb.setLength(0);
@@ -104,6 +158,7 @@
}
lines[i] = sb.toString();
}
+ lines[uids.length] = null;
return lines;
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
new file mode 100644
index 0000000..4a23f40
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static android.os.BatteryStats.STATS_SINCE_CHARGED;
+
+import static com.android.internal.os.BatteryStatsImpl.LongSamplingCounterArray;
+import static com.android.internal.os.BatteryStatsImpl.TimeBase;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+
+/**
+ * Test class for {@link BatteryStatsImpl.LongSamplingCounterArray}.
+ *
+ * To run the tests, use
+ *
+ * runtest -c com.android.internal.os.LongSamplingCounterArrayTest frameworks-core
+ *
+ * or the following steps:
+ *
+ * Build: m FrameworksCoreTests
+ * Install: adb install -r \
+ * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
+ * Run: adb shell am instrument -e class com.android.internal.os.LongSamplingCounterArrayTest -w \
+ * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LongSamplingCounterArrayTest {
+
+ private static final long[] COUNTS = {1111, 2222, 3333, 4444};
+ private static final long[] LOADED_COUNTS = {5555, 6666, 7777, 8888};
+ private static final long[] PLUGGED_COUNTS = {9999, 11111, 22222, 33333};
+ private static final long[] UNPLUGGED_COUNTS = {44444, 55555, 66666, 77777};
+ private static final long[] ZEROES = {0, 0, 0, 0};
+
+ @Mock private TimeBase mTimeBase;
+ private LongSamplingCounterArray mCounterArray;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mCounterArray = new LongSamplingCounterArray(mTimeBase);
+ Mockito.reset(mTimeBase);
+ }
+
+ @Test
+ public void testReadWriteParcel() {
+ final Parcel parcel = Parcel.obtain();
+ initializeCounterArrayWithDefaultValues();
+ LongSamplingCounterArray.writeToParcel(parcel, mCounterArray);
+ parcel.setDataPosition(0);
+
+ // Now clear counterArray and verify values are read from parcel correctly.
+ updateCounts(null, null, null, null);
+ mCounterArray = LongSamplingCounterArray.readFromParcel(parcel, mTimeBase);
+ assertArrayEquals(COUNTS, mCounterArray.mCounts, "Unexpected counts");
+ assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
+ assertArrayEquals(COUNTS, mCounterArray.mPluggedCounts, "Unexpected pluggedCounts");
+ assertArrayEquals(UNPLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
+ "Unexpected unpluggedCounts");
+ parcel.recycle();
+ }
+
+ @Test
+ public void testReadWriteSummaryParcel() {
+ final Parcel parcel = Parcel.obtain();
+ initializeCounterArrayWithDefaultValues();
+ LongSamplingCounterArray.writeSummaryToParcelLocked(parcel, mCounterArray);
+ parcel.setDataPosition(0);
+
+ // Now clear counterArray and verify values are read from parcel correctly.
+ updateCounts(null, null, null, null);
+ mCounterArray = LongSamplingCounterArray.readSummaryFromParcelLocked(parcel, mTimeBase);
+ assertArrayEquals(COUNTS, mCounterArray.mCounts, "Unexpected counts");
+ assertArrayEquals(COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
+ assertArrayEquals(COUNTS, mCounterArray.mPluggedCounts, "Unexpected pluggedCounts");
+ assertArrayEquals(COUNTS, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+ parcel.recycle();
+ }
+
+ @Test
+ public void testOnTimeStarted() {
+ initializeCounterArrayWithDefaultValues();
+ mCounterArray.onTimeStarted(0, 0, 0);
+ assertArrayEquals(PLUGGED_COUNTS, mCounterArray.mCounts, "Unexpected counts");
+ assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
+ assertArrayEquals(PLUGGED_COUNTS, mCounterArray.mPluggedCounts, "Unexpected pluggedCounts");
+ assertArrayEquals(PLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
+ "Unexpected unpluggedCounts");
+ }
+
+ @Test
+ public void testOnTimeStopped() {
+ initializeCounterArrayWithDefaultValues();
+ mCounterArray.onTimeStopped(0, 0, 0);
+ assertArrayEquals(COUNTS, mCounterArray.mCounts, "Unexpected counts");
+ assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
+ assertArrayEquals(COUNTS, mCounterArray.mPluggedCounts, "Unexpected pluggedCounts");
+ assertArrayEquals(UNPLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
+ "Unexpected unpluggedCounts");
+ }
+
+ @Test
+ public void testGetCountsLocked() {
+ initializeCounterArrayWithDefaultValues();
+
+ when(mTimeBase.isRunning()).thenReturn(false);
+ long[] actualVal = mCounterArray.getCountsLocked(STATS_SINCE_CHARGED);
+ long[] expectedVal = PLUGGED_COUNTS;
+ assertArrayEquals(expectedVal, actualVal, "Unexpected values");
+
+ when(mTimeBase.isRunning()).thenReturn(true);
+ actualVal = mCounterArray.getCountsLocked(STATS_SINCE_CHARGED);
+ expectedVal = COUNTS;
+ assertArrayEquals(expectedVal, actualVal, "Unexpected values");
+ }
+
+ @Test
+ public void testAddCountLocked() {
+ final long[] deltas = {123, 234, 345, 456};
+ mCounterArray.addCountLocked(deltas);
+ assertArrayEquals(deltas, mCounterArray.mCounts, "Unexpected counts");
+ assertArrayEquals(null, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
+ assertArrayEquals(null, mCounterArray.mPluggedCounts, "Unexpected pluggedCounts");
+ assertArrayEquals(null, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+
+ initializeCounterArrayWithDefaultValues();
+ final long[] newCounts = new long[deltas.length];
+ for (int i = 0; i < deltas.length; ++i) {
+ newCounts[i] = COUNTS[i] + deltas[i];
+ }
+ mCounterArray.addCountLocked(deltas);
+ assertArrayEquals(newCounts, mCounterArray.mCounts, "Unexpected counts");
+ assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
+ assertArrayEquals(PLUGGED_COUNTS, mCounterArray.mPluggedCounts, "Unexpected pluggedCounts");
+ assertArrayEquals(UNPLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
+ "Unexpected unpluggedCounts");
+ }
+
+ @Test
+ public void testReset() {
+ initializeCounterArrayWithDefaultValues();
+ // Test with detachIfReset=false
+ mCounterArray.reset(false /* detachIfReset */);
+ assertArrayEquals(ZEROES, mCounterArray.mCounts, "Unexpected counts");
+ assertArrayEquals(ZEROES, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
+ assertArrayEquals(ZEROES, mCounterArray.mPluggedCounts, "Unexpected pluggedCounts");
+ assertArrayEquals(ZEROES, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+ verifyZeroInteractions(mTimeBase);
+
+ initializeCounterArrayWithDefaultValues();
+ // Test with detachIfReset=true
+ mCounterArray.reset(true /* detachIfReset */);
+ assertArrayEquals(ZEROES, mCounterArray.mCounts, "Unexpected counts");
+ assertArrayEquals(ZEROES, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
+ assertArrayEquals(ZEROES, mCounterArray.mPluggedCounts, "Unexpected pluggedCounts");
+ assertArrayEquals(ZEROES, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+ verify(mTimeBase).remove(mCounterArray);
+ verifyNoMoreInteractions(mTimeBase);
+ }
+
+ @Test
+ public void testDetach() {
+ mCounterArray.detach();
+ verify(mTimeBase).remove(mCounterArray);
+ verifyNoMoreInteractions(mTimeBase);
+ }
+
+ private void initializeCounterArrayWithDefaultValues() {
+ updateCounts(COUNTS, LOADED_COUNTS, PLUGGED_COUNTS, UNPLUGGED_COUNTS);
+ }
+
+ private void assertArrayEquals(long[] expected, long[] actual, String msg) {
+ assertTrue(msg + ", expected: " + Arrays.toString(expected)
+ + ", actual: " + Arrays.toString(actual), Arrays.equals(expected, actual));
+ }
+
+ private void updateCounts(long[] counts, long[] loadedCounts,
+ long[] pluggedCounts, long[] unpluggedCounts) {
+ mCounterArray.mCounts = counts;
+ mCounterArray.mLoadedCounts = loadedCounts;
+ mCounterArray.mPluggedCounts = pluggedCounts;
+ mCounterArray.mUnpluggedCounts = unpluggedCounts;
+ }
+}