Quantcast
Channel: BogDan Vatra, Author at KDAB

Qt on Android: How to create an Android service using Qt

$
0
0

Starting with Qt 5.7, we added the ability to create Android services using Qt.
In this article we’re going to see how to get started and also how to communicate between the two.

Before we get started I want to add a big bold WARNING about the performance! Because the services are run in the background for a very long time, make sure your service doesn’t drain the device battery!

Getting started

Step I: Extend QtService

Every single Qt Android Service must have its own Service java class which extends QtService, so the first step is to create such a service:

// java file goes in android/src/com/kdab/training/MyService.java
package com.kdab.training;
import org.qtproject.qt5.android.bindings.QtService;

public class MyService extends QtService
{
}

Step II: Add the service section(s) to your AndroidManifest.xml file

The next step is to add the service section(s) to your AndroidManifest.xml file. To do that you first need to copy & paste the template from https://wiki.qt.io/AndroidServices to your AndroidManifest.xml file, then set android:name attribute with your service class name, as shown in the following snippet:

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

    <!-- .... -->

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

BE AWARE: Every single Qt service/activity MUST run in it’s own process! Therefore for each service you must set a different android:process attribute value.

Step III: How to start the service ?

Now you need to decide how to start the service. There are two ways to do it:

  • on demand
  • at boot time

We’re going to check them both:

Start the service on demand

This is the most common way to start your service(s). To start the service you just need to call Context.startService(Intent intent) method.
The easiest way is to add a static method to your MyService:

// java file goes in android/src/com/kdab/training/MyService.java
package com.kdab.training;

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 ctx) {
        ctx.startService(new Intent(ctx, MyService.class));
    }
}

Then simply call it from Qt to start it:

QAndroidJniObject::callStaticMethod<void>("com/kdab/training/MyService",
                                              "startMyService",
                                              "(Landroid/content/Context;)V",
                                              QtAndroid::androidActivity().object());

Start the service at boot time

This method is used quite seldom and is useful ONLY when you really need to run the service at boot time, otherwise I do recommend you to start it on demand.

First you need to add android.permission.RECEIVE_BOOT_COMPLETED permission to your AndroidManifest.xml file:

<application ... >

  <!-- .... -->
  <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
</application>

Then you need to add a receiver element to your AndroidManifest.xml file:

<application ... >
    <!-- .... -->
    <receiver android:name=".MyBroadcastReceiver">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
    <!-- .... -->
</application>

And finally, you need to implement MyBroadcastReceiver class, as shown in the following snippet:

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent startServiceIntent = new Intent(context, MyService.class);
        context.startService(startServiceIntent);
    }
}

Step IV: Where to put your Qt Service code?

Next you need to decide where you’re going to put your service code. Qt (and qmake) has two options for you:

  • in the same .so file with the application
  • in a separate .so file

We’re going to check them both:

Same .so for app & service(s)

Because you’ll have one big .so file, you need a way to know when it will run as an activity or as a service. To do that you just need pass some arguments to your main function. AndroidManifest.xml allows you to easily do that:

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

Then make sure you set the same android.app.lib_name metadata for both service(s) & activity elements:

<service ... >
    <!-- ... -->
    <meta-data android:name="android.app.lib_name"
                android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
    <!-- ... -->
</service>

I recommend you to use this method only if your activity and your service(s) share a large piece of code.

Separate .so files for app & service(s)

The second option is to create separate .so files for your app & service(s).
First you need to create a separate server .pro file(s):

TEMPLATE = lib
TARGET = server
CONFIG += dll
QT += core
SOURCES += \
    server.cpp

The server .so main entry is the main function:

#include <QDebug>

int main(int argc, char *argv[])
{
    qDebug() << "Hello from service";
    return 0
}

Last you need to load the server .so file:

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

Use QtRemoteObject for communication

We’ve seen how to create and how to start a Qt on Android service, now let’s see how to do the communication between them.
There are lots of solutions out there, but for any Qt project, I do recommend you use QtRemoteObject, because it will make your life so easy!

QtRemoteObjects is a playground Qt module led by Ford, for object remoting between processes/devices:

  • exports QObjects remotely (properties, signals & slots)
  • exports QAbstractItemModels remotely
  • creates a replicant on the client side you can interface with
  • repc generates source & replica (server & client) source files from .rep files
    • .rep file is the QtRemoteObjects IDL (interface description language)

As you can see it’s very Qt specific!
Let’s see how to add it to your projects and use it.

Get QtRemoteObjects

QtRemoteObjects project is located at http://code.qt.io/cgit/playground/qtremoteobjects.git/, to get it you need to run the following commands:

$ git clone git://code.qt.io/playground/qtremoteobjects.git
$ cd qtremoteobjects
$ ~/Qt/5.7/android_armv7/bin/qmake -r && make && make install

