android源码分析之JNI调用与回调

Posted 古冥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android源码分析之JNI调用与回调相关的知识,希望对你有一定的参考价值。

通过JNI,Java程序可以在加载本地库之后,调用Java类中声明的在本地库中实现的本地方法。此外,本地库中的函数也可以通过回调的方式调用Java类中的成员变量或者成员函数。
       1、在Java中,本地库的加载以及本地方法的声明         public class Natvie                     //本地方法声明                     public native void nativeInit();                     public native void nativeStart();                      public native boolean nativeLoop(int ptr );                     //本地库加载                    static                              System.LoadLibrary("native");                              
        2、在Native层的C文件中,需要进行本地方法的实现,以及方法绑定。
        #include"jni.h"                  void nativeInit( JNIEnv* env, jclass clazz )                 //方法体实现                 //将Java类中的方法与本地方法名字进行绑定,即写入JNINativeMethod数组中          static JNINativeMethod gTestMethods[] =                     "nativeInit",//Java类中的方法名             //方法参数,有Java中的全路径类名,以及上下文等等             "(Lcom/android/server/test/TestService;Landroid/content/Context;Landroid/os/MessageQueue;)I",             (void*) nativeInit ,//C++中的方法名                     "nativeStart",             "(Lcom/android/server/test/TestService;Landroid/content/Context;Landroid/os/MessageQueue;)I",             (void*) nativeStart ,                     ...,        
        3、在Native中获取Java类的回调,即在C++中调用Java的成员变量或成员方法。         在Java类中声明:         public void  onNativeCallback(int count)                     Log.d("Natvie","onNativeCallback count="+count);                 在C++或C文件中声明回调:          static struct                     jmethodID onNativeCallback;                    ...           gServiceClassInfo;
        在C++或C文件中进行回调获取:        1) 获取Java类             #define FIND_CLASS(var, className) \\             var = env->FindClass(className); \\             LOG_FATAL_IF(! var, "Unable to find class " className);
        2)获取Java成员方法             #define  GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \\             var = env->GetMethodID(clazz, methodName, methodDescriptor); \\             LOG_FATAL_IF(! var, "Unable to find method " methodName);
        3)获取Java成员变量             #define  GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \\             var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \\             LOG_FATAL_IF(! var, "Unable to find field " fieldName);
        4、将JNINativeMethod以及回调函数等等注册到JNI_OnLoad()中去。
             int register_android_server_Test(JNIEnv* env)                      int res = jniRegisterNativeMethods(env, "com/android/server/test/TestService",                              gTestMethods, NELEM(gTestMethods));                     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
                   // Callbacks
                   jclass clazz;                    FIND_CLASS(clazz, "com/android/server/test/TestService");
                   GET_METHOD_ID( gServiceClassInfo.onNativeCallback, clazz,                                 "onNativeCallback", "(J)V");
                   return 0;            
            此方法将gTestMethods数组,并绑定gServiceClassInfo中的回调函数,最后会在 JNI_OnLoad()方法中将会调用                                     register_android_server_Test(env)方法,这里由于是自定义JNI,所以会在C++类中定义extern方法JNI_OnLoad(),并调用register_android_server_Test,但如果是framework/base/service下面的服务,则不需定义JNI_OnLoad()方法,但是它会在OnLoad.cpp中的JNI_OnLoad()方法中调用此服务中定义的类似于register_android_server_Test()的方法。             它会在Dalvik虚拟机启动时,通过调用 Dalvik_java_lang_Runtime_nativeLoad()->dvmLoadNativeCode()-> vonLoad = dlsym(handle, "JNI_OnLoad");将相应的JNI方法加载。
        5、JNI库加载过程
时序图如下:

以上是关于android源码分析之JNI调用与回调的主要内容,如果未能解决你的问题,请参考以下文章

Android Framework实战开发-binder通信java及jni部分源码分析

Android Framework实战开发-binder通信java及jni部分源码分析

Android Framework实战开发-binder通信java及jni部分源码分析

Android JNI之JAVA与C++对象建立对称关联(JNI优化设计,确保JNI调用的稳定性)

如何在android的jni线程中实现回调

RxJava && Agera从源码简要分析基本调用流程