在NDK中,我们通过env->FindClass
来查找一个Java类,接下来,来看一下FindClass内部逻辑。
env->FindClass
实际会调用jni_internal.cc#FindClass
来看art/runtime/jni_internal.cc
再来看art/runtime/class_linker.cc
可以看到,这里有个LookupClass,传入要加载的类的签名,hash值和classLoader,如果返回的kclass不为null,则说明之前已经加载过,会直接return (双亲委托机制)。
如果不为null, 来看2148行,class_loader如果获取为null,那么调用FindInClassPath,从系统的启动类里去找,然后返回DifineClass。
如果class_loader不为null,则也会调用FindInClassPath,返回DefineClass。
再来看DefineClass
来看这里的LoadClass
先来看下它的参数
dex_file:dex文件
dex_class_def:要加载的类,在dex文件里面的一些信息
kclass:加载完成的一个对象 (class)
class_loader:类加载器
通过dex_file.GetClassDescriptor(dex_class_def);
获取class的描述
然后的一些代码,都是给Kclass进行赋值,
所以这个方法的作用就是将dex文件的信息,赋值给kclass
最后,会调用LoadClassMembers,来加载fields和methods,并赋值给kclass
可以看到注释,load fields,这里可以看到用到了ArtField
load methods
NumdirectMethods:直接方法 ,这里可以看到ArtMethod,后期会用到
NumVirtualMethods:虚方法
接着,再来看LinkCode,通过字面名称,知晓是来链接字节码的
method:ArtMethod
其中const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
,通过索引来找方法,然后调用oat_method.LinkMethod(method.Get());
,通过oat_method给函数设置一个默认的入口
来看art/runtime/oat_file.cc
method是ArtMethod,可以看到,根据解释器模式和AOT模式,设置不同的参数,这里的参数就是 art/runtime/mirror art_method.h
结构体中的字段
再往下看,bool enter_interpreter = NeedsInterpreter()
,用来判断是否是解释器模式
其中,isNative:是否是Native方法,ProxyMethod是否是代理方法,这两个都没有字节码,就算是解释器模式,也不需要使用解释器执行。
再来往下看,LinkCode
方法中,根据是否是解释器模式设置不同的方法执行入口
在往下看,如果是本地Native方法,那么会调用method->UnregisterNative(Thread::Current());
来看art/runtime/mirror/art_method.cc#UnregisterNative
,
setAccessFlags:设置访问权限
setEntryPointFromJni:设置artmethod中的entry_point_from_jni_,表明是JNI函数
在回来看art/runtime/class_linker.cc
,可以看到,这里调用了Instrumentation.updateMethodsCode
来看art/runtime/instrumentation.cc
这里来看updateEntryPoints
可以看到,这里是更改方法的执行入口
#if defined(ART_USE_PORTABLE_COMPILER)
method->SetEntryPointFromPortableCompiledCode(portable_code);
#endif
method->SetEntryPointFromQuickCompiledCode(quick_code);
然后,设置method相应的属性。(SetEntryPointFromInterpreter)
小结
env->FindClass
的内部调用过程
- env->FindClass //寻找Java Class
- art/runtime/jni_internal.cc#FindClass() //实际调用此方法
- art/runtime/class_linker.cc#FindClass() //接着调用此方法
- art/runtime/class_linker.cc#DefineClass() //最终会返回DefineClass
- art/runtime/class_linker.cc#LoadClass() //DefineClass内部会调用LoadClass,将dex文件的信息,赋值给kclass
- art/runtime/class_linker.cc#LoadClassMembers() //调用LoadClassMembers,加载fields和methods,并赋值给kclass
- art/runtime/class_linker.cc#LinkCode() //链接字节码
- art/runtime/oat_file.cc#LinkMethod() //LinkCode内部会调用LinkMethod,通过oat_method给函数设置一个默认的入口
- art/runtime/class_linker.cc#NeedsInterpreter() //是否是解释器模式
- art/runtime/mirror/art_method.cc#UnregisterNative() //如果是Native方法会设置访问权限、设置artmethod中的entry_point_from_jni_(表明是JNI函数)
- art/runtime/instrumentation.cc#UpdateMethodsCode() //更新方法的执行入口
- art/runtime/instrumentation.cc#UpdateEntrypoints() //UpdateMethodsCode会调用此方法,真正修改方法的执行入口
其他
源码为Android 5.1.0_r3