If needed, replace ~/Qt/5.7/android_armv7 with your Qt version and android ABI of choice.

Use QtRemoteObjects

Using QtRemoteObjects is pretty easy, you need to do a few easy steps:

– add QtRemoteObjects to your .pro files

# ...
QT += remoteobjects
# ...

– create .rep file(s)

class PingPong {
    SLOT(void ping(const QString &msg));
    SIGNAL(pong(const QString &msg));
}

– add .rep file(s) to the server .pro file

# ...
REPC_SOURCE += pingpong.rep
# ...

– add .rep file(s) to the client .pro file

# ...
REPC_REPLICA += pingpong.rep
# ...

– QtRemoteObjects source(server) side implementation

#include <QCoreApplication>
#include "rep_pingpong_source.h"

class PingPong : public PingPongSource {
public slots:
    // PingPongSource interface
    void ping(const QString &msg) override {
        emit pong(msg + " from server");
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:replica")));
    PingPong pingPongServer;
    srcNode.enableRemoting(&pingPongServer);

    return app.exec();
}

Let’s check the code a little bit.
First you need to implement all .rep interfaces (PingPongSource), then export PingPong object using enableRemoting.

– QtRemoteObjects replica(client) side implementation

#include "rep_pingpong_replica.h"

// ....
    QRemoteObjectNode repNode;
    repNode.connectToNode(QUrl(QStringLiteral("local:replica")));
    QSharedPointer<PingPongReplica> rep(repNode.acquire<PingPongReplica>());
    bool res = rep->waitForSource();
    Q_ASSERT(res);
    QObject::connect(rep.data(), &PingPongReplica::pong, [](const QString &msg){
        qDebug() << msg;
    });
    rep->ping("Hello");
// ....

Let’s check the code:

  • use QRemoteObjectNode to connect to QRemoteObjectHost
  • use QRemoteObjectNode:acquire to link the local object to the remote one
  • use the acquired object as its local (call slots, connect to signals, etc.)

As you can see, using Qt + QtRemoteObject is (much?) easier and more straight forward than Android’s Java services + AIDL 😉

Limitations

  • the activities & service(s) must run on a different process.
  • it is not possible (yet) to use QtCreator to easily add a service section to your AndroidManifest.xml file check QTCREATORBUG-16884
  • it is not possible (yet) to use QtCreator to easily generate a service subproject for us, check QTCREATORBUG-16885
  • it is not possible (yet) to see the services logs in QtCreator. You’ll need to use
     $ adb logcat 

    to see it, check QTCREATORBUG-16887

  • it is not possible (yet (hopefully)) to debug the services in QtCreator. This feature will take some time to implement it, therefore I’ll not hold my breath for it, check QTCREATORBUG-16886

Please use the above bug report links to vote for your favorite tasks, the ones that have more votes (usually) are implemented first!

You can find the full source code of this article here: https://github.com/KDAB/android

The post Qt on Android: How to create an Android service using Qt appeared first on KDAB.


“Unboxing” the Android Things Developer Preview

$
0
0

Android Things is Google’s answer to creating an environment for IoT devices. Take a slimmed down Android build, add some sensor-specific APIs, and provide it on a number of powerful pre-integrated micro-boards and you have a ready-made platform for building a host of upcoming IoT devices. Android Things can take advantage of many existing Android libraries, toolkits, and APIs, making it easier and quicker for developers to turn ideas into product. What’s not to like?

We decided to test this theory by checking out the Android Things Developer Preview on a Raspberry Pi 3. We were looking to assess the overall experience, to understand what types of products it is targeting and to try to determine how well it can support Qt.

Raspberry Pi 3 (Model B)

One of my very first observations is that Google does not provide the source, just a pre-built image. This makes it difficult to customize the image and puts us at the mercy of Google for updates to any of the contained components or packages like the kernel or SSL library. Let’s hope that this will change once we’re beyond the Developer Preview stage.

Once you have the image loaded onto a board, it’s time to boot it and take it for a spin. This is an appropriate time to get a coffee — and you’ve got the time to drive to Starbucks — because booting Android Things takes a very long time. Linux builds for Yocto or Debian on the same hardware boot significantly faster than Android Things, so we can probably assume the boot process hasn’t yet been fine-tuned. Without knowing the final boot speed of an Android Things product, you may want to plan use cases around a system that’s always on and rarely needs a reboot, or that isn’t real-time and can afford a boot process that takes minutes.

The Android Things Preview on the Raspberry Pi 3 doesn’t provide OpenGL ES support or a virtual keyboard, which severely limits what type of Android Java apps will run. (Unfortunately, that also means it cannot support Qt QML either.) It’s pretty safe to say that if your device plans to have a full smartphone-like display, you might not want to use Android Things anyway. Although it does support frame buffer graphics, without hardware acceleration the graphics are quite pokey. Our guess is that even if Android Things will eventually support OpenGL ES, its best application will be for a headless configuration or one where your display needs aren’t too sophisticated.

Unfortunately, boot speed and graphics aren’t the only things that are sluggish. Running and installing apps are quite slow: first time loads for a Java app are around 20 seconds, and for a Qt app around 25 seconds. This delay is likely due to the AOT compiler, because things speed up dramatically to a boot in just 2-3 seconds on subsequent loads. While this is a pain for developers who will suffer these load times for each new build, the AOT compiling means that customers would only notice a slow experience first time out-of-the-box.

Now for the good news. Qt developers will be happy to know that Qt Creator works very well with Android Things — running and debugging apps just works. And not only will QWidget-based applications run on Android Things, they’re even faster than the platform’s native Android Java widgets. This may not be saying much without GPU-accelerated graphics but any speed improvement is a bonus.

Also good news is the device’s security. Android Things uses the Android security/permissions model across the board, letting you have complete security control of your IoT device access, and placing all apps in isolated containers by default. With IoT security being a primary concern, built-in security from the ground up is most welcome.

Finally, Android Things is Apache 2 licensed. People who are building an IoT device to be sold as a product will appreciate that they don’t have to open up their source code to the world. It is a disadvantage to those who are tinkering but this choice (and the Google source ownership) pretty clearly point to a commercial product bias.

Conclusion

Android Things

If you’re an Android fan, you’ll like where Android Things is going. It’s a bit on the slow side, as it’s clearly designed with certain use cases in mind — like little (or no) display and infrequent reboots — but the benefits of Android development may outweigh the disadvantage of carrying around a massive Android runtime. It will definitely suffer on low-end devices but we can hope that optimizations will be made as more programmers get their hands on it. We’ll certainly be keeping our eyes on it and, as running C++ can do nothing but help the overall speed, we’ll be trying to make sure that it supports Qt as best as possible.

The post “Unboxing” the Android Things Developer Preview appeared first on KDAB.

Perfect Debugging Experience with QtCreator on Android

$
0
0

While I was working on a yet-to-be-announced super secret and cool Qt on Android project, I had to do a lot of debugging. This way I found that debugging Qt apps on Android using QtCreator was ok, but it had some issues, which was kinda frustrating.

