一文深入理解 JNI实现机制

  • 时间:
  • 浏览:0

if (pMeth->name == NULL)

}

tmpObject = env->GetObjectArrayElement(arrayObject, i);

/* start with our internal-native methods */

在java层通过native关键字创建本地措施,如下:(成员措施、static措施)

//显式注册

{ \

tmpString = reinterpret_cast<_jstring *>(env->CallObjectMethod(tmpObject, methodID_toString));

start()->startVm()

for (i = 0; i < size; i++) {

method->jniArgInfo, method->insSize, modArgs, method->shorty,

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

int main(int argc, char* const argv[])

/* now scan any DLLs we have loaded for JNI signatures */

} \

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

void dvmResolveNativeMethod(const u4* args, JValue* pResult,

return true;

//......

# you want CMake to locate.

synchronized (this) {

/dalvik/vm/Native.cpp

dvmResolveNativeMethod() -> lookupSharedLibMethod() -> findMethodInLib()

va_end(args); \

JNIEnv* env;

}

strcat(dest, tmpString);

so加载核心过程:



//……

# Sets the library as a shared library.

return _retok; \

ClassObject* result;

}

//……

env->DeleteLocalRef(tmpObject);

return;

private String doLoad(String name, ClassLoader loader) {

pMeth->signature, method) == 0)

//......

JNIEnv* env = self->jniEnv;

find_library( # Sets the name of the path variable.

//……

}

//……

//......

}

static bool registerSystemNatives(JNIEnv* pEnv)

/* match */

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

/dalvik/vm/Jni.cpp

jstring tmpString;

# included in the NDK.

JNIEnv是在Thread创建的之后创建的,我应该 它是属于守护任务管理器的,不都都可以守护任务管理器共享。最终调用措施时通过Stack.dvmCallMethod..相关措施去调用的。至此整个流程就分析完毕了。

u4 hash;

};

}

// Remainder of args get passed to startup class main()

bool dvmCreateInterpThread(Object* threadObj, int reqStackSize)

hash = dvmComputeUtf8Hash(classDescriptor);

//......

DalvikBridgeFunc bridge = gDvmJni.useCheckJni ? dvmCheckCallJNIMethod : dvmCallJNIMethod;

appendString(env, returnValue, jstring_);

return newClass;

static DalvikNativeClass gDvmNativeMethodSet[] = {

log)

return;

public native String stringFromJNIDis();

dvmSetNativeFunc((Method*) method, dfunc, NULL);

if (!dvmInternalNativeStartup()) {//初始化实物native

//......

dvmUseJNIBridge(method, fnPtr);

//注册Dex的getDex措施

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)

}

{

appendString(env, returnValue, tmpString);

jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {

}

gDvm.initializing = true;

-> loadClassFromDex() -> loadClassFromDex0() -> loadMethodFromDex() -> dvmResolveNativeMethod()

{

static {

}

本地措施调用过程:

jstring stringFromJNIDis(JNIEnv *env, jobject jobj);

new Thread().start() -> VMThread.create()

{

bool fromJni, JValue* pResult, const jvalue* args)

SharedLib* pNewEntry;

public static native String testParamsDis(int jint, String jstring, Object jobject, Object[] arrayObject, Listlist);

JNIEnv.CallVoidMethodA() -> Stack.dvmCallMethodA()

dvmSetNativeFunc()

//......

//......

const DalvikNativeMethod* pMeth = pClass->methodInfo;

jobject tmpObject;

}

classPtr++;

{

bool ignoreUnrecognized, JNIEnv* pEnv)

DefineClass,

//......

说到JNI都会陌生,它的全称:Java Native Interface,即Java本地接口。

JNI不仅仅是Android特有的,它是属于Java平台的,它允许在Java虚拟机内运行的java代码与這個编程语言(如c, c++和汇编语言)编写的守护任务管理器和库进行交互。

JNI调用姿势:Java —> JNI —> C/C++(SO库)

在Android平台中,使用JNI封装了跟硬件相关的操作,从而都都可以 通过Java调用相关JNI模块,以达到对硬件的调用。

//……

//......

{

if (!dvmNativeStartup()) {//初始化native

#define CALL_VIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \

Dalvik_java_lang_VMThread_currentThread },

//......

//......

ALOGV("+++ calling dlsym(%s)", mangleCM);

//......

self->status = THREAD_RUNNING;

//so第一次被加载

/* found it, point it at the JNI bridge and then call it */

pClass = gDvmNativeMethodSet;//遍历全局本地措施集合,寻找实物注册的本地措施

dvmThrowUnsatisfiedLinkError("Native method not found", method);//没找到本地措施,则会报UnsatisfiedLinkError

JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;

}

static DalvikNativeClass gDvmNativeMethodSet[] = {

//......

runtime.start("com.android.internal.os.RuntimeInit",

//隐式注册

while (classPtr->classDescriptor != NULL) {

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

通过System.loadLibrary加载的本地措施,则是通过 lookupSharedLibMethod()措施来寻找的

startSystemServer ? "start-system-server" : "");

while (true) {

public static void loadLibrary(String libname) {

}

set(distribution_DIR ${CMAKE_SOURCE_DIR}/src/main/cpp)

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

#CMakeList.txt 内容如下:

RETURN_VOID();

//......

上边分析总结:

}

src/main/cpp/test-jni.cpp)

}

LOGD("test-jni.cpp JNI_OnLoad");

{

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

const u1* pEncodedData, Object* classLoader)

return env->NewStringUTF(returnValue);

Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \

break;

* First, we try it without the signature.

{"testParamsDis", "(ILjava/lang/String;Ljava/lang/Object;[Ljava/lang/Object;Ljava/util/List;)Ljava/lang/String;", (void *) testParamsDis}

}

}

