android源码分析之JNI调用与回调
2016-04-28 14:45
429 查看
通过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库加载过程
时序图如下:
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 shape的使用
- android中view坐标相关的知识
- Android smali 语法二
- Android 5.0 自定义dialog 背景不透明解决方法
- Android避免进入页面自动弹出软键盘(真正好用)
- 遇到onActivityResult不执行
- android开启手机wifi热点和连接到wifi热点
- Android中Preference的使用以及监听事件分析
- Android 应用安全开发之源码安全
- android通过反射获得资源数据
- JPush服务器端源码参考
- 为Android的apk应用程序文件加壳以防止反编译的教程
- Android照相机图片
- Android活动标题栏隐藏
- Android ImageView的scaleType属性与adjustViewBounds属性
- Android 自定义View的一些总结
- android KeyEvent分发
- ViewPager+Fragment第二次进入显示空白
- 关于ViewHolder的终极优化
- Fragment里面的Viewpaper不显示内容不执行getItem的解决方案