Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin paths in AndroidManifest.xml not correctly resolved #1

Closed
Martchus opened this issue Dec 2, 2018 · 20 comments
Closed

Plugin paths in AndroidManifest.xml not correctly resolved #1

Martchus opened this issue Dec 2, 2018 · 20 comments

Comments

@Martchus
Copy link
Contributor

Martchus commented Dec 2, 2018

Since changing the paths the %%INSERT_LOCAL_LIBS%% placeholder in AndroidManifest.xml is not resolved correctly anymore.

I get lib/qt/plugins/platforms/android/libqtforandroid.so:lib/qt/plugins/bearer/libqandroidbearer.so:lib/libQt5QuickParticles.so instead of plugins/platforms/android/libqtforandroid.so:plugins/bearer/libqandroidbearer.so:lib/libQt5QuickParticles.so. Despite changing the paths the latter still seems correct. The incorrect version prevents the application to start at all because C++ functions provided by the platform plugin can not be loaded, eg.:

12-02 20:28:40.110 31531 31552 E passwordmanage: No implementation found for boolean org.qtproject.qt5.android.QtNative.startQtAndroidPlugin(java.lang.String, java.lang.String) (tried Java_org_qtproject_qt5_android_QtNative_startQtAndroidPlugin and Java_org_qtproject_qt5_android_QtNative_startQtAndroidPlugin__Ljava_lang_String_2Ljava_lang_String_2)
12-02 20:28:40.112 31531 31552 E AndroidRuntime: FATAL EXCEPTION: qtMainLoopThread
12-02 20:28:40.112 31531 31552 E AndroidRuntime: Process: org.martchus.passwordmanager, PID: 31531
12-02 20:28:40.112 31531 31552 E AndroidRuntime: java.lang.UnsatisfiedLinkError: No implementation found for boolean org.qtproject.qt5.android.QtNative.startQtAndroidPlugin(java.lang.String, java.lang.String) (tried Java_org_qtproject_qt5_android_QtNative_startQtAndroidPlugin and Java_org_qtproject_qt5_android_QtNative_startQtAndroidPlugin__Ljava_lang_String_2Ljava_lang_String_2)
12-02 20:28:40.112 31531 31552 E AndroidRuntime:        at org.qtproject.qt5.android.QtNative.startQtAndroidPlugin(Native Method)
12-02 20:28:40.112 31531 31552 E AndroidRuntime:        at org.qtproject.qt5.android.QtNative$5.run(QtNative.java:345)
12-02 20:28:40.112 31531 31552 E AndroidRuntime:        at org.qtproject.qt5.android.QtThread$2.run(QtThread.java:87)
12-02 20:28:40.112 31531 31552 E AndroidRuntime:        at org.qtproject.qt5.android.QtThread$1.run(QtThread.java:61)
12-02 20:28:40.112 31531 31552 E AndroidRuntime:        at java.lang.Thread.run(Thread.java:764)
12-02 20:28:40.117  1423  4526 W ActivityManager:   Force finishing activity org.martchus.passwordmanager/.Activity

I had also applied your patch 0003-Fix-androiddeployqt-search-paths.patch when building Qt. So it at least does not fix this or maybe this bug is even an unwanted side-effect of that patch.

Of course one can easily workaround the issue by hard-coding the path instead of using the placeholder: Martchus/passwordmanager@06c2807

So it is not really important.

@hipersayanX
Copy link
Owner

hipersayanX commented Dec 4, 2018

When building and deploying a basic Qml Android app this is the layout of the /android-build/libs folder:

