UnsatisfiedLinkError when run System.loadLibrary - android

I am using pjsip library through android ndk. I used Android NDK 16 to compile pjsip. One user (HTC One, Android 5.0.2) faced a lot of crashes while trying to start our project. This is the error:
Fatal Exception: java.lang.UnsatisfiedLinkError
dlopen failed: cannot locate symbol "stdin" referenced by "libpjsua2.so"...
... .PjSipApp.<clinit>
In the project we have .so-files for 4 abis, as stated in google android ndk official docs: arm64-v8a, armeabi-v7a, x86, x86_64.
Here is how I load libraries in code:
public class PjSipApp {
private static final String TAG = "Pjsua-PjSipApp";
static {
try {
System.loadLibrary("openh264");
System.loadLibrary("yuv");
} catch (UnsatisfiedLinkError ignore) {
}
System.loadLibrary("pjsua2");
Log.v(TAG, "LibraryLoaded");
}...
So System.loadLibrary("pjsua2"); throws this UnsatisfiedLinkError.
Maybe anyone knows, what is the reason for this?

You probably compiled binaries with a higher API Level.
This is how they are defined in stdio.h
#if __ANDROID_API__ >= 23
extern FILE* stdin __INTRODUCED_IN(23);
extern FILE* stdout __INTRODUCED_IN(23);
extern FILE* stderr __INTRODUCED_IN(23);
/* C99 and earlier plus current C++ standards say these must be macros. */
#define stdin stdin
#define stdout stdout
#define stderr stderr
#else
/* Before M the actual symbols for stdin and friends had different names. */
extern FILE __sF[] __REMOVED_IN(23);
#define stdin (&__sF[0])
#define stdout (&__sF[1])
#define stderr (&__sF[2])
#endif
So, if you built for API level >= 23, the symbol will resolve to File* stdin which doesn't exist in API < 23. I'd suggest to reduce the API level.

Related

Crash on android x86_64 not happening on x86 (Android API30, API31)

Former title was: crash on vsprintf starting from Android12 (api >= 31)
My Android app uses a native library (libexif) built with NDK. At some time in my native code (adapted from exif), I call the vsprintf function which makes the app crash.
Formerly in exif, it was a call to vfprintf (stderr, format, args); that I replaced by vsprintf so as to store the string for later use.
static void
log_func (ExifLog *log, ExifLogCode code, const char *domain,
const char *format, va_list args, void *data)
{
char dest[1024] = {0, };
vsprintf(dest, format, args);
}
The message (as per the output from an API where it works) should be:
The tag 'ComponentsConfiguration' contains an invalid number of components (3, expected 4).
The format variable contains: "The tag '%s' contains an invalid number of components (%i, expected %i)."
I couldn't check the values of the arguments (haven't found how to print them to check their values).
This works without any problems up to API30 (on the emulator).
On an image using API31 it crashes at the call of the vsprintf function.
Updating NDK to 25b doesn't fix either.
My API30 image is x86, the API31 image is x86_64.
Any idea to fix/workaround this?
Other parts of code that may be of interest:
#ifndef NO_VERBOSE_TAG_STRINGS
static void
exif_entry_log (ExifEntry *e, ExifLogCode code, const char *format, ...)
{
va_list args;
ExifLog *l = NULL;
if (e && e->parent && e->parent->parent)
l = exif_data_get_log (e->parent->parent);
va_start (args, format);
exif_logv (l, code, "ExifEntry", format, args);
va_end (args);
}
#else
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define exif_entry_log(...) do { } while (0)
#elif defined(__GNUC__)
#define exif_entry_log(x...) do { } while (0)
#else
#define exif_entry_log (void)
#endif
#endif
#define CC(entry,target,v,maxlen) \
{ \
if (entry->components != target) { \
exif_entry_log (entry, EXIF_LOG_CODE_CORRUPT_DATA, \
_("The tag '%s' contains an invalid number of " \
"components (%i, expected %i)."), \
exif_tag_get_name (entry->tag), \
(int) entry->components, (int) target); \
break; \
} \
}
// Then this call later
CC (e, 4, val, maxlen);
Update:
In the meantime since API30 images have x86 arch, and API31 images are x86_64 I just tried API30 with a x86_64. For now:
API 30 x86 → no crash in app
API 30 x86_64 → crash in app
API 31 x86_64 → crash in app
So this looks like it is x86 vs x86_64 emulator image related.
On a real arm8 device, there is no crash either.
I also found that the args passed to vsprintf don't have the expected values. And If a simulate vsprintf with the expected values, vsprintf works fine. So the problem is likely not vsprintf.
The cause of the problem was that I was using args twice: Once in vsprintf and once in vsprintf.
This is now allowed according to https://stackoverflow.com/a/10807375/15401262 and leads to undefined behavior.
It can't be used twice and one has to use va_copy in that case.

