Qt for Android サービスに関して気付いたこと ～目覚まし #8～

少し前に[QtにおけるAndroidのサービスとスレッドの作成 -Qtで作るAndroid目覚ましもどき #6-1-](https://qiita.com/hakua-doublemoon/items/a5af13c528e132ad63c3)を書いたが、それからしばらくして改造をしていたら２点ほど気付きというかネタを見つけたので書きます。
というか２つのネタのうち２つ目のネタを調べてたら１つ目のネタを見つけたというわけです。つまりは下記が参考にしたページ。

* [QtService automatically restarts on Android after running the application
](https://stackoverflow.com/questions/48963731/qtservice-automatically-restarts-on-android-after-running-the-application)

# 気付き/トピック
1. サービスとアクティビティのオブジェクトを同じにする方法  
    これまでサービスとアクティビティのオブジェクトを別々にする方法しかわからなかったが、同じにする方法を見つけた。これでプロジェクトの構成が楽になった。
2. Qt 5.10ではQAndroidService じゃないと起動しないっぽい  
    Qt5.9まではQCoreApplicationでできたんだけど

## サービスとアクティビティを同じオブジェクトにする
まずAndroidManifest.xmlで別々にしていたオブジェクト（ライブラリというべき？）を同じものにする。すなわち[私のコード](https://github.com/hakua-doublemoon/SummerIce/blob/master/summer_ice/android/AndroidManifest.xml)では下記。

``` AndroidManifest.xml
:
        <activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="unspecified" android:launchMode="singleTop">
:
           <meta-data android:name="android.app.lib_name" android:value="summer_clock"/>
:
        </activity>
:
        <service android:process=":qt" android:name="com.summer.test.Spring">
:
           <meta-data android:name="android.app.lib_name" android:value="ice_clock"/>
:
        </service>
:
```
から、↓ へ

``` AndroidManifest.xml
:
        <activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="unspecified" android:launchMode="singleTop">
:
           <meta-data android:name="android.app.lib_name" android:value="summer_ice"/>
:
        </activity>
:
        <service android:process=":qt" android:name="com.summer.test.Spring">
:
           <meta-data android:name="android.app.lib_name" android:value="summer_ice"/>
:
        </service>
:
```

別にアクティビティとサービスのどちらかのライブラリに統一するだけでもいいが、私の場合は、summer_clockと名付けた親プロジェクトからsummer_clockとice_clockの２つのプロジェクトをつくりライブラリもつくっていた状態から、子プロジェクトを廃止して親プロジェクト１つに統合したので上記のような変更になる。
そして当然、こうなるとライブラリを起動させられたときにアクティビティとサービスそれぞれに流さないといけないので、main()を下記のようにする。

``` summer_clock.cpp
int main(int argc, char *argv[])
{
    if(argc > 1 && strcmp(argv[1], "-service") == 0) {
        qInfo() << "Summer_Ice::Service starting...";
        return ice_clock(argc, argv);
    } else {
        qInfo() << "Summer_Ice::Activity starting...";
        return summer_clock(argc, argv);
    }
}
```
ice_clock()とsummer_clock()の中はそれぞれサービスとアクティビティを開始する処理であり、これ自体は特別なことはない、これまで書いた内容なので説明しません。
こう条件分岐できるのはおそらくなんですが下記にAndroidManifest.xmlに書いてある下記のおかげなのでしょう。

``` AndroidManifest.xml
           <meta-data android:name="android.app.arguments" android:value="-service"/>
```

## Qt 5.10ではQAndroidService じゃないと起動しないっぽい
2017年末にようやく動くレベルになってから2018年の5月の連休に社畜が休みを取って改造していたときに、Qtを5.9から5.10にあげたら下記な感じで動かなくなった。

> 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

ANR……Application Not Responding？ なにそれーって感じで別に処理同じだしそんな重くないしで困り果ててネットの海を漂っていたところ冒頭のページを発見。
結論としては下記のまま。

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

というわけで下記のように変更する。

``` ice_clock()@summer_clock.cpp
// サービス
int ice_clock(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
:
}
```

から ↓ へ

``` ice_clock()@summer_clock.cpp
// サービス
int ice_clock(int argc, char *argv[])
{
#ifdef    __ANDROID__
    QAndroidService app(argc, argv);
#else
    QCoreApplication app(argc, argv);
#endif
:
}
```

QAndroidServiceはAndroidアプリ用のコンパイルじゃないとコンパイルできないので、WindowsやLinuxで画面確認するために```__ANDROID__```で分けておく。（Android以外ではサービス起動しないからコンパイルさえ通ればなんだけど）

せっかくなのでgoogleの翻訳と英文を見比べながら読んでみるが、どうやら、QCoreApplicationでは？QAndroidServiceのプライベートなセマフォを触りに行って固まりANRになる、だからQAndroidServiceはだめ、でもQt5.10.0ではQAndroidServiceでもANRになっていて、Qt5.10.1ではなおったっぽいけど変更内容には小さなバグ修正としか書いてなくて不思議、でも大丈夫、みたいなことが書いてあると思った。
いなかで底辺IT企業の社畜やってる身にはとても計り知れない感じがしました。