./android-build/libs/QtAndroidBearer.jar
./android-build/libs/QtAndroid.jar
./android-build/libs/x86_64/gdbserver
./android-build/libs/x86_64/libAndroidTest.so
./android-build/libs/x86_64/libc++_shared.so
./android-build/libs/x86_64/libgdbserver.so
./android-build/libs/x86_64/libqml_QtQuick.2_libqtquick2plugin.so
./android-build/libs/x86_64/libqml_QtQuick_Window.2_libwindowplugin.so
./android-build/libs/x86_64/libQt5Core.so
./android-build/libs/x86_64/libQt5Gui.so
./android-build/libs/x86_64/libQt5Network.so
./android-build/libs/x86_64/libQt5Qml.so
./android-build/libs/x86_64/libQt5QuickParticles.so
./android-build/libs/x86_64/libQt5Quick.so
./android-build/libs/x86_64/qt/plugins/bearer/libqandroidbearer.so
./android-build/libs/x86_64/qt/plugins/imageformats/libqgif.so
./android-build/libs/x86_64/qt/plugins/imageformats/libqicns.so
./android-build/libs/x86_64/qt/plugins/imageformats/libqico.so
./android-build/libs/x86_64/qt/plugins/imageformats/libqjpeg.so
./android-build/libs/x86_64/qt/plugins/imageformats/libqtga.so
./android-build/libs/x86_64/qt/plugins/imageformats/libqtiff.so
./android-build/libs/x86_64/qt/plugins/imageformats/libqwbmp.so
./android-build/libs/x86_64/qt/plugins/imageformats/libqwebp.so
./android-build/libs/x86_64/qt/plugins/platforminputcontexts/libqtvirtualkeyboardplugin.so
./android-build/libs/x86_64/qt/plugins/platforms/android/libqtforandroid.so
./android-build/libs/x86_64/qt/plugins/qmltooling/libqmldbg_debugger.so
./android-build/libs/x86_64/qt/plugins/qmltooling/libqmldbg_inspector.so
./android-build/libs/x86_64/qt/plugins/qmltooling/libqmldbg_local.so
./android-build/libs/x86_64/qt/plugins/qmltooling/libqmldbg_messages.so
./android-build/libs/x86_64/qt/plugins/qmltooling/libqmldbg_nativedebugger.so
./android-build/libs/x86_64/qt/plugins/qmltooling/libqmldbg_native.so
./android-build/libs/x86_64/qt/plugins/qmltooling/libqmldbg_profiler.so
./android-build/libs/x86_64/qt/plugins/qmltooling/libqmldbg_quickprofiler.so
./android-build/libs/x86_64/qt/plugins/qmltooling/libqmldbg_server.so
./android-build/libs/x86_64/qt/plugins/qmltooling/libqmldbg_tcp.so

But the internal layout of the apk (android-build-debug) is:

./android-build/build/outputs/apk/android-build-debug/AndroidManifest.xml
./android-build/build/outputs/apk/android-build-debug/assets/--Added-by-androiddeployqt--/debugger.command
./android-build/build/outputs/apk/android-build-debug/assets/--Added-by-androiddeployqt--/qml/QtQuick.2/plugins.qmltypes
./android-build/build/outputs/apk/android-build-debug/assets/--Added-by-androiddeployqt--/qml/QtQuick.2/qmldir
./android-build/build/outputs/apk/android-build-debug/assets/--Added-by-androiddeployqt--/qml/QtQuick/Window.2/plugins.qmltypes
./android-build/build/outputs/apk/android-build-debug/assets/--Added-by-androiddeployqt--/qml/QtQuick/Window.2/qmldir
./android-build/build/outputs/apk/android-build-debug/assets/--Added-by-androiddeployqt--/qt_cache_pregenerated_file_list
./android-build/build/outputs/apk/android-build-debug/classes.dex
./android-build/build/outputs/apk/android-build-debug/lib/x86_64/libAndroidTest.so
./android-build/build/outputs/apk/android-build-debug/lib/x86_64/libc++_shared.so
./android-build/build/outputs/apk/android-build-debug/lib/x86_64/libgdbserver.so
./android-build/build/outputs/apk/android-build-debug/lib/x86_64/libqml_QtQuick.2_libqtquick2plugin.so
./android-build/build/outputs/apk/android-build-debug/lib/x86_64/libqml_QtQuick_Window.2_libwindowplugin.so
./android-build/build/outputs/apk/android-build-debug/lib/x86_64/libQt5Core.so
./android-build/build/outputs/apk/android-build-debug/lib/x86_64/libQt5Gui.so
./android-build/build/outputs/apk/android-build-debug/lib/x86_64/libQt5Network.so
./android-build/build/outputs/apk/android-build-debug/lib/x86_64/libQt5Qml.so
./android-build/build/outputs/apk/android-build-debug/lib/x86_64/libQt5QuickParticles.so
./android-build/build/outputs/apk/android-build-debug/lib/x86_64/libQt5Quick.so
./android-build/build/outputs/apk/android-build-debug/META-INF/CERT.RSA
./android-build/build/outputs/apk/android-build-debug/META-INF/CERT.SF
./android-build/build/outputs/apk/android-build-debug/META-INF/MANIFEST.MF
./android-build/build/outputs/apk/android-build-debug/res/layout/splash.xml
./android-build/build/outputs/apk/android-build-debug/resources.arsc

