2

TLDR; Problem:

When I run my native Android executable alone with Runtime.exec(), I can get its printf() outputs from my app. But when I do it with Runtime.exec("su -c <native executable>"), I can't get its outputs anymore.


Better explanation:

So, say I have an Android app that has a native executable called "executable". I rename "executable" to "libexecutable.so" to trick the apk installer into copying the file over into the device.

Then, the app runs the executable with

String executable = context.getFilesDir().getParent() + "/lib/libexecutable.so";
String me = context.getPackageName();

Process p = Runtime.getRuntime().exec(String.format("%s %s", executable, me));

From my native executable, whenever I use printf(), I can get the output in my app with p.getInputStream(). Perfect.

However, this native executable needs root permissions, so, I run it like this:

String su = "su -c";
String executable = context.getFilesDir().getParent() + "/lib/libexecutable.so";
String me = context.getPackageName();

Process p = Runtime.getRuntime().exec(String.format("%s %s %s", su, executable, me));

Now, whenever my native executable uses printf(), I no longer can get the output with p.getInputStream().

I looked it up and got to this: Java: can't get stdout data from Process unless its manually flushed

And tried fflush(stdout) in my native executable directly after every printf() call, like the page suggested but it didn't work.

Community
  • 1
  • 1
Justin AnyhowStep
  • 1,130
  • 3
  • 12
  • 19
  • 1
    did you try to read stderr? – njzk2 Apr 08 '14 at 19:15
  • I didn't. I just tried it upon your suggestion and looks like you were spot on.. I got "Permission denied". Which is **very** strange to me. My phone **is** rooted *(I've used other root apps fine)*, the Superuser app logs show that it has **Allowed** every single request by my app.. – Justin AnyhowStep Apr 08 '14 at 19:21

1 Answers1

2
String[] cmd = new String[]{
    "su",
    "-c",
    getFilesDir().getParent() + "/lib/libexecutable.so " + getPackageName()
};
Process p = Runtime.getRuntime().exec(cmd);
//No more permission denied error

Oh, never mind. I got it running with this. Could someone tell me why this works and not my initial attempt?

Justin AnyhowStep
  • 1,130
  • 3
  • 12
  • 19
  • Shouldn't make a difference -- `exec(String)` just tokenizes the string and passes it to `exec(String[])`. Did you do a `chmod` in there somewhere to set the file's executable bit? – fadden Apr 08 '14 at 19:41
  • I didn't. I literally just replaced my string concats with this string array. I didn't even know what chmod was until recently. I'm still very new to this whole Unix thing. – Justin AnyhowStep Apr 08 '14 at 20:05
  • 1
    The real proof of meaningful difference or not would be if your can *break* it again by *reverting* to the original. If so, this is (puzzlingly) the fix. If not, it is coincidence and the meaningful change was elsewhere. Also, it's not clear if you have some mechanism other than the expected output messages to know if the command executed; if not it's possible some subtle mistaken in the other invocation mechanism was simply preventing it from running, rather than from providing collectable output. – Chris Stratton Apr 08 '14 at 21:13
  • I just tried it as you suggested. String fails with "Permission denied" being output on error stream. String array succeeds. – Justin AnyhowStep Apr 08 '14 at 21:21