QtService automatically restarts on Android after running the application

2

I was able to find a code that creates a service for Android using Qt in this link. I put the service code in separate .so files like the code in this article. But I have a problem:

After I started my application, the service auto restarted (0 processes and 1 service in Running services menu) like in this image (MyActivities).

MyActivities (0 processes and 1 service)

My manifest.xml (only relevant lines):

<service android:process=":qt" android:name="org.qtproject.example.MyService">
    <!-- android:process=":qt" is needed to force the service to run on a separate process than the Activity -->

    <!-- Application arguments -->
    <meta-data android:name="android.app.arguments" android:value="-service"/>
    <!-- Application arguments -->

    <!-- If you are using the same application (.so file) for activity and also for service, then you
         need to use *android.app.arguments* to pass some arguments to your service in order to know which
         one is which.
    -->

    <!-- Application to launch -->
    <meta-data android:name="android.app.lib_name" android:value="MyService"/>
    <!-- Application to launch -->

    <!-- Ministro -->
    <meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
    <meta-data android:name="android.app.repository" android:value="default"/>
    <meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
    <meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
    <!-- Ministro -->

    <!-- Deploy Qt libs as part of package -->
    <meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
    <meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
    <meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
    <!-- Deploy Qt libs as part of package -->

    <!-- Run with local libs -->
    <meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
    <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
    <meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
    <meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
    <meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
    <!-- Run with local libs -->

    <!--  Messages maps -->
    <meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
    <meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
    <meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
    <!--  Messages maps -->

    <!-- Background running -->
    <meta-data android:name="android.app.background_running" android:value="true"/>
    <!-- Background running -->
</service>

My service (java part):

package org.qtproject.example;

import android.content.Context;
import android.content.Intent;
import org.qtproject.qt5.android.bindings.QtService;

public class MyService extends QtService {
    public static void startMyService(Context context) {
        Intent intent = new Intent(context, MyService.class);   // New Intent;
        context.startService(intent);                           // Start service;
    }
}

Logcat when the service restart:

E/ActivityManager( 1553): ANR in org.qtproject.example:qt
E/ActivityManager( 1553): PID: 3006
E/ActivityManager( 1553): Reason: Executing service org.qtproject.example/.MyService
E/ActivityManager( 1553): Load: 0.59 / 0.56 / 0.24
E/ActivityManager( 1553): CPU usage from 17710ms to 0ms ago:
E/ActivityManager( 1553):   2.3% 1553/system_server: 0.9% user + 1.3% kernel / faults: 2515 minor 1 major
E/ActivityManager( 1553):   1.5% 1146/surfaceflinger: 0% user + 1.4% kernel / faults: 2 minor
E/ActivityManager( 1553):   1.4% 1668/com.android.systemui: 0.5% user + 0.9% kernel / faults: 2944 minor
E/ActivityManager( 1553):   0.3% 1150/adbd: 0% user + 0.3% kernel / faults: 176 minor
E/ActivityManager( 1553):   0.2% 2194/com.google.android.gms: 0.2% user + 0% kernel / faults: 2607 minor
E/ActivityManager( 1553):   0.1% 2761/com.android.settings: 0.1% user + 0% kernel / faults: 1130 minor
E/ActivityManager( 1553):   0.1% 1141/logd: 0% user + 0% kernel / faults: 1 minor
E/ActivityManager( 1553):   0% 1155/mediaserver: 0% user + 0% kernel / faults: 4 minor
E/ActivityManager( 1553):   0% 1724/com.google.android.gms.persistent: 0% user + 0% kernel / faults: 8 minor
E/ActivityManager( 1553):   0% 1776/com.android.phone: 0% user + 0% kernel / faults: 2 minor
E/ActivityManager( 1553):   0% 1797/com.android.launcher: 0% user + 0% kernel / faults: 607 minor
E/ActivityManager( 1553):   0% 2030/com.google.process.gapps: 0% user + 0% kernel / faults: 344 minor
E/ActivityManager( 1553):  +0% 3027/logcat: 0% user + 0% kernel
E/ActivityManager( 1553): 3.2% TOTAL: 1.1% user + 1.7% kernel + 0.1% iowait + 0.1% softirq
E/ActivityManager( 1553): CPU usage from 1336ms to 1838ms later:
E/ActivityManager( 1553):   16% 1553/system_server: 4% user + 12% kernel / faults: 15 minor
E/ActivityManager( 1553):     14% 1792/Binder_4: 2% user + 12% kernel
E/ActivityManager( 1553):   1.8% 1146/surfaceflinger: 0% user + 1.8% kernel
E/ActivityManager( 1553):     1.8% 1200/Binder_1: 0% user + 1.8% kernel
E/ActivityManager( 1553):   1.8% 2761/com.android.settings: 1.8% user + 0% kernel / faults: 8 minor
E/ActivityManager( 1553):     1.8% 2761/ndroid.settings: 0% user + 1.8% kernel
E/ActivityManager( 1553): 9.1% TOTAL: 1% user + 6.1% kernel + 2% iowait
I/ActivityManager( 1553): Killing 3006:org.qtproject.example:qt/u0a58 (adj 0): bg anr
W/libprocessgroup( 1553): failed to open /acct/uid_10058/pid_3006/cgroup.procs: No such file or directory
W/libprocessgroup( 1553): failed to open /acct/uid_10058/pid_3006/cgroup.procs: No such file or directory
W/ActivityManager( 1553): Scheduling restart of crashed service org.qtproject.example/.MyService in 43754ms
D/EGL_emulation( 1668): eglMakeCurrent: 0xb312e100: ver 2 0
W/ResourceType( 2761): No package identifier when getting value for resource number 0x00000000
W/PackageManager( 2761): Failure retrieving resources for org.qtproject.example: Resource ID #0x0
W/ResourceType( 2761): No package identifier when getting value for resource number 0x00000000
W/PackageManager( 2761): Failure retrieving resources for com.google.android.gsf.login: Resource ID #0x0
W/ResourceType( 2761): No package identifier when getting value for resource number 0x00000000
W/PackageManager( 2761): Failure retrieving resources for org.qtproject.example: Resource ID #0x0
W/ResourceType( 2761): No package identifier when getting value for resource number 0x00000000
W/PackageManager( 2761): Failure retrieving resources for com.google.android.gsf.login: Resource ID #0x0
W/ResourceType( 2761): No package identifier when getting value for resource number 0x00000000
W/PackageManager( 2761): Failure retrieving resources for org.qtproject.example: Resource ID #0x0
W/ResourceType( 2761): No package identifier when getting value for resource number 0x00000000
W/PackageManager( 2761): Failure retrieving resources for com.google.android.gsf.login: Resource ID #0x0
W/ResourceType( 2761): No package identifier when getting value for resource number 0x00000000
W/PackageManager( 2761): Failure retrieving resources for org.qtproject.example: Resource ID #0x0
W/ResourceType( 2761): No package identifier when getting value for resource number 0x00000000
W/PackageManager( 2761): Failure retrieving resources for com.google.android.gsf.login: Resource ID #0x0
W/ResourceType( 2761): No package identifier when getting value for resource number 0x00000000
W/PackageManager( 2761): Failure retrieving resources for org.qtproject.example: Resource ID #0x0
W/ResourceType( 2761): No package identifier when getting value for resource number 0x00000000
W/PackageManager( 2761): Failure retrieving resources for com.google.android.gsf.login: Resource ID #0x0
W/ResourceType( 2761): No package identifier when getting value for resource number 0x00000000
W/PackageManager( 2761): Failure retrieving resources for org.qtproject.example: Resource ID #0x0
W/ResourceType( 2761): No package identifier when getting value for resource number 0x00000000
W/PackageManager( 2761): Failure retrieving resources for com.google.android.gsf.login: Resource ID #0x0

After this, the service is no longer active!

My App in this picture is a service I code in Android Studio and it works perfectly. But service in Qt have problem.

android
qt
android-service
asked on Stack Overflow Feb 24, 2018 by tulm • edited Apr 5, 2018 by Ayberk Özgür

2 Answers

2

I had the same problem with Qt 5.10.0 and as you are experiencing, the service never got past onCreate() and was shortly killed by an ANR. The ANR stack trace showed the following:

native: #00 pc 000174e8 /system/lib/libc.so (syscall+28)
native: #01 pc 0004777d /system/lib/libc.so (_ZL24__pthread_cond_timedwaitP23pthread_cond_internal_tP15pthread_mutex_tbPK8timespec+102)
native: #02 pc 0007888f /data/app/com.ourcompany.ourapp-1/lib/arm/libQt5Core.so (???)
native: #03 pc 0007873d /data/app/com.ourcompany.ourapp-1/lib/arm/libQt5Core.so (_ZN14QWaitCondition4waitEP6QMutexm+100)
native: #04 pc 000756cd /data/app/com.ourcompany.ourapp-1/lib/arm/libQt5Core.so (_ZN10QSemaphore7acquireEi+46)
native: #05 pc 00019975 /data/data/com.ourcompany.ourapp/qt-reserved-files/plugins/platforms/android/libqtforandroid.so (???)
at org.qtproject.qt5.android.QtNative.startQtApplication(Native method)
at org.qtproject.qt5.android.QtNative.startApplication(QtNative.java:333)
at org.qtproject.qt5.android.QtServiceDelegate.startApplication(QtServiceDelegate.java:176)
at java.lang.reflect.Method.invoke!(Native method)
at org.qtproject.qt5.android.bindings.QtLoader.loadApplication(QtLoader.java:251)
at org.qtproject.qt5.android.bindings.QtLoader.startApp(QtLoader.java:676)
at org.qtproject.qt5.android.bindings.QtServiceLoader.onCreate(QtServiceLoader.java:60)
at org.qtproject.qt5.android.bindings.QtService.onCreateHook(QtService.java:54)
at org.qtproject.qt5.android.bindings.QtService.onCreate(QtService.java:60)
at com.ourcompany.ourapp.OurService.onCreate(OurService.java:26)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:3231)
at android.app.ActivityThread.-wrap5(ActivityThread.java:-1)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1597)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6236)
at java.lang.reflect.Method.invoke!(Native method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:891)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:781)