  • First issue was that I could not debug on an Android 8 device.
  • Second issue was that, even if the debugger was almost ok for debugging Qt apps, debugging Qt itself was not that good.

Long story short, these problems will be fixed starting with QtCreator 4.6.1 (was too late for 4.6.0) or 4.7, and I also paved the way for using lldb if necessary, though, gdb works perfectly for me. And in the (distant) future MAYBE even being able to do java debugging from QtCreator as well!

Keep reading if you are interested in technical details.

How the debugging worked until now: it used a handshake technique:

  • The application built for debugging bundles gdbserver into the apk.
  • We start the application from QtC with some special params.
  • The app checks these params, it starts gdbserver, it creates a socket, then it waits for QtCreator to connect to this socket.
  • QtCreator uses adb to forward gdbservers and the socket port to your host.
  • QtCreator tries to connect to the socket created by your application. When it succeeds to connect to that socket it attaches host gdb to gdbserver. At this moment all the application’s .so files are loaded and gdb will search for their symbols on the host side. It sets the breakpoints.
  • At the end it signals the java application (using the previous socket) that it can continue the execution.

How it works now: it’s using the same technique that Android Studio uses:

  • The application built for debugging bundles gdbserver into the apk.
  • The application is started in debug mode (we add “-D” param to adb shell am start).
  • The default wait for debugger dialog appears which waits for a jdb connection.
  • QtCreator uses “adb shell run-as” to search for gdbserver and it starts it.
  • QtCreator uses adb to forward gdbservers and the socket port to your host. At this moment no .so files are loaded by your application.
  • QtCreator connects to gdbserver.
  • QtCreator uses jdb to attach to the java debugger and it signals the application to continue the execution.

At first glance, both ways look similar, but …. there is a big difference 🙂

