电竞比分网-中国电竞赛事及体育赛事平台

分享

認(rèn)識(shí)*.so里的JNI_OnLoad()函數(shù)

 lifei_szdz 2012-12-11

認(rèn)識(shí)*.so里的JNI_OnLoad()函數(shù)

當(dāng)Android VM(Virtual Machine)執(zhí)行到C組件(*so文件)里的System.loadLibrary()函數(shù)時(shí),首先會(huì)去執(zhí)行C組件里的JNI_OnLoad()函數(shù)。它的用途有二:

1.       告訴VMC組件使用那一個(gè)JNI版本。如果你的*.so文件沒(méi)有提供JNI_OnLoad()函數(shù),VM會(huì)默認(rèn)該*.so檔是使用最老的JNI 1.1版本。由于新版的JNI做了許多擴(kuò)充,如果需要使用JNI的新版功能,例如JNI 1.4 java.nio.ByteBuffer, 就必須藉由JNI_OnLoad()函數(shù)來(lái)告知VM。

2.       由于VM執(zhí)行到System.loadLibrary()函數(shù)時(shí),就會(huì)立即先呼叫JNI_OnLoad(),所以C組件的開發(fā)者可以藉由JNI_OnLoad()來(lái)進(jìn)行C組件內(nèi)的初期值之設(shè)定(Initialization)。

 

例如,在Android/system/lib/libmedia_jni.so檔案里,就提供了JNI_OnLoad()函數(shù),其程序代碼片段為:

 

//#define LOG_NDEBUG 0

#define LOG_TAG "MediaPlayer-JNI"

………

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;

    }

    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;

    }

    /* success -- return valid version number */

    result = JNI_VERSION_1_4;

bail:

    return result;

}

// KTHXBYE

 

    此函數(shù)回傳JNI_VERSION_1_4值給VM,于是VM知道了其所使用的JNI版本了。此外,它也做了一些初期的動(dòng)作(可呼叫任何本地函數(shù)),例如指令:

 

   if (register_android_media_MediaPlayer(env) < 0) {

        LOGE("ERROR: MediaPlayer native registration failed\n");

        goto bail;

    }

 

就將此組件提供的各個(gè)本地函數(shù)(Native Function)登記到VM里,以便能加快后續(xù)呼叫本地函數(shù)之效率。

    JNI_OnUnload()函數(shù)JNI_OnLoad()相對(duì)應(yīng)的。在加載C組件時(shí)會(huì)立即呼叫JNI_OnLoad()來(lái)進(jìn)行組件內(nèi)的初期動(dòng)作;而當(dāng)VM釋放該C組件時(shí),則會(huì)呼叫JNI_OnUnload()函數(shù)來(lái)進(jìn)行善后清除動(dòng)作。當(dāng)VM呼叫JNI_OnLoad()JNI_Unload()函數(shù)時(shí),都會(huì)將VM的指標(biāo)(Pointer)傳遞給它們,其參數(shù)如下:

 

jint JNI_OnLoad(JavaVM* vm, void* reserved)

{

      ………

}

 

jint JNI_OnUnload(JavaVM* vm, void* reserved)

{

      ………

}

 

JNI_OnLoad()函數(shù)里,就透過(guò)VM之指標(biāo)而取得JNIEnv之指標(biāo)值,并存入env指針變量里,如下述指令:

 

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;

    }

 

    由于VM通常是多執(zhí)行緒(Multi-threading)的執(zhí)行環(huán)境。每一個(gè)執(zhí)行緒在呼叫JNI_OnLoad()時(shí),所傳遞進(jìn)來(lái)的JNIEnv指標(biāo)值都是不同的。為了配合這種多執(zhí)行緒的環(huán)境,C組件開發(fā)者在撰寫本地函數(shù)時(shí),可藉由JNIEnv指標(biāo)值之不同而避免執(zhí)行緒的數(shù)據(jù)沖突問(wèn)題,才能確保所寫的本地函數(shù)能安全地在Android多執(zhí)行緒VM 里安全地執(zhí)行?;谶@個(gè)理由,當(dāng)在呼叫C組件的函數(shù)時(shí),都會(huì)將JNIEnv指標(biāo)值傳遞給它,如下:

jint JNI_OnLoad(JavaVM* vm, void* reserved)

{

JNIEnv* env = NULL;

  ……….

    if (register_android_media_MediaPlayer(env) < 0) {

       …….

    }

     }

JNI_OnLoad()呼叫register_android_media_MediaPlayer(env)函數(shù)時(shí),就將env指標(biāo)值傳遞過(guò)去。如此,在register_android_media_MediaPlayer()函數(shù)就能藉由該指標(biāo)值而區(qū)別不同的執(zhí)行緒,以便化解數(shù)據(jù)沖突的問(wèn)題。

      例如,在register_android_media_MediaPlayer()函數(shù)里,可撰寫下述指令:

        if ((*env)->MonitorEnter(env, obj) != JNI_OK) {

             ………

 }

 

    查看是否已經(jīng)有其它執(zhí)行緒進(jìn)入此對(duì)象,如果沒(méi)有,此執(zhí)行緒就進(jìn)入該對(duì)象里執(zhí)行了。還有,也可撰寫下述指令:

 

         if ((*env)->MonitorExit(env, obj) != JNI_OK) {

              ………

          }

 

查看是否此執(zhí)行緒正在此對(duì)象內(nèi)執(zhí)行,如果是,此執(zhí)行緒就會(huì)立即離開。

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多