最近換工作接手新項(xiàng)目,著手調(diào)查一個(gè)jni crash問(wèn)題。
crash log信息相當(dāng)明顯:
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
.....
從這里一看,我們就大概明白和編碼有關(guān)了 因?yàn)槌霈F(xiàn)了關(guān)鍵字?input is not valid Modified UTF-8:
繼續(xù)查看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)
我們發(fā)現(xiàn)log 中還是給出了足夠的信息
我們代碼在調(diào)用NewStringUTF()的時(shí)候發(fā)生了crash,原因是utf-8編碼有問(wèn)題,繼續(xù)查看 log:
08-31 18:34:27.172? 5921? 9804 F zygote64: java_vm_ext.cc:534]? ? string: '(????hi_resource'
這里是關(guān)鍵。明顯看的出這里有問(wèn)題。
繼續(xù)查看log 發(fā)現(xiàn) 有File相關(guān)信息出現(xiàn)。發(fā)現(xiàn)是有File調(diào)用下去的
繼續(xù)在我們的業(yè)務(wù)代碼中查找與File相關(guān)的代碼。發(fā)現(xiàn)listFile().
從代碼業(yè)務(wù)分析,我們的代碼關(guān)鍵地方是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);
}
至此懷疑到問(wèn)題發(fā)生點(diǎn),我們驗(yàn)證一下。
既然crash發(fā)生是與utf-8編碼有關(guān),那我們就制造一個(gè)非utf-8命名的文件,制造方法非常簡(jiǎn)單,直接新建一個(gè)txt文件,然后另存為其他文件,保存時(shí)候?yàn)橹形拿?,非utf-8編碼,然后push到手機(jī),在adb下查看該文件,發(fā)現(xiàn)文件名已經(jīng)有問(wèn)題
然后跑業(yè)務(wù)代碼, crash概率100%。
然后我們繼續(xù)正向分析file.listfiles().
調(diào)查過(guò)程非常簡(jiǎn)單?
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().
繼續(xù)利用addr2line反編譯libart.so??

查看Android源代碼:check_jni.cc 2251

check_jni.cc 1276 行

ok,找到關(guān)鍵文件,正是這里拋出jni異常。AbortF().
至此我們斷定crash 從這里拋出。
問(wèn)題發(fā)生原因:
調(diào)用file標(biāo)準(zhǔn)接口的時(shí)候,有l(wèi)istFliles()發(fā)現(xiàn)目錄下有非utf-8編碼的文件名,導(dǎo)致jni crash。
修改方案:在AndroidManifest.xml 中添加 android:debbuggabel="false"
修改原因:這里我也不知道了,?Stackoverflow?中查到的,別問(wèn)我為什么,我也不知道
?猜測(cè)是Android設(shè)置了debbuggabel后,應(yīng)該在調(diào)用newStringUTF()的時(shí)候清楚了異常,所以沒(méi)有這個(gè)crash上報(bào)了。
更多關(guān)于android utf-8知識(shí)看這篇blog,寫(xiě)的還是相當(dāng)不錯(cuò)的
https://blog.csdn.net/self_study/article/details/78886686