Merge "Resolve STATSD and batterystats race condition" into pi-dev
am: 1639c330fc
Change-Id: I7715069130c5e8d3d4b74cdc8da4306942931627
This commit is contained in:
@@ -33,9 +33,6 @@ import android.net.wifi.WifiManager;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.Build;
|
||||
import android.os.connectivity.CellularBatteryStats;
|
||||
import android.os.connectivity.WifiBatteryStats;
|
||||
import android.os.connectivity.GpsBatteryStats;
|
||||
import android.os.FileUtils;
|
||||
import android.os.Handler;
|
||||
import android.os.IBatteryPropertiesRegistrar;
|
||||
@@ -53,6 +50,9 @@ import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.os.WorkSource;
|
||||
import android.os.WorkSource.WorkChain;
|
||||
import android.os.connectivity.CellularBatteryStats;
|
||||
import android.os.connectivity.GpsBatteryStats;
|
||||
import android.os.connectivity.WifiBatteryStats;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.DataConnectionRealTimeInfo;
|
||||
import android.telephony.ModemActivityInfo;
|
||||
@@ -90,8 +90,8 @@ import com.android.internal.util.FastXmlSerializer;
|
||||
import com.android.internal.util.JournaledFile;
|
||||
import com.android.internal.util.XmlUtils;
|
||||
|
||||
import java.util.List;
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
@@ -109,11 +109,11 @@ import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
@@ -234,11 +234,15 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
protected final SparseIntArray mPendingUids = new SparseIntArray();
|
||||
|
||||
@GuardedBy("this")
|
||||
private long mNumCpuTimeReads;
|
||||
private long mNumSingleUidCpuTimeReads;
|
||||
@GuardedBy("this")
|
||||
private long mNumBatchedCpuTimeReads;
|
||||
private long mNumBatchedSingleUidCpuTimeReads;
|
||||
@GuardedBy("this")
|
||||
private long mCpuTimeReadsTrackingStartTime = SystemClock.uptimeMillis();
|
||||
@GuardedBy("this")
|
||||
private int mNumUidsRemoved;
|
||||
@GuardedBy("this")
|
||||
private int mNumAllUidCpuTimeReads;
|
||||
|
||||
/** Container for Resource Power Manager stats. Updated by updateRpmStatsLocked. */
|
||||
private final RpmStats mTmpRpmStats = new RpmStats();
|
||||
@@ -246,6 +250,67 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
private static final long RPM_STATS_UPDATE_FREQ_MS = 1000;
|
||||
/** Last time that RPM stats were updated by updateRpmStatsLocked. */
|
||||
private long mLastRpmStatsUpdateTimeMs = -RPM_STATS_UPDATE_FREQ_MS;
|
||||
/**
|
||||
* Use a queue to delay removing UIDs from {@link KernelUidCpuTimeReader},
|
||||
* {@link KernelUidCpuActiveTimeReader}, {@link KernelUidCpuClusterTimeReader},
|
||||
* {@link KernelUidCpuFreqTimeReader} and from the Kernel.
|
||||
*
|
||||
* Isolated and invalid UID info must be removed to conserve memory. However, STATSD and
|
||||
* Batterystats both need to access UID cpu time. To resolve this race condition, only
|
||||
* Batterystats shall remove UIDs, and a delay {@link Constants#UID_REMOVE_DELAY_MS} is
|
||||
* implemented so that STATSD can capture those UID times before they are deleted.
|
||||
*/
|
||||
@GuardedBy("this")
|
||||
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
|
||||
protected Queue<UidToRemove> mPendingRemovedUids = new LinkedList<>();
|
||||
|
||||
@VisibleForTesting
|
||||
public final class UidToRemove {
|
||||
int startUid;
|
||||
int endUid;
|
||||
long timeAddedInQueue;
|
||||
|
||||
/** Remove just one UID */
|
||||
public UidToRemove(int uid, long timestamp) {
|
||||
this(uid, uid, timestamp);
|
||||
}
|
||||
|
||||
/** Remove a range of UIDs, startUid must be smaller than endUid. */
|
||||
public UidToRemove(int startUid, int endUid, long timestamp) {
|
||||
this.startUid = startUid;
|
||||
this.endUid = endUid;
|
||||
timeAddedInQueue = timestamp;
|
||||
}
|
||||
|
||||
void remove() {
|
||||
if (startUid == endUid) {
|
||||
mKernelUidCpuTimeReader.removeUid(startUid);
|
||||
mKernelUidCpuFreqTimeReader.removeUid(startUid);
|
||||
if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
|
||||
mKernelUidCpuActiveTimeReader.removeUid(startUid);
|
||||
mKernelUidCpuClusterTimeReader.removeUid(startUid);
|
||||
}
|
||||
if (mKernelSingleUidTimeReader != null) {
|
||||
mKernelSingleUidTimeReader.removeUid(startUid);
|
||||
}
|
||||
mNumUidsRemoved++;
|
||||
} else if (startUid < endUid) {
|
||||
mKernelUidCpuFreqTimeReader.removeUidsInRange(startUid, endUid);
|
||||
mKernelUidCpuTimeReader.removeUidsInRange(startUid, endUid);
|
||||
if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
|
||||
mKernelUidCpuActiveTimeReader.removeUidsInRange(startUid, endUid);
|
||||
mKernelUidCpuClusterTimeReader.removeUidsInRange(startUid, endUid);
|
||||
}
|
||||
if (mKernelSingleUidTimeReader != null) {
|
||||
mKernelSingleUidTimeReader.removeUidsInRange(startUid, endUid);
|
||||
}
|
||||
// Treat as one. We don't know how many uids there are in between.
|
||||
mNumUidsRemoved++;
|
||||
} else {
|
||||
Slog.w(TAG, "End UID " + endUid + " is smaller than start UID " + startUid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface BatteryCallback {
|
||||
public void batteryNeedsCpuUpdate();
|
||||
@@ -376,6 +441,14 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
}
|
||||
}
|
||||
|
||||
public void clearPendingRemovedUids() {
|
||||
long cutOffTime = mClocks.elapsedRealtime() - mConstants.UID_REMOVE_DELAY_MS;
|
||||
while (!mPendingRemovedUids.isEmpty()
|
||||
&& mPendingRemovedUids.peek().timeAddedInQueue < cutOffTime) {
|
||||
mPendingRemovedUids.poll().remove();
|
||||
}
|
||||
}
|
||||
|
||||
public void copyFromAllUidsCpuTimes() {
|
||||
synchronized (BatteryStatsImpl.this) {
|
||||
copyFromAllUidsCpuTimes(
|
||||
@@ -3961,12 +4034,7 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
u.removeIsolatedUid(isolatedUid);
|
||||
mIsolatedUids.removeAt(idx);
|
||||
}
|
||||
mKernelUidCpuTimeReader.removeUid(isolatedUid);
|
||||
mKernelUidCpuFreqTimeReader.removeUid(isolatedUid);
|
||||
if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
|
||||
mKernelUidCpuActiveTimeReader.removeUid(isolatedUid);
|
||||
mKernelUidCpuClusterTimeReader.removeUid(isolatedUid);
|
||||
}
|
||||
mPendingRemovedUids.add(new UidToRemove(isolatedUid, mClocks.elapsedRealtime()));
|
||||
}
|
||||
|
||||
public int mapUid(int uid) {
|
||||
@@ -9860,9 +9928,9 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
mBsi.mOnBatteryTimeBase.isRunning(),
|
||||
mBsi.mOnBatteryScreenOffTimeBase.isRunning(),
|
||||
mBsi.mConstants.PROC_STATE_CPU_TIMES_READ_DELAY_MS);
|
||||
mBsi.mNumCpuTimeReads++;
|
||||
mBsi.mNumSingleUidCpuTimeReads++;
|
||||
} else {
|
||||
mBsi.mNumBatchedCpuTimeReads++;
|
||||
mBsi.mNumBatchedSingleUidCpuTimeReads++;
|
||||
}
|
||||
if (mBsi.mPendingUids.indexOfKey(mUid) < 0
|
||||
|| ArrayUtils.contains(CRITICAL_PROC_STATES, mProcessState)) {
|
||||
@@ -11024,6 +11092,9 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
mLastStepStatSoftIrqTime = mCurStepStatSoftIrqTime = 0;
|
||||
mLastStepStatIdleTime = mCurStepStatIdleTime = 0;
|
||||
|
||||
mNumAllUidCpuTimeReads = 0;
|
||||
mNumUidsRemoved = 0;
|
||||
|
||||
initDischarge();
|
||||
|
||||
clearHistoryLocked();
|
||||
@@ -12009,9 +12080,11 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
if (!onBattery) {
|
||||
mKernelUidCpuTimeReader.readDelta(null);
|
||||
mKernelUidCpuFreqTimeReader.readDelta(null);
|
||||
mNumAllUidCpuTimeReads += 2;
|
||||
if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
|
||||
mKernelUidCpuActiveTimeReader.readDelta(null);
|
||||
mKernelUidCpuClusterTimeReader.readDelta(null);
|
||||
mNumAllUidCpuTimeReads += 2;
|
||||
}
|
||||
for (int cluster = mKernelCpuSpeedReaders.length - 1; cluster >= 0; --cluster) {
|
||||
mKernelCpuSpeedReaders[cluster].readDelta();
|
||||
@@ -12029,9 +12102,11 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
updateClusterSpeedTimes(updatedUids, onBattery);
|
||||
}
|
||||
readKernelUidCpuFreqTimesLocked(partialTimersToConsider, onBattery, onBatteryScreenOff);
|
||||
mNumAllUidCpuTimeReads += 2;
|
||||
if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
|
||||
readKernelUidCpuActiveTimesLocked(onBattery);
|
||||
readKernelUidCpuClusterTimesLocked(onBattery);
|
||||
mNumAllUidCpuTimeReads += 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13256,11 +13331,8 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
public void onCleanupUserLocked(int userId) {
|
||||
final int firstUidForUser = UserHandle.getUid(userId, 0);
|
||||
final int lastUidForUser = UserHandle.getUid(userId, UserHandle.PER_USER_RANGE - 1);
|
||||
mKernelUidCpuFreqTimeReader.removeUidsInRange(firstUidForUser, lastUidForUser);
|
||||
mKernelUidCpuTimeReader.removeUidsInRange(firstUidForUser, lastUidForUser);
|
||||
if (mKernelSingleUidTimeReader != null) {
|
||||
mKernelSingleUidTimeReader.removeUidsInRange(firstUidForUser, lastUidForUser);
|
||||
}
|
||||
mPendingRemovedUids.add(
|
||||
new UidToRemove(firstUidForUser, lastUidForUser, mClocks.elapsedRealtime()));
|
||||
}
|
||||
|
||||
public void onUserRemovedLocked(int userId) {
|
||||
@@ -13277,12 +13349,8 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
* Remove the statistics object for a particular uid.
|
||||
*/
|
||||
public void removeUidStatsLocked(int uid) {
|
||||
mKernelUidCpuTimeReader.removeUid(uid);
|
||||
mKernelUidCpuFreqTimeReader.removeUid(uid);
|
||||
if (mKernelSingleUidTimeReader != null) {
|
||||
mKernelSingleUidTimeReader.removeUid(uid);
|
||||
}
|
||||
mUidStats.remove(uid);
|
||||
mPendingRemovedUids.add(new UidToRemove(uid, mClocks.elapsedRealtime()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -13335,24 +13403,24 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
= "track_cpu_times_by_proc_state";
|
||||
public static final String KEY_TRACK_CPU_ACTIVE_CLUSTER_TIME
|
||||
= "track_cpu_active_cluster_time";
|
||||
public static final String KEY_READ_BINARY_CPU_TIME
|
||||
= "read_binary_cpu_time";
|
||||
public static final String KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS
|
||||
= "proc_state_cpu_times_read_delay_ms";
|
||||
public static final String KEY_KERNEL_UID_READERS_THROTTLE_TIME
|
||||
= "kernel_uid_readers_throttle_time";
|
||||
public static final String KEY_UID_REMOVE_DELAY_MS
|
||||
= "uid_remove_delay_ms";
|
||||
|
||||
private static final boolean DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE = true;
|
||||
private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true;
|
||||
private static final boolean DEFAULT_READ_BINARY_CPU_TIME = true;
|
||||
private static final long DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS = 5_000;
|
||||
private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 10_000;
|
||||
private static final long DEFAULT_UID_REMOVE_DELAY_MS = 5L * 60L * 1000L;
|
||||
|
||||
public boolean TRACK_CPU_TIMES_BY_PROC_STATE = DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE;
|
||||
public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME;
|
||||
public boolean READ_BINARY_CPU_TIME = DEFAULT_READ_BINARY_CPU_TIME;
|
||||
public long PROC_STATE_CPU_TIMES_READ_DELAY_MS = DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS;
|
||||
public long KERNEL_UID_READERS_THROTTLE_TIME = DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME;
|
||||
public long UID_REMOVE_DELAY_MS = DEFAULT_UID_REMOVE_DELAY_MS;
|
||||
|
||||
private ContentResolver mResolver;
|
||||
private final KeyValueListParser mParser = new KeyValueListParser(',');
|
||||
@@ -13390,14 +13458,14 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE));
|
||||
TRACK_CPU_ACTIVE_CLUSTER_TIME = mParser.getBoolean(
|
||||
KEY_TRACK_CPU_ACTIVE_CLUSTER_TIME, DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME);
|
||||
updateReadBinaryCpuTime(READ_BINARY_CPU_TIME,
|
||||
mParser.getBoolean(KEY_READ_BINARY_CPU_TIME, DEFAULT_READ_BINARY_CPU_TIME));
|
||||
updateProcStateCpuTimesReadDelayMs(PROC_STATE_CPU_TIMES_READ_DELAY_MS,
|
||||
mParser.getLong(KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS,
|
||||
DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS));
|
||||
updateKernelUidReadersThrottleTime(KERNEL_UID_READERS_THROTTLE_TIME,
|
||||
mParser.getLong(KEY_KERNEL_UID_READERS_THROTTLE_TIME,
|
||||
DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME));
|
||||
updateUidRemoveDelay(
|
||||
mParser.getLong(KEY_UID_REMOVE_DELAY_MS, DEFAULT_UID_REMOVE_DELAY_MS));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13407,24 +13475,17 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
mKernelSingleUidTimeReader.markDataAsStale(true);
|
||||
mExternalSync.scheduleCpuSyncDueToSettingChange();
|
||||
|
||||
mNumCpuTimeReads = 0;
|
||||
mNumBatchedCpuTimeReads = 0;
|
||||
mNumSingleUidCpuTimeReads = 0;
|
||||
mNumBatchedSingleUidCpuTimeReads = 0;
|
||||
mCpuTimeReadsTrackingStartTime = mClocks.uptimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateReadBinaryCpuTime(boolean oldEnabled, boolean isEnabled) {
|
||||
READ_BINARY_CPU_TIME = isEnabled;
|
||||
if (oldEnabled != isEnabled) {
|
||||
mKernelUidCpuFreqTimeReader.setReadBinary(isEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateProcStateCpuTimesReadDelayMs(long oldDelayMillis, long newDelayMillis) {
|
||||
PROC_STATE_CPU_TIMES_READ_DELAY_MS = newDelayMillis;
|
||||
if (oldDelayMillis != newDelayMillis) {
|
||||
mNumCpuTimeReads = 0;
|
||||
mNumBatchedCpuTimeReads = 0;
|
||||
mNumSingleUidCpuTimeReads = 0;
|
||||
mNumBatchedSingleUidCpuTimeReads = 0;
|
||||
mCpuTimeReadsTrackingStartTime = mClocks.uptimeMillis();
|
||||
}
|
||||
}
|
||||
@@ -13440,13 +13501,16 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateUidRemoveDelay(long newTimeMs) {
|
||||
UID_REMOVE_DELAY_MS = newTimeMs;
|
||||
clearPendingRemovedUids();
|
||||
}
|
||||
|
||||
public void dumpLocked(PrintWriter pw) {
|
||||
pw.print(KEY_TRACK_CPU_TIMES_BY_PROC_STATE); pw.print("=");
|
||||
pw.println(TRACK_CPU_TIMES_BY_PROC_STATE);
|
||||
pw.print(KEY_TRACK_CPU_ACTIVE_CLUSTER_TIME); pw.print("=");
|
||||
pw.println(TRACK_CPU_ACTIVE_CLUSTER_TIME);
|
||||
pw.print(KEY_READ_BINARY_CPU_TIME); pw.print("=");
|
||||
pw.println(READ_BINARY_CPU_TIME);
|
||||
pw.print(KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS); pw.print("=");
|
||||
pw.println(PROC_STATE_CPU_TIMES_READ_DELAY_MS);
|
||||
pw.print(KEY_KERNEL_UID_READERS_THROTTLE_TIME); pw.print("=");
|
||||
@@ -13459,6 +13523,43 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
mConstants.dumpLocked(pw);
|
||||
}
|
||||
|
||||
@GuardedBy("this")
|
||||
public void dumpCpuStatsLocked(PrintWriter pw) {
|
||||
int size = mUidStats.size();
|
||||
pw.println("Per UID CPU user & system time in ms:");
|
||||
for (int i = 0; i < size; i++) {
|
||||
int u = mUidStats.keyAt(i);
|
||||
Uid uid = mUidStats.get(u);
|
||||
pw.print(" "); pw.print(u); pw.print(": ");
|
||||
pw.print(uid.getUserCpuTimeUs(STATS_SINCE_CHARGED) / 1000); pw.print(" ");
|
||||
pw.println(uid.getSystemCpuTimeUs(STATS_SINCE_CHARGED) / 1000);
|
||||
}
|
||||
pw.println("Per UID CPU active time in ms:");
|
||||
for (int i = 0; i < size; i++) {
|
||||
int u = mUidStats.keyAt(i);
|
||||
Uid uid = mUidStats.get(u);
|
||||
if (uid.getCpuActiveTime() > 0) {
|
||||
pw.print(" "); pw.print(u); pw.print(": "); pw.println(uid.getCpuActiveTime());
|
||||
}
|
||||
}
|
||||
pw.println("Per UID CPU cluster time in ms:");
|
||||
for (int i = 0; i < size; i++) {
|
||||
int u = mUidStats.keyAt(i);
|
||||
long[] times = mUidStats.get(u).getCpuClusterTimes();
|
||||
if (times != null) {
|
||||
pw.print(" "); pw.print(u); pw.print(": "); pw.println(Arrays.toString(times));
|
||||
}
|
||||
}
|
||||
pw.println("Per UID CPU frequency time in ms:");
|
||||
for (int i = 0; i < size; i++) {
|
||||
int u = mUidStats.keyAt(i);
|
||||
long[] times = mUidStats.get(u).getCpuFreqTimes(STATS_SINCE_CHARGED);
|
||||
if (times != null) {
|
||||
pw.print(" "); pw.print(u); pw.print(": "); pw.println(Arrays.toString(times));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Parcel mPendingWrite = null;
|
||||
final ReentrantLock mWriteLock = new ReentrantLock();
|
||||
|
||||
@@ -15183,10 +15284,14 @@ public class BatteryStatsImpl extends BatteryStats {
|
||||
}
|
||||
super.dumpLocked(context, pw, flags, reqUid, histStart);
|
||||
pw.print("Total cpu time reads: ");
|
||||
pw.println(mNumCpuTimeReads);
|
||||
pw.println(mNumSingleUidCpuTimeReads);
|
||||
pw.print("Batched cpu time reads: ");
|
||||
pw.println(mNumBatchedCpuTimeReads);
|
||||
pw.println(mNumBatchedSingleUidCpuTimeReads);
|
||||
pw.print("Batching Duration (min): ");
|
||||
pw.println((mClocks.uptimeMillis() - mCpuTimeReadsTrackingStartTime) / (60 * 1000));
|
||||
pw.print("All UID cpu time reads since the later of device start or stats reset: ");
|
||||
pw.println(mNumAllUidCpuTimeReads);
|
||||
pw.print("UIDs removed since the later of device start or stats reset: ");
|
||||
pw.println(mNumUidsRemoved);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Reads binary proc file /proc/uid_cpupower/concurrent_active_time and reports CPU active time to
|
||||
@@ -54,6 +55,7 @@ public class KernelUidCpuActiveTimeReader extends
|
||||
|
||||
private final KernelCpuProcReader mProcReader;
|
||||
private SparseArray<Double> mLastUidCpuActiveTimeMs = new SparseArray<>();
|
||||
private int mCores;
|
||||
|
||||
public interface Callback extends KernelUidCpuTimeReaderBase.Callback {
|
||||
/**
|
||||
@@ -75,7 +77,60 @@ public class KernelUidCpuActiveTimeReader extends
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readDeltaImpl(@Nullable Callback cb) {
|
||||
protected void readDeltaImpl(@Nullable Callback callback) {
|
||||
readImpl((buf) -> {
|
||||
int uid = buf.get();
|
||||
double activeTime = sumActiveTime(buf);
|
||||
if (activeTime > 0) {
|
||||
double delta = activeTime - mLastUidCpuActiveTimeMs.get(uid, 0.0);
|
||||
if (delta > 0) {
|
||||
mLastUidCpuActiveTimeMs.put(uid, activeTime);
|
||||
if (callback != null) {
|
||||
callback.onUidCpuActiveTime(uid, (long) delta);
|
||||
}
|
||||
} else if (delta < 0) {
|
||||
Slog.e(TAG, "Negative delta from active time proc: " + delta);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void readAbsolute(Callback callback) {
|
||||
readImpl((buf) -> {
|
||||
int uid = buf.get();
|
||||
double activeTime = sumActiveTime(buf);
|
||||
if (activeTime > 0) {
|
||||
callback.onUidCpuActiveTime(uid, (long) activeTime);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private double sumActiveTime(IntBuffer buffer) {
|
||||
double sum = 0;
|
||||
boolean corrupted = false;
|
||||
for (int j = 1; j <= mCores; j++) {
|
||||
int time = buffer.get();
|
||||
if (time < 0) {
|
||||
// Even if error happens, we still need to continue reading.
|
||||
// Buffer cannot be skipped.
|
||||
Slog.e(TAG, "Negative time from active time proc: " + time);
|
||||
corrupted = true;
|
||||
} else {
|
||||
sum += (double) time * 10 / j; // Unit is 10ms.
|
||||
}
|
||||
}
|
||||
return corrupted ? -1 : sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* readImpl accepts a callback to process the uid entry. readDeltaImpl needs to store the last
|
||||
* seen results while processing the buffer, while readAbsolute returns the absolute value read
|
||||
* from the buffer without storing. So readImpl contains the common logic of the two, leaving
|
||||
* the difference to a processUid function.
|
||||
*
|
||||
* @param processUid the callback function to process the uid entry in the buffer.
|
||||
*/
|
||||
private void readImpl(Consumer<IntBuffer> processUid) {
|
||||
synchronized (mProcReader) {
|
||||
final ByteBuffer bytes = mProcReader.readBytes();
|
||||
if (bytes == null || bytes.remaining() <= 4) {
|
||||
@@ -89,6 +144,11 @@ public class KernelUidCpuActiveTimeReader extends
|
||||
}
|
||||
final IntBuffer buf = bytes.asIntBuffer();
|
||||
final int cores = buf.get();
|
||||
if (mCores != 0 && cores != mCores) {
|
||||
Slog.wtf(TAG, "Cpu active time wrong # cores: " + cores);
|
||||
return;
|
||||
}
|
||||
mCores = cores;
|
||||
if (cores <= 0 || buf.remaining() % (cores + 1) != 0) {
|
||||
Slog.wtf(TAG,
|
||||
"Cpu active time format error: " + buf.remaining() + " / " + (cores
|
||||
@@ -97,25 +157,7 @@ public class KernelUidCpuActiveTimeReader extends
|
||||
}
|
||||
int numUids = buf.remaining() / (cores + 1);
|
||||
for (int i = 0; i < numUids; i++) {
|
||||
int uid = buf.get();
|
||||
boolean corrupted = false;
|
||||
double curTime = 0;
|
||||
for (int j = 1; j <= cores; j++) {
|
||||
int time = buf.get();
|
||||
if (time < 0) {
|
||||
Slog.e(TAG, "Corrupted data from active time proc: " + time);
|
||||
corrupted = true;
|
||||
} else {
|
||||
curTime += (double) time * 10 / j; // Unit is 10ms.
|
||||
}
|
||||
}
|
||||
double delta = curTime - mLastUidCpuActiveTimeMs.get(uid, 0.0);
|
||||
if (delta > 0 && !corrupted) {
|
||||
mLastUidCpuActiveTimeMs.put(uid, curTime);
|
||||
if (cb != null) {
|
||||
cb.onUidCpuActiveTime(uid, (long) delta);
|
||||
}
|
||||
}
|
||||
processUid.accept(buf);
|
||||
}
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Read uids: " + numUids);
|
||||
@@ -123,26 +165,11 @@ public class KernelUidCpuActiveTimeReader extends
|
||||
}
|
||||
}
|
||||
|
||||
public void readAbsolute(Callback cb) {
|
||||
synchronized (mProcReader) {
|
||||
readDelta(null);
|
||||
int total = mLastUidCpuActiveTimeMs.size();
|
||||
for (int i = 0; i < total; i ++){
|
||||
int uid = mLastUidCpuActiveTimeMs.keyAt(i);
|
||||
cb.onUidCpuActiveTime(uid, mLastUidCpuActiveTimeMs.get(uid).longValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeUid(int uid) {
|
||||
mLastUidCpuActiveTimeMs.delete(uid);
|
||||
}
|
||||
|
||||
public void removeUidsInRange(int startUid, int endUid) {
|
||||
if (endUid < startUid) {
|
||||
Slog.w(TAG, "End UID " + endUid + " is smaller than start UID " + startUid);
|
||||
return;
|
||||
}
|
||||
mLastUidCpuActiveTimeMs.put(startUid, null);
|
||||
mLastUidCpuActiveTimeMs.put(endUid, null);
|
||||
final int firstIndex = mLastUidCpuActiveTimeMs.indexOfKey(startUid);
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Reads binary proc file /proc/uid_cpupower/concurrent_policy_time and reports CPU cluster times
|
||||
@@ -89,6 +90,72 @@ public class KernelUidCpuClusterTimeReader extends
|
||||
|
||||
@Override
|
||||
protected void readDeltaImpl(@Nullable Callback cb) {
|
||||
readImpl((buf) -> {
|
||||
int uid = buf.get();
|
||||
double[] lastTimes = mLastUidPolicyTimeMs.get(uid);
|
||||
if (lastTimes == null) {
|
||||
lastTimes = new double[mNumClusters];
|
||||
mLastUidPolicyTimeMs.put(uid, lastTimes);
|
||||
}
|
||||
if (!sumClusterTime(buf, mCurTime)) {
|
||||
return;
|
||||
}
|
||||
boolean valid = true;
|
||||
boolean notify = false;
|
||||
for (int i = 0; i < mNumClusters; i++) {
|
||||
mDeltaTime[i] = (long) (mCurTime[i] - lastTimes[i]);
|
||||
if (mDeltaTime[i] < 0) {
|
||||
Slog.e(TAG, "Negative delta from cluster time proc: " + mDeltaTime[i]);
|
||||
valid = false;
|
||||
}
|
||||
notify |= mDeltaTime[i] > 0;
|
||||
}
|
||||
if (notify && valid) {
|
||||
System.arraycopy(mCurTime, 0, lastTimes, 0, mNumClusters);
|
||||
if (cb != null) {
|
||||
cb.onUidCpuPolicyTime(uid, mDeltaTime);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void readAbsolute(Callback callback) {
|
||||
readImpl((buf) -> {
|
||||
int uid = buf.get();
|
||||
if (sumClusterTime(buf, mCurTime)) {
|
||||
for (int i = 0; i < mNumClusters; i++) {
|
||||
mCurTimeRounded[i] = (long) mCurTime[i];
|
||||
}
|
||||
callback.onUidCpuPolicyTime(uid, mCurTimeRounded);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean sumClusterTime(IntBuffer buffer, double[] clusterTime) {
|
||||
boolean valid = true;
|
||||
for (int i = 0; i < mNumClusters; i++) {
|
||||
clusterTime[i] = 0;
|
||||
for (int j = 1; j <= mNumCoresOnCluster[i]; j++) {
|
||||
int time = buffer.get();
|
||||
if (time < 0) {
|
||||
Slog.e(TAG, "Negative time from cluster time proc: " + time);
|
||||
valid = false;
|
||||
}
|
||||
clusterTime[i] += (double) time * 10 / j; // Unit is 10ms.
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* readImpl accepts a callback to process the uid entry. readDeltaImpl needs to store the last
|
||||
* seen results while processing the buffer, while readAbsolute returns the absolute value read
|
||||
* from the buffer without storing. So readImpl contains the common logic of the two, leaving
|
||||
* the difference to a processUid function.
|
||||
*
|
||||
* @param processUid the callback function to process the uid entry in the buffer.
|
||||
*/
|
||||
private void readImpl(Consumer<IntBuffer> processUid) {
|
||||
synchronized (mProcReader) {
|
||||
ByteBuffer bytes = mProcReader.readBytes();
|
||||
if (bytes == null || bytes.remaining() <= 4) {
|
||||
@@ -130,7 +197,7 @@ public class KernelUidCpuClusterTimeReader extends
|
||||
int numUids = buf.remaining() / (mNumCores + 1);
|
||||
|
||||
for (int i = 0; i < numUids; i++) {
|
||||
processUid(buf, cb);
|
||||
processUid.accept(buf);
|
||||
}
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Read uids: " + numUids);
|
||||
@@ -138,57 +205,6 @@ public class KernelUidCpuClusterTimeReader extends
|
||||
}
|
||||
}
|
||||
|
||||
public void readAbsolute(Callback cb) {
|
||||
synchronized (mProcReader) {
|
||||
readDelta(null);
|
||||
int total = mLastUidPolicyTimeMs.size();
|
||||
for (int i = 0; i < total; i ++){
|
||||
int uid = mLastUidPolicyTimeMs.keyAt(i);
|
||||
double[] lastTimes = mLastUidPolicyTimeMs.get(uid);
|
||||
for (int j = 0; j < mNumClusters; j++) {
|
||||
mCurTimeRounded[j] = (long) lastTimes[j];
|
||||
}
|
||||
cb.onUidCpuPolicyTime(uid, mCurTimeRounded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processUid(IntBuffer buf, @Nullable Callback cb) {
|
||||
int uid = buf.get();
|
||||
double[] lastTimes = mLastUidPolicyTimeMs.get(uid);
|
||||
if (lastTimes == null) {
|
||||
lastTimes = new double[mNumClusters];
|
||||
mLastUidPolicyTimeMs.put(uid, lastTimes);
|
||||
}
|
||||
|
||||
boolean notify = false;
|
||||
boolean corrupted = false;
|
||||
|
||||
for (int j = 0; j < mNumClusters; j++) {
|
||||
mCurTime[j] = 0;
|
||||
for (int k = 1; k <= mNumCoresOnCluster[j]; k++) {
|
||||
int time = buf.get();
|
||||
if (time < 0) {
|
||||
Slog.e(TAG, "Corrupted data from cluster time proc uid: " + uid);
|
||||
corrupted = true;
|
||||
}
|
||||
mCurTime[j] += (double) time * 10 / k; // Unit is 10ms.
|
||||
}
|
||||
mDeltaTime[j] = (long) (mCurTime[j] - lastTimes[j]);
|
||||
if (mDeltaTime[j] < 0) {
|
||||
Slog.e(TAG, "Unexpected delta from cluster time proc uid: " + uid);
|
||||
corrupted = true;
|
||||
}
|
||||
notify |= mDeltaTime[j] > 0;
|
||||
}
|
||||
if (notify && !corrupted) {
|
||||
System.arraycopy(mCurTime, 0, lastTimes, 0, mNumClusters);
|
||||
if (cb != null) {
|
||||
cb.onUidCpuPolicyTime(uid, mDeltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns if it has read valid info.
|
||||
private boolean readCoreInfo(IntBuffer buf, int numClusters) {
|
||||
int numCores = 0;
|
||||
@@ -214,10 +230,6 @@ public class KernelUidCpuClusterTimeReader extends
|
||||
}
|
||||
|
||||
public void removeUidsInRange(int startUid, int endUid) {
|
||||
if (endUid < startUid) {
|
||||
Slog.w(TAG, "End UID " + endUid + " is smaller than start UID " + startUid);
|
||||
return;
|
||||
}
|
||||
mLastUidPolicyTimeMs.put(startUid, null);
|
||||
mLastUidPolicyTimeMs.put(endUid, null);
|
||||
final int firstIndex = mLastUidPolicyTimeMs.indexOfKey(startUid);
|
||||
|
||||
@@ -21,11 +21,9 @@ import static com.android.internal.util.Preconditions.checkNotNull;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.StrictMode;
|
||||
import android.os.SystemClock;
|
||||
import android.util.IntArray;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TimeUtils;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
@@ -34,6 +32,7 @@ import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Reads /proc/uid_time_in_state which has the format:
|
||||
@@ -75,9 +74,6 @@ public class KernelUidCpuFreqTimeReader extends
|
||||
private long[] mCurTimes; // Reuse to prevent GC.
|
||||
private long[] mDeltaTimes; // Reuse to prevent GC.
|
||||
private int mCpuFreqsCount;
|
||||
private long mLastTimeReadMs = Long.MIN_VALUE;
|
||||
private long mNowTimeMs;
|
||||
private boolean mReadBinary = true;
|
||||
private final KernelCpuProcReader mProcReader;
|
||||
|
||||
private SparseArray<long[]> mLastUidCpuFreqTimeMs = new SparseArray<>();
|
||||
@@ -140,180 +136,6 @@ public class KernelUidCpuFreqTimeReader extends
|
||||
if (line == null) {
|
||||
return null;
|
||||
}
|
||||
return readCpuFreqs(line, powerProfile);
|
||||
}
|
||||
|
||||
public void setReadBinary(boolean readBinary) {
|
||||
mReadBinary = readBinary;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readDeltaImpl(@Nullable Callback callback) {
|
||||
if (mCpuFreqs == null) {
|
||||
return;
|
||||
}
|
||||
if (mReadBinary) {
|
||||
readDeltaBinary(callback);
|
||||
} else {
|
||||
readDeltaString(callback);
|
||||
}
|
||||
}
|
||||
|
||||
private void readDeltaString(@Nullable Callback callback) {
|
||||
mNowTimeMs = SystemClock.elapsedRealtime();
|
||||
final int oldMask = StrictMode.allowThreadDiskReadsMask();
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) {
|
||||
readDelta(reader, callback);
|
||||
} catch (IOException e) {
|
||||
Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e);
|
||||
} finally {
|
||||
StrictMode.setThreadPolicyMask(oldMask);
|
||||
}
|
||||
mLastTimeReadMs = mNowTimeMs;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void readDeltaBinary(@Nullable Callback callback) {
|
||||
synchronized (mProcReader) {
|
||||
ByteBuffer bytes = mProcReader.readBytes();
|
||||
if (bytes == null || bytes.remaining() <= 4) {
|
||||
// Error already logged in mProcReader.
|
||||
return;
|
||||
}
|
||||
if ((bytes.remaining() & 3) != 0) {
|
||||
Slog.wtf(TAG, "Cannot parse cluster time proc bytes to int: " + bytes.remaining());
|
||||
return;
|
||||
}
|
||||
IntBuffer buf = bytes.asIntBuffer();
|
||||
final int freqs = buf.get();
|
||||
if (freqs != mCpuFreqsCount) {
|
||||
Slog.wtf(TAG, "Cpu freqs expect " + mCpuFreqsCount + " , got " + freqs);
|
||||
return;
|
||||
}
|
||||
if (buf.remaining() % (freqs + 1) != 0) {
|
||||
Slog.wtf(TAG, "Freq time format error: " + buf.remaining() + " / " + (freqs + 1));
|
||||
return;
|
||||
}
|
||||
int numUids = buf.remaining() / (freqs + 1);
|
||||
for (int i = 0; i < numUids; i++) {
|
||||
int uid = buf.get();
|
||||
long[] lastTimes = mLastUidCpuFreqTimeMs.get(uid);
|
||||
if (lastTimes == null) {
|
||||
lastTimes = new long[mCpuFreqsCount];
|
||||
mLastUidCpuFreqTimeMs.put(uid, lastTimes);
|
||||
}
|
||||
boolean notify = false;
|
||||
boolean corrupted = false;
|
||||
for (int j = 0; j < freqs; j++) {
|
||||
mCurTimes[j] = (long) buf.get() * 10; // Unit is 10ms.
|
||||
mDeltaTimes[j] = mCurTimes[j] - lastTimes[j];
|
||||
if (mCurTimes[j] < 0 || mDeltaTimes[j] < 0) {
|
||||
Slog.e(TAG, "Unexpected data from freq time proc: " + mCurTimes[j]);
|
||||
corrupted = true;
|
||||
}
|
||||
notify |= mDeltaTimes[j] > 0;
|
||||
}
|
||||
if (notify && !corrupted) {
|
||||
System.arraycopy(mCurTimes, 0, lastTimes, 0, freqs);
|
||||
if (callback != null) {
|
||||
callback.onUidCpuFreqTime(uid, mDeltaTimes);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Read uids: " + numUids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void readAbsolute(Callback cb) {
|
||||
synchronized (mProcReader) {
|
||||
readDelta(null);
|
||||
int total = mLastUidCpuFreqTimeMs.size();
|
||||
for (int i = 0; i < total; i ++){
|
||||
int uid = mLastUidCpuFreqTimeMs.keyAt(i);
|
||||
cb.onUidCpuFreqTime(uid, mLastUidCpuFreqTimeMs.get(uid));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeUid(int uid) {
|
||||
mLastUidCpuFreqTimeMs.delete(uid);
|
||||
}
|
||||
|
||||
public void removeUidsInRange(int startUid, int endUid) {
|
||||
if (endUid < startUid) {
|
||||
return;
|
||||
}
|
||||
mLastUidCpuFreqTimeMs.put(startUid, null);
|
||||
mLastUidCpuFreqTimeMs.put(endUid, null);
|
||||
final int firstIndex = mLastUidCpuFreqTimeMs.indexOfKey(startUid);
|
||||
final int lastIndex = mLastUidCpuFreqTimeMs.indexOfKey(endUid);
|
||||
mLastUidCpuFreqTimeMs.removeAtRange(firstIndex, lastIndex - firstIndex + 1);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void readDelta(BufferedReader reader, @Nullable Callback callback) throws IOException {
|
||||
String line = reader.readLine();
|
||||
if (line == null) {
|
||||
return;
|
||||
}
|
||||
while ((line = reader.readLine()) != null) {
|
||||
final int index = line.indexOf(' ');
|
||||
final int uid = Integer.parseInt(line.substring(0, index - 1), 10);
|
||||
readTimesForUid(uid, line.substring(index + 1, line.length()), callback);
|
||||
}
|
||||
}
|
||||
|
||||
private void readTimesForUid(int uid, String line, Callback callback) {
|
||||
long[] uidTimeMs = mLastUidCpuFreqTimeMs.get(uid);
|
||||
if (uidTimeMs == null) {
|
||||
uidTimeMs = new long[mCpuFreqsCount];
|
||||
mLastUidCpuFreqTimeMs.put(uid, uidTimeMs);
|
||||
}
|
||||
final String[] timesStr = line.split(" ");
|
||||
final int size = timesStr.length;
|
||||
if (size != uidTimeMs.length) {
|
||||
Slog.e(TAG, "No. of readings don't match cpu freqs, readings: " + size
|
||||
+ " cpuFreqsCount: " + uidTimeMs.length);
|
||||
return;
|
||||
}
|
||||
final long[] deltaUidTimeMs = new long[size];
|
||||
final long[] curUidTimeMs = new long[size];
|
||||
boolean notify = false;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
// Times read will be in units of 10ms
|
||||
final long totalTimeMs = Long.parseLong(timesStr[i], 10) * 10;
|
||||
deltaUidTimeMs[i] = totalTimeMs - uidTimeMs[i];
|
||||
// If there is malformed data for any uid, then we just log about it and ignore
|
||||
// the data for that uid.
|
||||
if (deltaUidTimeMs[i] < 0 || totalTimeMs < 0) {
|
||||
if (DEBUG) {
|
||||
final StringBuilder sb = new StringBuilder("Malformed cpu freq data for UID=")
|
||||
.append(uid).append("\n");
|
||||
sb.append("data=").append("(").append(uidTimeMs[i]).append(",")
|
||||
.append(totalTimeMs).append(")").append("\n");
|
||||
sb.append("times=").append("(");
|
||||
TimeUtils.formatDuration(mLastTimeReadMs, sb);
|
||||
sb.append(",");
|
||||
TimeUtils.formatDuration(mNowTimeMs, sb);
|
||||
sb.append(")");
|
||||
Slog.e(TAG, sb.toString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
curUidTimeMs[i] = totalTimeMs;
|
||||
notify = notify || (deltaUidTimeMs[i] > 0);
|
||||
}
|
||||
if (notify) {
|
||||
System.arraycopy(curUidTimeMs, 0, uidTimeMs, 0, size);
|
||||
if (callback != null) {
|
||||
callback.onUidCpuFreqTime(uid, deltaUidTimeMs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private long[] readCpuFreqs(String line, PowerProfile powerProfile) {
|
||||
final String[] freqStr = line.split(" ");
|
||||
// First item would be "uid: " which needs to be ignored.
|
||||
mCpuFreqsCount = freqStr.length - 1;
|
||||
@@ -339,10 +161,116 @@ public class KernelUidCpuFreqTimeReader extends
|
||||
mPerClusterTimesAvailable = false;
|
||||
}
|
||||
Slog.i(TAG, "mPerClusterTimesAvailable=" + mPerClusterTimesAvailable);
|
||||
|
||||
return mCpuFreqs;
|
||||
}
|
||||
|
||||
@Override
|
||||
@VisibleForTesting
|
||||
public void readDeltaImpl(@Nullable Callback callback) {
|
||||
if (mCpuFreqs == null) {
|
||||
return;
|
||||
}
|
||||
readImpl((buf) -> {
|
||||
int uid = buf.get();
|
||||
long[] lastTimes = mLastUidCpuFreqTimeMs.get(uid);
|
||||
if (lastTimes == null) {
|
||||
lastTimes = new long[mCpuFreqsCount];
|
||||
mLastUidCpuFreqTimeMs.put(uid, lastTimes);
|
||||
}
|
||||
if (!getFreqTimeForUid(buf, mCurTimes)) {
|
||||
return;
|
||||
}
|
||||
boolean notify = false;
|
||||
boolean valid = true;
|
||||
for (int i = 0; i < mCpuFreqsCount; i++) {
|
||||
mDeltaTimes[i] = mCurTimes[i] - lastTimes[i];
|
||||
if (mDeltaTimes[i] < 0) {
|
||||
Slog.e(TAG, "Negative delta from freq time proc: " + mDeltaTimes[i]);
|
||||
valid = false;
|
||||
}
|
||||
notify |= mDeltaTimes[i] > 0;
|
||||
}
|
||||
if (notify && valid) {
|
||||
System.arraycopy(mCurTimes, 0, lastTimes, 0, mCpuFreqsCount);
|
||||
if (callback != null) {
|
||||
callback.onUidCpuFreqTime(uid, mDeltaTimes);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void readAbsolute(Callback callback) {
|
||||
readImpl((buf) -> {
|
||||
int uid = buf.get();
|
||||
if (getFreqTimeForUid(buf, mCurTimes)) {
|
||||
callback.onUidCpuFreqTime(uid, mCurTimes);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean getFreqTimeForUid(IntBuffer buffer, long[] freqTime) {
|
||||
boolean valid = true;
|
||||
for (int i = 0; i < mCpuFreqsCount; i++) {
|
||||
freqTime[i] = (long) buffer.get() * 10; // Unit is 10ms.
|
||||
if (freqTime[i] < 0) {
|
||||
Slog.e(TAG, "Negative time from freq time proc: " + freqTime[i]);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* readImpl accepts a callback to process the uid entry. readDeltaImpl needs to store the last
|
||||
* seen results while processing the buffer, while readAbsolute returns the absolute value read
|
||||
* from the buffer without storing. So readImpl contains the common logic of the two, leaving
|
||||
* the difference to a processUid function.
|
||||
*
|
||||
* @param processUid the callback function to process the uid entry in the buffer.
|
||||
*/
|
||||
private void readImpl(Consumer<IntBuffer> processUid) {
|
||||
synchronized (mProcReader) {
|
||||
ByteBuffer bytes = mProcReader.readBytes();
|
||||
if (bytes == null || bytes.remaining() <= 4) {
|
||||
// Error already logged in mProcReader.
|
||||
return;
|
||||
}
|
||||
if ((bytes.remaining() & 3) != 0) {
|
||||
Slog.wtf(TAG, "Cannot parse freq time proc bytes to int: " + bytes.remaining());
|
||||
return;
|
||||
}
|
||||
IntBuffer buf = bytes.asIntBuffer();
|
||||
final int freqs = buf.get();
|
||||
if (freqs != mCpuFreqsCount) {
|
||||
Slog.wtf(TAG, "Cpu freqs expect " + mCpuFreqsCount + " , got " + freqs);
|
||||
return;
|
||||
}
|
||||
if (buf.remaining() % (freqs + 1) != 0) {
|
||||
Slog.wtf(TAG, "Freq time format error: " + buf.remaining() + " / " + (freqs + 1));
|
||||
return;
|
||||
}
|
||||
int numUids = buf.remaining() / (freqs + 1);
|
||||
for (int i = 0; i < numUids; i++) {
|
||||
processUid.accept(buf);
|
||||
}
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Read uids: #" + numUids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeUid(int uid) {
|
||||
mLastUidCpuFreqTimeMs.delete(uid);
|
||||
}
|
||||
|
||||
public void removeUidsInRange(int startUid, int endUid) {
|
||||
mLastUidCpuFreqTimeMs.put(startUid, null);
|
||||
mLastUidCpuFreqTimeMs.put(endUid, null);
|
||||
final int firstIndex = mLastUidCpuFreqTimeMs.indexOfKey(startUid);
|
||||
final int lastIndex = mLastUidCpuFreqTimeMs.indexOfKey(endUid);
|
||||
mLastUidCpuFreqTimeMs.removeAtRange(firstIndex, lastIndex - firstIndex + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts no. of cpu clusters and no. of freqs in each of these clusters from the freqs
|
||||
* read from the proc file.
|
||||
|
||||
@@ -1084,6 +1084,49 @@ public class BatteryStatsCpuTimesTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadKernelUidCpuActiveTimesLocked_invalidUid() {
|
||||
// PRECONDITIONS
|
||||
updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
|
||||
|
||||
final int testUserId = 11;
|
||||
final int invalidUserId = 15;
|
||||
final int invalidUid = UserHandle.getUid(invalidUserId, FIRST_APPLICATION_UID + 99);
|
||||
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
|
||||
when(mUserInfoProvider.exists(invalidUserId)).thenReturn(false);
|
||||
final int[] testUids = getUids(testUserId, new int[]{
|
||||
FIRST_APPLICATION_UID + 22,
|
||||
FIRST_APPLICATION_UID + 27,
|
||||
FIRST_APPLICATION_UID + 33
|
||||
});
|
||||
final long[] uidTimesMs = {8000, 25000, 3000, 0, 42000};
|
||||
doAnswer(invocation -> {
|
||||
final KernelUidCpuActiveTimeReader.Callback callback =
|
||||
(KernelUidCpuActiveTimeReader.Callback) invocation.getArguments()[0];
|
||||
for (int i = 0; i < testUids.length; ++i) {
|
||||
callback.onUidCpuActiveTime(testUids[i], uidTimesMs[i]);
|
||||
}
|
||||
// And one for the invalid uid
|
||||
callback.onUidCpuActiveTime(invalidUid, 1200L);
|
||||
return null;
|
||||
}).when(mKernelUidCpuActiveTimeReader).readDelta(
|
||||
any(KernelUidCpuActiveTimeReader.Callback.class));
|
||||
|
||||
// RUN
|
||||
mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked(true);
|
||||
|
||||
// VERIFY
|
||||
for (int i = 0; i < testUids.length; ++i) {
|
||||
final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
|
||||
assertNotNull("No entry for uid=" + testUids[i], u);
|
||||
assertEquals("Unexpected cpu active time for uid=" + testUids[i], uidTimesMs[i],
|
||||
u.getCpuActiveTime());
|
||||
}
|
||||
assertNull("There shouldn't be an entry for invalid uid=" + invalidUid,
|
||||
mBatteryStatsImpl.getUidStats().get(invalidUid));
|
||||
verify(mKernelUidCpuActiveTimeReader).removeUid(invalidUid);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadKernelUidCpuClusterTimesLocked() {
|
||||
// PRECONDITIONS
|
||||
@@ -1153,6 +1196,97 @@ public class BatteryStatsCpuTimesTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadKernelUidCpuClusterTimesLocked_invalidUid() {
|
||||
// PRECONDITIONS
|
||||
updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
|
||||
|
||||
final int testUserId = 11;
|
||||
final int invalidUserId = 15;
|
||||
final int invalidUid = UserHandle.getUid(invalidUserId, FIRST_APPLICATION_UID + 99);
|
||||
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
|
||||
when(mUserInfoProvider.exists(invalidUserId)).thenReturn(false);
|
||||
final int[] testUids = getUids(testUserId, new int[]{
|
||||
FIRST_APPLICATION_UID + 22,
|
||||
FIRST_APPLICATION_UID + 27,
|
||||
FIRST_APPLICATION_UID + 33
|
||||
});
|
||||
final long[][] uidTimesMs = {
|
||||
{4000, 10000},
|
||||
{5000, 1000},
|
||||
{8000, 0}
|
||||
};
|
||||
doAnswer(invocation -> {
|
||||
final KernelUidCpuClusterTimeReader.Callback callback =
|
||||
(KernelUidCpuClusterTimeReader.Callback) invocation.getArguments()[0];
|
||||
for (int i = 0; i < testUids.length; ++i) {
|
||||
callback.onUidCpuPolicyTime(testUids[i], uidTimesMs[i]);
|
||||
}
|
||||
// And one for the invalid uid
|
||||
callback.onUidCpuPolicyTime(invalidUid, new long[] {400, 1000});
|
||||
return null;
|
||||
}).when(mKernelUidCpuClusterTimeReader).readDelta(
|
||||
any(KernelUidCpuClusterTimeReader.Callback.class));
|
||||
|
||||
// RUN
|
||||
mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true);
|
||||
|
||||
// VERIFY
|
||||
for (int i = 0; i < testUids.length; ++i) {
|
||||
final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
|
||||
assertNotNull("No entry for uid=" + testUids[i], u);
|
||||
assertArrayEquals("Unexpected cpu cluster time for uid=" + testUids[i], uidTimesMs[i],
|
||||
u.getCpuClusterTimes());
|
||||
}
|
||||
assertNull("There shouldn't be an entry for invalid uid=" + invalidUid,
|
||||
mBatteryStatsImpl.getUidStats().get(invalidUid));
|
||||
verify(mKernelUidCpuClusterTimeReader).removeUid(invalidUid);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveUidCpuTimes() {
|
||||
mClocks.realtime = mClocks.uptime = 0;
|
||||
mBatteryStatsImpl.getPendingRemovedUids().add(
|
||||
mBatteryStatsImpl.new UidToRemove(1, mClocks.elapsedRealtime()));
|
||||
mBatteryStatsImpl.getPendingRemovedUids().add(
|
||||
mBatteryStatsImpl.new UidToRemove(5, 10, mClocks.elapsedRealtime()));
|
||||
mBatteryStatsImpl.clearPendingRemovedUids();
|
||||
assertEquals(2, mBatteryStatsImpl.getPendingRemovedUids().size());
|
||||
|
||||
mClocks.realtime = mClocks.uptime = 100_000;
|
||||
mBatteryStatsImpl.clearPendingRemovedUids();
|
||||
assertEquals(2, mBatteryStatsImpl.getPendingRemovedUids().size());
|
||||
|
||||
mClocks.realtime = mClocks.uptime = 200_000;
|
||||
mBatteryStatsImpl.getPendingRemovedUids().add(
|
||||
mBatteryStatsImpl.new UidToRemove(100, mClocks.elapsedRealtime()));
|
||||
mBatteryStatsImpl.clearPendingRemovedUids();
|
||||
assertEquals(3, mBatteryStatsImpl.getPendingRemovedUids().size());
|
||||
|
||||
mClocks.realtime = mClocks.uptime = 400_000;
|
||||
mBatteryStatsImpl.clearPendingRemovedUids();
|
||||
assertEquals(1, mBatteryStatsImpl.getPendingRemovedUids().size());
|
||||
verify(mKernelUidCpuActiveTimeReader).removeUid(1);
|
||||
verify(mKernelUidCpuActiveTimeReader).removeUidsInRange(5, 10);
|
||||
verify(mKernelUidCpuClusterTimeReader).removeUid(1);
|
||||
verify(mKernelUidCpuClusterTimeReader).removeUidsInRange(5, 10);
|
||||
verify(mKernelUidCpuFreqTimeReader).removeUid(1);
|
||||
verify(mKernelUidCpuFreqTimeReader).removeUidsInRange(5, 10);
|
||||
verify(mKernelUidCpuTimeReader).removeUid(1);
|
||||
verify(mKernelUidCpuTimeReader).removeUidsInRange(5, 10);
|
||||
|
||||
mClocks.realtime = mClocks.uptime = 800_000;
|
||||
mBatteryStatsImpl.clearPendingRemovedUids();
|
||||
assertEquals(0, mBatteryStatsImpl.getPendingRemovedUids().size());
|
||||
verify(mKernelUidCpuActiveTimeReader).removeUid(100);
|
||||
verify(mKernelUidCpuClusterTimeReader).removeUid(100);
|
||||
verify(mKernelUidCpuFreqTimeReader).removeUid(100);
|
||||
verify(mKernelUidCpuTimeReader).removeUid(100);
|
||||
|
||||
verifyNoMoreInteractions(mKernelUidCpuActiveTimeReader, mKernelUidCpuClusterTimeReader,
|
||||
mKernelUidCpuFreqTimeReader, mKernelUidCpuTimeReader);
|
||||
}
|
||||
|
||||
private void updateTimeBasesLocked(boolean unplugged, int screenState,
|
||||
long upTime, long realTime) {
|
||||
// Set PowerProfile=null before calling updateTimeBasesLocked to avoid execution of
|
||||
|
||||
@@ -244,13 +244,16 @@ public class BatteryStatsNoteTest extends TestCase {
|
||||
assertEquals(bi.getScreenState(), Display.STATE_OFF);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Test BatteryStatsImpl.noteScreenStateLocked updates timers correctly.
|
||||
*
|
||||
* Unknown and doze should both be subset of off state
|
||||
*
|
||||
* Timeline 0----100----200----310----400------------1000 Unknown ------- On ------- Off
|
||||
* ------- ---------------------- Doze ----------------
|
||||
* Timeline 0----100----200----310----400------------1000
|
||||
* Unknown -------
|
||||
* On -------
|
||||
* Off ------- ----------------------
|
||||
* Doze ----------------
|
||||
*/
|
||||
@SmallTest
|
||||
public void testNoteScreenStateTimersLocked() throws Exception {
|
||||
|
||||
@@ -57,7 +57,7 @@ public class KernelUidCpuActiveTimeReaderTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadDelta() throws Exception {
|
||||
public void testReadDelta() {
|
||||
final int cores = 8;
|
||||
final int[] uids = {1, 22, 333, 4444, 5555};
|
||||
|
||||
@@ -104,7 +104,7 @@ public class KernelUidCpuActiveTimeReaderTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadAbsolute() throws Exception {
|
||||
public void testReadAbsolute() {
|
||||
final int cores = 8;
|
||||
final int[] uids = {1, 22, 333, 4444, 5555};
|
||||
|
||||
@@ -128,7 +128,7 @@ public class KernelUidCpuActiveTimeReaderTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadDelta_malformedData() throws Exception {
|
||||
public void testReadDelta_malformedData() {
|
||||
final int cores = 8;
|
||||
final int[] uids = {1, 22, 333, 4444, 5555};
|
||||
final long[][] times = increaseTime(new long[uids.length][cores]);
|
||||
|
||||
@@ -21,7 +21,6 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -144,82 +143,6 @@ public class KernelUidCpuFreqTimeReaderTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadDelta() throws Exception {
|
||||
final long[] freqs = {1, 12, 123, 1234, 12345, 123456};
|
||||
final int[] uids = {1, 22, 333, 4444, 5555};
|
||||
final long[][] times = new long[uids.length][freqs.length];
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
for (int j = 0; j < freqs.length; ++j) {
|
||||
times[i][j] = uids[i] * freqs[j] * 10;
|
||||
}
|
||||
}
|
||||
when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs));
|
||||
long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mBufferedReader, mPowerProfile);
|
||||
|
||||
assertArrayEquals(freqs, actualFreqs);
|
||||
when(mBufferedReader.readLine())
|
||||
.thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, times));
|
||||
mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
Mockito.verify(mCallback).onUidCpuFreqTime(uids[i], times[i]);
|
||||
}
|
||||
verifyNoMoreInteractions(mCallback);
|
||||
|
||||
// Verify that a second call will only return deltas.
|
||||
Mockito.reset(mCallback, mBufferedReader);
|
||||
final long[][] newTimes1 = new long[uids.length][freqs.length];
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
for (int j = 0; j < freqs.length; ++j) {
|
||||
newTimes1[i][j] = (times[i][j] + uids[i] + freqs[j]) * 10;
|
||||
}
|
||||
}
|
||||
when(mBufferedReader.readLine())
|
||||
.thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1));
|
||||
mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
Mockito.verify(mCallback).onUidCpuFreqTime(uids[i], subtract(newTimes1[i], times[i]));
|
||||
}
|
||||
verifyNoMoreInteractions(mCallback);
|
||||
|
||||
// Verify that there won't be a callback if the proc file values didn't change.
|
||||
Mockito.reset(mCallback, mBufferedReader);
|
||||
when(mBufferedReader.readLine())
|
||||
.thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1));
|
||||
mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
|
||||
verifyNoMoreInteractions(mCallback);
|
||||
|
||||
// Verify that calling with a null callback doesn't result in any crashes
|
||||
Mockito.reset(mCallback, mBufferedReader);
|
||||
final long[][] newTimes2 = new long[uids.length][freqs.length];
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
for (int j = 0; j < freqs.length; ++j) {
|
||||
newTimes2[i][j] = (newTimes1[i][j] + uids[i] * freqs[j]) * 10;
|
||||
}
|
||||
}
|
||||
when(mBufferedReader.readLine())
|
||||
.thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes2));
|
||||
mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, null);
|
||||
|
||||
// Verify that the readDelta call will only return deltas when
|
||||
// the previous call had null callback.
|
||||
Mockito.reset(mCallback, mBufferedReader);
|
||||
final long[][] newTimes3 = new long[uids.length][freqs.length];
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
for (int j = 0; j < freqs.length; ++j) {
|
||||
newTimes3[i][j] = (newTimes2[i][j] * (uids[i] + freqs[j])) * 10;
|
||||
}
|
||||
}
|
||||
when(mBufferedReader.readLine())
|
||||
.thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes3));
|
||||
mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
Mockito.verify(mCallback).onUidCpuFreqTime(uids[i],
|
||||
subtract(newTimes3[i], newTimes2[i]));
|
||||
}
|
||||
verifyNoMoreInteractions(mCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadDelta_Binary() throws Exception {
|
||||
VerifiableCallback cb = new VerifiableCallback();
|
||||
@@ -236,7 +159,7 @@ public class KernelUidCpuFreqTimeReaderTest {
|
||||
|
||||
assertArrayEquals(freqs, actualFreqs);
|
||||
when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times));
|
||||
mKernelUidCpuFreqTimeReader.readDeltaBinary(cb);
|
||||
mKernelUidCpuFreqTimeReader.readDeltaImpl(cb);
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
cb.verify(uids[i], times[i]);
|
||||
}
|
||||
@@ -252,7 +175,7 @@ public class KernelUidCpuFreqTimeReaderTest {
|
||||
}
|
||||
}
|
||||
when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, newTimes1));
|
||||
mKernelUidCpuFreqTimeReader.readDeltaBinary(cb);
|
||||
mKernelUidCpuFreqTimeReader.readDeltaImpl(cb);
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
cb.verify(uids[i], subtract(newTimes1[i], times[i]));
|
||||
}
|
||||
@@ -262,7 +185,7 @@ public class KernelUidCpuFreqTimeReaderTest {
|
||||
cb.clear();
|
||||
Mockito.reset(mProcReader);
|
||||
when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, newTimes1));
|
||||
mKernelUidCpuFreqTimeReader.readDeltaBinary(cb);
|
||||
mKernelUidCpuFreqTimeReader.readDeltaImpl(cb);
|
||||
cb.verifyNoMoreInteractions();
|
||||
|
||||
// Verify that calling with a null callback doesn't result in any crashes
|
||||
@@ -275,7 +198,7 @@ public class KernelUidCpuFreqTimeReaderTest {
|
||||
}
|
||||
}
|
||||
when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, newTimes2));
|
||||
mKernelUidCpuFreqTimeReader.readDeltaBinary(null);
|
||||
mKernelUidCpuFreqTimeReader.readDeltaImpl(null);
|
||||
cb.verifyNoMoreInteractions();
|
||||
|
||||
// Verify that the readDelta call will only return deltas when
|
||||
@@ -289,7 +212,7 @@ public class KernelUidCpuFreqTimeReaderTest {
|
||||
}
|
||||
}
|
||||
when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, newTimes3));
|
||||
mKernelUidCpuFreqTimeReader.readDeltaBinary(cb);
|
||||
mKernelUidCpuFreqTimeReader.readDeltaImpl(cb);
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
cb.verify(uids[i], subtract(newTimes3[i], newTimes2[i]));
|
||||
}
|
||||
@@ -336,91 +259,6 @@ public class KernelUidCpuFreqTimeReaderTest {
|
||||
cb.verifyNoMoreInteractions();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadDelta_malformedData() throws Exception {
|
||||
final long[] freqs = {1, 12, 123, 1234, 12345, 123456};
|
||||
final int[] uids = {1, 22, 333, 4444, 5555};
|
||||
final long[][] times = new long[uids.length][freqs.length];
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
for (int j = 0; j < freqs.length; ++j) {
|
||||
times[i][j] = uids[i] * freqs[j] * 10;
|
||||
}
|
||||
}
|
||||
when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs));
|
||||
long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mBufferedReader, mPowerProfile);
|
||||
|
||||
assertArrayEquals(freqs, actualFreqs);
|
||||
when(mBufferedReader.readLine())
|
||||
.thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, times));
|
||||
mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
Mockito.verify(mCallback).onUidCpuFreqTime(uids[i], times[i]);
|
||||
}
|
||||
verifyNoMoreInteractions(mCallback);
|
||||
|
||||
// Verify that there is no callback if any value in the proc file is -ve.
|
||||
Mockito.reset(mCallback, mBufferedReader);
|
||||
final long[][] newTimes1 = new long[uids.length][freqs.length];
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
for (int j = 0; j < freqs.length; ++j) {
|
||||
newTimes1[i][j] = (times[i][j] + uids[i] + freqs[j]) * 10;
|
||||
}
|
||||
}
|
||||
newTimes1[uids.length - 1][freqs.length - 1] *= -1;
|
||||
when(mBufferedReader.readLine())
|
||||
.thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1));
|
||||
mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
if (i == uids.length - 1) {
|
||||
continue;
|
||||
}
|
||||
Mockito.verify(mCallback).onUidCpuFreqTime(uids[i], subtract(newTimes1[i], times[i]));
|
||||
}
|
||||
verifyNoMoreInteractions(mCallback);
|
||||
|
||||
// Verify that the internal state was not modified when the proc file had -ve value.
|
||||
Mockito.reset(mCallback, mBufferedReader);
|
||||
for (int i = 0; i < freqs.length; ++i) {
|
||||
newTimes1[uids.length - 1][i] = times[uids.length - 1][i];
|
||||
}
|
||||
when(mBufferedReader.readLine())
|
||||
.thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1));
|
||||
mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
|
||||
verifyNoMoreInteractions(mCallback);
|
||||
|
||||
// Verify that there is no callback if the values in the proc file are decreased.
|
||||
Mockito.reset(mCallback, mBufferedReader);
|
||||
final long[][] newTimes2 = new long[uids.length][freqs.length];
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
for (int j = 0; j < freqs.length; ++j) {
|
||||
newTimes2[i][j] = (newTimes1[i][j] + uids[i] * freqs[j]) * 10;
|
||||
}
|
||||
}
|
||||
newTimes2[uids.length - 1][freqs.length - 1] =
|
||||
newTimes1[uids.length - 1][freqs.length - 1] - 222;
|
||||
when(mBufferedReader.readLine())
|
||||
.thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes2));
|
||||
mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
if (i == uids.length - 1) {
|
||||
continue;
|
||||
}
|
||||
Mockito.verify(mCallback).onUidCpuFreqTime(uids[i],
|
||||
subtract(newTimes2[i], newTimes1[i]));
|
||||
}
|
||||
verifyNoMoreInteractions(mCallback);
|
||||
|
||||
// Verify that the internal state was not modified when the proc file had decreasing values.
|
||||
Mockito.reset(mCallback, mBufferedReader);
|
||||
for (int i = 0; i < freqs.length; ++i) {
|
||||
newTimes2[uids.length - 1][i] = newTimes1[uids.length - 1][i];
|
||||
}
|
||||
when(mBufferedReader.readLine())
|
||||
.thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes2));
|
||||
mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
|
||||
verifyNoMoreInteractions(mCallback);
|
||||
}
|
||||
|
||||
private long[] subtract(long[] a1, long[] a2) {
|
||||
long[] val = new long[a1.length];
|
||||
for (int i = 0; i < val.length; ++i) {
|
||||
@@ -438,21 +276,6 @@ public class KernelUidCpuFreqTimeReaderTest {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String[] getUidTimesLines(int[] uids, long[][] times) {
|
||||
final String[] lines = new String[uids.length + 1];
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < uids.length; ++i) {
|
||||
sb.setLength(0);
|
||||
sb.append(uids[i] + ":");
|
||||
for (int j = 0; j < times[i].length; ++j) {
|
||||
sb.append(" " + times[i][j] / 10);
|
||||
}
|
||||
lines[i] = sb.toString();
|
||||
}
|
||||
lines[uids.length] = null;
|
||||
return lines;
|
||||
}
|
||||
|
||||
private ByteBuffer getUidTimesBytes(int[] uids, long[][] times) {
|
||||
int size = (1 + uids.length + uids.length * times[0].length) * 4;
|
||||
ByteBuffer buf = ByteBuffer.allocate(size);
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.util.SparseIntArray;
|
||||
|
||||
import com.android.internal.location.gnssmetrics.GnssMetrics;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
@@ -66,6 +67,10 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
|
||||
return mScreenState;
|
||||
}
|
||||
|
||||
public Queue<UidToRemove> getPendingRemovedUids() {
|
||||
return mPendingRemovedUids;
|
||||
}
|
||||
|
||||
public boolean isOnBattery() {
|
||||
return mForceOnBattery ? true : super.isOnBattery();
|
||||
}
|
||||
|
||||
@@ -306,6 +306,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
|
||||
for (int uid : uidsToRemove) {
|
||||
mStats.removeIsolatedUidLocked(uid);
|
||||
}
|
||||
mStats.clearPendingRemovedUids();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1193,6 +1193,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
|
||||
pw.println(" --new-daily: immediately create and write new daily stats record.");
|
||||
pw.println(" --read-daily: read-load last written daily stats.");
|
||||
pw.println(" --settings: dump the settings key/values related to batterystats");
|
||||
pw.println(" --cpu: dump cpu stats for debugging purpose");
|
||||
pw.println(" <package.name>: optional name of package to filter output by.");
|
||||
pw.println(" -h: print this help text.");
|
||||
pw.println("Battery stats (batterystats) commands:");
|
||||
@@ -1211,6 +1212,12 @@ public final class BatteryStatsService extends IBatteryStats.Stub
|
||||
}
|
||||
}
|
||||
|
||||
private void dumpCpuStats(PrintWriter pw) {
|
||||
synchronized (mStats) {
|
||||
mStats.dumpCpuStatsLocked(pw);
|
||||
}
|
||||
}
|
||||
|
||||
private int doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable) {
|
||||
i++;
|
||||
if (i >= args.length) {
|
||||
@@ -1324,6 +1331,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub
|
||||
} else if ("--settings".equals(arg)) {
|
||||
dumpSettings(pw);
|
||||
return;
|
||||
} else if ("--cpu".equals(arg)) {
|
||||
dumpCpuStats(pw);
|
||||
return;
|
||||
} else if ("-a".equals(arg)) {
|
||||
flags |= BatteryStats.DUMP_VERBOSE;
|
||||
} else if (arg.length() > 0 && arg.charAt(0) == '-'){
|
||||
|
||||
@@ -177,7 +177,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
|
||||
// frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
|
||||
mKernelUidCpuFreqTimeReader.setThrottleInterval(0);
|
||||
long[] freqs = mKernelUidCpuFreqTimeReader.readFreqs(powerProfile);
|
||||
mKernelUidCpuFreqTimeReader.setReadBinary(true);
|
||||
mKernelUidCpuClusterTimeReader.setThrottleInterval(0);
|
||||
mKernelUidCpuActiveTimeReader.setThrottleInterval(0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user