[bug小记]System.loadLibrary加载so库时报警告JNI_OnLoad returned bad version(-1)并且crash

这次项目中的大部分代码是写在NDK层的,并通过jni相关函数封装成一个个jni函数接口。然后在java层,通过以下这样一个NDKController类封装所有jni函数接口,供其它java代码直接调用。

public class NDKController{

static{

System.loadLibrary("libnameA");

System.loadLibrary("libnameB");

System.loadLibrary("libnameC");

System.loadLibrary("NdkLibName"); //上述libnameA,libnameB, libnameC库都是被NdkLibName库用到的更底层的库

System.loadLibrary("JniLibName");

}

... ...

... ...

... ...

public native long NdkFunc1( ..., ..., ... );

public native long NdkFunc2( ..., ..., ... );

public native long NdkFunc3( ..., ..., ... );

... ...

... ...

} //class end


这种架构在以前的项目中已经用得很稳定了。这次居然在NDKController类第一次被使用的地方就crash了,伴随在logcat中的是这样的warning:

... JNI_OnLoad returned badversion(-1)in /.../.../libxxxx.so

也就是System.loadLibrary("libnameC")加载不成功。

 

在网上搜索相关错误,多半类似错误的原因是在Manifest中没将APP的文件读写权限打开,或者是路径不对。总之就是不能成功读取这个so文件。可是我这里很确定路径和权限是没问题的。

 

然后我也怀疑是不是这里的libnameC库本身的问题,或者编译版本不对之类的,但是ibnameC库是很底层的平台库,之前项目中使用都没出现过这种加载的问题。而且即使把当前项目的android版本等相关配置改成和之前项目完全一致,问题也依然存在。

 

搜索过程中,发现了两个很不错的链接:
1) http://my.oschina.net/wolfcs/blog/129696  这个比较详细讲了System.loadLibrary的机制,我注意到其中有一段源代码如下:

 

int version;

vonLoad =dlsym(handle, "JNI_OnLoad");

if(vonLoad == NULL)

{

ALOGD("NoJNI_OnLoad found in %s %p, skipping init",pathName, classLoader);

else

{

OnLoadFunc func =(OnLoadFunc)vonLoad;

Object*prevOverride = self->classLoaderOverride;

 

self->classLoaderOverride= classLoader;

oldStatus =dvmChangeStatus(self, THREAD_NATIVE);

if(gDvm.verboseJni){

ALOGI("[CallingJNI_OnLoad for \"%s\"]", pathName);

}

version =(*func)(gDvmJni.jniVm, NULL);

dvmChangeStatus(self,oldStatus);

self->classLoaderOverride= prevOverride;

 

if(version !=JNI_VERSION_1_2 && version != JNI_VERSION_1_4 && version!= JNI_VERSION_1_6)

{

ALOGW("JNI_OnLoadreturned bad version (%d) in %s %p", version,pathName, classLoader);

result = false;

}

... ...

... ...

}

 

想必是这里的gDvmJni.jniVm失败返回-1。可是我没有找到gDvmJni.jniVm对应的源代码,却幸运地又看到了下面这个网页:

 

2http://blog.xuite.net/free6d1823/blog/162878865-Android+JNI+debug+%E5%BF%83%E5%BE%97

最后一句“Java不呼叫 yyyfunction, apk啟動時會出現上述錯誤” 救了我....我的错误果然也是这个原因。很感谢原作者,因为我在google论坛等各种国外网站上搜索,也没找到这种说法,还好这位同胞小哥亲身试验过这个问题。

 

也就是说,System.loadLibrary加载的so库,必须有被用到,不然gDvmJni.jniVm失败返回-1,然后就会导致程序卡死。

 

后来查证了下,我们最新的项目代码中果然没有用到libnameC这个so库。而我只要将System.loadLibrary("libnameC")删掉,并且在NdkLibNameJniLibName库的原始工程中的Android.mk中删掉其对libnameC的依赖关系,问题就解决了。

 

感觉上这应该是系统函数本身的缺陷,如果报个加载库没被用到warning是合理的,但是让程序crash就很奇怪了。没什么逻辑性。算是增长了一个工程过程中的经验值吧。

 

你可能感兴趣的:(android)