LINUX.ORG.RU

Не работает JNI-код в Qt 5.11, но нормально работает в 5.9 и 5.10

 , ,


0

2

ПРОБЛЕМА

Мой код, который работает на Android, будучи скомпилированным на:

Qt 5.9.2 и
Qt 5.10.1,

не работает на Android, если компиляция была сделана на:

Qt 5.11.2


КОД

Я сделал код минимального примера: http://rgho.st/7t6YyyQdB

В нем используется немного измененный код пользователя EXL, взятый отсюда: https://github.com/EXLMOTODEV/QmlDestroyTest

То есть, код EXL нормально работает на всех Qt, включая Qt 5.11.

А мой код минимального примера работает на Qt 5.9 и Qt5.10, но не работает на Qt 5.11.

Поэтому на Qt 5.11 не грешу, грешу на свои кривые руки. Однако понять, почему так получается не могу.


ПОДРОБНОСТИ

В коде используется демонстрация вызовов по JNI. Проблемный код лежит в файле /android/src/ru/farwater/gnss/farwaterma/JniEventActivity.java и выглядит так:

    @Override
    public void onStart() {
        Log.w(TAG, "onStart() called!");
        NativeHelper.invokeVoidMethod(100);
        super.onStart();
    }

На Qt 5.9 и Qt 5.10 он отрабатывает, показывая такой лог:
W JniEventActivity: onStart() called!
E HAL     : load: id=gralloc != hmi->id=gralloc
I OpenGLRenderer: Initialized EGL, version 1.4
I HwSecImmHelper: mSecurityInputMethodService is null
...

А на Qt 5.11 получается такая ошибка:
W JniEventActivity: onStart() called!
E art     : No implementation found for
void ru.farwater.gnss.farwaterma.NativeHelper.invokeVoidMethod(int)
(tried Java_ru_farwater_gnss_farwaterma_NativeHelper_invokeVoidMethod 
and
Java_ru_farwater_gnss_farwaterma_NativeHelper_invokeVoidMethod__I)
I Process : Sending signal. PID: 7227 SIG: 9

Где я накосяпорил?

★★★★★

Последнее исправление: Xintrea (всего исправлений: 1)

Чет у тебя минимальный пример - больше, чем последняя кодовая база, которую при мне за пару мультов продали :)

По теме - у тебя в логе ошибка. Код EXL тоже к такой приводит? В общем и целом, выглядит так, будто библиотека не подгружается, попробуй ldd выполнить(если он есть под андроид), для библиотеки и её зависимостей на целевой платформе.

onhydro
()
Ответ на: комментарий от onhydro

Там три микроскопических C++ класса, которые образуют костяк приложения.

Нет, код EXL к такой ошибке не приводит ни на одном из Qt, об этом и речь.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Я про вот такой вот лог:

E HAL : load: id=gralloc != hmi->id=gralloc

Там три микроскопических C++ класса, которые образуют костяк приложения.

Хорошо, что не 5, и что не надо себе в хомяк какие то непонятные архивы класть. А, нет, надо...

onhydro
()
Ответ на: комментарий от Xintrea

Мой lmgtfy говорит, что таки надо смотреть есть ли на устройстве нужный рантайм(плагины Qt крайне любят не взлетать если в системе отсутствует нужная версия библиотеки). Второй вариант некая очепятка в интерфейсных файлах, которую ты нагрепаешь быстрее, чем я скачаю архив.

Можно ещё погрепать выхлоп nm (без --demangle) на предмет нужного символа в бинаре.

onhydro
()
Ответ на: комментарий от onhydro

Чтобы запустить ldd в каталоге приложения, надо в этот каталог перейти. А без рутования этого никак не сделать. А у меня нет ни одного рутованного устройства.

Ошибка говорит о том, что по какойто причине не находится сигнатура вызываемого метода. Причем метод этот - часть приложения, что совсем загадочно.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

ldd можно в любой директории запускать, по крайней мере на православных онтопиках.

Может всё же опечатка?

grep invokeVoidMethod -r --include "*.cpp"

onhydro
()
Ответ на: комментарий от Xintrea

Опечатка не обьясняет как оно работает под другой версией Qt.

Ну тогда только nm(надо брать тот, который в ndk, если он там есть) приходит на ум:

nm /path/to/native/library/on/localhost | grep -E "Java_ru_farwater_gnss_farwaterma_NativeHelper_invokeVoidMethod|Java_ru_farwater_gnss_farwaterma_NativeHelper_invokeVoidMethod__I"

Если nm нет, то можно использовать `objdump -x`.

onhydro
()
Ответ на: комментарий от onhydro

Завтра отвечу, целевоой машины нет под рукой.

Как опечатка может работать на 5.9 и 5.10, и не работать на 5.11 ?

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от onhydro

Я сделал логи компиляции и логи запуска для Qt 5.9 и Qt 5.11 (для Qt 5.10 нет, потому что он стоит на другой машине на другом конце города).

Файлы: http://rgho.st/7YRFdCXsp

Номера версий Qt в тексте заменены на «v» чтобы легче было диффить.

Я увидел только три принципиальных отличия:

1.

Qt 5.9 использует системный make:

/usr/bin/make

А Qt 5.11 использует make из комплекта Android:
/opt/android/android-ndk-r16/prebuilt/linux-x86_64/bin/make


2.

Qt 5.11 при инсталляции программы на устройство выполняет команду по установке некоего файла linker, а Qt 5.9 никакого линкера не добавляет:
12:39:56: Установка пакета: 
Выполнение команды «/opt/android/platform-tools/adb 
-s X9L0214930005121 
pull /system/bin/linker 
/home/xi/...../build-JniSample-Android_armeabi_v7a_GCC_4_9_Qt_Qt_v_for_Android_ARMv7-Debug/linker».


3.

При запуске программы Qt 5.9, перед отладочным сообщением:
W JniEventActivity: onStart() called!

есть строка, которая показывает, что линкер обработал библиотеку самой программы libJniSample.so:
W linker  : /data/app/ru.farwater.gnss.farwaterma-2/lib/arm/libJniSample.so: unused DT entry: type 0x1d arg 0x1b3b

А при запуске программы Qt 5.11 этой строки нет. То есть, такое впечатление, что в момент вызова проблемной функции сама библиотека с этой функцией libJniSample.so еще не подгружена. Возможно, что в этом проблема, но я не знаю как на это можно повлиять.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от onhydro

Ну тогда только nm(надо брать тот, который в ndk, если он там есть) приходит на ум:
nm /path/to/native/library/on/localhost | grep -E «Java_ru_farwater_gnss_farwaterma_NativeHelper_invokeVoidMethod|Java_ru_farwater_gnss_farwaterma_NativeHelper_invokeVoidMethod__I»
Если nm нет, то можно использовать `objdump -x`.

Для Qt 5.9 и Qt 5.11 вывод команд для so-шников libJniSample.so абсолютно одинаковый:

00005024 T Java_ru_farwater_gnss_farwaterma_NativeHelper_invokeVoidMethod
000074cc r _ZZ62Java_ru_farwater_gnss_farwaterma_NativeHelper_invokeVoidMethodE19__PRETTY_FUNCTION__

То есть, функция имеется, она вкомпилена, и с этой сигнатурой нормально отрабатывается в Qt 5.9.

Видимо, действительно проблема у Qt 5.11 в последовательности подгрузки so-шника libJniSample.so, который на момент вызова функции не подгружен, о чем я написал выше.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от onhydro

Кстати, пример EXL тоже не работает на Qt 5.11, если в файл QmlDestroyTest.java добавить код, вызываемый при старте:

    @Override
    public void onStart() {
        Log.w(TAG, "onStart() called!");
        NativeHelper.invokeVoidMethod(100);
        super.onStart();
    }

У него этого кода не было, поэтому сегфолта тоже не было.

В общем, пока я делаю вывод, что в Qt 5.11 по каким-то причинам делается такая сборка, которая вызывает Java-код, не дожидаясь подгрузки всех библиотек.

Зачем так сделали - непонятно. Как будто забыли о том, что есть JNI, и что из Java может быть вызван нативный код даже на этапе развертывания приложения в памяти.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от fluorite

Похоже на то, добавил свои пять копеек.

Xintrea ★★★★★
() автор топика

Скажи, а вот таким образом можно что-то добавить в Java-часть, и затем дернуть ее из Qt на Android? Некую функцию, чтобы периодически по таймеру смотреть что там в Java-части принялось.

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от I-Love-Microsoft

Конечно можно. Хоть из C++ дергать Java, хоть наоборот. В примере все есть.

Xintrea ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.