欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 运维知识 > Android >内容正文

Android

Android系统的JNI原理分析(二)- 数据类型转换和方法签名

发布时间:2024/1/1 Android 44 豆豆
生活随笔 收集整理的这篇文章主要介绍了 Android系统的JNI原理分析(二)- 数据类型转换和方法签名 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

声明

  • 前阶段在项目中使用了Android的JNI技术,在此文中做些技术知识总结。
  • 本文参考了一些书籍的若干章节,比如《Android进阶解密-第9章-JNI原理》、《深入理解Android虚拟机-第4章-分析JNI》、《深入理解Android系统-第2章-分析JNI》、《Android NDK Beginner_'s Guide》等
  • 本文使用的代码时LineageOS的cm-14.1,对应Android 7.1.2,可以参考我的另一篇博客:cm-14.1 Android系统启动过程分析(〇)-如何下载Nexus5的LineageOS14.1(cm-14.1)系统源码并编译、刷机

1 Java层和JNI层的数据类型转换

    进入到源码路径:
vim ~/LineageOS/frameworks/base/media/jni/android_
media_MediaRecorder.cpp,查看函数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;}// create new listener and give it to MediaRecordersp<JNIMediaRecorderListener> listener = new JNIMediaRecorderListener(env, thiz, weak_this);mr->setListener(listener);// Convert client name jstring to String16const 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));// pass client package name for permissions trackingmr->setClientName(clientName);setMediaRecorder(env, thiz, mr); }

    其中jobject、jstring类型参数都是JNI层的数据类型,Java层数据类型到JNI层就要转换为JNI层数据结构。包括基本数据类型引用数据类型

1.1 Java层至JNI层基本数据类型的转换

Java类型JNI类型C++类型关系描述签名占内存大小
booleanjbooleanunsigned char 或 unit8_t布尔类型Z1
intjintint或long整形I4
floatjfloatfloat单精度类型F4
doublejdoubledouble双精度类型D8
longjlonglong长整形J8
shortjshortshort短整型S2
charjcharunsigned short字符C2
bytejbytesigned char字节类型B1
voidvoidvoid空类型V

    从转换表中可以看出Java层基本数据类型转换到JNI层只需将数据类型前加个“j”即可(除了void类型)。

1.2 Java层至JNI层引用数据类型的转换

JavaNative签名(以;结尾)
所有对象jobjectL+classname +;
ClassjclassLjava/lang/Clas;
StringjstringLjava/lang/String;
TrowablejthrowableLjava/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;

    对应在~/LineageOS/frameworks/base/media/jni/android_
media_MediaRecorder.cpp,查看函数android_media_MediaRecorder_native_setup:

static void android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,jstring packageName, jstring opPackageName) { ...省略n行... }

    可以发现:Object类型转换为jobject类型,String类型转换为jstring类型。

2 方法签名

    进入到源码路径: vim ~/LineageOS/frameworks/base/media/jni/
android_media_MediaRecorder.cpp,在数组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 }, };

    简单地说,存在签名的原因就是Java语言的方法是可以重载的,重载的方法名字相同而参数不同,所以JNI仅通过方法名无法确定对应的是重载的哪个方法,必须要参数签名来辅助其关联。

避免博客拖太长,后续参见下篇Android系统的JNI原理分析(三)- JNIEnv

总结

以上是生活随笔为你收集整理的Android系统的JNI原理分析(二)- 数据类型转换和方法签名的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。