The plugins and the qml files did not get copied properly, not sure if there are more files missing.
It's seems more like a problem related to hard coded paths in the androiddeployqt tool, it expect the files to be relative to the install directory and ignored the paths used in ./configure and the paths in qmake -query.

@Martchus
Copy link
Contributor Author

Martchus commented Dec 4, 2018

Yes, the APK is obviously missing plugins in your case. That means you don't even come far enough to reproduce the issue I've been reporting.

So let's talk about the issue you've encountered first :-)

I didn't notice it because I'm using CMake and I've written my own CMake module to produce android-deployment.json with the correct paths. But I've been hardcoding paths before too and had to adapt it.

So androiddeployqt actually just uses the paths from android-deployment.json. But qmake apparently doesn't generate it correctly by not considering its own variables/configuration. So if that theory is correct, it is actually qmake which needs patching in the same way as my CMake module needed.

@hipersayanX
Copy link
Owner

In my case I'm using Qmake which is the default build system, did not tried with Cmake yet.

So androiddeployqt actually just uses the paths from android-deployment.json. But qmake apparently doesn't generate it correctly

I tried to find information on that android-deployment.json file but it's not located in the system and grepping qt-everywhere-src does not give any result, is it a Cmake thing or I'm missing something?

by not considering its own variables/configuration. So if that theory is correct, it is actually qmake which needs patching in the same way as my CMake module needed.

If you do:

/opt/android-libs/aarch64/bin/qmake -query

the paths are correct but androiddeployqt does not seems to be using those paths at all, did not read the source code at all so not sure.

@Martchus
Copy link
Contributor Author

Martchus commented Dec 4, 2018

android-deployment.json is the file you pass to androiddeployqt via the --input argument. That's all the documentation you can find about it: http://doc.qt.io/qt-5/deployment-android.html#command-line-arguments

So the actual name of this file might be different when using qmake. In fact android-deployment.json is freely chosen by me. Sorry for causing any confusion with that name. But qmake should generate such a JSON file somewhere in your build directory and pass it to androiddeployqt.

If you do the paths are correct

I'm aware. My adjusted CMake module actually uses qmake -query to find out the correct paths. But that qmake -query works doesn't mean that qmake generates android-deployment.json correctly.

@hipersayanX
Copy link
Owner

android-deployment.json is the file you pass to androiddeployqt via the --input argument.

Get it, in the root of the source code, qmake put a *-deployment-settings.json file.
This is generated by qtbase/mkspecs/features/android/android_deployment_settings.prf.

{
   "description": "This file is generated by qmake to be read by androiddeployqt and should not be modified by hand.",
   "qt": "/opt/android-libs/x86-64",
   "sdk": "/opt/android-sdk",
   "sdkBuildToolsRevision": "28.0.3",
   "ndk": "/opt/android-ndk",
   "toolchain-prefix": "x86_64",
   "tool-prefix": "x86_64-linux-android",
   "toolchain-version": "4.9",
   "ndk-host": "linux-x86_64",
   "target-architecture": "x86_64",
   "qml-root-path": "/home/user/AndroidTest",
   "stdcpp-path": "/opt/android-ndk/sources/cxx-stl/llvm-libc++/libs/x86_64/libc++_shared.so",
   "application-binary": "/home/user/AndroidTest/libAndroidTest.so"
}

@hipersayanX
Copy link
Owner

Here I changed qml with lib/qt/qml, and then added "deployment-dependencies": "lib" to the json file, this basically copies the whole lib folder into the apk, far from ideal but whatever. And now I'm getting this error:

W System.err: java.lang.ClassNotFoundException: Didn't find class "org.qtproject.qt5.android.QtActivityDelegate" on path: DexPathList[[],nativeLibraryDirectories=[/system/lib64, /vendor/lib64]]

Afaik NDK apps needs an activity class to load the binary as explained here,androiddeployqt is supposed to take all java binding files and compile into the .dex file and it's not doing that.

Without the "deployment-dependencies": "lib" line I get this error.

-- Skipping /opt/android-libs/x86-64/lib/qt/plugins/platforms/libqwebgl.so. It has unmet dependencies: lib/libQt5WebSockets.so.
-- Skipping /opt/android-libs/x86-64/lib/qt/plugins/iconengines/libqsvgicon.so. It has unmet dependencies: lib/libQt5Svg.so,lib/libQt5Widgets.so.
-- Skipping /opt/android-libs/x86-64/lib/qt/plugins/imageformats/libqsvg.so. It has unmet dependencies: lib/libQt5Svg.so,lib/libQt5Widgets.so.

