diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 719dc5396c77..6644982f8ddd 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -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 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 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); } diff --git a/core/java/com/android/internal/os/KernelSingleUidTimeReader.java b/core/java/com/android/internal/os/KernelSingleUidTimeReader.java index 31952ebbaf69..90526443c394 100644 --- a/core/java/com/android/internal/os/KernelSingleUidTimeReader.java +++ b/core/java/com/android/internal/os/KernelSingleUidTimeReader.java @@ -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 diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java index aecab3db4cc4..d98b73f8ce93 100644 --- a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java +++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java @@ -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); diff --git a/core/jni/com_android_internal_os_KernelSingleUidTimeReader.cpp b/core/jni/com_android_internal_os_KernelSingleUidTimeReader.cpp index 689b25987cba..bea5ffe31da0 100644 --- a/core/jni/com_android_internal_os_KernelSingleUidTimeReader.cpp +++ b/core/jni/com_android_internal_os_KernelSingleUidTimeReader.cpp @@ -50,7 +50,8 @@ static jlongArray getUidCpuFreqTimeMs(JNIEnv *env, jclass, jint uid) { */ static jboolean addCpuTimeInFreqDelta( jint uid, jlong counterNativePtr, jlong timestampMs, - std::optional>> timeInFreqDataNanos) { + std::optional>> 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 &delta = counter->updateValue(flattened, timestampMs); + if (deltaOutContainerNativePtr) { + std::vector *vector = + reinterpret_cast *>(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::optional>>(), + deltaOutContainerNativePtr); } std::vector> 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) { diff --git a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp index 8326de22e938..6e7ebdabeeb3 100644 --- a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp +++ b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp @@ -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(nativePtr); + std::vector *vector = + reinterpret_cast *>(longArrayContainerNativePtr); + counter->addValue(*vector); +} + static void native_reset(jlong nativePtr) { battery::LongArrayMultiStateCounter *counter = reinterpret_cast(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}, diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java index cca66420c596..8b060ffa7cc1 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java @@ -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 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 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, diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java index 63e13fd071c6..441e85d4bca5 100644 --- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java @@ -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); } } } diff --git a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java index 418257470be9..74ab644f1376 100644 --- a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java +++ b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java @@ -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); } } }