  • First and foremost the application doesn’t need the handshake hack, this means that we can soon drop that code from Android Qt apps.
  • The second difference, which makes the debugging perfect, is at the point when we attach gdbserver to the application. As you can see, in the first way we attach gdbserver to the application after we load all .so file, this means that all breakpoints to static vars constructors or to JNI_Onload will not work, because these functions are already called by the linker.
  • Now, because QtCreator is in control of the gdbserver part, with some effort it can search for lldbserver instead, and start it.
  • Last but not least, because it’s using jdb to start the application, it might be possible to use it also to debug the java part of the application!

The downside of the new way is that the start up is a little bit slower, because instead of loading the symbols for all the .so files at once, it will load them one by one as they are loaded by the application, which on my Ryzen 1700X is from 2 to 5 seconds slower.

If you can’t wait for QtCreator 4.6.1/4.7 you can cherry-pick the following two patches and rebuild QtCreator yourself:

In the end I want to thank The Qt Company folks who helped me in testing these patches on all platforms and on as many devices as we had!


About KDAB

KDAB is a consulting company offering a wide variety of expert services in Qt, C++ and 3D/OpenGL and providing training courses in:

KDAB believes that it is critical for our business to contribute to the Qt framework and C++ thinking, to keep pushing these technologies forward to ensure they remain competitive.

The post Perfect Debugging Experience with QtCreator on Android appeared first on KDAB.

QtCreator CMake for Android plugin

$
0
0

Santa Claus is coming to … wait a minute, it’s not Christmas yet!

I have the pleasure to let you know that KDAB has contributed to Qt with yet another super cool project! It’s about QtCreator CMake for Android! I know it’s a strange coincidence between this article and The Qt Company’s decision to ditch QBS and use CMake for Qt 6, but I swear I started to work on this project *before* they announced it 🙂 ! This plugin enables painless experience when you want to create Android apps using Qt, CMake and QtCreator. It’s almost as easy as Android Qmake QtCreator plugin! The user will build, run & debug Qt on Android Apps as easy as it does with Qmake. Before I go into the boring details, let’s see what the requirements are and, more importantly, when it will be available! Requirements:

  • cmake 3.7 or newer (needed for server support in QtCreator)
  • NDKr18 or newer (only Clang and libc++ shared are supported)
  • Qt 5.12.1 (was too late for this patch to get in 5.12.0)

When will it be available? Well, I started the blog with the Santa on purpose, because, sadly, it’s too late to push it in QtCreator 4.8 and it will be available in the next version (4.9). If you can’t wait for QtCreator 4.9 and you like to try it sooner, you can apply this patch on top of QtCreator’s master branch. Now back to technical details, in order to build your Qt Android application, this plugin must do some magic:

  • after it builds the C++ bits, it copies all the targets (DynamicLibraries) into “{build_folder}/android/libs/{arch}”
  • generates android_deployment_settings.json, which is needed by androiddeployqt tool

After this step, androiddeployqt will complete your Android Qt APK by copying all the Qt dependencies (libs & resources). Last but not least, these are qmake features that you’ll not find in cmake:

  • IDE management for ANDROID_PACKAGE_SOURCE_DIR yes, it supports even the same naming as qmake. You’ll need to add the following piece of cmake script to your CMakeLists.txt file:
    if(ANDROID)
        set(ANDROID_PACKAGE_SOURCE_DIR &quot;${CMAKE_CURRENT_SOURCE_DIR}/android&quot; CACHE INTERNAL &quot;&quot;)
    endif()
    

    The CACHE is mandatory, otherwise QtCreator won’t see the variable and it won’t use it

  • IDE support ANDROID_EXTRA_LIBS, you’ll need to add the next piece of CMake script to your CMakeLists.txt file
    if(ANDROID)
        if (ANDROID_ABI STREQUAL &quot;armeabi-v7a&quot;)
            set(ANDROID_EXTRA_LIBS ${CMAKE_CURRENT_SOURCE_DIR}/3rd-party/android_armeabi-v7a/ssl/libcrypto.so ${CMAKE_CURRENT_SOURCE_DIR}/3rd-party/android_armeabi-v7a/ssl/libssl.so CACHE INTERNAL &quot;&quot;)
        endif()
    endif()
    

    The previous snippet will add libcrypto.so and libssl.so files ONLY for armeabi-v7a android ABI.

Note: KDAB offers training in CMake, including all the latest tips from our trainers, who are all active developers.

The post QtCreator CMake for Android plugin appeared first on KDAB.

Qt sensors just got better on Android

$
0
0

Each month KDAB schedules time for me to maintain the Qt for Android port. Usually I use it to review the pending patches or fix bugs, but sometime there is a quiet month and I have time to add new functionalities or improve the existing ones.

April was quite quiet so I decided to rewrite the Android sensors plugin (no, this is not a late April fool’s joke).

Why on earth did I want to do that? Why try to fix something that works? After all, the current implementation faithfully served us for years!

I decided to rewrite it after I did some performance tests that showed some surprising numbers. When I used the NDK API to get sensors data, the CPU usage dropped from over 60% to even less than 20% (it fluctuates from 15% up to 30%)! Yup, that’s a surprising performance improvement, which TBH I hadn’t expected at all!

I expected it to be faster, as the NDK API doesn’t need to move the data to JAVA and then back to C/C++ world (via JNI) but, I never dreamed it would be that fast!

Are you wondering why we didn’t use the NDK API in the first place? It’s because the sensors NDK API was not introduced until API-16, which means that when we first implemented the sensors API, we were supporting Android from API-9. However, starting with Qt 5.9, the minimum API has been raised to API-16, so, now I can safely use NDK API for this job.

Here you can find the pending patch. It targets dev branch which will be part of Qt 5.14.

The post Qt sensors just got better on Android appeared first on KDAB.

Qt for Android better than ever before

$
0
0

As you already know KDAB is the largest independent contributor to Qt code. Of course we didn’t get lazy and we’ve added a lot of cool stuff to Qt 5.14.

In this article I’m going to write about the super cool stuff that we’ve added to Qt 5.14 for Android.

Android multi arch build in one go

Folks, this is the biggest feature added to Qt on Android since I made the Qt on Android port! I dreamt on this change for a very loong time! I found that is possible to add such support to qmake by mistake :). I had to do some work on Windows (which is not my platform of choice) and there I found that debug and release builds are different on Windows, the makefiles generated by qmake will build twice your source files.