which showed that the service was stuck waiting on a semaphore. Tracing this further reveals that this waiting occurs during the QtAndroidPrivate::waitForServiceSetup(); call at line 548 in androidjnimain.cpp, waiting on QtAndroidPrivate::g_waitForServiceSetupSemaphore to be released. This should normally occur within QtAndroidPrivate::setOnBindListener(QtAndroidPrivate::OnBindListener *listener) that is called by the QAndroidServicePrivate::QAndroidServicePrivate(QAndroidService *service) constructor, that is a private member of QAndroidService (extends QCoreApplication) and is created alongside it. This means that you should absolutely not use QCoreApplication but QAndroidService if you're launching your service natively, otherwise your service gets stuck at this semaphore and gets an ANR.

However, even if I used QAndroidService, the ANR problem persisted in Qt 5.10.0. In Qt 5.10.1, I realized that the call QtAndroidPrivate::setOnBindListener(this); was replaced with QTimer::singleShot(0,this, [this]{ QtAndroidPrivate::setOnBindListener(this);}); letting the call occur after the constructor returns. This seems to have effectively fixed the ANR problem for me for the moment; for reference, my main.cpp looks like this:

#include <QAndroidService>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <string.h>

int main(int argc, char** argv){

    //GUI
    if(argc <= 1){
        QGuiApplication app(argc, argv);
        qInfo() << "Service GUI starting...";
        QQmlApplicationEngine engine;
        engine.load(QUrl(QStringLiteral("qrc:///src/main.qml")));
        return app.exec();
    }

    //Service
    else if(argc > 1 && strcmp(argv[1], "-service") == 0){
        QAndroidService app(argc, argv);
        qInfo() << "Service starting...";

        // My service stuff

        return app.exec();
    }

    //Unrecognized argument
    else{
        qWarning() << "Unrecognized command line argument.";
        return -1;
    }
}

What is weird is that http://code.qt.io/cgit/qt/qtandroidextras.git/tree/dist/changes-5.10.1/?h=v5.10.1 lists only minor changes, which is not true since they apparently fixed the ANR problem that previously made Android services effectively unusable.

So the solution seems to be using Qt 5.10.1 with QAndroidService instead of QCoreApplication.

answered on Stack Overflow Mar 29, 2018 by Ayberk Özgür
0

Ayberk sorted me out.

I've been trying to run android services with Qt 5.12 for 4 days now. Worth mentioning:

In the Manifest.. You MUST HAVE android:enabled="true" as part of the service tag, eg:

<service android:process=":qt" android:enabled="true" android:name="org.qtproject.example.MyCustomAppService">

Ayberks code was the only example where I saw this. Nothing worked until then.

ALSO If you run an endless loop before you run qAndroidservice.exec(), android will kill the process and your output will most likely not make it to the logcat.

[x] Does not work:

qInfo() << "You should see this once for app and once for service";
if (strcmp(argv[1], "-service") == 0) {
    qInfo() << "Service is running";
    QAndroidService svc(argc, argv);
    while (true) {
        qInfo("This may or may not get displayed");
    }
    qInfo() << "This output does not display";
    return svc.exec();
}

[+] Does work:

qInfo() << "You should see this once for app and once for service";
if (strcmp(argv[1], "-service") == 0) {
    qInfo() << "Service is running";
    QAndroidService svc(argc, argv);
    qInfo() << "You should see this";
    return svc.exec();
}

This might seem obvious but I was trying to repeat a gps upload in a loop with a delay. Which seemed easy enough. I think the better approach is to use QTimer. As the QAndroidService does actually run and QWebSocket works perfectly.

Secondly:

qInfo and qDebug DOES display in the logcat. Just not in QT Creators logcat. I used Android Studio's logcat viewer and I can see my output from the service.

Thirdly.

I couldn't figure out where to put the java service file. It turns out it's either not very important or I just happened to put it in the right place. I put it in /QtProjFolder/Android/src/org/qtproject/example/MyCustomAppService.java and it works great.

If anybody has any "Good" ideas on communicating with the main application, pls let me know :)

I hope this helps you guys avoid wasting 4 days on this like I did.

answered on Stack Overflow Mar 10, 2020 by Parthanon

User contributions licensed under CC BY-SA 3.0