Android JNI(实现自己的JNI_OnLoad函数)

举报
ShaderJoy 发表于 2022/01/12 00:43:12 2022/01/12
【摘要】 简单的Jni 例子都是映射模式,及对应的Jni 的c/c++ 实现需要,被java的函数命名规则限制死,为了解决这类毛病,引入的JNI_OnLoad这类方法。 jint JNI_OnLoad(JavaVM* vm, void* reserved) 该方法在Jni so 被加载时调用。该方法告诉VM此C组件使用高级的JNI版本。如果你的...

简单的Jni 例子都是映射模式,及对应的Jni 的c/c++ 实现需要,被java的函数命名规则限制死,为了解决这类毛病,引入的JNI_OnLoad这类方法。
jint JNI_OnLoad(JavaVM* vm, void* reserved)
该方法在Jni so 被加载时调用。该方法告诉VM此C组件使用高级的JNI版本。如果你的*.so文件没有使用JNI_OnLoad()函数,VM会默认该*.so是使用最老的JNI1.1版本。新版的JNI做了许多的扩充,如果需要使用新版的功能,如JNI 1.4 java.nio.ByteBuffer,就必须藉由JNI_OnLoad()函数来告知VM.


转载自:http://blog.csdn.net/zhenyongyuan123/archive/2010/09/03/5862054.aspx


实现JNI中本地函数注册可以两种方式: 
(1)采用默认的本地函数注册流程。 
(2)自己重写JNI_OnLoad()函数。(本文介绍)(Android中采用这种)

Java端代码:


  
  1. package com.jni;
  2. public class JavaHello {
  3. public static native String hello();
  4. static {
  5. // load library: libtest.so
  6. try {
  7. System.loadLibrary("test");
  8. } catch (UnsatisfiedLinkError ule) {
  9. System.err.println("WARNING: Could not load library!");
  10. }
  11. }
  12. public staticvoid main(String[] args) {
  13. String s = new JavaHello().hello();
  14. System.out.println(s);
  15. }
  16. }
本地C语言代码:

  
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <jni.h>
  5. #include <assert.h>
  6. JNIEXPORT jstring JNICALL native_hello(JNIEnv *env, jclass clazz)
  7. {
  8. printf("hello in c native code.\n");
  9. return (*env)->NewStringUTF(env, "hello world returned.");
  10. }
  11. #define JNIREG_CLASS "com/jni/JavaHello"//指定要注册的类
  12. /**
  13. * Table of methods associated with a single class.
  14. */
  15. static JNINativeMethod gMethods[] = {
  16. { "hello", "()Ljava/lang/String;", (void*)native_hello },//绑定
  17. };
  18. /*
  19. * Register several native methods for one class.
  20. */
  21. static int registerNativeMethods(JNIEnv* env, constchar* className,
  22. JNINativeMethod* gMethods, int numMethods)
  23. {
  24. jclass clazz;
  25. clazz = (*env)->FindClass(env, className);
  26. if (clazz == NULL) {
  27. return JNI_FALSE;
  28. }
  29. if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
  30. return JNI_FALSE;
  31. }
  32. return JNI_TRUE;
  33. }
  34. /*
  35. * Register native methods for all classes we know about.
  36. */
  37. static int registerNatives(JNIEnv* env)
  38. {
  39. if (!registerNativeMethods(env, JNIREG_CLASS, gMethods,
  40. sizeof(gMethods) / sizeof(gMethods[0])))
  41. return JNI_FALSE;
  42. return JNI_TRUE;
  43. }
  44. /*
  45. * Set some test stuff up.
  46. *
  47. * Returns the JNI version on success, -1 on failure.
  48. */
  49. JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
  50. {
  51. JNIEnv* env = NULL;
  52. jint result = -1;
  53. if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
  54. return -1;
  55. }
  56. assert(env != NULL);
  57. if (!registerNatives(env)) {//注册
  58. return -1;
  59. }
  60. /* success -- return valid version number */
  61. result = JNI_VERSION_1_4;
  62. return result;
  63. }

编译及运行流程:


Linux环境下:


1 设置三个环境变量: 
export JAVA_HOME:=/usr/lib/jvm/java-6-sun-1.6.0.15 
export JAVA_SRC_PATH:=/home/kortide/Jackey/jni/jni_onload/com/jfo 
export NATIVE_SRC_PATH:=/home/kortide/Jackey/jni/jni_onload/jni


2 编译JavaHello.java: 
javac $JAVA_SRC_PATH/JavaHello.java


3. 编译NativeHello.c,生成共享库 
gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -c -o $NATIVE_SRC_PATH/NativeHello.o  $NATIVE_SRC_PATH/NativeHello.c


gcc -fPIC -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -shared -o $NATIVE_SRC_PATH/libtest.so $NATIVE_SRC_PATH/NativeHello.o


4. 运行 
java com/jni/JavaHello


 Windows环境下:


HelloJNI_Load工程



补充:


JNI_OnUnload()函数与JNI_OnLoad()相对应的。在加载C组件时会立即呼叫JNI_OnLoad()来进行组件内的初期动作;而当VM释放该C组件时,则会呼叫JNI_OnUnload()函数来进行善后清除动作。


由于VM通常是多线程(Multi-threading)的执行环境。每一个线程在呼叫JNI_OnLoad()时,所传递进来的JNIEnv指标值都是不同的。为了配合这种多线程的环境,C组件开发者在撰写本地函数时,可藉由JNIEnv指标值之不同而避免线程的数据冲突问题,才能确保所写的本地函数能安全地在Android的多线程VM 里安全地执行。基于这个理由,当在呼叫C组件的函数时,都会将JNIEnv指标值传递给它


 认识so里的JNI_OnLoad()函数


 Android JNI 使用的数据结构JNINativeMethod详解


文章来源: panda1234lee.blog.csdn.net,作者:panda1234lee,版权归原作者所有,如需转载,请联系作者。

原文链接:panda1234lee.blog.csdn.net/article/details/8261806

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。