How to use unix pipes in Android
Asked Answered
S

2

11

I need to send some data to a C program from my app in Android, and I think about using pipes. I read that Java can access to existing pipes (and open them as if it's a normal file), but I'm unable to do such a thing in my application. When I try, the app just block until the message wait close appears, without writing anything special on logcat.

I found a thread on android mailing lists about this subject, but it was not very clear, and it refers to a folder that does not exist on my phone.

Furthermore, I know it's not possible to make pipes on the sdcard, but when I try to do so in/data, I think I have root issues… Do you know if it is possible to access to that pipe (I try in and out of the app folder without success)?

I made the pipe with mkfifo, and the permissions seems OK to be open by any user.

prw-rw-rw- root     root              2010-11-18 04:53 video_pipe

I tried to add the X permission (who knows...) Here is what I have back:

# chmod u+x video_pipe 
Bad mode

The code that blocks is the camera initialisation (PATH is just the path to the pipe):

recorder.setOutputFile(PATH);

Here is the whole source : https://github.com/rbochet/Simple-Camera-App/commits/piped (commit 22dba257f6)

Sympathetic answered 17/5, 2011 at 4:48 Comment(8)
Is the C program a child of your java pocess? If so, it's pretty easy to get its stdin/stdout/stderr pipes. If not, unix domain sockets (private rather than file namespace) should work. Will the C program run as the same userID as the java? If so you may be able to use a named pipe in the app's private directory. chmod on android only takes octal arguments, not the alphabetic ones. Most importantly, What exactly do you need to accomplish?Mesocratic
And try posting the code that is blocking until ANR dialog shows up.Mesocratic
The C program is ffmpeg, cross-compiled for Android. I want to use it to live transcode the video through a pipe. I think it should not be too difficult to make it a child process (it is only launching it from Runtime.exec(), isn't it?). BTW, thx for the octal thing... I should have seen it by myself.Sympathetic
Try posting the code that's failing. Or see any open source android terminal application. Try testing your ffmpeg command line from the adb shell. Try testing your java exec and pipe code with a tiny C program that just does something expected with its stdin/out (you can link it against the android log library so it can give you its perspective on what is happening out of band)Mesocratic
By post the code, I mean post enough of it that someone has a chance of spotting why it isn't working, or even duplicate the problem.Mesocratic
Consider using the form of recorder.setOutputFile() that takes a file descriptor rather than a path, and giving it the fd to the child process. But first test it in your code. Right now I suspect you are trying to splice up an opaque android framework to an opaque ffmpeg - try putting your own code on both ends to understand how the mechanism works.Mesocratic
Possibly relevant: #2740821Treytri
Unfortunately, it not that relevant, because I'm in a fully java environmentSympathetic
S
10

Ok, I tried to fix the problem with the most stupid app that exists. You can find this one as a gist on github.

So far, I discover this :

  • The only place where the pipe works is the app folder (ie /data/data/package.full.name/)
  • If you want to pass data to another program, you had better to launch it as a child of your app to ensure they are in the same group and thus have the same authorisation for the folder. If you can't, you might be able to play with the groups (do ls -l -a on /data/data/ and have a look to the group name).

DO NOT FORGET : You can't actually write in the pipe until someone is listening at the other side. So if you test the file I posted on github, you will have that kind of logcat result.

I/ActivityManager(  220): Start proc fr.stackr.android.upt for activity fr.stackr.android.upt/.UnixPipeActivity: pid=1359 uid=10048 gids={}
I/UPIPE   ( 1359): Attempt started
W/ActivityManager(  220): Launch timeout has expired, giving up wake lock!
W/ActivityManager(  220): Activity idle timeout for HistoryRecord{4643c8b8 fr.stackr.android.upt/.UnixPipeActivity}

Here, the system pause because nothing happens… Then I run cat v_pipe on the phone.

V/UPIPE   ( 1359): SEND :: Try to write the first paragraph ....
V/UPIPE   ( 1359): SEND :: Bip
V/UPIPE   ( 1359): Flushing...
V/UPIPE   ( 1359): SEND :: Bip post flush
V/UPIPE   ( 1359): Closing…
I/UPIPE   ( 1359): Attempt ended

That's done.

closing : when I close the OutputStreamWriter, the listening side (ie cat) ends. If I commment the line, cat will still wait for input.

flushing : seems to be important if you intent to get something without calling close.

Carriage Return : Use \n.

Sympathetic answered 18/5, 2011 at 4:0 Comment(0)
F
2

I think you can use ParcelFileDescriptor.createPipe()

It will return an array of pipe for read and write. For more information, visit the developers website.

Favorable answered 23/4, 2015 at 9:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.