在Android的VM裡,可以加載C模塊(也就是so庫),及通過System.loadLibrary()函數來加載。當加載某個so庫時,VM會先執行其實現的JNI_Onload函數。該函數的原型為:exern "c" jint JNI_Onload(JavaVM* vm, void* reserved); 注意每個線程調用這個so庫時傳入的vm會不同。保證線程安全的代碼必須注意對此vm的判斷。
於是,我們可以在JNI_Onload函數裡進行一些初始化工作,可以向java層注冊c層的native函數,實現java層向c層的調用。
利用傳入的vm我們可以得到JNIEnv 指針,然後利用jniResiterNativMetheds函數來實現向java層注冊C函數。首先定義一個結構:
static JNINativeMethod sMethods[] = {
/*name,signature,funcptr */
{"close","(I)V" ,(void*)android_close},
{....... },
};
return jniRegisterNativeMethods(env,"com/android/server/AlarmService",sMethods,NELEM(sMethods));
然後在C層實現static void android_close(JNIEnv *env, jobject obj)函數。
OK,到這就可以在java的AlarmService類裡聲明一個這樣的函數:
private static native void close();
調用它就進入了該so模塊。所有這一切都是android的java虛擬機幫我們完成的。
反之,利用java虛擬機,我們也可以完成從c層回調java層。利用的還是那個很重要的類變量JNIEnv env.
FindClass();
GetMethodID();
CallObjectMethod();
CallStaticObjectMethod();
具體的細節可以參考手冊。