聲明
前階段在項(xiàng)目中使用了Android的JNI技術(shù),在此文中做些技術(shù)知識(shí)總結(jié)。 本文參考了一些書籍的若干章節(jié),比如《Android進(jìn)階解密-第9章-JNI原理》、《深入理解Android虛擬機(jī)-第4章-分析JNI》、《深入理解Android系統(tǒng)-第2章-分析JNI》、《Android NDK Beginner_'s Guide》等 本文使用的代碼時(shí)LineageOS的cm-14.1,對(duì)應(yīng)Android 7.1.2,可以參考我的另一篇博客:cm-14.1 Android系統(tǒng)啟動(dòng)過(guò)程分析(〇)-如何下載Nexus5的LineageOS14.1(cm-14.1)系統(tǒng)源碼并編譯、刷機(jī)
1 Java層和JNI層的數(shù)據(jù)類型轉(zhuǎn)換
????進(jìn)入到源碼路徑: vim ~/LineageOS/frameworks/base/media/jni/android_ media_MediaRecorder.cpp,查看函數(shù)android_media_MediaRecorder_native_setup:
static void
android_media_MediaRecorder_native_setup ( JNIEnv
* env
, jobject thiz
, jobject weak_this
, jstring packageName
, jstring opPackageName
)
{ ALOGV ( "setup" ) ; ScopedUtfChars
opPackageNameStr ( env
, opPackageName
) ; sp
< MediaRecorder
> mr
= new MediaRecorder ( String16 ( opPackageNameStr
. c_str ( ) ) ) ; if ( mr
== NULL ) { jniThrowException ( env
, "java/lang/RuntimeException" , "Out of memory" ) ; return ; } if ( mr
- > initCheck ( ) != NO_ERROR
) { jniThrowException ( env
, "java/lang/RuntimeException" , "Unable to initialize media recorder" ) ; return ; } sp
< JNIMediaRecorderListener
> listener
= new JNIMediaRecorderListener ( env
, thiz
, weak_this
) ; mr
- > setListener ( listener
) ; const char16_t * rawClientName
= reinterpret_cast < const char16_t * > ( env
- > GetStringChars ( packageName
, NULL ) ) ; jsize rawClientNameLen
= env
- > GetStringLength ( packageName
) ; String16
clientName ( rawClientName
, rawClientNameLen
) ; env
- > ReleaseStringChars ( packageName
, reinterpret_cast < const jchar
* > ( rawClientName
) ) ; mr
- > setClientName ( clientName
) ; setMediaRecorder ( env
, thiz
, mr
) ;
}
????其中jobject、jstring類型參數(shù)都是JNI層的數(shù)據(jù)類型,Java層數(shù)據(jù)類型到JNI層就要轉(zhuǎn)換為JNI層數(shù)據(jù)結(jié)構(gòu)。包括基本數(shù)據(jù)類型 和引用數(shù)據(jù)類型
1.1 Java層至JNI層基本數(shù)據(jù)類型的轉(zhuǎn)換
Java類型JNI類型C++類型關(guān)系描述簽名占內(nèi)存大小 boolean jboolean unsigned char 或 unit8_t 布爾類型 Z 1 int jint int或long 整形 I 4 float jfloat float 單精度類型 F 4 double jdouble double 雙精度類型 D 8 long jlong long 長(zhǎng)整形 J 8 short jshort short 短整型 S 2 char jchar unsigned short 字符 C 2 byte jbyte signed char 字節(jié)類型 B 1 void void void 空類型 V
????從轉(zhuǎn)換表中可以看出Java層基本數(shù)據(jù)類型轉(zhuǎn)換到JNI層只需將數(shù)據(jù)類型前加個(gè)“j”即可(除了void類型)。
1.2 Java層至JNI層引用數(shù)據(jù)類型的轉(zhuǎn)換
JavaNative簽名(以;結(jié)尾) 所有對(duì)象 jobject L+classname +; Class jclass Ljava/lang/Clas; String jstring Ljava/lang/String; Trowable jthrowable Ljava/lang/Throwable; Object[] jobjectArray [L+classname +; byte[] jbyteArray [B char[] jcharArray [C double[] jdoubleArray [D float[] jfloatArray [F int[] jintArray [I short[] jshortArray [S long[] jlongArray [J boolean[] jbooleanArray [Z
????以~/LineageOS/frameworks/base/media/java/android/media/ MediaRecorder.java中的native_setup方法為例:
private native final
void native_setup ( Object mediarecorder_this
, String clientName
, String opPackageName
) throws IllegalStateException
;
????對(duì)應(yīng)在~/LineageOS/frameworks/base/media/jni/android_ media_MediaRecorder.cpp,查看函數(shù)android_media_MediaRecorder_native_setup:
static void
android_media_MediaRecorder_native_setup ( JNIEnv
* env
, jobject thiz
, jobject weak_this
, jstring packageName
, jstring opPackageName
)
{
. . . 省略n行
. . .
}
????可以發(fā)現(xiàn):Object類型轉(zhuǎn)換為jobject類型,String類型轉(zhuǎn)換為jstring類型。
2 方法簽名
????進(jìn)入到源碼路徑: vim ~/LineageOS/frameworks/base/media/jni/ android_media_MediaRecorder.cpp,在數(shù)組gMethods[]中可看到簽名信息:
static const JNINativeMethod gMethods
[ ] = { { "setCamera" , "(Landroid/hardware/Camera;)V" , ( void * ) android_media_MediaRecorder_setCamera
} , { "setVideoSource" , "(I)V" , ( void * ) android_media_MediaRecorder_setVideoSource
} , { "setAudioSource" , "(I)V" , ( void * ) android_media_MediaRecorder_setAudioSource
} , { "setOutputFormat" , "(I)V" , ( void * ) android_media_MediaRecorder_setOutputFormat
} , { "setVideoEncoder" , "(I)V" , ( void * ) android_media_MediaRecorder_setVideoEncoder
} , { "setAudioEncoder" , "(I)V" , ( void * ) android_media_MediaRecorder_setAudioEncoder
} , { "setParameter" , "(Ljava/lang/String;)V" , ( void * ) android_media_MediaRecorder_setParameter
} , { "_setOutputFile" , "(Ljava/io/FileDescriptor;JJ)V" , ( void * ) android_media_MediaRecorder_setOutputFileFD
} , { "setVideoSize" , "(II)V" , ( void * ) android_media_MediaRecorder_setVideoSize
} , { "setVideoFrameRate" , "(I)V" , ( void * ) android_media_MediaRecorder_setVideoFrameRate
} , { "setMaxDuration" , "(I)V" , ( void * ) android_media_MediaRecorder_setMaxDuration
} , { "setMaxFileSize" , "(J)V" , ( void * ) android_media_MediaRecorder_setMaxFileSize
} , { "_prepare" , "()V" , ( void * ) android_media_MediaRecorder_prepare
} , { "getSurface" , "()Landroid/view/Surface;" , ( void * ) android_media_MediaRecorder_getSurface
} , { "getMaxAmplitude" , "()I" , ( void * ) android_media_MediaRecorder_native_getMaxAmplitude
} , { "start" , "()V" , ( void * ) android_media_MediaRecorder_start
} , { "stop" , "()V" , ( void * ) android_media_MediaRecorder_stop
} , { "pause" , "()V" , ( void * ) android_media_MediaRecorder_pause
} , { "resume" , "()V" , ( void * ) android_media_MediaRecorder_resume
} , { "native_reset" , "()V" , ( void * ) android_media_MediaRecorder_native_reset
} , { "release" , "()V" , ( void * ) android_media_MediaRecorder_release
} , { "native_init" , "()V" , ( void * ) android_media_MediaRecorder_native_init
} , { "native_setup" , "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V" , ( void * ) android_media_MediaRecorder_native_setup
} , { "native_finalize" , "()V" , ( void * ) android_media_MediaRecorder_native_finalize
} , { "native_setInputSurface" , "(Landroid/view/Surface;)V" , ( void * ) android_media_MediaRecorder_setInputSurface
} ,
} ;
????簡(jiǎn)單地說(shuō),存在簽名的原因就是Java語(yǔ)言的方法是可以重載的 ,重載的方法名字相同而參數(shù)不同,所以JNI僅通過(guò)方法名無(wú)法確定對(duì)應(yīng)的是重載的哪個(gè)方法,必須要參數(shù)簽名來(lái)輔助其關(guān)聯(lián)。
避免博客拖太長(zhǎng),后續(xù)參見(jiàn)下篇Android系統(tǒng)的JNI原理分析(三)- JNIEnv
總結(jié)
以上是生活随笔 為你收集整理的Android系统的JNI原理分析(二)- 数据类型转换和方法签名 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。