I am getting an error while running this code and the error is " Root access rejected [java.io.IOException] : Error running exec(). Command: [su] Working Directory: null Environment: null"
try
{
suProcess = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
DataInputStream osRes = new DataInputStream(suProcess.getInputStream());
if (null != os && null != osRes)
{
// Getting the id of the current user to check if this is root
os.writeBytes("id\n");
os.flush();
String currUid = osRes.readLine();
boolean exitSu = false;
if (null == currUid)
{
retval = false;
exitSu = false;
Log.d("ROOT", "Can't get root access or denied by user");
}
else if (true == currUid.contains("uid=0"))
{
retval = true;
exitSu = true;
Log.d("ROOT", "Root access granted");
}
else
{
retval = false;
exitSu = true;
Log.d("ROOT", "Root access rejected: " + currUid);
}
if (exitSu)
{
os.writeBytes("exit\n");
os.flush();
}
}
}
catch (Exception e)
{
Log.d("ROOT", "Root access rejected [" + e.getClass().getName()
+ "] : " + e.getMessage());
}
This is because apps do not have a super user permission in the android system.
Well, first of all ... you need to get your device rooted. A little Google Search will help with that.
If your application will be running on anonymous client devices, then you should better check first if the device is rooted or not. My library has a root availability check method which looks like below, but it doesn't work in a few cases.
public static boolean hasRoot() {
String tags = Build.TAGS;
if ((tags != null) && tags.contains("test-keys"))
return true;
try {
if (new File("/system/app/Superuser.apk").exists())
return true;
} catch (Exception exception) {
exception.printStackTrace();
}
String[] commands = {
"/system/xbin/which su",
"/system/bin/which su",
"which su"
};
for (String command : commands) {
try {
Runtime.getRuntime().exec(command);
return true;
} catch (Exception exception) {
exception.printStackTrace();
}
}
return false;
}
Then you can proceed with your procedure to execute a superuser shell & check for uid.
Or if you want to simplify things, you can have a look at my open-source Android CLI library with which, this task would be simpler. You can find the github project here.
If your phone has root access then you can fire shell scripts using Process and Runtime class..
see the below link:-
Run a shell command as root on android?
http://en.wikipedia.org/wiki/Rooting_%28Android_OS%29
Related
I have a custom device android 4.3. Problem occurs with some commands, one of an example:
su -c 'pm enable com.android.systemui'
When I run this command over adb it works. However when I run the code programatically using this library it just does not work, no error is shown as well.
Interesting observations:
Shell.SU.available() : false
Shell.SU.isSELinuxEnforcing() : false
Ok so device is rooted. Any reason why you are trying to do that command using that library?
What I am trying to say is why can't you just run the shell command yourself?
runRootCommand method:
static boolean runRootCommand(String command) {
boolean status = true;
DataOutputStream os = null;
try {
Process process = Runtime.getRuntime().exec("su");
os = new DataOutputStream(process.getOutputStream());
os.writeBytes(command + "\n");
os.writeBytes("exit\n");
os.flush();
process.waitFor();
} catch (IOException | InterruptedException e) {
Log.e(TAG, e.toString());
status = false;
} finally {
try {
if (os != null)
os.close();
} catch (IOException e) {
Log.e(TAG, e.toString());
status = false;
}
}
return status;
}
And then call that method like this:
boolean success = runRootCommand("pm enable com.android.systemui");
if(success) {
// command was successful
} else {
// command was NOT successful
}
This will run the command as "su" (superuser).
Hope this helps.
This question is possibly a duplicate but I have gone through all the answers and noticed that they won't be working anymore.
private static boolean checkRootMethod1() {
String buildTags = android.os.Build.TAGS;
return buildTags != null && buildTags.contains("test-keys");
}
Method-1 failed
private static boolean checkRootMethod2() {
String[] paths = { "/system/app/Superuser.apk", "/sbin/su", "/system/bin/su", "/system/xbin/su", "/data/local/xbin/su", "/data/local/bin/su", "/system/sd/xbin/su",
"/system/bin/failsafe/su", "/data/local/su" };
for (String path : paths) {
if (new File(path).exists()) return true;
}
return false;
}
Method 2 also failed because "SuperSu" is not system app anymore it can be uninstall and su file is now present on separate folder SU/bin/su
private static boolean checkRootMethod3() {
Process process = null;
try {
process = Runtime.getRuntime().exec(new String[] { "/system/xbin/which", "su" });
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
if (in.readLine() != null) return true;
return false;
} catch (Throwable t) {
return false;
} finally {
if (process != null) process.destroy();
}
}
method 3 also failed because there is no "which" file on android devices nowadays
RootTools.isavailable();
also failed
My question is can I detect device rooted by checking whether the su file is inside the Su/bin/su folder? Is this the right way to detect rooted device?
add "/su/bin/su" to paths variable of checkRootMethod2()
as to method 3, you should also call "which" by using "/system/bin/which"
Okay, Im very new to android programming, and im making a root app to push a specific file to /system/framework with a button
how can i accomplish this? i tried the command style and none are working
There are a number of steps you need to take to be able to do this.
First (of course) the device needs to be rooted. You can check this in a number of ways.
The following code will check if the "su" command returns a command not found error (su binary exists) AND that a super user app is installed to grant the permissions after you request them.
private boolean isDeviceRooted() {
// check for SU command in shell
if ((new ExecShell().executeCommand(ExecShell.SHELL_COMMAND.su_check) != null) && (appInstalled("eu.chainfire.supersu.nonag") || appInstalled("eu.chainfire.supersu") || appInstalled("com.noshufou.android.su") || appInstalled("com.koushikdutta.superuser"))) {
Log.i(TAG, "Device Rooted");
return true;
}
// check for SU application installed
if (appInstalled("eu.chainfire.supersu.nonag") || appInstalled("eu.chainfire.supersu") || appInstalled("com.noshufou.android.su") || appInstalled("com.koushikdutta.superuser")) {
Log.i(TAG, "Device Rooted");
return true;
}
Log.i(TAG, "Device Not Rooted");
return false;
}
private boolean appInstalled(String uri) {
PackageManager pm = getPackageManager();
boolean app_installed = false;
try {
pm.getPackageInfo(uri, PackageManager.GET_ACTIVITIES);
app_installed = true;
} catch (PackageManager.NameNotFoundException e) {
app_installed = false;
}
return app_installed;
}
If this code returns false you could set a flag or display and error, else continue.
Then, once you know the device is rooted, you want to execute the necessary root commands to do what you need.
The following code takes as input String[] of commands, and executes them sequentially as root.
public boolean RunAsRoot(String[] cmds) {
Process p;
try {
p = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
try {
for (String tmpCmd : cmds) {
os.writeBytes(tmpCmd + "\n");
}
os.writeBytes("exit\n");
os.flush();
return true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
In your case you will first want to mount /system as rw. There is lots of information on the web to help you find the command you want but it will look something like
mount -o remount rw /system mount -o remount rw /system
You then want to move the file you want using either mv or cp.
An example of the use of the root commands would be
String[] cmds = {"mount -o remount rw /system mount -o remount rw /system", "cp /sdcard/myfile /system/framework/myfile"};
if(!RunAsRoot(cmds)){
//Commands failed to run, show an error/retry
}
This covers the "hard" bit which is the root functionality.
An easy tutorial for the button can be found here.
Program flow could be
onCreate(){
checkIsRooted();
Button x = (Button) findViewById(R.id.x);
x.setOnClickListener(onClickListener());
}
onClickListener(){
onClick(){
String[] cmds = {...};
if(!runAsRoot(cmds))
AlertDialog.Builder.makeText(...).show();
}
}
NOTE, THIS IS PSEUDO CODE, YOU CAN'T COPY AND PASTE THIS CODE TO MAKE IT WORK, YOU NEED TO DO IT PROPERLY YOURSELF!
I'm developing my first Android application, and I'm curious if there are any "standard" ways for executing privileged shell commands. I've only been able to find one way to do it, by executing su, and then appending my commands to stdin of the su process.
DataOutputStream pOut = new DataOutputStream(p.getOutputStream());
DataInputStream pIn = new DataInputStream(p.getInputStream());
String rv = "";
// su must exit before its output can be read
pOut.writeBytes(cmd + "\nexit\n");
pOut.flush();
p.waitFor();
while (pIn.available() > 0)
rv += pIn.readLine() + "\n";
I've read about wrapping privileged (superuser) calls up in JNI: is this possible? If so, how would one go about accomplishing it? Other than that, are there any other ways of calling privileged instructions from Java?
As far as I know, you can only run command-line commands using root privileges. You can use this generic class I made that wraps the root access in your code:
http://muzikant-android.blogspot.com/2011/02/how-to-get-root-access-and-execute.html
All you need to do is extend this class and override the getCommandsToExecute method to return the commands you want to execute as root.
public abstract class ExecuteAsRootBase
{
public static boolean canRunRootCommands()
{
boolean retval = false;
Process suProcess;
try
{
suProcess = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
DataInputStream osRes = new DataInputStream(suProcess.getInputStream());
if (null != os && null != osRes)
{
// Getting the id of the current user to check if this is root
os.writeBytes("id\n");
os.flush();
String currUid = osRes.readLine();
boolean exitSu = false;
if (null == currUid)
{
retval = false;
exitSu = false;
Log.d("ROOT", "Can't get root access or denied by user");
}
else if (true == currUid.contains("uid=0"))
{
retval = true;
exitSu = true;
Log.d("ROOT", "Root access granted");
}
else
{
retval = false;
exitSu = true;
Log.d("ROOT", "Root access rejected: " + currUid);
}
if (exitSu)
{
os.writeBytes("exit\n");
os.flush();
}
}
}
catch (Exception e)
{
// Can't get root !
// Probably broken pipe exception on trying to write to output stream (os) after su failed, meaning that the device is not rooted
retval = false;
Log.d("ROOT", "Root access rejected [" + e.getClass().getName() + "] : " + e.getMessage());
}
return retval;
}
public final boolean execute()
{
boolean retval = false;
try
{
ArrayList<String> commands = getCommandsToExecute();
if (null != commands && commands.size() > 0)
{
Process suProcess = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
// Execute commands that require root access
for (String currCommand : commands)
{
os.writeBytes(currCommand + "\n");
os.flush();
}
os.writeBytes("exit\n");
os.flush();
try
{
int suProcessRetval = suProcess.waitFor();
if (255 != suProcessRetval)
{
// Root access granted
retval = true;
}
else
{
// Root access denied
retval = false;
}
}
catch (Exception ex)
{
Log.e("ROOT", "Error executing root action", ex);
}
}
}
catch (IOException ex)
{
Log.w("ROOT", "Can't get root access", ex);
}
catch (SecurityException ex)
{
Log.w("ROOT", "Can't get root access", ex);
}
catch (Exception ex)
{
Log.w("ROOT", "Error executing internal operation", ex);
}
return retval;
}
protected abstract ArrayList<String> getCommandsToExecute();
}
A possible solution I know is to sign your application as system, which is not exactly the same as root as far as I know: How to sign Android app with system signature?. But I suppose this is not what you wanted.
Another thing I did is to create a native application that does what is needed, running it as an external process. But it is necessary to give this native application the privileges you need and the suid bit, provided the partition is not nosuid. But this is not what you needed either I suppose.
C code called through JNI should be subject to the same limitations as living in the same process, I suppose.
If you have the su binary available then you can run commands from java with something like: Runtime.getRuntime().exec("su -c reboot").
I don't remember any other way.
I was in the need of doing this in a rooted device recently and found out about libsu, which is a library allowing to execute su commands.
This library is written by the author of Magisk.
I have a rooted device with Magisk and libsu works pretty well from my app. The first time you execute a su command, Magisk will show a dialog where you grant or deny the root capabilities.
Running a command with libsu from an app is as simple as doing the following:
Shell.cmd("find /dev/block -iname boot").exec()
I'm trying to create a ServerSocket on a port below 1024.
Obviously, this is restricted to root access only.
But I'm struggling on getting the right permissions for my app.
I'm using this code, for example, to test if I have root access (or trigger the dialog)
But it still doesn't let me ServerSocket work.
AFAIK, the process that is created with the SU command has the root access, not my app. How do I get root access into my own process?
public stat
ic boolean getRoot() {
try {
Process p = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
os.writeBytes("echo \"Do I have root?\" >/system/sd/temporary.txt\n");
os.writeBytes("exit\n");
os.flush();
try {
p.waitFor();
if (p.exitValue() != 255) {
return true;
} else {
return false;
}
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
Afaik you cannot open a port below 1024 under *nix systems if you're not root...