ログイン後にアプリケーション問題分析(jni libdvm)を終了


あるアプリケーションが再ログインしたときに突然終了し、アプリケーションは他のプラットフォームでも良いと言っているので、システムromの問題です.まずロゴを見てからにしよう
native_eup( 4929): waitpid:return n=5143 status=00000b7f 10391 I/native_eup( 4929): child is stopped 10392 I/native_eup( 4929): cause by fatal signal SIGSEGV 10393 I/native_eup( 4929):  collect crashInfo 10394 I/native_eup( 4929): start to collect crash info of child pid:5143 tid:5143 10395 I/native_eup( 4929): create_tombstone filePath :/data/data/com.tencent.qqgame.qqlord.tv/app_tomb/tomb_1444874383556.txt 10396 I/native_eup( 4929): file open success!/data/data/com.tencent.qqgame.qqlord.tv/app_tomb/tomb_1444874383556.txt: 10397 I/native_eup( 4929): dump crash banner start 10398 I/native_eup( 4929): dump dump_crash_banner start 10399 I/native_eup( 4929): read/proc/4929/cmdline 10400 I/native_eup( 4929): read success! 10401 I/native_eup( 4929): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 10402 I/native_eup( 4929): dump dump_build_info start 10403 I/native_eup( 4929): Build fingerprint: 'realtek/rtd299x_tv030/rtd299x_tv030:4.2.1/JOP40D/eng.ffeng.20150928.163008:eng/test-keys' 10404 I/native_eup( 4929): dump dump_build_info end 10405 I/native_eup( 4929): pid: 5143, tid: 5143  >>> com.tencent.qqgame.qqlord.tv <<< 10406 I/native_eup( 4929): NativeRQDVersion:NRQD_1.7.4.1 10407 I/native_eup( 4929): dump dump_fault_addr start 10408 I/native_eup( 4929): signal 11 (SIGSEGV), fault addr deadd00d
もとはSIGSEGVで、普通はメモリアドレスの不法アクセスの問題です.スタックを見てみましょう
 7639 D/WeGame BeaconHelper.reportMSDKEvent( 4929):  >>>event:MSDK_getNotice,wattingTime:259,flag:true  7640 D/beacon_step_api( 4929):  onUA: MSDK_getNotice,true,259,-1,true  7641 I/dalvikvm( 4929):   #00  pc 000012a0 /system/lib/libcorkscrew.so (unwind_backtrace_thread+27)  7642 I/dalvikvm( 4929):   #01  pc 0005f270 /system/lib/libdvm.so (dvmDumpNativeStack(DebugOutputTarget const*, int)+35)  7643 I/dalvikvm( 4929):   #02  pc 00053b68 /system/lib/libdvm.so (dvmDumpThreadEx(DebugOutputTarget const*, Thread*, bool)+303)  7644 I/dalvikvm( 4929):   #03  pc 00053c02 /system/lib/libdvm.so (dvmDumpThread(Thread*, bool)+25)  7645 I/dalvikvm( 4929):   #04  pc 00038b7a /system/lib/libdvm.so  7646 I/dalvikvm( 4929):   #05  pc 0003dd36 /system/lib/libdvm.so  7647 I/dalvikvm( 4929):   #06  pc 002bf7b8 /data/app-lib/com.tencent.qqgame.qqlord.tv-1/libgame.so (_JNIEnv::CallStaticBooleanMethod(_jclass*,             _jmethodID*, ...)+15)  7648 I/dalvikvm( 4929):   #07  pc 002cdad4 /data/app-lib/com.tencent.qqgame.qqlord.tv-1/libgame.so (GameManager::OnWakeupNotify(WakeupRet&)+71)  7649 I/dalvikvm( 4929):   #08  pc 0041b7b4 /data/app-lib/com.tencent.qqgame.qqlord.tv-1/libgame.so (X8Observer::OnTimer(unsigned int)+243)  7650 I/dalvikvm( 4929):   #09  pc 0041c4aa /data/app-lib/com.tencent.qqgame.qqlord.tv-1/libgame.so (void MTGame::TEventProducerImpl>::FireEvent(void 
