http://blog.csdn.net/yujun411522/article/details/46342793
本文出自:【yujun411522的博客】
2.1 概述
public boolean setLastModified(long time) { if (time < 0) { throw new IllegalArgumentException("time < 0"); } return setLastModifiedImpl( path, time);//调用本地方法setLastModifiedImpl方法 } private static native boolean setLastModifiedImpl(String path, long time);
Log.d("tag","Msg");
public final class Log{ public static int d(String tag, String msg) { return println_native( LOG_ID_MAIN, DEBUG , tag, msg);//调用本地方法println_native } public static native int println_native(int bufID, int priority, String tag, String msg); }
/* * In class android.util.Log: * public static native int println_native(int buffer, int priority, String tag, String msg) */ static jint android_util_Log_println_native(JNIEnv* env, jobject clazz, jint bufID, jint priority, jstring tagObj, jstring msgObj) { //比java层的println_native 函数多了两个参数JNIEnv* env, jobject clazz,其他的参数和java层一一对应。 const char* tag = NULL; const char* msg = NULL; if (msgObj == NULL) { //异常处理,后面会涉及到 jniThrowNullPointerException(env, "println needs a message"); return -1; } if (bufID < 0 || bufID >= LOG_ID_MAX) { jniThrowNullPointerException(env, "bad bufID"); return -1; } if (tagObj != NULL) // 将java 中String对象转换成本地UTF-8字符串 tag = env->GetStringUTFChars(tagObj, NULL); msg = env->GetStringUTFChars(msgObj, NULL); //继续调用本地方法 __android_log_buf_write。 int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg); if (tag != NULL) //使用完之后要释放资源,否则导致JVM内存泄露 env->ReleaseStringUTFChars(tagObj, tag); env->ReleaseStringUTFChars(msgObj, msg); return res; }
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; } //通过jni操作java对应,后面会介绍。 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")); //调用了registerNativeMethod方法 return AndroidRuntime::registerNativeMethods(env, "android/util/Log", gMethods, NELEM(gMethods)); }
/* * 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 }, };
typedef struct { const char* name; //java层的native函数的名称 const char* signature; //该native函数的签名(返回值+参数列表),因为java中支持函数重载,所以函数名称+函数签名才能明确确定一个函数 void* fnPtr; //函数指针,指向jni层该对应的函数实现 } JNINativeMethod;
{ "println_native", "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native } "println_native", //对应java层的函数名称为println_native的函数 "(IILjava/lang/String;Ljava/lang/String;)I",//该函数签名为(IILjava/lang/String;Ljava/lang/String;)I,关于函数签名后面会介绍含义 (void*) android_util_Log_println_native//该函数在jni层实现的方法指针为 (void*) android_util_Log_println_native
/* * Register native methods using JNI. */ /*static*/ int AndroidRuntime::registerNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods) { return jniRegisterNativeMethods(env, className, gMethods, numMethods); }
extern "C" int jniRegisterNativeMethods(C_JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods) { JNIEnv* e = reinterpret_cast<JNIEnv*>(env); LOGV("Registering %s natives", className); scoped_local_ref<jclass> c(env, findClass(env, className)); if (c.get() == NULL) { LOGE("Native registration unable to find class '%s', aborting", className); abort(); } if ((*env)->RegisterNatives(e, c.get(), gMethods, numMethods) < 0) { LOGE("RegisterNatives failed for '%s', aborting", className); abort(); } return 0; }
public class MediaScanner{ static { System.loadLibrary("media_jni"); native_init(); } ... private static native final void native_init(); private native void processFile(String path, String mimeType, MediaScannerClient client); }
// This function gets a field ID, which in turn causes class initialization. // It is called from a static block in MediaScanner, which won't run until the // first time an instance of this class is used. //java层中native_init 在jni层的实现 static void android_media_MediaScanner_native_init(JNIEnv *env) { LOGV("native_init"); // kClassMediaScannerClient = "android/media/MediaScannerClient"; jclass clazz = env->FindClass(kClassMediaScanner); if (clazz == NULL) { return; } //在fields.context 中保存int类型的mNativeContext成员变量的fieldId fields.context = env->GetFieldID(clazz, "mNativeContext", "I"); if (fields.context == NULL) { return; } }
static void android_media_MediaScanner_processFile( JNIEnv *env, jobject thiz, jstring path, jstring mimeType, jobject client) { LOGV("processFile"); // Lock already hold by processDirectory MediaScanner *mp = getNativeScanner_l(env, thiz); if (mp == NULL) { //异常处理,后面会介绍异常处理 jniThrowException(env, kRunTimeException, "No scanner available"); return; } if (path == NULL) { //异常处理 jniThrowException(env, kIllegalArgumentException, NULL); return; } const char *pathStr = env->GetStringUTFChars(path, NULL); if (pathStr == NULL) { // Out of memory return; } const char *mimeTypeStr = (mimeType ? env->GetStringUTFChars(mimeType, NULL) : NULL); if (mimeType && mimeTypeStr == NULL) { // Out of memory // ReleaseStringUTFChars can be called with an exception pending. env->ReleaseStringUTFChars(path, pathStr); return; } MyMediaScannerClient myClient(env, client); //调用MediaScanner的本地方法processFile MediaScanResult result = mp->processFile(pathStr, mimeTypeStr, myClient); if (result == MEDIA_SCAN_RESULT_ERROR) { LOGE("An error occurred while scanning file '%s'.", pathStr); } env->ReleaseStringUTFChars(path, pathStr); if (mimeType) { env->ReleaseStringUTFChars(mimeType, mimeTypeStr); }
// This function only registers the native methods, and is called from // JNI_OnLoad in android_media_MediaPlayer.cpp int register_android_media_MediaScanner(JNIEnv *env) { return AndroidRuntime::registerNativeMethods(env, kClassMediaScanner, gMethods, NELEM(gMethods)); }
static JNINativeMethod gMethods[] = { //.. { "processFile", //java层名称为processFile "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V", //java层函数签名为(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;) (void *)android_media_MediaScanner_processFile //该函数在jni层中的函数指针为(void *)android_media_MediaScanner_processFile }, //.. { "native_init", //java层名称为native_init "()V", //java层函数签名为()V (void *)android_media_MediaScanner_native_init 该函数在jni层中的函数指针为(void *)android_media_MediaScanner_native_init }, };
typedef struct { const char* name; //java层的native函数的名称 const char* signature; //该native函数的签名(返回值+参数列表),因为java中支持函数重载,所以函数名称+函数签名才能明确确定一个函数 void* fnPtr; //函数指针,指向jni层该对应的函数实现 } JNINativeMethod;
jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { LOGE("ERROR: GetEnv failed\n"); goto bail; } assert(env != NULL); if (register_android_media_MediaPlayer(env) < 0) { LOGE("ERROR: MediaPlayer native registration failed\n"); goto bail; } if (register_android_media_MediaRecorder(env) < 0) { LOGE("ERROR: MediaRecorder native registration failed\n"); goto bail; } //在这里调用register_android_media_MediaScanner 注册函数 if (register_android_media_MediaScanner(env) < 0) { LOGE("ERROR: MediaScanner native registration failed\n"); goto bail; } if (register_android_media_MediaMetadataRetriever(env) < 0) { LOGE("ERROR: MediaMetadataRetriever native registration failed\n"); goto bail; } if (register_android_media_AmrInputStream(env) < 0) { LOGE("ERROR: AmrInputStream native registration failed\n"); goto bail; } if (register_android_media_ResampleInputStream(env) < 0) { LOGE("ERROR: ResampleInputStream native registration failed\n"); goto bail; } if (register_android_media_MediaProfiles(env) < 0) { LOGE("ERROR: MediaProfiles native registration failed"); goto bail; } if (register_android_mtp_MtpDatabase(env) < 0) { LOGE("ERROR: MtpDatabase native registration failed"); goto bail; } if (register_android_mtp_MtpDevice(env) < 0) { LOGE("ERROR: MtpDevice native registration failed"); goto bail; } if (register_android_mtp_MtpServer(env) < 0) { LOGE("ERROR: MtpServer native registration failed"); goto bail; } /* success -- return valid version number */ result = JNI_VERSION_1_4; }
struct _JNIEnv; typedef const struct JNINativeInterface* C_JNIEnv; #if defined(__cplusplus) typedef _JNIEnv JNIEnv; //c++中使用_JNIEnv .. #else typedef const struct JNINativeInterface* JNIEnv; //c语言中使用JNINativeInterface .. #endif
/* * C++ object wrapper. * * This is usually overlaid on a C struct whose first element is a * JNINativeInterface*. We rely somewhat on compiler behavior. */ struct _JNIEnv { /* do not rename this; it does not seem to be entirely opaque */ const struct JNINativeInterface* functions; #if defined(__cplusplus) ..很多方法 jclass FindClass(const char* name) { return functions->FindClass(this, name); } jthrowable ExceptionOccurred() { return functions->ExceptionOccurred(this); } void ExceptionDescribe() { functions->ExceptionDescribe(this); } void ExceptionClear() { functions->ExceptionClear(this); } jobject NewGlobalRef(jobject obj) { return functions->NewGlobalRef(this, obj); } void DeleteGlobalRef(jobject globalRef) { functions->DeleteGlobalRef(this, globalRef); } jmethodID GetMethodID(jclass clazz, const char* name, const char* sig) { return functions->GetMethodID(this, clazz, name, sig); } jmethodID GetStaticMethodID(jclass clazz, const char* name, const char* sig) { return functions->GetStaticMethodID(this, clazz, name, sig); } jfieldID GetFieldID(jclass clazz, const char* name, const char* sig) { return functions->GetFieldID(this, clazz, name, sig); } jobject GetObjectField(jobject obj, jfieldID fieldID) { return functions->GetObjectField(this, obj, fieldID); } //各种GetXXXField 方法 void SetObjectField(jobject obj, jfieldID fieldID, jobject value) { functions->SetObjectField(this, obj, fieldID, value); } //各种SetXXXField 方法 #define CALL_TYPE_METHOD(_jtype, _jname) _jtype Call##_jname##Method(jobject obj, jmethodID methodID, ...) { _jtype result; va_list args; va_start(args, methodID); result = functions->Call##_jname##MethodV(this, obj, methodID,args); va_end(args); return result; } #define CALL_STATIC_TYPE_METHOD(_jtype, _jname) _jtype CallStatic##_jname##Method(jclass clazz, jmethodID methodID, ..) { _jtype result; va_list args; va_start(args, methodID); result = functions->CallStatic##_jname##MethodV(this, clazz,methodID, args); va_end(args); return result; } //..其他方法 }
struct JNINativeInterface { jclass (*FindClass)(JNIEnv*, const char*); jint (*Throw)(JNIEnv*, jthrowable); jint (*ThrowNew)(JNIEnv *, jclass, const char *); jthrowable (*ExceptionOccurred)(JNIEnv*); void (*ExceptionDescribe)(JNIEnv*); void (*ExceptionClear)(JNIEnv*); jobject (*NewGlobalRef)(JNIEnv*, jobject); void (*DeleteGlobalRef)(JNIEnv*, jobject); jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...); jfieldID (*GetFieldID)(JNIEnv*, jclass, const char*, const char*); jobject (*GetObjectField)(JNIEnv*, jobject, jfieldID); //..其他方法 }
jint AttachCurrentThread(JNIEnv** p_env, void* thr_args) { return functions->AttachCurrentThread(this, p_env, thr_args); }
jint DetachCurrentThread() { return functions->DetachCurrentThread(this); }
/* * Primitive types that match up with Java equivalents. */ #ifdef HAVE_INTTYPES_H # include <inttypes.h> /* C99 */ typedef uint8_t jboolean; /* unsigned 8 bits */ typedef int8_t jbyte; /* signed 8 bits */ typedef uint16_t jchar; /* unsigned 16 bits */ typedef int16_t jshort; /* signed 16 bits */ typedef int32_t jint; /* signed 32 bits */ typedef int64_t jlong; /* signed 64 bits */ typedef float jfloat; /* 32-bit IEEE 754 */ typedef double jdouble; /* 64-bit IEEE 754 */ #else typedef unsigned char jboolean; /* unsigned 8 bits */ typedef signed char jbyte; /* signed 8 bits */ typedef unsigned short jchar; /* unsigned 16 bits */ typedef short jshort; /* signed 16 bits */ typedef int jint; /* signed 32 bits */ typedef long long jlong; /* signed 64 bits */ typedef float jfloat; /* 32-bit IEEE 754 */ typedef double jdouble; /* 64-bit IEEE 754 */ #endif
{ "println_native", "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native }
{ "processFile","(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V" (void *)android_media_MediaScanner_processFile }
jclass Findclass(const char* name)//查找全路径名称为name的类信息 jclass GetObjectClass(jobject ojb)//返回该对象所在类的信息
jclass clazz = env->FindClass("android/util/Log");
jfieldID GetFieldID(jclass clazz,const char* name,const char*sig);
fields.context =env->GetFieldID(clazz, "mNativeContext", "I");
jmethodID GetMethodID(jclass clazz,const char* name,const char*sig);
MyMediaScannerClient(JNIEnv *env, jobject client){ .. jclass mediaScannerClientInterface = env->FindClass(kClassMediaScannerClient); //对应MediaScannerClie中void scanFile(String,long,long,boolean,boolean)方法 mScanFileMethodID = env->GetMethodID( mediaScannerClientInterface, "scanFile", "(Ljava/lang/String;JJZZ)V"); //对应MediaScannerClie中void handleStringTag (String,String)方法 mHandleStringTagMethodID = env->GetMethodID( mediaScannerClientInterface, "handleStringTag", "(Ljava/lang/String;Ljava/lang/String;)V"); //对应MediaScannerClie中 void setMimeType(String)方法 mSetMimeTypeMethodID = env->GetMethodID( mediaScannerClientInterface, "setMimeType", "(Ljava/lang/String;)V"); ... }
static MediaScanner *getNativeScanner_l(JNIEnv* env, jobject thiz) { //fields.context =env->GetFieldID(clazz, "mNativeContext", "I"); return (MediaScanner *) env->GetIntField(thiz, fields.context); }
GetTypeField(jobject,jfieldID)//返回jobject类中变量为jfieldID的变量
//fields.context =env->GetFieldID(clazz, "mNativeContext", "I"); env->SetIntField(thiz, fields.context, 0);//将mNativeContext设置为0
SetTypeField(jobject obj,jfieldID fieldID,nativeType value)//fieldID的值设置为value
mEnv->CallVoidMethod(mClient, mScanFileMethodID, pathStr, lastModified, fileSize, isDirectory, noMedia);
CallTypeMethod(jobject obj,jmethodID methodID,参数1,参数2...)来调用jmethodID函数,并将参数传递进去。
GetStaticFieldID(jclass clazz,const char* name,const char*sig); GetStaticTypeField(jobject obj,jfieldID fieldID) SetStaticTypeField(jobject obj,jfieldID fieldID,nativeType value) GetStaticMethodID(jclass clazz,const char* name,const char*sig); CallStaticTypeMethod(jobject obj,jmethodID methodID,参数1,参数2...)
static jobject save_class = NULL//定义了一个全局的jobject static void android_media_MediaScanner_processFile( JNIEnv *env, jobject thiz, jstring path, jstring mimeType, jobject client) { .... //保存thiz对象,也就是MediaScanner对象 save_class =thiz ; ... return ; } //调用call方法 void call() { //使用save_class 可以吗? //不可以,因为有可能MediaScanner对象已经被回收了。 }
boolean test(const char* name) { for(int i=0;i<10000;i++) { jstring nameStr = env->NewStringUTF(name); //如果这里我们不立即释放nameStr,那么会在函数结束之后才释放。看起来没有太大区别,若像这样创建10000个jstring 就占用了非常多的内存了。所以要这里在不需要使用的时候还是及时释放 //env->DeleteLocalRef(nameStr); } }
public: MyMediaScannerClient(JNIEnv *env, jobject client) : mEnv(env), mClient(env->NewGlobalRef(client)),//创建一个全局引用mClient mScanFileMethodID(0), mHandleStringTagMethodID(0), mSetMimeTypeMethodID(0) { LOGV("MyMediaScannerClient constructor"); jclass mediaScannerClientInterface = env->FindClass(kClassMediaScannerClient); if (mediaScannerClientInterface == NULL) { LOGE("Class %s not found", kClassMediaScannerClient); } else { mScanFileMethodID = env->GetMethodID( mediaScannerClientInterface, "scanFile", "(Ljava/lang/String;JJZZ)V"); mHandleStringTagMethodID = env->GetMethodID( mediaScannerClientInterface, "handleStringTag", "(Ljava/lang/String;Ljava/lang/String;)V"); mSetMimeTypeMethodID = env->GetMethodID( mediaScannerClientInterface, "setMimeType", "(Ljava/lang/String;)V"); } } virtual ~MyMediaScannerClient() { LOGV("MyMediaScannerClient destructor"); //在析构函数中主动释放mClient mEnv->DeleteGlobalRef(mClient); }
static void android_media_MediaScanner_processFile( JNIEnv *env, jobject thiz, jstring path, jstring mimeType, jobject client) { ... // Lock already hold by processDirectory MediaScanner *mp = getNativeScanner_l(env, thiz); if (mp == NULL) { jniThrowException(env, kRunTimeException, "No scanner available"); return; } .. }
extern "C" int jniThrowException(C_JNIEnv* env, const char* className, const char* msg) { JNIEnv* e = reinterpret_cast<JNIEnv*>(env); if ((*env)->ExceptionCheck(e)) { /* TODO: consider creating the new exception with this as "cause" */ scoped_local_ref<jthrowable> exception(env, (*env)->ExceptionOccurred(e)); (*env)->ExceptionClear(e); if (exception.get() != NULL) { char* text = getExceptionSummary(env, exception.get()); LOGW("Discarding pending exception (%s) to throw %s", text, className); free(text); } } scoped_local_ref<jclass> exceptionClass(env, findClass(env, className)); if (exceptionClass.get() == NULL) { LOGE("Unable to find exception class %s", className); /* ClassNotFoundException now pending */ return -1; } if ((*env)->ThrowNew(e, exceptionClass.get(), msg) != JNI_OK) { LOGE("Failed throwing '%s' '%s'", className, msg); /* an exception, most likely OOM, will now be pending */ return -1; } return 0; }