summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java2
-rw-r--r--core/java/com/android/internal/os/KernelCpuThreadReader.java298
-rw-r--r--core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java79
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java17
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java125
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java2
6 files changed, 192 insertions, 331 deletions
diff --git a/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java b/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java
index 0c30302d63a3..1f261882b2d3 100644
--- a/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java
@@ -47,7 +47,7 @@ public class KernelCpuThreadReaderPerfTest {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
assertNotNull(mKernelCpuThreadReader);
while (state.keepRunning()) {
- this.mKernelCpuThreadReader.getCurrentProcessCpuUsage();
+ this.mKernelCpuThreadReader.getProcessCpuUsage();
}
}
}
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReader.java b/core/java/com/android/internal/os/KernelCpuThreadReader.java
index 248e0266b70b..e4de1586bc51 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReader.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReader.java
@@ -32,15 +32,18 @@ import java.util.ArrayList;
import java.util.function.Predicate;
/**
- * Given a process, will iterate over the child threads of the process, and return the CPU usage
- * statistics for each child thread. The CPU usage statistics contain the amount of time spent in a
- * frequency band.
+ * Iterates over processes, and all threads owned by those processes, and return the CPU usage for
+ * each thread. The CPU usage statistics contain the amount of time spent in a frequency band. CPU
+ * usage is collected using {@link ProcTimeInStateReader}.
+ *
+ * <p>We only collect CPU data for processes and threads that are owned by certain UIDs. These UIDs
+ * are configured via {@link #setUidPredicate}.
*
* <p>Frequencies are bucketed together to reduce the amount of data created. This means that we
- * return less frequencies than provided by {@link ProcTimeInStateReader}. The number of
- * frequencies is configurable by {@link #setNumBuckets}. Frequencies are reported as the lowest
- * frequency in that range. Frequencies are spread as evenly as possible across the buckets. The
- * buckets do not cross over the little/big frequencies reported.
+ * return less frequencies than provided by {@link ProcTimeInStateReader}. The number of frequencies
+ * is configurable by {@link #setNumBuckets}. Frequencies are reported as the lowest frequency in
+ * that range. Frequencies are spread as evenly as possible across the buckets. The buckets do not
+ * cross over the little/big frequencies reported.
*
* <p>N.B.: In order to bucket across little/big frequencies correctly, we assume that the {@code
* time_in_state} file contains every little core frequency in ascending order, followed by every
@@ -60,56 +63,39 @@ public class KernelCpuThreadReader {
private static final String CPU_STATISTICS_FILENAME = "time_in_state";
/**
- * The name of the file to read process command line invocation from, must be found in
- * {@code /proc/$PID/}
+ * The name of the file to read process command line invocation from, must be found in {@code
+ * /proc/$PID/}
*/
private static final String PROCESS_NAME_FILENAME = "cmdline";
/**
- * The name of the file to read thread name from, must be found in
- * {@code /proc/$PID/task/$TID}
+ * The name of the file to read thread name from, must be found in {@code /proc/$PID/task/$TID}
*/
private static final String THREAD_NAME_FILENAME = "comm";
- /**
- * Glob pattern for the process directory names under {@code proc}
- */
+ /** Glob pattern for the process directory names under {@code proc} */
private static final String PROCESS_DIRECTORY_FILTER = "[0-9]*";
- /**
- * Default process name when the name can't be read
- */
+ /** Default process name when the name can't be read */
private static final String DEFAULT_PROCESS_NAME = "unknown_process";
- /**
- * Default thread name when the name can't be read
- */
+ /** Default thread name when the name can't be read */
private static final String DEFAULT_THREAD_NAME = "unknown_thread";
- /**
- * Default mount location of the {@code proc} filesystem
- */
+ /** Default mount location of the {@code proc} filesystem */
private static final Path DEFAULT_PROC_PATH = Paths.get("/proc");
- /**
- * The initial {@code time_in_state} file for {@link ProcTimeInStateReader}
- */
+ /** The initial {@code time_in_state} file for {@link ProcTimeInStateReader} */
private static final Path DEFAULT_INITIAL_TIME_IN_STATE_PATH =
DEFAULT_PROC_PATH.resolve("self/time_in_state");
- /**
- * Value returned when there was an error getting an integer ID value (e.g. PID, UID)
- */
+ /** Value returned when there was an error getting an integer ID value (e.g. PID, UID) */
private static final int ID_ERROR = -1;
- /**
- * Thread ID used when reporting CPU used by other threads
- */
+ /** Thread ID used when reporting CPU used by other threads */
private static final int OTHER_THREADS_ID = -1;
- /**
- * Thread name used when reporting CPU used by other threads
- */
+ /** Thread name used when reporting CPU used by other threads */
private static final String OTHER_THREADS_NAME = "__OTHER_THREADS";
/**
@@ -124,9 +110,7 @@ public class KernelCpuThreadReader {
*/
private int mMinimumTotalCpuUsageMillis;
- /**
- * Where the proc filesystem is mounted
- */
+ /** Where the proc filesystem is mounted */
private final Path mProcPath;
/**
@@ -135,14 +119,10 @@ public class KernelCpuThreadReader {
*/
private int[] mFrequenciesKhz;
- /**
- * Used to read and parse {@code time_in_state} files
- */
+ /** Used to read and parse {@code time_in_state} files */
private final ProcTimeInStateReader mProcTimeInStateReader;
- /**
- * Used to sort frequencies and usage times into buckets
- */
+ /** Used to sort frequencies and usage times into buckets */
private FrequencyBucketCreator mFrequencyBucketCreator;
private final Injector mInjector;
@@ -150,10 +130,9 @@ public class KernelCpuThreadReader {
/**
* Create with a path where `proc` is mounted. Used primarily for testing
*
- * @param procPath where `proc` is mounted (to find, see {@code mount | grep
- * ^proc})
+ * @param procPath where `proc` is mounted (to find, see {@code mount | grep ^proc})
* @param initialTimeInStatePath where the initial {@code time_in_state} file exists to define
- * format
+ * format
*/
@VisibleForTesting
public KernelCpuThreadReader(
@@ -162,7 +141,8 @@ public class KernelCpuThreadReader {
int minimumTotalCpuUsageMillis,
Path procPath,
Path initialTimeInStatePath,
- Injector injector) throws IOException {
+ Injector injector)
+ throws IOException {
mUidPredicate = uidPredicate;
mMinimumTotalCpuUsageMillis = minimumTotalCpuUsageMillis;
mProcPath = procPath;
@@ -205,7 +185,7 @@ public class KernelCpuThreadReader {
* #setUidPredicate}.
*/
@Nullable
- public ArrayList<ProcessCpuUsage> getProcessCpuUsageByUids() {
+ public ArrayList<ProcessCpuUsage> getProcessCpuUsage() {
if (DEBUG) {
Slog.d(TAG, "Reading CPU thread usages for processes owned by UIDs");
}
@@ -213,7 +193,7 @@ public class KernelCpuThreadReader {
final ArrayList<ProcessCpuUsage> processCpuUsages = new ArrayList<>();
try (DirectoryStream<Path> processPaths =
- Files.newDirectoryStream(mProcPath, PROCESS_DIRECTORY_FILTER)) {
+ Files.newDirectoryStream(mProcPath, PROCESS_DIRECTORY_FILTER)) {
for (Path processPath : processPaths) {
final int processId = getProcessId(processPath);
final int uid = mInjector.getUidForPid(processId);
@@ -231,7 +211,7 @@ public class KernelCpuThreadReader {
}
}
} catch (IOException e) {
- Slog.w("Failed to iterate over process paths", e);
+ Slog.w(TAG, "Failed to iterate over process paths", e);
return null;
}
@@ -248,30 +228,68 @@ public class KernelCpuThreadReader {
}
/**
- * Read all of the CPU usage statistics for each child thread of the current process
- *
- * @return process CPU usage containing usage of all child threads
+ * Get the CPU frequencies that correspond to the times reported in {@link
+ * ThreadCpuUsage#usageTimesMillis}
*/
@Nullable
- public ProcessCpuUsage getCurrentProcessCpuUsage() {
- return getProcessCpuUsage(mProcPath.resolve("self"), mInjector.myPid(), mInjector.myUid());
+ public int[] getCpuFrequenciesKhz() {
+ return mFrequenciesKhz;
+ }
+
+ /** Set the number of frequency buckets to use */
+ void setNumBuckets(int numBuckets) {
+ if (numBuckets < 1) {
+ Slog.w(TAG, "Number of buckets must be at least 1, but was " + numBuckets);
+ return;
+ }
+ // If `numBuckets` hasn't changed since the last set, do nothing
+ if (mFrequenciesKhz != null && mFrequenciesKhz.length == numBuckets) {
+ return;
+ }
+ mFrequencyBucketCreator =
+ new FrequencyBucketCreator(mProcTimeInStateReader.getFrequenciesKhz(), numBuckets);
+ mFrequenciesKhz =
+ mFrequencyBucketCreator.getBucketMinFrequencies(
+ mProcTimeInStateReader.getFrequenciesKhz());
+ }
+
+ /** Set the UID predicate for {@link #getProcessCpuUsage} */
+ void setUidPredicate(Predicate<Integer> uidPredicate) {
+ mUidPredicate = uidPredicate;
+ }
+
+ /**
+ * If a thread has strictly less than {@code minimumTotalCpuUsageMillis} total CPU usage, it
+ * will not be reported
+ */
+ void setMinimumTotalCpuUsageMillis(int minimumTotalCpuUsageMillis) {
+ if (minimumTotalCpuUsageMillis < 0) {
+ Slog.w(TAG, "Negative minimumTotalCpuUsageMillis: " + minimumTotalCpuUsageMillis);
+ return;
+ }
+ mMinimumTotalCpuUsageMillis = minimumTotalCpuUsageMillis;
}
/**
* Read all of the CPU usage statistics for each child thread of a process
*
* @param processPath the {@code /proc} path of the thread
- * @param processId the ID of the process
- * @param uid the ID of the user who owns the process
+ * @param processId the ID of the process
+ * @param uid the ID of the user who owns the process
* @return process CPU usage containing usage of all child threads. Null if the process exited
- * and its {@code proc} directory was removed while collecting information
+ * and its {@code proc} directory was removed while collecting information
*/
@Nullable
private ProcessCpuUsage getProcessCpuUsage(Path processPath, int processId, int uid) {
if (DEBUG) {
- Slog.d(TAG, "Reading CPU thread usages with directory " + processPath
- + " process ID " + processId
- + " and user ID " + uid);
+ Slog.d(
+ TAG,
+ "Reading CPU thread usages with directory "
+ + processPath
+ + " process ID "
+ + processId
+ + " and user ID "
+ + uid);
}
int[] filteredThreadsCpuUsage = null;
@@ -305,64 +323,15 @@ public class KernelCpuThreadReader {
// Add the filtered out thread CPU usage under an "other threads" ThreadCpuUsage
if (filteredThreadsCpuUsage != null) {
- threadCpuUsages.add(new ThreadCpuUsage(
- OTHER_THREADS_ID, OTHER_THREADS_NAME, filteredThreadsCpuUsage));
+ threadCpuUsages.add(
+ new ThreadCpuUsage(
+ OTHER_THREADS_ID, OTHER_THREADS_NAME, filteredThreadsCpuUsage));
}
if (DEBUG) {
Slog.d(TAG, "Read CPU usage of " + threadCpuUsages.size() + " threads");
}
- return new ProcessCpuUsage(
- processId,
- getProcessName(processPath),
- uid,
- threadCpuUsages);
- }
-
- /**
- * Set the number of frequency buckets to use
- */
- void setNumBuckets(int numBuckets) {
- if (numBuckets < 1) {
- Slog.w(TAG, "Number of buckets must be at least 1, but was " + numBuckets);
- return;
- }
- // If `numBuckets` hasn't changed since the last set, do nothing
- if (mFrequenciesKhz != null && mFrequenciesKhz.length == numBuckets) {
- return;
- }
- mFrequencyBucketCreator = new FrequencyBucketCreator(
- mProcTimeInStateReader.getFrequenciesKhz(), numBuckets);
- mFrequenciesKhz = mFrequencyBucketCreator.getBucketMinFrequencies(
- mProcTimeInStateReader.getFrequenciesKhz());
- }
-
- /**
- * Set the UID predicate for {@link #getProcessCpuUsageByUids}
- */
- void setUidPredicate(Predicate<Integer> uidPredicate) {
- mUidPredicate = uidPredicate;
- }
-
- /**
- * If a thread has strictly less than {@code minimumTotalCpuUsageMillis} total CPU usage, it
- * will not be reported
- */
- void setMinimumTotalCpuUsageMillis(int minimumTotalCpuUsageMillis) {
- if (minimumTotalCpuUsageMillis < 0) {
- Slog.w(TAG, "Negative minimumTotalCpuUsageMillis: " + minimumTotalCpuUsageMillis);
- return;
- }
- mMinimumTotalCpuUsageMillis = minimumTotalCpuUsageMillis;
- }
-
- /**
- * Get the CPU frequencies that correspond to the times reported in
- * {@link ThreadCpuUsage#usageTimesMillis}
- */
- @Nullable
- public int[] getCpuFrequenciesKhz() {
- return mFrequenciesKhz;
+ return new ProcessCpuUsage(processId, getProcessName(processPath), uid, threadCpuUsages);
}
/**
@@ -370,7 +339,7 @@ public class KernelCpuThreadReader {
*
* @param threadDirectory the {@code /proc} directory of the thread
* @return thread CPU usage. Null if the thread exited and its {@code proc} directory was
- * removed while collecting information
+ * removed while collecting information
*/
@Nullable
private ThreadCpuUsage getThreadCpuUsage(Path threadDirectory) {
@@ -398,27 +367,21 @@ public class KernelCpuThreadReader {
return new ThreadCpuUsage(threadId, threadName, cpuUsages);
}
- /**
- * Get the command used to start a process
- */
+ /** Get the command used to start a process */
private String getProcessName(Path processPath) {
final Path processNamePath = processPath.resolve(PROCESS_NAME_FILENAME);
- final String processName =
- ProcStatsUtil.readSingleLineProcFile(processNamePath.toString());
+ final String processName = ProcStatsUtil.readSingleLineProcFile(processNamePath.toString());
if (processName != null) {
return processName;
}
return DEFAULT_PROCESS_NAME;
}
- /**
- * Get the name of a thread, given the {@code /proc} path of the thread
- */
+ /** Get the name of a thread, given the {@code /proc} path of the thread */
private String getThreadName(Path threadPath) {
final Path threadNamePath = threadPath.resolve(THREAD_NAME_FILENAME);
- final String threadName =
- ProcStatsUtil.readNullSeparatedFile(threadNamePath.toString());
+ final String threadName = ProcStatsUtil.readNullSeparatedFile(threadNamePath.toString());
if (threadName == null) {
return DEFAULT_THREAD_NAME;
}
@@ -441,9 +404,8 @@ public class KernelCpuThreadReader {
}
}
- /**
- * Get the sum of all CPU usage across all frequencies
- */
+ /** Get the sum of all CPU usage across all frequencies */
+ @SuppressWarnings("ForLoopReplaceableByForEach")
private static int totalCpuUsage(int[] cpuUsage) {
int total = 0;
for (int i = 0; i < cpuUsage.length; i++) {
@@ -452,9 +414,7 @@ public class KernelCpuThreadReader {
return total;
}
- /**
- * Add two CPU frequency usages together
- */
+ /** Add two CPU frequency usages together */
private static int[] sumCpuUsage(int[] a, int[] b) {
int[] summed = new int[a.length];
for (int i = 0; i < a.length; i++) {
@@ -463,9 +423,7 @@ public class KernelCpuThreadReader {
return summed;
}
- /**
- * Puts frequencies and usage times into buckets
- */
+ /** Puts frequencies and usage times into buckets */
@VisibleForTesting
public static class FrequencyBucketCreator {
private final int mNumBuckets;
@@ -480,7 +438,7 @@ public class KernelCpuThreadReader {
* Buckets based of a list of frequencies
*
* @param frequencies the frequencies to base buckets off
- * @param numBuckets how many buckets to create
+ * @param numBuckets how many buckets to create
*/
@VisibleForTesting
public FrequencyBucketCreator(long[] frequencies, int numBuckets) {
@@ -502,20 +460,20 @@ public class KernelCpuThreadReader {
// Ensure that we don't have more buckets than frequencies
mLittleNumBuckets = Math.min(littleNumBuckets, mBigFrequenciesStartIndex);
- mBigNumBuckets = Math.min(
- bigNumBuckets, frequencies.length - mBigFrequenciesStartIndex);
+ mBigNumBuckets =
+ Math.min(bigNumBuckets, frequencies.length - mBigFrequenciesStartIndex);
mNumBuckets = mLittleNumBuckets + mBigNumBuckets;
// Set the size of each little and big bucket. If they have no buckets, the size is zero
- mLittleBucketSize = mLittleNumBuckets == 0 ? 0 :
- mBigFrequenciesStartIndex / mLittleNumBuckets;
- mBigBucketSize = mBigNumBuckets == 0 ? 0 :
- (frequencies.length - mBigFrequenciesStartIndex) / mBigNumBuckets;
+ mLittleBucketSize =
+ mLittleNumBuckets == 0 ? 0 : mBigFrequenciesStartIndex / mLittleNumBuckets;
+ mBigBucketSize =
+ mBigNumBuckets == 0
+ ? 0
+ : (frequencies.length - mBigFrequenciesStartIndex) / mBigNumBuckets;
}
- /**
- * Find the index where frequencies change from little core to big core
- */
+ /** Find the index where frequencies change from little core to big core */
@VisibleForTesting
public static int getBigFrequenciesStartIndex(long[] frequenciesKhz) {
for (int i = 0; i < frequenciesKhz.length - 1; i++) {
@@ -527,16 +485,14 @@ public class KernelCpuThreadReader {
return frequenciesKhz.length;
}
- /**
- * Get the minimum frequency in each bucket
- */
+ /** Get the minimum frequency in each bucket */
@VisibleForTesting
public int[] getBucketMinFrequencies(long[] frequenciesKhz) {
Preconditions.checkArgument(frequenciesKhz.length == mNumFrequencies);
// If there's only one bucket, we bucket everything together so the first bucket is the
// min frequency
if (mNumBuckets == 1) {
- return new int[]{(int) frequenciesKhz[0]};
+ return new int[] {(int) frequenciesKhz[0]};
}
final int[] bucketMinFrequencies = new int[mNumBuckets];
@@ -561,6 +517,7 @@ public class KernelCpuThreadReader {
* @return the bucketed usage times
*/
@VisibleForTesting
+ @SuppressWarnings("ForLoopReplaceableByForEach")
public int[] getBucketedValues(long[] values) {
Preconditions.checkArgument(values.length == mNumFrequencies);
final int[] bucketed = new int[mNumBuckets];
@@ -580,18 +537,18 @@ public class KernelCpuThreadReader {
}
// Initialize the big buckets
for (int i = mBigFrequenciesStartIndex; i < values.length; i++) {
- final int bucketIndex = Math.min(
- mLittleNumBuckets + (i - mBigFrequenciesStartIndex) / mBigBucketSize,
- mNumBuckets - 1);
+ final int bucketIndex =
+ Math.min(
+ mLittleNumBuckets
+ + (i - mBigFrequenciesStartIndex) / mBigBucketSize,
+ mNumBuckets - 1);
bucketed[bucketIndex] += values[i];
}
return bucketed;
}
}
- /**
- * CPU usage of a process
- */
+ /** CPU usage of a process */
public static class ProcessCpuUsage {
public final int processId;
public final String processName;
@@ -610,46 +567,23 @@ public class KernelCpuThreadReader {
}
}
- /**
- * CPU usage of a thread
- */
+ /** CPU usage of a thread */
public static class ThreadCpuUsage {
public final int threadId;
public final String threadName;
public final int[] usageTimesMillis;
- ThreadCpuUsage(
- int threadId,
- String threadName,
- int[] usageTimesMillis) {
+ ThreadCpuUsage(int threadId, String threadName, int[] usageTimesMillis) {
this.threadId = threadId;
this.threadName = threadName;
this.usageTimesMillis = usageTimesMillis;
}
}
- /**
- * Used to inject static methods from {@link Process}
- */
+ /** Used to inject static methods from {@link Process} */
@VisibleForTesting
public static class Injector {
- /**
- * Get the PID of the current process
- */
- public int myPid() {
- return Process.myPid();
- }
-
- /**
- * Get the UID that owns the current process
- */
- public int myUid() {
- return Process.myUid();
- }
-
- /**
- * Get the UID for the process with ID {@code pid}
- */
+ /** Get the UID for the process with ID {@code pid} */
public int getUidForPid(int pid) {
return Process.getUidForPid(pid);
}
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java b/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
index b8dfe0d63a66..3851ce6d9cbd 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
@@ -47,33 +47,29 @@ import java.util.regex.Pattern;
public class KernelCpuThreadReaderSettingsObserver extends ContentObserver {
private static final String TAG = "KernelCpuThreadReaderSettingsObserver";
- /**
- * The number of frequency buckets to report
- */
+ /** The number of frequency buckets to report */
private static final String NUM_BUCKETS_SETTINGS_KEY = "num_buckets";
+
private static final int NUM_BUCKETS_DEFAULT = 8;
- /**
- * List of UIDs to report data for
- */
+ /** List of UIDs to report data for */
private static final String COLLECTED_UIDS_SETTINGS_KEY = "collected_uids";
+
private static final String COLLECTED_UIDS_DEFAULT = "0-0;1000-1000";
- /**
- * Minimum total CPU usage to report
- */
+ /** Minimum total CPU usage to report */
private static final String MINIMUM_TOTAL_CPU_USAGE_MILLIS_SETTINGS_KEY =
"minimum_total_cpu_usage_millis";
+
private static final int MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT = 10000;
private final Context mContext;
- @Nullable
- private final KernelCpuThreadReader mKernelCpuThreadReader;
+ @Nullable private final KernelCpuThreadReader mKernelCpuThreadReader;
/**
- * @return returns a created {@link KernelCpuThreadReader} that will be modified by any
- * change in settings, returns null if creation failed
+ * @return returns a created {@link KernelCpuThreadReader} that will be modified by any change
+ * in settings, returns null if creation failed
*/
@Nullable
public static KernelCpuThreadReader getSettingsModifiedReader(Context context) {
@@ -81,10 +77,10 @@ public class KernelCpuThreadReaderSettingsObserver extends ContentObserver {
KernelCpuThreadReaderSettingsObserver settingsObserver =
new KernelCpuThreadReaderSettingsObserver(context);
// Register the observer to listen for setting changes
- Uri settingsUri =
- Settings.Global.getUriFor(Settings.Global.KERNEL_CPU_THREAD_READER);
- context.getContentResolver().registerContentObserver(
- settingsUri, false, settingsObserver, UserHandle.USER_SYSTEM);
+ Uri settingsUri = Settings.Global.getUriFor(Settings.Global.KERNEL_CPU_THREAD_READER);
+ context.getContentResolver()
+ .registerContentObserver(
+ settingsUri, false, settingsObserver, UserHandle.USER_SYSTEM);
// Return the observer's reader
return settingsObserver.mKernelCpuThreadReader;
}
@@ -92,10 +88,11 @@ public class KernelCpuThreadReaderSettingsObserver extends ContentObserver {
private KernelCpuThreadReaderSettingsObserver(Context context) {
super(BackgroundThread.getHandler());
mContext = context;
- mKernelCpuThreadReader = KernelCpuThreadReader.create(
- NUM_BUCKETS_DEFAULT,
- UidPredicate.fromString(COLLECTED_UIDS_DEFAULT),
- MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT);
+ mKernelCpuThreadReader =
+ KernelCpuThreadReader.create(
+ NUM_BUCKETS_DEFAULT,
+ UidPredicate.fromString(COLLECTED_UIDS_DEFAULT),
+ MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT);
}
@Override
@@ -103,9 +100,7 @@ public class KernelCpuThreadReaderSettingsObserver extends ContentObserver {
updateReader();
}
- /**
- * Update the reader with new settings
- */
+ /** Update the reader with new settings */
private void updateReader() {
if (mKernelCpuThreadReader == null) {
return;
@@ -113,8 +108,10 @@ public class KernelCpuThreadReaderSettingsObserver extends ContentObserver {
final KeyValueListParser parser = new KeyValueListParser(',');
try {
- parser.setString(Settings.Global.getString(
- mContext.getContentResolver(), Settings.Global.KERNEL_CPU_THREAD_READER));
+ parser.setString(
+ Settings.Global.getString(
+ mContext.getContentResolver(),
+ Settings.Global.KERNEL_CPU_THREAD_READER));
} catch (IllegalArgumentException e) {
Slog.e(TAG, "Bad settings", e);
return;
@@ -122,8 +119,9 @@ public class KernelCpuThreadReaderSettingsObserver extends ContentObserver {
final UidPredicate uidPredicate;
try {
- uidPredicate = UidPredicate.fromString(
- parser.getString(COLLECTED_UIDS_SETTINGS_KEY, COLLECTED_UIDS_DEFAULT));
+ uidPredicate =
+ UidPredicate.fromString(
+ parser.getString(COLLECTED_UIDS_SETTINGS_KEY, COLLECTED_UIDS_DEFAULT));
} catch (NumberFormatException e) {
Slog.w(TAG, "Failed to get UID predicate", e);
return;
@@ -132,14 +130,13 @@ public class KernelCpuThreadReaderSettingsObserver extends ContentObserver {
mKernelCpuThreadReader.setNumBuckets(
parser.getInt(NUM_BUCKETS_SETTINGS_KEY, NUM_BUCKETS_DEFAULT));
mKernelCpuThreadReader.setUidPredicate(uidPredicate);
- mKernelCpuThreadReader.setMinimumTotalCpuUsageMillis(parser.getInt(
- MINIMUM_TOTAL_CPU_USAGE_MILLIS_SETTINGS_KEY,
- MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT));
+ mKernelCpuThreadReader.setMinimumTotalCpuUsageMillis(
+ parser.getInt(
+ MINIMUM_TOTAL_CPU_USAGE_MILLIS_SETTINGS_KEY,
+ MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT));
}
- /**
- * Check whether a UID belongs to a set of UIDs
- */
+ /** Check whether a UID belongs to a set of UIDs */
@VisibleForTesting
public static class UidPredicate implements Predicate<Integer> {
private static final Pattern UID_RANGE_PATTERN = Pattern.compile("([0-9]+)-([0-9]+)");
@@ -150,14 +147,14 @@ public class KernelCpuThreadReaderSettingsObserver extends ContentObserver {
* Create a UID predicate from a string representing a list of UID ranges
*
* <p>UID ranges are a pair of integers separated by a '-'. If you want to specify a single
- * UID (e.g. UID 1000), you can use {@code 1000-1000}. Lists of ranges are separated by
- * a single ';'. For example, this would be a valid string representation: {@code
+ * UID (e.g. UID 1000), you can use {@code 1000-1000}. Lists of ranges are separated by a
+ * single ';'. For example, this would be a valid string representation: {@code
* "1000-1999;2003-2003;2004-2004;2050-2060"}.
*
* <p>We do not use ',' to delimit as it is already used in separating different setting
* arguments.
*
- * @throws NumberFormatException if the input string is incorrectly formatted
+ * @throws NumberFormatException if the input string is incorrectly formatted
* @throws IllegalArgumentException if an UID range has a lower end than start
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
@@ -169,9 +166,10 @@ public class KernelCpuThreadReaderSettingsObserver extends ContentObserver {
throw new NumberFormatException(
"Failed to recognize as number range: " + uidSpecifier);
}
- acceptedUidRanges.add(Range.create(
- Integer.parseInt(uidRangeMatcher.group(1)),
- Integer.parseInt(uidRangeMatcher.group(2))));
+ acceptedUidRanges.add(
+ Range.create(
+ Integer.parseInt(uidRangeMatcher.group(1)),
+ Integer.parseInt(uidRangeMatcher.group(2))));
}
return new UidPredicate(acceptedUidRanges);
}
@@ -181,6 +179,7 @@ public class KernelCpuThreadReaderSettingsObserver extends ContentObserver {
}
@Override
+ @SuppressWarnings("ForLoopReplaceableByForEach")
public boolean test(Integer uid) {
for (int i = 0; i < mAcceptedUidRanges.size(); i++) {
if (mAcceptedUidRanges.get(i).contains(uid)) {
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
index 1c84829c5491..e9cad0acfcc6 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
@@ -35,6 +35,7 @@ import org.junit.runner.RunWith;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
+import java.util.Optional;
import java.util.OptionalDouble;
import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer;
@@ -126,17 +127,21 @@ public class KernelCpuThreadReaderEndToEndTest {
final KernelCpuThreadReader kernelCpuThreadReader =
KernelCpuThreadReader.create(8, uid -> uid == Process.myUid(), 0);
assertNotNull(kernelCpuThreadReader);
- final ProcessCpuUsage currentProcessCpuUsage =
- kernelCpuThreadReader.getCurrentProcessCpuUsage();
+ kernelCpuThreadReader.setUidPredicate(uid -> uid == Process.myUid());
+ final Optional<ProcessCpuUsage> currentProcessCpuUsage =
+ kernelCpuThreadReader.getProcessCpuUsage().stream()
+ .filter(p -> p.processId == Process.myPid())
+ .findFirst();
+ assertTrue(currentProcessCpuUsage.isPresent());
// Threads can terminate, as we've finished crawling them from /proc
threadFinishedLatch.countDown();
// Check that we've got times for every thread we spawned
- final List<ThreadCpuUsage> threadCpuUsages = currentProcessCpuUsage.threadCpuUsages
- .stream()
- .filter((thread) -> thread.threadName.startsWith(tag))
- .collect(Collectors.toList());
+ final List<ThreadCpuUsage> threadCpuUsages =
+ currentProcessCpuUsage.get().threadCpuUsages.stream()
+ .filter((thread) -> thread.threadName.startsWith(tag))
+ .collect(Collectors.toList());
assertEquals(
"Incorrect number of threads returned by KernelCpuThreadReader",
numSamples, threadCpuUsages.size());
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
index e6e7a85ae16e..61209e21dda8 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
@@ -25,6 +25,7 @@ import static org.testng.Assert.assertThrows;
import android.content.Context;
import android.os.FileUtils;
+import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -44,27 +45,10 @@ import java.util.ArrayList;
import java.util.Comparator;
import java.util.function.Predicate;
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class KernelCpuThreadReaderTest {
-
- private static final int UID = 1000;
- private static final int PROCESS_ID = 1234;
- private static final int[] THREAD_IDS = {0, 1000, 1235, 4321};
- private static final String PROCESS_NAME = "test_process";
- private static final String[] THREAD_NAMES = {
- "test_thread_1", "test_thread_2", "test_thread_3", "test_thread_4"
- };
- private static final int[] THREAD_CPU_FREQUENCIES = {
- 1000, 2000, 3000, 4000,
- };
- private static final int[][] THREAD_CPU_TIMES = {
- {1, 0, 0, 1},
- {0, 0, 0, 0},
- {1000, 1000, 1000, 1000},
- {0, 1, 2, 3},
- };
-
private File mProcDirectory;
@Before
@@ -79,41 +63,6 @@ public class KernelCpuThreadReaderTest {
}
@Test
- public void testReader_currentProcess() throws IOException {
- KernelCpuThreadReader.Injector processUtils =
- new KernelCpuThreadReader.Injector() {
- @Override
- public int myPid() {
- return PROCESS_ID;
- }
-
- @Override
- public int myUid() {
- return UID;
- }
-
- @Override
- public int getUidForPid(int pid) {
- return 0;
- }
- };
- setupDirectory(mProcDirectory.toPath().resolve("self"), THREAD_IDS, PROCESS_NAME,
- THREAD_NAMES, THREAD_CPU_FREQUENCIES, THREAD_CPU_TIMES);
-
- final KernelCpuThreadReader kernelCpuThreadReader = new KernelCpuThreadReader(
- 8,
- uid -> 1000 <= uid && uid < 2000,
- 0,
- mProcDirectory.toPath(),
- mProcDirectory.toPath().resolve("self/task/" + THREAD_IDS[0] + "/time_in_state"),
- processUtils);
- final KernelCpuThreadReader.ProcessCpuUsage processCpuUsage =
- kernelCpuThreadReader.getCurrentProcessCpuUsage();
- checkResults(processCpuUsage, kernelCpuThreadReader.getCpuFrequenciesKhz(), UID, PROCESS_ID,
- THREAD_IDS, PROCESS_NAME, THREAD_NAMES, THREAD_CPU_FREQUENCIES, THREAD_CPU_TIMES);
- }
-
- @Test
public void testReader_byUids() throws IOException {
int[] uids = new int[]{0, 2, 3, 4, 5, 6000};
Predicate<Integer> uidPredicate = uid -> uid == 0 || uid >= 4;
@@ -121,16 +70,6 @@ public class KernelCpuThreadReaderTest {
KernelCpuThreadReader.Injector processUtils =
new KernelCpuThreadReader.Injector() {
@Override
- public int myPid() {
- return 0;
- }
-
- @Override
- public int myUid() {
- return 0;
- }
-
- @Override
public int getUidForPid(int pid) {
return pid;
}
@@ -150,7 +89,7 @@ public class KernelCpuThreadReaderTest {
mProcDirectory.toPath().resolve(uids[0] + "/task/" + uids[0] + "/time_in_state"),
processUtils);
ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsageByUids =
- kernelCpuThreadReader.getProcessCpuUsageByUids();
+ kernelCpuThreadReader.getProcessCpuUsage();
processCpuUsageByUids.sort(Comparator.comparing(usage -> usage.processId));
assertEquals(expectedUids.length, processCpuUsageByUids.size());
@@ -173,16 +112,6 @@ public class KernelCpuThreadReaderTest {
KernelCpuThreadReader.Injector processUtils =
new KernelCpuThreadReader.Injector() {
@Override
- public int myPid() {
- return 0;
- }
-
- @Override
- public int myUid() {
- return 0;
- }
-
- @Override
public int getUidForPid(int pid) {
return pid;
}
@@ -206,7 +135,7 @@ public class KernelCpuThreadReaderTest {
mProcDirectory.toPath().resolve(uids[0] + "/task/" + uids[0] + "/time_in_state"),
processUtils);
ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsageByUids =
- kernelCpuThreadReader.getProcessCpuUsageByUids();
+ kernelCpuThreadReader.getProcessCpuUsage();
processCpuUsageByUids.sort(Comparator.comparing(usage -> usage.uid));
assertEquals(expectedUids.length, processCpuUsageByUids.size());
@@ -220,7 +149,7 @@ public class KernelCpuThreadReaderTest {
@Test
public void testReader_otherThreads() throws IOException {
- final Path processPath = mProcDirectory.toPath().resolve("self");
+ final Path processPath = mProcDirectory.toPath().resolve("1000");
setupDirectory(
processPath,
new int[]{1, 2, 3},
@@ -228,39 +157,34 @@ public class KernelCpuThreadReaderTest {
new String[]{"thread1", "thread2", "thread3"},
new int[]{1000, 2000},
new int[][]{{0, 100}, {10, 0}, {0, 300}});
- final KernelCpuThreadReader kernelCpuThreadReader = new KernelCpuThreadReader(
- 8,
- i -> true,
- 2000,
- mProcDirectory.toPath(),
- processPath.resolve("task/1/time_in_state"),
+ KernelCpuThreadReader.Injector injector =
new KernelCpuThreadReader.Injector() {
@Override
- public int myPid() {
- return 1000;
- }
-
- @Override
- public int myUid() {
- return 0;
- }
-
- @Override
public int getUidForPid(int pid) {
return 0;
}
- });
+ };
+ final KernelCpuThreadReader kernelCpuThreadReader =
+ new KernelCpuThreadReader(
+ 8,
+ uid -> true,
+ 2000,
+ mProcDirectory.toPath(),
+ processPath.resolve("task/1/time_in_state"),
+ injector);
+ ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsages =
+ kernelCpuThreadReader.getProcessCpuUsage();
+ assertEquals(1, processCpuUsages.size());
checkResults(
- kernelCpuThreadReader.getCurrentProcessCpuUsage(),
+ processCpuUsages.get(0),
kernelCpuThreadReader.getCpuFrequenciesKhz(),
0,
1000,
- new int[]{-1, 3},
+ new int[] {-1, 3},
"process",
- new String[]{"__OTHER_THREADS", "thread3"},
- new int[]{1000, 2000},
- new int[][]{{100, 1000}, {0, 3000}}
- );
+ new String[] {"__OTHER_THREADS", "thread3"},
+ new int[] {1000, 2000},
+ new int[][] {{10, 100}, {0, 300}});
}
private void setupDirectory(Path processPath, int[] threadIds, String processName,
@@ -289,8 +213,7 @@ public class KernelCpuThreadReaderTest {
final OutputStream timeInStateStream =
Files.newOutputStream(threadPath.resolve("time_in_state"));
for (int j = 0; j < cpuFrequencies.length; j++) {
- final String line = String.valueOf(cpuFrequencies[j]) + " "
- + String.valueOf(cpuTimes[i][j]) + "\n";
+ final String line = cpuFrequencies[j] + " " + cpuTimes[i][j] + "\n";
timeInStateStream.write(line.getBytes());
}
timeInStateStream.close();
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 2b17d19e1cf7..9f1eace32180 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -1721,7 +1721,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
throw new IllegalStateException("mKernelCpuThreadReader is null");
}
ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsages =
- this.mKernelCpuThreadReader.getProcessCpuUsageByUids();
+ this.mKernelCpuThreadReader.getProcessCpuUsage();
if (processCpuUsages == null) {
throw new IllegalStateException("processCpuUsages is null");
}