I have an app which should execute some root commands.
SuperSU version is 1.04.
Su version is 1.02.
Android 4.1.1.
Device is Samsung Galaxy S3 - rooted.
The problem is I cannot get a permission prompt from SuperSU.
I've tried many things, but prompt never shows up.
For RootChecker basic, ADB and other apps it shows up.
Here is my procedure - maybe I'm doing something wrong.
private static String runShellCommand(String command) {
DataOutputStream os = null;
Process process = null;
try {
String [] env = {"PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin"};
process = Runtime.getRuntime().exec("su", env, Environment.getExternalStorageDirectory() );
os = new DataOutputStream(process.getOutputStream());
InputStreamHandler err = new InputStreamHandler(process.getErrorStream(), false);
InputStreamHandler out = new InputStreamHandler(process.getInputStream(), false);
os.writeBytes(command + "\n");
os.flush();
os.writeBytes(EXIT);
os.flush();
os.close();
Log.d(LOGTAG, "Waiting on: " + process.waitFor());
String errOut = err.getOutput();
String stdOut = out.getOutput();
Log.d(LOGTAG, "Exit code: " + process.exitValue());
Log.d(LOGTAG, command + " erroutput: [" + errOut + "]");
Log.d(LOGTAG, command + " output: [" + stdOut + "]");
if (errOut != null && !errOut.equals(""))
return errOut;
else if (stdOut != null&& !stdOut.equals(""))
return stdOut;
else
return null;
} catch (Exception e) {
Log.e(LOGTAG, "runShellCommand error: ", e);
return null;
} finally {
try {
if (os != null) {
os.close();
}
if (process != null) {
Log.d(LOGTAG, "Exit val: " + process.exitValue());
process.destroy();
}
} catch (Exception ignored) {}
}
}
InputStream handler is:
private static class InputStreamHandler extends Thread {
private final InputStream stream;
private final boolean devNull;
StringBuffer output;
public String getOutput() {
return output.toString();
}
InputStreamHandler(InputStream stream, boolean devNull) {
this.devNull = devNull;
this.stream = stream;
output = new StringBuffer();
start();
}
#Override
public void run() {
try {
if (devNull) {
while (stream.read() != -1) {}
} else {
BufferedReader br = new BufferedReader(new InputStreamReader(stream));
while (true) {
String line = br.readLine();
if (line == null) {
Log.d(LOGTAG, "Ended with reading!");
br.close();
return;
}
output.append(line);
}
}
} catch (IOException ignored) {
Log.e(LOGTAG, "Error", ignored);
}
}
}
Anyone have an idea why does it block so it doesn't show permission window?
Thanks.
I'm not exactly sure why this wouldn't work. The first thing that strikes me as odd is passing Environment.getExternalStorageDirectory() to exec. Maybe this (path) is not allowed (to execute from) ?
Why not simply use libsuperuser, written specifically to perform this very task ? It is open source, tiny, fully commented, has an example project, and even a document detailing the common problems you may encounter when trying to do this very operation.
I finally figured it out. The trick is to create a process (execute Runtime.getRuntime().exec("su");) separately in another thread. I'm not sure why this works, but it does.
Similar way is used in RootTools.
This has solved my problem.
Related
I need to convert a lot of wave files simultaneously. About 300 files in parallel. And new files come constantly. I use ffmpeg process call from my Java 1.8 app, which is running on CentOS. I know that I have to read error and input streams for making created process from Java possible to exit.
My code after several expirements:
private void ffmpegconverter(String fileIn, String fileOut){
String[] comand = new String[]{"ffmpeg", "-v", "-8", "-i", fileIn, "-acodec", "pcm_s16le", fileOut};
Process process = null;
BufferedReader reader = null;
try {
ProcessBuilder pb = new ProcessBuilder(comand);
pb.redirectErrorStream(true);
process = pb.start();
//Reading from error and standard output console buffer of process. Or it could halts because of nobody
//reads its buffer
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String s;
//noinspection StatementWithEmptyBody
while ((s = reader.readLine()) != null) {
log.info(Thread.currentThread().getName() + " with fileIn " + fileIn + " and fileOut " + fileOut + " writes " + s);
//Ignored as we just need to empty the output buffer from process
}
log.info(Thread.currentThread().getName() + " ffmpeg process will be waited for");
if (process.waitFor( 10, TimeUnit.SECONDS )) {
log.info(Thread.currentThread().getName() + " ffmpeg process exited normally");
} else {
log.info(Thread.currentThread().getName() + " ffmpeg process timed out and will be killed");
}
} catch (IOException | InterruptedException e) {
log.error(Thread.currentThread().getName() + "Error during ffmpeg process executing", e);
} finally {
if (process != null) {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
log.error("Error during closing the process streams reader", e);
}
}
try {
process.getOutputStream().close();
} catch (IOException e) {
log.error("Error during closing the process output stream", e);
}
process.destroyForcibly();
log.info(Thread.currentThread().getName() + " ffmpeg process " + process + " must be dead now");
}
}
}
If I run separate test with this code it goes normally. But in my app I have hundreds of RUNNING deamon threads "process reaper" which are waiting for ffmpeg process finish. In my real app ffpmeg is started from timer thread. Also I have another activity in separate threads, but I don't think that this is the problem. Max CPU consume is about 10%.
Here is that I usual see in thread dump:
"process reaper" #454 daemon prio=10 os_prio=0 tid=0x00007f641c007000 nid=0x5247 runnable [0x00007f63ec063000]
java.lang.Thread.State: RUNNABLE
at java.lang.UNIXProcess.waitForProcessExit(Native Method)
at java.lang.UNIXProcess.lambda$initStreams$3(UNIXProcess.java:289)
at java.lang.UNIXProcess$$Lambda$32/2113551491.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
What am I doing wrong?
UPD:
My app accepts a lot of connects with voice traffic. So I have about 300-500 another "good" threads in every moment. Could it be the reason? Deamon threads have low priority. But I don't beleive that they really can't do their jobs in one hour. Ususally it takes some tens of millis.
UPD2:
My synthetic test that runs fine. I tried with new threads option and without it just with straigt calling of run method.
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
public class FFmpegConvert {
public static void main(String[] args) throws Exception {
FFmpegConvert f = new FFmpegConvert();
f.processDir(args[0], args[1], args.length > 2);
}
private void processDir(String dirPath, String dirOutPath, boolean isNewThread) {
File dir = new File(dirPath);
File dirOut = new File(dirOutPath);
if(!dirOut.exists()){
dirOut.mkdir();
}
for (int i = 0; i < 1000; i++) {
for (File f : dir.listFiles()) {
try {
System.out.println(f.getName());
FFmpegRunner fFmpegRunner = new FFmpegRunner(f.getAbsolutePath(), dirOut.getAbsolutePath() + "/" + System.currentTimeMillis() + f.getName());
if (isNewThread) {
new Thread(fFmpegRunner).start();
} else {
fFmpegRunner.run();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
class FFmpegRunner implements Runnable {
private String fileIn;
private String fileOut;
FFmpegRunner(String fileIn, String fileOut) {
this.fileIn = fileIn;
this.fileOut = fileOut;
}
#Override
public void run() {
try {
ffmpegconverter(fileIn, fileOut);
} catch (Exception e) {
e.printStackTrace();
}
}
private void ffmpegconverter(String fileIn, String fileOut) throws Exception{
String[] comand = new String[]{"ffmpeg", "-i", fileIn, "-acodec", "pcm_s16le", fileOut};
Process process = null;
try {
ProcessBuilder pb = new ProcessBuilder(comand);
pb.redirectErrorStream(true);
process = pb.start();
//Reading from error and standard output console buffer of process. Or it could halts because of nobody
//reads its buffer
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
//noinspection StatementWithEmptyBody
while ((line = reader.readLine()) != null) {
System.out.println(line);
//Ignored as we just need to empty the output buffer from process
}
process.waitFor();
} catch (IOException | InterruptedException e) {
throw e;
} finally {
if (process != null)
process.destroy();
}
}
}
}
UPD3:
Sorry, I forgot to notice that I see the work of all these process - they created new converted files but anyway don't exit.
Your application is I/O bound, not CPU bound. If all your files are in the same HDD, then opening simultaneously 300 files will definitely degrade the performance. (that is a likely reason on why you have hundreds of processes waiting).
If I understood correctly, you mentioned that processing 1 file takes some tens of millis? (and this is doing sequential reads - the fastest that your HDD will read a file)
in this case, processing 300 files sequentially should take no more than 30 seconds.
100 millis - process 1 file
1 second - process 10 files
30 second - process 300 files
EDIT
I did 2 simple changes to your sample code (I removed the first loop, then changed the codec) finally I put one song in "ogg" format in "/tmp/origin" directory. now the program works well).
see code below:
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
public class FFMpegConvert {
public static void main(String[] args) throws Exception {
FFMpegConvert f = new FFMpegConvert();
f.processDir("/tmp/origin", "/tmp/destination", false);
}
private void processDir(String dirPath, String dirOutPath, boolean isNewThread) {
File dir = new File(dirPath);
File dirOut = new File(dirOutPath);
if (!dirOut.exists()) {
dirOut.mkdir();
}
for (File f : dir.listFiles()) {
try {
System.out.println(f.getName());
FFmpegRunner fFmpegRunner = new FFmpegRunner(f.getAbsolutePath(), dirOut.getAbsolutePath() + "/" + System.currentTimeMillis() + f.getName());
if (isNewThread) {
new Thread(fFmpegRunner).start();
} else {
fFmpegRunner.run();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class FFmpegRunner implements Runnable {
private String fileIn;
private String fileOut;
FFmpegRunner(String fileIn, String fileOut) {
this.fileIn = fileIn;
this.fileOut = fileOut;
}
#Override
public void run() {
try {
ffmpegconverter(fileIn, fileOut);
} catch (Exception e) {
e.printStackTrace();
}
}
private void ffmpegconverter(String fileIn, String fileOut) throws Exception {
String[] comand = new String[]{"ffmpeg", "-i", fileIn, "-acodec", "copy", fileOut};
Process process = null;
try {
ProcessBuilder pb = new ProcessBuilder(comand);
pb.redirectErrorStream(true);
process = pb.start();
//Reading from error and standard output console buffer of process. Or it could halts because of nobody
//reads its buffer
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
//noinspection StatementWithEmptyBody
while ((line = reader.readLine()) != null) {
System.out.println(line);
//Ignored as we just need to empty the output buffer from process
}
process.waitFor();
} catch (IOException | InterruptedException e) {
throw e;
} finally {
if (process != null)
process.destroy();
}
}
}
}
Got it!
In some cases ffmpeg wants to ask me should it override already existed file. In my code I close outputstream of this child process. But as it appears this only closes outputstream for Java but not for the process.
So my solution is to make ffmpeg silent at all: no output from this process with "-v -8", no asking question with default "Yes" "-y".
I am trying to:
Execute Bash script
Read log file
I have following code using processBuilder which has readLog function that reads log file and executeBash which executes the command and then destroys processbuilder's readlog process. But as readLog file is reading a live log file executeBash never gets called.
How do I read the log file in real time and display it simultaneously with executeBash?
public void performAction(OssSystem system) {
readLog(system);
executeBash(system);
}
public void executeBash(OssSystem system) {
try {
Process process = new ProcessBuilder().command("/bin/sh", system.getCommand_path(), system.getParam()).start();
BufferedReader reader
= new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder builder = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
builder.append(line);
builder.append(System.getProperty("line.separator"));
}
int status = process.waitFor();
cmdResult = builder.toString() + " command status " + status;
int exitValue = process.exitValue();
readProcess.destroy();
} catch (IOException ex) {
LOG.log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
LOG.log(Level.SEVERE, null, ex);
}
}
String logOutput;
Process readProcess;
public void readLog(OssSystem system) {
String user = system.getUsername() + "#" + system.getIp();
String cmd = "tail -f " + system.getLog_dir() + " | less";
try {
readProcess = new ProcessBuilder().command("/usr/bin/ssh", user, cmd).start();
int status = readProcess.waitFor();
BufferedReader reader
= new BufferedReader(new InputStreamReader(readProcess.getInputStream()));
StringBuilder builder = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
builder.append(line);
builder.append(System.getProperty("line.separator"));
}
logOutput = builder.toString() + " command status " + status;
} catch (IOException ex) {
Logger.getLogger(Shell.class.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
Logger.getLogger(Shell.class.getName()).log(Level.SEVERE, null, ex);
}
}
According to javadoc,
Causes the current thread to wait, if necessary, until the process
represented by this Process object has terminated. This method returns
immediately if the subprocess has already terminated. If the
subprocess has not yet terminated, the calling thread will be blocked
until the subprocess exits.
So the readProcess.waitFor(); will block the main thread and you can never expect executeBash(system); to be called before readProcess has terminated.
You can start a thread to launch readProcess.
public void performAction(OssSystem system) {
readLog(system);
ExecuteBashThread thread = new ExecuteBashThread(system);
thread.start();
}
class ExecuteBashThread extends Thread{
private OssSystem system;
public ExecuteBashThread(OssSystem system){
this.system = system;
}
#Override
public void run(){
executeBash(system);
}
}
I am trying to execute a c++ code from java on a remote Windows machine. In order to deal with the remote part, I have created a Web service from where the actual command is run using Runtime.exec(). The c++ exe is not being called directly from the java code. I have a batch file that eventually calls the exe.
The problem is, both java and c++ processes hang. The java code on server side does handle the output stream and error stream. Also, the c++ code is logging everything in a file on Windows. The strange thing is that, when I remove the WS call and run the java code on server side as a standalone java program, it succeeds. Here is the java code:
public class RunCPlusPlusExecutable {
public int runExecutable() {
int exitValue = 0;
try {
Process p = null;
Runtime rt = Runtime.getRuntime();
System.out.println("About to execute" + this + rt);
p = rt.exec("c:/temp/execcplusplus.bat");
System.out.println("Process HashCode=" + p.hashCode());
StreamProcessor errorHandler = new StreamProcessor(p.getErrorStream(), "Error");
StreamProcessor outputHandler = new StreamProcessor(p.getInputStream(), "Output");
errorHandler.start();
outputHandler.start();
exitValue = p.waitFor();
System.out.println("Exit value : " + exitValue);
if (exitValue == 0)
System.out.println("SUCCESS");
else
System.out.println("FAILURE");
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
}
return exitValue;
}
class StreamProcessor extends Thread {
private InputStream is = null;
private String type = null;
private InputStreamReader isr = null;
private BufferedReader br = null;
private FileWriter writer = null;
private BufferedWriter out = null;
StreamProcessor(InputStream is, String type) {
this.is = is;
this.type = type;
}
public void run() {
try {
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
writer = new FileWriter("*******path to log file********");
out = new BufferedWriter(writer);
String line = null;
while ((line = br.readLine()) != null) {
Date date = new Date();
out.write("[" + type + "]: " + date + " : " + line);
out.newLine();
}
writer.flush();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
try {
if (br != null)
br.close();
if (isr != null)
isr.close();
if (out != null)
out.close();
if (writer != null)
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Any idea what is causing the problem and how to debug it? Please note that I won't be able to debug the c++ code.
Thanks
Update 1:
Here are some more details...
The WS server is running from some admin user. And I have been running the standalone java program from some other user.
*It seems that the c++ executable is giving referenced memory error while executing from WS call. There are pop-ups citing the error with OK and Cancel buttons. *
Update 2:
The tomcat server where the WS is deployed is running as a Windows NT service. Can that be the cause of the error? If yes, how to resolve this?
I use StreamGobbler to read output from external program. Before I used to read and parse big(20-40 strings) output from stderr of ffmpeg. Now I want to read and parse only one string from stdout(one string is all output of program and this program ends very quickly) of identify(ImageMagick). And sometimes it works, but sometimes I have error "Stream closed". I think that StreamGobbler has no time to work with stream(process ends before streamGobler do some work).
Below you can see class ExecThread and example of it's usage.
Sorry for my English...
String command = ffmpegExe.getAbsolutePath()+ " -i \""+ fileName +"\"";
ExecThread thread = new ExecThread(command);
thread.setPriority(ExecThread.MIN_PRIORITY);
thread.start();
thread.waitFor(DEFAULT_WAIT);
//reading ffmpeg stderr
BufferedReader ffmpegErr = thread.getErrBufferedReader();
String line;
try
{
while((line = ffmpegErr.readLine()) !=null)
//some code
private static class ExecThread extends Thread
{
public ExecThread(String command)
{
this.command = command;
}
#Override
public void run()
{
try
{
ExecCommand(command);
exitVal = process.waitFor();
}
catch (Exception e )
{
logger.error("Error while executing command: " + command + e.getMessage(),e);
System.err.println("Error");
System.exit(1);
}
}
public void waitFor(long millis)
{
try
{
this.join(millis);
process.destroy();
} catch (Exception e)
{
logger.error("Error while interupting command: " + command + e.getMessage(), e);
}
}
private void ExecCommand(String command) throws IOException
{
//run command
Runtime rt = Runtime.getRuntime();
process = rt.exec(new String[]{shellName,shellOption, command}, null, null);
//get stderr buffered reader
StreamGobbler errGobbler = new StreamGobbler(process.getErrorStream());
StreamGobbler outGobbler = new StreamGobbler(process.getInputStream());
ErrBufferedReader = new BufferedReader(new InputStreamReader(errGobbler));
OutBufferedReader = new BufferedReader(new InputStreamReader(outGobbler));
}
private BufferedReader ErrBufferedReader;
public BufferedReader getOutBufferedReader()
{
return OutBufferedReader;
}
private BufferedReader OutBufferedReader;
private Process process;
private String command;
private int exitVal=-1;
public BufferedReader getErrBufferedReader()
{
return ErrBufferedReader;
}
public Process getProcess()
{
return process;
}
public String getCommand()
{
return command;
}
public int getExitVal()
{
return exitVal;
}
}
I'd recommend two changes:
Use the Java Process instead of writing a Thread.
Close your input, output, and error streams and destroy the Process. You'll have file handle leaks if you don't.
This is not good decision but it works. Before it was String command = identifyExe.getAbsolutePath() + " \"" + file.getAbsolutePath() + "\"";
now it String command = "sleep 1 ; " + identifyExe.getAbsolutePath() + " \"" + file.getAbsolutePath() + "\"";
Sleep is very usefull function :-)
But, if you know better decision please tell...
I'm trying to enter some value in external application using Java.
Java application looks like this:
Runtime runtime = Runtime.getRuntime();
// ... str build ...
proc = runtime.exec(str);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
bw.write(value);
bw.flush();
bw.close();
if (proc.waitFor() != 0)
// error msg
// the end
Application hangs at waitFor method.
External application looks like this:
welcome banner
please enter 8 character input:
Welcome banner is printed using printf and input is taken with SetConsoleMode/ReadConsoleInput. ReadConsoleInput reads one char and they are masked with * character.
Help
you can use:
proc.getOutputStream().write("some date".getBytes())
keep in mind that you HAVE to read everything the app send to stdout and stderr, else it might get stuck writing there.
I use a generic class to read it in a different thread.
usage is like:
InputStreamSucker inSucker = new InputStreamSucker(proc.getInputStream());
InputStreamSucker errSucker = new InputStreamSucker(proc.getErrorStream());
proc.waitFor();
int exit = process.exitValue();
inSucker.join();
errSucker.join();
InputStreamSucker code is here:
public class InputStreamSucker extends Thread
{
static Logger logger = Logger.getLogger(InputStreamSucker.class);
private final BufferedInputStream m_in;
private final ByteArrayOutputStream m_out;
private final File m_outFile;
public InputStreamSucker(InputStream in) throws FileNotFoundException
{
this(in, null);
}
public InputStreamSucker(InputStream in, File outFile) throws FileNotFoundException
{
m_in = new BufferedInputStream(in, 4096);
m_outFile = outFile;
m_out = new ByteArrayOutputStream();
start();
}
#Override
public void run()
{
try
{
int c;
while ((c = m_in.read()) != -1)
{
m_out.write(c);
}
}
catch (IOException e)
{
logger.error("Error pumping stream", e);
}
finally
{
if (m_in != null)
{
try
{
m_in.close();
}
catch (IOException e)
{
}
}
try
{
m_out.close();
}
catch (IOException e)
{
logger.error("Error closing out stream", e);
}
if (m_outFile != null)
{
byte data[] = m_out.toByteArray();
if (data.length > 0)
{
FileOutputStream fo = null;
try
{
fo = new FileOutputStream(m_outFile);
fo.write(data);
}
catch (IOException e)
{
logger.error("Error writing " + m_outFile);
}
finally
{
try
{
if (fo != null) fo.close();
}
catch (IOException e)
{
logger.error("Error closing " + m_outFile);
}
}
}
}
}
}
public String getOutput()
{
return new String(m_out.toByteArray());
}
}
Got the answer! The trick is to use WriteConsoleInput() API because program expects keyboard event, not text ... That's why the waitFor() waited forever! :)