前面说过在android上实现jni调用有两种方式,在框架层实现,在应用程序 apk上实现。
在框架上实现:
需要在 java 源码中声明, 在C++代码中实现jni的各种方法,并注册到系统中。
jni的核心是jniNativeMethod 结构体,在jni.h中声明。
typedef struct {
const char *name; //jnj 函数的名称
const cgar *signature; //参数以及返回值
void * fnptr; //对应的C/C++函数实现
}JNINativeMethod;
比如 frameworks/base/core/jni 中的 android_util_Log.cpp 是对 frameworks/base/core/java/android/util 目录中的文件
Log.java的实现。
android_util_Log.cpp 定义了结构JNINativeMethod 实现的java方法,
/*
* JNI registration.
*/
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "isLoggable", "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable },
{ "println_native", "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native },
};
gMethods[] 保存声明的方法,但要通过jni提供的注册函数注册到运行时库中,由系统启动时自动初始化,
int register_android_util_Log(JNIEnv* env)
{
jclass clazz = env->FindClass("android/util/Log");
if (clazz == NULL) {
LOGE("Can't find android/util/Log");
return -1;
}
levels.verbose = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "VERBOSE", "I"));
levels.debug = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "DEBUG", "I"));
levels.info = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "INFO", "I"));
levels.warn = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "WARN", "I"));
levels.error = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ERROR", "I"));
levels.assert = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ASSERT", "I"));
return AndroidRuntime::registerNativeMethods(env, "android/util/Log", gMethods, NELEM(gMethods));
}
registerNativeMethods 函数为系统提供的注册jni函数的方法。
在 frameworks/base/core/java/android/util 的Log.java文件中,要声明静态方法。
。。。。。。。。。。。。。。。。。。
public static native boolean isLoggable(String tag, int level);
public static int w(String tag, Throwable tr) {
return println_native(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr));
}
。。。。。
基本流程就是这样, 核心点为通过 registerNativeMethods 注册到系统中,实现绑定。
util log 因其简单,是一个学习的好例子,还有其他如 android_util_Binder.cpp ,android_util_process.cpp 可以深入学习。