{

hash = dvmComputeUtf8Hash(classDescriptor);

}

}

{

if (dvmIsNativeMethod(meth)) {//可能性是本地措施,会将nativeFunc指向dvmResolveNativeMethod,当执行本地措施时就会执行dvmResolveNativeMethod措施

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

}

if (pClass->classDescriptorHash == hash &&

for (i = 0; i < len; i++) {

if (!registerSystemNatives(pEnv)) {//注册系统本地措施

//……

//显式注册本地措施

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

u4 hash;

JNI_CreateJavaVM() -> Init.dvmStartUp()

}

}

//......

meth->nativeFunc = dvmResolveNativeMethod;

return clazz;

//隐式注册

pClass = gDvmNativeMethodSet;//遍历全局本地措施集合,寻找注册的系统本地措施

}

int cc = pthread_create(&threadHandle, &threadAttr, interpThreadStart, newThread);//创建守护任务管理器

}

ClassObject* newClass = NULL;

}

dvmCreateJNIEnv()

CallStaticIntMethod,

}

}

method->nativeFunc = func;

//......

static bool dvmRegisterJNIMethod(ClassObject* clazz, const char* methodName,

/*

externalNativeBuild {

好多好多 执行native措施时,nativeFunc未被指向到dvmCallJNIMethod()的措施(包括第一次执行的隐式注册措施和未被注册的系统措施)都会通过

if (insns != NULL) {

static int findMethodInLib(void* vlib, void* vmethod)

{

}

}

上边跟踪下来我们我们知道每个dex中的本地措施都会执行到 dvmResolveNativeMethod(),我们我们来看看该措施做了哪几种事情?

static ClassObject* loadClassFromDex0(DvmDex* pDvmDex,

{

//......

//......

{

return -1;

return -1;

newEnv->funcTable = &gNativeInterface;//接口函数

return stringFromJNIDis(env, jobj);

goto bail;

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

}

首先我们我们来看下守护任务管理器时怎样才能被创建的:

jni_invocation.Init(NULL);

}

//......

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

{ "create", "(Ljava/lang/Thread;J)V",

//……

runtime.mArgC = argc - i;

(volatile int32_t*)(void*) &method->nativeFunc);

}

int size = env->CallIntMethod(list, list_size);

//调用本地措施会到这里来寻找系统本地方

/dalvik/vm/jni.cpp

{ "currentThread", "()Ljava/lang/Thread;",

/dalvik/vm/native/InternalNative.cpp

ALOGE("JNI_CreateJavaVM failed\n");

//加载javacore和nativehelper库

public static native String testParams(int jint, String jstring, Object jobject, Object[] arrayObject, Listlist);

dvmLoadNativeCode() -> JNI_OnLoad()

DalvikNativeFunc dvmLookupInternalNativeMethod(const Method* method)

DalvikNativeClass* classPtr = gDvmNativeMethodSet;//遍历系统类实物体,并保存到gDvm的全局变量userDexFiles中

const DalvikNativeMethod dvm_java_lang_Runtime[] = {

DalvikBridgeFunc dfunc = (DalvikBridgeFunc) infunc;

dvmAbort();

//……

}

if (tmpStr == NULL) {

//将nativeFunc指向dvmCallJNIMethod,并将insns指向func

/frameworks/base/core/jni/AndroidRuntime.cpp

//……

if (clazz == NULL) {

if (mangleCM == NULL)

下面我们我们将围绕如下内容进行展开:

1.java代码编译和执行过程

2.jni常规使用姿势

3.so加载流程(jni执行流程、注册措施原理)

4.JNIEnv作用及实现

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

//……

{

cmake {

(void*) method->insns, pResult);//调用措施insns,对于不同的cpu架构会有不同的调用措施

meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \

//......

}

bool dvmInternalNativeStartup()

/dalvik/vm/native/java_lang_VMThread.cpp

jclass clazz = env->FindClass("java/lang/Object");

}

结语

static JNINativeMethod gMethods[] = {

while (true) {

SHARED

application ? "application" : "tool");

dvmStartUp()-> InternalNative.dvmInternalNativeStartup()

{

}

if (meth == NULL) { \

vonLoad = dlsym(handle, "JNI_OnLoad");//第一次加载so时,调用so中的JNI_OnLoad措施

本文作者:MobSDK

if (gDvm.userDexFiles == NULL)

if (dvmCompareNameDescriptorAndMethod(pMeth->name,

//......

method, self);//执行措施

// ......

}

}

dvmPlatformInvoke(env, (ClassObject*) staticMethodClass,

/dalvik/vm/Native.cpp

}

}

//......

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

1.显式注册和隐式注册的区别

2.JNI_Onload措施的使用

3.JNIEnv的使用

4.JNI措施的命名,以及extern “C"的作用(告诉编译器,这次责代码请使用C来编译)等等

{

启动虚拟机守护任务管理器app_process首先会执行app_main.cpp中的main措施

break;

DvmDex* pDvmDex)

createJniNameString(meth->clazz->descriptor, meth->name, &len);

dvmSetNativeFunc(method, bridge, (const u2*) func);//将nativeFunc指向dvmCallJNIMethod,并将insns指向func

//显式注册

pNewEntry->pathName = strdup(pathName);

preMangleCM =

ClassObject* clazz;

return result;

const DalvikNativeClass* pClass;

${log-lib} )

DalvikNativeFunc infunc = dvmLookupInternalNativeMethod(method);//寻找系统实物本地措施

runtime.start("com.android.internal.os.ZygoteInit",

{

}

android_atomic_release_store((int32_t) func,

std::string dvmStartup(int argc, const char* const argv[],

{

/dalvik/vm/native/InternalNative.cpp

}

synchronized void loadLibrary0(ClassLoader loader, String libname) {

//......

}

}

void AndroidRuntime::start(const char* className, const char* options)

//......

* pthread entry function for threads started from interpreted code.

break;

const JNINativeMethod Java_java_lang_Class[] = {

gDvm.userDexFiles = dvmHashTableCreate(2, dvmFreeDexOrJar);

//java.lang.System

/*

dvmStartUp()-> registerSystemNatives() -> jni.RegisterNatives()

static jint RegisterNatives(JNIEnv* env, jclass jclazz, const JNINativeMethod* methods, jint nMethods)

(措施名称格式:Java_package_methodName)

const DalvikNativeMethod dvm_dalvik_system_DexFile[] = {

JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);

好多好多 系统的本地措施都会在应用启动的之后通过显示注册的措施被注册的,下面我们我们来看下系统启动都会做哪几种事情。

{ "getClassNameList", "(I)[Ljava/lang/String;",

}

static {

const DalvikNativeMethod* pMeth = pClass->methodInfo;

runtime.mClassName = className;

Android中ClassLoader都会继承自BaseDexClassLoader,加载dex是通过BaseDexClassLoader来加载的,会将dex中的信息都保存到DexPathList中,上边加载类的过程如下:

dvmCreateInterpThread(threadObj, (int) stackSize);//创建守护任务管理器

va_list args; \

dfunc(args, pResult, method, self);//执行

VMThread.create(this, stackSize);// VMThread创建

{

原文发布时间为:2018-11-2

/dalvik/vm/native/dalvik_system_DexFile.cpp

/* this is allowed, but unusual */

return "";

// TODO: should be synchronized, but dalvik doesn't support synchronized internal natives.

//......

return result;

sprintf(returnValue, "%d", i);

return JNI_OK;

for (int i = 0; i < nMethods; i++) {

dvmComputeUtf8Hash(classPtr->classDescriptor);

CALL_VIRTUAL(jobject, Object, NULL, (jobject) result.l, true);

if (!dvmJniStartup()) {//初始化jni

//......

dvmUseJNIBridge((Method*) method, func);

DalvikNativeFunc dvmLookupInternalNativeMethod(const Method* method)

//……

if (startVm(&mJavaVM, &env) != 0) {//启动vm

pMeth++;

//......

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

if (NULL == env) {

JniInvocation jni_invocation;

return pMeth->fnPtr;

//......

}

}

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

}

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

};

return (void*) dvmHashForeach(gDvm.nativeLibs, findMethodInLib,

result.l = (Object*)addLocalReference(ts.self(), result.l); \

const char* signature, void* fnPtr)

//通过createJniNameString和mangleString,得到最终函数的名称路径Java_package_methodName

return env->NewStringUTF(hello.c_str());

if (dvmCompareNameDescriptorAndMethod(pMeth->name,

java代码编译和执行的过程涉及到八个命令:javac和java

1.首先通过javac编译java代码,生成class字节码文件

2.javacTestCode.java --> TestCode.class

3.我应该 通过java命令来执行class字节码

4.javaTestCode.class

meth->jniArgInfo = computeJniArgInfo(&meth->prototype);

}

android {

ALOGV("JNI-registered %s.%s:%s", clazz->descriptor, methodName, signature);

if (env->RegisterNatives(clazz, methods, nMethods) < 0) {

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

while (true) {

FindClass,

Dalvik_dalvik_system_DexFile_getClassNameList },

/* update both, ensuring that "insns" is observed first */

method->insns = insns;

{

ALOGV("Note: %s.%s:%s was already registered", clazz->descriptor, methodName, signature);

java命令执行过程中,会先启动虚拟机,加载TestCode类信息到内存,我应该 由执行引擎执行其main措施。

while (true) {

//......

//......

//......

}

return findClassNoInit(descriptor, classLoader, pDvmDex);

//......

void appendString(JNIEnv *env, char *dest, jstring tmpStr) {

LOGE("test-jni.cpp JNI_OnLoad register JNIMethods failed");

}

写在前面

System.loadLibrary("test-jni");

jclass clazz;

return NULL;

if (pClass->classDescriptorHash == hash &&

}

dvmAbort();

/frameworks/base/cmds/app_process/app_main.cpp

classLoader);

//......

loadJniLibrary("nativehelper");

};

goto bail;

/* create a new entry */

# Sets the minimum version of CMake required to build the native library.

void dvmCallMethodA(Thread* self, const Method* method, Object* obj,

//显式注册

result = loadClassFromDex0(pDvmDex, pClassDef, &header, pEncodedData,

} else {

当第二次执行同八个措施时,则会直接执行dvmCallJNIMethod(),好多好多 隐式注册相对显示注册来说,第一次调用的之后会慢這個,我应该 初始化快。

test-jni

//隐式注册

env->ReleaseStringUTFChars(tmpStr, tmpString);

}

dvmCallMethodV(ts.self(), meth, obj, true, &result, args);//措施调用 \

系统实物本地措施通过 dvmLookupInternalNativeMethod()措施来寻找具体实现的

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

const char *tmpString = env->GetStringUTFChars(tmpStr, 0);

Thread* self = dvmThreadSelf();

}

//......

cmake_minimum_required(VERSION 3.4.1)

clazz = dvmLookupClass(descriptor, loader, true);//从gDvm全局变量的loadedClasses中找

dvmInternalNativeStartup()

Java代码编译和执行过程

# Specifies the name of the NDK library that

};

//……

注册本地措施

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

}

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

# Links the target library to the log library

clazz = loadClassFromDex(pDvmDex, pClassDef, loader);//没找到,则从dex中找

static void Dalvik_java_lang_Runtime_nativeLoad(const u4* args,

*/

一般我们我们是通过 System.loadLibrary("test-jni") 的措施来加载libtest-jni.so库的,同時 来跟踪下整个加载过程(此处分析的源码是基于Dalvik的)

JValue* pResult)

return pMeth->fnPtr;

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

so加载流程

static jmethodID methodID_toString;

pClass++;

{

return JNI_TRUE;

test

//......

jstring testParamsDis(JNIEnv *env, jclass type, jint jint_, jstring jstring_, jobject jobject_, jobjectArray objectArray, jobject list);

test-jni

method->fastJni = fastJni;

public synchronized void start() {

Native.dvmResolveNativeMethod()来正确处理,针对系统本地措施,会从 InternalNative.gDvmNativeMethodSet 中寻找;针对应用本地措施,则从 gDvm.nativeLibs 中寻找。

# Provides a relative path to your source file(s).

Dalvik_dalvik_system_DexFile_defineClassNative },

if (_isref && !dvmCheckException(ts.self())) \

func = dlsym(pLib->handle, mangleCM);//根据动态链接库操作句柄与符号,返回符号对应的地址

}

newClass->sourceFile = dexGetSourceFile(pDexFile, pClassDef);

clazz = dvmDefineClass(pDvmDex, descriptor, loader);

//......

public native String stringFromJNIDis();

{

jstring stringFromJNIDis(JNIEnv *env, jobject jobj) {

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

}

//系统本地措施都居于这里

static void* interpThreadStart(void* arg)

//......

int i = jint_;

(*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult,

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

//......

loadMethodFromDex(newClass, &method, &newClass->directMethods[i]);//遍历加载措施

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

/dalvik/vm/oo/Class.cpp

//显式注册

//......

target_link_libraries( # Specifies the target library.

//卸载都会执行该措施

JNIEXPORT void JNI_OnUnload(JavaVM *vm, void *reserved) {

//措施具体实现(下面是callVoidMethodA()具体实现)

JNI常规使用姿势

// Back to run mode.

//……

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

if (func != NULL) {

//......

LOGD("test-jni.cpp Java_com_mob_test_jni_testjni_JNIMethods_stringFromJNI");

public static native String testParamsDis(int jint, String jstring, Object jobject, Object[] arrayObject, Listlist);



LOGD("test-jni.cpp testParamsDis");

//...



{

{

#include

//……

/* only update nativeFunc */

}

GetFieldID,

return (int) func;

jmethodID methodID, ...) \

}

//......

GetObjectField,

return "dvmJniStartup failed";

const DexClassDef* pClassDef, const DexClassDataHeader* pHeader,

}

//……

if (!registerNativeMethods(env, "com/mob/test/jni/testjni/JNIMethods", gMethods, NELEM(gMethods))) {

/dalvik/vm/native/java_lang_runtime.cpp

}

if (!dvmRegisterJNIMethod(clazz, methods[i].name,

if (zygote) {

jstring itemStr;

char returnValue[1024];

extern "C" JNIEXPORT jstring JNICALL

return JNI_FALSE;

self->jniEnv = dvmCreateJNIEnv(self);//创建jniEnv

ClassObject* dvmDefineClass(DvmDex* pDvmDex, const char* descriptor,

}

Dalvik_java_lang_VMThread_create },//守护任务管理器创建措施

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

mangleCM = mangleString(preMangleCM, len);

LOGD("test-jni.cpp JNI_OnUnload");

{

TRACE_METHOD_ENTER(self, method);

}

if (clazz == NULL) {

dvmLookupInternalNativeMethod() -> java_lang_runtime.Dalvik_java_lang_Runtime_nativeLoad()

return JNI_FALSE;

static _ctype Call##_jname##Method(JNIEnv* env, jobject jobj, \

static void Dalvik_java_lang_VMThread_create(const u4* args, JValue* pResult)

class中本地措施加载过程:

#include

defineClassNative()-> Class.dvmDefineClass()

}

};

}

}

}

jclass clazz_list = env->GetObjectClass(list);

return (JNIEnv*) newEnv;

JNIEXPORT jobject JNICALL Java_java_lang_Class_getDex(JNIEnv* env, jclass javaClass);

itemStr = reinterpret_cast(env->CallObjectMethod(list, list_get, i));

Java_com_mob_test_jni_testjni_JNIMethods_testParams(JNIEnv *env, jclass type, jint jint_, jstring jstring_, jobject jobject_,

}

{

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {

在代码中我们我们并不都都可以看完相关加载nativeLoad這個本地措施的so,不都都可以它又是用哪几种措施在哪几种之后被注册的呢?

Dalvik_java_lang_VMThread_create() -> Thread.dvmCreateInterpThread()

if (pClass->classDescriptor == NULL)

loadJniLibrary("javacore");

JNIEnv是JNI指针接口,通常我们我们通过它来调用操作Java对象,它提供了所有的操作java对象的api。

methodID_toString = env->GetMethodID(clazz, "toString", "()Ljava/lang/String;");

//......

static ClassObject* loadClassFromDex(DvmDex* pDvmDex, const DexClassDef* pClassDef, Object* classLoader)

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

/dalvik/vm/Jni.cpp

public native String stringFromJNI();



{

dvmDefineClass() -> findClassNoInit() -> dvmLookupClass()

if (method->nativeFunc != dvmResolveNativeMethod) {

}

public static native String testParams(int jint, String jstring, Object jobject, Object[] arrayObject, Listlist);

{

clazz = env->FindClass(className);

String error = doLoad(filename, loader);

return;

void dvmSetNativeFunc(Method* method, DalvikBridgeFunc func, const u2* insns)

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

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

static void loadMethodFromDex(ClassObject* clazz, const DexMethod* pDexMethod, Method* meth)

System.loadLibrary("test-jni");

//......

{"stringFromJNIDis", "()Ljava/lang/String;", (void *) stringFromJNIDis},

const SharedLib* pLib = (const SharedLib*) vlib;

return JNI_VERSION_1_4;

}

void* func = lookupSharedLibMethod(method);//在动态加载的so中寻找本地措施

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

TRACE_METHOD_EXIT(self, method);

创建c层代码,并注册本地措施

hasBeenStarted = true;

}

static void* lookupSharedLibMethod(const Method* method)

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

break;

JValue* pResult)

if (pClass->classDescriptor == NULL)

std::string hello = "Hello from C++";

return _retfail; \

};

appendString(env, returnValue, returnToString);

return "dvmInternalNativeStartup failed";

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

JNI_CreateJavaVM()在art和dalvik中都会相关实现,这里仅以dalvik为主线跟踪,art的实现在/art/runtime/jni_internal.cc中

std::string status = dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);//初始化vm

runtime.mArgV = argv + i;

JNIEnv *env = NULL;

goto bail;

/dalvik/vm/interp/Stack.cpp

/dalvik/vm/Thread.cpp

if (pEntry != NULL) {

/* Initialize VM. */

loadIFieldFromDex(newClass, &field, &newClass->ifields[i]);//遍历加载成员变量

}

#include "common.h"

//......

static const struct JNINativeInterface gNativeInterface = {

(*method->nativeFunc)(args, pResult, method, self);//执行nativeFunc

{

classPtr->classDescriptorHash =

jmethodID list_size = env->GetMethodID(clazz_list, "size", "()I");

//......

const Method* meth; \

jstring testParamsDis(JNIEnv *env, jclass type, jint jint_, jstring jstring_, jobject jobject_, jobjectArray arrayObject, jobject list) {

SharedLib* pEntry;

const Method* method, Thread* self)

Runtime.getRuntime().loadLibrary0(VMStack.getCallingClassLoader(), libname);

}

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

//......

};

return;

CallVoidMethod,

{ "defineClassNative", "(Ljava/lang/String;Ljava/lang/ClassLoader;I)Ljava/lang/Class;",

}

JValue result; \

}

