torsdag 12 juni 2014

Build native application for android with stl-support

Once a while you want to use your c++ code on your android device. Since i don't like the process of looking into references and manuals all the time i prefer to use the built in tools in the android-sdk to make it all a bit leaner. So this is how to do it quick and simple in eclipse.

I do this on my ubuntu computer but many of the steps are generic for all operating systems (as long as you have eclipse, android-sdk and ndk installed.

I write specifically about the stl-stuff (the std::string, std::list, std::vector and so on) because they tend to be a bit tricky to get to work, I if you dont want to use them feel free to skip them. I have noted when it is possible to skip code.

Make sure you have your environment set up

The following steps requires you to have the android sdk (in it eclipse is included) and the ndk (used for native/c++ support). You might also have to install the cdt for c++ functionality in eclipse.

Create the project.

In eclipse, create a ordinary android project, and create some kind of standard activity if you want to quickly get some test output

Add native support to the project

The simplest way i found to do this is to right click on the project in the project explorer, goto android tools → Add native support 


Then enter a nice name for your library like "ndktest" as I will use here

You will then have a directory called jni, filled with one file called something with cpp, like ndktest.cpp and one Android.mk. I will not use the cpp-file but, just let it be there, it feels safe :)

Automatic builds

I use to make sure to enable automatic build, to be sure everything is up to date when i change things. To do this go to project properties. Select C/C++ build → Behaviour and check the "Build on resource save"

Connect it together

This is how my native class file could look like anyway. Any class can contain native functions. I use to keep it in a separate class to automatic generate the c function definitions.


 //NativeClass.java:  
 package com.experiment.ndktest;  
 public class NativeClass {  
      static native void test(); //This is our native function. Create as many as you like  
      static { //This is loading our native library at startup time  
           System.loadLibrary("gnustl_shared"); //must be first, skip this if you're not using stl-stuff  
           System.loadLibrary("ndktest"); //this is your library  
      }  
 }  

For some devices (like my older phone) you need to explicitly link to the stl, and you need to link to it first. Otherwise you will have the unsatisfied link exception. For some newer devices you will not have to do this at all, but if you are planning to have a large user base it can be a good idea (This confused me for a while when I got the unsatisfied link exception on some devices but not on others)


Generate header file (or write them your-self)

I will use javah-program to generate my header files. more specifically in this example i would run

javah -jni -classpath ../bin/classes/ com.experiment.ndktest.NativeClass

while I'm in the jni-path of the project. This will generate a file called com_experiment_ndktest_NativeClass.h in the directory i am currently in. (This may be linux specific) You can also write the function definitions yourself. Then you will have to make sure to know the form of how it should look.

For this example I will have the file (plus some comments I just wrote)

 //com_experiment_ndktest_NativeClass.h  
 /* DO NOT EDIT THIS FILE - it is machine generated */  
 #include  
 /* Header for class com_experiment_ndktest_NativeClass */  
 #ifndef _Included_com_experiment_ndktest_NativeClass //standard include block  
 #define _Included_com_experiment_ndktest_NativeClass  
 #ifdef __cplusplus //no avoid name mangling  
 extern "C" {  
 #endif  
 /*  
  * Class:   com_experiment_ndktest_NativeClass  
  * Method:  test  
  * Signature: ()V  
  */  
 JNIEXPORT void JNICALL Java_com_experiment_ndktest_NativeClass_test  
  (JNIEnv *, jclass);  //the function definition  
 #ifdef __cplusplus //end of name mangling-handling :)  
 }  
 #endif  
 #endif  


There is some things to take note of:
1. The extern "C" statement is used to not have trouble with name mangling. Java is using c-names and not c++-ones (which are not the same). If you miss this when you write your own, you will probably have unsatisfied link exeption

2. The look of the function... well that is how it looks....

Create a source file

You can write the function declarations in the auto-generated source-file. However i prefer to create a source file named the same as the header file to make use of eclipses source tools to automatically create function definitions, in this case com_experiment_ndktest_NativeClass.cpp.

