When I perform a throw command in my native library, my Android application crashes. Does Android not support these calls? It never reaches the catch.
try
{
__android_log_print(ANDROID_LOG_ERROR, "nativeLib", "throw");
throw;
}
catch (...) {
__android_log_print(ANDROID_LOG_ERROR, "nativeLib", "catch");
}
I recently switched from gnustl_shared to c++_shared, I'm not sure if this has anything to do with my problem.
Developer guides say that gnustl_shared has exceptions enabled by default, but c++_shared does not. I have included the -fexceptions flag as describe in the guide.
https://developer.android.com/ndk/guides/cpp-support.html
This is expected behavior. From the C++ standard:
If no exception is presently being handled, executing a throw-expression with no operand calls terminate()(15.5.1).
If you want it to catch you need to throw something:
try
{
__android_log_print(ANDROID_LOG_ERROR, "nativeLib", "throw");
throw new std::exception();
}
catch (...) {
__android_log_print(ANDROID_LOG_ERROR, "nativeLib", "catch");
env->ExceptionCheck();
}
It looks like this is a known issue:
https://developer.android.com/ndk/guides/cpp-support.html
Compatibility
The NDK's libc++ is not stable. Not all the tests pass, and the test suite is not comprehensive. Some known issues are:
•Using c++_shared on ARM can crash when an exception is thrown.
•Support for wchar_t and the locale APIs is limited.
Has this severe error been established as a official bug within the Android developer community? If not, it should. It is really a major, major flaw in the design. Catastrophic.
Related
I have an aar library that uses JNI and loads an .so using the below:
static {
try {
System.loadLibrary("Native_Thing");
} catch (UnsatisfiedLinkError var3) {
String nativeAbsolutePath = NativeNetworkMonitor.GetNativeLibraryAbsolutePath();
if (nativeAbsolutePath != null) {
String libAbsolutePath = nativeAbsolutePath + System.mapLibraryName("Native_Thing");
System.load(libAbsolutePath);
} else {
System.out.println("Native Library reference incorrect and no context set");
}
} catch (Exception var4) {
var4.printStackTrace();
}
}
This code works fine and dandy in Android 11. But for some reason in Android 12 it does not. The catch clause is entered and the error message states: "java.lang.UnsatisfiedLinkError: dlopen failed: "[...]/lib/x86_64/libNative_Thing.so" is for EM_X86_64 (62) instead of EM_AARCH64 (183)"
This error makes no sense to me. The emulator image is an Android 12 x86_64 image. But that error seems to be complaining about the .so being build for an x86_64 image and thinks it wants an .so built for arm64
I have confirmed that my applications APK contains all the ABI versions of the .so.
If I build the aar in a way that each ABI is a separate file and include the amd64 one in my application it works.
So in summary it seems like the Android 12 x86_64 emulator image is installed my applications APK with the x86_64 ABI .so as it should but then when it goes to actually load the .so for some reason the emulator thinks it wants an arm64 version
Upon further investigation it appears the issue is that the aar library that uses JNI is not 64 bit compatible. However, the above errors are still very confusing and irrelevant.
I was experimenting with CryptoPP library and I noticed it crashes in some cases, on investigating further, I saw that when it threw an exception, on linux it caught it too , but on android, it doesnt. So i made a very simple sanity check, here it is :
void random_test() {
LOGD("EXCEPTION : THROW ");
throw Exception();
}
And then I call it so :
try {
random_test();
} catch (Exception e ) {
LOGD("EXCEPTION CAUGHT");
}
It doesnt go to Exception caught.
This is the output from logcat:
2022-07-07 01:54:23.156 24102-24186/ D/JNIpart: EXCEPTION : THROW
2022-07-07 01:54:23.157 24102-24186/ E/libc++abi: terminating with uncaught exception of type cv::Exception
Then I tried this
try {
random_test();
} catch (...) {
LOGD("EXCEPTION CAUGHT");
}
And this catches the exception.
Now in CryptoPP library:
https://github.com/weidai11/cryptopp/blob/9ea66ce4d97d59d61e49c93f5af191107ebd1925/asn.cpp#L559
This is where exception is thrown, and when we try to catch it like this :
catch (const BERDecodeErr e)
{
LOGD("QRCPP : CATCH THE EXCEPTION FFS %s ", e.what());
}
And the code still crashes, even with this code :
catch (...)
{
LOGD("QRCPP : CATCH THE EXCEPTION FFS %s ", e.what());
}
The most common cause is exception types that are missing key functions. https://developer.android.com/ndk/guides/common-problems#rttiexceptions_not_working_across_library_boundaries
RTTI behaves differently in a plugin environment like JNI than it does in a typical executable. Without key functions, type info may not merge correctly depending on your exact library load order and symbol use. If they do not merged, they are different types according to the C++ ABI. Adding a key function to your classes ensures that a single definition of the typeinfo will be emitted and that no merging is required.
https://itanium-cxx-abi.github.io/cxx-abi/abi.html#vague-vtable
https://itanium-cxx-abi.github.io/cxx-abi/abi.html#rtti
Some platforms do not follow the C++ ABI, and allow two types to be equal if their type names match (as defined by strcmp). This can result in false positives, so Android follows the spec explicitly. aiui Apple does too. GNU is the only platform I know of that doesn't.
I'm a beginner on Android NDK, and less aware of C++. I have written some logic using C++ and then build them to .so file, then use it with JNI for my Android project, but sometimes it will raise crash in .so files.
I want to quickly fix this problem, I want to know if I can use try-catch syntax to my C++ code? (I tried, but it always reports compile error.) If yes, how can I do it?
C++ codes:
JNIEXPORT void JNICALL Java_xxoo_com_xxoo_model_ARDrawModel_draw(JNIEnv * env, jobject obj) {
try {
if(controller)
{
controller->Update(/*float dt*/);
controller->DrawGLScene();
}
} catch (int a) {
LOGD("drawModel---exception");
}
}
Compile error:
error: exception handling disabled, use -fexceptions to enable
Yes. you can use try catch in c++ NDK code, but it will not catch all native crashes.
And as your error says, you need to explicitly enable exceptions feature while compiling NDK code. To do so add
APP_CPPFLAGS += -fexceptions
to Application.mk file.
If you want to catch all possible NDK crashes check out https://github.com/xroche/coffeecatch library.
I have created a shared object for Android in Visual Studio 2015.
It works fine so far, but pop_back() for a wstring does not work:
wstring element = "JustATest!";
if (element.back() == L'!')
{
element.pop_back();
}
VS2015 tells me:
"no member named 'pop_back' in 'std::basic_string<wchar_t>'".
Can anybody tell me how to get rid of this error?
I have no idea why this should not work.
Is that because for some reason VS2015 does not use C++11 here?
Thank you for the help!
Edit: Another error:
When I try to use _wtoi, VS tells me: "use of undeclared identifier '_wtoi'.
Very very strange.
You need to turn on STL support. Turn on STL with Configuration Properties -> General -> Use of STL. Good options are LLVM libc++ static library (fewer features, more compatible with CLANG) and GNU STL static library (more features, I had an issue that required me to turn the CLANG optimizer to -Oz to prevent a segfault).
The title says it all. I'm using NDK to build a native library for use with Unity (the game engine, not the Ubuntu shell). I already have much of the code in place and it works on my Xperia Z Ultra which runs Android 4.4.4. However, recently I sent the app to some other people to test on their phones, and it worked on none of their phones. They were using Android 4.0 and 4.1, so I tried running the app on my own Android 4.0.4 device (an old Xperia Mini Pro) and had the same problem. After much narrowing down, I've found out that the root of the problem is including OpenCV in the build, even if it's not referenced at all.
Here's the code I have now. First, the simplest CPP file you've seen:
//Test.cpp:
extern "C"
{
int Test(int a, int b)
{
return a + b;
}
}
Note how it doesn't even include anything from OpenCV. The makefile (or whatever it's called in the context of NDK, I'm mostly a Windows/Visual Studio person) is:
#Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#---------------------------
#note: if I comment these lines out, the library works just fine.
#if I don't, it won't load at all.
#---------------------------
OPENCV_PACKAGE_DIR := D:\Eclipse\OpenCVAndroid\OpenCV-2.4.9-android-sdk
include $(OPENCV_PACKAGE_DIR)/sdk/native/jni/OpenCV.mk
LOCAL_MODULE := Test
LOCAL_SRC_FILES := Test.cpp
include $(BUILD_SHARED_LIBRARY)
Building this project gives me a "libTest.so" file. I put this into my Unity project, at Assets/Plugins/Android/ (I've also tried putting it in Plugins/Android/libs/armeabi-v7a/, no luck). I also have a script inside unity which invokes the library:
//TestNative.cs:
using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
public class TestNative : MonoBehaviour
{
[DllImport("Test")]
public static extern int Test(int a, int b);
void OnGUI()
{
try
{
GUI.Label(new Rect(0, 0, 100, 100), "2 + 3 = " + Test(2, 3));
}
catch (System.Exception e)
{
GUI.Label(new Rect(0, 0, 600, 400), e.GetType().ToString() + " " + e.Message + "\n" + e.StackTrace);
}
}
}
When I run this on my Z Ultra, it works just fine. When I run it on the Mini Pro, it fails with the exception "DllNotFoundException: Test". I've checked logcat for errors, and this is what it says:
01-06 06:46:27.660: D/dalvikvm(11135): Trying to load lib /mnt/asec/com.cet.sna2-2/lib/libTest.so 0x2bb86638
01-06 06:46:27.660: D/dalvikvm(11135): Trying to load lib /mnt/asec/com.cet.sna2-2/lib/libTest.so 0x2bb86638
01-06 06:46:27.660: E/Unity(11135): Unable to find Test
It doesn't say anything else, it just fails. The fact that it works on 4.4.4 makes me think it might have something to do with build configurations or something like that, but I can't figure out what it is. Any ideas? Thanks.
I found out, after much trial and error, that the reason for the error is that Android somehow manages to mess the library dependencies up. The work-around is to manually load the libraries in the specific order of their dependencies, using LoadLibrary. This can be done in Unity using AndroidJavaClass to avoid having to write an entire jar library just for loading the native ones.
You have to build a .so that correspond to the architecture of the device your are using.
You should look at this link :
https://developer.nvidia.com/AndroidWorks
It provides useful tools to develop on Android with Visual Studio
You can easily configure an Android Dynamic Library (.so) that correspond to the architecture you need :)