This was exactly what I needed to add multi abi for Android! A few days later I had a WIP patch and, with the help of The Qt Company people, we landed the change in Qt 5.14 alpha!

Let’s see what is new:

  • First and foremost from Qt 5.14 there will be a single Qt for Android SDK. Same as the Android NDK, the Qt for Android SDK contains the libs & plugins built for all Android platforms (armv7a, arm64-v8a, x86, x86_64). If you’re building Qt from sources and you want to build only for e.g. arm architectures, you can filter them using the new -android-abis configure parameter:
     ./configure -android-abis armv7a,arm64-v8a -developer-build -xplatform android-clang -android-ndk /home/bogdan/android/ndk-bundle -android-sdk /home/bogdan/android
    
  • If not specified otherwise, your application will be built by default for all these platforms in one go. You can filter which ABI(s) you want to build for using the ANDROID_ABIS qmake variable, this is useful while you develop your application, to cut the build time. Build only for arm64-v8a
    qmake ANDROID_ABIS="arm64-v8a"

    Build only for armv7a and arm64-v8a

    qmake ANDROID_ABIS="armeabi-v7a arm64-v8a"

Yes, we changed Qt Creator to make it easier to choose which platforms you want to build for, check the next image:

In order to support this super cool feature we had to change a few things:

  • All the .so files produced by qmake are suffixed with the android abi. If you’re using Qt library/plugins classes you don’t need to take any actions, otherwise qmake sets QT_ARCH variable for the ABI you’re currently building, so you can use it to know which suffix you need to add e.g:
    # ...
    android: DEFINES += LIBS_SUFFIX='\\"_$${QT_ARCH}.so\\"'
    # ...
    

    Then you can use LIBS_SUFFIX macro in your srcs.

  • Because on android we have only one libs folder level, we must rename all the [qml] plugins to make sure we don’t have any name clashes. We use the following naming scheme:
    lib + "plugin/path".replace('/','_') + {plugin_name} + _$${QT_ARCH}.so.

    If you have a plugin which uses ANDROID_LIB_DEPENDENCIES qmake variable make sure you use the previous naming scheme. Here https://codereview.qt-project.org/c/qt/qtgamepad/+/273676/2/src/gamepad/gamepad.pro you can see how we did it for Qt Gamepad module. Initially I did the renaming from androiddeployqt, but soon I found that this breaks the plugins debugging, as the gdb won’t find the renamed files on the Qt folders, and for me not being able to debug my precious plugins was unacceptable.

Android App Bundles (aab)

I’m going to tell you a secret, Android App Bundles were the main reason for doing the multi arch build in one go :). Without multi arch build in one go you can’t have aab, well at least not without a lot of work, pain and sorrow. Because I’m a happy, lazy person, I don’t like to work more than I must, therefore I had to find a solution to make our life easier. In Qt 5.14, it’s very easy to build an .aab file:

$ make aab

it’s all you need to run on a terminal to build it!

Same as above, I added a new option to Qt Creator to enable .aab packages with a single check box, see the following image:

Load Qt plugins directly from android libs folder

Since Qt 5.14, the Qt plugins were stored to android assets and then extracted to your home folder at the very first start. There are two problems with this approach:

  • The very first startup time needed more time to extract all the files
  • It occupies more disk space

Starting with 5.14, instead of bundling the plugins and QML resources in assets and extracting them on first start, Qt now creates an .rcc file and registers it before invoking the main function.

Other pretty nice changes

  • Same as above, in Qt 5.14 you can easily create an apk from the command line:
    $ make apk

    is all you need to type on your terminal to create it.

  • Reworked assets support – the new version fixes QDirIterators, also it lists all the files and folders.
  • NDK r20+ is needed as I updated the clang mkspecs to follow https://android.googlesource.com/platform/ndk/+/ndk-release-r20/docs/BuildSystemMaintainers.md guide. With this change, let’s hope we’ll have less issues with newer NDK versions, as you probably noticed Google folks are restless and they are doing their best to break other tools from time to time :).
  • Drop gcc support – this was a change that personally I didn’t like to do it, but I had to, mostly because it was quite challenging to support NDK r10e (the recommended NDK for gcc).
  • Last but not least, an easy way to run tests on Android:
    $ make check

    It’s all you need. For more details and tweaks about it, you can come to my Qt World Summit presentation ;-).

  • See more about KDAB Talks at Qt World Summit

