A View from the Top: A Virtual Prototyping Blog

 

21 steps to setup a debugger for Android

Using the Google Search Debugger

I am spending a reasonable amount of my time helping our users to bring up Android on their chipsets or devices. I am not an Android expert, I gathered my limited knowledge about Android mainly during debugging. I must admit that the first tool I am using when a problem appears is a Google Search. This brings me to the respective expert forums where I hope somebody else has already done the job for me. With Android, this works reasonable well as Android produces an extensive debug log from which I can copy and paste messages into the search bar. With more than 7000 users and 16000 messages just in the Android porting group, chances are high to find something useful. Often the solution to the problem is already there for me.

Android forums did sometimes also the opposite and put me and a completely wrong track. The fact that a symptom is the same, it does not imply the root cause is also the same. Android is a huge SW stack sitting on-top of Linux, which runs on the HW. A bug is often only triggered because of a special combination of Android/Linux version & patch  combinations and the specialties of the underlying HW platform. How to get back from Googling into Thinking? Today, I try to force me limiting my Google Search debugging to 20min.  After this time I get my hands on into debugging the problem.

Hurdles of using a SW debugger for Android applications and the Android platform

Let’s start debugging the problem. Unfortunately, it is not just launching the software in a debugger and step through the code as we are used to for desktop applications. There are quite a number of hurdles to overcome before we can actually debug. When porting to new hardware, the root cause can be everywhere. Even proven applications, stable Android runtime modules or Linux drivers cannot be excluded.  I have often wasted a lot of time debugging when I have refrained myself from investigating SW modules that are said to be stable. Of course, the stability of a module has to be considered, but one should not hesitate to question and debug those as well. Just recently I have found a defect in the Android Apps installer, which has been triggered by a very specific kernel version and filesystem type (http://tinyurl.com/3b3szbj, could only reply my fix directly to the author). Debugging is not exactly easy with Android. Not because Android is so complicated, but just from a pure practical perspective it can be very hard to setup  a debugger.  For application developers, the Android SDK is providing very convenient debugging capabilities for the Java layer. The companion NDK (native development kit) allows developers to package native code libraries with their applications. But, only one year after its first release in June 2009 it actually provided support for native code debugging.  Beyond the NDK and SDK, when the whole Android platform is subject of debug, then things get much more complicated and solutions are sparse. A very useful guideline for debugging I have found in the web, it still requires 12 steps to set up the debug session and another 9 steps to connect the debugger.

Why is setting a debug session more difficult with Android?

What applies to Android may as well apply to many other integrated SW stacks. Each high level device function is delivered by the interaction of many distributed software entities, some of them may be written in Java, others in native code. Most of them executing in the user space, but a fair amount of functions of course also reside in the OS and its drivers.

Another challenge is imposed by the fact that processes and threads are launched and terminated by other processes automatically. First of all you do not know which processes are contributing to a high level device function, and even if you know, the process is often terminated already before you had a chance to connect a debugger. In order to solve that,  the best practice is to add an busy wait loop into the code and recompile the respective module.  This will give you the chance to connect the debugger at the right point in time and before the bug has eventually passed. The same technique is required when debugging on the Java/C boundary as there is no way to auto-step from Java code down to native code within the debugger. Once you can connect a debugger, it all works pretty well as long as you stay in one software module. But, it is a very tedious process as it requires to modify and rebuild software module, bundle new filesystem images, reproduce complex scenarios each time you want to debug another piece in the puzzle.

If you do not know which SW function to debug, you may add those halts to many places with dangerous side effects. Halted processes may cause time outs or simply impact the sequence of events in the system masking the bug. Many more challenges exist, but I want to stop here as I would like to switch over to talk about some solutions to these problems.

What’s next?

In my next post, I would like to introduce how Virtual Prototypes (VP) can help to overcome some of the debug challenges appearing with SW stacks such as Android. As a simple example, the controllability of a VP will help us to intercept the execution of a single SW process. Moreover, I will show you how to inject a halt without modifying the software using a VP. But beyond fixing deficiencies in debug flows, VPs enable much more if used in the right way. A VP can act as a debug server which significantly eases the debug setup and turns you much quicker from an experimenting/guessing mode into systematically analyzing the problem.

Share and Enjoy:
  • del.icio.us
  • Digg
  • Facebook
  • Google Bookmarks
  • Print
  • Twitter
  • StumbleUpon
  • LinkedIn
  • RSS