Programming with the dynamic linker library in Android NDK

Dynamic loading is a technique to load a library into memory at runtime, and execute functions or access variables defined in the library. It allows the app to start without these libraries.

We have seen dynamic loading in almost every recipe of this book. When we call the System.loadLibrary or System.load function to load the native libraries, we are using dynamic loading.

Android NDK has provided the dynamic linker library to support dynamic loading in NDK, since Android 1.5. This recipe discusses the dynamic linker library functions.

Getting ready...

Readers are expected to know how to create an Android NDK project. You can refer to the Writing a Hello NDK program recipe of Chapter 1, Hello NDK for detailed instructions.

How to do it...

The following steps describe how to create an Android application using the dynamic linking library to load the math library and compute the square root of 2.

  1. Create an Android application named DynamicLinker. Set the package name as cookbook.chapter7.dynamiclinker. Refer to the Loading native libraries and registering native methods recipe of Chapter 2, Java Native Interface for more detailed instructions.
  2. Right-click on the DynamicLinker project, select Android Tools | Add Native Support.
  3. Add a Java file named MainActivity.java under the cookbook.chapter7.dynamiclinker package. This Java file simply loads the native DynamicLinker library and calls the native naDLDemo method.
  4. Add the mylog.h and DynamicLinker.cpp files under the jni folder. A part of the code in the OpenSLESDemo.cpp file is shown in the following code.

    naDLDemo loads the libm.so library, obtains the address of the sqrt function and calls the function with input argument 2.0:

    void naDLDemo(JNIEnv* pEnv, jclass clazz) {
      void *handle;
      double (*sqrt)(double);
      const char *error;
      handle = dlopen("libm.so", RTLD_LAZY);
      if (!handle) {
        LOGI(1, "%s
    ", dlerror());
        return;
      }
      dlerror();    /* Clear any existing error */
      *(void **) (&sqrt) = dlsym(handle, "sqrt");
      if ((error = dlerror()) != NULL)  {
        LOGI(1, "%s
    ", error);
        return;
      }
      LOGI(1, "%f
    ", (*sqrt)(2.0));
    }
  5. Add an Android.mk file under the jni folder with the following content:
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE    := DynamicLinker
    LOCAL_SRC_FILES := DynamicLinker.cpp
    LOCAL_LDLIBS := -llog -ldl
    include $(BUILD_SHARED_LIBRARY)
  6. Build and run the Android project, and use the following command to monitor the logcat output:
    $ adb logcat -v time DynamicLinker:I *:S

    A screenshot of the logcat output is shown as follows:

    How to do it...

How it works...

In order to build with dynamic loading library libdl.so, we must add the following line to the Android.mk file:

LOCAL_LDLIBS := -ldl

The following functions are defined in the dlfcn.h header file by the Android dynamic linking library:

void*        dlopen(const char*  filename, int flag);
int          dlclose(void*  handle);
const char*  dlerror(void);
void*        dlsym(void*  handle, const char*  symbol);
int          dladdr(const void* addr, Dl_info *info);

The dlopen function loads the library dynamically. The first argument indicates the library name, while the second argument refers to the loading mode, which describes how dlopen resolves the undefined symbols. When an object file (for example, shared library, executable file, and so on) is loaded, it may contain references to symbols whose addresses are not known until another object file is loaded (such symbols are referred to as undefined symbols). These references need to be resolved before they can be used to access the symbols. The following two modes determine when the resolving happens:

  • RTLD_NOW: When the object file is loaded, the undefined symbols are resolved. This means the resolving occurs before the dlopen function returns. This may be a waste if resolving is performed but the references are never accessed.
  • RTLD_LAZY: The resolving can be performed after the dlopen function returns, that is, the undefined symbols are resolved when the code is executed.

The following two modes determine the visibility of the symbols in the loaded object. They can be ORed with the previously mentioned two modes:

  • RTLD_LOCAL: The symbols will not be available for another object
  • RTLD_GLOBAL: The symbols will be available for subsequently loaded objects

The dlopen function returns a handle upon success. The handle should be used for the subsequent calls to dlsym and dlclose.

The dlclose function simply decrements the reference count of the loaded library handle. If the reference count is reduced to zero, the library will be unloaded.

The dlerror function returns a string to describe the most recent error occurred while calling dlopen, dlsym, or dlclose since the last call to dlerror. It returns NULL if no such error occurred.

The dlsym function returns the memory address of a given symbol of the loaded dynamic library referred by the input argument handle. The returned address can be used to access the symbol.

The dladdr function takes an address and tries to return more information about the address and library through the info argument of the DI_info type. The DI_info data structure is defined as shown in the following code snippet:

typedef struct {
   const char *dli_fname;  
   void       *dli_fbase;  
   const char *dli_sname;  
   void       *dli_saddr;  
} Dl_info;

dli_fname indicates the path of the shared object referred by the input argument addr. The dli_fbase is the address where the shared object is loaded. dli_sname indicates the name of the nearest symbol with address lower than addr, and dli_saddr is the address of symbol named by dli_sname.

In our example, we demonstrated the usage of the first four functions. We load the math library by dlopen, obtain the address of the sqrt function by dlsym, check the error by dlerror, and close the library by dlclose.

For more details on the dynamic loading library, refer to http://tldp.org/HOWTO/Program-Library-HOWTO/dl-libraries.html and http://linux.die.net/man/3/dlopen.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset