Presentation is loading. Please wait.

Presentation is loading. Please wait.

Writing Native Code for Android Systems. Why ndk (native developers kit) There exist large c/c++ code libraries – E.g., Audio and video compression, e.g.,

Similar presentations


Presentation on theme: "Writing Native Code for Android Systems. Why ndk (native developers kit) There exist large c/c++ code libraries – E.g., Audio and video compression, e.g.,"— Presentation transcript:

1 Writing Native Code for Android Systems

2 Why ndk (native developers kit) There exist large c/c++ code libraries – E.g., Audio and video compression, e.g., Ogg Vorbis, The LAME Project (mp3),.. OpenGL OpenSL ES – Low level audio Advanced CPU features – E.g., some ARM cpus support the NEON instruction set for signal and video processing

3 Apps that use the NDK are typically mixed java and c/c++ – Pure c/c++ apps are possible The java app is like a regular app. The java app is started by os. The c/c++ program is placed in a shared library – Shared libraries have names like libMyProgram.so The application package (.apk) will include the java app and the shared library jni (Java Native Interface) must be used to move data between java and c++

4 Outline of Steps Goto http://developer.android.com/sdk/ndk/index.html and get NDKhttp://developer.android.com/sdk/ndk/index.html – Note: the current version of the ndk works well in windows. Previous versions needed cygwin Make regular java project, e.g., MyProject Make subdirectory, MyProject/jni Write c++ code in MyProject/jni Describe project sources in MyProject/jni/Android.mk – Like a make file, but much easier Linux and MAC – Build project by running the command../android-ndk-r7/ndk-build from your MyProject/jni directory Windows – Build project by running the command c:\android\android-ndk-r7b\ndk-build from your MyProject\jni directory ndk-build is like make – ndk-build Builds – ndk-build clean Cleans everything – Generates shared lib (libXX.so file) and places it in correct directory so the java program can get it Make.apk file by building the app in eclipse – Important: whenever you make a change in the c++ program, of course, you need to run ndk-build. But, you also must rerun the java compile. To do this, make a trivial change in your java code and resave. Or run clean project from eclipse

5 HelloJni Make new app called – Package: edu.udel.eleg454.HelloJni – Activity Name: HelloJni – Project: HelloJni Make new subdirectory in project call jni – i.e., HelloJni/jni In jni directory make new file called – MyHelloJni.cpp In this file, put – #include – extern "C" { – JNIEXPORT jstring JNICALL – Java_edu_udel_eleg454_HelloJni_HelloJniActivity_stringFromJNI( JNIEnv* env, – jobject thiz ) – { – return env->NewStringUTF("Hello from JNI!"); – } Save file Important: function names must be exactly correct – Java_packageNameWithDotReplacedByUnderScore_JavaClassNameThatWillCallThisFunction_functionName

6 Android.mk In HelloJni/jni make new file called Android.mk Put the following in Android.mk – LOCAL_PATH := $(call my-dir) – include $(CLEAR_VARS) – LOCAL_MODULE := HelloJni – LOCAL_SRC_FILES := MyHelloJni.cpp – include $(BUILD_SHARED_LIBRARY) Note that LOCAL_MODULE defines the module name Build library – Open terminal. – Cd dir to /HelloJni/jni – Run build /ndk-build – Check that libHelloJni.so is created

7 In java HelloJni After public class HelloJniActivity extends Activity { – public native String stringFromJNI(); // the c++ function name – static { – System.loadLibrary("HelloJni"); // shared lib is called libHelloJni.so. // this name is from the LOCAL_MODULE part of the Android.mk file – } In onCreate, after setContentView(R.layout.main); put – Log.e("debug","calling jni"); – Log.e("debug",stringFromJNI()); // last part of name of c++ function – Log.e("Debug","done"); Run and check log Note: public native … allows any function to be defined. But when this function is called, the shared library must have already been loaded (via System.loadLibrary)

8 play Change c++ function to be make string – Hello from JNI 2 Instead of – Hello from JNI! Rebuild and run from eclipse – Log does not show anything. Not even an error In eclipse make trivial change (delete and add ;) Run, and everything is ok

9 C++ Function name Change c++ function name. recompile and see error in LogCat – “no implementation found for native …” Make a new class called TestJni Move jni stuff into TestJni Run and see error Change function name from – Java_edu_udel_eleg454_HelloJNI_HelloJNIActivity_string FromJNI To – Java_edu_udel_eleg454_helloJNI_TestJni_stringFromJNI And runs ok

10 Logging from c++ In cpp file, add – #include In Android.mk, after include $(CLEAR_VARS) add, – LOCAL_LDLIBS := -llog In function add – __android_log_print(ANDROID_LOG_INFO, "DEBUG", "Here we are");

11 Passing strings from java to c++ with JNI In java code, make function arg include a string – Change public native String stringFromJNI(); – To public native String stringFromJNI(String name); – And change Log.e("debug",stringFromJNI()); – To Log.e("debug",stringFromJNI("string para")); In c++ code – Change JNIEXPORT jstring JNICALL Java_edu_udel_eleg454_helloJni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz) – To JNIEXPORT jstring JNICALL Java_edu_udel_eleg454_helloJni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz, jstring javaString ) – And add const char *str = env->GetStringUTFChars(javaString, 0); // convert java string to c++ str __android_log_print(ANDROID_LOG_INFO, "DEBUG", str); // do something env->ReleaseStringUTFChars(javaString, str); // release str Build, compile, run Note: after release, str is no longer valid