When done a file like that could look like this

 #include "com_experiment_ndktest_NativeClass.h"  
 #include <string>  
 #include <android/log.h>  
 std::string apa = "bepa"; //stl-stuff  
 void Java_com_experiment_ndktest_NativeClass_test(JNIEnv*, jclass) {  
      apa = "cepa";  
      int x = 0;  
      auto y = x + 1; //c++11 stuff  
      __android_log_write(ANDROID_LOG_INFO, "ndktest", "hej");  
      __android_log_print(ANDROID_LOG_INFO, "ndktest", "x = %d", x);  
 }  



That would not do anything special but just use som stl-stuff (string) and then write to logcat (the debug output)

The Android.mk

The Android.mk-file describes how to build the native library that you are using. When using the "Add native support" function mentioned above we will have it automatically generated for us. However we will have to change it a bit for our needs. This is how it will look like

 #Android.mk  
 LOCAL_PATH := $(call my-dir)  
 include $(CLEAR_VARS)  
 LOCAL_MODULE  := ndktest #the name of the library  
 LOCAL_SRC_FILES := NDKTest.cpp com_experiment_ndktest_NativeClass.cpp #our new file  
 LOCAL_LDLIBS  += -llog #For logcat output. Can also be skipped if you're not using it  
 LOCAL_CPPFLAGS := -std=c++11 #to be able to use c++11 stuff. You can skip this if you're not  
 include $(BUILD_SHARED_LIBRARY)  

The Application.mk

To use the stl-library you must refer to it in the Application.mk. Note that it is not the same as the Android.mk. But it should be created in the jni directory. If you are not using stl-you will probably not need this file

#Application.mk:APP_STL:=gnustl_shared

now in my jni directory i have

Android.mk
Application.mk
com_experiment_ndktest_NativeClass.cpp
com_experiment_ndktest_NativeClass.h
NDKTest.cpp

Finally - Call the native functions from java

Now we can use the NativeClass in java to call our native functions how much we like. For example I could put a call in the onCreate of the main activity of the project to check if everything is working


//MainActivity.java
...
public class MainActivity extends ActionBarActivity {  
      @Override  
      protected void onCreate(Bundle savedInstanceState) {  
           super.onCreate(savedInstanceState);  
           setContentView(R.layout.activity_main);  
           if (savedInstanceState == null) {  
                getSupportFragmentManager().beginTransaction()  
                          .add(R.id.container, new PlaceholderFragment()).commit();  
           } 
           //End of generated code
           NativeClass.test();  
      }
...


Extra - Add headers for Eclipse syntax checking

For Eclipse not to report non existing problems because of "missing headers" for stl-elements you need to add the android headers to the project. To do this. Open project properties. Go to "paths and symbols". Add the following paths to the include directories.

 some/path/to/android-ndk-r9c/sources/cxx-stl/stlport/stlport

For the rest of the needed includes it will hopefully be creating when adding native library through Eclipse

And now probably it will work as it should... cheers


onsdag 11 juni 2014

Finding maximum correction for three samples

I always recalculate this when I need it, but now it is time to save it somewere.


You have three samples y1 y2 y3. and you want to know there the maximum is, if you do a quadratic regression from it. We here assume that the distance between the points in the x-axis is 1.

First, lets do the quadratic regression
We describe the graph as y = ax² + by + c

So we want the values of a, b and c

for y2 = y(x = 0) we have
y2 = a·0 + b·0 + c → 
c = y2

We then have that 
y1 = y(-1) = a·(-1)² + b·(-1) + c →
y1 = a - b + c →   (c = y2)
y1 = a - b + y2

and also in a similar fashion 
y3 = y(1) = a·1² + b·1 + c →
y3 = a + b + y2

Therefore we can take
y3 - y1 = 2b →
b = (y3 - y1) / 2

and
y1 + y3 = 2a + 2c = 2a + 2y2
2a = y1 + y3 - 2y2
a = (y1 + y3)/2 - y2


To get the maximum of the graph, we just have to find the zero of the derivative y'.
y = ax² + bx + c →
y' = 2ax + b

0 = y'
0 = 2ax + b
0 = 2((y1 + y3) / 2 + y2)·x + (y3 - y1)/2
2((y1 + y3) / 2 - y2)·x = -(y3 - y1)/2
(y1 + y3 - 2y2)·x = (y1 - y3)/2
x =  (y1 - y3) / (y1 + y3 - 2y2) / 2

...Done once for all.