zoukankan      html  css  js  c++  java
  • JAVA调用C语言写的SO文件

      JAVA调用C语言写的SO文件

      因为工作需要写一份SO文件,作为手机硬件IC读卡和APK交互的桥梁,也就是中间件,看了网上有说到JNI接口技术实现,这里转载了一个实例

     1 // 用JNI实现
     2 // 实例:
     3 
     4 // 创建HelloWorld.java
     5 class HelloWorld
     6 {
     7     private native void print();
     8     public static void main(String[] args)
     9     {
    10         new HelloWorld().print();
    11     }
    12 
    13     static
    14     {
    15         System.loadLibrary("HelloWorld");
    16     }
    17 }
    18 // 注意print方法的声明,关键字native表明该方法是一个原生代码实现的。另外注意static代码段的System.loadLibrary调用,这段代码表示在程序加载的时候,自动加载libHelloWorld.so库。
    19 // 编译HelloWorld.java
    20 // 在命令行中运行如下命令:
    21 javac HelloWorld.java
    22 // 在当前文件夹编译生成HelloWorld.class。
    23 // 生成HelloWorld.h
    24 // 在命令行中运行如下命令:
    25 javah -jni HelloWorld
    26 // 在当前文件夹中会生成HelloWorld.h。打开HelloWorld.h将会发现如下代码:
    27 /* DO NOT EDIT THIS FILE - it is machine generated */
    28 #include <jni.h>
    29 /* Header for class HelloWorld */
    30 
    31 #ifndef _Included_HelloWorld
    32 #define _Included_HelloWorld
    33 #ifdef __cplusplus
    34 extern "C" {
    35 #endif
    36 /*
    37  * Class:     HelloWorld
    38  * Method:    print
    39  * Signature: ()V
    40  */
    41 JNIEXPORT void JNICALL Java_HelloWorld_print
    42 (JNIEnv *, jobject);
    43 
    44 #ifdef __cplusplus
    45 }
    46 #endif
    47 #endif
    48 // 该文件中包含了一个函数Java_HelloWorld_print的声明。这里面包含两个参数,非常重要,后面讲实现的时候会讲到。
    49 // 实现HelloWorld.c
    50 // 创建HelloWorld.c文件输入如下的代码:
    51 #include <jni.h>
    52 #include <stdio.h>
    53 #include "HelloWorld.h"
    54 
    55 JNIEXPORT void JNICALL
    56 Java_HelloWorld_print(JNIEnv *env, jobject obj)
    57 {
    58     printf("Hello World!
    ");
    59 }
    60 // 注意必须要包含jni.h头文件,该文件中定义了JNI用到的各种类型,宏定义等。
    61 // 另外需要注意Java_HelloWorld_print的两个参数,本例比较简单,不需要用到这两个参数。但是这两个参数在JNI中非常重要。
    62 // env代表java虚拟机环境,Java传过来的参数和c有很大的不同,需要调用JVM提供的接口来转换成C类型的,就是通过调用env方法来完成转换的。
    63 // obj代表调用的对象,相当于c++的this。当c函数需要改变调用对象成员变量时,可以通过操作这个对象来完成。
    64 // 编译生成libHelloWorld.so
    65 // 在Linux下执行如下命令来完成编译工作:
    66 cc -I/usr/lib/jvm/java-6-sun/include/linux/
    67 -I/usr/lib/jvm/java-6-sun/include/
    68 -fPIC -shared -o libHelloWorld.so HelloWorld.c
    69 // 在当前目录生成libHelloWorld.so。注意一定需要包含Java的include目录(请根据自己系统环境设定),因为Helloworld.c中包含了jni.h。
    70 // 另外一个值得注意的是在HelloWorld.java中我们LoadLibrary方法加载的是“HelloWorld”,可我们生成的Library却是libHelloWorld。这是Linux的链接规定的,一个库的必须要是:lib+库名+.so。链接的时候只需要提供库名就可以了。
    71 // 运行Java程序HelloWorld
    72 // 大功告成最后一步,验证前面的成果的时刻到了:
    73 java HelloWorld
    74 // 如果你这步发生问题,如果这步你收到java.lang.UnsatisfiedLinkError异常,可以通过如下方式指明共享库的路径:
    75 java -Djava.library.path='.' HelloWorld
    76 // 当然还有其他的方式可以指明路径请参考《在Linux平台下使用JNI》。
    77 // 我们可以看到久违的“Hello world!”输出了。
    View Code

      试着去完成,自己生成了一份com_test_GetMsg.h头文件,并完成test.c,生成libtest.so文件,JAVA调用SO文件时,屡次报:

    failed: Cannot load library: load_library(linker.cpp:761): not a valid ELF executable: /data/app-lib/com.example.iccommtest-libtest.so

      也就是提供的SO无法load,是valid的。

      注意,刚才引用的实例是JAVA调用SO,而我需要的是android调用SO,不然会频繁上面错误。

      原因有两点:

      1、JAVA和android的虚拟环境不一样
      2、Linux和android的系统库文件不一样

      这样导致了在Linux下通过JNI标准命名方式编译的SO文件,在android是调用失败的,原因是Linux和android的系统库不一样,而生产的SO跟生产环境库文件有依赖关系,然后搭建了NDK和Cywin环境,然后生产的SO可以被android调用,

      参考地址:http://zctya.blog.163.com/blog/static/1209178201181074018603/

      那么SO文件就必须完全遵循JNI命名规则,方法名是这样:

    /*
     * Class:     com_samples_jni_test
     * Method:    GetMsg
     * Signature: ()V
     */
    JNIEXPORT jstring JNICALL Java_com_samples_jni_test_GetMsg
    (JNIEnv *, jobject);
    

      通过NDK和Cywin生产libtest.so,android调用成功!

  • 相关阅读:
    机器学习-聚类问题
    机器学习--回归问题
    CreateRemoteThread盲注提权原理分析
    Linux下进程隐藏的方法及其对抗
    常见未授权访问漏洞总结
    Windows日志识别入侵痕迹
    打造自己的弱口令扫描工具
    Linux 命令被劫持,应急处理办法
    攻击Java Web应用--思维导图
    新型横向移动工具原理分析、代码分析、优缺点以及检测方案
  • 原文地址:https://www.cnblogs.com/1024Planet/p/4084094.html
Copyright © 2011-2022 走看看