futimes function not present with API version 28 selected while cross compiling

I am trying to cross compile PuTTY utilities to run under Termux and despite using API level 28 it says the function 'futimes' is not present.
Here is where it gets stuck:
/home/xb/Desktop/android-ndk-r21d/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android28-clang -DHAVE_CONFIG_H -I. -I././ -I./charset/ -I./windows/ -I./unix/ -Wall -Werror -Wpointer-arith -Wvla -g -O2 -MT unix/uxsftpserver.o -MD -MP -MF $depbase.Tpo -c -o unix/uxsftpserver.o unix/uxsftpserver.c &&\
mv -f $depbase.Tpo $depbase.Po
unix/uxsftpserver.c:472:18: error: implicit declaration of function 'futimes' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
SETSTAT_GUTS(FD_PREFIX, fd, attrs, success);
^
You can browse the source file in question by downloading PuTTY source code version 0.74.
This page shows futimes was added in API version 26.
I am aware of the binary package for PuTTY avaliable in Termux's repo, I just want to learn how to cross compile.
The issue is that while we may have our minimum SDK version to be 26, we do not have the __USE_BSD macro defined, not adding the definition.
#if defined(__USE_BSD)
#if __ANDROID_API__ >= 26
int futimes(int __fd, const struct timeval __times[2]) __INTRODUCED_IN(26);
int lutimes(const char* __path, const struct timeval __times[2]) __INTRODUCED_IN(26);
#endif /* __ANDROID_API__ >= 26 */
#endif
sys/time.h source (same as above)
Looking deeper into where that macro is defined, we see this definition:
/*
* With bionic, you always get all C and POSIX API.
*
* If you want BSD and/or GNU extensions, _BSD_SOURCE and/or _GNU_SOURCE are
* expected to be defined by callers before *any* standard header file is
* included.
*
* In our header files we test against __USE_BSD and __USE_GNU.
*/
#if defined(_GNU_SOURCE)
# define __USE_BSD 1
# define __USE_GNU 1
#endif
#if defined(_BSD_SOURCE)
# define __USE_BSD 1
#endif
sys/cdefs.h source (same as above)
As a result, we must add either _GNU_SOURCE or _BSD_SOURCE as a compiler cFlag, which in gradle looks as such:
android {
compileSdkVersion 30
...
defaultConfig {
minSdkVersion 26
targetSdkVersion 30
...
externalNativeBuild {
cmake {
cFlags "-D_BSD_SOURCE" // or cFlags "-D_GNU_SOURCE"
...
}
}
}
It turns out that it is not necessarily guaranteed anywhere that NDK will use those flags, as shown by the comment in sys/cdefs.h. Instead, we have to provide the preprocessor macro definition ourselves.

Android - NDK strange error

I start getting funny errors with NDK with fairly complex program:
#include <stdio.h>
#include <iostream>
int main( int argc, char **argv ) {
return 0;
}
>call c:\android-ndk-r9\ndk-build.cmd
"Compile++ thumb : test <= test.cpp
In file included from C:/workspace/c++11_test//jni/test.cpp:11:
In file included from c:/android-ndk-r9/sources/cxx-stl/stlport/stlport\iostream:43:
In file included from c:/android-ndk-r9/sources/cxx-stl/stlport/stlport\stl/_istream.h:31:
In file included from c:/android-ndk-r9/sources/cxx-stl/stlport/stlport\stl/_ostream.h:380:
In file included from c:/android-ndk-r9/sources/cxx-stl/stlport/stlport\stl/_ostream.c:26:
In file included from c:/android-ndk-r9/sources/cxx-stl/stlport/stlport\stl/_num_put.h:180:
In file included from c:/android-ndk-r9/sources/cxx-stl/stlport/stlport\stl/_num_put.c:26:
c:/android-ndk-r9/sources/cxx-stl/stlport/stlport\stl/_limits.h:217:48: error: non-type template argument evaluates to -2147483648, which cannot be narrowed to type 'wchar_t'
[-Wc++11-narrowing]
: public _STLP_PRIV _Integer_limits<wchar_t, WCHAR_MIN, WCHAR_MAX, -1, true>
^
c:/android-ndk-r9/platforms/android-14/arch-arm/usr/include\../include/wchar.h:76:22: note: expanded from macro 'WCHAR_MIN'
#define WCHAR_MIN INT_MIN
^
c:/android-ndk-r9/platforms/android-14/arch-arm/usr/include\sys/limits.h:69:18: note: expanded from macro 'INT_MIN'
#define INT_MIN (-0x7fffffff-1) /* min value for an int */
^
1 error generated.
make: * [C:/workspace/c++11_test//obj/local/armeabi/objs/test/test.o] Error 1
It's ndk-r9. 4.8 complie it just fine, only clang stumbles on it.
Do I need to define something to make clang work?
I've tried to Google errors, but got nothing relevant...
Obviously, I can turn it off with -Wno-c++11-narrowing, but I don't want disable narrowing checks.
And it's only shows with stlport_static, there is NO error with gnustl_static
You appear to have enabled C++11, since you are getting this warning.
STLport support for C++11 is not very good. I suspect this is the reason for your woes.
A fix requires changes to STLport, or removing the "-std=c++11" switch from the clang command-line.
IMHO, I would recommend switching to the gnustl (aka. libstdc++), unless there are other reasons that prevent you from doing so (licensing: libstdc++ is GPL3 with some significant exceptions that may or may not be valid for clang - you should determine that for yourself), legacy support, size etc.). I have had very good experiences with that.

Android FAT APK: How to force to use ARMv7

I built FAT APK from hello-gl2 example from NDK examples.
It has 2 folders armeabi and armeabi-v7a
I added following method to it
JNIEXPORT jstring JNICALL Java_com_android_gl2jni_GL2JNILib_status(JNIEnv * env, jobject obj)
{
const char * result = "Hop";
#ifdef __ARM__
result = "__ARM__";
#endif
#ifdef __ARM_ARCH_5TE__
result = "__ARM_ARCH_5TE__";
#endif
#ifdef __ARM_ARCH_7A__
result = "__ARM_ARCH_7A__";
#endif
return env->NewStringUTF(result);
}
When app runs it calls that method and shows returned value in popup dialog.
When I run app on device with ARMv7 CPU I get __ARM_ARCH_5TE__ message instead of __ARM_ARCH_7A__
Then I delete armeabi folder in APK and re-install APK. I see __ARM_ARCH_7A__ message
If I compile armeabi-v7a only APK then I see __ARM_ARCH_7A__ and it does not work on ARMv6 device.
I wish to compile FAT APK that will run armeabi-v7a lib on ARMv7 CPU and armeabi on ARMv6 CPU.
What I am doing wrong or missing to do?
I'm guessing you are getting this Android ICS bug:
http://www.moodstocks.com/2012/03/20/ice-cream-sandwich-why-native-code-support-sucks/
https://groups.google.com/forum/#!msg/android-ndk/N8FLjvM81pg/2rYeClQZcckJ

Type could not be resolved in ndk

In android ndk when i use the header files that is generated by helper tool javah it works fine. but when i create a normal file with .h extension and include jni.h and any other required header files i am not able use the type or keyword or any functions from the included header files and it always shows me the "Type 'whatever' couldn't be resolved" while this same thing i can do in the machine generated header files with javah tools without any cause.
Though i've included arm platforms library in C/C++ General -> Paths and Symbols ->Include. it keeps showing me this error.
Consider the following piece of code.
#include "store.h"
#include <jni.h>
#include <stdint.h>
#include <pthread.h>
#ifndef _STOREWATCHER_H_
#define _STOREWATCHER_H_
#define SLEEP_DURATION 5
#define STATE_OK 0
#define STATE_KO 1
#ifdef __cplusplus
extern "C" {
#endif
typedef struct{
Store* mStore;
JavaVM* mJavaVM;
jobject mStoreFront;
pthread_t mThread;
int32_t mState;
}StoreWatcher;
#ifdef __cplusplus
}
#endif
#endif
it shows me in this code that Store, JavaVM, jobject, pthread_t couldn't be resolved. Please help me.
any kind of help will be appreciated.
In C, unlike Java, you have files with names like storewatcher.c and files with names like storewatcher.h. The .h files are not compiled on themselves, you must use #include directive in one or more .c files for the .h file to be recognized by the compiler, e.g.
#include "storewatcher.h"

Categories

Resources