Idk, I'm quite lost with this.

@Martchus
Copy link
Contributor Author

Martchus commented Dec 6, 2018

and then added "deployment-dependencies": "lib" to the json file, this basically copies the whole lib folder into the apk

I suppose I did that better in my CMake module. But I still end up having lots of plugins I actually don't need.

And now I'm getting this error:

Yes, looks like some Java code couldn't be dexed correctly. I haven't run into this issue so far.


I can share the JSON file for androiddeployqt produced by my CMake module and also the exact invocation of the tools when I'm accessing the computer where I've built that stuff again. Otherwise you can checkout qtutilities/passwordmanager from my GitHub. That are my demo/practicing projects for Qt stuff and also contain the configuration files and build system magic the Android build.

dirkhh referenced this issue in subsurface/subsurface Dec 24, 2018
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
@hipersayanX
Copy link
Owner

I've reported the issue in Qt issue tracker.

@emericg
Copy link

emericg commented Jan 19, 2019

Great thanks!

@hipersayanX
Copy link
Owner

This is not going anywhere 😕
Even without modifying the install paths, androiddeployqt can't solve libraries paths properly:

-- Skipping /opt/android-libs/x86-64/plugins/platforms/libqwebgl.so. It has unmet dependencies: lib/libQt5WebSockets.so.
-- Skipping /opt/android-libs/x86-64/plugins/platforminputcontexts/libqtvirtualkeyboardplugin.so. It has unmet dependencies: lib/libQt5VirtualKeyboard.so.
-- Skipping /opt/android-libs/x86-64/plugins/iconengines/libqsvgicon.so. It has unmet dependencies: lib/libQt5Svg.so,lib/libQt5Widgets.so.
-- Skipping /opt/android-libs/x86-64/plugins/imageformats/libqsvg.so. It has unmet dependencies: lib/libQt5Svg.so,lib/libQt5Widgets.so.

And there are a lot of hard coded paths relative to the prefix.

@Martchus
Copy link
Contributor Author

Martchus commented Mar 11, 2019

Wait, I thought this "It has unmet dependencies" log message only means that the plugin is not bundled because the application does not make use of the related Qt module.

So the plugin libqsvgicon.so would only be bundled if the application links against the Qt Svg module and is otherwise skipped with that message. If that wouldn't be the case, how would you tell androiddeployqt which plugins to bundle? For instance, if you don't use SVG icons, you actually most likely don't want that plugin to be bundled.

What actually works for me is this CMake module to invoke androiddeployqt: https://github.com/Martchus/qtutilities/blob/master/cmake/modules/AndroidApk.cmake

It uses qmake -query to find the paths and creates based on that the JSON file for androiddeployqt. The only problem I still have is that it actually bundles too many plugins. So likely setting the plugin directory via "android-extra-plugins" isn't the best idea either. But at least the SVG icons and other plugin-based features work this way.

@hipersayanX
Copy link
Owner

Wait, I thought this "It has unmet dependencies" log message only means that the plugin is not bundled because the application does not make use of the related Qt module.

And you are right, I was not able to test well the apk because I have some problems with Qt Creator not detecting the installed images. The apk runs well if I leave the install paths untouched.

What actually works for me is this CMake module to invoke androiddeployqt: https://github.com/Martchus/qtutilities/blob/master/cmake/modules/AndroidApk.cmake

But even so users expect Qt Creator templates to be ready to use, they expect to press the run button, get the apk compiled, and then launch and Android image with the app running, also even when Qt supports cmake, qmake is the default build systems and that is what users expect. Adding a 3rd-party dependency is not a solution here.

It uses qmake -query to find the paths and creates based on that the JSON file for androiddeployqt.

androiddeployqt has many hard dependencies relative to the install prefix (1 2 3 4 5), and the paths referenced in /opt/android-libs//lib/-android-dependencies.xml are always relative to the prefix. *-android-dependencies.xml files are generated by qt_android_deps.prf, and grepping for example:

grep -r ANDROID_LIB_DEPENDENCIES
cat qtgamepad/src/gamepad/gamepad.pro

ANDROID_LIB_DEPENDENCIES = \
    plugins/gamepads/libandroidgamepad.so

androiddeployqt is ignoring install paths completely. I'll continue making more tests.

@emericg
Copy link

emericg commented Mar 12, 2019

But even so users expect Qt Creator templates to be ready to use, they expect to press the run button, get the apk compiled, and then launch and Android image with the app running

Most definitely. This bug makes the package unusable for most use cases.

