OboeTester: Add CPU info to device report
diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/DeviceReportActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/DeviceReportActivity.java index 44f0da0..5a1e8a4 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/DeviceReportActivity.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/DeviceReportActivity.java
@@ -41,12 +41,19 @@ import com.mobileer.audio_device.AudioDeviceInfoConverter; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.TreeMap; /** * Print a report of all the available audio devices. @@ -151,6 +158,7 @@ report.append(reportUsbDevices()); report.append(reportMidiDevices()); report.append(reportMediaCodecs()); + report.append(CpuInfoReader.reportCpuInfo()); log(report.toString()); } @@ -308,6 +316,118 @@ return report.toString(); } + public static class CpuInfoReader { + + private static final String CPU_CAPACITY_PATH_FORMAT = "/sys/devices/system/cpu/cpu%d/cpu_capacity"; + private static final String CPU_MIN_FREQ_PATH_FORMAT = "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq"; + private static final String CPU_MAX_FREQ_PATH_FORMAT = "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq"; + private static final String CPU_CURRENT_FREQ_PATH_FORMAT = "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq"; + + // Inner class to hold all the details for a single CPU core + private static class CoreDetails { + int index; + int capacity = -1; // -1 indicates not found + int minFreq = -1; + int maxFreq = -1; + int currentFreq = -1; + + CoreDetails(int index) { + this.index = index; + } + + @Override + public String toString() { + // Format frequencies from Hz to KHz for readability + String min = minFreq != -1 ? String.valueOf(minFreq / 1000) : "N/A"; + String max = maxFreq != -1 ? String.valueOf(maxFreq / 1000) : "N/A"; + String cur = currentFreq != -1 ? String.valueOf(currentFreq / 1000) : "N/A"; + String cap = capacity != -1 ? String.valueOf(capacity) : "N/A"; + + return String.format("Idx %d Cap %s | Freq(KHz): Mn %s Mx %s Cur %s", + index, cap, min, max, cur); + } + } + + /** + * Reads a single integer value from a specified sysfs path. + * Returns -1 if the file doesn't exist, can't be read, or contains invalid data. + */ + private static int readSysfsInt(String path) { + File file = new File(path); + if (!file.exists()) { + return -1; // File not found + } + try (BufferedReader br = new BufferedReader(new FileReader(file))) { + String line = br.readLine(); + if (line != null) { + return Integer.parseInt(line.trim()); + } + } catch (IOException | NumberFormatException e) { + // Log.e(TAG, "Error reading " + path, e); // Use Android's Log if in an Android context + System.err.println("Error reading or parsing " + path + ": " + e.getMessage()); + } + return -1; // Error or invalid data + } + + /** + * Gathers detailed CPU core information and formats it into a string. + * This method requires appropriate file system permissions to access /sys paths. + * + * @return A neatly formatted string containing CPU core details, or an error message. + */ + public static String reportCpuInfo() { + Map<Integer, CoreDetails> cpuDetailsMap = new TreeMap<>(); // Use TreeMap to keep cores sorted by index + + int cpuIndex = 0; + boolean foundAnyCore = false; + + while (true) { + String capacityPath = String.format(CPU_CAPACITY_PATH_FORMAT, cpuIndex); + String minFreqPath = String.format(CPU_MIN_FREQ_PATH_FORMAT, cpuIndex); + String maxFreqPath = String.format(CPU_MAX_FREQ_PATH_FORMAT, cpuIndex); + String curFreqPath = String.format(CPU_CURRENT_FREQ_PATH_FORMAT, cpuIndex); + + // Check if at least one common file exists for this CPU index + if (!new File(capacityPath).exists() && + !new File(minFreqPath).exists() && + !new File(maxFreqPath).exists() && + !new File(curFreqPath).exists()) { + // If none of the paths exist for this CPU index, assume no more CPUs + break; + } + foundAnyCore = true; + + // Get or create CoreDetails for the current CPU index + CoreDetails details = cpuDetailsMap.get(cpuIndex); + if (details == null) { + details = new CoreDetails(cpuIndex); + cpuDetailsMap.put(cpuIndex, details); + } + + details.capacity = readSysfsInt(capacityPath); + details.minFreq = readSysfsInt(minFreqPath); + details.maxFreq = readSysfsInt(maxFreqPath); + details.currentFreq = readSysfsInt(curFreqPath); + + cpuIndex++; + } + + if (!foundAnyCore) { + return "############################\nCould not retrieve CPU core information. This usually means the necessary permissions are not available, or the /sys/devices/system/cpu paths do not exist on this device."; + } + + StringBuilder resultBuilder = new StringBuilder(); + resultBuilder.append("############################\n"); + resultBuilder.append("CPU Cores:\n"); + + for (CoreDetails details : cpuDetailsMap.values()) { + resultBuilder.append(details.toString()).append("\n"); + } + + return resultBuilder.toString(); + } + } + // Write to scrollable TextView private void log(final String text) { runOnUiThread(new Runnable() {