Fun with Android
AKA: I know what you did last Christmas !
I’d like to share with you a few things that I did during this Xmas.
Besides the fact I’ll never ever take a vacation before Xmas, because Brasov is a tourist attraction and it was FULL of tourists in that period. I could ski only once 🙁 , because it snowed just a few days before New Year and then the police closed the roads to the ski resort because there were way too many cars in that area.
Anyway it was also great because I spent a lot of time with my family. But because there was no snow outside, I also had some time for myself and I didn’t want to waste it all. So, for the sake of old times, I started to buy some old games (from gog.com) and I began to play them with my son. But we soon finished most of them and we started to play 0 A.D. a super cool and free (as in freedom and also as in beer) strategy game. After a while my son asked me if he can play that game on a tablet. I said:
“at this moment you can’t play it, but I’ll take a look 🙂 “
This is how my new journey began, and this is what this article is about 🙂 .
Strangely, exactly five years ago I began another journey, on the same day I started the Qt on Android port ;-).
So, I began to check the source code and I posted my intention on wildfiregame’s forum and then, I started the 0 A.D. game engine port:
- the first step was to compile all 0 A.D. dependencies, TBH this was the most time-consuming step and it wasn’t fun at all. Qt framework has all the features that 0 A.D. needs and my first approach was to use Qt instead of all 0 A.D.’s dependencies but 0 A.D. developers didn’t like it and I had to cross-compile all the dependencies for Android. This step was already begun some time ago by someone else, but it was quite unfinished. The good news is that I learned how to cross-compile automake, cmake, etc. projects for Android ;-). Again this job is anything but fun 🙂 .
- the next step was to add to 0 A.D. a first citizen class support for Android, that I can use to code, deploy, run & debug on Android. Even though I know how to debug Android apps from a terminal, I’m way WAY to lazy to do such a thing. Of course the only choice I had, was QtCreator. When I designed QtCreator’s Android plugin, I did it in such a way that it can be used also by non-qt apps, but I never had the chance to put that theory to the test 😀 . So, after I had added qmake project files, (nope, I don’t like qmake that much, I chose qmake simply because it is the only build system that can be used by QtCreator to target Android devices), it was time to test if I can use QtCreator to develop non-qt apps on Android. Folks, I’m happy to let you know that QtCreator works just fine with non-qt apps to target Android! In this step I had to update the Android (java) part of the project to add debug support needed by QtCreator.
- the next step was to fix all the crashes and enable all 0 A.D. features. Using QtCreator and being able to debug the application in a decent way, this job was quite easy, and soon I fixed all (visible) crashes and I enabled all 0 A.D.’s features!
- but la vie is not always en rose and I faced a problem that was way beyond my (current) knowledge. 0 A.D. had some problems with GLES on Android. Together with an 0 A.D. developer, we started hunting this errors. But this job was extremely hard and boring … The problem was that I had to add tones to glGetError() to find the place where the error occurred… after a long time, we managed to hunt down one of the errors. But a few more still remained. Thanks to my legendary laziness, I started to look for another much easier solution. That guy asked me if Android has any OpenGL debuggers/tracers. After that moment I become obsessed by the idea of finding a decent solution to debug/trace OpenGL calls on Android.
AKA: The quest of hunting down 0 A.D.’s GLES problems!
So, the big question is: Are there any decent OpenGL debuggers/tracers for Android? A quick search on the net answered my question. It seems there are a few OpenGL debuggers/tracers for Android. So, I started to check if any of them are decent and useful 🙂 .
- I began my research with Android’s own tool. To start tracing is quite easy: you need to start the application on the device, click on trace icon (in that tool), choose a file (on your desktop), check a few options and wait … After the trace was finished I was very anxious to see which one of the +10k OpenGL calls/frame caused the problem! Sadly I had a very unpleasant surprise. The thing didn’t point me to the problem at all 🙁 . Even more, going from one frame to another takes an eternity… so, at least for me, this tool was no good.
- then I found Mail’s graphics debugger. After a quick look on their website my heart was full of hope! MGD is not that easy to use, but I managed to get it deployed on Android. I started the GUI and I also got it connected to application on the device. But after this step my hope was ruined and my heart broken. After it connects to GUI the application crashes on the device; it seems it has some unimplemented EGL/GLES APIs 🙁 . Of course my first thought was that I did something wrong and I started to dig deeper, but no luck, so, one more OpenGL debugger off my list.
- the next tool on my list was powervr. I looked at it with a lot of hope but that soon vanished because, after I downloaded, the “SDK” asked me for root permissions to install. I wasn’t that desperate to give it root permissions!
- I briefly checked NVidia’s Tegra graphics debugger, but I didn’t even dare to download it because I don’t have any Tegra Devices.
- The last tool I checked was apitrace. Folks it was love at first sight! Even though apitrace is not as easy to use as Google’s tool, I managed to integrate it quite easy (and in a decent way) into 0 A.D.’s project. After I created the trace, I pulled it from the device to check it. TBH after the previous failures, my hope was not that great, but I took the courage to check it anyway. Folks, apitrace’s GUI it a gazillion times faster than Google’s tool! I was extremely surprised to see my laptop really replaying the trace and finding some errors! I began to check those errors and I soon found out that my desktop GLES implementation is not the same as the one on Android 🙁 … Most probably most Android implementations are not the same (e.g. Mali’s implementation is probably different from Adreno’s). The only hope to catch those errors was, somehow, by doing the retrace on Android alone …
Retracing on Android … AKA: Mission Impossible
So, I started to check the apitrace (retrace) source code to see how and if it can be ported on Android. The challenge was to pass the application arguments and to redirect somehow the stdout and stderr from the device to the desktop.
Apitrace (retrace) uses stdout, stderr to send back results to the user/UI. So, the only way to do it, it was to hook stdout and stderr on Android and redirect all the traffic to a pair of sockets, then forward those sockets (using adb) to the desktop. I also chose to use stdout socket to send the params to application on device. But what if the application doesn’t have INTERNET permission set, which is needed for sockets? What if those ports are already in use? This was an easy task, because I asked myself the same question a few months ago, when I worked on Android 5.0 support, so I chose to use LocalServerSocket instead of the old fashioned sockets. This way all the potential problems were avoided.
So, I created an android GLES retrace on the C++ side (based on egl_x11), a custom Android Activity, a custom Surface, etc. Of course, I also added QtCreator support (yeah more qmake projects 😀 ), to be able to debug, and soon, I had a working Android retracer!
I could use it via telnet with just a few steps (I’m listing those steps because they can be used to debug the connection):
- start apitrace application on Android.
- forward ports (once is enough):
adb forward tcp:1234 localabstract:apitrace.github.io.eglretrace.stdout adb forward tcp:1235 localabstract:apitrace.github.io.eglretrace.stderr
- connect to both channels
telnet 127.0.0.1 1235 telnet 127.0.0.1 1234
- then send the arguments via stdout channel (1234 port in our example)
But, as you can see, is not very easy to use and I couldn’t use the UI …
Again, my titanic laziness come into place, and I began to work on a decent way to do retrace on Android using the existing UI.
IMHO a decent retracing on Android needs to meet the following requirements:
- a way to pull the trace from device to desktop
- a way to push a trace from desktop to an Android device, if the trace was done on another device and you have it on your desktop.
- a way to link a desktop trace file with an Android trace file
- automatically starts the retrace application on device
- forwards the ports (using adb) to desktop
- connect to those ports, send the params
- read the data from ports instead of QProcess stdout, stderr
Folks, I’m proud to let you know that I managed to finish all those requirements! I’m quite pleased how it ended up! All the mysterious errors were revealed!
Of course because I want all the people to enjoy a decent Android OpenGL debugging, I created the pull request for all my work.
Using apitrace on Android I knew which OpenGL commands caused the errors! This helped an 0 A.D. developer, (Philip` is his nickname on irc), to fix these errors in a few minutes. I needed his help because my OpenGL skills are close to 0 (A.D.) and making an Android retracer didn’t make me smarter at all in that area :).
Of course this is the first step to get 0 A.D. on Android, there is a lot of work to be done before we’ll be able to enjoy it on our tablets!
If anyone wants to join this fantastic free project, please check 0 A.D.’s participate page. 0 A.D. is a project where anyone can help not only programmers! If you are an artist that knows how to paint, create music, write scenarios, have a nice voice, etc., or you want to help with translations for the game, in your own language, you can join and contribute!
Also apitrace needs contributors, if you want to help, then you can check their TODO list to see if you can make the world a better place 😉 !
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.