有个应用再登录的时候突然退出,而应用说再其他平台上都是好的,所以是系统rom的问题.先看看log再说
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<MTGame:: TModuleImpl<MTGame::ITimerManagerProxy, MTGame::CTimerManagerProxy, 1l> >::FireEvent<MTGame::ITimerManagerProxyEvent, unsigned int>(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/rt95/e6700a/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行了么,dvm就要退出了.
那么是哪里调用了abortMaybe()呢, 我们再看看0003dd36 对应的代码是那里,
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
看到了是调用Check_CallStaticBooleanMethodV函数
再看看CheckJni.cpp第1671行:
CALL(jboolean, Boolean, jboolean result, result=, NON_VOID_RETURN("Z", jboolean), "Z");
这里有点困惑,这里的代码不是Check_CallStaticBooleanMethodV函数啊,只是一个CALL宏,展开的函数应该就是调用地方.当时没想到这点,有点迷茫了,看不出是哪里调用了abortMaybe()了.
后来采取了一种迂回的方法, 打出堆栈前的log会不会有调用函数的线索呢? 突然发现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 19650 ) utm=360 stm=94 core=1
这里有个warning, 在CheckJni.cpp搜索"expected return type", 发现只有一个地方,
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 }
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 }
这里有一个标识,gDvmJni.warnOnly,只要为true的话, 那么就不会调用dvmAbort()了.
经过多方寻找,终于找到了修改gDvmJni.warnOnly的方法:
再编译项目的时候,加上
PRODUCT_PROPERTY_OVERRIDES += dalvik.vm.jniopts=warnonly
就ok了.