12 Passing int, floats, etc to c++ In java – Change public native String stringFromJNI(); – To public native String stringFromJNI(int val); – And change Log.e("debug",stringFromJNI()); – To int i = 100; Log.e("debug",stringFromJNI(i)); In c++ – Change JNIEXPORT jstring JNICALL Java_edu_udel_eleg454_helloJni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz) – To JNIEXPORT jstring JNICALL Java_edu_udel_eleg454_helloJni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz, jint ji ) – And comment out const char *str = env->GetStringUTFChars(javaString, 0); env->ReleaseStringUTFChars(javaString, str); – Add char str[80]; sprintf(str,"data is %d",ji); // be sure to add #include __android_log_print(ANDROID_LOG_INFO, "DEBUG", str); Build, compile, run

13 Jni Data types C++ type = jave type unsigned char = jboolean signed char = jbyte unsigned short = jchar Short = jshort Long = jlong Long long = jlong __int64 = jlong float = jfloat double = jdouble

14 Passing arrays of ints to c++ In java – Define function to take int array as argument Replace – public native String stringFromJNI(); With – public native String stringFromJNI(int[] val); – In onCreate Make array – int[] ints = new int[]{1,1,2,3,5,8,13}; Call function with ints as augment – Log.e("debug",stringFromJNI(ints));

