尊重原创,转载请注明出处!
创作不易,如有帮助请点赞支持~
背景
最近又开始调之前烂尾的一个项目,在我们的产品上调试一个外设。当时调到一半,基本功能已经调通了,结果因为某些原因停滞了。。。
前几天,领导又要求重新调试。回过头来看项目,好家伙,一年多前写的代码已经基本不认识了,一看SDK,和之前调试的代码相比,API接口也更新了。
好吧,老老实实重新调试,在demo应用上调试通过,移植到系统服务中,编译,推应用,推库,重启机器,崩溃。。。
日志分析
抓了系统日志,其中崩溃的关键日志如下:
--------- beginning of crash
12-25 10:21:18.413 1314 1314 E AndroidRuntime: FATAL EXCEPTION: main
12-25 10:21:18.413 1314 1314 E AndroidRuntime: Process: com.xxx.xxx, PID: 1314
12-25 10:21:18.413 1314 1314 E AndroidRuntime: java.lang.UnsatisfiedLinkError: No implementation found for MVIDPDACodeReaderWrapper.MVIDCodeReaderDefine$Handle MVIDPDACodeReaderWrapper.MVIDCodeReader.MVID_CR_CreateHandleByPath(java.lang.String, int, int) (tried Java_MVIDPDACodeReaderWrapper_MVIDCodeReader_MVID_1CR_1CreateHandleByPath and Java_MVIDPDACodeReaderWrapper_MVIDCodeReader_MVID_1CR_1CreateHandleByPath__Ljava_lang_String_2II)
12-25 10:21:18.413 1314 1314 E AndroidRuntime: at MVIDPDACodeReaderWrapper.MVIDCodeReader.MVID_CR_CreateHandleByPath(Native Method)
12-25 10:21:18.413 1314 1314 E AndroidRuntime: at MVIDPDACodeReaderWrapper.MVIDCodeReader.MVID_CR_CreateHandle(MVIDCodeReader.java:41)
12-25 10:21:18.413 1314 1314 E AndroidRuntime: at com.hikrobot.api.MvidCodeRead.createHandle(MvidCodeRead.java:88)
从日志中可以很明显看到在so中找不到对应的native方法,因此抛出UnsatisfiedLinkError异常。
解决问题
so 用 demo 调试过,按理来说不应该有问题。难道是因为 so 没有更新成功?
手动把 out 目录下 /system/lib/ 下对应的 so 删除,重新把最新的 so 拷贝到系统中,touch Android.mk,重新编译,可以看到 /out/target/product/xxx/system/lib/libXXX.so 的日期是最新的。嗯,应该没问题了,再次推库,重启机器,又崩了,一样的报错。。。
好吧,老老实实分析下这个问题。
先在服务器上分别对源码中的 so 以及 out 目录下的 so 分别执行了 nm -D libXXX.so | grep MVID_CR_CreateHandleByPath,看是否存在此函数。
结果源码中的 so 正常输出了此函数,而 out 目录下的 so 则无输出!
一开始我还以为是原始 so 或者编译选项的问题,导致编译后函数丢失,还查了半天资料,结果一无所获。
然后被同事提醒了一下,突然想起来除了 /system/lib/, out 目录下还有其他 so 的缓存。
xxx@xxx-bu2-dev3:~/xxx/out$ find . -name "libXXX.so"
./target/product/xxx/obj/SHARED_LIBRARIES/libXXX_intermediates/LINKED/libXXX.so
./target/product/xxx/obj/SHARED_LIBRARIES/libXXX_intermediates/libXXX.so
./target/product/xxx/obj/SHARED_LIBRARIES/libXXX_intermediates/PACKED/libXXX.so
./target/product/xxx/symbols/system/lib/libXXX.so
./target/product/xxx/system/lib/libXXX.so
如果 intermediates 目录下存在缓存,编译时会使用这些缓存文件直接生成新的 so,这就是为啥编译过一次之后,再次编译会更快的原因。
手动把这些缓存的 so 全部删掉,再在应用路径下执行 mm 编译整个模块,生成 so,推到机器里面,重启,没有崩溃,功能正常,问题成功解决~
总结
其实是很简单的问题,之前开发调试过程中也有遇到过 No implementation found for xxx 的问题,但是一时没想起来,意识到缓存的问题后也就知道如何解决了。
所以还是得时不时地总结、回顾一下,这样遇到问题才能更得心应手地解决问题~
遇到 java.lang.UnsatisfiedLinkError: No implementation found for xxx 的问题时,可以按照以下思路定位问题:
1、先确认 so 是否存在于应用或系统中,比如 /data/app/[package name]/lib/ 目录下或 /system/lib/ 目录下等
2、通过 nm -D | grep [function name],可以确认 so 中是否存在对应的函数。如果原始 so 都不存在此函数,则可以排除自己应用的问题了。
3、编译 so 时一定要记得清缓存,如果是普通应用开发可以 clean 工程,如果是系统服务或应用,则需要手动删除 out 下的相关 so,或者执行 make clean-[module name],直接清除指定模块的所有缓存