logcatのcrush前のスタックを見て、テンセントのsoはlibdvmを呼び出しました.so、対応するコードを見てみましょう.
コマンドの実行:
arm-none-linux-gnueabi-addr2line -aCfe libdvm.so 00038b7a 0x00038b7a abortMaybe/home/lw/rt95/e6700a/project/kernel/android/JB/dalvik/vm/CheckJni.cpp:37見て/home/lw/rt 95/e 6700 a/project/kernel/android/JB/dalvik/vm/CheckJni.cppの37行でしょう
  35 static void abortMaybe() {                                                                                          ||     checkCallResultCommon   36     if (!gDvmJni.warnOnly) {                                                                                        ||     checkClass [ScopedCheck   37     ┊   dvmDumpThread(dvmThreadSelf(), false);                                                                      ||     checkClassName [ScopedC   38     ┊   dvmAbort();                                                                                                 ||     checkFieldTypeForGet [S   39     }                                                                                                               ||     checkFieldTypeForSet [S   40 }
ここはすでにdumpの情报、38行を见て、dvdはもうすぐ退出します.
では、abortMaybe()はどこで呼び出されたのでしょうか.0003 dd 36に対応するコードがどこにあるか見てみましょう.
lw@pub:~/rt95/e6700a/project/kernel/android/JB/out/target/product/rtd299x_tv030/symbols/system/lib$ arm-none-linux-gnueabi-addr2line -aCfe libdvm.so 0003dd36
0x0003dd36 Check_CallStaticBooleanMethodV/home/lw/rt95/e6700a/project/kernel/android/JB/dalvik/vm/CheckJni.cpp:1671
チェックを呼び出しているのが見えましたCallStaticBooleanMethodV関数
もう一度見てみろcpp 1671行目:
CALL(jboolean, Boolean, jboolean result, result=, NON_VOID_RETURN("Z", jboolean), "Z"); 
ここはちょっと困惑していますが、ここのコードはCheckではありません.CallStaticBooleanMethodV関数ですね.ただのCALLマクロです.展開された関数が呼び出し場所だったはずです.その時は思わなかったのですが、ちょっと迷っていました.どこでabortMaybe()が呼び出されたのか分かりませんでした.
後で迂回する方法を採用して、スタックを出す前のlogは関数を呼び出す手がかりがありますか?突然ロゴに
7629 W/dalvikvm( 4929): JNI WARNING: expected return type 'Z'  7630 W/dalvikvm( 4929):              calling Lcom/qqgame/MTLoginAdapter/JNIInterface;.SetMStartedFromHallJNI (Z)V  7631 W/dalvikvm( 4929):              in Lcom/qqgame/MTSDK/MTTimer;.nativeOnTimer:(I)V (CallStaticBooleanMethodV)  7632 I/dalvikvm( 4929): "GLThread 193"prio=5 tid=15 NATIVE  7633 I/dalvikvm( 4929):   | group="main"sCount=0 dsCount=0 obj=0x428363b0 self=0x72220df8  7634 I/dalvikvm( 4929):   | sysTid=4946 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=1914544320  7635 I/dalvikvm( 4929):|state=R schedstat=(4550392204 4687113569 196650)utm=360 stm=94 core=1ここにwarningがあり、CheckJni.cppは「expected return type」を検索し、1つの場所しかないことを発見しました.
 384     void checkSig(jmethodID methodID, const char* expectedType, bool isStatic) {                                    ||     checkArray [ScopedCheck
 385     ┊   const Method* method = (const Method*) methodID;                                                            ||     checkCallResultCommon
 386     ┊   bool printWarn = false;                                                                                     ||     checkClass [ScopedCheck
 387                                                                                                                     ||     checkClassName [ScopedC
 388     ┊   if (*expectedType != method->shorty[0]) {                                                                   ||     checkFieldTypeForGet [S
 389     ┊   ┊   ALOGW("JNI WARNING: <span style="background-color: rgb(0, 0, 0);"><span style="color:#33CC00;">expected return type '%s</span></span>'", expectedType);                                          ||     checkFieldTypeForSet [S
 390     ┊   ┊   <span style="background-color: rgb(0, 0, 0);"><span style="color:#009900;">printWarn = true</span></span>;                                                                                       ||     checkInstance [ScopedCh
 391     ┊   } else if (isStatic && !dvmIsStaticMethod(method)) {                                                        ||     checkInstanceFieldID [S
 392     ┊   ┊   if (isStatic) {                                                                                         ||     checkLengthPositive [Sc
 393     ┊   ┊   ┊   ALOGW("JNI WARNING: calling non-static method with static call");                                   ||     checkNonNull [ScopedChe
 394     ┊   ┊   } else {                                                                                                ||     checkObject [ScopedChec
 395     ┊   ┊   ┊   ALOGW("JNI WARNING: calling static method with non-static call");                                   ||     checkReleaseMode [Scope
 396     ┊   ┊   }                                                                                                       ||     checkSig [ScopedCheck] 
 397     ┊   ┊   printWarn = true;                                                                                       ||     checkStaticFieldID [Sco
 398     ┊   }                                                                                                           ||     checkStaticMethod [Scop
 399                                                                                                                     ||     checkString [ScopedChec
 400     ┊   if (<span style="background-color: rgb(0, 0, 0);"><span style="color:#33CC00;">printWarn</span></span>) {                                                                                            ||     checkThread [ScopedChec
 401     ┊   ┊   char* desc = dexProtoCopyMethodDescriptor(&method->prototype);                                          ||     checkUtfBytes [ScopedCh
 402     ┊   ┊   ALOGW("             calling %s.%s %s", method->clazz->descriptor, method->name, desc);                  ||     checkUtfString [ScopedC
 403     ┊   ┊   free(desc);                                                                                             ||     checkVirtualMethod [Sco
 404     ┊   ┊   showLocation();                                                                                         ||     create [GuardedCopy]
 405     ┊   ┊   <span style="background-color: rgb(0, 0, 0);"><span style="color:#33CC00;">abortMaybe()</span></span>;                                                                                           ||     createGuardedPACopy
 406     ┊   }                                                                                                           ||     debugAlloc [GuardedCopy
 407     } 

jniは呼び出し時にチェックします.ここではbooleanの戻り値(Zはbooleanを表します)が必要ですが、下位jniはvoidを返したはずです.jniは自分のsoを適用しているので、ソースコードも見えません.
原因が分かりました.どうやって修正しますか.二つの案があります.
1.アプリケーションにjniを修正させる
2. システムの中で修正して、このような致命的なwarning検査の中で、dvmAbort()を呼び出しません.
に見える
  35 static void abortMaybe() {                                                                                          ||     checkCallResultCommon   36     if (!gDvmJni.warnOnly) {                                                                                        ||     checkClass [ScopedCheck   37     ┊   dvmDumpThread(dvmThreadSelf(), false);                                                                      ||     checkClassName [ScopedC   38     ┊   dvmAbort();                                                                                                 ||     checkFieldTypeForGet [S   39     }                                                                                                               ||     checkFieldTypeForSet [S   40 }
ここに標識がありますgDvmJniwarnOnly,trueであればdvmAbort()は呼び出されない.
いろいろ探して、やっと修正gDvmJniを見つけた.warnOnlyの方法:
プロジェクトを再コンパイルするときに、
PRODUCT_PROPERTY_OVERRIDES += dalvik.vm.jniopts=warnonly
OKです.