JNI函数在进程空间中的起始地址被保存在ClassObject->directMethods中。 struct ClassObject : Object { /* static, private, and <init> methods */ int directMethodCount; Method* directMethods; /* virtual methods defined in this class; invoked through vtable */ int virtualMethodCount; Method* virtualMethods; } 此ClassObject通过gDvm.jniGlobalRefTable或gDvm.jniWeakGlobalRefLock获取。
//HelloWorld.java: package test; public class HelloWorld { public static void main(String[] args){ System.loadLibrary("HelloWorld"); printHello(); } public static native final void printHello(); }
dvmLoadNativeCode 打开函数dvmLoadNativeCode,可以找到以下代码 bool result = true; void* vonLoad; int version;
vonLoad = dlsym(handle, "JNI_OnLoad"); //获取JNI_OnLoad的地址 if (vonLoad == NULL) { //这是用javah风格的代码了,推迟解析 LOGD("No JNI_OnLoad found in %s %p, skipping init", pathName, classLoader); } else { /* * Call JNI_OnLoad. We have to override the current class * loader, which will always be "null" since the stuff at the * top of the stack is around Runtime.loadLibrary(). (See * the comments in the JNI FindClass function.) */ OnLoadFunc func = (OnLoadFunc)vonLoad; Object* prevOverride = self->classLoaderOverride;
self->classLoaderOverride = classLoader; oldStatus = dvmChangeStatus(self, THREAD_NATIVE); if (gDvm.verboseJni) { LOGI("[Calling JNI_OnLoad for \"%s\"]", pathName); } version = (*func)(gDvmJni.jniVm, NULL); //调用JNI_OnLoad,并获取返回的版本信息 dvmChangeStatus(self, oldStatus); self->classLoaderOverride = prevOverride;
if (version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4 && version != JNI_VERSION_1_6) //对版本进行判断,这是为什么要返回正确版本的原因 { LOGW("JNI_OnLoad returned bad version (%d) in %s %p", version, pathName, classLoader); /* * It's unwise to call dlclose() here, but we can mark it * as bad and ensure that future load attempts will fail. * * We don't know how far JNI_OnLoad got, so there could * be some partially-initialized stuff accessible through * newly-registered native method calls. We could try to * unregister them, but that doesn't seem worthwhile. */ result = false; } else { if (gDvm.verboseJni) { LOGI("[Returned from JNI_OnLoad for \"%s\"]", pathName); } }
/* * If this is a static method, it could be called before the class * has been initialized. */ if (dvmIsStaticMethod(method)) { if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) { assert(dvmCheckException(dvmThreadSelf())); return; } } else { assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz)); }
/* start with our internal-native methods */ DalvikNativeFunc infunc = dvmLookupInternalNativeMethod(method); if (infunc != NULL) { /* resolution always gets the same answer, so no race here */ IF_LOGVV() { char* desc = dexProtoCopyMethodDescriptor(&method->prototype); LOGVV("+++ resolved native %s.%s %s, invoking", clazz->descriptor, method->name, desc); free(desc); } if (dvmIsSynchronizedMethod(method)) { LOGE("ERROR: internal-native can't be declared 'synchronized'"); LOGE("Failing on %s.%s", method->clazz->descriptor, method->name); dvmAbort(); // harsh, but this is VM-internal problem } DalvikBridgeFunc dfunc = (DalvikBridgeFunc) infunc; dvmSetNativeFunc((Method*) method, dfunc, NULL); dfunc(args, pResult, method, self); return; }
/* now scan any DLLs we have loaded for JNI signatures */ void* func = lookupSharedLibMethod(method); //注意到,这里,是获取地址的地方 if (func != NULL) { /* found it, point it at the JNI bridge and then call it */ dvmUseJNIBridge((Method*) method, func); (*method->nativeFunc)(args, pResult, method, self); return; }
IF_LOGW() { char* desc = dexProtoCopyMethodDescriptor(&method->prototype); LOGW("No implementation found for native %s.%s %s", clazz->descriptor, method->name, desc); free(desc); }
if (meth->clazz->classLoader != pLib->classLoader) { LOGV("+++ not scanning '%s' for '%s' (wrong CL)", pLib->pathName, meth->name); return 0; } else LOGV("+++ scanning '%s' for '%s'", pLib->pathName, meth->name);
/* * First, we try it without the signature. */ preMangleCM = createJniNameString(meth->clazz->descriptor, meth->name, &len); if (preMangleCM == NULL) goto bail;
在Android的WebViewCore类里,静态加载了 static { // Load libwebcore and libchromium_net during static initialization. // This happens in the zygote process so they will be shared read-only // across all app processes. try { System.loadLibrary("webcore"); System.loadLibrary("chromium_net"); } catch (UnsatisfiedLinkError e) { Log.e(LOGTAG, "Unable to load native support libraries."); } }