Use LongArrayMultiStateCounter for proc-in-state time counting

The acquisition of eBPF's per-UID time-in-state data is now done
in the native code, directly integrating with the native layer
of LongArrayMultiStateCounter.

Bug: 197162116
Test: atest FrameworksCoreTests:BatteryStatsImplTest
      atest FrameworksCoreTests:BstatsCpuTimesValidationTest
      atest FrameworksCoreTests:LongArrayMultiStateCounterTest
      atest FrameworksCoreTests:KernelSingleUidTimeReaderTest

Change-Id: I1fdc747f272ecc0c35c51db39e442aac67d1b24c
This commit is contained in:
Dmitri Plotnikov 2021-09-16 13:05:44 -07:00
parent ee014a0699
commit 2464cfb9d0
8 changed files with 529 additions and 188 deletions

View File

@ -77,7 +77,6 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.IndentingPrintWriter;
import android.util.IntArray;
import android.util.KeyValueListParser;
import android.util.Log;
import android.util.LongSparseArray;
@ -161,7 +160,7 @@ public class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
static final int VERSION = 200;
static final int VERSION = 201;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@ -464,10 +463,12 @@ public class BatteryStatsImpl extends BatteryStats {
uidStates = mPendingUids.clone();
mPendingUids.clear();
}
final long timestampMs = mClock.elapsedRealtime();
for (int i = uidStates.size() - 1; i >= 0; --i) {
final int uid = uidStates.keyAt(i);
final int procState = uidStates.valueAt(i);
final int[] isolatedUids;
final LongArrayMultiStateCounter[] isolatedUidTimeInFreqCounters;
final Uid u;
synchronized (BatteryStatsImpl.this) {
// It's possible that uid no longer exists and any internal references have
@ -479,26 +480,44 @@ public class BatteryStatsImpl extends BatteryStats {
}
if (u.mChildUids == null) {
isolatedUids = null;
isolatedUidTimeInFreqCounters = null;
} else {
isolatedUids = u.mChildUids.toArray();
for (int j = isolatedUids.length - 1; j >= 0; --j) {
isolatedUids[j] = u.mChildUids.get(j);
int childUidCount = u.mChildUids.size();
isolatedUids = new int[childUidCount];
isolatedUidTimeInFreqCounters = new LongArrayMultiStateCounter[childUidCount];
for (int j = childUidCount - 1; j >= 0; --j) {
isolatedUids[j] = u.mChildUids.keyAt(j);
isolatedUidTimeInFreqCounters[j] = u.mChildUids.valueAt(j);
}
}
}
long[] cpuTimesMs = mKernelSingleUidTimeReader.readDeltaMs(uid);
LongArrayMultiStateCounter onBatteryCounter =
u.getProcStateTimeCounter().getCounter();
LongArrayMultiStateCounter onBatteryScreenOffCounter =
u.getProcStateScreenOffTimeCounter().getCounter();
onBatteryCounter.setState(procState, timestampMs);
mKernelSingleUidTimeReader.addDelta(uid, onBatteryCounter, timestampMs);
onBatteryScreenOffCounter.setState(procState, timestampMs);
mKernelSingleUidTimeReader.addDelta(uid, onBatteryScreenOffCounter, timestampMs);
if (isolatedUids != null) {
LongArrayMultiStateCounter.LongArrayContainer deltaContainer =
new LongArrayMultiStateCounter.LongArrayContainer(getCpuFreqCount());
for (int j = isolatedUids.length - 1; j >= 0; --j) {
cpuTimesMs = addCpuTimes(cpuTimesMs,
mKernelSingleUidTimeReader.readDeltaMs(isolatedUids[j]));
}
}
if (onBattery && cpuTimesMs != null) {
synchronized (BatteryStatsImpl.this) {
u.addProcStateTimesMs(procState, cpuTimesMs, onBattery);
u.addProcStateScreenOffTimesMs(procState, cpuTimesMs, onBatteryScreenOff);
if (isolatedUidTimeInFreqCounters[j] != null) {
mKernelSingleUidTimeReader.addDelta(isolatedUids[j],
isolatedUidTimeInFreqCounters[j], timestampMs, deltaContainer);
onBatteryCounter.addCounts(deltaContainer);
onBatteryScreenOffCounter.addCounts(deltaContainer);
}
}
}
onBatteryCounter.setState(u.mProcessState, timestampMs);
onBatteryScreenOffCounter.setState(u.mProcessState, timestampMs);
}
}
@ -537,6 +556,7 @@ public class BatteryStatsImpl extends BatteryStats {
return;
}
// TODO(b/197162116): just get a list of UIDs
final SparseArray<long[]> allUidCpuFreqTimesMs =
mCpuUidFreqTimeReader.getAllUidCpuFreqTimeMs();
// If the KernelSingleUidTimeReader has stale cpu times, then we shouldn't try to
@ -553,24 +573,40 @@ public class BatteryStatsImpl extends BatteryStats {
if (u == null) {
continue;
}
final long[] cpuTimesMs = allUidCpuFreqTimesMs.valueAt(i);
if (cpuTimesMs == null) {
continue;
final int procState;
final int idx = mPendingUids.indexOfKey(uid);
if (idx >= 0) {
procState = mPendingUids.valueAt(idx);
mPendingUids.removeAt(idx);
} else {
procState = u.mProcessState;
}
final long[] deltaTimesMs = mKernelSingleUidTimeReader.computeDelta(
uid, cpuTimesMs.clone());
if (onBattery && deltaTimesMs != null) {
final int procState;
final int idx = mPendingUids.indexOfKey(uid);
if (idx >= 0) {
procState = mPendingUids.valueAt(idx);
mPendingUids.removeAt(idx);
} else {
procState = u.mProcessState;
}
if (procState >= 0 && procState < Uid.NUM_PROCESS_STATE) {
u.addProcStateTimesMs(procState, deltaTimesMs, onBattery);
u.addProcStateScreenOffTimesMs(procState, deltaTimesMs, onBatteryScreenOff);
final long timestampMs = mClock.elapsedRealtime();
final LongArrayMultiStateCounter onBatteryCounter =
u.getProcStateTimeCounter().getCounter();
final LongArrayMultiStateCounter onBatteryScreenOffCounter =
u.getProcStateScreenOffTimeCounter().getCounter();
onBatteryCounter.setState(procState, timestampMs);
mKernelSingleUidTimeReader.addDelta(uid, onBatteryCounter, timestampMs);
onBatteryScreenOffCounter.setState(procState, timestampMs);
mKernelSingleUidTimeReader.addDelta(uid, onBatteryScreenOffCounter, timestampMs);
if (u.mChildUids != null) {
final LongArrayMultiStateCounter.LongArrayContainer deltaContainer =
new LongArrayMultiStateCounter.LongArrayContainer(getCpuFreqCount());
for (int j = u.mChildUids.size() - 1; j >= 0; --j) {
final LongArrayMultiStateCounter counter = u.mChildUids.valueAt(j);
if (counter != null) {
final int isolatedUid = u.mChildUids.keyAt(j);
mKernelSingleUidTimeReader.addDelta(isolatedUid,
counter, timestampMs, deltaContainer);
onBatteryCounter.addCounts(deltaContainer);
onBatteryScreenOffCounter.addCounts(deltaContainer);
}
}
}
}
@ -1653,6 +1689,97 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
private static class TimeInFreqMultiStateCounter implements TimeBaseObs {
private final TimeBase mTimeBase;
private final LongArrayMultiStateCounter mCounter;
private TimeInFreqMultiStateCounter(TimeBase timeBase, Parcel in, long timestampMs) {
mTimeBase = timeBase;
mCounter = LongArrayMultiStateCounter.CREATOR.createFromParcel(in);
mCounter.setEnabled(mTimeBase.isRunning(), timestampMs);
timeBase.add(this);
}
private TimeInFreqMultiStateCounter(TimeBase timeBase, int stateCount, int cpuFreqCount,
long timestampMs) {
mTimeBase = timeBase;
mCounter = new LongArrayMultiStateCounter(stateCount, cpuFreqCount);
mCounter.setEnabled(mTimeBase.isRunning(), timestampMs);
timeBase.add(this);
}
private void writeToParcel(Parcel out) {
mCounter.writeToParcel(out, 0);
}
@Override
public void onTimeStarted(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
mCounter.setEnabled(true, elapsedRealtimeUs / 1000);
}
@Override
public void onTimeStopped(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
mCounter.setEnabled(false, elapsedRealtimeUs / 1000);
}
public LongArrayMultiStateCounter getCounter() {
return mCounter;
}
public int getStateCount() {
return mCounter.getStateCount();
}
public void setTrackingEnabled(boolean enabled, long timestampMs) {
mCounter.setEnabled(enabled && mTimeBase.isRunning(), timestampMs);
}
private void setState(int uidRunningState, long elapsedRealtimeMs) {
mCounter.setState(uidRunningState, elapsedRealtimeMs);
}
/**
* Returns accumulated counts for the specified state, or null if all counts are zero.
*/
@Nullable
public long[] getCountsLocked(int which, int procState) {
LongArrayMultiStateCounter.LongArrayContainer longArrayContainer =
new LongArrayMultiStateCounter.LongArrayContainer(mCounter.getArrayLength());
mCounter.getCounts(longArrayContainer, procState);
final long[] counts = new long[mCounter.getArrayLength()];
longArrayContainer.getValues(counts);
// Return counts only if at least one of the elements is non-zero.
for (int i = counts.length - 1; i >= 0; --i) {
if (counts[i] != 0) {
return counts;
}
}
return null;
}
public void logState(Printer pw, String prefix) {
pw.println(prefix + "mCounter=" + mCounter);
}
/**
* Clears state of this counter.
*/
@Override
public boolean reset(boolean detachIfReset, long elapsedRealtimeUs /* unused */) {
mCounter.reset();
if (detachIfReset) {
detach();
}
return true;
}
@Override
public void detach() {
mTimeBase.remove(this);
}
}
@VisibleForTesting
public static class LongSamplingCounter extends LongCounter implements TimeBaseObs {
final TimeBase mTimeBase;
@ -7300,10 +7427,10 @@ public class BatteryStatsImpl extends BatteryStats {
LongSamplingCounterArray mScreenOffCpuFreqTimeMs;
LongSamplingCounterArray mCpuClusterTimesMs;
LongSamplingCounterArray[] mProcStateTimeMs;
LongSamplingCounterArray[] mProcStateScreenOffTimeMs;
TimeInFreqMultiStateCounter mProcStateTimeMs;
TimeInFreqMultiStateCounter mProcStateScreenOffTimeMs;
IntArray mChildUids;
SparseArray<LongArrayMultiStateCounter> mChildUids;
/**
* The statistics we have collected for this uid's wake locks.
@ -7455,8 +7582,10 @@ public class BatteryStatsImpl extends BatteryStats {
}
@VisibleForTesting
public void setProcessStateForTest(int procState) {
public void setProcessStateForTest(int procState, long elapsedTimeMs) {
mProcessState = procState;
getProcStateTimeCounter().setState(procState, elapsedTimeMs);
getProcStateScreenOffTimeCounter().setState(procState, elapsedTimeMs);
}
@Override
@ -7481,7 +7610,7 @@ public class BatteryStatsImpl extends BatteryStats {
@Override
public long[] getCpuFreqTimes(int which, int procState) {
if (which < 0 || which >= NUM_PROCESS_STATE) {
if (procState < 0 || procState >= NUM_PROCESS_STATE) {
return null;
}
if (mProcStateTimeMs == null) {
@ -7491,12 +7620,13 @@ public class BatteryStatsImpl extends BatteryStats {
mProcStateTimeMs = null;
return null;
}
return nullIfAllZeros(mProcStateTimeMs[procState], which);
return mProcStateTimeMs.getCountsLocked(which, procState);
}
@Override
public long[] getScreenOffCpuFreqTimes(int which, int procState) {
if (which < 0 || which >= NUM_PROCESS_STATE) {
if (procState < 0 || procState >= NUM_PROCESS_STATE) {
return null;
}
if (mProcStateScreenOffTimeMs == null) {
@ -7506,7 +7636,7 @@ public class BatteryStatsImpl extends BatteryStats {
mProcStateScreenOffTimeMs = null;
return null;
}
return nullIfAllZeros(mProcStateScreenOffTimeMs[procState], which);
return mProcStateScreenOffTimeMs.getCountsLocked(which, procState);
}
public long getBinderCallCount() {
@ -7525,15 +7655,26 @@ public class BatteryStatsImpl extends BatteryStats {
public void addIsolatedUid(int isolatedUid) {
if (mChildUids == null) {
mChildUids = new IntArray();
} else if (mChildUids.indexOf(isolatedUid) >= 0) {
mChildUids = new SparseArray<>();
} else if (mChildUids.indexOfKey(isolatedUid) >= 0) {
return;
}
mChildUids.add(isolatedUid);
if (mBsi.trackPerProcStateCpuTimes()) {
LongArrayMultiStateCounter counter =
new LongArrayMultiStateCounter(1, mBsi.getCpuFreqCount());
// Set initial values to all 0. This is a child UID and we want to include
// the entirety of its CPU time-in-freq stats into the parent's stats.
counter.updateValues(
new LongArrayMultiStateCounter.LongArrayContainer(mBsi.getCpuFreqCount()),
mBsi.mClock.elapsedRealtime());
mChildUids.put(isolatedUid, counter);
} else {
mChildUids.put(isolatedUid, null);
}
}
public void removeIsolatedUid(int isolatedUid) {
final int idx = mChildUids == null ? -1 : mChildUids.indexOf(isolatedUid);
final int idx = mChildUids == null ? -1 : mChildUids.indexOfKey(isolatedUid);
if (idx < 0) {
return;
}
@ -7557,31 +7698,37 @@ public class BatteryStatsImpl extends BatteryStats {
return null;
}
private void addProcStateTimesMs(int procState, long[] cpuTimesMs, boolean onBattery) {
if (mProcStateTimeMs == null) {
mProcStateTimeMs = new LongSamplingCounterArray[NUM_PROCESS_STATE];
private void ensureMultiStateCounters() {
if (mProcStateTimeMs != null) {
return;
}
if (mProcStateTimeMs[procState] == null
|| mProcStateTimeMs[procState].getSize() != cpuTimesMs.length) {
detachIfNotNull(mProcStateTimeMs[procState]);
mProcStateTimeMs[procState] = new LongSamplingCounterArray(
mBsi.mOnBatteryTimeBase);
}
mProcStateTimeMs[procState].addCountLocked(cpuTimesMs, onBattery);
final long timestampMs = mBsi.mClock.elapsedRealtime();
mProcStateTimeMs =
new TimeInFreqMultiStateCounter(mBsi.mOnBatteryTimeBase,
NUM_PROCESS_STATE, mBsi.getCpuFreqCount(), timestampMs);
mProcStateScreenOffTimeMs =
new TimeInFreqMultiStateCounter(mBsi.mOnBatteryScreenOffTimeBase,
NUM_PROCESS_STATE, mBsi.getCpuFreqCount(), timestampMs);
}
private void addProcStateScreenOffTimesMs(int procState, long[] cpuTimesMs,
boolean onBatteryScreenOff) {
if (mProcStateScreenOffTimeMs == null) {
mProcStateScreenOffTimeMs = new LongSamplingCounterArray[NUM_PROCESS_STATE];
private TimeInFreqMultiStateCounter getProcStateTimeCounter() {
ensureMultiStateCounters();
return mProcStateTimeMs;
}
private TimeInFreqMultiStateCounter getProcStateScreenOffTimeCounter() {
ensureMultiStateCounters();
return mProcStateScreenOffTimeMs;
}
private void setProcStateTimesTrackingEnabled(boolean enabled, long timestampMs) {
if (mProcStateTimeMs != null) {
mProcStateTimeMs.setTrackingEnabled(enabled, timestampMs);
}
if (mProcStateScreenOffTimeMs[procState] == null
|| mProcStateScreenOffTimeMs[procState].getSize() != cpuTimesMs.length) {
detachIfNotNull(mProcStateScreenOffTimeMs[procState]);
mProcStateScreenOffTimeMs[procState] = new LongSamplingCounterArray(
mBsi.mOnBatteryScreenOffTimeBase);
if (mProcStateScreenOffTimeMs != null) {
mProcStateScreenOffTimeMs.setTrackingEnabled(enabled, timestampMs);
}
mProcStateScreenOffTimeMs[procState].addCountLocked(cpuTimesMs, onBatteryScreenOff);
}
@Override
@ -9108,18 +9255,14 @@ public class BatteryStatsImpl extends BatteryStats {
mCpuClusterTimesMs.writeToParcel(out);
if (mProcStateTimeMs != null) {
out.writeInt(mProcStateTimeMs.length);
for (LongSamplingCounterArray counters : mProcStateTimeMs) {
LongSamplingCounterArray.writeToParcel(out, counters);
}
out.writeInt(mProcStateTimeMs.getStateCount());
mProcStateTimeMs.writeToParcel(out);
} else {
out.writeInt(0);
}
if (mProcStateScreenOffTimeMs != null) {
out.writeInt(mProcStateScreenOffTimeMs.length);
for (LongSamplingCounterArray counters : mProcStateScreenOffTimeMs) {
LongSamplingCounterArray.writeToParcel(out, counters);
}
out.writeInt(mProcStateScreenOffTimeMs.getStateCount());
mProcStateScreenOffTimeMs.writeToParcel(out);
} else {
out.writeInt(0);
}
@ -9412,22 +9555,27 @@ public class BatteryStatsImpl extends BatteryStats {
mCpuActiveTimeMs = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
mCpuClusterTimesMs = new LongSamplingCounterArray(mBsi.mOnBatteryTimeBase, in);
int length = in.readInt();
if (length == NUM_PROCESS_STATE) {
mProcStateTimeMs = new LongSamplingCounterArray[length];
for (int procState = 0; procState < length; ++procState) {
mProcStateTimeMs[procState] = LongSamplingCounterArray.readFromParcel(
in, mBsi.mOnBatteryTimeBase);
final long timestampMs = mBsi.mClock.elapsedRealtime();
int stateCount = in.readInt();
if (stateCount != 0) {
// Read the object from the Parcel, whether it's usable or not
TimeInFreqMultiStateCounter counter = new TimeInFreqMultiStateCounter(
mBsi.mOnBatteryTimeBase, in, timestampMs);
if (stateCount == NUM_PROCESS_STATE) {
mProcStateTimeMs = counter;
}
} else {
mProcStateTimeMs = null;
}
length = in.readInt();
if (length == NUM_PROCESS_STATE) {
mProcStateScreenOffTimeMs = new LongSamplingCounterArray[length];
for (int procState = 0; procState < length; ++procState) {
mProcStateScreenOffTimeMs[procState] = LongSamplingCounterArray.readFromParcel(
in, mBsi.mOnBatteryScreenOffTimeBase);
stateCount = in.readInt();
if (stateCount != 0) {
// Read the object from the Parcel, whether it's usable or not
TimeInFreqMultiStateCounter counter =
new TimeInFreqMultiStateCounter(
mBsi.mOnBatteryScreenOffTimeBase, in, timestampMs);
if (stateCount == NUM_PROCESS_STATE) {
mProcStateScreenOffTimeMs = counter;
}
} else {
mProcStateScreenOffTimeMs = null;
@ -10603,6 +10751,16 @@ public class BatteryStatsImpl extends BatteryStats {
return mCpuFreqs;
}
/**
* Returns the total number of frequencies across all CPU clusters.
*/
private int getCpuFreqCount() {
if (mCpuFreqs == null) {
mCpuFreqs = mCpuUidFreqTimeReader.readFreqs(mPowerProfile);
}
return mCpuFreqs != null ? mCpuFreqs.length : 0;
}
public BatteryStatsImpl(File systemDir, Handler handler, PlatformIdleStateCallback cb,
MeasuredEnergyRetriever energyStatsCb, UserInfoProvider userInfoProvider) {
this(Clock.SYSTEM_CLOCK, systemDir, handler, cb, energyStatsCb, userInfoProvider);
@ -14747,6 +14905,7 @@ public class BatteryStatsImpl extends BatteryStats {
DEFAULT_BATTERY_CHARGED_DELAY_MS);
}
@GuardedBy("BatteryStatsImpl.this")
private void updateTrackCpuTimesByProcStateLocked(boolean wasEnabled, boolean isEnabled) {
TRACK_CPU_TIMES_BY_PROC_STATE = isEnabled;
if (isEnabled && !wasEnabled) {
@ -14757,6 +14916,10 @@ public class BatteryStatsImpl extends BatteryStats {
mNumBatchedSingleUidCpuTimeReads = 0;
mCpuTimeReadsTrackingStartTimeMs = mClock.uptimeMillis();
}
final long timestampMs = mClock.elapsedRealtime();
for (int i = mUidStats.size() - 1; i >= 0; i--) {
mUidStats.valueAt(i).setProcStateTimesTrackingEnabled(isEnabled, timestampMs);
}
}
private void updateProcStateCpuTimesReadDelayMs(long oldDelayMillis, long newDelayMillis) {
@ -15531,31 +15694,32 @@ public class BatteryStatsImpl extends BatteryStats {
u.mCpuActiveTimeMs.readSummaryFromParcelLocked(in);
u.mCpuClusterTimesMs.readSummaryFromParcelLocked(in);
int length = in.readInt();
if (length == Uid.NUM_PROCESS_STATE) {
detachIfNotNull(u.mProcStateTimeMs);
u.mProcStateTimeMs = new LongSamplingCounterArray[length];
for (int procState = 0; procState < length; ++procState) {
u.mProcStateTimeMs[procState]
= LongSamplingCounterArray.readSummaryFromParcelLocked(
in, mOnBatteryTimeBase);
detachIfNotNull(u.mProcStateTimeMs);
u.mProcStateTimeMs = null;
int stateCount = in.readInt();
if (stateCount != 0) {
// Read the object from the Parcel, whether it's usable or not
TimeInFreqMultiStateCounter counter = new TimeInFreqMultiStateCounter(
mOnBatteryTimeBase, in, mClock.elapsedRealtime());
if (stateCount == Uid.NUM_PROCESS_STATE) {
u.mProcStateTimeMs = counter;
}
} else {
detachIfNotNull(u.mProcStateTimeMs);
u.mProcStateTimeMs = null;
}
length = in.readInt();
if (length == Uid.NUM_PROCESS_STATE) {
detachIfNotNull(u.mProcStateScreenOffTimeMs);
u.mProcStateScreenOffTimeMs = null;
stateCount = in.readInt();
if (stateCount != 0) {
detachIfNotNull(u.mProcStateScreenOffTimeMs);
u.mProcStateScreenOffTimeMs = new LongSamplingCounterArray[length];
for (int procState = 0; procState < length; ++procState) {
u.mProcStateScreenOffTimeMs[procState]
= LongSamplingCounterArray.readSummaryFromParcelLocked(
in, mOnBatteryScreenOffTimeBase);
// Read the object from the Parcel, whether it's usable or not
TimeInFreqMultiStateCounter counter =
new TimeInFreqMultiStateCounter(
mOnBatteryScreenOffTimeBase, in, mClock.elapsedRealtime());
if (stateCount == Uid.NUM_PROCESS_STATE) {
u.mProcStateScreenOffTimeMs = counter;
}
} else {
detachIfNotNull(u.mProcStateScreenOffTimeMs);
u.mProcStateScreenOffTimeMs = null;
}
if (in.readInt() != 0) {
@ -16058,18 +16222,15 @@ public class BatteryStatsImpl extends BatteryStats {
u.mCpuClusterTimesMs.writeSummaryToParcelLocked(out);
if (u.mProcStateTimeMs != null) {
out.writeInt(u.mProcStateTimeMs.length);
for (LongSamplingCounterArray counters : u.mProcStateTimeMs) {
LongSamplingCounterArray.writeSummaryToParcelLocked(out, counters);
}
out.writeInt(u.mProcStateTimeMs.getStateCount());
u.mProcStateTimeMs.writeToParcel(out);
} else {
out.writeInt(0);
}
if (u.mProcStateScreenOffTimeMs != null) {
out.writeInt(u.mProcStateScreenOffTimeMs.length);
for (LongSamplingCounterArray counters : u.mProcStateScreenOffTimeMs) {
LongSamplingCounterArray.writeSummaryToParcelLocked(out, counters);
}
out.writeInt(u.mProcStateScreenOffTimeMs.getStateCount());
u.mProcStateScreenOffTimeMs.writeToParcel(out);
} else {
out.writeInt(0);
}

View File

@ -243,6 +243,23 @@ public class KernelSingleUidTimeReader {
}
}
/**
* Retrieves CPU time-in-state data for the specified UID and adds the accumulated
* delta to the supplied counter.
*/
public void addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs) {
mInjector.addDelta(uid, counter, timestampMs, null);
}
/**
* Same as {@link #addDelta(int, LongArrayMultiStateCounter, long)}, also returning
* the delta in the supplied array container.
*/
public void addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs,
LongArrayMultiStateCounter.LongArrayContainer deltaContainer) {
mInjector.addDelta(uid, counter, timestampMs, deltaContainer);
}
@VisibleForTesting
public static class Injector {
public byte[] readData(String procFile) throws IOException {
@ -254,14 +271,19 @@ public class KernelSingleUidTimeReader {
/**
* Reads CPU time-in-state data for the specified UID and adds the delta since the
* previous call to the current state stats in the LongArrayMultiStateCounter.
*
* The delta is also returned via the optional deltaOut parameter.
*/
public boolean addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs) {
return addDeltaFromBpf(uid, counter.mNativeObject, timestampMs);
public boolean addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs,
LongArrayMultiStateCounter.LongArrayContainer deltaOut) {
return addDeltaFromBpf(uid, counter.mNativeObject, timestampMs,
deltaOut != null ? deltaOut.mNativeObject : 0);
}
@CriticalNative
private static native boolean addDeltaFromBpf(int uid,
long longArrayMultiStateCounterNativePointer, long timestampMs);
long longArrayMultiStateCounterNativePointer, long timestampMs,
long longArrayContainerNativePointer);
/**
* Used for testing.
@ -269,13 +291,15 @@ public class KernelSingleUidTimeReader {
* Takes mock cpu-time-in-frequency data and uses it the same way eBPF data would be used.
*/
public boolean addDeltaForTest(int uid, LongArrayMultiStateCounter counter,
long timestampMs, long[][] timeInFreqDataNanos) {
return addDeltaForTest(uid, counter.mNativeObject, timestampMs, timeInFreqDataNanos);
long timestampMs, long[][] timeInFreqDataNanos,
LongArrayMultiStateCounter.LongArrayContainer deltaOut) {
return addDeltaForTest(uid, counter.mNativeObject, timestampMs, timeInFreqDataNanos,
deltaOut != null ? deltaOut.mNativeObject : 0);
}
private static native boolean addDeltaForTest(int uid,
long longArrayMultiStateCounterNativePointer, long timestampMs,
long[][] timeInFreqDataNanos);
long[][] timeInFreqDataNanos, long longArrayContainerNativePointer);
}
@VisibleForTesting

View File

@ -26,6 +26,8 @@ import dalvik.annotation.optimization.FastNative;
import libcore.util.NativeAllocationRegistry;
import java.util.Arrays;
/**
* Performs per-state counting of multi-element values over time. The class' behavior is illustrated
* by this example:
@ -62,7 +64,9 @@ public final class LongArrayMultiStateCounter implements Parcelable {
NativeAllocationRegistry.createMalloced(
LongArrayContainer.class.getClassLoader(), native_getReleaseFunc());
private final long mNativeObject;
// Visible to other objects in this package so that it can be passed to @CriticalNative
// methods.
final long mNativeObject;
private final int mLength;
public LongArrayContainer(int length) {
@ -93,6 +97,13 @@ public final class LongArrayMultiStateCounter implements Parcelable {
native_getValues(mNativeObject, array);
}
@Override
public String toString() {
final long[] array = new long[mLength];
getValues(array);
return Arrays.toString(array);
}
@CriticalNative
private static native long native_init(int length);
@ -133,6 +144,14 @@ public final class LongArrayMultiStateCounter implements Parcelable {
mLength = native_getArrayLength(mNativeObject);
}
public int getStateCount() {
return mStateCount;
}
public int getArrayLength() {
return mLength;
}
/**
* Enables or disables the counter. When the counter is disabled, it does not
* accumulate counts supplied by the {@link #updateValues} method.
@ -147,7 +166,7 @@ public final class LongArrayMultiStateCounter implements Parcelable {
public void setState(int state, long timestampMs) {
if (state < 0 || state >= mStateCount) {
throw new IllegalArgumentException(
"State: " + state + ", outside the range: [0-" + mStateCount + "]");
"State: " + state + ", outside the range: [0-" + (mStateCount - 1) + "]");
}
native_setState(mNativeObject, state, timestampMs);
}
@ -166,6 +185,17 @@ public final class LongArrayMultiStateCounter implements Parcelable {
native_updateValues(mNativeObject, longArrayContainer.mNativeObject, timestampMs);
}
/**
* Adds the supplied values to the current accumulated values in the counter.
*/
public void addCounts(LongArrayContainer counts) {
if (counts.mLength != mLength) {
throw new IllegalArgumentException(
"Invalid array length: " + counts.mLength + ", expected: " + mLength);
}
native_addCounts(mNativeObject, counts.mNativeObject);
}
/**
* Resets the accumulated counts to 0.
*/
@ -230,6 +260,10 @@ public final class LongArrayMultiStateCounter implements Parcelable {
private static native void native_updateValues(long nativeObject,
long longArrayContainerNativeObject, long timestampMs);
@CriticalNative
private static native void native_addCounts(long nativeObject,
long longArrayContainerNativeObject);
@CriticalNative
private static native void native_reset(long nativeObject);

View File

@ -50,7 +50,8 @@ static jlongArray getUidCpuFreqTimeMs(JNIEnv *env, jclass, jint uid) {
*/
static jboolean addCpuTimeInFreqDelta(
jint uid, jlong counterNativePtr, jlong timestampMs,
std::optional<std::vector<std::vector<uint64_t>>> timeInFreqDataNanos) {
std::optional<std::vector<std::vector<uint64_t>>> timeInFreqDataNanos,
jlong deltaOutContainerNativePtr) {
if (!timeInFreqDataNanos) {
return false;
}
@ -70,20 +71,35 @@ static jboolean addCpuTimeInFreqDelta(
for (size_t i = 0; i < s; ++i) {
flattened[i] /= NSEC_PER_MSEC;
}
counter->updateValue(flattened, timestampMs);
if (s != counter->getCount(0).size()) { // Counter has at least one state
ALOGE("Mismatch between eBPF data size (%d) and the counter size (%d)", (int)s,
(int)counter->getCount(0).size());
return false;
}
const std::vector<uint64_t> &delta = counter->updateValue(flattened, timestampMs);
if (deltaOutContainerNativePtr) {
std::vector<uint64_t> *vector =
reinterpret_cast<std::vector<uint64_t> *>(deltaOutContainerNativePtr);
*vector = delta;
}
return true;
}
static jboolean addDeltaFromBpf(jint uid, jlong counterNativePtr, jlong timestampMs) {
static jboolean addDeltaFromBpf(jint uid, jlong counterNativePtr, jlong timestampMs,
jlong deltaOutContainerNativePtr) {
return addCpuTimeInFreqDelta(uid, counterNativePtr, timestampMs,
android::bpf::getUidCpuFreqTimes(uid));
android::bpf::getUidCpuFreqTimes(uid), deltaOutContainerNativePtr);
}
static jboolean addDeltaForTest(JNIEnv *env, jclass, jint uid, jlong counterNativePtr,
jlong timestampMs, jobjectArray timeInFreqDataNanos) {
jlong timestampMs, jobjectArray timeInFreqDataNanos,
jlong deltaOutContainerNativePtr) {
if (!timeInFreqDataNanos) {
return addCpuTimeInFreqDelta(uid, counterNativePtr, timestampMs,
std::optional<std::vector<std::vector<uint64_t>>>());
std::optional<std::vector<std::vector<uint64_t>>>(),
deltaOutContainerNativePtr);
}
std::vector<std::vector<uint64_t>> timeInFreqData;
@ -97,17 +113,18 @@ static jboolean addDeltaForTest(JNIEnv *env, jclass, jint uid, jlong counterNati
}
timeInFreqData.push_back(cluster);
}
return addCpuTimeInFreqDelta(uid, counterNativePtr, timestampMs, std::optional(timeInFreqData));
return addCpuTimeInFreqDelta(uid, counterNativePtr, timestampMs, std::optional(timeInFreqData),
deltaOutContainerNativePtr);
}
static const JNINativeMethod g_single_methods[] = {
{"readBpfData", "(I)[J", (void *)getUidCpuFreqTimeMs},
// @CriticalNative
{"addDeltaFromBpf", "(IJJ)Z", (void *)addDeltaFromBpf},
{"addDeltaFromBpf", "(IJJJ)Z", (void *)addDeltaFromBpf},
// Used for testing
{"addDeltaForTest", "(IJJ[[J)Z", (void *)addDeltaForTest},
{"addDeltaForTest", "(IJJ[[JJ)Z", (void *)addDeltaForTest},
};
int register_com_android_internal_os_KernelSingleUidTimeReader(JNIEnv *env) {

View File

@ -65,6 +65,14 @@ static void native_updateValues(jlong nativePtr, jlong longArrayContainerNativeP
counter->updateValue(*vector, timestamp);
}
static void native_addCounts(jlong nativePtr, jlong longArrayContainerNativePtr) {
battery::LongArrayMultiStateCounter *counter =
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
std::vector<uint64_t> *vector =
reinterpret_cast<std::vector<uint64_t> *>(longArrayContainerNativePtr);
counter->addValue(*vector);
}
static void native_reset(jlong nativePtr) {
battery::LongArrayMultiStateCounter *counter =
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
@ -184,6 +192,8 @@ static const JNINativeMethod g_LongArrayMultiStateCounter_methods[] = {
// @CriticalNative
{"native_updateValues", "(JJJ)V", (void *)native_updateValues},
// @CriticalNative
{"native_addCounts", "(JJ)V", (void *)native_addCounts},
// @CriticalNative
{"native_reset", "(J)V", (void *)native_reset},
// @CriticalNative
{"native_getCounts", "(JJI)V", (void *)native_getCounts},

View File

@ -27,10 +27,13 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.os.BatteryStats;
import android.util.SparseArray;
import android.util.SparseIntArray;
@ -40,20 +43,19 @@ import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
import com.android.internal.util.ArrayUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Arrays;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class BatteryStatsImplTest {
private static final long[] CPU_FREQS = {1, 2, 3, 4, 5};
private static final int NUM_CPU_FREQS = CPU_FREQS.length;
@Mock
private KernelCpuUidFreqTimeReader mKernelUidCpuFreqTimeReader;
@Mock
@ -61,13 +63,16 @@ public class BatteryStatsImplTest {
private MockBatteryStatsImpl mBatteryStatsImpl;
private MockClock mMockClock = new MockClock();
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mKernelUidCpuFreqTimeReader.readFreqs(any())).thenReturn(CPU_FREQS);
when(mKernelUidCpuFreqTimeReader.allUidTimesAvailable()).thenReturn(true);
when(mKernelSingleUidTimeReader.singleUidCpuTimesAvailable()).thenReturn(true);
mBatteryStatsImpl = new MockBatteryStatsImpl()
mBatteryStatsImpl = new MockBatteryStatsImpl(mMockClock)
.setKernelCpuUidFreqTimeReader(mKernelUidCpuFreqTimeReader)
.setKernelSingleUidTimeReader(mKernelSingleUidTimeReader)
.setTrackingCpuByProcStateEnabled(true);
@ -76,9 +81,17 @@ public class BatteryStatsImplTest {
@Test
public void testUpdateProcStateCpuTimes() {
mBatteryStatsImpl.setOnBatteryInternal(true);
mBatteryStatsImpl.updateTimeBasesLocked(false, Display.STATE_ON, 0, 0);
synchronized (mBatteryStatsImpl) {
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
}
final int[] testUids = {10032, 10048, 10145, 10139};
final int[] activityManagerProcStates = {
ActivityManager.PROCESS_STATE_RECEIVER,
ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
ActivityManager.PROCESS_STATE_TOP,
ActivityManager.PROCESS_STATE_CACHED_EMPTY
};
final int[] testProcStates = {
PROCESS_STATE_BACKGROUND,
PROCESS_STATE_FOREGROUND_SERVICE,
@ -86,14 +99,24 @@ public class BatteryStatsImplTest {
PROCESS_STATE_CACHED
};
addPendingUids(testUids, testProcStates);
// Initialize time-in-freq counters
mMockClock.realtime = 1000;
for (int i = 0; i < testUids.length; ++i) {
mBatteryStatsImpl.noteUidProcessStateLocked(testUids[i], activityManagerProcStates[i]);
mockKernelSingleUidTimeReader(testUids[i], new long[5]);
}
mBatteryStatsImpl.updateProcStateCpuTimes(true, false);
// Obtain initial CPU time-in-freq counts
final long[][] cpuTimes = {
{349734983, 394982394832l, 909834, 348934, 9838},
{349734983, 394982394832L, 909834, 348934, 9838},
{7498, 1239890, 988, 13298, 98980},
{989834, 384098, 98483, 23809, 4984},
{4859048, 348903, 4578967, 5973894, 298549}
};
for (int i = 0; i < testUids.length; ++i) {
when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(cpuTimes[i]);
mockKernelSingleUidTimeReader(testUids[i], cpuTimes[i]);
// Verify there are no cpu times initially.
final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUids[i]);
@ -102,7 +125,9 @@ public class BatteryStatsImplTest {
assertNull(u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED, procState));
}
}
addPendingUids(testUids, testProcStates);
mMockClock.realtime += 1000;
mBatteryStatsImpl.updateProcStateCpuTimes(true, false);
verifyNoPendingUids();
@ -119,6 +144,7 @@ public class BatteryStatsImplTest {
}
}
// Accumulate CPU time-in-freq deltas
final long[][] delta1 = {
{9589, 148934, 309894, 3098493, 98754},
{21983, 94983, 4983, 9878493, 84854},
@ -126,10 +152,15 @@ public class BatteryStatsImplTest {
{843895, 43948, 949582, 99, 384}
};
for (int i = 0; i < testUids.length; ++i) {
when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(delta1[i]);
long[] newCpuTimes = new long[cpuTimes[i].length];
for (int j = 0; j < cpuTimes[i].length; j++) {
newCpuTimes[j] = cpuTimes[i][j] + delta1[i][j];
}
mockKernelSingleUidTimeReader(testUids[i], newCpuTimes);
}
addPendingUids(testUids, testProcStates);
mMockClock.realtime += 1000;
mBatteryStatsImpl.updateProcStateCpuTimes(true, false);
verifyNoPendingUids();
@ -150,7 +181,12 @@ public class BatteryStatsImplTest {
}
}
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
// Validate the on-battery-screen-off counter
synchronized (mBatteryStatsImpl) {
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0,
mMockClock.realtime * 1000);
}
final long[][] delta2 = {
{95932, 2943, 49834, 89034, 139},
{349, 89605, 5896, 845, 98444},
@ -158,10 +194,15 @@ public class BatteryStatsImplTest {
{488, 998, 8498, 394, 574}
};
for (int i = 0; i < testUids.length; ++i) {
when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(delta2[i]);
long[] newCpuTimes = new long[cpuTimes[i].length];
for (int j = 0; j < cpuTimes[i].length; j++) {
newCpuTimes[j] = cpuTimes[i][j] + delta1[i][j] + delta2[i][j];
}
mockKernelSingleUidTimeReader(testUids[i], newCpuTimes);
}
addPendingUids(testUids, testProcStates);
mMockClock.realtime += 1000;
mBatteryStatsImpl.updateProcStateCpuTimes(true, true);
verifyNoPendingUids();
@ -184,6 +225,10 @@ public class BatteryStatsImplTest {
}
}
// Verify handling of isolated UIDs - their time-in-freq must be directly
// added to that of the parent UID's. The proc state of the isolated UID is
// assumed to be the same as that of the parent UID, so there is no per-state
// data for isolated UIDs.
final long[][] delta3 = {
{98545, 95768795, 76586, 548945, 57846},
{788876, 586, 578459, 8776984, 9578923},
@ -191,16 +236,20 @@ public class BatteryStatsImplTest {
{9493, 784, 99895, 8974893, 9879843}
};
for (int i = 0; i < testUids.length; ++i) {
when(mKernelSingleUidTimeReader.readDeltaMs(testUids[i])).thenReturn(
delta3[i].clone());
long[] newCpuTimes = new long[cpuTimes[i].length];
for (int j = 0; j < cpuTimes[i].length; j++) {
newCpuTimes[j] = cpuTimes[i][j] + delta1[i][j] + delta2[i][j] + delta3[i][j];
}
mockKernelSingleUidTimeReader(testUids[i], newCpuTimes);
}
addPendingUids(testUids, testProcStates);
final int parentUid = testUids[1];
final int childUid = 99099;
addIsolatedUid(parentUid, childUid);
final long[] isolatedUidCpuTimes = {495784, 398473, 4895, 4905, 30984093};
when(mKernelSingleUidTimeReader.readDeltaMs(childUid)).thenReturn(isolatedUidCpuTimes);
mockKernelSingleUidTimeReader(childUid, isolatedUidCpuTimes, isolatedUidCpuTimes);
mMockClock.realtime += 1000;
mBatteryStatsImpl.updateProcStateCpuTimes(true, true);
verifyNoPendingUids();
@ -233,7 +282,11 @@ public class BatteryStatsImplTest {
@Test
public void testCopyFromAllUidsCpuTimes() {
mBatteryStatsImpl.setOnBatteryInternal(false);
mBatteryStatsImpl.updateTimeBasesLocked(false, Display.STATE_ON, 0, 0);
synchronized (mBatteryStatsImpl) {
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
}
mMockClock.realtime = 1000;
final int[] testUids = {10032, 10048, 10145, 10139};
final int[] testProcStates = {
@ -242,8 +295,14 @@ public class BatteryStatsImplTest {
PROCESS_STATE_TOP,
PROCESS_STATE_CACHED
};
final int[] pendingUidIdx = {1, 2};
updateProcessStates(testUids, testProcStates, pendingUidIdx);
addPendingUids(testUids, testProcStates);
for (int i = 0; i < testUids.length; ++i) {
BatteryStatsImpl.Uid uid = mBatteryStatsImpl.getUidStatsLocked(testUids[i]);
uid.setProcessStateForTest(testProcStates[i], mMockClock.elapsedRealtime());
mockKernelSingleUidTimeReader(testUids[i], new long[NUM_CPU_FREQS]);
}
mBatteryStatsImpl.updateProcStateCpuTimes(true, false);
final SparseArray<long[]> allUidCpuTimes = new SparseArray<>();
long[][] allCpuTimes = {
@ -257,18 +316,16 @@ public class BatteryStatsImplTest {
}
when(mKernelUidCpuFreqTimeReader.getAllUidCpuFreqTimeMs()).thenReturn(allUidCpuTimes);
long[][] expectedCpuTimes = {
{843598745, 397843, 32749, 99854},
{9834, 5885, 487589, 394},
{203984, 439, 9859, 30948},
{9389, 858, 239, 349}
{843598745, 397843, 32749, 99854, 23454},
{9834, 5885, 487589, 394, 93933},
{203984, 439, 9859, 30948, 49494},
{9389, 858, 239, 349, 50505}
};
for (int i = 0; i < testUids.length; ++i) {
final int idx = i;
final ArgumentMatcher<long[]> matcher = times -> Arrays.equals(times, allCpuTimes[idx]);
when(mKernelSingleUidTimeReader.computeDelta(eq(testUids[i]), argThat(matcher)))
.thenReturn(expectedCpuTimes[i]);
mockKernelSingleUidTimeReader(testUids[i], expectedCpuTimes[i]);
}
mMockClock.realtime += 1000;
mBatteryStatsImpl.copyFromAllUidsCpuTimes(true, false);
verifyNoPendingUids();
@ -286,6 +343,39 @@ public class BatteryStatsImplTest {
}
}
private void mockKernelSingleUidTimeReader(int testUid, long[] cpuTimes) {
doAnswer(invocation -> {
LongArrayMultiStateCounter counter = invocation.getArgument(1);
long timestampMs = invocation.getArgument(2);
LongArrayMultiStateCounter.LongArrayContainer container =
new LongArrayMultiStateCounter.LongArrayContainer(NUM_CPU_FREQS);
container.setValues(cpuTimes);
counter.updateValues(container, timestampMs);
return null;
}).when(mKernelSingleUidTimeReader).addDelta(eq(testUid),
any(LongArrayMultiStateCounter.class), anyLong());
}
private void mockKernelSingleUidTimeReader(int testUid, long[] cpuTimes, long[] delta) {
doAnswer(invocation -> {
LongArrayMultiStateCounter counter = invocation.getArgument(1);
long timestampMs = invocation.getArgument(2);
LongArrayMultiStateCounter.LongArrayContainer deltaContainer =
invocation.getArgument(3);
LongArrayMultiStateCounter.LongArrayContainer container =
new LongArrayMultiStateCounter.LongArrayContainer(NUM_CPU_FREQS);
container.setValues(cpuTimes);
counter.updateValues(container, timestampMs);
if (deltaContainer != null) {
deltaContainer.setValues(delta);
}
return null;
}).when(mKernelSingleUidTimeReader).addDelta(eq(testUid),
any(LongArrayMultiStateCounter.class), anyLong(),
any(LongArrayMultiStateCounter.LongArrayContainer.class));
}
@Test
public void testAddCpuTimes() {
long[] timesA = null;
@ -314,7 +404,9 @@ public class BatteryStatsImplTest {
final int releaseTimeMs = 1005;
final int currentTimeMs = 1011;
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
synchronized (mBatteryStatsImpl) {
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
}
// Create a Uid Object
final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid);
@ -325,7 +417,7 @@ public class BatteryStatsImplTest {
u.noteWifiMulticastDisabledLocked(releaseTimeMs);
// Get the total acquisition time
long totalTime = u.getWifiMulticastTime(currentTimeMs*1000,
long totalTime = u.getWifiMulticastTime(currentTimeMs * 1000,
BatteryStats.STATS_SINCE_CHARGED);
assertEquals("Miscalculations of Multicast wakelock acquisition time",
(releaseTimeMs - acquireTimeMs) * 1000, totalTime);
@ -337,7 +429,9 @@ public class BatteryStatsImplTest {
final int acquireTimeMs = 1000;
final int currentTimeMs = 1011;
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
synchronized (mBatteryStatsImpl) {
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
}
// Create a Uid Object
final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid);
@ -347,7 +441,7 @@ public class BatteryStatsImplTest {
u.noteWifiMulticastEnabledLocked(acquireTimeMs);
// Get the total acquisition time
long totalTime = u.getWifiMulticastTime(currentTimeMs*1000,
long totalTime = u.getWifiMulticastTime(currentTimeMs * 1000,
BatteryStats.STATS_SINCE_CHARGED);
assertEquals("Miscalculations of Multicast wakelock acquisition time",
(currentTimeMs - acquireTimeMs) * 1000, totalTime);
@ -363,7 +457,9 @@ public class BatteryStatsImplTest {
final int releaseTimeMs_2 = 1009;
final int currentTimeMs = 1011;
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
synchronized (mBatteryStatsImpl) {
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
}
// Create a Uid Object
final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid);
@ -377,7 +473,7 @@ public class BatteryStatsImplTest {
u.noteWifiMulticastDisabledLocked(releaseTimeMs_2);
// Get the total acquisition time
long totalTime = u.getWifiMulticastTime(currentTimeMs*1000,
long totalTime = u.getWifiMulticastTime(currentTimeMs * 1000,
BatteryStats.STATS_SINCE_CHARGED);
assertEquals("Miscalculations of Multicast wakelock acquisition time",
(releaseTimeMs_2 - acquireTimeMs_1) * 1000, totalTime);
@ -393,7 +489,9 @@ public class BatteryStatsImplTest {
final int releaseTimeMs_2 = 1009;
final int currentTimeMs = 1011;
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
synchronized (mBatteryStatsImpl) {
mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
}
// Create a Uid Object
final BatteryStats.Uid u = mBatteryStatsImpl.getUidStatsLocked(testUid);
@ -407,11 +505,11 @@ public class BatteryStatsImplTest {
u.noteWifiMulticastDisabledLocked(releaseTimeMs_2);
// Get the total acquisition time
long totalTime = u.getWifiMulticastTime(currentTimeMs*1000,
long totalTime = u.getWifiMulticastTime(currentTimeMs * 1000,
BatteryStats.STATS_SINCE_CHARGED);
assertEquals("Miscalculations of Multicast wakelock acquisition time",
((releaseTimeMs_1 - acquireTimeMs_1) + (releaseTimeMs_2 - acquireTimeMs_2))
* 1000, totalTime);
* 1000, totalTime);
}
private void addIsolatedUid(int parentUid, int childUid) {
@ -426,20 +524,6 @@ public class BatteryStatsImplTest {
}
}
private void updateProcessStates(int[] uids, int[] procStates,
int[] pendingUidsIdx) {
final SparseIntArray pendingUids = mBatteryStatsImpl.getPendingUids();
for (int i = 0; i < uids.length; ++i) {
final BatteryStatsImpl.Uid u = mBatteryStatsImpl.getUidStatsLocked(uids[i]);
if (ArrayUtils.contains(pendingUidsIdx, i)) {
u.setProcessStateForTest(PROCESS_STATE_TOP);
pendingUids.put(uids[i], procStates[i]);
} else {
u.setProcessStateForTest(procStates[i]);
}
}
}
private void verifyNoPendingUids() {
final SparseIntArray pendingUids = mBatteryStatsImpl.getPendingUids();
assertEquals("There shouldn't be any pending uids left: " + pendingUids,

View File

@ -183,7 +183,9 @@ public class BstatsCpuTimesValidationTest {
sCpuFreqTimesAvailable = totalCpuTimes != null;
final long[] fgCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID,
PROCESS_STATE_FOREGROUND);
sPerProcStateTimesAvailable = fgCpuTimes != null;
final long[] topCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID,
PROCESS_STATE_TOP);
sPerProcStateTimesAvailable = fgCpuTimes != null || topCpuTimes != null;
}
@Test
@ -563,7 +565,7 @@ public class BstatsCpuTimesValidationTest {
final long[] cpuTimesMs3 = getAllCpuFreqTimes(sTestPkgUid, PROCESS_STATE_TOP);
assertCpuTimesValid(cpuTimesMs3);
assertCpuTimesEqual(cpuTimesMs3, cpuTimesMs, 20,
assertCpuTimesEqual(cpuTimesMs3, cpuTimesMs, 500,
"Unexpected cpu times after turning on tracking");
doSomeWork(PROCESS_STATE_TOP);
@ -588,7 +590,8 @@ public class BstatsCpuTimesValidationTest {
private void assertCpuTimesEqual(long[] actual, long[] expected, long delta, String errMsg) {
for (int i = actual.length - 1; i >= 0; --i) {
if (actual[i] > expected[i] + delta || actual[i] < expected[i]) {
fail(errMsg + ", actual=" + actual + ", expected=" + expected + ", delta=" + delta);
fail(errMsg + ", actual=" + Arrays.toString(actual)
+ ", expected=" + Arrays.toString(expected) + ", delta=" + delta);
}
}
}

View File

@ -285,7 +285,7 @@ public class KernelSingleUidTimeReaderTest {
LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 5);
counter.setState(0, 0);
mInjector.setCpuTimeInStatePerClusterNs(new long[][]{{0, 0, 0}, {0, 0}});
boolean success = mInjector.addDelta(TEST_UID, counter, 0);
boolean success = mInjector.addDelta(TEST_UID, counter, 0, null);
assertThat(success).isTrue();
// Nanoseconds
@ -294,13 +294,16 @@ public class KernelSingleUidTimeReaderTest {
{1_000_000, 2_000_000, 3_000_000},
{4_000_000, 5_000_000}});
success = mInjector.addDelta(TEST_UID, counter, 2000);
assertThat(success).isTrue();
LongArrayMultiStateCounter.LongArrayContainer array =
new LongArrayMultiStateCounter.LongArrayContainer(5);
long[] out = new long[5];
success = mInjector.addDelta(TEST_UID, counter, 2000, array);
assertThat(success).isTrue();
array.getValues(out);
assertThat(out).isEqualTo(new long[]{1, 2, 3, 4, 5});
counter.getCounts(array, 0);
array.getValues(out);
assertThat(out).isEqualTo(new long[]{1, 2, 3, 4, 5});
@ -312,9 +315,12 @@ public class KernelSingleUidTimeReaderTest {
{11_000_000, 22_000_000, 33_000_000},
{44_000_000, 55_000_000}});
success = mInjector.addDelta(TEST_UID, counter, 4000);
success = mInjector.addDelta(TEST_UID, counter, 4000, array);
assertThat(success).isTrue();
array.getValues(out);
assertThat(out).isEqualTo(new long[]{10, 20, 30, 40, 50});
counter.getCounts(array, 0);
array.getValues(out);
assertThat(out).isEqualTo(new long[]{1 + 5, 2 + 10, 3 + 15, 4 + 20, 5 + 25});
@ -371,8 +377,10 @@ public class KernelSingleUidTimeReaderTest {
}
@Override
public boolean addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs) {
return addDeltaForTest(uid, counter, timestampMs, mCpuTimeInStatePerClusterNs);
public boolean addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs,
LongArrayMultiStateCounter.LongArrayContainer deltaOut) {
return addDeltaForTest(uid, counter, timestampMs, mCpuTimeInStatePerClusterNs,
deltaOut);
}
}
}