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 viadlopen
anddlsym
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 isrand
- prior toandroid-21
,rand
was an inline function that actually calledlrand48()
, so your binary ended up depending onlrand48
which existed in the older android versions'libc.so
, while they didn't have anyrand
there. Inandroid-21
, a lot of such functions have been added, and the inline functions removed, so if you build withAPP_PLATFORM := android-21
, your binary will end up depending on the functionrand
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?
android:minSdkVersion
is the minimum OS version that your app expects.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 withandroid: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 hastargetSdkVersion
=19, so it gives you the old API behavior, but if some other app saystargetSdkVersion
=20, Android will give it the new API behavior.APP_PLATFORM
is the version of the native headers and libraries that the NDK will compile your native code with. If you setAPP_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. SoAPP_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 usedlopen
/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
Getlaunchintentforpackage Is Null for Some Apps
Garbage Collection Causes:Mediaplayer Finalized Without Being Released
Android: Skimagedecoder:: Factory Returned Null
Listview Items Are Not Clickable. Why
How to Display Gif in React-Native Android App
Elevation on Android Lollipop Not Working
Checking My App Version Programmatically in Android Market
Creating Different Layout for Android Phone and Tablet
Handle a View Visibility Change Without Overriding the View
How to Detect If Any of My Activity Is Front-Most and Visible to User
How to Switch Automatically Between Viewpager Pages
How to Setup Appium in Ubuntu for Android
Set Language to French in Android Datepickerdialog
How to Set Delay in Android Onclick Function