15 Passing arrays of ints to c++ In c++ – Define function to take array as argument JNIEXPORT jstring JNICALL Java_edu_udel_eleg454_helloJni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz, jintArray jiArray ) – Get size of array jsize arrayLength = env->GetArrayLength(jiArray); – Get pointer to array jint *data = env->GetIntArrayElements(jiArray, 0); – Do something with data char str[80]; for (int i=0; iReleaseIntArrayElements(jiArray, data, 0); Build, compile, run

16 More passing arrays to c++ env->ReleaseIntArrayElements(jiArray, data, 0); – Last argument is 0 => data is copied back to java and java can delete data array – Last argument is JNI_COMMIT => data is copied back, but java should not delete the array – Last argument is JNI_ABORT => data is not copied back and java can delete Check if the data was changed in c++ – In java, after Log.e("debug",stringFromJNI(ints)); add for (int i=0; i { "@context": "http://schema.org", "@type": "ImageObject", "contentUrl": "http://images.slideplayer.com/13/4039434/slides/slide_16.jpg", "name": "More passing arrays to c++ env->ReleaseIntArrayElements(jiArray, data, 0); – Last argument is 0 => data is copied back to java and java can delete data array – Last argument is JNI_COMMIT => data is copied back, but java should not delete the array – Last argument is JNI_ABORT => data is not copied back and java can delete Check if the data was changed in c++ – In java, after Log.e( debug ,stringFromJNI(ints)); add for (int i=0; iReleaseIntArrayElements(jiArray, data, 0); – Last argument is 0 => data is copied back to java and java can delete data array – Last argument is JNI_COMMIT => data is copied back, but java should not delete the array – Last argument is JNI_ABORT => data is not copied back and java can delete Check if the data was changed in c++ – In java, after Log.e( debug ,stringFromJNI(ints)); add for (int i=0; i

17 Returning data Java – define function to return int public native int stringFromJNI(int[] val); – Call function and print return value Log.e("debug","results = "+stringFromJNI(ints)); C++ – Change function prototype to return jint JNIEXPORT jint JNICALL Java_edu_udel_eleg454_helloJni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz, jintArray jiArray ) – return int return 12; Build, compile, run

18 Return arrays Same as returning a string but use NewIntArray

19 SWIG SWIG automatically builds an interface between java and c/c++ – SWIG constructs an interface that is composed of java and c/c++ code. The result is that your java code and your c/c++ code is simpler you don’t need to mess with JNI You don’t need to change the basic c++ code to support java. Just use swig to make an interface – Swig also for interfaces between c/c++ and many other scripting languages – More info on swig and java: http://www.swig.org/Doc1.3/Java.htmlhttp://www.swig.org/Doc1.3/Java.html Section 5 of http://www.swig.org/Doc2.0/SWIGDocumentation.pdfhttp://www.swig.org/Doc2.0/SWIGDocumentation.pdf Swig and android: http://swig.svn.sourceforge.net/viewvc/swig/trunk/Doc/Manual/Android.html – Swig is a bit time consuming to get set up, but if you are working with a complicated interface between java and c/c++, it is worth it. I have found jni is difficult to work with. We already saw some problems with how difficult the naming is. And there are other complications Windows set up – http://www.swig.org/download.html http://www.swig.org/download.html – Download full version of SWIG (not the windows executable version) Decompress into D:\SWIG – Download windows executable version Decompress and get swig.exe and paste swig.exe into D:\SWIG Linux – apt-get install swig

20 Swig 1 New app, TestSwig Make jni directory – You can make this in eclipse package explorer right click on TestSwig New->Folder: Folder name: jni Check that jni appears between bin and res – Otherwise, make it in file explorer. Then, in eclipse package explorer, right click TestSwig and select Refresh – Either way, Jni must appear in list of directories, otherwise this process will fail Make testSwig.c – Could be TestSwig.cpp, but there is a minor difference later – #include – int testThis(double val) { – char str[128]; – sprintf(str,"Here we are: %f",val); – __android_log_print(ANDROID_LOG_INFO, "TestSwig", str); – return 12; – } Make TestSwig.h – A.h file is needed to the interface. Any function that is aprt of the interfaces (i.e., can be called from java) must be in a.h file – int testThis(double val); Make interface file called TestSwig.i and save in jni directory. This defines the interface between java and c/c++ – %module testSwig – %{ – #include "TestSwig.h" – %} – extern int testThis(double val); Get ready to run swig – Make directory – TestSwig\src\edu\udel\eleg454\Swig Run swig – Open command prompt – Change to TestSwig\jni directory – execute D:\swig\swig.exe –java –package edu.udel.eleg454.Swig – outdir../src/edu/udel/eleg454/Swig testSwig.i – -package will make this interface a package – -outdir defines the directory. This directory must be made before running swig – Check Check that java files are made in

21 Import to eclipse Import – The first import is a bit odd. After the first time, everything runs smoothly – Open file explorer and browse to TestSwig\src\edu\udel\eleg454 – Cut Swig directory i.e., the directory with all the java files we just made – Paste to d:\temp\testSwig\edu\udel\eleg454\Swig you need to make this directory Make sure that you cut, i.e., that Swig directory is deleted from TestSwig\src\edu\udel\eleg454 – Go Back to eclipse – In project explorer, right click on TestSwig/src (the project) – Select import – Under General is File System, select File System. Next – From Directory: Browse to d:\temp and select testSwig. OK – Select the check box next to edu – Set Into folder to TestSwig/src – Click finish – Check that under /src is a new package edu.udel.eleg454.Swig Now, the next time you run swig.exe …. The files will be updated. – The reason we had to move them to \temp is that eclipse does not let you import to the location where the files are. – I don’t understand why sometime when you import the eclipse package explorer shows you edu/udel/eleg454/Swig and other times, edu.udel.eleg454.Swig. We must have edu.udel.eleg454.Swig Advanced/optional: – You can make swig.exe run automatically – In package explores, right click on project, TestSwig -> properties->Builders-> new-> program click ok – Name: swig – Location: d:\swig\swig.exe – Work directory, ${project_loc}/jni – Augments: –java –package edu.udel.eleg454.Swig –outdir edu/udel/eleg454/Swig testSwig.i

22 NDK Android.mk – LOCAL_PATH := $(call my-dir) – include $(CLEAR_VARS) – LOCAL_LDLIBS := -llog – LOCAL_MODULE := TestSwig – LOCAL_SRC_FILES := testSwig.c testSwig_wrap.c – include $(BUILD_SHARED_LIBRARY) testSwig.c is our c code testSwig_wrap.c is generated by swig – Don’t attempt to read testSwig_wrap.c. It is not meant to be read or understood

23 java Now we can use this nice interface in our java code In TestSwigActivity, after public class TestSwigActivity extends Activity {, add – static { – System.loadLibrary("TestSwig"); – } – It is too bad that you need to add this manually. I think swig should add it to the java files automatically. But it does not, so you need to add it here In onCreate, after setContentView(), add – Log.e("testSwig","test: "+testSwig.testThis(2)); testSwig is the class, and testThis is the c/c++ function

24 Structures In TestSwig.h add – struct TestStruct { int a; double b; – }; In TestSwig.i, after extern int testThis(double val); add – struct TestStruct { int a; double b; – }; Note that the struct must be defined in both places. – It is defined in.i so swig makes an interface – It is defined in.h so that TestSwig_wrap.c has a.h where the struct is defined Run swig as before Swig will generate class TestStruct and TestStruct.java with operators – getA(), getB(), setA(int a), setB(double b) – To use TestStruct in java, TestStruct testStruct = new TestStruct(); The extra java files can be added to the project as before – Cut them from the directory to some other directory. Then drag the file from file explorer to eclipse package explorer

25 classes Make TestSwigClass.h – class TestSwigClass { – public: int a; double b; void set_b(double _b) { b = _b; }; int get_a() {return a;} TestSwigClass() {}; void process() { – // nothing yet } – }; At the top of TestSwig.i, add TestSwigClass.h to module section, so it looks like – %module testSwig – %{ – #include "testSwig.h" – #include "TestSwigClass.h" – %} At the end of TestSwig.i, add the contents of TestSwigClass.h Running swig for c++ code is slightly different than running for c code – D:\swig\swig.exe –java –c++ –package edu.udel.eleg454.Swig –outdir../src/edu/udel/eleg454/Swig –o testSwig_wrap.cpp testSwig.i – This will generate a testSwig_wrap.cxx file, not testSwig_wrap.c – Android ndk does not accept.cxx files. So you need to add –o testSwig_wrap.cpp to make the correct output file – Note: mixing.c and.cpp is a bad idea. So rename TestSwig.c to TestSwig.cpp and update Android.mk This will generate even more java files that need to be added to your project

26 Extending structures/classes: motivation A key goal of SWIG is that the c/c++ code does not need to be changed to support the java interface SWIG generates a interface code in c/c++ and several in java However, sometimes simply “porting” the c/c++ interface to java is insuffucient – E.g., some c/c++ functions return data in the arguments, which might not be compatible with java – E.g., java makes functions that c/c++ does not, such as toString – E.g., the c/c++ interface does not fit well into java, so a new interface should be made

27 Extending classes/structures A new class can be defined in the.i file and these or any class can be extended The result of an extension is that the java interface appears as it would if the c/c++ interface had these changes. However, the c/c++ code is not changed

28 Extending classes/structures Consider the TestSwigClass made before. Goal: extend to include add fucntion In swig.i, add – %extend TestSwigClass { void add(class TestSwigClass *other) { – self->a = self->a + other->a; – self->b = self->b + other->b; } – }; Note that self is like this. When this function is generate, it is not a member function of TestSwigClass (that would require changing TestSwigClass). Instead, the following is generated – SWIGINTERN void TestSwigClass_add(TestSwigClass *self, TestSwigClass *other){ self->a = self->a + other->a; self->b = self->b + other->b; – } Note that self is automatically added as a parameter, this you can use the same way you use this. The java interface is – public void add(TestSwigClass other) { …} One drawback of extending classes is that your extension code might have bugs and then debugging requires examining testSwig_wrap.cxx

29 Making a new interface class/structure Instead of only extending an existing class/structure, you might want to make an entire new class – Again, this class should only be implemented in the interface code generated by swig E.g., make class MyInterfaceClass – In testSwig.i, – At the top, in the %module testSwig section, add class MyInterfaceClass { public: – int a; – double b; }; – Also, after the %module testSwig section, add (yes, you must add the same stuff in two places) class MyInterfaceClass { public: – int a; – double b; }; – After class MyInterfaceClass, add %extend MyInterfaceClass { – MyInterfaceClass() { » MyInterfaceClass *u = new MyInterfaceClass(); » u->a = 0; » u->b= 0; » return u; – } }; Clearly, if you need to make more than a small number of interface classes, you should just make them in c/c++ yourself and not rely on swig.

30 stl::vector, stl::string, … Much of stl can be accommodated See section 8.4 in the swig documentation However, my install was missing stl_list.i, so I could not get list to work. Vector and string did work


Download ppt "Writing Native Code for Android Systems. Why ndk (native developers kit) There exist large c/c++ code libraries – E.g., Audio and video compression, e.g.,"

Similar presentations


Ads by Google