1

I am writting an application for Android which passes a JAVA fd taken from ParcelFileDescriptor.getFd() which according to [1] states that the int I get back is a native fd.

Now, with this fd, I am trying to write it over a unix domain socket to the existing process which is listening. To do this, I am using JNI and I pass the int received above to the JNI function as an argument named fdToSend.

When my JNI code attempts to call sendmsg(), an error occurs stating "Bad file number".

With some help from google, It seems like the socket connection might be closed when I call sendmsg(), but I cannot see how this would be the case.

The sendfd() method is exactly as found in [2].

Below is my bridging JNI function:

JNIEXPORT jint JNICALL Java_com_example_myapp_AppManager_bridgeSendFd(JNIEnv *env, jint fdToSend) {
    int fd;
    struct sockaddr_un addr;

    if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        __android_log_print(ANDROID_LOG_ERROR, APPNAME, "socket() failed: %s (socket fd = %d)\n", strerror(errno), fd);
        return (jint)-1;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, "/data/data/com.example.myapp/sock_path", sizeof(addr.sun_path)-1);

    if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
        __android_log_print(ANDROID_LOG_ERROR, APPNAME, "connect() failed: %s (fd = %d)\n", strerror(errno), fd);
        return (jint)-1;
    }

    return (jint)sendfd(fd, (int)fdToSend);
}

[1] http://developer.android.com/reference/android/os/ParcelFileDescriptor.html#getFd()

[2] https://stackoverflow.com/a/4491203/2796346

Community
  • 1
  • 1
Dulax
  • 553
  • 3
  • 20
  • 1
    As a test, you could try to validate (use) the fd in native code before sending, or send a test one opened in native code. – Chris Stratton Oct 06 '13 at 14:57
  • Turns out I get the same error when I simply read() from the fdToSend. So I guess in this case Android's FDs are off-limits to the Native side? – Dulax Oct 06 '13 at 16:32
  • Odd. Can you get a shell as the application's userid and look at the links in its /proc/PID/fd directory while it is running? Or use the emulator where adbd is root. – Chris Stratton Oct 06 '13 at 21:35
  • @ChrisStratton I concur. Check the fd's listed for the process, not sure if lsof is available on android, but you could try to list the file descriptors via `lsof -a -p ` to validate that your fd returned from Java is indeed a valid fd – Samhain Oct 07 '13 at 13:03

1 Answers1

1

Turns out the issue was the JNI function declaration.

The first arg is JNIEnv, the second is jclass THEN it's the values passed in from Java (i.e. for me, fdToSend).

So, my guess is that since I was using the second arg (supposed to be a jclass), then I'm probably getting a memory reference or something weird like that.

As seen here: https://stackoverflow.com/a/10743451/2796346

Community
  • 1
  • 1
Dulax
  • 553
  • 3
  • 20
  • 1
    Actually either is possible - but your Java and C must agree if your native function is a `static` method, or one which needs to be passed its class instance. – Chris Stratton Oct 07 '13 at 14:56