• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

How can I get the CPU load in a multi-core android device?

Matt Pil

Lurker
As a student, I have a project where I must analyze the CPU load of every core in multi-core and Big.little architectures. I execute some applications on recent Android devices (Oreo 8.0). From what I've seen on the internet, it seems that the CPU load (average and detailled for each core) is not available anymore to developers. Therefore, it is impossible for me to analyze it, unless I try to root all my devices to unlock features.

I currently have 3 devices: a Samsung A5 (2017), a Samsung A7 (2018) and a LG Nexus 5X. I can't access the CPU load for any of those devices.

I've tried the following code to access the data related to the CPU utilization.

RandomAccessFile reader = new RandomAccessFile("/proc/stat", "r");

This should give me information about the CPU, and it only gives me an exception.

java.io.FileNotFoundException: /proc/stat: open failed: EACCES (Permission denied)

Is there any other way to access this information (average CPU load and the detailled load for each core)? Or do I have to root my devices and hope it solves my problem?
 
@Matt Pil
Root is required. Prior to android 6, you can read root files with RandomAccessFile, but as of android 6 this was changed for security reasons.

You can get info for each individual core in the following directory:
Code:
/sys/devices/system/cpu

On a rooted device, the following example can get you started. It's a method that you can use to read root files...
Java:
static String exec(String cmd) {
    try {
        Process process = Runtime.getRuntime().exec("su -c " + cmd);
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        int read;
        char[] buffer = new char[4096];
        StringBuilder output = new StringBuilder();
        while ((read = reader.read(buffer)) > 0) {
            output.append(buffer, 0, read);
        }
        reader.close();
        process.waitFor();
        return output.toString();
    } catch (IOException | InterruptedException e) {
        throw new RuntimeException(e);
    }
}

Usage of the above method...
Java:
String maxFreq = exec("cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq");
setText(maxFreq);

If you still get permission denied, then you'll have to change SELinux context for the file temporarily like so...

Assuming you're rooted with magisk. Upon reboot the file will go back to its normal se-context...
Java:
String[] cmds = { "chcon u:object_r:magisk_file:s0 /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq" };
exec(cmds);

static void exec(String[] cmds) {
    try {
        Process process = Runtime.getRuntime().exec("su");
        DataOutputStream os = new DataOutputStream(process.getOutputStream());
        for (String tmpCmd : cmds) {
            os.writeBytes(tmpCmd + "\n");
        }
        os.writeBytes("exit\n");
        os.flush();
        os.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

With the above method you can pass multiple commands, reducing the amount of su calls. For example...
Java:
String[] cmds = {
    "cat /dir/file_one",
    "cat /dir/file_two",
    "cat /dir/file_three"
};
exec(cmds);

I provided 2 different methods, one for reading root files to get stdout and the other for executing root commands.

As these are brief samples, I gave you basic code to get you started with root development.
Word of caution: The su call is a blocking call which blocks the UI thread. You need to wrap these methods in an AsyncTask or any other background threading otherwise you'll get a lot of ANRs(android not responding). The above samples should all work as is, at least for testing and getting started.

There's also root libraries that make this all really simple so you may want to find one and read the documentation on how to use it.

Good luck :)
 
Back
Top Bottom