加载中 ...
首页 > 常见问题 正文

干货|JNI实现机制

2019-03-24 10:31:08 来源:沈阳软件公司 作者:沈阳软件开发

{

const char* classDescriptor = method->clazz->descriptor;

const DalvikNativeClass* pClass;

u4 hash;

hash = dvmComputeUtf8Hash(classDescriptor);

pClass = gDvmNativeMethodSet;//遍历全局当地要领荟萃,寻找内部注册的当地要领

while (true) {

if (pClass->classDescriptor == NULL)

break;

if (pClass->classDescriptorHash == hash &&

strcmp(pClass->classDescriptor, classDescriptor) == 0)

{

const DalvikNativeMethod* pMeth = pClass->methodInfo;

while (true) {

if (pMeth->name == NULL)

break;

if (dvmCompareNameDescriptorAndMethod(pMeth->name,

pMeth->signature, method) == 0)

{

/* match */

//ALOGV("+++ match on %s.%s %s at %p",

// className, methodName, methodSignature, pMeth->fnPtr);

return pMeth->fnPtr;

}

pMeth++;

}

}

pClass++;

}

return NULL;

}

 

static DalvikNativeClass gDvmNativeMethodSet[] = {

{ "Ljava/lang/Object;", dvm_java_lang_Object, 0 },

{ "Ljava/lang/Class;", dvm_java_lang_Class, 0 },

//……

{ "Ljava/lang/Runtime;", dvm_java_lang_Runtime, 0 },

{ "Ljava/lang/String;", dvm_java_lang_String, 0 },

{ "Ljava/lang/System;", dvm_java_lang_System, 0 },

{ "Ljava/lang/Throwable;", dvm_java_lang_Throwable, 0 },

{ "Ljava/lang/VMClassLoader;", dvm_java_lang_VMClassLoader, 0 },

{ "Ljava/lang/VMThread;", dvm_java_lang_VMThread, 0 },

//……

{ "Ldalvik/system/DexFile;", dvm_dalvik_system_DexFile, 0 },

{ "Ldalvik/system/VMRuntime;", dvm_dalvik_system_VMRuntime, 0 },

//……

};

/dalvik/vm/native/java_lang_runtime.cpp

java_lang_runtime.Dalvik_java_lang_Runtime_nativeLoad() -> Native.dvmLoadNativeCode()

const DalvikNativeMethod dvm_java_lang_Runtime[] = {

//……

{ "nativeExit", "(I)V",

Dalvik_java_lang_Runtime_nativeExit },

{ "nativeLoad", "(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/String;",

Dalvik_java_lang_Runtime_nativeLoad },

//……

};

 

static void Dalvik_java_lang_Runtime_nativeLoad(const u4* args,

JValue* pResult)

{

//......

bool success = dvmLoadNativeCode(fileName, classLoader, &reason);

//......

}

/dalvik/vm/Native.cpp

dvmLoadNativeCode() -> JNI_OnLoad()

bool dvmLoadNativeCode(const char* pathName, Object* classLoader,

char** detail)

{

SharedLib* pEntry;

//......

pEntry = findSharedLibEntry(pathName);//so被加载过一次之后,就会缓存起来

if (pEntry != NULL) {

//......

return true;

}

//……

//so第一次被加载

handle = dlopen(pathName, RTLD_LAZY);//打开so动态链接库,生存句柄到handle

//......

/* create a new entry */

SharedLib* pNewEntry;

pNewEntry = (SharedLib*) calloc(1, sizeof(SharedLib));

pNewEntry->pathName = strdup(pathName);

pNewEntry->handle = handle;//生存handle到pNewEntry

//……

SharedLib* pActualEntry = addSharedLibEntry(pNewEntry);//将pNewEntry生存到gDvm全局变量nativeLibs中,下次可以直接通过缓存获取

//......

vonLoad = dlsym(handle, "JNI_OnLoad");//第一次加载so时,挪用so中的JNI_OnLoad要领

//......

return result;

}

}

 

 

上面剖析总结:

通过System.loadLibrary()加载的库会被生存到全局变量gDvm.nativeLibs中,并执行其JNI_OnLoad要领。

 

JNI显式注册是直接将当地要领挪用地址指向到c层某要领,并将执行要领改成dvmCallJNIMethod(),隐式是通过要领命名规则去寻找要领的挪用地址,然后通过dvmCallJNIMethod()来执行类被加载时,所有的当地要领执行地址nativeFunc都被指向了Native.dvmResolveNativeMethod()

 

通过JNI显式注册会将当地要领挪用地址执行C能某实现要领,并将执行地址nativeFunc指向dvmCallJNIMethod(),隐式注册则是在挪用的时间才会通过命名规则去寻找要领的挪用地址,寻找到之后,再将执行地址nativeFunc指向dvmCallJNIMethod()

 

以是执行native要领时,nativeFunc未被指向到dvmCallJNIMethod()的要领(包罗第一次执行的隐式注册要领和未被注册的系统要领)都市通过

Native.dvmResolveNativeMethod()来处置惩罚,针对系统当地要领,会从 InternalNative.gDvmNativeMethodSet 中寻找;针对应用当地要领,则从 gDvm.nativeLibs 中寻找。

 

当第二次执行统一个要领时,则会直接执行dvmCallJNIMethod(),以是隐式注册相对显示注册来说,第一次挪用的时间会慢一点,可是初始化快。

Jni.dvmCallJNIMethod()执行当地要领,是通过挪用dvmPlatformInvoke() 来凭据差别cpu架构实现方式来执行的。

“沈阳软件公司”的新闻页面文章、图片、音频、视频等稿件均为自媒体人、第三方机构发布或转载。如稿件涉及版权等问题,请与

我们联系删除或处理,客服QQ:55506560,稿件内容仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同

其观点或证实其内容的真实性。

推荐阅读