LINUX.ORG.RU

Qt Android Services. Служба запускается, но main не является точкой входа?! Почему?

 , ,


0

1

Добрый день, ув. форумчане!

Разбираюсь с запуском служб Android в Qt. Делаю согластно документации: https://doc.qt.io/qt-5/android-services.html

Служба стартует вызовом QAndroidJniObject::callStaticMethod, статического метода в классе наследуемом от QtService:

// DemoService.java
public class DemoService extends QtService
{
    public static void startDemoService(Context ctx) {
        Intent intent = new Intent(ctx, DemoService.class);
        ctx.startService(intent);
    }
}

Компилирую в одну общую библиотеку .so. В документации сказано:

Qt loads the .so file defined in android.app.lib_name meta-data, and calls the main function with all the arguments set in android.app.arguments meta-data.

Т.е. точкой входа для службы служит int main(int argc, char *argv[]). Однако, в действительности, main вызывается только один раз для активности, а для сервиса - нет. И тем не менее, сам сервис успешно запускается и продолжает работать.

Вот еще пример на Stack Overflow: https://stackoverflow.com/questions/48963731/qtservice-automatically-restarts-on-android-after-running-the-application

// Вызывается только один раз
int main(int argc, char** argv){
    
    // Работает
    //GUI
    if(argc <= 1){
        QGuiApplication app(argc, argv);
        qInfo() << "Service GUI starting...";
        ...
    }

    // Не работает!
    //Service
    else if(argc > 1 && strcmp(argv[1], "-service") == 0){
        QAndroidService app(argc, argv);
        qInfo() << "Service starting...";
	...
    }

}

Почему при запуске службы Android не вызывается main (хотя, сама служба успешно стартует)? Что я делаю не так? Или что-то не правильно понимаю?

OS: Debian 9; Qt: 5.14.1; Android: 7.0



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

Проще выбросить вообще Qt и JNI и сделать нормальный сервис на Android API (Java) и меняться данными со своим Qt-приложением с помощью тех же Preferences.

Порт Qt для Android в извечном состоянии proof-of-concept. А подводных костылей расставлять для того, чтобы оно хоть как-то работало нужно уйму.

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

В целом, Вы правы. Я не часто пишу Android-приложения, тем более нативно на Qt. Хотя, QML, на мой взгляд, довольно неплохо эволюционировал, как UI (тем более cross-platform) - хороший инструмент.

Не в этом суть. Я просто, не могу разобраться - описанная мной ситуация - баг, или я что-то неправильно понимаю/делаю? Должна же main() библиотеки, в данном случае, вызываться для сервиса? Правильно? И как он (сервис) тогда работает без:

 QAndroidService app(argc, argv);
   ...
 app.exec();

Как я понимаю, по задумке разработчиков Qt, именно это должно обеспечить основной цикл жизни сервиса? А он спокойно работает без этой конструкции. Вопрос: почему?

И вопрос по форуму: уведомления на почту о новых ответах нельзя включить (не нашел в настройках профиля)? ЛОР не первый день читаю, но не регистрировался ранее.

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

Должна же main() библиотеки, в данном случае, вызываться для сервиса?

Вообще main() в разделяемой библиотеке находиться по идее никак не должен. Ни в Android, ни в привычных Linux-дистрибутивах. Для этого в Qt наверняка имеется грязный хак-костыль, который делает что-то вроде:

#define main qMain

И уже дальше из Java-кода через native-методы и JNI начинает дёргаться нативная so-либа за все эти qMain’ы и прочие палочки.

Раньше вроде так всё было, и не только в Qt, а в том же порте SDL2 на Android. Сейчас может и переделали.

Нужно внимательно смотреть вермишель классов этого QtService.java и думать как оно там всё работает:

https://code.qt.io/cgit/qt/qtbase.git/tree/src/android/java/src/org/qtproject/qt5/android/bindings

А вообще какой смысл повторно вызывать main() из сервиса? Не думаю, что это вообще хорошая практика. Сделай отдельную функцию типа service_start() и дёргай из Java-кода сервиса её. Это железобетонно должно работать по идее.

И как он (сервис) тогда работает без <КОД> Как я понимаю, по задумке разработчиков Qt, именно это должно обеспечить основной цикл жизни сервиса? А он спокойно работает без этой конструкции. Вопрос: почему?

Service на Java-стороне и ему чихать что там происходит в Qt.

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

А вообще какой смысл повторно вызывать main() из сервиса? Не думаю, что это вообще хорошая практика. Сделай отдельную функцию типа service_start() и дёргай из Java-кода сервиса её. Это железобетонно должно работать по идее.

По логике вещей - да. Но нет задачи «железобетонно». Задача - разобраться как это ПРАВИЛЬНО работает, чего я уже второй день сделать не могу.

Вот из официальной страницы документации: https://doc.qt.io/qt-5/android-services.html

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

и

Qt загружает файл .so, определенный в метаданных android.app.lib_name, и вызывает main-функцию со всеми аргументами, установленными в метаданных android.app.arguments.

Следую из этого, я думал, что алгоритм такой:

  1. Вызываем метод из активности в классе наследуемом от org.qtproject.qt5.android.bindings.QtService

  2. Происходит магия с вызовом main и передачей ей аргумента из android.app.arguments

  3. В main используя условие запускаем сервис через QAndroidService app(argc, argv)

А на практике получается, что QAndroidService вообще не нужен (а если нужен, то в каких случаях?). Не вяжется всё это с документацией. А знаний самому разобраться в этот раз не хватает, т.к. Qt, как и мобильная разработка совсем не основная сфера деятельности.

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