jni

参数传递

  • Java传String到底层,利用GetStringUTFChars转换成字符指针数组,该过程需要分配内存,要进行一个判空操作:
    jni
    同时需要释放上面操作所消耗的内存。
  • 操作数组,env->getArrayElemetns 返回java数组的一个拷贝,优良的VM,会返回指向Java数组的一个直接的指针,并标记该内存区域,不允许被GC。
  • 对象数组,使用Get/SetObjectArrayElement操作,对象数组只针对单个的元素,不提供类似Region的区域性操作。
  • 获得类字节码:getObjectClass,FindClass
  • 获得类的字段,getFieldID
  • 获得某个对象的字段的值,getObjectField

添加日志

#include <android/log.h>

#define LOGD(…) android_log_print(ANDROID_LOG_DEBUG,”TAG”,VA_ARGS__)

类型签名

  1. 基本类型签名
    签名

  2. 函数签名,java支持函数重载,虽然参数不一样,但是方法名一样,因此jni层需要通过方法名和方法签名来唯一确定函数的调用
    (参数类型签名) + 返回值类型签名,对于没有返回值的,用V表示
    String test() Ljava/lang/String;
    int test(int i ,Object object) (ILjava/lang/Object;)I
    void set(byte[] b) ([B)V

c语言的指针

  • 在声明指针中,“*”号表示所声明的变量是个指针
  • 在指针使用时,“*”号表示操作指针所指向的内存空间中的值
  • 当*p放在等号左边时,相当于给内存赋值
  • 当*p放在等号右边时,相当于从内存取值

    1
    2
    3
    4
    5
    int i = 3,j = 0;
    int *p = NULL;
    p = &i; //p指向i所在的内存
    *p = 5; //将p所指向的内存里的值修改为5,此时i的值也为5
    j = *p; //将p所指向的内存空间的值赋值给j
  • 如果函数的参数里包含指针,进入函数系统会重新创建一个指针变量,与该参数指向相同的变量,因此如果要想在函数内部想修改指针的指向,就要用到二级指针

定位jni运行时的错误日志(Fatal signal 11 (SIGSEGV))

  1. 命令行输入: adb logcat > log.txt,将会在项目更目录写入log.txt文件
  2. 再在命令行输入:ndk-stack -sym app/build/intermediates/cmake/debug/obj/armeabi-v7a -dump ./log.txt