1 / 18

Writing Native Code for Android Systems

Writing Native Code for Android Systems. Why ndk. There exist large c++ code libraries E.g., Audio and video compression, e.g., Ogg Vorbis , The LAME Project (mp3), .. OpenGL O penSL ES Low level audio Advanced CPU features

stefan
Download Presentation

Writing Native Code for Android Systems

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Writing Native Code for Android Systems

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

  3. App are mixed java and c/c++ • The java app is like a regular app. The java app is started by os. • It is not possible to have a stand alone c++ program (not sure, it might be) • The 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 • Write c++ code in MyProject/jni • Describe project sources in MyProject/jni/Android.mk • Like a make file, but much easier • Build project by running the command ../android-ndk-r5b/ndk-build from your MyProject 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 app in eclipse • Important: whenever you make a change in the c++ program, of coruse, 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.

  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 <string.h> • #include <jni.h> • extern "C" { • JNIEXPORT jstring JNICALL • Java_edu_udel_eleg454_helloJni_HelloJni_stringFromJNI( JNIEnv* env, • jobjectthiz ) • { • 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 := HelloJni.cpp • include $(BUILD_SHARED_LIBRARY) • Note that LOCAL_MODULE is the module name • Build library • Open terminal. • Cd dir to <workspace>/HelloJni/jni • Run build • <android-ndk-r5b>/ndk-build • Check that libHelloJni.so is created

  7. In java HelloJni • After public class HelloJni 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 • } • Note: HelloJni is our • In onCreate, after setContentView(R.layout.main); put • Log.e("debug","callingjni"); • 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_HelloJni_stringFromJNI • To • Java_edu_udel_eleg454_helloJni_TestJni_stringFromJNI • And runs ok

  10. Logging from c++ • In cpp file, add • #include <android/log.h> • In Android.mk 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, • jobjectthiz) • To • JNIEXPORT jstring JNICALL • Java_edu_udel_eleg454_helloJni_HelloJni_stringFromJNI( JNIEnv* env, • jobjectthiz, jstringjavaString ) • 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(intval); • And change • Log.e("debug",stringFromJNI()); • To • inti = 100; • Log.e("debug",stringFromJNI(i)); • In c++ • Change • JNIEXPORT jstring JNICALL • Java_edu_udel_eleg454_helloJni_HelloJni_stringFromJNI( JNIEnv* env, • jobjectthiz) • To • JNIEXPORT jstring JNICALL • Java_edu_udel_eleg454_helloJni_HelloJni_stringFromJNI( JNIEnv* env, • jobjectthiz, jintji ) • 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 <stdio.h> • __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, • jobjectthiz, jintArrayjiArray ) • Get size of array • jsizearrayLength = env->GetArrayLength(jiArray); • char str[80]; • __android_log_print(ANDROID_LOG_INFO, "DEBUG", str); • Get pointer to array • jint *data = env->GetIntArrayElements(jiArray, 0); • Do something with data • for (inti=0; i<arrayLength; i++) { • sprintf(str,"val %d is %d",i,data[i]); • __android_log_print(ANDROID_LOG_INFO, "DEBUG", str); • data[i] = i; • } • Release pointer • env->ReleaseIntArrayElements(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<ints.length; i++) { • Log.e("DEBUG","ret val["+i+"] = "+ints[i]); • } • run, and see that ints is updated

  17. Returning data • Java • define function to return int • public native intstringFromJNI(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, • jobjectthiz, jintArrayjiArray ) • return int • return 12; • Build, compile, run

  18. Return arrays • Same as returning a string but use NewIntArray

More Related