Hi all,
I have been experimenting with using native code on the Android
platform for a few days now, and I am still facing a number of
problems.
Let's start with my successes so far. I have tested the sample
applications included in the Android NDK, and they work perfectly. I
have also already been able to write a small C library and invoke its
methods on Android through the NDK build tools and the .mk build
files.
My goal however is to access the functionality of an (existing) C++
library on the Android platform. The library contains a number of
classes and I would like to be able to use the library on Android as
on other platforms (i.e. win32 and unix). Instead of completely
converting the code to Java, I would like to use it as a native
library and invoke its functionality through JNI.
To the best of my knowledge, the most straightforward way to do so
would be to use SWIG (the Simplified Wrapper and Interface Generator,
http://www.swig.org/). Please correct me if I am wrong in this
statement as I am far from an expert in the field of Java programming.
Using SWIG allows programmers to work with the classes implemented in C
++ libraries in other languages, including Java. I have tested this on
win32 and it worked perfectly.
On Android however, I have up till now not been able to achieve the
same outcome. It appears to me the problem is that the implementation
of the native methods cannot be located in the native library. I could
however be wrong in this assessment.
Here is my source code. First there is the "native" C++ class, which
is implemented in files newtestclass.h and newtestclass.cpp as
follows:
newtestclass.h
-------------------
#ifndef NEWTESTCLASS_H
#define NEWTESTCLASS_H
class NewTestClass
{
public:
NewTestClass();
~NewTestClass();
void setX(const int x);
int getX() const;
private:
int m_x;
};
#endif // NEWTESTCLASS_H
newtestclass.cpp
----------------------
#include "newtestclass.h"
NewTestClass::NewTestClass() : m_x(0)
{
}
NewTestClass::~NewTestClass()
{
}
void NewTestClass::setX(const int x)
{
m_x = x;
}
int NewTestClass::getX() const
{
return m_x;
}
As you can see this is pretty straightforward C++ code, to make sure
the problems are not being caused by advanced C++ constructs.
As instructed in the SWIG tutorial, I have written a SWIG interface
file for this class. The contents is as follows:
newtestclass.i
-------------------
%module newtestclassmodule
%{
#include "newtestclass.h"
%}
%include "newtestclass.h"
Again very simple. On this interface class, I invoke the swig tool as
follows:
swig -c++ -o newtestclass_wrap.cpp -package com.example.newtest -java
newtestclass.i
which generates the file newtestclass_wrap.cpp. If desired/needed, I
can provide the contents of this file. Files newtestclass.cpp and
newtestclass_wrap.cpp are added to the LOCAL_SRC_FILES variable of my
Android.mk build file. Compiling the native library using the NDK make
tool succeeds and generates the library libnewtest.so (as the name of
my NDK module is "newtest").
Besides the newtestclass_wrap.cpp file, the swig tool also generates a
number of .java files which contain the Java implementation of the
NewTestClass class. As is expected, each memberfunction of this Java
class simply invokes its corresponding native method. This
implementation seems correct to me.
Finally, I attempt to use the Java NewTestClass inside the onCreate
method of an Android activity class as follows:
public class RunMe extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
System.loadLibrary("newtest");
NewTestClass ntc = new NewTestClass();
TextView tv = new TextView(this);
tv.setText("Returned value = " + ntc.getX());
setContentView(tv);
}
}
I compile and run the Android activity class using the Eclipse ADT
plug-in. When executing the Android application, LogCat output
suggests the libnewtest.so library is loaded successfully. However I
do get some warnings:
D/dalvikvm( 2027): Trying to load lib /data/data/com.example.newtest/
lib/libnewtest.so 0x43597078
D/dalvikvm( 2027): Added shared lib /data/data/com.example.newtest/lib/
libnewtest.so 0x43597078
D/dalvikvm( 2027): No JNI_OnLoad found in /data/data/
com.example.newtest/lib/libnewtest.so 0x43597078
D/dalvikvm( 2027): +++ not scanning '/system/lib/libwebcore.so' for
'new_NewTestClass' (wrong CL)
D/dalvikvm( 2027): +++ not scanning '/system/lib/libmedia_jni.so' for
'new_NewTestClass' (wrong CL)
D/dalvikvm( 2027): +++ not scanning '/system/lib/libwebcore.so' for
'NewTestClass_getX' (wrong CL)
D/dalvikvm( 2027): +++ not scanning '/system/lib/libmedia_jni.so' for
'NewTestClass_getX' (wrong CL)
As soon as the application tries to instantiate a NewTestClass object
in the onCreate method, the application terminates and I get the
following LogCat dump:
I/DEBUG ( 539): *** *** *** *** *** *** *** *** *** *** *** *** ***
*** *** ***
I/DEBUG ( 539): Build fingerprint: 'generic/sdk/generic/:1.5/
CUPCAKE/148875:eng/test-keys'
I/DEBUG ( 539): pid: 2027, tid: 2027 >>> com.example.newtest <<<
I/DEBUG ( 539): signal 7 (SIGBUS), fault addr 00000000
I/DEBUG ( 539): r0 42382b49 r1 4359d428 r2 00000000 r3 00000000
I/DEBUG ( 539): r4 be9a4540 r5 00000004 r6 804005f0 r7 41049d10
I/DEBUG ( 539): r8 be9a451c r9 41049d04 10 41049cf4 fp 00000000
I/DEBUG ( 539): ip 804005f0 sp be9a4508 lr 80400604 pc
804005e8 cpsr 80000010
I/DEBUG ( 539): #00 pc 000005e8 /data/data/
com.example.newtest/lib/libnewtest.so
I/DEBUG ( 539): #01 pc 00000600 /data/data/
com.example.newtest/lib/libnewtest.so
I/DEBUG ( 539): #02 pc 0000e3b4 /system/lib/libdvm.so
I/DEBUG ( 539): stack:
I/DEBUG ( 539): be9a44c8 000000da
I/DEBUG ( 539): be9a44cc 000001b8
I/DEBUG ( 539): be9a44d0 00003071
I/DEBUG ( 539): be9a44d4 afe0af93 /system/lib/libc.so
I/DEBUG ( 539): be9a44d8 804005f0 /data/data/
com.example.newtest/lib/libnewtest.so
I/DEBUG ( 539): be9a44dc 00000006
I/DEBUG ( 539): be9a44e0 afe3c980
I/DEBUG ( 539): be9a44e4 afe39dd0
I/DEBUG ( 539): be9a44e8 0000a000 [heap]
I/DEBUG ( 539): be9a44ec 00000088
I/DEBUG ( 539): be9a44f0 42382b49
I/DEBUG ( 539): be9a44f4 00000000
I/DEBUG ( 539): be9a44f8 0018cbe8 [heap]
I/DEBUG ( 539): be9a44fc 000e1940 [heap]
I/DEBUG ( 539): be9a4500 df002777
I/DEBUG ( 539): be9a4504 e3a070ad
I/DEBUG ( 539): #01 be9a4508 00000000
I/DEBUG ( 539): be9a450c 00000000
I/DEBUG ( 539): be9a4510 00000002
I/DEBUG ( 539): be9a4514 ad00e3b8 /system/lib/libdvm.so
I/ActivityManager( 570): Process com.example.newtest (pid 2027) has
died.
D/Zygote ( 541): Process 2027 terminated by signal (7)
I hope my explanation has been sufficiently elaborate. Has anyone any
experience on using SWIG on the Android platform and could point out
what is wrong with my approach?
Many thanks in advance,
Maarten Wijnants