LINUX.ORG.RU

Создание фиктивного провайдера местоположения в Qt/QML - Странный сегфолт в Java

 , , , ,


0

1

На основании обсуждения в теме «Самописный провайдер навигационных данных под Android - возможно ли такое?»...

Взяв за основу статью «Тестирование приложений в Android с использованием фиктивных данных о местоположении»...

Я сделал следующий проект:

https://github.com/xintrea/fakeLocationProviderOnQt

Он нужен мне для проверки того, может ли провайдер, созданный через метод addTestProvider(), поставлять данные геолокации для всей ОС Android (т. е. не только для приложения, в котором он запущен).

Проект должен быть на Qt/QML, поэтому вызовы Java-кода делаются через JNI. В данном примере есть просто две кнопки (Setup и Update), и при нажатии на каждую вызывается следующий Java-код:

    // Инициализация фиктивного провайдера
    public void setupFakeLocationProvider() {
        Log.w(TAG, "Java: setupFakeLocationProvider start");

        if(this==null) {
            Log.w(TAG, "For JniEventActivity this is null");
            return;
        }

        // Создание экземпляра класса MockLocationProvider
        // с контекстом данной Активности
        mock = new MockLocationProvider(LocationManager.GPS_PROVIDER, this);
        Log.w(TAG, "After new MockLocationProvider");

        //Set test location
        mock.pushLocation(45.0, 45.0);
        Log.w(TAG, "After mock.pushLocation");

        Log.w(TAG, "Java: setupFakeLocationProvider stop");
    }


    // Обновление значений координат в фиктивном провайдере
    public void updateFakeLocationProvider() {
        Log.w(TAG, "Java: updateFakeLocationProvider");
        // Пока ничего этот код не делает
    }
Вот это место в самом проекте: https://github.com/xintrea/fakeLocationProviderOnQt/blob/bdb675186094402a37c0...

Проблема в том, что при выполнении метода setupFakeLocationProvider(), выводится только строчка:
Java: setupFakeLocationProvider start

и больше строчек нет. Но сегфолта сразу не происходит, приложение как будто продолжает работать. И если нажать вторую кнопку, то выполнится метод updateFakeLocationProvider(), появится строка:
Java: updateFakeLocationProvider

и после этого произойдет сегфолт:
Core::setupFakeLocationProvider()): setupFakeLocationProvider from C++
W JniEventActivity: Java: setupFakeLocationProvider start
W libJniFakeLocationSample.so: ../JniFakeLocationSampleSrc/src/core/Core.cpp:119 (void Core::updateFakeLocationProvider()): updateFakeLocationProvider from C++
F art     : art/runtime/java_vm_ext.cc:410] JNI DETECTED ERROR IN APPLICATION: JNI CallVoidMethodV called with pending exception java.lang.IllegalStateException: System services not available to Activities before onCreate()
F art     : art/runtime/java_vm_ext.cc:410]   at java.lang.Object android.app.Activity.getSystemService(java.lang.String) (Activity.java:5381)
F art     : art/runtime/java_vm_ext.cc:410]   at void ru.farwater.gnss.fakelocsample.MockLocationProvider.<init>(java.lang.String, android.content.Context) (MockLocationProvider.java:16)
F art     : art/runtime/java_vm_ext.cc:410]   at void ru.farwater.gnss.fakelocsample.JniEventActivity.setupFakeLocationProvider() (JniEventActivity.java:91)
F art     : art/runtime/java_vm_ext.cc:410]   at void org.qtproject.qt5.android.QtNative.startQtApplication() (QtNative.java:-2)
F art     : art/runtime/java_vm_ext.cc:410]   at void org.qtproject.qt5.android.QtNative$6.run() (QtNative.java:359)
F art     : art/runtime/java_vm_ext.cc:410]   at void org.qtproject.qt5.android.QtThread$1.run() (QtThread.java:61)
F art     : art/runtime/java_vm_ext.cc:410]   at void java.lang.Thread.run() (Thread.java:833)
F art     : art/runtime/java_vm_ext.cc:410]
F art     : art/runtime/java_vm_ext.cc:410]     in call to CallVoidMethodV
F art     : art/runtime/java_vm_ext.cc:410]     from void org.qtproject.qt5.android.QtNative.startQtApplication()
F art     : art/runtime/java_vm_ext.cc:410] "qtMainLoopThread" prio=5 tid=10 Runnable
Полный текст ошибки: https://pastebin.com/D4SxRyYm

