I'm a beginner in stackoverflow so I cant add a comment.
I saw this page:
Read command output inside su process
and I tried this answer and it is ok:
Process p = Runtime.getRuntime().exec(new String[]{"su", "-c", "system/bin/sh"});
DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
//from here all commands are executed with su permissions
stdin.writeBytes("ls /data\n"); // \n executes the command
InputStream stdout = p.getInputStream();
byte[] buffer = new byte[BUFF_LEN];
int read;
String out = new String();
//read method will wait forever if there is nothing in the stream
//so we need to read it in another way than while((read=stdout.read(buffer))>0)
while(true){
read = stdout.read(buffer);
out += new String(buffer, 0, read);
if(read<BUFF_LEN){
//we have read everything
break;
}
}
//do something with the output
but when I tried at command in the shell the response was the same command.
I put this command:
stdin.writeBytes("echo AT+CQI?\n");
the answer was:
AT+CQI?
I wrote:
stdin.writeBytes("echo ATinkd\n");
the answer was:
ATinkd
That is mean "bla..bla..bla..". that is mean the android system does not recognize this commands as at commands.
I wonder if any body have an advice or solution.
First I think you are just sending the AT command to stdout in the shell which will not do anything other than giving you an echo which you read back. For this approach to work you have to redirect the echo command to the serial port device file. Android phones use various devices for this, /dev/ttyGS0 and /dev/smd0 seems to be common names.
However I would suggest using the program atinput to send AT commands and capture modem responses. It is specifically written to be used from the command line like that. That will relieve you from communicating directly with the modem and the only thing left is the pipe handling reading the response.
Related
I am writing an application which involves getting information on all running processes (name/package name to begin with). I am doing this by invoking "ps" in my code. I requested superuser access from within the application before invoking the "ps" command. However, when I attempt to read the input stream, the application freezes and I do not get any output in the Logcat. Below is the code that I am using:
Process process = Runtime.getRuntime().exec("su");
DataOutputStream outputStream = new DataOutputStream(process.getOutputStream());
outputStream.writeBytes("ps -t -x -P -p -c");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String topInfo = bufferedReader.readLine(); //Where it freezes
while(topInfo != null)
{
Log.i(appInfo, topInfo);
topInfo = bufferedReader.readLine();
}
outputStream.flush();
outputStream.close();
The code works as expected without superuser request, however the result only consists of my application and the "ps" process.
Is there something that I have missed, or something I need to research before I attempt to fix this?I have tried to search this issue on the Internet before asking here, without success. Any help is appreciated.
Thanks in advance.
P.S The application is being run on a rooted device running Android 7.1.1
I have found the cause of the problem. As it turns out, the BufferedReader was not ready to read, therefore it was not getting any input from the input stream. I confirmed this with the following code:
while(bufferedReader.ready())
{
String topInfo;
while ((topInfo = bufferedReader.readLine()) != null)
{
Log.i(appInfo, topInfo);
}
}
The fix to this problem is to wait for the BufferedReader to be ready to to read the process input stream. This can either be done by pausing the thread for some time, or including a loop that will loop through till the BufferedReader is ready to read. I opted for the latter, as shown below:
do
{
//Wait
} while(!bufferedReader.ready());
This gave me the desired results, which was a list of processes running on my device.
I want to generate a file while app is running thus my computer can monitor my app status in time(the cell phone is connected via usb all the time).
Is there anyway to let both adb and app point the same directory?
Also, If there has another way to make android can communicate with computer, please tell me.
Methods I tried:
At first, I though
echo $EXTERNAL_STORAGE
and
Environment.getExternalStorageDirectory()
would return the same value.
The value adb shell returned:
/storage/emulated/legacy
However, the result of calling Environment.getExternalStorageDirectory() In program is:
/storage/emulated/0
Then, I make android run shell command
Process su = Runtime.getRuntime().exec("echo $EXTERNAL_STORAGE");
//also tried "echo \\$EXTERNAL_STORAGE"
su.waitFor();
in = su.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = "";
while ((line = reader.readLine())!= null){
result = result + line + "\n";
}
reader.close();
in.close();
su.destroy();
return result;
but it return empty string.
echo is not a separate executable but rather a shell's built-in command.
Use Runtime.getRuntime().exec("sh -c 'echo $EXTERNAL_STORAGE'"); instead
Finally, I got the value by following command.
Runtime.getRuntime().exec(new String[] { "sh", "-c", "echo $EXTERNAL_STORAGE" });
Thanks Alex P. inspiring me.
I have a rooted android phone. I am trying to read the output of "ls" via my program:
Process p = null;
p = Runtime.getRuntime().exec(new String[]{"su", "-c", "system/bin/sh"});
DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
stdin.writeBytes("ls / \n");
stdin.flush();
InputStream stdout = p.getInputStream();
and after that when I do read() , the read call blocks sometimes, sometimes it doesn't get blocked and I am able to read from the stream. Sometime i have to wait for the buffer to be filled.
read = stdout.read(buffer);
Isn't there any consistent way in which this read could happen. I am doing ls on the same directory and i am noting different delays.
or
Is it better to use pseudo terminal?
I have rooted my device, then in my application
Process p = Runtime.getRuntime().exec("su");
and it work fine, my application will be root mode. Then I try add wlan address space, but it doesn't work, when I check out in terminal, following error message is shown
busybox ifconfig there is not a new wlan address space.
I try with following way:
Process p = Runtime.getRuntime().exec("su");
p = Runtime.getRuntime().exec("busybox ifconfig wlan0 add xxxxxxxxxxxx");
p.waitfor();
When I run my application, the toast shows that the app is root mode but there is not added wlan0.
The "su -c COMMAND" syntax is not really supported. For better portability, use something like this:
p = Runtime.getRuntime().exec("su");
stream = p.getOutputStream();
stream.write("busybox ifconfig wlan0 add xxxxxxxxxxxx");
The write() command doesn't exists as-is, but I'm sure you'll find how to write your stream to it, maybe encapsulating the output stream in a BufferedOutputWriter or so.
because the process that started with "busybox" is not the same one
which started with "su". you should like this:
Process process = Runtime.getRuntime().exec("su");
OutputStream os = process.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
dos.writeBytes("busybox ifconfig wlan0 add xxxxxxxxxxxx" + "\n");
dos.flush();
That might be because when you run su, it launches one process. Then you run busybox ..., and it happens in another process, which is not started as a superuser.
Try something like
Process p = Runtime.getRuntime().exec(new String[] {"su", "-c", "busybox ifconfig wlan0 add xxxxxxxxxxxx"});
, i.e. executing it in a single command-line.
I'm writing a file explorer which will be capable of modifying system files with root access, but I came across some problems.
What I'm doing now is to grant my app root access, but executing "su" doesn't work.
If I set permissions to the folder in adb shell, the app works fine but I think root browsing doesn't rely on chmods.
Can anyone tell me is there a proper way to make my app work as if it were with root privileges?
Running an android application process (its dalvik VM and native libraries) as root is extremely difficult to achieve, and inadvisable for a number of reasons including not just security but memory waste resulting from having to load private copies of system libraries instead of using the shared read-only copies available when you inherit an unprivileged process from zygote as in a normal application launch.
What the unofficial "su" hack on some rooted phones does is lets you launch a helper process which runs as root while your application process remains unprivileged. It does not change the userid of the application calling it - indeed, there really isn't by design any mechanism for doing that on unix-like operating systems.
Once you have a privileged helper process, you would then need to communicate with it via some means of interprocess communication such as its stdin/stdout or unix domain sockets to have it do file operations on your behalf. The shell present on the phone could probably even be used as the helper application - most of what a file manager needs to do can be implemented with the 'cat' command. Officially, none of this is a stable API, but then an application-accesable "su" hack isn't in official android anyway, so the whole project is deep in "unsupported" territory to begin with.
Root access creates a new Process, so, your app does not have root privileges.
The unique thing you can do with root privileges is execute commands, so, you have to know the commands of android, many of commands is based on Linux, like cp, ls and more.
Use this code for execute commands and get output:
/**
* Execute command and get entire output
* #return Command output
*/
private String executeCommand(String cmd) throws IOException, InterruptedException {
Process process = Runtime.getRuntime().exec("su");
InputStream in = process.getInputStream();
OutputStream out = process.getOutputStream();
out.write(cmd.getBytes());
out.flush();
out.close();
byte[] buffer = new byte[1024];
int length = buffer.read(buffer);
String result = new String(buffer, 0, length);
process.waitFor();
return result;
}
/**
* Execute command and an array separates each line
* #return Command output separated by lines in a String array
*/
private String[] executeCmdByLines(String cmd) throws IOException, InterruptedException {
Process process = Runtime.getRuntime().exec("su");
InputStream in = process.getInputStream();
OutputStream out = process.getOutputStream();
out.write(cmd.getBytes());
out.flush();
out.close();
byte[] buffer = new byte[1024];
int length = buffer.read(buffer);
String output = new String(buffer, 0, length);
String[] result = output.split("\n");
process.waitFor();
return result;
}
Usages for a file explorer:
Get list of files:
for (String value : executeCmdByLines("ls /data/data")) {
//Do your stuff here
}
Read text file:
String content = executeCommand("cat /data/someFile.txt");
//Do your stuff here with "content" string
Copy file (cp command not working on some devices):
executeCommand("cp /source/of/file /destination/file");
Delete file (rm command not working on some devices):
executeCommand("rm /path/to/file");