Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Android

Writing an Android GUI using C++: Part 3: Debug

4.81/5 (8 votes)
23 Apr 2013CPOL4 min read 47.4K   1.4K  
This article talks about how to debug C++ code using NDK-debug tool, and gives some advice about C++ programming on Android. If the application is written in Java, programmers can use Eclipse to debug the code, set break points, and trace step by step.

Introduction

This article talks about how to debug C++ code using the NDK debug tool, and give some advice about C++ programming on android. If the application is written in Java, programmers can use Eclipse to debug the code, set break points, and trace step by step. When written in C++, how do we debug? By now, for android version above 2.2, NDK provides an NDK debug tool, which runs on Linux, and can be used to debug the source code.

The debug environment may vary with platforms. The steps given here are based on the environment of my host, which is Windows XP, Android-ndk-r6b, and Cgywin is used to build C++ code for android. How to install android-ndk-r6b and cgywin are out of the scope of this article. You can refer to other materials.

The example code to be debugged is a list view holder which is given in the previous article. Suppose you have already prepared the environment, and the C++ code can be built for android successfully.

Changes to the project

  1. Change AndroidManifest.xml to enable gdbserver.

    Based on document of NDK, in order to debug the native code, AndroidManifest.xml should add a flag android:debuggable="true", as follows.

    XML
    <application
         android:icon="@drawable/ic_launcher"
         android:label="@string/app_name" 
         android:debuggable="true" >
        <activity
            android:label="@string/app_name"
            android:name=".DebugActivity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application> 
  2. Recompile the project with debug flag “NDK_DEBUG=1”.

    Image 1

  3. Run the project from eclipse.

Debug with ndk-debug 

Switch to Cgywin console 

  1. Run ndk-debug as follows:

    Image 2

    There may be many warnings. But need not worry, they do not affect the debug process.

  2. Type list command, you can see the source file.

    Image 3

    • use b command to set the break points.
    • use c command to continue to run.
  3. The mobile may respond slowly, please wait until the mobile can operate normally.

    If the mobile has no response for a long time, you can type CTRL+C to exit ndk-debug and repeat the above steps.

  4. Click button, then the source will be broken at the break point set before.

    Image 4

In the Cygwin console, when watching the variable value, you may see “value optimized out”.

In this case, you should add –Oo flags to the Android.mk file, rebuild the project, and restart.

LOCAL_CFLAGS += -Wno-write-strings -O0 -DENV_ANDROID
LOCAL_CPPFLAGS += -Wno-write-strings -O0 -fexceptions -DENV_ANDROID
LOCAL_LDFLAGS += -Wno-write-strings -O0 -DENV_ANDROID 

Image 5

Debug on the simulator may be less efficient with a slow response. The better choice is to buy a cheaper mobile or palm, and debug using the real device. Debugging C++ code on android is not an easy work, whether you are familiar with GDB or not. I think migrating mature code from another platform to android is a good choice, or debugging on another platform using more convenient tools other than on android directly.

Debug on Win32

CLE also supports Windows and Linux, therefore we can debug program logic on Windows. Let's discuss this in deeper. To debug on Windows, there is lots of work to do, not technology, but the work to setup stubs for android classes. The work has not started yet, so this article only gives the steps to illustrate how we can debug Android c++ code on Windows. You can also write stubs yourself following the examples in this article. The examples are also included in the download package. The result of the C++ code is a share library, on Windows platform, and it can only be built into a dynamic library. So the first step is to create a loader to init environment and load it.

Before starting, CLE for Win32 should be installed from http://www.srplab.com/data/starcore_win32.1.5.1.exe.

Dynamic library loader

