NDK 调用 so 时的异常问题解决

这两天开始学习下android ndk的使用,给自己提了两个问题

1。 .so文件时怎么生成的?
2。 生成了so文件之后要怎么取调用呢
3。 为什么要用so文件,为什么要用java调用c/c++代码呢?

问题1:
站在巨人的肩膀上学习,大家可直接下载这位同学分享出来的项目学习和生成
https://github.com/wobiancao/NdkJniDemo

问题2:
(1)给我一个so文件,首先我需要知道这个so支持哪些方法,以下命令就可以查询

 nm -D  /Users/scucheri/AllMyProjects/AI_android/ndk/test_use_so/app/libs/armeabi/libNdkJniDemo.so

结果如下:

00000690 T Java_com_wobiancao_ndkjnidemo_ndk_JniUtils_getIv
00000610 T Java_com_wobiancao_ndkjnidemo_ndk_JniUtils_getKeyValue
000005e0 T Java_com_wobiancao_ndkjnidemo_ndk_JniUtils_getStringFormC
00003004 A __bss_start
         U __cxa_atexit
00000000 w __cxa_begin_cleanup
00000000 w __cxa_call_unexpected
         U __cxa_finalize
00000000 w __cxa_type_match
00000000 w __gnu_Unwind_Find_exidx
00003004 A _edata
00003004 A _end
         U abort
00001d99 R iv
00001d68 R keyValue
         U memcpy

可以看出来,支持的JNI方法有 Java_com_wobiancao_ndkjnidemo_ndk_JniUtils_getIv,Java_com_wobiancao_ndkjnidemo_ndk_JniUtils_getKeyValue 和 Java_com_wobiancao_ndkjnidemo_ndk_JniUtils_getStringFormC

(2)查询到方法之后那怎么调用这个方法呢? 先将 libNdkJniDemo.so 文件放入到libs目录下,然后 在app的gradle文件中 加入以下配置

android{
...
sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
}

这时候就如果在android studio中的项目工程jniLibs目录下出现了这个so文件,就说明已经导入成功。

这时候需要写一个java类作为JNI接口,实现java对c代码的调用,需要特别注意的是,这个JNI接口类的package,className都必须和so文件中支持的方法保持一致,否则就会报错 method can’t found error

比如Java_com_wobiancao_ndkjnidemo_ndk_JniUtils_getIv ,若需要调用它,需要新建的java类为JniUtils ,package name为 com.wobiancao.ndkjnidemondk

代码如下:

package com.wobiancao.ndkjnidemo.ndk;


import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;

/**
 * Created by xy on 16/1/4.
 */
public class JniUtils {
    public static native String getStringFormC();
    public static native byte[] getKeyValue();
    public static native byte[] getIv();

    private static byte[]keyValue;
    private static byte[]iv;

    private static SecretKey key;
    private static AlgorithmParameterSpec paramSpec;
    private static Cipher ecipher;

    static {
        System.loadLibrary("NdkJniDemo");   //defaultConfig.ndk.moduleName
        keyValue = getKeyValue();
        iv = getIv();
        if(null != keyValue && null !=iv) {
            KeyGenerator kgen;
            try {
                kgen = KeyGenerator.getInstance("AES");
                SecureRandom random = SecureRandom.getInstance("SHA1PRNG","Crypto");
                random.setSeed(keyValue);
                kgen.init(128,random);
                key =kgen.generateKey();
                paramSpec =new IvParameterSpec(iv);
                ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

            } catch (NoSuchAlgorithmException e) {
            } catch (NoSuchPaddingException e) {
            } catch (NoSuchProviderException e) {
                e.printStackTrace();
            }
        }
    }
    }

除了JNI的package name和className一定要与so文件中的配置保持一致之外,还需要注意:
在执行 System.loadLibrary(“NdkJniDemo”); 时,这个名字不是指so文件的全名“libNdkJniDemo“,不包含前面的lib。

(3)问题3:
见博文:
http://allenfeng.com/2016/11/06/what-you-should-know-about-android-abi-and-so/

* so机制让开发者最大化利用已有的C和C++代码,达到重用的效果,利用软件世界积累了几十年的优秀代码;
* so是二进制,没有解释编译的开消,用so实现的功能比纯java实现的功能要快;
* so内存分配不受Dalivik/ART的单个应用限制,减少OOM;
* 相对于java代码,二进制代码的反编译难度更大,一些核心代码可以考虑放在so中。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值