The post Qt for Android better than ever before appeared first on KDAB.

All about Qt on Android

$
0
0

In this session we’ll see real life examples of using JNI on Android. We’ll start by checking the Qt 5.7 goodies which will make our lives easier, then we’ll see simple examples that you’ll need to use in almost any Qt on Android application, and we’ll end up with an Android Service made with Qt.

In this session we’ll see real life examples of using JNI on Android. We’ll start by checking the Qt 5.7 goodies which will make our lives easier, then we’ll see simple examples that you’ll need to use in almost any Qt on Android application. At the end, we’ll see how to create an Android Service made with Qt, and we’ll see how to use QtRemoteObjects to communicate with that service.

View the slides

The post All about Qt on Android appeared first on KDAB.

Automotive Grade Maps and Navigation for Everyone

$
0
0

It is our pleasure to introduce a shiny new Maps & Navigation solution for QML developers!

This QML plugin is a joint effort between KDAB & General Magic to bring the excellent General Magic Maps and Navigation SDK to the QML world.

What makes the General Magic QML plugin special?

  • It’s easy to use. With this QML plugin, you can write custom Map & Navigation apps in no time.
  • It’s lightweight. It runs on even low-end embedded platforms
  • You can work with it both offline and online. Yes, you can do: mapping, searching, routing, and navigation using only the offline data stored on your device. Of course the same features will work with online data, if an internet connection is available.
  • It supports multiple platforms. We currently support the following platforms:
    • Embedded: GNU/Linux (armv7a, armv8)
    • Mobile: Android (x86, x86_64, armv7 & armv8), iOS
    • Desktop: GNU/Linux, Mac OS X, Windows (msvc)
  • It has all the features that you expect from a first class Maps and Navigation SDK:
    • Maps: OpenStreetMaps, terrain, satellite imagery, online & offline
    • Search: fuzzy search, address search, forward geocoding, reverse geocoding, online & offline
    • Routing: car, pedestrian, bicycle, public transport, traffic aware routing, online & offline
    • Navigation: turn-by-turn guidance, traffic aware rerouting, lane guidance, speed limits, speed cameras, online & offline

For more information, including licensing options, please visit the products and pricing pages.

How can I get the maps and navigation QML plugin?

Please see this page for step by step instructions.

In the above video, you’ll find a step-by-step example of how to create a simple navigation application on Linux and deploy and run it on Android and RPi4. The QML plugin and its documentation and examples should then be installed in your Qt/QtCreator. If you prefer the online documentation, you can access it here.

This plugin is currently a Technical Preview release! That means that, while it is fully functional and ready for you to try out, you should use it with caution in production, as we reserve the right to change the API without notice, for the moment. It also means that we are looking for feedback and issue reports. We encourage everyone to report them here.

About KDAB

If you like this article and want to read similar material, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post Automotive Grade Maps and Navigation for Everyone appeared first on KDAB.


Android Shared Storage Qt Wrapper

$
0
0

In this article, I’d like to talk about Android storage.

In recent Android versions, Google decided, for a good reason, to restrict the access to the SD card. This means, even if your application will have the old READ/WRITE_EXTERNAL_STORAGE permissions declared and granted, you won’t be able to freely access the SD Card contents like you used to.

In order to access the SD card or any other shared storage places, you’ll have to use the Android shared storage API. The good news is that, with this API, you’ll be able to access any file from any storage location (i.e. from gdrive), without any special code.

As you probably already know, a long time ago, my colleagues added to Qt 5.13 the following basic support features for shared storage:

  • create a new file using an existing content provider (i.e. QFileDialog)
  • open an existing file using an existing content provider (i.e. QFileDialog)
  • list directory content* using an URL from an existing content provider (i.e. QFileDialog)

But there are quite a few features that are missing, mostly due to these missing implementation or incompatible/limited Qt platform abstractions:

  • create a new file in an existing folder URI.
  • create a new folder in an existing folder URI.
  • remove a file/folder.
  • rename a file/folder.
  • move a file/folder to another place.
  • copy a file/folder to another place.
  • get file mime type.
  • etc.

We’ve added all the above missing features to a new Qt (5.x & 6.x) shared storage library for Android. This library gives you complete access to documents and other files from shared storage.

Until we manage to add the missing pieces to Qt’s platform abstraction, or if you still need to use Qt 5.x, you can use our shared storage library.

Here you can find an example that shows how to use this library to perform most of the common operations.

