Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8e38552b authored by myfluxi's avatar myfluxi Committed by Steve Kondik
Browse files

Settings: Apply Processor settings to all cpus

QCOMs multicore implementation allows for different governors
and min/max values per cpu. Let the Settings app live up to the
user's assumed expectation and keep values synced across all
available cpus.

While this can be easily accomplished with a root-app, there are
a few prerequisites for our application: This patch requires
ueventd rules for cpu*/cpufreq/scaling_* files and write perms
to cpu*/online for the SYSTEM user in init.${ro.hardware}.rc.

Change-Id: Ic9349977f02282649a11319758dd7f546538f149
parent fcf981d9
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -536,6 +536,14 @@ public class Utils {
        return new File(filename).exists();
    }

    public static boolean fileIsReadable(String fname) {
        return new File(fname).canRead();
    }

    public static boolean fileIsWritable(String fname) {
        return new File(fname).canWrite();
    }

    public static String fileReadOneLine(String fname) {
        BufferedReader br;
        String line = null;
+83 −7
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 The CyanogenMod Project
 * Copyright (C) 2012-2014 The CyanogenMod Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
@@ -19,20 +19,26 @@ package com.android.settings.cyanogenmod;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemProperties;
import android.os.SystemService;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceScreen;
import android.util.Log;

import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;

import java.lang.Runtime;

//
// CPU Related Settings
//
public class Processor extends SettingsPreferenceFragment implements
        Preference.OnPreferenceChangeListener {

    public static final String CPU_ONLINE = "/sys/devices/system/cpu/cpu0/online";
    public static final String FREQ_CUR_PREF = "pref_cpu_freq_cur";
    public static final String SCALE_CUR_FILE = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq";
    public static final String FREQINFO_CUR_FILE = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq";
@@ -224,9 +230,10 @@ public class Processor extends SettingsPreferenceFragment implements
        }
    }

    public boolean onPreferenceChange(Preference preference, Object newValue) {
    public boolean onPreferenceChange(Preference preference, Object value) {
        initFreqCapFiles();

        final String newValue = (String) value;
        String fname = "";

        if (newValue != null) {
@@ -238,15 +245,84 @@ public class Processor extends SettingsPreferenceFragment implements
                fname = FREQ_MAX_FILE;
            }

            if (Utils.fileWriteOneLine(fname, (String) newValue)) {
            if (Utils.fileWriteOneLine(fname, newValue)) {
                final String file = fname;
                final int nrcpus = Runtime.getRuntime().availableProcessors();
                if (nrcpus > 1) {
                    new Thread() {
                        public void run() {
                            int count = 0;
                            int maxcount = 5;
                            String on = "1";
                            String off = "0";
                            String onfile = "";
                            String cpufile = "";
                            String savedstate = "";
                            String state = "";
                            String mpdec = "mpdecision";
                            SystemService.State mpdecstate = SystemService.getState(mpdec);
                            // Dumb down to a running mpdecision service
                            if (mpdecstate.equals(SystemService.State.RUNNING)) {
                                SystemService.stop(mpdec);
                            }
                            try {
                                for (int i = 1; i < nrcpus; i++) {
                                    onfile = CPU_ONLINE.replace("cpu0", "cpu" + i);
                                    cpufile = file.replace("cpu0", "cpu" + i);
                                    savedstate = Utils.fileReadOneLine(onfile);
                                    // Writing on to already online cpu throws EINVAL exception
                                    if (savedstate.equals(off)) {
                                        if (Utils.fileIsWritable(onfile)) {
                                            Utils.fileWriteOneLine(onfile, on);
                                        } else {
                                            String hw = SystemProperties.get("ro.hardware");
                                            Log.e(TAG, onfile +
                                            " not writable, did you set ownership in init." +
                                            hw + ".rc?");
                                        }
                                    }
                                    // Give ueventd a little time to set perms
                                    while (count < maxcount) {
                                        Thread.sleep(10);
                                        if (Utils.fileExists(cpufile)) {
                                            if (Utils.fileIsWritable(cpufile)) {
                                                Utils.fileWriteOneLine(cpufile, newValue);
                                                break;
                                            } else {
                                                Log.e(TAG, cpufile +
                                                " not writable, did you set ueventd rules?");
                                            }
                                        }
                                        count++;
                                        if (count == maxcount) {
                                            Log.e(TAG, "Failed setting new value to " + cpufile);
                                        }
                                    }
                                    count = 0;
                                    state = Utils.fileReadOneLine(onfile);
                                    // Restore prior state of onlined cpu
                                    if (state.equals(on) && !state.equals(savedstate)) {
                                        Utils.fileWriteOneLine(onfile, off);
                                    }
                                }
                            } catch (InterruptedException e) {
                            }
                            // Restart mpdec
                            if (mpdecstate.equals(SystemService.State.RUNNING)) {
                                SystemService.start(mpdec);
                            }
                        }
                    }.start();
                }

                if (preference == mGovernorPref) {
                    mGovernorPref.setSummary(String.format(mGovernorFormat, (String) newValue));
                    mGovernorPref.setSummary(String.format(mGovernorFormat, newValue));
                } else if (preference == mMinFrequencyPref) {
                    mMinFrequencyPref.setSummary(String.format(mMinFrequencyFormat,
                            toMHz((String) newValue)));
                            toMHz(newValue)));
                } else if (preference == mMaxFrequencyPref) {
                    mMaxFrequencyPref.setSummary(String.format(mMaxFrequencyFormat,
                            toMHz((String) newValue)));
                            toMHz(newValue)));
                }
                return true;
            } else {