Android studio在2.2之后是开始兼容ndk的开发,尝鲜用来本地开发,各种坑,不兼容。之前用得好好的,一个升级AS或者NDK版本都会一不小心导致了编译失败,或者成功之后,加载不成功。故随手笔记记录下自己踩过的坑,也方便其他人查询。
Trap One :
Caused by: java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__aeabi_memcpy" referenced by **
原因:
情景一、AS配置Builde.grade来编译生成so文件。
升级AS之后,到2.3版本,新建的module默认配置builde.grade中Android sdk编译版本,以及目标目标都会自动配置到最新版 本,这个时候就会容易没有注意到新版本的sdk(version>23),这是24版本之后出现的bug,但不能低于9。
解决方式:把目标版本降低到23以及以下即可
详细说明:http://stackoverflow.com/questions/39541599/error-loading-package-jni-cannot-locate-symbol-aeabi-memcpy
情景二、使用Ndk-build命令
修改Application.mk文件中APP_PLATFORM所配置的版本要高于8以上,但不能高于23
Trap Two:
NDK library "libgnustl_shared.so" not found
这个是STL配置错误导致的,查看发现APP_STL := gnustl_shared 配置成共享型了。
APP_STL 可用值
stlport_static - 使用STLport作为静态库
stlport_shared - 使用STLport 作为共享库
gnustl_static - 使用GNU libstdc++ 作为静态库
gnustl_shared - 使用GNU libstdc++ 作为共享库
其中STLport和libstdc的区别详见https://www.zhihu.com/question/20845153。建议配置成stlport_static
Trap Three: DeleteLocalRef error
在jni.h中定义void DeleteLocalRef(jobject localRef)函数删除引用时,是针对尝试jobject以及子类,如jstring,jclass,jobject
但是一些基本类型的 jboolean 、jmethodId 、jfieldId 缺不可以,否则会报编译失败。
Trap Three: local reference table overflow
JNI ERROR (app bug): local reference table overflow (max=512)
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] local reference table dump:
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] Last 10 entries (of 512):
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 511: 0x70473f60 java.lang.Class
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 510: 0x70473f60 java.lang.Class
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 509: 0x70473f60 java.lang.Class
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 508: 0x70473f60 java.lang.Class
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 507: 0x70473f60 java.lang.Class
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 506: 0x70473f60 java.lang.Class
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 505: 0x70473f60 java.lang.Class
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 504: 0x70473f60 java.lang.Class
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 503: 0x70473f60 java.lang.Class
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 502: 0x70473f60 java.lang.Class
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] Summary:
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 1 of cn.egame.terminal.paysdk.EgamePay$1
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 2 of dalvik.system.DexClassLoader (1 unique instances)
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 455 of java.lang.Class (14 unique instances)
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 39 of java.lang.String (39 unique instances)
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 1 of java.lang.Exception
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 1 of java.io.BufferedWriter
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 1 of java.io.FileInputStream
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 1 of java.security.MessageDigest$MessageDigestImpl
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 1 of java.util.TreeMap$KeySet$1
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 1 of java.util.TreeMap
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 3 of byte[] (162 elements) (3 unique instances)
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 1 of byte[] (4096 elements)
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115] 5 of java.io.File (5 unique instances)
05-19 12:53:40.563 32571-32667/com.sanguo.cdws A/art: art/runtime/indirect_reference_table.cc:115]
05-19 12:53:40.564 32571-32667/com.sanguo.cdws A/art: art/runtime/runtime.cc:368] Runtime aborting...
在android nativie开发中jni局部引用限制了512个LocalRef,如果创建了局部引用,如上述的 jclass、jstring、jobject等通过FindClass /NewString/ NewStringUTF/NewObject来产生了localRef。如果用完了(已经传递赋值了或者不再使用了),必须调用env->DeleteLocalRef来删除,否则引用计数超过512就会导致运行终止,local reference table overflow。
同时有个不好习惯导致没有删除,习惯性直接FindClass /NewString/ NewStringUTF/NewObject来给函数直接赋值,没有直接使用引用,并删除,依然会被计数,如下代码:
这种方式直接导致局部应用没有被回收,循环中从而超过512个。必须直接写出来,并删除:
所以不能再偷懒了。
Trap four
dynamic section has invalid link(0) sh_type: 0 (expected SHT_STRTAB)
多见于加载so失败,上层报UnsatisfiedLinkError 异常,由于google在Android 7.0 以后对so做了更加严格的限制,对于非标准so,比如section header缺失或者dynamic table中数据项不对,会直接崩溃,对于这类问题,可以过滤linker的log查看logcat-s linker。
----结头表里面dynamic section 对应的sh_link字段非法,这里正常应该是字符串表,如果不是字符串表,就会报错。
相关错误信息:
xxx.so has invalid e_phnum
-----程序头项数不对
xxx.so has no section headers
-----结头丢失
xxx.so .dynamic section header was not found
-----动态结区丢失
xxx.so .dynamic section has invalid link(%d) sh_type: %d (expected SHT_STRTAB)
-----结头表里面dynamic section 对应的sh_link字段非法,这里正常应该是字符串表,如果不是字符串表,就会报错。
xxx.so has invalid offset/size of .dynamic section
-----动态结区offset 校验失败
xxx.so: has text relocations
-----so有text 重定位section,对于targetSDK>22 会报错。
Trap Five
error:only position independent executables (PIE) are supported.
PIE这个安全机制从4.1引入,但是Android L之前的系统版本并不会去检验可执行文件是否基于PIE编译出的。因此不会报错。
但是Android L已经开启验证,如果调用的可执行文件不是基于PIE方式编译的,则无法运行。解决办法非常简单,在Android.mk中加入如下flag就行。
LOCAL_CFLAGS += -pie -fPIE
LOCAL_LDFLAGS += -pie -fPIE
Trap six
make: *** No rule to make target
问题在Android.mk没有配置好,之前配置多了字符
LOCAL_PATH:= $(call my-dir)