关于JNI的基本使用方法,网络上有很多文章。我只想把我最近遇到的关于JNI的问题总结一下。
在android 源码下创建一个工程,将源文件拷贝到工程目录的 apps和jni文件夹下。
工程的Android.mk文件为
LOCAL_PATH := $(call my-dir)
LIB_COMMC_INCLUDE := $(LOCAL_PATH)/../../bionic/libc/include
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=/
./apps/bdk_app_demo.c/
./apps/bdk_app_generic.c/
./apps/bdk_app_spp_c.c/
./apps/bdk_app_spp_drv.c/
./apps/bdk_app_spp_s.c/
./apps/bdk_app_sys.c/
./apps/iconv.c/
./apps/bdk_app_ui_data.c/
./apps/cheat_fun.c/
./jni/jnimain.c
LOCAL_C_INCLUDES:=/
$(JNI_H_INCLUDE)/
$(LOCAL_PATH)/inc/
$(LOCAL_PATH)/apps/
$(LIB_COMMC_INCLUDE)
LOCAL_STATIC_LIBRARIES:=/
libcutils
LOCAL_LDFLAGS+=
$(LOCAL_PATH)/lib/libgeneric.a/
$(LOCAL_PATH)/lib/libstack.a/
$(LOCAL_PATH)/lib/libsys.a/
$(LOCAL_PATH)/lib/libusb.a
LOCAL_PRELINK_MODULE:=false
LOCAL_MODULE:=libhello
include $(BUILD_SHARED_LIBRARY)
工程源文件如LOCAL_SRC_FILES所示,除了libc库外,还包括了四个外部链接库libgeneric.a libstack.a libsys.a libusb.a, 这四个库为第三方得到,而且已经被证明在android平台上可用的。
模块名由LOCAL_MODULE=libhello指定,include $(BUILD_SHARED_LIBRARY)表示目标模块被编译为动态库,JNI要求Native代码编译为动态库供虚拟机加载。
配置好工程的源文件和Android.mk后,执行make libhello SHOW_COMMANDS=a; 经过分析android的build系统,我发现只要将SHOW_COMMANDS设置为一个非空的字符串,就可以在make 的过程中将Makefile命令执行的内容打印。虽然android build系统提供了一个showcommands命令来完成同样的工作,我习惯了用前面的方式。
最初的build出现了一个错误,build log显示为:
target non-prelinked: libhello (out/target/product/generic/symbols/system/lib/libhello.so)
out/host/linux-x86/bin/acp -fpt
out/target/product/generic/obj/SHARED_LIBRARIES/libhello_intermediates/LINKED/libhello.so
out/target/product/generic/symbols/system/lib/libhello.so
target Strip: libhello (out/target/product/generic/obj/lib/libhello.so)
out/host/linux-x86/bin/soslim --strip --shady --quiet
out/target/product/generic/symbols/system/lib/libhello.so --outfile
out/target/product/generic/obj/lib/libhello.so
external/elfcopy/elfcopy.c(1097): gelf_update_phdr(): invalid data
make: *** [out/target/product/generic/obj/lib/libhello.so] Error 1
make: *** Deleting file `out/target/product/generic/obj/lib/libhello.so'
错误行为external/elfcopy/elfcopy.c(1097): gelf_update_phdr(): invalid data
从源代码结构以及上面的 Log可以看到,elfcopy是 soslim模块的一部分, soslim是源代码目录toolchain工具arm-eabi-strip的替代工具,功能是为了去除库中多余的符号和调试信息,为动态库瘦身。
通过分析make输出的日志。动态库的生成包括几个过程:
1 设置目标和主机相关的变量(包括编译器选择,基本编译选项设置以及其他build变量设置)
2 读取所有模块的Android.mk,生成各模块的build规则。
3 执行libhello的build过程
编译源文件
连接目标文件为动态库
使用soslim为动态库瘦身
将瘦身的libhello 复制到输出文件夹
当前的错误出现在步骤3的瘦身过程。好在android Developer的mail list中,看到有帖子遇到了同样的问题,在发言中有人建议使用gcc 4.2.4以下版本生成目标文件。 android build system默认使用gcc 4.2.1版本编译器。最后发现那四个第三方库使用的是gcc 4.3.1编译器生成, 重编那四个lib库, 问题解决了。