Breaking down a voltage control app

I learned so many things while making the S4 GPU voltage control app, that I thought it would be appropriate to break it down into groups.

Here is the source on GitHub:

https://github.com/alaskalinuxuser/S4_GPU_voltage_control_app

And a download link for the app itself: http://www.mediafire.com/file/hk5vcce0s5r6kb7/GpuVoltageControl_1.0.apk

Since, by nature of the app, it was inherently dangerous, I wanted to make sure that people without the appropriate files would not be able to use this app. That part was pretty simple. First, I declared the needed file. If you don’t have this file, there is no reason to use this app.

[CODE]
// declare the gpu file
File gpu = new File(“/sys/devices/system/cpu/cpufreq/vdd_table/gpu_vdd_levels”);

// check if the file exists
if(gpu.exists()){
System.out.println(“gpu exists”);
} else {
Toast.makeText(this, “This kernel does not support this action!”, Toast.LENGTH_SHORT).show();
finish();
}
[/CODE]

So, if the file exists, then it pints out “gpu exists” to no where, which does nothing, but allows the program to continue. If not, or “else” it creates a pop-up (toast) that tells the user they don’t have the file and thus the kernel doesn’t support this app, and the app closes with the “finish();” command.

Then, I needed a way to tell the user what the current state of the GPU voltage was. Is it set to the default values? Is it over volted? Under volted? They needed to know so they could decide what they wanted to do next. Remember, above we already declared the file in question as “gpu”.

[CODE]
// read the file for the current status
try {
FileInputStream fIn = new FileInputStream(gpu);
BufferedReader myReader = new BufferedReader(
new InputStreamReader(fIn));
String aDataRow = “”;
String aBuffer = “”;
while ((aDataRow = myReader.readLine()) != null) {
aBuffer += aDataRow + “\n”;
}
// get first 3 characters
String result = aBuffer.toString().substring(0, 3);

// if overvolted, tell the user
if (result.equals(“955”)) {
Toast.makeText(getBaseContext(),
“GPU is currently overvolted.”,
Toast.LENGTH_LONG).show();
} else {
// do nothing
}

// if undervolted, tell the user
if (result.equals(“935”)) {
Toast.makeText(getBaseContext(),
“GPU is currently undervolted.”,
Toast.LENGTH_LONG).show();
} else {
System.out.println(result);
}

// if default, tell the user
if (result.equals(“945”)) {
Toast.makeText(getBaseContext(),
“GPU is currently set to default.”,
Toast.LENGTH_LONG).show();
} else {
System.out.println(result);
}

myReader.close();
} catch (Exception e) {
Toast.makeText(getBaseContext(), e.getMessage(),
Toast.LENGTH_SHORT).show();
}
[/CODE]

Here we see that the reader will take a file input stream (the gpu file) and read the first few bytes of the file. This is because the file is laid out like this:

[CODE]
945000
1050000
1150000
[/CODE]

With each line being the voltage of the corresponding frequency stage. Honestly, now that I have progressed farther in my course, I could have done this part better, to check for options that were outside of my program, say, if the user had manually set the voltages. What I did, though, was knowing what my pre-set over/under/default voltages would be, I tailored this part of the code to look for one of my presets, and to tell the user what it is set to with a toast. It works well within the confines of the app, if the user only uses this app to control the voltages.

However, if the user were to use a different app (although one does not exist at present) to control the voltages, their changes may fall outside of the limited choices of my app, so this could have been done better, but for this app, it works well enough, provided this app is the only means the user uses to control the GPU voltage.

Now that the user knows the current status of the GPU voltage, I present them with buttons to choose their own voltage options. There are only 4 options, so it is a very limited selection, but they were voltage choices that seemed to work safely, and hence why I chose them. We will only look at one for brevity, but you can check them all out on my GitHub if you would like.

[CODE]
// first up, the over volt button
oVButton = (Button) findViewById(R.id.ovButton);
oVButton.setOnClickListener(new OnClickListener() {

public void onClick(View v) {
try {
// the command to run
String[] pwrUp = { “su”, “-c”, “echo ‘955000\n1150000\n1250000’ > /sys/devices/system/cpu/cpufreq/vdd_table/gpu_vdd_levels” };
Runtime.getRuntime().exec(pwrUp);
// tell the user
Toast.makeText(getBaseContext(),
“GPU overvolted by 10 mV!”,
Toast.LENGTH_SHORT).show();

} catch (IOException e) {
// tell the user the problem
e.printStackTrace();
Toast.makeText(getBaseContext(), e.getMessage(),
Toast.LENGTH_LONG).show();
}
}
});
[/CODE]

The real magic here was how to run a command as the superuser so the program would be able to write to that system file.

Runtime.getRuntime().exec(pwrUp); // This line actually runs the command.

String[] pwrUp = { “su”, “-c”, “echo ‘955000\n1150000\n1250000’ > /sys/devices/system/cpu/cpufreq/vdd_table/gpu_vdd_levels” }; // This line is the command. If printed, it would look like this:

su -c echo ‘955000\n1150000\n1250000’ > /sys/devices/system/cpu/cpufreq/vdd_table/gpu_vdd_levels

Remember that echo is using the apostraphe, for quotes. The “\n” portion becomes a litteral line break in the file. If you used the double quote, then the output would be a litteral one line file of:

955000\n1150000\n1250000

Which wouldn’t work at all. This is convenient, since the double quote would also end the String[] (array) and break it into more parts and cause errors. So, by clicking the over volt button, they are sending a pre-set string of voltage parameters to their GPU. This is very limiting for the user, but very simple to implement, and in a way prevents abuse of the GPU by an error or unknowledgable input by the user.

All that being said, it also requires some permissions to be built into the app, by placing them in the AndroidManifest.xml file, as you can see here:

[CODE]
<?xml version=”1.0″ encoding=”utf-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android&#8221;
package=”com.alaskalinuxuser.gvc” >
<uses-permission android:name=”android.permission.ACCESS_SUPERUSER” />
<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” />

<application
android:allowBackup=”true”
[/CODE]

Notice the two “uses-permission” lines. The app has access to the superuser, and the permission to write (and consequently read) to/from files. Technically, I am not sure that I need the write permission, since the writing is done by the super user, however, I do need to read the file in question, so at a minimum, I would change this to READ_EXTERNAL_STORAGE.

I hope all of my scribbles make sense! Granted, there are probably much better ways to do this, and I hope to improve as I continue to build apps.

Linux – keep it simple.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s