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库加载过程
时序图如下:


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值