jni本来不在阅读计划里,想到这个场景更加常见,特意看了一下art源码中与jni相关的部分。
方法定义和绑定
信道建立
两种方式,一种是静态的宏声明,另一种是JNIEnv#RegisterNatives。后者逻辑如下: jni_internal.cc#RegisterNatives -> 对每个方法,找到对应的java方法(ArtMethod对象),交由class_linker.cc#RegisterNative -> art_method.h#SetEntryPointFromJni -> SetEntryPointFromJniPtrSize -> SetDataPtrSize -> SetNativePointer 这里直接利用artmethod基地址 + 偏移量的方式快速找到方法指针,并存下对应的native方法
java call c++
java调用jni方法的字节码是invokevirtual。
字节码映射关系
整体入口应该是interpreter.cc#EnterInterpreterFromEntryPoint(from啥不确定,但不影响后续)-> Execute -> ExecuteSwitch -> interpreter_switch_impl.h#ExecuteSwitchImpl -> interpreter_switch_impl-inl.h#ExecuteSwitchImplCpp 会在这里利用宏定义把invokevirtual映射到INVOKE_VIRTUAL方法上,其他op也是一样的流程。
INVOKE_VIRTUAL
interpreter_switch_impl-inl.h#HandleInvoke -> interpreter_common.h#DoInvoke -> 试图利用classlinker找到真实的artmethod对象(这里用到了一个threadlocal的cache),再利用VTable找到虚方法的真实实现对象,传给interpreter_common.cc#DoCall -> DoCallCommon -> PerformCall -> interpreter.cc#ArtInterpreterToInterpreterBridge -> unstarted_runtime.cc#UnstartedRuntime#Jni 这里就是直接找注册好的jni方法直接调用了