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.
Related
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 am trying to run these shell commands via java but no success.Code executes perfectly but .so file do not exectue. while i use these commands in adb everything work perfeclty.
private void submit() {
System.out.println("doooooooooo");
try {
String[] commands = {"cd /data/data/com.dailydeals.usethisnow/lib",
"./libdeals.so" };
Process p = Runtime.getRuntime().exec("/system/bin/sh -");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
for (String tmpCmd : commands) {
os.writeBytes(tmpCmd+"\n");
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("doneooooooooo");
}
Executing shell commands in Android Applications (Android Programming)
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()
On a rooted android device, I tried to run a cat command that read kernel log, as follow:
Process p = Runtime.getRuntime().exec("su");
p = Runtime.getRuntime().exec("/system/bin/cat /proc/kmsg");
The su command was successfully executed but not the cat.
I tried to read the output of the command using getInputStream() but nothing was there, as follow:
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((read = err.read(buffer)) > 0)
{ //read error to buffer
catOutput.append(buffer, 0, read);
}
in.close();
I used the same code with ls command instead of displaying the kernel log, it worked just fine and show me the result.
I wonder if what error I am getting and wantted to see the error message on the shell when executing the cat command. Tried the p.getErrorStream() but it doesn't give me any result.
Could any one help me with this ? Thanks.
Here's a comprehensive example on how to do this - note that I got the idea from this answer:
public void catKmsg() {
Runtime runtime = Runtime.getRuntime();
Process proc = null;
OutputStreamWriter osw = null;
StringBuilder sbstdOut = new StringBuilder();
StringBuilder sbstdErr = new StringBuilder();
String command="/system/bin/cat /proc/kmsg";
try { // Run Script
proc = runtime.exec("su");
osw = new OutputStreamWriter(proc.getOutputStream());
osw.write(command);
osw.flush();
osw.close();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (osw != null) {
try {
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
try {
if (proc != null) {
proc.waitFor();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
sbstdOut.append(ReadBufferedReader(new InputStreamReader
(proc.getInputStream())));
sbstdErr.append(ReadBufferedReader(new InputStreamReader
(proc.getErrorStream())));
if (proc.exitValue() != 0) {
}
}
I finally found the solution for the problem by using RootTools library.
Recently released (few months after my question was asked), RootTools provides a easy-to-use tool set that helps running commands that required root privilege. I created a wrapper to check if root access is available before executing shell command:
void testRootToolsCommand(String command){
if (RootTools.isRootAvailable())
toastMessage("Root is available !!!");
else {
toastMessage("NO ROOT !!! ");
return;
}
int timeOut = 1000;
try {
List<String> output = RootTools.sendShell(command,timeOut);
toastMessage("OUTPUT of the command \n" + output.toString());
} catch (RootToolsException re) {
toastMessage("Funny thing happened with RootTools!!! ");
} catch (TimeoutException te)
{
toastMessage("Timeout exception - Increase timeout !!! !!! ");
}
catch (Exception e) {
toastMessage(e.getMessage().toString());
}
}
An example of a function call is:
testRootToolsCommand("cat /proc/kmsg > /sdcard/jun11_4h51.txt");
Note: The Tool also support running multiple commands at once.
I am trying to write an android application that runs a shell commands, or a shell script if that is preferable, and displays the output... can anyone give me in the right direction?
My code is as follows:
void execCommandLine()
{
Runtime runtime = Runtime.getRuntime();
Process proc = null;
OutputStreamWriter osw = null;
try
{
String[] str={"/system/bin/sh","/data/shTest.sh"};
System.out.println("EXEC STRING");
proc = runtime.exec(str);
osw = new OutputStreamWriter(proc.getOutputStream());
//osw.write(command);
osw.flush();
osw.close();
}
catch (IOException ex)
{
Log.e("erre","ioexception");
//Log.e("execCommandLine()", "Command resulted in an IO Exception: " + command);
return;
}
finally
{
if (osw != null)
{
try
{
osw.close();
}
catch (IOException e){}
}
}
try
{
proc.waitFor();
}
catch (InterruptedException e){}
if (proc.exitValue() != 0)
{
Log.e("erre","interruotexception");
//Log.e("execCommandLine()", "Command returned error: " + command + "\n Exit code: " + proc.exitValue());
}
}
// **************************************
Code is running successfully but I am not getting any output in adb shell logcat
would anyone tell me if this script is executed successfully how to get this output
in Adb shell.
Have you looked into GScript. It is quite flexible.