Android & iOS · 2015-05-22

Openssl移植到Android

Openssl移植到Android都是使用别人提好(从Android源码)的Openssl代码,方法简单但过程不那么顺利,因为Openssl版本变动太频繁了,再加上NDK一堆BUG,极不愿意去调试原始配置,单单Openssl的模块编译前后就等了两个月直到Google推出NDK新版本R8C才编译通过。因为原生程序应用到很多Openssl签名、验证算法函数,就连Openssl的版本升级一下往往都要修改一些代码才能通过。

一、下载Openssl最新版本

可选的Openssl Android版本下载地址:

Openssl 1.0.0a:

https://github.com/guardianproject/openssl-android

Openssl 1.0.1c:

https://github.com/aluvalasuman/OpenSSL1.0.1cForAndroid

本文将要使用的Openssl版本为1.0.1c,前一1.0.0a版本未验证通过(NDKr8b),编译时会出现下文的编译错误。所以改用较新版本,目前已知1.0.1c在NDK r8b上编译会有很多问题,不是Openssl工程有兼容BUG就是NDK版本有BUG,反正不是那么容易调试通过。

二、编译过程

本文编译使用最新的NDK r8c(Ubuntu 12.04),下载Openssl android工程后解压,可以看到完整的NDK工程,简单的编译过程如下:

  1. 进入解压目录,执行:
  2. $NDK_HOME/ndk-build clean
  3. $NDK_HOME/ndk-build
  4. 编译结果在obj目录下(libcrypto-static.a和libssl-static.a或是libcrypto.so和libssl.so)
  5. 把结果拷贝出来放到自己的Android工程Helloworld对应目录下进行调用即可。

上述步骤4编译出Openssl的链接库,一般拷贝到ndk_r8c\platforms\android-10\arch-arm\usr\lib目录下(仅为示例),然后把openssl根下的include目录都拷贝出去就是编译头文件,这样就可以构建自己的helloworld工程了,在helloworld的Android.mk中增加类似如下调用:

LOCAL_LDLIBS := -L$(SYSROOT)/lib/ -llog -lcrypto -lssl

三、常见错误

以下编译错误,有的在1.0.0a版本中遇到,有的是在NDK r8b环境下遇到,此间涉及到OpenSSL版本问题、GCC版本问题、NDK版本BUG问题,等等都混到一起总结方便对应处理。

1、undefined reference to `zError’

openssl 库时错误如下:

SharedLibrary  : libssl.so
Executable     : openssl
/root/android-ndk-r8b/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.6.x-google/../../../../arm-linux-androideabi/bin/ld: warning: libz.so, needed by ./obj/local/armeabi/libcrypto.so, not found (try using -rpath or -rpath-link)

./obj/local/armeabi/libcrypto.so: undefined reference to `zError'
./obj/local/armeabi/libcrypto.so: undefined reference to `inflateEnd'
./obj/local/armeabi/libcrypto.so: undefined reference to `deflate'
./obj/local/armeabi/libcrypto.so: undefined reference to `deflateInit_'
./obj/local/armeabi/libcrypto.so: undefined reference to `inflate'
./obj/local/armeabi/libcrypto.so: undefined reference to `deflateEnd'
./obj/local/armeabi/libcrypto.so: undefined reference to `inflateInit_'
collect2: ld returned 1 exit status

解决办法:

1、$NDK_HOME/ndk-build NDK_TOOLCHAIN_VERSION=4.4.3

$NDK_HOME/ndk-build NDK_TOOLCHAIN=arm-linux-androideabi-4.4.3

该方法参考来自:android-ndk-r8b/doc/NDK-BUILD.html 说明,ndk-build可以携带 NDK_XXX这样的参数,来指定编译环境版本信息。具体参数有哪些?目前可以通过android-ndk-r8b/build/core/init.mk里查询到一些NDK_开头的参数。

2、在openssl的jni目录下的Application.mk中增加:

APP_PLATFORM := android-8

3、在openssl根下的android-config.mk中增加:

APP_ABI := armeabi armeabi-v7a

该参考来源android-ndk-r8b/docs/APPLICATION-MK.html

2、Unknown EABI object attribute 44

SharedLibrary  : libssl.so
/root/android-ndk-r8b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.4.3/../../../../arm-linux-androideabi/bin/ld: Warning: /root/android-ndk-r8b/platforms/android-8/arch-arm/usr/lib/crtend_so.o: Unknown EABI object attribute 44
Executable     : openssl
/root/android-ndk-r8b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.4.3/../../../../arm-linux-androideabi/bin/ld: Warning: /root/android-ndk-r8b/platforms/android-8/arch-arm/usr/lib/crtend_android.o: Unknown EABI object attribute 44
Install        : openssl => /root/aluvalassuman/libs/armeabi/openssl
Install        : libssl.so => /root/aluvalassuman/libs/armeabi/libssl.so
Compile thumb  : ssltest <= ssltest.c
Executable     : ssltest
/root/android-ndk-r8b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.4.3/../../../../arm-linux-androideabi/bin/ld: Warning: /root/android-ndk-r8b/platforms/android-8/arch-arm/usr/lib/crtend_android.o: Unknown EABI object attribute 44
Install        : ssltest => /root/aluvalassuman/libs/armeabi/ssltest

解决办法:

4.4.3似乎跟链接库的编译环境可能对不上(44冲突),网上有说改成4.6就没问题了,不会出现该提示,但是4.6支持STL有BUG啊?

crypto/Android.mk 大约535行,添加:

LOCAL_EXPORT_LDLIBS := -lz

注意有没添加以下两个静态库,大约576行,添加(暂时不用):

LOCAL_LDLIBS := -lz –ldl

3、build/gmsl/__gmsl:512: *** non-numeric second

Complile Openssl:

Error:
build/gmsl/__gmsl:512: *** non-numeric second
Changes:

I changed the file  __gmsl, the second wordlist argument(line 512),
and it’s running my jni example without errors:

int_encode = $(__gmsl_tr1)$(wordlist 1, $1,$(__gmsl_input_int))

to:

int_encode = $(__gmsl_tr1)$(wordlist 1,$(words $1),$
(__gmsl_input_int))

参考资料(下述可能有地址被墙了):

http://www.uml.org.cn/mobiledev/201108101.asp

http://blog.csdn.net/someonea/article/details/6312213

http://ssuman185.blogspot.sg/p/steps-for-porting-openssl-for-android.html

http://stackoverflow.com/questions/11856688/openssl-build-issue-with-android-ndk-r8

http://stackoverflow.com/questions/11929773/compiling-the-latest-openssl-for-android

https://groups.google.com/forum/?fromgroups=#!topic/android-ndk/b4DSxE1NAS0