I am using "pthread_condattr_setclock" in one of my native shared library. Building is fine, but when I load the native library in android application using System.loadLibrary app is getting terminated throwing exception
failed: dlopen failed: cannot locate symbol "pthread_condattr_setclock" referenced by abcd.so
This exception I am not getting when I run my application in android 5.0, but in other android versions.
Anybody has any idea about this?
Android did use non-standard functions when it came to pthread_condattr functions. Even when the declarations for the standard ones are there in the pthread.h file of my NDK directory, Android complains about them not being defined if I use a version prior to API level 21 too.
Before Android 5.0, one could use other non-standard functions for waiting using the monotonic clock, for example (pthread_cond_timedwait_monotonic_np), but they have been removed in Android 5.0. I do not know why the functions don't work when they are declared and (AFAIK) are not officially unsupported, but it looks like the non-standard methods of the pthread_condattr family need to be used if on an Android version prior to 5.0.
See for example here.
Related
I have an App that uses a library with native libs and now in Android 11 is crashing due to fdsan.
I have contacted the library providers, but they are not going to deliver a new version of the library with this issue solved, so I need to be able to somehow disable fdsan.
I think the solution would be to call when I am on Android 11 or higher:
if(android_get_device_api_level()>=30)
android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
But I am unable to compile because of error:
use of undeclared identifier 'android_fdsan_set_error_level'
Because this was only added in Android 10 (API 29)
So my question is how can I call this function in my project?
I am creating a specific cpp file for this and a specific library for this, so I would need to some how for this library say that it is only for Android 10 or higher.
Is there some definition in the cpp file or in the Android.mk file that I can use to be able to compile this specific library that I will invoke from Java in Android 11 or higher only when my App starts?
According to the documentation here you should do it like this:
if (android_fdsan_set_error_level) {
android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
}
You will have to set your target SDK to 10 or above for this to work.
Alternatively, if you are compiling this in to a separate native binary, you can use conditional compilation.
Include this file.
Then do something like this:
#if __ANDROID_API__ >= __ANDROID_API_P__
android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
#endif
Just make sure this binary is never loaded on older devices, else the linker will give an error.
Depending on how your whole project is built, you may need to ship a separate APK for this in a bundle.
Finally, if all else fails, you may try using dlopen and dlsym to load the function dynamically at runtime, but you will need to find out which module exactly it is included in.
I've tried this library on plain Kotlin, it's working well. But when I've tried on Android, it doesn't work anymore. Why? What is the difference between codes that I wrote on Kotlin and Android/Kotlin? What is the connection between an API and Java library?
Error on Logcat:
java.lang.NoClassDefFoundError: Failed resolution of:
Ljava/time/LocalTime;
The line I got error is:
val current = LocalTime.now().hour
I've tried this library on plain Kotlin, it's working well. But when
I've tried on Android, it doesn't work anymore. Why?
Java 8 introduced new Date and time classes (and a lot of other utiility classes), previously developers mostly used Joda Time a third party library as the built-in java date classes where not reliable and limited in functionality. By default the java and kotlin compilers targets java 6 which is max supported upto android 25 (Nougat).
What is the connection between an API and Java library?
An api is built into the target device and alibrary has to be shipped with your app.
What is the difference between codes that I wrote on Kotlin and
Android/Kotlin
There is not much difference between the java and kotlin compiler, only the target jvm's. Though the kotlin compiler will usually compile code that will fail to run later as it heavily relies on annotations (which you setup)
Depending on your environment (target 6 or 8 for kotlin and java) and your devices (android version 25 and below or above 26) the code will have different classes available to it and setting the target jvm will allow consistancy across android versions.
I recently built libssh2 for Android using OpenSSL as a crypto backend, I also built libcrypto.so and libssl.so myself using the NDK.
In my build process I generate a final libcustom.so linked with libssh2.a.
Google said "If you tried to use your own copy of OpenSSL but forgot to bundle it with your app's APK, the app may run normally on versions of Android platform that includes libcrypto.so. However, the app could crash on later versions of Android that do not include this library (such as, Android 6.0 and later)." that's why I package libcrypto.so, libssl.so and libcustom.so into my APK.
When running an Android app that loads the libcustom.so, my app crashes with the following error:
failed: dlopen failed: cannot locate symbol "EVP_cast5_cbc" referenced by "libcustom.so"... ONLY ON ANDROID 5.
It works well on Android 6 and above.
The symbol EVP_cast5_cbc is undefined but referenced in libssh2.a, but well defined in libcrypto.so.
I don't understand why it runs correctly on Android 6 and above and not on Android 5.
I thought that on Android 5, the libcrypto.so used was not the one I embed in the APK but the one from /system/lib ; so I tried to rename the libcrypto.so and build libssh2.a using the libcrypto renamed, but I am facing the same issue.
Does anybody have an idea ?
Thank's in advance.
Google has changed the use of private libraries for Marshmallow and above; this may be the case that you are experiencing.
Starting in Android 6.0, the system prevents apps from dynamically linking against non-NDK libraries, which may cause your app to crash.
According to this table: https://developer.android.com/about/versions/nougat/android-7.0-changes.html#ndk. You should be able to see logcat warnings when you are running Lollipop with private libraries. For example:
03-21 17:07:51.502 31234 31234 W linker : library "libandroid_runtime.so"
("/system/lib/libandroid_runtime.so") needed or dlopened by
"/data/app/com.popular-app.android-2/lib/arm/libapplib.so" is not accessible
for the namespace "classloader-namespace" - the access is temporarily granted
as a workaround for http://b/26394120
After updating NDK to version 19 my application throws a UnsatisfiedLinkError with this message "Unable to load native library "/data/app/com.company.appname-SkXFrxADQ610MNjJr7Ak3A==/lib/arm64/libnative-activity.so": null" at start, and then terminates.
Anyone knows what is causing this error, and how to resolve it?
Notes:
1) When CMAKE_BUILD_TYPE is set to Debug, everything works fine, regardless of optimization (-O) level or DEBUG_MODE setting.
2) This did not happen prior to NDK 19
3) I do call app_dummy(), even though the call is deprecated and not necessary
4) The application uses android_native_app_glue.h/.c i.e no Java at all.
5) The exception libname is "native-activity", and funcname is "ANativeActivity_onCreate"
Update:
From the NDK r19 revision history Google says ndk-depends has been removed. We believe that ReLinker is a better solution to native library loading issues on old Android versions. I suppose this is relevant, guessing ndk-depends preserved the native activity, but as a native glue application does not contain any java code, how can I apply ReLinker from code?
fread_unlocked isn't available until Android P. You can't use that function in an app with a minSdkVersion lower than 28.
This shouldn't have compiled unless you've given CMake an incorrect ANDROID_PLATFORM, as the symbol wouldn't have been available to link against. If you're building your app with gradle and externalNativeBuild then gradle configures this for you based on your minSdkVersion. If you're not, you should probably switch to using it as it provides these safeguards.
I have a game that I am working on that uses the LibGDX game framework. Currently the platforms I am targeting are Desktop (PC, Mac, Linux) via a platform independent jar and Android.
The project is hosted at https://github.com/NoxHarmonium/project-whiplash Feel free to take a look if you need to.
The bulk of the code is in a module called core and is written entirely in Kotlin. This module is linked into both the Desktop and Android projects.
This works fine for Android versions 7.1+ and for desktop. For all other versions of Android I get a pile of java.lang.NoClassDefFoundError exceptions on anonymous functions such as this:
val objectObservable = this.observableCache.computeIfAbsent(assetRef, fun(assetRef: AssetRef): Observable<T> {
return Async.start(fun(): T {
...
}).observeOn(this.eventLoopScheduler)
})
Exception Sample:
java.lang.NoClassDefFoundError: com.projectwhiplash.utils.assets.LibGdxDataManager$objectMapFromYaml$objectMapObservable$1
It seems to be caused by an incompatibility with the JVM that Kotlin targets by default (1.8) and the JVM level that older versions of Android support (1.6). I could be wrong but this explains why the latest version of Android works as it supports a later version of the JVM.
The solution should be as simple as forcing Kotlin to emit JVM byte code as version 1.6 but I can't seem to work it out. If you compile Kotlin directly into an Android, this seems to be handled by using the kotlin-android Gradle plugin. Unfortunately I can't use this plugin for the core module because it should not have any Android dependencies.
I tried to override the JVM version using the build settings mentioned at https://kotlinlang.org/docs/reference/using-gradle.html#compiler-options like this:
compileKotlin {
kotlinOptions {
jvmTarget = "1.6"
}
}
However, it did not seem to work no matter which Gradle file I placed it in. In fact I get a "Cannot resolve symbol 'kotlinOptions'" error shown by Intellij when I try it. It is possible that the Kotlin team have changed something and the documentation has not been updated.
I can override the Kotlin settings manually in the Intellij module settings but it gets overridden every time I sync the gradle project and is not a good long term solution. The project is designed to be IDE independent.
Does anyone know how I could set up the core module for max compatibility with older versions of Android?
I currently have the minimum API level set to 9 as this is the current LibGDX default but I'm willing to set this higher if it would be too difficult to target such a low API level.
Edit 1:
I just extracted the jar file produced by the core module and examined the class files using the javap tool.
I ran the following command on a random class file
java -verbose foo.class
and it output text with the following text
...
minor version: 0
major version: 50
...
using this question List of Java class file format major version numbers? I determined that the class file is actually targeting JVM 1.6.
Therefore my original theory is wrong and there is another reason why older Android versions cannot load classes generated by Kotlin lambdas.
It looks like you are using functionality that only exists within the JDK 8 library. Specifically the computeIfAbsent() method on the Map class.
Because of this, even though your code has been compiled down to JVM 1.6 compatibility, the underlying implementation on Android devices is missing that functionality and thus the reason for the NoClassDefFoundError exception you were seeing.
Updated: You can see in the javadoc located at https://docs.oracle.com/javase/8/docs/api/java/util/Map.html#computeIfAbsent-K-java.util.function.Function- that the computeIfAbsent() has only been around since JDK 8