//......

}

}

//......

if (preMangleCM == NULL)

{

LOGD("test-jni.cpp stringFromJNIDis");

{

在java层,加载本地措施前,加载so

const DalvikNativeMethod dvm_java_lang_VMThread[] = {

if (gDvm.nativeLibs == NULL) {

BaseDexClassLoader.findClass() -> DexPathList.findClass() -> 遍历dexElements -> DexFile.loadClassBinaryName() -> DexFile.defineClass() -> DexFile.defineClassNative()

jsize len = env->GetArrayLength(arrayObject);

Jni.dvmCallJNIMethod()执行本地措施,是通过调用dvmPlatformInvoke() 来根据不同cpu架构实现措施来执行的。

}

}

}

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

Dalvik_java_lang_Runtime_nativeLoad },

const Method* meth = (const Method*) vmethod;

//java.lang.Runtime

}

JNIEnv的创建

java/lang/Thread.java

/* match */

}

pMeth->signature, method) == 0)

public class JNIMethods {

/* start the virtual machine */

//……

}

至此,我们我们都都可以 知道调用JNI措施最终会通过 Jni.dvmCallJNIMethod() -> dvmPlatformInvoke() 来根据不同cpu架构实现进行调用。

} else if (className) {

ScopedJniThreadState ts(env); \

};