Насколько я понимаю, главная проблема в том, что «System services not available to Activities before onCreate()».

Она возникает в конструкторе класса MockLocationProvider на строке:
LocationManager lm = (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE);

Вот это место в коде: https://github.com/xintrea/fakeLocationProviderOnQt/blob/bdb675186094402a37c0...

Люди в интернете говорят, что проблема может быть из-за того, что переменная ctx (в которую передается указатель на текущую Activity) просто не определена, так как у активности еще не вызван метод onCreate(): https://ru.stackoverflow.com/questions/448723/Ошибка-java-lang-illegalstateex...

Но в данном случае у меня активность создается задолго до того, как пользователь будет нажимать на кнопки для вызова Java-кода.

В общем, в чем может быть проблема, как ее исправить?

★★★★★

Ответ на: комментарий от Moondancer

Я уже декомпилил два проекта. Нихрена не пойму как там провайдер подменяется. Видимо, я не то ищу. В гуглах и яндексах нигде методику как подменять провайдера геолокации найти не могу.

Xintrea ★★★★★ ()

Это или это:

mock = new MockLocationProvider(LocationManager.GPS_PROVIDER, this);

LocationManager lm = (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE);

Должно быть в onCreate(), а не где-то там, непонятно где.

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

Должно быть в onCreate(), а не где-то там, непонятно где.

Перенес создание экземпляра класса MockLocationProvider в onCreate() той же Активности:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.w(TAG, "onCreate() called!");

        this.setVolumeControlStream(AudioManager.STREAM_MUSIC);

        super.onCreate(savedInstanceState);

        // Создание экземпляра класса MockLocationProvider
        // в контексте данной Активности
        // Log.w(TAG, "Before MockLocationProvider create");
        // mock = new MockLocationProvider(LocationManager.GPS_PROVIDER, this);
        // Log.w(TAG, "After MockLocationProvider create");

        Log.w(TAG, "onCreate() success finished");
    }


Так вот, если запустить с закомментированным кодом создания экземпляра, то программа стартует нормально. И видно, что метод onCreate() вызывается очень рано, еще до момента, когда проинициализируются основные системы, такие как:
I Qt      : qt started
...
I QtPositioning: Positioning start
...
I Qt      : Sensors start

А завершается onCreate() после момента «I Qt : Sensors start» (через строчку ниже).

Вот лог запуска, вызов onCreate() идет на 4-й строчке:
I art     : Late-enabling -Xcheck:jni
E HAL     : load: id=gralloc != hmi->id=gralloc
I HwCust  : Constructor found for class android.app.HwCustHwWallpaperManagerImpl
W JniEventActivity: onCreate() called! <----------------
W System  : ClassLoader referenced unknown path:
I QtCore  : Start
W linker  : /data/app/ru.farwater.gnss.fakelocsample-2/lib/arm/libQt5Network.so: unused DT entry: type 0x1d arg 0x143a2
...
W linker  : /data/data/ru.farwater.gnss.fakelocsample/qt-reserved-files/plugins/platforms/android/libqtforandroid.so: unsupported flags DT_FLAGS_1=0x81
I Qt      : qt started
W linker  : /data/data/ru.farwater.gnss.fakelocsample/qt-reserved-files/plugins/bearer/libqandroidbearer.so: unused DT entry: type 0x1d arg 0x1711
...
W linker  : /data/data/ru.farwater.gnss.fakelocsample/qt-reserved-files/plugins/position/libqtposition_android.so: unsupported flags DT_FLAGS_1=0x81
I QtPositioning: Positioning start
W linker  : /data/data/ru.farwater.gnss.fakelocsample/qt-reserved-files/plugins/sensors/libqtsensors_android.so: unused DT entry: type 0x1d arg 0x10ac
...
W linker  : /data/data/ru.farwater.gnss.fakelocsample/qt-reserved-files/plugins/sensors/libqtsensors_android.so: unsupported flags DT_FLAGS_1=0x81
I Qt      : Sensors start
I HwSecImmHelper: mSecurityInputMethodService is null
W JniEventActivity: onCreate() success finished <----------------
W JniEventActivity: onStart() called!
E HAL     : load: id=gralloc != hmi->id=gralloc
I OpenGLRenderer: Initialized EGL, version 1.4
W linker  : /data/app/ru.farwater.gnss.fakelocsample-2/lib/arm/libJniFakeLocationSample.so: unused DT entry: type 0x1d arg 0x1a84
I HwSecImmHelper: mSecurityInputMethodService is null
W linker  : /data/data/ru.farwater.gnss.fakelocsample/qt-reserved-files/plugins/styles/libqandroidstyle.so: unused DT entry: type 0x1d arg 0x44b9
W linker  : /data/data/ru.farwater.gnss.fakelocsample/qt-reserved-files/plugins/styles/libqandroidstyle.so: unsupported flags DT_FLAGS_1=0x81
W libJniFakeLocationSample.so: ../JniFakeLocationSampleSrc/src/helpers/KeepAwakeHelper.cpp:48 (void KeepAwakeHelper::on()): Locked device, can't go to standby anymore
W linker  : /data/data/ru.farwater.gnss.fakelocsample/qt-reserved-files/qml/QtQuick.2/libqtquick2plugin.so: unused DT entry: type 0x1d arg 0x4de
...
W linker  : /data/data/ru.farwater.gnss.fakelocsample/qt-reserved-files/qml/QtQuick/Controls/libqtquickcontrolsplugin.so: unsupported flags DT_FLAGS_1=0x81
W libJniFakeLocationSample.so: ../JniFakeLocationSampleSrc/src/core/Core.cpp:52 (void Core::appActivation()): On activation actions


А если строчки создания экземпляра MockLocationProvider раскомментировать, то программа сегфолтится вот с таким логом:
I art     : Late-enabling -Xcheck:jni
E HAL     : load: id=gralloc != hmi->id=gralloc
I HwCust  : Constructor found for class android.app.HwCustHwWallpaperManagerImpl
W JniEventActivity: onCreate() called! <----------------
W System  : ClassLoader referenced unknown path:
I QtCore  : Start
W linker  : /data/app/ru.farwater.gnss.fakelocsample-1/lib/arm/libQt5Network.so: unused DT entry: type 0x1d arg 0x143a2
...
W linker  : /data/data/ru.farwater.gnss.fakelocsample/qt-reserved-files/plugins/platforms/android/libqtforandroid.so: unsupported flags DT_FLAGS_1=0x81
I Qt      : qt started
W linker  : /data/data/ru.farwater.gnss.fakelocsample/qt-reserved-files/plugins/bearer/libqandroidbearer.so: unused DT entry: type 0x1d arg 0x1711
...
W linker  : /data/data/ru.farwater.gnss.fakelocsample/qt-reserved-files/plugins/position/libqtposition_android.so: unsupported flags DT_FLAGS_1=0x81
I QtPositioning: Positioning start
W linker  : /data/data/ru.farwater.gnss.fakelocsample/qt-reserved-files/plugins/sensors/libqtsensors_android.so: unused DT entry: type 0x1d arg 0x10ac
W linker  : /data/data/ru.farwater.gnss.fakelocsample/qt-reserved-files/plugins/sensors/libqtsensors_android.so: unsupported flags DT_FLAGS_1=0x81
I Qt      : Sensors start
I HwSecImmHelper: mSecurityInputMethodService is null
W JniEventActivity: Before MockLocationProvider create
I Process : Sending signal. PID: 21030 SIG: 9

То есть, создание MockLocationProvider происходит после всех основных инициализаций, после «I Qt : Sensors start». Но все равно имеем сегфолт. Весь используемый код - только Java, никаких Qt-объектов не используется при инициализации MockLocationProvider. Тем не менее, код не работает.

Я пробовал передвинуть вызов метода базового класса в конец onCreate():
super.onCreate(savedInstanceState);

чтобы он выполнялся после инициализации MockLocationProvider. Но тогда программа вообще не может запуститься и ни одного символа в консоль не выдает.

Видимо, в super.onCreate() и происходит вся портянка инициализаций. И по-хорошему, создание MockLocationProvider надо делать после нее, как и написано в начале сообщения. Но даже если и делать после super.onCreate(), то код не работает.

Xintrea ★★★★★ ()

@Xintrea

Было время, посмотрел проблему и сделал вот такой вот прототип приложения:

https://github.com/EXLMOTODEV/QmlDestroyTest/tree/mock_location