Another thing that I personally don’t like about the current Qt platform abstraction is that FileDialog QML Type will add QWidgets to your pure QML application. I hope we’ll address this in the next Qt versions as well.

About KDAB

If you like this article and want to read similar material, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post Android Shared Storage Qt Wrapper appeared first on KDAB.

Reverse Engineering Android Apps

$
0
0

Reverse engineering in general is a tricky business and sometimes not very orthodox. So, why bother to write this article?

Well, sometimes reverse engineering is also for something good. It started when my wife dusted off her watch. We had a huge unpleasant surprise when we found that the companion app is not available anymore on Google Play! The watch is completely useless without the companion app, as you can’t even set the time on it… Because I hate to throw away a perfectly working watch I decided to create an app for it myself.

My first instinct was to find an older phone with the app still alive and to use a BLE sniffer to reverse engineer the BLE protocol. But I didn’t find the application installed on any old phones. I found the application online but the application cannot be used anymore as it was using some online services which are offline now…

Next obvious step was to decompile the application to get the communication protocol and also the algorithms behind the sleep & activities. This is how our story begins ;-).

Long story short

Decompiling Android apps is not that complicated. It takes time (a LOT of time), but it’s fun and rewarding.

Just don’t believe all those movies where someone decompiles an app and understands all the logic behind it in seconds :).