The loader init CLE environment imports the wrapandroid service description file SRPWrapAndroidEngine.xml and creates a service for the share library. The loader can be created with Java, Python, lua, C#, C++, or other languages supported by CLE. Here we create it using C++. The code is shown below.

  1. Init the CLE environment.
    C++
    class ClassOfBasicSRPInterface *BasicSRPInterface;
    VS_CORESIMPLECONTEXT Context;
    
    // init CLE environment. The first parameter Context is used to get the return value.
    BasicSRPInterface = VSCore_InitSimpleEx(&Context,0,0,NULL,0,NULL);
    if( BasicSRPInterface == NULL ){
        printf("init starcore fail\n");
        return -1;
    } 
    // import wrapandroid service description file. This file contains id and name of android classe.
    {
        FILE *hFile;
        int FileSize;
        char *xmlBufer;
        hFile = fopen("SRPWrapAndroidEngine.xml","rt");
        fseek(hFile,0,SEEK_END);
        FileSize = ftell(hFile);
        fseek(hFile,0,SEEK_SET);
        xmlBufer = (char *)malloc(FileSize+1);
        FileSize = fread(xmlBufer,1,FileSize,hFile);
        fclose(hFile);
        xmlBufer[FileSize] = 0;
        if( BasicSRPInterface ->ImportServiceFromXmlBuf(xmlBufer,false) == VS_FALSE ){
            printf("parse [SRPWrapAndroidEngine.xml] failed\n");
            return -1;
        }
        free(xmlBufer);
    }
    // create a service for share library.
    BasicSRPInterface -> CreateService( "","wrapandroid", NULL, "123",5,0,0,0,0,0 );
    // obtain the service interface.
    SRPInterface = BasicSRPInterface ->GetSRPInterface("wrapandroid","root","123");
    // set not check password flag for share library.
    SRPInterface ->CheckPassword(VS_FALSE);
  2. Create root activity.

    The Share library needs a pre-created activity. The following is used to create it. And we write stub code for the getCurrent function of the activity. Then this function can be called from the share library.

    Here is the stub function of getCurrent:

    C++
    void *RootActivity;
    static void *ActivityClass_getCurrent(void *Object){
        return RootActivity;
    }

    The code for creating the root activity:

    C++
    //---get ActivityClass defined in wrapandroid service description file.
    void *ActivityClass = SRPInterface -> GetObjectEx(NULL,"ActivityClass");
    //---change to atomic object
    void *AtomicActivityClass = SRPInterface ->ObjectToAtomic(ActivityClass);
    //---create function stub for getCurrent
    void *AtomicActivityClassFunction_getCurrent = SRPInterface ->CreateAtomicFunctionSimple(
          AtomicActivityClass,"getCurrent","VS_OBJPTR getCurrent();",NULL,NULL,VS_FALSE,VS_FALSE);
    //---set the function address
    SRPInterface -> SetAtomicFunction(AtomicActivityClassFunction_getCurrent,(void *)ActivityClass_getCurrent);
     
    //alloc root activity
    RootActivity = SRPInterface ->MallocObjectL(&VSOBJID_ActivityClass,0,NULL);  
  3. Load the share library.

    Loading the  share library is simple. We call the CLE interface DoFile function to do this, more like the script interface. 

    C++
    if( SRPInterface ->DoFile("","../libcode.dll",NULL, NULL, VS_FALSE) == VS_FALSE ){
        printf("load library file\n");
        return -1;
    } 

When compiling, starlib_vcm.lib should be added to the project, as shown below:

Image 6

Add header files to the project:

Image 7

Set break points on code.cpp, and Run.

Image 8

Create stubs for android classes

We create stubs for Android classes in order to debug or for other goals. It will enable us to debug android C++ codes on the Windows platform. How do we create a stub? It is simple, like this:

Define function:

C++
static void *ActivityClass_getCurrent(void *Object){
    …
}

Create the stub function:

C++
void *AtomicActivityClassFunction_getCurrent = 
  SRPInterface ->CreateAtomicFunctionSimple(AtomicActivityClass,
  "getCurrent","VS_OBJPTR getCurrent();",NULL,NULL,VS_FALSE,VS_FALSE); 

and assign the address to the stub function:

C++
SRPInterface -> SetAtomicFunction(AtomicActivityClassFunction_getCurrent,(void *)ActivityClass_getCurrent);  

If you create stubs of all functions of android classes, your application can be migrated to Windows or other platforms. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)