用NDK调用Android手机自带的openssl库函数 系统运行库层 和Android runtime

来源:互联网 发布:深圳网络教育哪家最好 编辑:程序博客网 时间:2024/06/13 21:17

最近在做视频播放那块,ffmpeg的neon移植之后,
发现yuv2rgb的转码效率太低,所以打算在jni里面,
直接将ffmpeg解码之后的yuv数据输出到SoftwareRenderer之后显示,
省去了yuv2rgb的过程。但在jni中,发现需要用到安卓源码的库和头文件。
请问这个是怎么使用的?在编译安卓源代码之后,
怎么使用?不编译源代码,从手机里面把相应的so文件和头文件拷贝到jni目录下面,可行吗?谢谢。本人对安卓不太熟悉,请多指教。谢谢各位。

为了解答这个问题而写的一篇通用类博客


目标: 目前很多Android手机已经自带了openssl库, 即libssl.so, libcrypto.so, 以下示例实现了APK通过NDK调用openssl库函数PKCS5_PBKDF2_HMAC(密钥生成算法)

1) 在android工程中创建 jni目录
2) 编辑AbcJni.java
package com.example;
public class AbcJni
{
    public native byte[] hashKey(byte[] key, byte[] salt, int count);
    static {
        System.loadLibrary("abc-jni");
    }
}
3) 编译成功(生成AbcJni.java, 例如在bin目录下), 利用AbcJni.class生成
javah -classpath bin/classes -d jni com.example.AbcJni
这样会在jni目录下生成一个com_example_AbcJni.h文件
4) 新建abc-jni.c文件, 实现上述的头文件函数
#include <string.h>
#include <jni.h>
#include <openssl/evp.h>
#include <openssl/sha.h>


JNIEXPORT jbyteArray JNICALL Java_com_example_AbcJni_hashKey
  (JNIEnv *env, jobject thiz, jbyteArray pass, jbyteArray salt, jint count)
{
  jbyte* pJbytePass = (*env)->GetByteArrayElements(env, pass, NULL);
  char* szBytePass = (char *)pJbytePass;
  int iLenPass = (*env)->GetArrayLength(env, pass);
  jbyte* pJbyteSalt = (*env)->GetByteArrayElements(env, salt, NULL);
  char* szByteSalt = (char *)pJbyteSalt;
  int iLenSalt = (*env)->GetArrayLength(env, salt);
  int OUTSIZE = 64;
  char buf[64];
  memset( buf, 0, sizeof(buf) );
  PKCS5_PBKDF2_HMAC(
                  szBytePass,
                  iLenPass,
                  szByteSalt,
                  iLenSalt,
                  count, EVP_sha512(), OUTSIZE, buf);
  jbyteArray jarray = (*env)->NewByteArray(env, OUTSIZE);
  (*env)->SetByteArrayRegion(env, jarray, 0, OUTSIZE,buf);
   (*env)->ReleaseByteArrayElements(env, pass, pJbytePass, 0);
   (*env)->ReleaseByteArrayElements(env, salt, pJbyteSalt, 0);
  return jarray;
}
4) 编辑Android.mk, 文件, 内容如下:LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := abc-jni
LOCAL_SRC_FILES := abc-jni.c
LOCAL_LDLIBS := -lcrypto -lssl
include $(BUILD_SHARED_LIBRARY)




5) 下载一个最新的openssl源代码, 解压. 假如解压后目录为/my/src/openssl-1.0.1k/
注: Android的SDK/NDK目录并没有openssl相关的头文件及库文件, 所以我们需要从源码中获取头文件


6) 进入ndk中以下目录(我使用android 4.4, platform 19), 建立头文件目录的软链接
cd /opt/android-ndk/platforms/android-19/arch-arm/usr/include
ln -s /my/src/openssl-1.0.1k/include/openssl .

7) 从你的手机拷贝以下文件(在/system/lib, 需要root哦)到ndk的lib目录下:
例如, 我的手机如下:
[my]# pwd                                                                                                                                                                                                  
/system/lib
[my]# ls -la libcrypto.so libssl.so                                                                                                                                                                        
-rw-r--r-- root     root      1249844 2013-02-09 03:36 libcrypto.so
-rw-r--r-- root     root       224784 2013-02-09 03:36 libssl.so

ndk的目录是:
/opt/android-ndk/platforms/android-19/arch-arm/usr/lib

8) 回到你的android工程
cd jni
ndk-build

如果成功, 你会发现../libs目录多了一个子目录, 及libabc-jni.so文件

9) 最后你可以在你的Android java代码中调用AbcJni.java中的以下方法了:
 byte[] hashKey(byte[] key, byte[] salt, int count);
0 0