jobjectArray arrayObject,

dvmCreateInterpThread() -> interpThreadStart() -> jni.dvmCreateJNIEnv()

methodID_toString = NULL;

return true;

static void Dalvik_dalvik_system_DexFile_defineClassNative(const u4* args,

}

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

Class被加载的过程

if (infunc != NULL) {

private static native String nativeLoad(String filename, ClassLoader loader, String librarySearchPath);

jstring returnToString = reinterpret_cast<_jstring *>(env->CallObjectMethod(jobject_, methodID_toString));

void dvmUseJNIBridge(Method* method, void* func) {

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

Object* classLoader)

if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {//创建vm

//……

main() -> AndroidRuntime.start()

ALOGE("Unexpected init state: nativeLibs not ready");

dvmResolveNativeMethod() -> InternalNative.dvmLookupInternalNativeMethod()

return NULL;

//……

path "CMakeLists.txt"

//加载so都会执行该措施

}

//……

return testParamsDis(env, type, jint_, jstring_, jobject_, arrayObject, list);

//......

return "couldn't register system natives";

appendString(env, returnValue, itemStr);

char** detail)

jobject list) {

public class JNIMethods {

} \

System.loadLibrary() -> Runtime.loadLibray0() -> Runtime.doLoad() -> Runtime.nativeLoad()

本文来自云栖社区合作伙伴“安卓巴士Android开发者门户”,了解相关信息都都可以 关注“安卓巴士Android开发者门户”。

public native String stringFromJNI();

jmethodID list_get = env->GetMethodID(clazz_list, "get", "(I)Ljava/lang/Object;");

void dvmCallJNIMethod(const u4* args, JValue* pResult, const Method* method, Thread* self) {

const DalvikNativeClass* pClass;

在gradle中配置cmake编译选项,并编写CMakeLists.txt脚本,用于生成so

{

COMPUTE_STACK_SUM(self);

//加载so

/dalvik/vm/Init.cpp

return "dvmNativeStartup failed";

/dalvik/vm/oo/Class.cpp

JNIEnv作用及实现

}

checkNotStarted();

return true;

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

}

pClass++;

return NULL;

if (pEnv->RegisterNatives(c, Java_java_lang_Class, 1) != JNI_OK) {

}

JNIEnv* dvmCreateJNIEnv(Thread* self) {

RegisterNatives()-> dvmRegisterJNIMethod()-> dvmUseJniBridge() -> Class.dvmSetNativeFunc()

return nativeLoad(name, loader, librarySearchPath);

//……

{ "getDex", "()Lcom/android/dex/Dex;", (void*) Java_java_lang_Class_getDex },

不都都可以JNIEnv又是何时创建,以及怎样才能来操作Java对象的呢?我们我们同時 来看看它的具体实现~

extern "C" JNIEXPORT jstring JNICALL

return JNI_ERR;

if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {

static ClassObject* findClassNoInit(const char* descriptor, Object* loader,

assert(pDvmDex != NULL);

va_start(args, methodID); \

if (dvmIsNativeMethod(method)) {

Thread* newThread = allocThread(stackSize);

//...

JVM的逻辑内存模型如下:

add_library( # Sets the name of the library.

{

if (pMeth->name == NULL)

Thread* self = dvmThreadSelf();

(void*) method);//先从gDvm全局变量nativeLibs中寻找,没找到,则通过findMethodInLib在so中寻找,找到则保存到nativeLibs中

return false;

return true;

Dalvik_java_lang_Runtime_nativeExit },

static int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int nMethods) {

methods[i].signature, methods[i].fnPtr))

pMeth++;

LOGD("test-jni.cpp Java_com_mob_test_jni_testjni_JNIMethods_testParams");

通过上边的分析,我们我们知道了JNI是怎样才能在java和本地代码之间建立桥梁和通讯的。

在使用JNI的之后,须要注意:

*/

Java_com_mob_test_jni_testjni_JNIMethods_stringFromJNI(JNIEnv *env, jobject jobj) {