git clone https://github.com/EXLMOTODEV/QmlDestroyTest/
git checkout mock_locations

Кода много там осталось от старого проекта, не было времени чистить. Но, в общем, оно работает и подставляемые программой данные у меня подхватываются из приложения Google Maps. Разбирайся. Чтобы операционная система не тушила приложение при нехватке памяти, можно вынести код в специальный сервис, по типу того что у меня было сделано в этом проекте. Удачи.

если смочь решить эту головоломку, и получится сделать фиктивного провайдера на Qt/QML, то таковая консультация будет оплачена.

Напишите мне насчёт этого, например, на почту или (лучше) в Telegram. Мои контактные данные в профиле.

EXL ★★★★★ ()
Последнее исправление: EXL (всего исправлений: 1)
Ответ на: комментарий от EXL

Напишите мне насчёт этого, например, на почту или (лучше) в Telegram. Мои контактные данные в профиле.

Ага, хорошо. В понедельник свяжусь с вами.

Я не понял вот какого момента. Чтобы код продолжал работать и при переключении на другую программу (на тот эе Google Maps) его надо оформить как service. Тем не менее, я не увидел в AndroidManifest.xml описания сервиса.

За счет чего ваш QmlDestroyTest работает в фоне? Или он не работает в фоне, а только подменяет координаты в момент, когда активно его окно?

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

Я не понял вот какого момента. Чтобы код продолжал работать и при переключении на другую программу (на тот эе Google Maps) его надо оформить как service. Тем не менее, я не увидел в AndroidManifest.xml описания сервиса.

Я написал об этом и привёл ссылку на простенький пример (который, правда, без Qt). Я не оборачивал QmlDestroyTest в Service, если есть желание – сделайте это сами, там ничего сложного быть не должно по идее.

За счет чего ваш QmlDestroyTest работает в фоне? Или он не работает в фоне, а только подменяет координаты в момент, когда активно его окно?

Он работает в фоне. Но только до тех пор, пока на устройстве достаточно памяти или пока юзер не вышел из приложения по кнопке Back или не закрыл его в Recent Apps.

EXL ★★★★★ ()
Последнее исправление: EXL (всего исправлений: 1)
Ответ на: комментарий от EXL

Он работает в фоне. Но только до тех пор, пока на устройстве достаточно памяти или пока юзер не вышел из приложения по кнопке Back или закрыв его в Recent Apps.

А за счет чего он работает в фоне? У меня QML-приложения останавливаются системой при помещении их в список запущенных приложений (кнопка с кружочком). Успевают только onDestriy() или onStop() для базовой активности отработать.

Xintrea ★★★★★ ()
Последнее исправление: Xintrea (всего исправлений: 1)
Ответ на: комментарий от Xintrea

Ты проверь прежде. Там код в отдельной задаче и он не особо связан с Activity, ему на onStop() всё равно. Не всё равно ему лишь на убийство процесса юзером (кнопка Back) или на убийство процесса операционной системой Android.

EXL ★★★★★ ()
Последнее исправление: EXL (всего исправлений: 1)
Ответ на: комментарий от EXL

Про QmlDestroyTest в ветке mock_locations.

Добрался я до компа, клонирую:

$ git clone https://github.com/EXLMOTODEV/QmlDestroyTest/
$ git checkout mock_locations
error: pathspec 'mock_locations' did not match any file(s) known to git.

А ветки этой нету. Ничего не понял.

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

Ага, увидел.

GitHub вообще себя странно ведет. Вроде как раньше при нажатии fork форкались все ветки основного репозитария. Теперь же форкается только master-ветка. И даже если в начальном репозитарии переключиться на ветку mock_location, и нажать fork, то форк будет только с веткой master.

В клоне основного репозитария имеем:

$ git branch --all
  master
* mock_location
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/mock_location


В клоне форка имеем:
$ git branch --all
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master


Раньше народ был озабочен как убрать лишние ветки после форка:

https://ru.stackoverflow.com/questions/713632/Как-на-github-форкнуть-только-с...

Теперь получается, проблема получить нужные ветки в форке. Пока не понял как это делать.

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

GitHub вообще себя странно ведет. Вроде как раньше при нажатии fork форкались все ветки основного репозитария. Теперь же форкается только master-ветка.

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

Либо удалите репозиторий и форкните его заново, либо настройте upstream и синхронизируйтесь:

https://help.github.com/articles/configuring-a-remote-for-a-fork/
https://help.github.com/articles/syncing-a-fork/

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

В общем, собрал я проект mock_location на Qt 5.11.2.

На реальном устройстве программа не запускается, полный лог такой:

I art     : Late-enabling -Xcheck:jni
E HAL     : load: id=gralloc != hmi->id=gralloc
I HwCust  : Constructor found for class android.app.HwCustHwWallpaperManagerImpl
W System  : ClassLoader referenced unknown path:
I QtCore  : Start
W linker  : /data/app/ru.exlmoto.qmldestroytest-1/lib/arm/libQt5Network.so: unused DT entry: type 0x1d arg 0x143a2
W linker  : /data/app/ru.exlmoto.qmldestroytest-1/lib/arm/libQt5Network.so: unsupported flags DT_FLAGS_1=0x81
W linker  : /data/app/ru.exlmoto.qmldestroytest-1/lib/arm/libQt5Qml.so: unused DT entry: type 0x1d arg 0x32dd0
W linker  : /data/app/ru.exlmoto.qmldestroytest-1/lib/arm/libQt5Qml.so: unsupported flags DT_FLAGS_1=0x81
W linker  : /data/app/ru.exlmoto.qmldestroytest-1/lib/arm/libQt5Gui.so: unused DT entry: type 0x1d arg 0x56805
W linker  : /data/app/ru.exlmoto.qmldestroytest-1/lib/arm/libQt5Gui.so: unsupported flags DT_FLAGS_1=0x81
W linker  : /data/app/ru.exlmoto.qmldestroytest-1/lib/arm/libQt5Quick.so: unused DT entry: type 0x1d arg 0x4bb50
W linker  : /data/app/ru.exlmoto.qmldestroytest-1/lib/arm/libQt5Quick.so: unsupported flags DT_FLAGS_1=0x81
W linker  : /data/app/ru.exlmoto.qmldestroytest-1/lib/arm/libQt5AndroidExtras.so: unused DT entry: type 0x1d arg 0x6f8e
W linker  : /data/app/ru.exlmoto.qmldestroytest-1/lib/arm/libQt5AndroidExtras.so: unsupported flags DT_FLAGS_1=0x81
W linker  : /data/app/ru.exlmoto.qmldestroytest-1/lib/arm/libQt5QuickParticles.so: unused DT entry: type 0x1d arg 0x5593
W linker  : /data/app/ru.exlmoto.qmldestroytest-1/lib/arm/libQt5QuickParticles.so: unsupported flags DT_FLAGS_1=0x81
W linker  : /data/app/ru.exlmoto.qmldestroytest-1/lib/arm/libQt5QuickTemplates2.so: unused DT entry: type 0x1d arg 0x24512
W linker  : /data/app/ru.exlmoto.qmldestroytest-1/lib/arm/libQt5QuickTemplates2.so: unsupported flags DT_FLAGS_1=0x81
W linker  : /data/app/ru.exlmoto.qmldestroytest-1/lib/arm/libQt5QuickControls2.so: unused DT entry: type 0x1d arg 0x87a4
W linker  : /data/app/ru.exlmoto.qmldestroytest-1/lib/arm/libQt5QuickControls2.so: unsupported flags DT_FLAGS_1=0x81
W linker  : /data/data/ru.exlmoto.qmldestroytest/qt-reserved-files/plugins/platforms/android/libqtforandroid.so: unused DT entry: type 0x1d arg 0x8d40
W linker  : /data/data/ru.exlmoto.qmldestroytest/qt-reserved-files/plugins/platforms/android/libqtforandroid.so: unsupported flags DT_FLAGS_1=0x81
I Qt      : qt started
W linker  : /data/data/ru.exlmoto.qmldestroytest/qt-reserved-files/plugins/bearer/libqandroidbearer.so: unused DT entry: type 0x1d arg 0x1711
W linker  : /data/data/ru.exlmoto.qmldestroytest/qt-reserved-files/plugins/bearer/libqandroidbearer.so: unsupported flags DT_FLAGS_1=0x81
I HwSecImmHelper: mSecurityInputMethodService is null
I Process : Sending signal. PID: 9835 SIG: 9

В режиме дебага понять где останавливается не могу, потому что нет даже стектрейса.

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