How to Use Mkfifo Using Android's Ndk

how to use mkfifo using Android's NDK

This happens if you build against the android-21 platform headers. Set APP_PLATFORM in jni/Application.mk to an older version, to build using the old headers, to make sure you only link to functions available earlier.

(Before android-21, the C library features and headers didn't really change significantly, so for the normal C library functions, it doesn't matter if you build targeting android-3 or android-20.)

This has been reported and is intentional behavior, see e.g. https://code.google.com/p/android/issues/detail?id=73725.

If you don't need to use new features from android-21, just build using older headers. (It doesn't matter that you're targeting an older platform version if you want to try to build for e.g. arm64-v8a or x86_64 that didn't exist before; ndk-build would build the 32 bit parts using the older target, and the 64 bit ones using the oldest target that supports them.)

In case you want to try to use new features from the android-21 platform conditionally if running on such a platform, you probably need to use dlopen and dlsym to load it conditionally anyway, so then you need to duplicate the other definitions from the new headers as well, to allow you to build using the older platform headers.

How to create named pipe (mkfifo) in Android?

Roosmaa's answer is correct -- mkfifo() just calls mknod() to create a special file, and FAT32 doesn't support that.

As an alternative you may want to consider using Linux's "abstract namespace" UNIX-domain sockets. They should be roughly equivalent to a named pipe. You can access them by name, but they're not part of the filesystem, so you don't have to deal with various permission issues. Note the socket is bi-directional.

Since it's a socket, you may need INTERNET permission. Not sure about that.

Here's a quick bit of client/server sample code:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stddef.h>
#include <sys/socket.h>
#include <sys/un.h>

/*
* Create a UNIX-domain socket address in the Linux "abstract namespace".
*
* The socket code doesn't require null termination on the filename, but
* we do it anyway so string functions work.
*/
int makeAddr(const char* name, struct sockaddr_un* pAddr, socklen_t* pSockLen)
{
int nameLen = strlen(name);
if (nameLen >= (int) sizeof(pAddr->sun_path) -1) /* too long? */
return -1;
pAddr->sun_path[0] = '\0'; /* abstract namespace */
strcpy(pAddr->sun_path+1, name);
pAddr->sun_family = AF_LOCAL;
*pSockLen = 1 + nameLen + offsetof(struct sockaddr_un, sun_path);
return 0;
}

int main(int argc, char** argv)
{
static const char* message = "hello, world!";
struct sockaddr_un sockAddr;
socklen_t sockLen;
int result = 1;

if (argc != 2 || (argv[1][0] != 'c' && argv[1][0] != 's')) {
printf("Usage: {c|s}\n");
return 2;
}

if (makeAddr("com.whoever.xfer", &sockAddr, &sockLen) < 0)
return 1;
int fd = socket(AF_LOCAL, SOCK_STREAM, PF_UNIX);
if (fd < 0) {
perror("client socket()");
return 1;
}

if (argv[1][0] == 'c') {
printf("CLIENT %s\n", sockAddr.sun_path+1);

if (connect(fd, (const struct sockaddr*) &sockAddr, sockLen) < 0) {
perror("client connect()");
goto bail;
}
if (write(fd, message, strlen(message)+1) < 0) {
perror("client write()");
goto bail;
}
} else if (argv[1][0] == 's') {
printf("SERVER %s\n", sockAddr.sun_path+1);
if (bind(fd, (const struct sockaddr*) &sockAddr, sockLen) < 0) {
perror("server bind()");
goto bail;
}
if (listen(fd, 5) < 0) {
perror("server listen()");
goto bail;
}
int clientSock = accept(fd, NULL, NULL);
if (clientSock < 0) {
perror("server accept");
goto bail;
}
char buf[64];
int count = read(clientSock, buf, sizeof(buf));
close(clientSock);
if (count < 0) {
perror("server read");
goto bail;
}
printf("GOT: '%s'\n", buf);
}
result = 0;

bail:
close(fd);
return result;
}

Android - Using pipe between native and java apps

