Android JNI c++ pointers to Java.

When working with Native on Android, it is many times needed to have a Native representation of a Java Object. This native Object should mainly behave like a proxy to the Java object which is mainly straightforward. Since the native support android is extremely limited, the use cases for this are almost infinite. From proper concurrent HttpRequest handling, to send a push notification, etc.
The tricky part is when the Java object should notify back the Native object about an event with origin on the Java side. For such scenario, it is a must to keep the Native reference object in Java, so that Java can notify back the expected Native object that initiated the call. To do so, the pointer to this must be sent from native to Java. A pointer, is just a memory address, and a casting to long will do. With the subtle detail that this will mangle the pointer and your code will break.

// somewhere in your c/c++ file:
// build a Java object to keep as native-to-java proxy.
// We instantiate from a Java constructor with a long parameter.
// The Java long is the c++ pointer object.
JNIEnv*   env=        ...;
jclass    clazz=      env->FindClass( className );
jmethodID constructor=env->GetMethodID( clazz, "", constructorSignature );

/////////// WRONG . SEG_MAPPER courtesy of mangled pointer 
long      thisPtr=    (long)this;
jobject   obj=        env->NewObject( clazz, constructor, thisPtr );

This code will fail. Converting ‘this’ to long won’t work. Instead, use the following:

////////// RIGHT. This will work. The call to 
// jlong(this) will handle endianness and type conversion.
jlong   thisPtr= jlong(this);  
jobject obj=     env->NewObject( clazz, constructor, thisPtr );

Now, there’s the part where we want to notify back from Java to native. Java must have a ‘native’ qualified method, like for example:

// somewhere in your .java file

public class Clazz {
    * ...
    * @param nativePtr the native object pointer got at construction time.
   private static native void onProgress( long nativePtr, float value );

And the implementation of this native function could be:

// somewhere in your c/c++ file

void JNICALL Java_fully_qualified_package_CLASSNAME_METHODNAME(
    JNIEnv* env, jobject thiz, jlong nativePtr, jfloat progress) {

    // nativePtr is safe to reinterpret as the original 
    // 'this' promoted to 'jlong' object's memory address.


As a warning note, watch out when calling jlong(this). If the object is temporary, whenever Java calls back to Native you’ll have a guaranteed application crash. It is important to have Object lifecycle so that you can free the native object pointers when it will safe to do so.

Android NDK with multiple pre-built libraries

I am currently playing a bit with the NDK and every step seems to be draining an hour to figure out stuff.
This time, I need to compile a shared library, which depends on pre-built multiple static and shared libraries. The NDK documentation example seems naive enough to be straightforward to have it working, but it took me some time to figure out how to do it.

Here’s a valid file which references two other pre-built static libraries. It took me some time to realize that:

  • The LOCAL_STATIC_LIBRARIES reference the name of the LOCAL_MODULE for the pre-built libraries, not the name of the library or anything alike. The name LOCAL_STATIC_LIBRARIES can be a bit misleading, and thus, lpw must be specified instead of the library name.
  • The LOCAL_SRC_FILES for each module can only reference one library, and the path will be relative to the point you invoke the ndk-build command, but absolute paths will work like a charm.
  • The $(TARGET_ARCH_ABI) will reference the valid library for the currently compiling architecture, so it is a must have.

LOCAL_PATH := $(call my-dir)

# prepare lib1
include $(CLEAR_VARS)
LOCAL_MODULE    := lpw
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libPluginWhatever.a

# prepare lib2
include $(CLEAR_VARS)
LOCAL_MODULE    := lib2

... your other stuff

LOCAL_STATIC_LIBRARIES := android_native_app_glue lib2 lpw


$(call import-module,android/native_app_glue)

Normally, when the ndk-build command ends, your libraries will be installed in the libs directory, a folder created in the same directory you invoked the nkd-build in. If you invoke ndk-build manually, Gradle will miserably fail to include the generated library files since it expects the installed libraries to be in the folder jniLibs instead of libs. If have a convenient symbolic link jniLibs->libs for this inconvenience.

Android development pain

We’ve been for a while developing the game iBasket at Ideateca. It’s been a real hit on iPhone/iPad. But the pain was about to come in the porting-to-Android stage.
After porting the code from C/Objective-C to Java, and leaving it on stable state, the game performed really poorly. The framerate regularly dropped from 50 to 5-10 frames per second. After some profiling session, we found that Cocos2D’s Label object was a real pain. So we decided to look for alternatives and started playing around with some custom code. But surprisingly, it did not solve the problem. We finally found, that the label object was not the cpu sinker but the String.format function instead. What an oddity isn’t it ?!?!?!?. After removing String.format calls from the game loop, we achieved a nice constant framerate which lead to a totally playable game in mid to low end devices like HTC Magic and HTC Hero. That was a great day, since we could release a game not devoted to be played in Nexus One or HTC Evo, but in all android devices. And aditionally, the Label object proudly got back to our widget toolchest. Lessons learned: String.format is evil on Android. As of Android 2.2 froyo, the String.format hell has been bug reported and solved. So, lessons learned 2: always test developments in the latest available platform stable versions as well.

After releasing the game to Android Market, we reveived some user complaints in the form of bad game rates regarding texture malfunctioning on some devices like Samsung Galaxy S and Droid-X. The fact is that some textures get duplicated, others totally rubished and yet others not visible at all. As they always were the same textures, that gave us some hints to find solutions for this new gotcha. After playing around with the profiler again to make sure we were not getting out of memory, we decided to take directly a look at Cocos2D Texture2D implementation. Everything was right, of course, but finally, we discovered that those devices which didn’t show textures properly had a buggy glGenTexture implementation. This function is supposed to return into the parameter array non zero unsigned integer values which will bind textures to opengl. But the fact, is that Java lacks of unsigned types, and, thought it is not stated that the function will return values starting from one incrementally, the values returned were totally random. So, by changing the optional use of glGenTexture function by our own one, we’ve magically solved this annoying problem. We’ve achieved the milestone of supplying with a functional iBasket version playable in *all* Android devices. Again, a good day for us. At least, until the next time.
BTW, Sansung Galaxy S is Android 2.1-update 1. I can’t exactly tell the version of the DroidX, since I’ve not one handy .