Is there a (temporary) solution to brige the gap between the "old" way (what was working with the 5.11 version of the package) and the current package? Like symlinking the directories to emulate the previous hierarchy while keeping the new "common" hierarchy ?
I didn't really pay attention at how it worked before, and now that the package as been recreated with a different name for qt 5.12 I couldn't really see what changed.

@hipersayanX
Copy link
Owner

I have updated the packages, it may be working now, I have tested with the Qt Quick Application template in Qt Creator. Some notes:

  • android-qt5 packages only work with jdk8-openjdk and android-sdk-25.2.5 otherwise androiddeployqt will fail.
  • When you try to run the apk, Qt Creator can't detect or manage any installed system-image, the bug is not related to android-qt5 packages is most likely a bug in Qt Creator. You can still launch a virtual device and install the package manually.
  • As I said, I had no option but to leave install paths untouched, but that is a bug that must be solved upstream.

@emericg

Is there a (temporary) solution to brige the gap between the "old" way (what was working with the 5.11 version of the package) and the current package? Like symlinking the directories to emulate the previous hierarchy while keeping the new "common" hierarchy ?

Yes, and I did so with latest changes, the problem will be when they release an hypothetical Qt6 in the future, if they don't fix this bug, you will be not able to have installed Qt5 and Qt6 at same time, for example sending all qml and plugins files to lib/qt5/qml and lib/qt5/plugins (for Qt5), and lib/qt6/qml and lib/qt6/plugins (for Qt6).

@emericg
Copy link

emericg commented Mar 13, 2019

Yes thanks, I tested the armv8 version and it's working again!
Tested with a qml/bluetooth/svg/charts application.

@lsevero
Copy link

lsevero commented Mar 17, 2019

I just installed the android-armv7a-eabi-qt5 package from aur and I'm getting this error when executing an example program on android:

I mple.calculato: Late-enabling -Xcheck:jni
W System  : ClassLoader referenced unknown path:
D OpenGLRenderer: Skia GL Pipeline
E AndroidRuntime: FATAL EXCEPTION: qtMainLoopThread
E AndroidRuntime: Process: org.qtproject.example.calculator, PID: 24035
E AndroidRuntime: java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__emutls_get_address" referenced by "/data/app/org.qtproject.example.calculator-sU4bjJr3ce540wR7wTY1ng==/lib/arm/libQt5Core.so"...
E AndroidRuntime: 	at java.lang.Runtime.load0(Runtime.java:928)
E AndroidRuntime: 	at java.lang.System.load(System.java:1633)
E AndroidRuntime: 	at org.qtproject.qt5.android.QtNative$2.run(QtNative.java:183)
E AndroidRuntime: 	at org.qtproject.qt5.android.QtThread$2.run(QtThread.java:87)
E AndroidRuntime: 	at org.qtproject.qt5.android.QtThread$1.run(QtThread.java:61)
E AndroidRuntime: 	at java.lang.Thread.run(Thread.java:764)
I Process : Sending signal. PID: 24035 SIG: 9


"org.qtproject.example.calculator" died.

Something still not right with the .so files.

I have the following android packages in my pc:

╭─lsevero at arch-topzera in /home/lsevero
╰─λ pacman -Q | grep android                                          0 < 15:09:21
android-apktool 2.3.3-1
android-armv7a-eabi-openssl 1.1.1.a-1
android-armv7a-eabi-qt5 5.12.1-3
android-cmake-git r147.556cc14-1
android-ndk r19.c-1
android-platform 27_r01-2
android-platform-21 5.0.1_r02-1
android-platform-22 5.1.1_r02-1
android-platform-28 9_r06-1
android-sdk-25.2.5 25.2.5-3
android-sdk-build-tools r27.0.3-1
android-sdk-cmake 3.6.4111459-2
android-sdk-ndk-symlink 1-1
android-sdk-platform-tools r26.0.2-1
android-studio 3.0.1.0-1
android-tools 9.0.0_r30-2
android-udev 20190315-1

@hipersayanX
Copy link
Owner

@lsevero executed in an Android phone or the emulator?

@lsevero
Copy link

lsevero commented Mar 18, 2019

In an android phone with android 9.

@hipersayanX
Copy link
Owner

hipersayanX commented Mar 19, 2019

I did not tested any app in a phone yet, but it could be that your phone is arm64-v8a instead of armv7a-eabi?

Edit

Could this be related?

@hipersayanX
Copy link
Owner

The original problem is already solved, closing issue before it goes offtopic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants