最近换工作接手新项目,着手调查一个jni crash问题。
crash log信息相当明显:
Revision: '0'
ABI: 'arm64'
pid: 5921, tid: 9804, name: Background >>> com.example.text <<<
signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
Abort message: 'java_vm_ext.cc:534] JNI DETECTED ERROR IN APPLICATION: input is not valid Modified UTF-8: illegal continuation byte 0xcd'
x0 0000000000000000 x1 000000000000264c x2 0000000000000006 x3 0000000000000008
.....
从这里一看,我们就大概明白和编码有关了 因为出现了关键字 input is not valid Modified UTF-8:
继续查看aplog:
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] JNI DETECTED ERROR IN APPLICATION: input is not valid Modified UTF-8: illegal continuation byte 0xcd
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] string: '(3эhi_resource'
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] input: '0x28 0x33 0xd0 <0xcd> 0x68 0x69 0x5f 0x72 0x65 0x73 0x6f 0x75 0x72 0x63 0x65'
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] in call to NewStringUTF
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] from java.lang.String[] java.io.UnixFileSystem.list0(java.io.File)
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] "Background" prio=5 tid=29 Runnable
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] | group="main" sCount=0 dsCount=0 flags=0 obj=0x12d0ac40 self=0x70ff676400
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] | sysTid=9804 nice=0 cgrp=default sched=0/0 handle=0x70ff5ff4f0
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] | state=R schedstat=( 63854 0 1 ) utm=0 stm=0 core=6 HZ=100
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] | stack=0x70ff4fd000-0x70ff4ff000 stackSize=1037KB
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] | held mutexes= "mutator lock"(shared held)
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] native: #00 pc 00000000003cad9c /system/lib64/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, int, BacktraceMap*, char const*, art::ArtMethod*, void*)+208)
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] native: #01 pc 000000000049b124 /system/lib64/libart.so (art::Thread::DumpStack(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, bool, BacktraceMap*, bool) const+348)
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] native: #02 pc 00000000002fd7dc /system/lib64/libart.so (art::JavaVMExt::JniAbort(char const*, char const*)+1048)
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] native: #03 pc 00000000002fdbcc /system/lib64/libart.so (art::JavaVMExt::JniAbortV(char const*, char const*, std::__va_list)+116)
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] native: #04 pc 000000000010e764 /system/lib64/libart.so (art::ScopedCheck::AbortF(char const*, ...)+148)
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] native: #05 pc 000000000010ec3c /system/lib64/libart.so (art::ScopedCheck::CheckUtfString(char const*, bool)+736)
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] native: #06 pc 000000000010c764 /system/lib64/libart.so (art::ScopedCheck::Check(art::ScopedObjectAccess&, bool, char const*, art::JniValueType*)+644)
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] native: #07 pc 0000000000102ec4 /system/lib64/libart.so (art::CheckJNI::NewStringUTF(_JNIEnv*, char const*)+636)
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] native: #08 pc 0000000000020c90 /system/lib64/libopenjdk.so (Java_java_io_UnixFileSystem_list0+456)
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] native: #09 pc 000000000006f958 /system/framework/arm64/boot-core-oj.oat (Java_java_io_UnixFileSystem_list0__Ljava_io_File_2+152)
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] at java.io.UnixFileSystem.list0(Native method)
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] at java.io.UnixFileSystem.list(UnixFileSystem.java:313)
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] at java.io.File.list(File.java:1122)
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] at java.io.File.listFiles(File.java:1248)
我们发现log 中还是给出了足够的信息
我们代码在调用NewStringUTF()的时候发生了crash,原因是utf-8编码有问题,继续查看 log:
08-31 18:34:27.172 5921 9804 F zygote64: java_vm_ext.cc:534] string: '(????hi_resource'
这里是关键。明显看的出这里有问题。
继续查看log 发现 有File相关信息出现。发现是有File调用下去的
继续在我们的业务代码中查找与File相关的代码。发现listFile().
从代码业务分析,我们的代码关键地方是File.listFile().
public void FileTest(){
FilenameFilter filter =new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".txt");
}
};
File file =new File("xx");
file.listFiles(filter);
}
至此怀疑到问题发生点,我们验证一下。
既然crash发生是与utf-8编码有关,那我们就制造一个非utf-8命名的文件,制造方法非常简单,直接新建一个txt文件,然后另存为其他文件,保存时候为中文名字,非utf-8编码,然后push到手机,在adb下查看该文件,发现文件名已经有问题
然后跑业务代码, crash概率100%。
然后我们继续正向分析file.listfiles().
调查过程非常简单
file.listfiles() -> list() -> UnixFileSystem.list() -> list0() -> UnixFileSystem_md.c.Java_java_io_UnixFileSystem_list0() ->jni_util.c.JNU_NewStringPlatform() ->jni_util_md.c.nativeNewStringPlatform() -> NewStringUTF().
继续利用addr2line反编译libart.so
查看Android源代码:check_jni.cc 2251
check_jni.cc 1276 行
ok,找到关键文件,正是这里抛出jni异常。AbortF().
至此我们断定crash 从这里抛出。
问题发生原因:
调用file标准接口的时候,有listFliles()发现目录下有非utf-8编码的文件名,导致jni crash。
修改方案:在AndroidManifest.xml 中添加 android:debbuggabel="false"
修改原因:这里我也不知道了, Stackoverflow 中查到的,别问我为什么,我也不知道
猜测是Android设置了debbuggabel后,应该在调用newStringUTF()的时候清楚了异常,所以没有这个crash上报了。
更多关于android utf-8知识看这篇blog,写的还是相当不错的
https://blog.csdn.net/self_study/article/details/78886686