Use BufferedReader instead `FileInputStream

Missing c standard library symbols when loading NDK library on Kindle Fire

Are you sure that you've built your NDK library targeting the right native API level? If you've built it targeting android-21 or newer and running on older android versions - especially these functions will fail. See https://stackoverflow.com/a/27338365/3115956 and https://stackoverflow.com/a/27093163/3115956 for more details.

Android NDK and Newer API Support

It's doable, but it is not too easy.

For the java code, as you know, you can set any higher target SDK version and use such features, as long as you make sure that those codepaths only are executed on the newer devices - simple.

For the native code, you can in principle set a higher APP_PLATFORM than your baseline, and try to do the same, but there's a few details you need to keep track of:

  • You can't unconditionally link to functions from the newer platform, you need to load them dynamically. That is, instead of calling functions directly and adding the libraries to LOCAL_LDLIBS, you need to load the functions via dlopen and dlsym instead, to make sure that the binary is loadable on the older versions. (Or alternatively, you can build separate shared libraries, where one shared library can be loaded on all platform, while another one only can be loaded on newer platforms.)

  • Some bionic libc functions have changed (mainly in android-21, but some minor ones also changed before that) - functions that did exist before but have changed symbol name. One of the more common functions that has changed is rand - prior to android-21, rand was an inline function that actually called lrand48(), so your binary ended up depending on lrand48 which existed in the older android versions' libc.so, while they didn't have any rand there. In android-21, a lot of such functions have been added, and the inline functions removed, so if you build with APP_PLATFORM := android-21, your binary will end up depending on the function rand which didn't exist before. See https://stackoverflow.com/a/27093163/3115956 and https://stackoverflow.com/a/27338365/3115956 for more details about this.

  • Keep in mind that you don't need to set APP_PLATFORM to the same as the target SDK on the java side, you only (may) need to set it if you want to selectively use newer features on newer firmware versions.

Due to the second issue you might not want to set a higher APP_PLATFORM at all. If you use dlopen (so you don't actually need the .so files to link against), you can manage pretty easily by copying those new headers from the newer platform version into your own project, and building with the older APP_PLATFORM.

Android Studio 1.3 NDK : cannot locate 'srand'

You need to build the native sources against a SDK version prior to 21, if you want the code to run on older versions. (The java part can still be built using the latest SDK.)

If it's ok to lower the generic compileSdkVersion, try lowering it to 19 or 20. If not, you might want to try adding compileSdkVersion 19 within the ndk block.

See https://stackoverflow.com/a/27338365/3115956 and https://stackoverflow.com/a/27093163/3115956 for more explanation on the issue.

What is the relation between APP_PLATFORM, android:minSdkVersion and android:targetSdkVersion?

  1. android:minSdkVersion is the minimum OS version that your app expects.

  2. android:targetSdkVersion is essentially the maximum OS version that you've designed your app to work with. Here's an example of how this works. Imagine that you tested your app fine with API 19 and you release your app with android:targetSdkVersion=19. Then Google decides to release API 20 with a change in behavior of some API, but they don't want to change the behavior for old apps (to prevent from breaking them). So when your app starts up, Android sees that your app has targetSdkVersion=19, so it gives you the old API behavior, but if some other app says targetSdkVersion=20, Android will give it the new API behavior.

  3. APP_PLATFORM is the version of the native headers and libraries that the NDK will compile your native code with. If you set APP_PLATFORM to a specific value and you use APIs that are only available in that platform version, then your app will not run properly on older platforms. So APP_PLATFORM is a minimum value. The solution is to use a lower value and not use those newer APIs, or to write code that decides at runtime whether to call the new APIs or not (and probably use dlopen/dlsym).

It seems like in general it doesn't make sense to use an APP_PLATFORM value newer than android:minSdkVersion, unless you're doing some special (like being careful not to call new APIs by checking the version at runtime, plus making sure not to link to new APIs and instead using dlopen/dlsym).

So if you use APP_PLATFORM=13 and you call AMotionEvent_getAxisValue (which is not in earlier platform headers, implying that it isn't available at runtime on earlier platforms), your app will not run on devices with API < 13. The one caveat would be if AMotionEvent_getAxisValue is actually available on older versions, but it just wasn't in the header/library files or it just wasn't documented. But I don't know if that's the case for this particular API (basically, that would require more research and risk analysis of whether you want to depend on something unsupported).



Related Topics



Leave a reply



Submit