[关闭]
@chopsticks 2014-12-21T17:44:12.000000Z 字数 3965 阅读 2337

An Analysis of Native Library Loading Process

Android



JNI is the way java code adopted to use native code. Usually, native code exists as a shared library. Thus, Java code should load this kinds of shared library first before using those exported fucntions.

Java provide two API for native shared library loading:

Note: It seems that, these two apis are almost same, acturally they have different totally different arument.
- the argument libName means the native shared library name which was difined in makefile under JNI compile environment. E.g, if developer defined the lib name as "test", then the complied native shared library name should be libtest.so, and developer can use api like that: System.loadlibrary("test"), or "System.load("libtest.so")".
- In another words, libName "XXX" for System.loadLibrary refers to a lib named libXXX.so, and os will automatically search lib libXXX.so in some specifical directories; However, the argument libpathName for System.load refers to a lib which named same with the argument, even can include the fully path.

No matter which way the developer adopts, the last step in Java code is calling a native method named nativeLoad.

The native method nativeLoad is mapped to Dalvik_java_lang_Runtime_nativeLoad, a function in libdvm.so, existing as native code, defined in java_lang_Runtime.c.

dvmLoadNativeCode

Location:``

findSharedLibEntry

addSharedLibEntry

  1. create LibEntry
  2. add LibEntry

init--JNI_OnLoad

jniRegisterNativeMethods

return load result

Native shared library support

Location:dalvik/vm/native.c

SharedLib

  1. /*
  2. * We add one of these to the hash table for every library we load. The
  3. * hash is on the "pathName" field.
  4. */
  5. struct SharedLib {
  6. char* pathName; /* absolute path to library */
  7. void* handle; /* from dlopen */
  8. Object* classLoader; /* ClassLoader we are associated with */
  9. pthread_mutex_t onLoadLock; /* guards remaining items */
  10. pthread_cond_t onLoadCond; /* wait for JNI_OnLoad in other thread */
  11. u4 onLoadThreadId; /* recursive invocation guard */
  12. OnLoadState onLoadResult; /* result of earlier JNI_OnLoad */
  13. };

dvmHashTableLookup and its callbacks

dvmHashTableLookup is a key function for manipulating SharedLibs in a process. Usually, it works by coordinating with several other callback functions. Usage:

  1. /*
  2. * (This is a dvmHashTableLookup callback.)
  3. *
  4. * Find an entry that matches the string.
  5. */
  6. static int hashcmpNameStr(const void* ventry, const void* vname)
  7. {
  8. const SharedLib* pLib = (const SharedLib*) ventry;
  9. const char* name = (const char*) vname;
  10. return strcmp(pLib->pathName, name);
  11. }
  1. /*
  2. * (This is a dvmHashTableLookup callback.)
  3. *
  4. * Find an entry that matches the new entry.
  5. *
  6. * We don't compare the class loader here, because you're not allowed to
  7. * have the same shared library associated with more than one CL.
  8. */
  9. static int hashcmpSharedLib(const void* ventry, const void* vnewEntry)
  10. {
  11. const SharedLib* pLib = (const SharedLib*) ventry;
  12. const SharedLib* pNewLib = (const SharedLib*) vnewEntry;
  13. ALOGD("--- comparing %p '%s' %p '%s'",
  14. pLib, pLib->pathName, pNewLib, pNewLib->pathName);
  15. return strcmp(pLib->pathName, pNewLib->pathName);
  16. }
  17. /*
  18. * Check to see if an entry with the same pathname already exists.
  19. */
  20. static SharedLib* findSharedLibEntry(const char* pathName)
  21. {
  22. u4 hash = dvmComputeUtf8Hash(pathName);
  23. void* ent;
  24. ent = dvmHashTableLookup(gDvm.nativeLibs, hash, (void*)pathName,
  25. hashcmpNameStr, false);
  26. return (SharedLib*)ent;
  27. }
  28. /*
  29. * Add the new entry to the table.
  30. *
  31. * Returns the table entry, which will not be the same as "pLib" if the
  32. * entry already exists.
  33. */
  34. static SharedLib* addSharedLibEntry(SharedLib* pLib)
  35. {
  36. u4 hash = dvmComputeUtf8Hash(pLib->pathName);
  37. /*
  38. * Do the lookup with the "add" flag set. If we add it, we will get
  39. * our own pointer back. If somebody beat us to the punch, we'll get
  40. * their pointer back instead.
  41. */
  42. return (SharedLib*)dvmHashTableLookup(gDvm.nativeLibs, hash, pLib,
  43. hashcmpSharedLib, true);
  44. }
  45. /*
  46. * Free up an entry. (This is a dvmHashTableFree callback.)
  47. */
  48. static void freeSharedLibEntry(void* ptr)
  49. {
  50. SharedLib* pLib = (SharedLib*) ptr;
  51. /*
  52. * Calling dlclose() here is somewhat dangerous, because it's possible
  53. * that a thread outside the VM is still accessing the code we loaded.
  54. */
  55. if (false)
  56. dlclose(pLib->handle);
  57. free(pLib->pathName);
  58. free(pLib);
  59. }

更多关于dvmHashTableLookp的使用可参考这里

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注