Android C ++: необработанное исключение из загруженной общей библиотеки - PullRequest
0 голосов
/ 14 ноября 2018

Я новичок в stackoverflow и хочу обратиться за помощью к Android C ++.

Я пытаюсь реализовать очень простую тестовую программу Android на C ++, которая также вызывает функцию в загруженной разделяемой библиотеке, реализованной на C ++.

Вот моя основная реализация JNI (native-lib.cpp):

#include <jni.h>
#include <string>
#include <dlfcn.h>
#include "external.hpp"

extern "C" JNIEXPORT jstring JNICALL
Java_com_useless_myapplication_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    void* handle;
    void (*funcext)();
    handle = dlopen("libexternal.so",RTLD_LAZY);
    funcext = (void (*)(void))dlsym(handle, "_Z5func2v");
    try {
        funcext();
    }
    catch (MyException &err)
    {
        std::string hello = "MyException from C++";
        return env->NewStringUTF(hello.c_str());
    }
    catch (GenericException &err)
    {
        std::string hello = "GenericException from C++";
        return env->NewStringUTF(hello.c_str());
    }
    catch (GenericException* err)
    {
        std::string hello = "GenericException* from C++";
        return env->NewStringUTF(hello.c_str());
    }

    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

А вот моя libexternal.so реализация (external.cpp):

#include <jni.h>
#include <string.h>
#include "external.hpp"
GenericException::GenericException(){};
GenericException::GenericException(int errcode,char* msg)
{
        errorcode = errcode;
        memset(message,0,256);
        strcpy(message,msg);
}

MyException::MyException(int errcode,char* msg)
{
    errorcode = errcode;
    memset(message,0,256);
    strcpy(message,msg);
}

void func()
{
    throw MyException(10,"Error1!");
}
bool func3()
{
    try {
        func();
    }
    catch (GenericException &err)
    {
        return false;
    }
    return true;
}

void func2()
{
    if (!func3())
        throw MyException(11,"Error2!");
}

Файл external.hpp определяется следующим образом:

void func();
void func2();
bool func3();
class GenericException
{
    public:
    GenericException();
    GenericException(int errcode,char* msg);
    protected:
    int errorcode;
    char message[256];
};

class MyException : public GenericException
{
    public:
    MyException(int errcode,char* msg);
};

Программа компилирует и очищает ссылки, однако, когда я запускаю ее, приложение для Android вылетает со следующим сообщением в logcat :

2018-11-14 09:57:42.058 6519-6519/com.useless.myapplication A/libc: /usr/local/google/buildbot/src/android/ndk-release-r18/external/libcxx/../../external/libcxxabi/src/abort_message.cpp:73: abort_message: assertion "terminating with uncaught exception of type MyException" failed

Ошибка возникает, когда я пытаюсь выполнить external.cpp строку 41:

throw MyException(11,"Error2!");

Как подсказывают другие посты, которые я обнаружил, я пытался включить флаг -frtti в своем приложении build.gradle cppflgs, но это не решило ошибку.

Я пытался запустить тот же код (без честного верхнего уровня Java) на Linux и MacOS , но на этих платформах исключение отлавливается кодом native-lib.cpp .

Есть ли что-то, чего я не знаю об исключениях C ++ в Android? Как я могу поймать исключение, выданное библиотекой, которую я загрузил с dlopen на Android?

Спасибо

1 Ответ

0 голосов
/ 15 ноября 2018

Ваш тип исключения не имеет ключевой функции, поэтому его typeinfo передается с нечеткой связью .Означает, что это слабый символ в каждой библиотеке, в которой он используется.

Ваша библиотека JNI загружает и обрабатывает свою собственную информацию типа.Ваша загруженная библиотека затем загружается и также разрешает свою собственную информацию типа, поскольку она не может получить доступ к родительской области (System.loadLibrary использует RTLD_LOCAL).Из-за этого есть два отдельных объекта типа info для вашего типа исключения.Равенство RTTI проверяется путем сравнения адресов объекта typeinfo (см. Спецификацию C ++ ABI ).

Я не уверен, что это можно решить без прямой связи вашего кода JNI с libexternal.так.Если вы добавите ключевую функцию, необходимую для этой работы (которая будет определена в libexternal.so), то я считаю, что вам нужно будет ссылаться на нее, чтобы ваш код JNI связывался.

...