Tools I used to decompile:

  • tintinweb.vscode-decompiler, a VSCode extension (https://marketplace.visualstudio.com/items?itemName=tintinweb.vscode-decompiler). Using this extension is quite easy to decompile an apk, just right click on it and the magic will happen in a few seconds. The only problem I found is that it doesn’t do any de-obfuscation (or at least I didn’t setup it correctly).
  • Dex to Java decompiler (https://github.com/skylot/jadx). I found it better than vscode-decompiler as it has semi de-obfuscation. You’ll never get the original namings, but you get unique names instead of a, b, c, etc.
  • NSA’s ghidra (https://github.com/NationalSecurityAgency/ghidra). Apart from a lot of java code, this application has all the logic into native C++. I used ghidra for decompiling the native (C++) stuff. It has java decompiler as well, but is not as good as jadx.

Short story long

I chose an older version as the last one had support for too many watches which I didn’t care about (at least not now). Android APKs supports (partial) obfuscation, which makes the decompilation not that straight forward, in some cases it’s actually pretty complicated. What does obfuscation do? It renames all packages to: a, b, c, etc. then all classes from each packages to: a, b, c, etc., then all members of each class to: a, b, c, etc., then all fields to (yes, you guessed right): a, b, c, etc. This means you’ll end up with loads of a classes, member functions and fields.

Some times it is easy to guess what the fields are, e.g.:

jSONObject.put("result", (int) this.c.a);
jSONObject.put("fileHandle", this.c.c);
jSONObject.put("newSizeWritten", this.c.d);

But in some cases you need to do lot of detective work.

As I mentioned in the beginning, I used 3 tools: vscode-decompiler extenstion, jadx and ghidra:

I started with vscode-decompiler, hoping that githubs copilot will help me in the process. It turned out to be completely useless for such tasks. When I imported the decompiled stuff into AndriodStudio, due to obfuscation, 90% of the classes had problems. Because there are dozens of classes with the same name (i.e. “a“, “b“), imagine how many conflicts you get.

Next was to use jadx to decompile the application, which supported semi de-obfuscation. I could import the project into AndroidStudio. Now, all the obfuscated classes have unique names (e.g. C1189f), which makes the AndroidStudio happier.

Just to be crystal clear, you cannot recompile the application and run it, unless the application is simple enough! After a few hours of guessing the name of the classes and their fields, I finally found what I was looking for: the BLE protocol! To my surprise, it has so many commands. I quickly cleaned out a few BLE commands that I was interested in:

  • start/stop the sync animation on the watch
  • set/get the time

I used bluetoothctl to quickly try the start/stopAnimation BLE commands, it worked perfectly.

The application has all the sleep & activities logic written in C++, so I had also to decompile the native part as well. For this job, I used ghidra with https://github.com/extremecoders-re/ghidra-jni extension. Ghidra is a fantastic tool. I tried a few more tools: radare2/rizin, binary ninja (the free online version), but, personally, I found ghidra the one most rich in features. The C++ compiled code is obfuscated “by design” due to various optimizations done by C/C++ compilers and it’s far, FAR harder to decompile than java. A long time ago I did a lot of binary decompilation and most of the time when I was trying to generate any C/C++ code from a binary, it resulted in pure garbage. I was amazed at how good ghidra’s C/C++ decompilation is.

Just to be clear, it requires a *LOT* of time to clean the code, to define all the structures, to do all the connections between them and to un-flatten all the STL stuff (here, some STL internals knowledge is needed), but the experience was better than I ever dreamt. Even if we can guess what it does from the function name, let’s take a very simple example to see what the C++ decompilation looks like and how verbose STL can be:

undefined Java_package_class_name_ActivityVect_1add
                    (JNIEnv *env,jclass thiz,jlong a0,jobject a1,jlong a2,jobject a3)
{
  undefined uVar1;
  undefined8 *puVar2;
  undefined8 uVar3;
  undefined8 *puVar4;

  if (a2 == 0) {
    uVar1 = FUN_0015d3ac((long *)env,7,
                         "std::vector< Activity >::value_type const & reference is null");
    return uVar1;
  }
  puVar4 = *(undefined8 **)(a0 + 8);
  puVar2 = *(undefined8 **)(a0 + 0x10);
  if (puVar4 != puVar2) {
    if (puVar4 != (undefined8 *)0x0) {
      uVar3 = *(undefined8 *)(a2 + 8);
      *puVar4 = *(undefined8 *)a2;
      puVar4[1] = uVar3;
      uVar3 = *(undefined8 *)(a2 + 0x18);
      puVar4[2] = *(undefined8 *)(a2 + 0x10);
      puVar4[3] = uVar3;
      uVar3 = *(undefined8 *)(a2 + 0x28);
      puVar4[4] = *(undefined8 *)(a2 + 0x20);
      puVar4[5] = uVar3;
      uVar3 = *(undefined8 *)(a2 + 0x38);
      puVar4[6] = *(undefined8 *)(a2 + 0x30);
      puVar4[7] = uVar3;
      puVar2 = *(undefined8 **)(a2 + 0x40);
      puVar4[8] = puVar2;
    }
    *(undefined8 **)(a0 + 8) = puVar4 + 9;
    return (char)puVar2;
  }
  std::vector<>::_M_emplace_back_aux<>((vector<> *)a0,(Activity *)a2);
  return (char)a0;
}

All right, the decompiled code is pretty cryptic and it doesn’t tell us too much. Now, let’s see if we can make it better:

  • first we need to define the Activity structure. I was lucky as I knew all the structure fields because they were set by the Java code via JNI in other places ;-).
  • next is to define the std::vector structure, every single std::vector defines 3 fields:
    T *__begin_;
    T *__end_;
    T *__enc_cap_;
    

    Yes, that’s all a std::vector needs to do all the magic: iterate, insert, push, pop, erase, etc.

  • last but not least use them in our function:
undefined Java_package_class_name_ActivityVect_1add
                    (JNIEnv *env,jclass thiz,vector<> *vec_ptr,jobject a1,Activity *value,jobject a3)
{
  undefined uVar1;
  Activity *end_cap;
  uint64_t uVar2;
  Activity *end;

  if (value == (Activity *)0x0) {
    uVar1 = FUN_0015d3ac((long *)env,7,
                         "std::vector< Activity >::value_type const & reference is null");
    return uVar1;
  }
  end = vec_ptr->__end_;
  end_cap = vec_ptr->__end_cap_;
  if (end != end_cap) {
    if (end != (Activity *)0x0) {
      uVar2 = value->endTime;
      end->startTime = value->startTime;
      end->endTime = uVar2;
      uVar2 = value->bipedalCount;
      end->point = value->point;
      end->bipedalCount = uVar2;
      uVar2 = value->maxVariance;
      end->variance = value->variance;
      end->maxVariance = uVar2;
      uVar2 = value->doubleTapCount;
      end->trippleTapCount = value->trippleTapCount;
      end->doubleTapCount = uVar2;
      end_cap = *(Activity **)&value->tag;
      *(Activity **)&end->tag = end_cap;
    }
    vec_ptr->__end_ = end + 1;
    return (char)end_cap;
  }
  std::vector<>::_M_emplace_back_aux<>(vec_ptr,value);
  return (char)vec_ptr;
}

Okay, so now the code is much cleaner and we figure out exactly what this function does. This means we can write it in a single line of code:

vec.push_back(val);

Of course, you’ll find more, MUCH more complicated cases where you’ll spend a lot of time to figure out what’s going on.

I really hope some day the AI will be intelligent enough to do this job for us. Yes, I’m one of these people that is not afraid to embrace the new technologies :).

Side note, even though ghidra has an excellent C/C++ decompilation, good ASM knowledge will help a lot where ghidra fails to decompile to C/C++.

After I had enough info about BLE protocol, I began to write a Qt application to use it. I found the BLE support in Qt 6.5.1 quite good (at least on android & linux desktop) as I could use quite a few BLE commands painlessly.

The application is still at the beginning and it will require more time, pain and sorrow to get it at the same level of the original application, but it’s a start ;-).

Thank you for your time.

About KDAB

If you like this article and want to read similar material, consider subscribing via our RSS feed.

Subscribe to KDAB TV for similar informative short video content.

KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.

The post Reverse Engineering Android Apps appeared first on KDAB.





Latest Images