<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Android JNI原理分析

          共 10510字,需瀏覽 22分鐘

           ·

          2022-05-26 15:46

          原文鏈接: http://gityuan.com/2016/05/28/android-jni/

          引言:分析Android源碼6.0的過(guò)程,一定離不開(kāi)Java與C/C++代碼直接的來(lái)回跳轉(zhuǎn),那么就很有必要掌握J(rèn)NI,這是鏈接Java層和Native層的橋梁,本文涉及相關(guān)源碼:

          frameworks/base/core/jni/AndroidRuntime.cpp

          libcore/luni/src/main/java/java/lang/System.java
          libcore/luni/src/main/java/java/lang/Runtime.java
          libnativehelper/JNIHelp.cpp
          libnativehelper/include/nativehelper/jni.h

          frameworks/base/core/java/android/os/MessageQueue.java
          frameworks/base/core/jni/android_os_MessageQueue.cpp

          frameworks/base/core/java/android/os/Binder.java
          frameworks/base/core/jni/android_util_Binder.cpp

          frameworks/base/media/java/android/media/MediaPlayer.java
          frameworks/base/media/jni/android_media_MediaPlayer.cpp

          一、JNI概述

          JNI(Java Native Interface,Java本地接口),用于打通Java層與Native(C/C++)層。這不是Android系統(tǒng)所獨(dú)有的,而是Java所有。眾所周知,Java語(yǔ)言是跨平臺(tái)的語(yǔ)言,而這跨平臺(tái)的背后都是依靠Java虛擬機(jī),虛擬機(jī)采用C/C++編寫(xiě),適配各個(gè)系統(tǒng),通過(guò)JNI為上層Java提供各種服務(wù),保證跨平臺(tái)性。

          相信不少經(jīng)常使用Java的程序員,享受著其跨平臺(tái)性,可能全然不知JNI的存在。在Android平臺(tái),讓JNI大放異彩,為更多的程序員所熟知,往往為了提供效率或者其他功能需求,就需要NDK開(kāi)發(fā)。上一篇文章Linux系統(tǒng)調(diào)用(syscall)原理,介紹了打通android上層與底層kernel的樞紐syscall,那么本文的目的則是介紹打通android上層中Java層與Native的紐帶JNI。

          二、JNI查找方式

          Android系統(tǒng)在啟動(dòng)啟動(dòng)過(guò)程中,先啟動(dòng)Kernel創(chuàng)建init進(jìn)程,緊接著由init進(jìn)程fork第一個(gè)橫穿Java和C/C++的進(jìn)程,即Zygote進(jìn)程。Zygote啟動(dòng)過(guò)程中會(huì)AndroidRuntime.cpp中的startVm創(chuàng)建虛擬機(jī),VM創(chuàng)建完成后,緊接著調(diào)用startReg完成虛擬機(jī)中的JNI方法注冊(cè)。

          2.1 startReg

          [–>AndroidRuntime.cpp]

          int?AndroidRuntime::startReg(JNIEnv*?env)
          {
          ????//設(shè)置線程創(chuàng)建方法為javaCreateThreadEtc
          ????androidSetCreateThreadFunc((android_create_thread_fn)?javaCreateThreadEtc);

          ????env->PushLocalFrame(200);
          ????//進(jìn)程JNI方法的注冊(cè)
          ????if?(register_jni_procs(gRegJNI,?NELEM(gRegJNI),?env)?0)?{
          ????????env->PopLocalFrame(NULL);
          ????????return?-1;
          ????}
          ????env->PopLocalFrame(NULL);
          ????return?0;
          }

          register_jni_procs(gRegJNI, NELEM(gRegJNI), env)這行代碼的作用就是就是循環(huán)調(diào)用gRegJNI數(shù)組成員所對(duì)應(yīng)的方法。

          static?int?register_jni_procs(const?RegJNIRec?array[],?size_t?count,?JNIEnv*?env)
          {
          ????for?(size_t?i?=?0;?i?????????if?(array[i].mProc(env)?0)?{
          ????????????return?-1;
          ????????}
          ????}
          ????return?0;
          }

          gRegJNI數(shù)組,有100多個(gè)成員變量,定義在AndroidRuntime.cpp

          static?const?RegJNIRec?gRegJNI[]?=?{
          ????REG_JNI(register_android_os_MessageQueue),
          ????REG_JNI(register_android_os_Binder),
          ????...
          };

          該數(shù)組的每個(gè)成員都代表一個(gè)類文件的jni映射,其中REG_JNI是一個(gè)宏定義,在Zygote中介紹過(guò),該宏的作用就是調(diào)用相應(yīng)的方法。

          2.2 如何查找native方法

          當(dāng)大家在看framework層代碼時(shí),經(jīng)常會(huì)看到native方法,這是往往需要查看所對(duì)應(yīng)的C++方法在哪個(gè)文件,對(duì)應(yīng)哪個(gè)方法?下面從一個(gè)實(shí)例出發(fā)帶大家如何查看java層方法所對(duì)應(yīng)的native方法位置。

          2.2.1 實(shí)例(一)

          當(dāng)分析Android消息機(jī)制源碼,遇到MessageQueue.java中有多個(gè)native方法,比如:

          package?android.os;
          public?final?class?MessageQueue?{
          ????private?native?void?nativePollOnce(long?ptr,?int?timeoutMillis);
          }

          步驟1: MessageQueue.java的全限定名為android.os.MessageQueue.java,完整的方法名為android.os.MessageQueue.nativePollOnce(),與之相對(duì)應(yīng)的native層方法名是將點(diǎn)號(hào)替換為下劃線,即android_os_MessageQueue_nativePollOnce()。

          步驟2: 有了native方法,那么接下來(lái)需要知道該native方法所在那個(gè)文件。前面已經(jīng)介紹過(guò)Android系統(tǒng)啟動(dòng)時(shí)就已經(jīng)注冊(cè)了大量的JNI方法,見(jiàn)AndroidRuntime.cpp的gRegJNI數(shù)組。這些注冊(cè)方法命令方式:

          那么MessageQueue.java所定義的jni注冊(cè)方法名應(yīng)該是register_android_os_MessageQueue,的確存在于gRegJNI數(shù)組,說(shuō)明這次JNI注冊(cè)過(guò)程是在開(kāi)機(jī)過(guò)程完成。該方法在AndroidRuntime.cpp申明為extern方法:

          extern?int?register_android_os_MessageQueue(JNIEnv*?env);

          這些extern方法絕大多數(shù)位于/framework/base/core/jni/目錄,大多數(shù)情況下native文件命名方式:

          [包名]_[類名].cpp
          [包名]_[類名].h

          Tips: /android/os路徑下的MessageQueue.java ==> android_os_MessageQueue.cpp

          打開(kāi)android_os_MessageQueue.cpp文件,搜索android_os_MessageQueue_nativePollOnce方法,這便找到了目標(biāo)方法:

          static?void?android_os_MessageQueue_nativePollOnce(JNIEnv*?env,?jobject?obj,
          ????????jlong?ptr,?jint?timeoutMillis)
          ?
          {
          ????NativeMessageQueue*?nativeMessageQueue?=?reinterpret_cast(ptr);
          ????nativeMessageQueue->pollOnce(env,?obj,?timeoutMillis);
          }

          到這里完成了一次從Java層方法搜索到所對(duì)應(yīng)的C++方法的過(guò)程。

          2.2.2 實(shí)例(二)

          對(duì)于native文件命名方式,有時(shí)并非[包名]_[類名].cpp,比如/android/os路徑下的Binder.java 所對(duì)應(yīng)的native文件:android_util_Binder.cpp

          package?android.os;
          public?class?Binder?implements?IBinder?{
          ????public?static?final?native?int?getCallingPid();
          }

          根據(jù)實(shí)例(一)方式,找到getCallingPid ==> android_os_Binder_getCallingPid(),并且在AndroidRuntime.cpp中的gRegJNI數(shù)組中找到register_android_os_Binder。

          按實(shí)例(一)方式則native文名應(yīng)該為android_os_Binder.cpp,可是在/framework/base/core/jni/目錄下找不到該文件,這是例外的情況。其實(shí)真正的文件名為android_util_Binder.cpp,這就是例外,這一點(diǎn)有些費(fèi)勁,不明白為何google要如此打破規(guī)律的命名。

          static?jint?android_os_Binder_getCallingPid(JNIEnv*?env,?jobject?clazz)
          {
          ????return?IPCThreadState::self()->getCallingPid();
          }

          有人可能好奇,既然如何遇到打破常規(guī)的文件命令,怎么辦?這個(gè)并不難,首先,可以嘗試在/framework/base/core/jni/中搜索,對(duì)于binder.java,可以直接搜索binder關(guān)鍵字,其他也類似。如果這里也找不到,可以通過(guò)grep全局搜索android_os_Binder_getCallingPid這個(gè)方法在哪個(gè)文件。

          jni存在的常見(jiàn)目錄:

          • /framework/base/core/jni/

          • /framework/base/services/core/jni/

          • /framework/base/media/jni/

          2.2.3 實(shí)例(三)

          前面兩種都是在Android系統(tǒng)啟動(dòng)之初,便已經(jīng)注冊(cè)過(guò)JNI所對(duì)應(yīng)的方法。那么如果程序自己定義的jni方法,該如何查看jni方法所在位置呢?下面以MediaPlayer.java為例,其包名為android.media:

          public?class?MediaPlayer{
          ????static?{
          ????????System.loadLibrary("media_jni");
          ????????native_init();
          ????}

          ????private?static?native?final?void?native_init();
          ????...
          }

          通過(guò)static靜態(tài)代碼塊中System.loadLibrary方法來(lái)加載動(dòng)態(tài)庫(kù),庫(kù)名為media_jni, Android平臺(tái)則會(huì)自動(dòng)擴(kuò)展成所對(duì)應(yīng)的libmedia_jni.so庫(kù)。接著通過(guò)關(guān)鍵字native加在native_init方法之前,便可以在java層直接使用native層方法。

          接下來(lái)便要查看libmedia_jni.so庫(kù)定義所在文件,一般都是通過(guò)Android.mk文件定義LOCAL_MODULE:= libmedia_jni,可以采用grep或者mgrep來(lái)搜索包含libmedia_jni字段的Android.mk所在路徑。

          搜索可知,libmedia_jni.so位于/frameworks/base/media/jni/Android.mk。用前面實(shí)例(一)中的知識(shí)來(lái)查看相應(yīng)的文件和方法名分別為:

          android_media_MediaPlayer.cpp
          android_media_MediaPlayer_native_init()

          再然后,你會(huì)發(fā)現(xiàn)果然在該Android.mk所在目錄/frameworks/base/media/jni/中找到android_media_MediaPlayer.cpp文件,并在文件中存在相應(yīng)的方法:

          ??static?void
          android_media_MediaPlayer_native_init(JNIEnv?*env)
          {
          ????jclass?clazz;
          ????clazz?=?env->FindClass("android/media/MediaPlayer");
          ????fields.context?=?env->GetFieldID(clazz,?"mNativeContext",?"J");
          ????...
          }

          Tips:MediaPlayer.java中的native_init方法所對(duì)應(yīng)的native方法位于/frameworks/base/media/jni/目錄下的android_media_MediaPlayer.cpp文件中的android_media_MediaPlayer_native_init方法。

          2.3 小結(jié)

          JNI作為連接Java世界和C/C++世界的橋梁,很有必要掌握??赐瓯疚?,至少能掌握在分析Android源碼過(guò)程中如何查找native方法。首先要明白native方法名和文件名的命名規(guī)律,其次要懂得該如何去搜索代碼。

          JNI注冊(cè)的兩種時(shí)機(jī):

          • Android系統(tǒng)啟動(dòng)過(guò)程中Zygote注冊(cè),可通過(guò)查詢AndroidRuntime.cpp中的gRegJNI,看看是否存在對(duì)應(yīng)的register方法;

          • 調(diào)用System.loadLibrary()方式注冊(cè)。

          三、 JNI原理分析

          再進(jìn)一步來(lái)分析,Java層與Native層方法是如何注冊(cè)并映射的,以MediaPlayer為例。文件MediaPlayer.java中調(diào)用System.loadLibrary(“media_jni”),把libmedia_jni.so動(dòng)態(tài)庫(kù)加載到內(nèi)存。以loadLibrary為起點(diǎn)展開(kāi)JNI注冊(cè)流程的過(guò)程分析。

          3.1 loadLibrary

          [System.java]

          public?static?void?loadLibrary(String?libName)?{
          ????//調(diào)用Runtime方法
          ????Runtime.getRuntime().loadLibrary(libName,?VMStack.getCallingClassLoader());
          }

          [Runtime.java]

          void?loadLibrary(String?libraryName,?ClassLoader?loader)?{
          ????if?(loader?!=?null)?{
          ????????String?filename?=?loader.findLibrary(libraryName);
          ????????//加載庫(kù)【見(jiàn)小節(jié)3.2】
          ????????String?error?=?doLoad(filename,?loader);
          ????????if?(error?!=?null)?{
          ????????????throw?new?UnsatisfiedLinkError(error);
          ????????}
          ????????return;
          ????}

          ????//loader為空,則會(huì)進(jìn)入該分支
          ????String?filename?=?System.mapLibraryName(libraryName);
          ????List<String>?candidates?=?new?ArrayList<String>();
          ????for?(String?directory?:?mLibPaths)?{
          ????????String?candidate?=?directory?+?filename;
          ????????candidates.add(candidate);
          ????????if?(IoUtils.canOpenReadOnly(candidate))?{
          ?????????????//加載庫(kù)【見(jiàn)小節(jié)3.2】
          ????????????String?error?=?doLoad(candidate,?loader);
          ????????????if?(error?==?null)?{
          ????????????????return;?//加載成功
          ????????????}
          ????????}
          ????}
          ????...
          }

          真正加載的工作是由doLoad(),更多詳情見(jiàn)loadLibrary動(dòng)態(tài)庫(kù)加載過(guò)程分析。

          3.2 doLoad

          該方法內(nèi)部增加同步鎖,保證并發(fā)時(shí)一致性。

          private?String?doLoad(String?name,?ClassLoader?loader)?{
          ????...
          ????synchronized?(this)?{
          ????????return?nativeLoad(name,?loader,?ldLibraryPath);
          ????}
          }

          nativeLoad()這是一個(gè)native方法,再進(jìn)入ART虛擬機(jī)的java_lang_Runtime.cc,最終的核心功能工作:

          • 調(diào)用dlopen函數(shù),打開(kāi)一個(gè)so文件并創(chuàng)建一個(gè)handle;

          • 調(diào)用dlsym()函數(shù),查看相應(yīng)so文件的JNI_OnLoad()函數(shù)指針,并執(zhí)行相應(yīng)函數(shù)。

          總之,System.loadLibrary()的作用就是調(diào)用相應(yīng)庫(kù)中的JNI_OnLoad()方法。接下來(lái)說(shuō)說(shuō)JNI_OnLoad()過(guò)程。

          3.2 JNI_OnLoad

          [-> android_media_MediaPlayer.cpp]

          jint?JNI_OnLoad(JavaVM*?vm,?void*?reserved)
          {
          ????JNIEnv*?env?=?NULL;
          ????//【見(jiàn)3.3】?注冊(cè)JNI方法
          ????if?(register_android_media_MediaPlayer(env)?0)?{
          ????????goto?bail;
          ????}
          ????...
          }

          3.3 register_android_media_MediaPlayer

          [-> android_media_MediaPlayer.cpp]

          static?int?register_android_media_MediaPlayer(JNIEnv?*env)
          {
          ????//【見(jiàn)3.4】
          ????return?AndroidRuntime::registerNativeMethods(env,
          ????????????????"android/media/MediaPlayer",?gMethods,?NELEM(gMethods));
          }

          其中gMethods,記錄java層和C/C++層方法的一一映射關(guān)系。

          static?JNINativeMethod?gMethods[]?=?{
          ????{"prepare",??????"()V",??(void?*)android_media_MediaPlayer_prepare},
          ????{"_start",???????"()V",??(void?*)android_media_MediaPlayer_start},
          ????{"_stop",????????"()V",??(void?*)android_media_MediaPlayer_stop},
          ????{"seekTo",???????"(I)V",?(void?*)android_media_MediaPlayer_seekTo},
          ????{"_release",?????"()V",??(void?*)android_media_MediaPlayer_release},
          ????{"native_init",??"()V",??(void?*)android_media_MediaPlayer_native_init},
          ????...
          };

          這里涉及到結(jié)構(gòu)體JNINativeMethod,其定義在jni.h文件:

          typedef?struct?{
          ????const?char*?name;??//Java層native函數(shù)名
          ????const?char*?signature;?//Java函數(shù)簽名,記錄參數(shù)類型和個(gè)數(shù),以及返回值類型
          ????void*???????fnPtr;?//Native層對(duì)應(yīng)的函數(shù)指針
          }?JNINativeMethod;

          關(guān)于函數(shù)簽名signature在下一小節(jié)展開(kāi)說(shuō)明。

          3.4 registerNativeMethods

          [-> AndroidRuntime.cpp]

          int?AndroidRuntime::registerNativeMethods(JNIEnv*?env,
          ????const?char*?className,?const?JNINativeMethod*?gMethods,?int?numMethods)
          {
          ????//【見(jiàn)3.5】
          ????return?jniRegisterNativeMethods(env,?className,?gMethods,?numMethods);
          }

          jniRegisterNativeMethods該方法是由Android JNI幫助類JNIHelp.cpp來(lái)完成。

          3.5 jniRegisterNativeMethods

          [-> JNIHelp.cpp]

          extern?"C"?int?jniRegisterNativeMethods(C_JNIEnv*?env,?const?char*?className,
          ????const?JNINativeMethod*?gMethods,?int?numMethods)

          {
          ????JNIEnv*?e?=?reinterpret_cast(env);
          ????scoped_local_ref?c(env,?findClass(env,?className));
          ????if?(c.get()?==?NULL)?{
          ????????e->FatalError("");//無(wú)法查找native注冊(cè)方法
          ????}
          ????//【見(jiàn)3.6】?調(diào)用JNIEnv結(jié)構(gòu)體的成員變量
          ????if?((*env)->RegisterNatives(e,?c.get(),?gMethods,?numMethods)?0)?{
          ????????e->FatalError("");//native方法注冊(cè)失敗
          ????}
          ????return?0;
          }

          3.6 RegisterNatives

          [-> jni.h]

          struct?_JNIEnv?{
          ????const?struct?JNINativeInterface*?functions;

          ????jint?RegisterNatives(jclass?clazz,?const?JNINativeMethod*?methods,
          ????????????jint?nMethods)

          ????
          {?return?functions->RegisterNatives(this,?clazz,?methods,?nMethods);?}
          ????...
          }

          functions是指向JNINativeInterface結(jié)構(gòu)體指針,也就是將調(diào)用下面方法:

          struct?JNINativeInterface?{
          ????jint?(*RegisterNatives)(JNIEnv*,?jclass,?const?JNINativeMethod*,jint);
          ????...
          }

          再往下深入就到了虛擬機(jī)內(nèi)部吧,這里就不再往下深入了??傊@個(gè)過(guò)程完成了gMethods數(shù)組中的方法的映射關(guān)系,比如java層的native_init()方法,映射到native層的android_media_MediaPlayer_native_init()方法。

          虛擬機(jī)相關(guān)的變量中有兩個(gè)非常重要的量JavaVM和JNIEnv:

          • JavaVM:是指進(jìn)程虛擬機(jī)環(huán)境,每個(gè)進(jìn)程有且只有一個(gè)JavaVM實(shí)例

          • JNIEnv:是指線程上下文環(huán)境,每個(gè)線程有且只有一個(gè)JNIEnv實(shí)例,

          四、JNI資源

          JNINativeMethod結(jié)構(gòu)體中有一個(gè)字段為signature(簽名),再介紹signature格式之前需要掌握各種數(shù)據(jù)類型在Java層、Native層以及簽名所采用的簽名格式。

          4.1 數(shù)據(jù)簽名

          4.1.1 基本數(shù)據(jù)類型

          Signature格式JavaNative
          Bbytejbyte
          Ccharjchar
          Ddoublejdouble
          Ffloatjfloat
          Iintjint
          Sshortjshort
          Jlongjlong
          Zbooleanjboolean
          Vvoidvoid

          4.1.2 數(shù)組數(shù)據(jù)類型

          數(shù)組簡(jiǎn)稱則是在前面添加[

          Signature格式JavaNative
          [Bbyte[]jbyteArray
          [Cchar[]jcharArray
          [Ddouble[]jdoubleArray
          [Ffloat[]jfloatArray
          [Iint[]jintArray
          [Sshort[]jshortArray
          [Jlong[]jlongArray
          [Zboolean[]jbooleanArray

          4.1.3 復(fù)雜數(shù)據(jù)類型

          對(duì)象類型簡(jiǎn)稱:L+classname +;

          Signature格式JavaNative
          Ljava/lang/String;Stringjstring
          L+classname +;所有對(duì)象jobject
          [L+classname +;Object[]jobjectArray
          Ljava.lang.Class;Classjclass
          Ljava.lang.Throwable;Throwablejthrowable

          4.1.4 Signature

          有了前面的鋪墊,那么再來(lái)通過(guò)實(shí)例說(shuō)說(shuō)函數(shù)簽名:(輸入?yún)?shù)...)返回值參數(shù),這里用到的便是前面介紹的Signature格式。

          Java函數(shù)對(duì)應(yīng)的簽名
          void foo()()V
          float foo(int i)(I)F
          long foo(int[] i)([I)J
          double foo(Class c)(Ljava/lang/Class;)D
          boolean foo(int[] i,String s)([ILjava/lang/String;)Z
          String foo(int i)(I)Ljava/lang/String;

          4.2 其他

          (一)垃圾回收 對(duì)于Java開(kāi)發(fā)人員來(lái)說(shuō)無(wú)需關(guān)系垃圾回收,完全由虛擬機(jī)GC來(lái)負(fù)責(zé)垃圾回收,而對(duì)于JNI開(kāi)發(fā)人員,對(duì)于內(nèi)存釋放需要謹(jǐn)慎處理,需要的時(shí)候申請(qǐng),使用完記得釋放內(nèi)容,以免發(fā)生內(nèi)存泄露。在JNI提供了三種Reference類型,Local Reference(本地引用), Global Reference(全局引用), Weak Global Reference(全局弱引用)。其中Global Reference如果不主動(dòng)釋放,則一直不會(huì)釋放;對(duì)于其他兩個(gè)類型的引用都是釋放的可能性,那是不是意味著不需要手動(dòng)釋放呢?答案是否定的,不管是這三種類型的那種引用,都盡可能在某個(gè)內(nèi)存不再需要時(shí),立即釋放,這對(duì)系統(tǒng)更為安全可靠,以減少不可預(yù)知的性能與穩(wěn)定性問(wèn)題。

          另外,ART虛擬機(jī)在GC算法有所優(yōu)化,為了減少內(nèi)存碎片化問(wèn)題,在GC之后有可能會(huì)移動(dòng)對(duì)象內(nèi)存的位置,對(duì)于Java層程序并沒(méi)有影響,但是對(duì)于JNI程序可要小心了,對(duì)于通過(guò)指針來(lái)直接訪問(wèn)內(nèi)存對(duì)象是,Dalvik能正確運(yùn)行的程序,ART下未必能正常運(yùn)行。

          (二)異常處理 Java層出現(xiàn)異常,虛擬機(jī)會(huì)直接拋出異常,這是需要try..catch或者繼續(xù)往外throw。但是對(duì)于JNI出現(xiàn)異常時(shí),即執(zhí)行到JNIEnv中某個(gè)函數(shù)異常時(shí),并不會(huì)立即拋出異常來(lái)中斷程序的執(zhí)行,還可以繼續(xù)執(zhí)行內(nèi)存之類的清理工作,直到返回到Java層時(shí)才會(huì)拋出相應(yīng)的異常。

          另外,Dalvik虛擬機(jī)有些情況下JNI函數(shù)出錯(cuò)可能返回NULL,但ART虛擬機(jī)在出錯(cuò)時(shí)更多的是拋出異常。這樣導(dǎo)致的問(wèn)題就可能是在Dalvik版本能正常運(yùn)行的程序,在ART虛擬機(jī)上由于沒(méi)有正確處理異常而崩潰。

          總結(jié)

          本文主要通過(guò)實(shí)例,在源碼視角分析JNI原理,講述JNI核心功能:

          • 介紹如何查找JNI方法,明白如何從Java層跳轉(zhuǎn)到Native層;

          • 分析JNI函數(shù)注冊(cè)流程,核心是通過(guò)JNIEnv的RegisterNatives()方法來(lái)完成注冊(cè);

          • 列舉Java與native以及函數(shù)簽名方式。

          jni存在的常見(jiàn)目錄:

          • /framework/base/core/jni/

          • /framework/base/services/core/jni/

          • /framework/base/media/jni/


          微信公眾號(hào) Gityuan | 微博 weibo.com/gityuan | 博客 留言區(qū)交流


          推薦閱讀:

          NDK | 帶你梳理 JNI 函數(shù)注冊(cè)的方式和時(shí)機(jī)

          Android NDK 開(kāi)發(fā):JNI 基礎(chǔ)篇

          Android NDK 開(kāi)發(fā):Java 與 Native 相互調(diào)用

          Android NDK POSIX 多線程編程

          NDK 開(kāi)發(fā)中 Native 方法的靜態(tài)注冊(cè)與動(dòng)態(tài)注冊(cè)

          Android NDK 開(kāi)發(fā)中快速定位 Crash 問(wèn)題

          Android JNI 中發(fā)送 Http 網(wǎng)絡(luò)請(qǐng)求

          Android ?NDK 減少 so 庫(kù)體積方法總結(jié)

          Android 引用三方庫(kù)導(dǎo)致 so 庫(kù)沖突的解決辦法

          瀏覽 54
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  啪啪啪网站免费看 | 香蕉视频偷拍 | 特级学生妹黄色一级片 | 青娱乐青青草视频 | 日韩一级电影在线 |