美文网首页tensorflow
Android JNI开发(二)

Android JNI开发(二)

作者: qiuxintai | 来源:发表于2020-08-14 18:54 被阅读0次

    引言

    Android JNI 开发 (一) 一文中介绍了JNI的数据结构和接口函数等基础知识。但是开发过程中只有JNI基础知识是不够的,为了避免遇到问题手足无措,我们还需要具备一定的调试和解决问题的能力,本文就简单介绍JNI的调试工具和调试方法。

    1. Log

    Log是最基础、最常用的调试工具。即使在其它工具都不能奏效的情况下,Log却往往还能提供一些蛛丝马迹帮助我们分析和解决问题。JNI 中使用 Log很简单,只要导入 android/log.h,然后就可以调用其中的__android_log_print等接口函数来输出日志到logcat,效果与java中的android.util.Log的输出效果几乎完全一致。与java中的android.util.Log一样,也可以为日志定义TAG。例如:

    #include <jni.h>
    #include <android/log.h>
    
    #define LOG_TAG "MyApp"
    #define LOGD(format, ...)  __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, format, ##__VA_ARGS__)
    #define LOGE(format, ...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, format, ##__VA_ARGS__)
    #define LOGI(format, ...)  __android_log_print(ANDROID_LOG_INFO,  LOG_TAG, format, ##__VA_ARGS__)
    #define LOGW(format, ...)  __android_log_print(ANDROID_LOG_WARN, LOG_TAG, format, ##__VA_ARGS__)
    
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_qxt_myapp_MainActivity_testObject(JNIEnv *env, jobject thiz) {
        jclass clazz = env->FindClass("com/qxt/myapp/MainActivity");
        if (clazz != nullptr) {
            //Access object field
            jfieldID ageID = env->GetFieldID(clazz, "age", "I");
            jint ageInt = (jint) env->GetIntField(thiz, ageID);
    
            //Access object method
            jmethodID getAgeID = env->GetMethodID(clazz, "getAge", "(Ljava/lang/String;)Ljava/lang/String;");
            jstring nameStr = env->NewStringUTF("JNI");
            jstring msgStr = (jstring) env->CallObjectMethod(thiz, getAgeID, nameStr);
    
            //Use string, convert jstring to char sequence
            char *name = (char *) env->GetStringUTFChars(nameStr, NULL);
            char *msg = (char *) env->GetStringUTFChars(msgStr, NULL);
            LOGD("[testObject] message:%s; age:%d", msg, ageInt);
    
            env->ReleaseStringUTFChars(nameStr, name);
            env->ReleaseStringUTFChars(msgStr, msg);
        }
        env->DeleteLocalRef(clazz);
    }
    

    日志输出:

    2020-08-14 14:17:47.811 17164-17164/com.qxt.myapp D/MyApp: [testObject] message:Hello JNI, I'm java method getAge; age:20
    

    2. 异常处理

    同java开发一样,异常处理也是JNI开发中很重要的工作,只有妥善了处理了异常,程序才能顺利执行。JNI代码执行时如果遇到异常,程序并不会停止执行,而是会继续执行下一句代码,直到崩溃发生。Java中捕获和处理异常有try-catch机制,JNI也提供了类似的机制。它就是在Android JNI 开发 (一) 的第9节中我们提到过的ExceptionCheck。JNI提供了ExceptionCheck、ExceptionDescribe等接口,它们可以捕获异常,并将异常的堆栈信息输出到logcat。例如:
    MainActivity:

        public String getName(String name) {
            throw new IllegalArgumentException("test");
        }
    
        public native void testException();
    

    native-lib.cpp:

    extern "C"
    JNIEXPORT void JNICALL
    Java_com_qxt_myapp_MainActivity_testException(JNIEnv *env, jobject thiz) {
        jclass clazz = env->FindClass("com/qxt/myapp/MainActivity");
        if (clazz != nullptr) {
            //Access object method
            jmethodID getName = env->GetMethodID(clazz, "getName", "(Ljava/lang/String;)Ljava/lang/String;");
            if (getName != nullptr) {
                jstring nameStr = env->NewStringUTF("JNI");
                jstring msgStr = (jstring) env->CallObjectMethod(thiz, getName, nameStr);
                if (env->ExceptionCheck()) {
                    LOGD("[testException] found an exception");
                    env->ExceptionDescribe();
                    env->ExceptionClear();
                }
            }
        }
        env->DeleteLocalRef(clazz);
    }
    

    在本地函数testException中我们调用了普通的Java方法getName,getName中会抛出一个异常IllegalArgumentException。运行一下这段代码,我们可以在logcat中发现异常的堆栈信息:

    2020-08-14 15:02:20.790 18893-18893/com.qxt.myapp D/MyApp: [testException] found an exception
    2020-08-14 15:02:20.791 18893-18893/com.qxt.myapp W/System.err: java.lang.IllegalArgumentException: test
    2020-08-14 15:02:20.791 18893-18893/com.qxt.myapp W/System.err:     at com.qxt.myapp.MainActivity.getName(MainActivity.java:61)
    2020-08-14 15:02:20.791 18893-18893/com.qxt.myapp W/System.err:     at com.qxt.myapp.MainActivity.testException(Native Method)
    2020-08-14 15:02:20.791 18893-18893/com.qxt.myapp W/System.err:     at com.qxt.myapp.MainActivity.onCreate(MainActivity.java:39)
    2020-08-14 15:02:20.791 18893-18893/com.qxt.myapp W/System.err:     at android.app.Activity.performCreate(Activity.java:7136)
    2020-08-14 15:02:20.791 18893-18893/com.qxt.myapp W/System.err:     at android.app.Activity.performCreate(Activity.java:7127)
    2020-08-14 15:02:20.791 18893-18893/com.qxt.myapp W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
    2020-08-14 15:02:20.792 18893-18893/com.qxt.myapp W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2924)
    2020-08-14 15:02:20.792 18893-18893/com.qxt.myapp W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3079)
    2020-08-14 15:02:20.792 18893-18893/com.qxt.myapp W/System.err:     at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
    2020-08-14 15:02:20.792 18893-18893/com.qxt.myapp W/System.err:     at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
    2020-08-14 15:02:20.792 18893-18893/com.qxt.myapp W/System.err:     at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
    2020-08-14 15:02:20.792 18893-18893/com.qxt.myapp W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1836)
    2020-08-14 15:02:20.792 18893-18893/com.qxt.myapp W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:106)
    2020-08-14 15:02:20.792 18893-18893/com.qxt.myapp W/System.err:     at android.os.Looper.loop(Looper.java:193)
    2020-08-14 15:02:20.792 18893-18893/com.qxt.myapp W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6702)
    2020-08-14 15:02:20.792 18893-18893/com.qxt.myapp W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
    2020-08-14 15:02:20.792 18893-18893/com.qxt.myapp W/System.err:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    2020-08-14 15:02:20.792 18893-18893/com.qxt.myapp W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:911)
    

    假如我们把ExceptionCheck这个判断的代码注释掉,不捕获这个异常,再次运行这段代码,就会出现崩溃:

    2020-08-14 14:58:05.597 16085-16085/com.qxt.myapp E/AndroidRuntime: FATAL EXCEPTION: main
        Process: com.qxt.myapp, PID: 16085
        java.lang.RuntimeException: Unable to start activity ComponentInfo{com.qxt.myapp/com.qxt.myapp.MainActivity}: java.lang.IllegalArgumentException: test
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2944)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3079)
            at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
            at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
            at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1836)
            at android.os.Handler.dispatchMessage(Handler.java:106)
            at android.os.Looper.loop(Looper.java:193)
            at android.app.ActivityThread.main(ActivityThread.java:6702)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:911)
         Caused by: java.lang.IllegalArgumentException: test
            at com.qxt.myapp.MainActivity.getName(MainActivity.java:61)
            at com.qxt.myapp.MainActivity.testException(Native Method)
            at com.qxt.myapp.MainActivity.onCreate(MainActivity.java:39)
            at android.app.Activity.performCreate(Activity.java:7136)
            at android.app.Activity.performCreate(Activity.java:7127)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2924)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3079) 
            at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
            at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
            at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1836) 
            at android.os.Handler.dispatchMessage(Handler.java:106) 
            at android.os.Looper.loop(Looper.java:193) 
            at android.app.ActivityThread.main(ActivityThread.java:6702) 
            at java.lang.reflect.Method.invoke(Native Method) 
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:911) 
    

    除了最常用的ExceptionCheck、ExceptionDescribe、ExceptionClear等接口外,JNI还有ExceptionOccurred接口,它也可以用来确定是否发生异常,以便我们妥善处理遇到的异常。

    3. 断点

    现在使用Android Studio开发JNI是非常方便的,同java代码一样,Android Studio也支持在JNI的C/C++中打断点进行调试。调试的步骤也基本是一样的:

    • 在Android Studio代码编辑器的左侧(行号之后的空白处)点击鼠标打上断点。
    • 点击小虫图标(Debug app)或者快捷键Shift +F9进行调试。
    • 等待调试运行起来后,可以打开底部的Debug面板进行操作,可以跳到下一行,跳进某个函数、跳到下个断点、停止调试等等。

    想了解更多调试相关的知识请参考官网:https://developer.android.google.cn/studio/debug

    4. ndk-stack

    通常情况下,native的崩溃和异常比java更不直观,比较难排查,但是我们可以借助NDK中的ndk-stack和addr2line两个工具来还原堆栈信息,找到出问题的代码所在的文件及行号。本节我们先来介绍ndk-stack,下节介绍addr2line。
    首先,我们先来故意制造一个崩溃:

    extern "C"
    JNIEXPORT void JNICALL
    Java_com_qxt_myapp_MainActivity_testCrash(JNIEnv *env, jobject thiz) {
        int* i = NULL;
        i[0] = 0;//实际CPP源文件158行
    }
    

    运行这段代码后出现崩溃,我们抓到的日志是这样的:

    2020-08-14 03:36:30.656 8866-8866/? I/crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstone
    2020-08-14 03:36:30.672 8866-8866/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    2020-08-14 03:36:30.672 8866-8866/? A/DEBUG: Native Crash TIME: 99296997
    2020-08-14 03:36:30.672 8866-8866/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    2020-08-14 03:36:30.672 8866-8866/? A/DEBUG: Build fingerprint: 'Symphony/i98/i98:10/QP1A.190711.020/55:user/release-keys'
    2020-08-14 03:36:30.672 8866-8866/? A/DEBUG: Revision: '0'
    2020-08-14 03:36:30.672 8866-8866/? A/DEBUG: ABI: 'arm64'
    2020-08-14 03:36:30.673 8866-8866/? A/DEBUG: Timestamp: 2020-08-14 01:36:30+0600
    2020-08-14 03:36:30.673 8866-8866/? A/DEBUG: pid: 8819, tid: 8819, name: com.qxt.myapp  >>> com.qxt.myapp <<<
    2020-08-14 03:36:30.673 8866-8866/? A/DEBUG: uid: 10158
    2020-08-14 03:36:30.673 8866-8866/? A/DEBUG: signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
    2020-08-14 03:36:30.673 8866-8866/? A/DEBUG: Cause: null pointer dereference
    2020-08-14 03:36:30.673 8866-8866/? A/DEBUG:     x0  0000007e55dd66c0  x1  0000007fc96ef4a4  x2  0000007fc96f0690  x3  0000007dd0b0a4f0
    2020-08-14 03:36:30.673 8866-8866/? A/DEBUG:     x4  0000007fc96ef5a0  x5  0000007dd0dbf874  x6  0000007fc96ef600  x7  0000000070400480
    2020-08-14 03:36:30.673 8866-8866/? A/DEBUG:     x8  0000000000000000  x9  f4d9345c68992d53  x10 0000000000430000  x11 0000007dc0000000
    2020-08-14 03:36:30.673 8866-8866/? A/DEBUG:     x12 0000000000000030  x13 0000000004a1c818  x14 0000000000000006  x15 ffffffffffffffff
    2020-08-14 03:36:30.674 8866-8866/? A/DEBUG:     x16 0000007dc05557c8  x17 0000007e530d38c0  x18 0000007e56690000  x19 0000007e55d19c00
    2020-08-14 03:36:30.674 8866-8866/? A/DEBUG:     x20 0000000000000000  x21 0000007e55d19c00  x22 0000007fc96ef710  x23 0000007dc82970ba
    2020-08-14 03:36:30.674 8866-8866/? A/DEBUG:     x24 0000000000000004  x25 0000007e55ed4020  x26 0000007e55d19cb0  x27 0000000000000001
    2020-08-14 03:36:30.674 8866-8866/? A/DEBUG:     x28 0000007fc96ef4a0  x29 0000007fc96ef4a0
    2020-08-14 03:36:30.674 8866-8866/? A/DEBUG:     sp  0000007fc96ef460  lr  0000007dd0965354  pc  0000007dc05557e0
    2020-08-14 03:36:31.437 8866-8866/? A/DEBUG: backtrace:
    2020-08-14 03:36:31.437 8866-8866/? A/DEBUG:       #00 pc 00000000000107e0  /data/app/com.qxt.myapp-mpm2LPzx1fA48I99gUSq-A==/base.apk!libnative-lib.so (offset 0x193000) (Java_com_qxt_myapp_MainActivity_testCrash+24) (BuildId: 9d5b5e236c849a878072b6e11ce4d15b1860df0f)
    2020-08-14 03:36:31.438 8866-8866/? A/DEBUG:       #01 pc 000000000013f350  /apex/com.android.runtime/lib64/libart.so (art_quick_generic_jni_trampoline+144) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.438 8866-8866/? A/DEBUG:       #02 pc 0000000000136334  /apex/com.android.runtime/lib64/libart.so (art_quick_invoke_stub+548) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.438 8866-8866/? A/DEBUG:       #03 pc 000000000014506c  /apex/com.android.runtime/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+244) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.438 8866-8866/? A/DEBUG:       #04 pc 00000000002df720  /apex/com.android.runtime/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+384) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.438 8866-8866/? A/DEBUG:       #05 pc 00000000002daa00  /apex/com.android.runtime/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+912) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.438 8866-8866/? A/DEBUG:       #06 pc 0000000000597d6c  /apex/com.android.runtime/lib64/libart.so (MterpInvokeVirtual+648) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.438 8866-8866/? A/DEBUG:       #07 pc 0000000000130814  /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_virtual+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.438 8866-8866/? A/DEBUG:       #08 pc 0000000000010c34  [anon:dalvik-classes2.dex extracted in memory from /data/app/com.qxt.myapp-mpm2LPzx1fA48I99gUSq-A==/base.apk!classes2.dex] (com.qxt.myapp.MainActivity$1.onClick+4)
    2020-08-14 03:36:31.438 8866-8866/? A/DEBUG:       #09 pc 0000000000599870  /apex/com.android.runtime/lib64/libart.so (MterpInvokeInterface+1740) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.438 8866-8866/? A/DEBUG:       #10 pc 0000000000130a14  /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_interface+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.439 8866-8866/? A/DEBUG:       #11 pc 00000000001a7a0e  /system/framework/framework.jar (android.view.View.performClick+34)
    2020-08-14 03:36:31.439 8866-8866/? A/DEBUG:       #12 pc 000000000059807c  /apex/com.android.runtime/lib64/libart.so (MterpInvokeVirtual+1432) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.439 8866-8866/? A/DEBUG:       #13 pc 0000000000130814  /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_virtual+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.439 8866-8866/? A/DEBUG:       #14 pc 00000000001a7a86  /system/framework/framework.jar (android.view.View.performClickInternal+6)
    2020-08-14 03:36:31.439 8866-8866/? A/DEBUG:       #15 pc 000000000059a40c  /apex/com.android.runtime/lib64/libart.so (MterpInvokeDirect+1168) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.439 8866-8866/? A/DEBUG:       #16 pc 0000000000130914  /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_direct+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.439 8866-8866/? A/DEBUG:       #17 pc 00000000001a3304  /system/framework/framework.jar (android.view.View.access$3500)
    2020-08-14 03:36:31.439 8866-8866/? A/DEBUG:       #18 pc 000000000059ac18  /apex/com.android.runtime/lib64/libart.so (MterpInvokeStatic+1136) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.439 8866-8866/? A/DEBUG:       #19 pc 0000000000130994  /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_static+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.439 8866-8866/? A/DEBUG:       #20 pc 0000000000182b28  /system/framework/framework.jar (android.view.View$PerformClick.run+16)
    2020-08-14 03:36:31.439 8866-8866/? A/DEBUG:       #21 pc 0000000000599870  /apex/com.android.runtime/lib64/libart.so (MterpInvokeInterface+1740) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.439 8866-8866/? A/DEBUG:       #22 pc 0000000000130a14  /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_interface+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.439 8866-8866/? A/DEBUG:       #23 pc 000000000030435c  /system/framework/framework.jar (android.os.Handler.handleCallback+4)
    2020-08-14 03:36:31.439 8866-8866/? A/DEBUG:       #24 pc 000000000059ac18  /apex/com.android.runtime/lib64/libart.so (MterpInvokeStatic+1136) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.440 8866-8866/? A/DEBUG:       #25 pc 0000000000130994  /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_static+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.440 8866-8866/? A/DEBUG:       #26 pc 00000000003041c8  /system/framework/framework.jar (android.os.Handler.dispatchMessage+8)
    2020-08-14 03:36:31.440 8866-8866/? A/DEBUG:       #27 pc 000000000059807c  /apex/com.android.runtime/lib64/libart.so (MterpInvokeVirtual+1432) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.440 8866-8866/? A/DEBUG:       #28 pc 0000000000130814  /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_virtual+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.440 8866-8866/? A/DEBUG:       #29 pc 000000000032a672  /system/framework/framework.jar (android.os.Looper.loop+466)
    2020-08-14 03:36:31.440 8866-8866/? A/DEBUG:       #30 pc 000000000059ac18  /apex/com.android.runtime/lib64/libart.so (MterpInvokeStatic+1136) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.440 8866-8866/? A/DEBUG:       #31 pc 0000000000130994  /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_static+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.440 8866-8866/? A/DEBUG:       #32 pc 0000000000193346  /system/framework/framework.jar (android.app.ActivityThread.main+430)
    2020-08-14 03:36:31.440 8866-8866/? A/DEBUG:       #33 pc 00000000002b036c  /apex/com.android.runtime/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEbb.llvm.6052660250618262909+240) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.440 8866-8866/? A/DEBUG:       #34 pc 0000000000589374  /apex/com.android.runtime/lib64/libart.so (artQuickToInterpreterBridge+1012) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.440 8866-8866/? A/DEBUG:       #35 pc 000000000013f468  /apex/com.android.runtime/lib64/libart.so (art_quick_to_interpreter_bridge+88) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.440 8866-8866/? A/DEBUG:       #36 pc 00000000001365b8  /apex/com.android.runtime/lib64/libart.so (art_quick_invoke_static_stub+568) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.440 8866-8866/? A/DEBUG:       #37 pc 000000000014508c  /apex/com.android.runtime/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+276) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.440 8866-8866/? A/DEBUG:       #38 pc 00000000004a9674  /apex/com.android.runtime/lib64/libart.so (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+104) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.440 8866-8866/? A/DEBUG:       #39 pc 00000000004ab09c  /apex/com.android.runtime/lib64/libart.so (art::InvokeMethod(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned long)+1476) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.441 8866-8866/? A/DEBUG:       #40 pc 0000000000437ab0  /apex/com.android.runtime/lib64/libart.so (art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobjectArray*)+52) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.441 8866-8866/? A/DEBUG:       #41 pc 00000000006d3374  /system/framework/arm64/boot.oat (art_jni_trampoline+180) (BuildId: 7e6536fb26a76f1b84b0c56847c93a5238a88664)
    2020-08-14 03:36:31.441 8866-8866/? A/DEBUG:       #42 pc 0000000000136334  /apex/com.android.runtime/lib64/libart.so (art_quick_invoke_stub+548) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.441 8866-8866/? A/DEBUG:       #43 pc 000000000014506c  /apex/com.android.runtime/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+244) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.441 8866-8866/? A/DEBUG:       #44 pc 00000000002df720  /apex/com.android.runtime/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+384) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.441 8866-8866/? A/DEBUG:       #45 pc 00000000002daa00  /apex/com.android.runtime/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+912) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.441 8866-8866/? A/DEBUG:       #46 pc 0000000000597d6c  /apex/com.android.runtime/lib64/libart.so (MterpInvokeVirtual+648) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.441 8866-8866/? A/DEBUG:       #47 pc 0000000000130814  /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_virtual+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.441 8866-8866/? A/DEBUG:       #48 pc 0000000000356f36  /system/framework/framework.jar (com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run+22)
    2020-08-14 03:36:31.441 8866-8866/? A/DEBUG:       #49 pc 00000000002b036c  /apex/com.android.runtime/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEbb.llvm.6052660250618262909+240) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.441 8866-8866/? A/DEBUG:       #50 pc 0000000000589374  /apex/com.android.runtime/lib64/libart.so (artQuickToInterpreterBridge+1012) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.441 8866-8866/? A/DEBUG:       #51 pc 000000000013f468  /apex/com.android.runtime/lib64/libart.so (art_quick_to_interpreter_bridge+88) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.441 8866-8866/? A/DEBUG:       #52 pc 0000000002116c6c  /system/framework/arm64/boot-framework.oat (com.android.internal.os.ZygoteInit.main+2076) (BuildId: aa37c86acfca1958ca3d1f1423214af04ae501f8)
    2020-08-14 03:36:31.441 8866-8866/? A/DEBUG:       #53 pc 00000000001365b8  /apex/com.android.runtime/lib64/libart.so (art_quick_invoke_static_stub+568) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.441 8866-8866/? A/DEBUG:       #54 pc 000000000014508c  /apex/com.android.runtime/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+276) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.441 8866-8866/? A/DEBUG:       #55 pc 00000000004a9674  /apex/com.android.runtime/lib64/libart.so (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+104) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.442 8866-8866/? A/DEBUG:       #56 pc 00000000004a92e0  /apex/com.android.runtime/lib64/libart.so (art::InvokeWithVarArgs(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, std::__va_list)+408) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.442 8866-8866/? A/DEBUG:       #57 pc 00000000003b67b4  /apex/com.android.runtime/lib64/libart.so (art::JNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, std::__va_list)+628) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    2020-08-14 03:36:31.442 8866-8866/? A/DEBUG:       #58 pc 00000000000bf560  /system/lib64/libandroid_runtime.so (_JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...)+116) (BuildId: 68ffb68d2f18afa0e7728e1e0e6d81c3)
    2020-08-14 03:36:31.442 8866-8866/? A/DEBUG:       #59 pc 00000000000c23e8  /system/lib64/libandroid_runtime.so (android::AndroidRuntime::start(char const*, android::Vector<android::String8> const&, bool)+780) (BuildId: 68ffb68d2f18afa0e7728e1e0e6d81c3)
    2020-08-14 03:36:31.442 8866-8866/? A/DEBUG:       #60 pc 00000000000034e0  /system/bin/app_process64 (main+1168) (BuildId: 17c28587f58ba3244a8f195cab83135f)
    2020-08-14 03:36:31.442 8866-8866/? A/DEBUG:       #61 pc 000000000007d798  /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+108) (BuildId: 676a709a0ee633ec9cf6ab05ec6410ae)
    2020-08-14 03:36:32.103 8819-8819/com.qxt.myapp I/DEBUG: Crash thread dumpable
    

    可以看到,日志里面有一些内存地址,还指明了出错的文件及函数:
    Java_com_qxt_myapp_MainActivity_testCrash+24
    但是却没有指明具体的出错的行号。虽然即使没有行号我们也可以结合源代码分析出错的位置,但是如果有具体的行号,我们就可以更加迅速的定位问题。

    ndk-stack是NDK中的一个工具,它允许把文件或者logcat当做输入,用来还原错误或异常的内存地址所对应的堆栈信息,还原后可以很直观的看到出问题的代码行号。还原时ndk-stack需要指定保留符号链接的so的路径。
    文件作为输入还原:

    qxt@ubuntu:~/code/open-source/MyApp$ adb logcat > error.txt
    qxt@ubuntu:~/code/open-source/MyApp$ ndk-stack -sym app/build/intermediates/cmake/debug/obj/arm64-v8a/ -dump error.txt
    

    logcat当做输入还原:

    qxt@ubuntu:~/code/open-source/MyApp$ adb logcat | ndk-stack -sym app/build/intermediates/cmake/debug/obj/arm64-v8a/
    

    还原后:

    ********** Crash dump: **********
    Build fingerprint: 'Symphony/i98/i98:10/QP1A.190711.020/55:user/release-keys'
    #00 0x00000000000107e0 /data/app/com.qxt.myapp-mpm2LPzx1fA48I99gUSq-A==/base.apk!libnative-lib.so (offset 0x193000) (Java_com_qxt_myapp_MainActivity_testCrash+24) (BuildId: 9d5b5e236c849a878072b6e11ce4d15b1860df0f)
                                                                                                       Java_com_qxt_myapp_MainActivity_testCrash
                                                                                                       /mnt/sdb/home/qxt/code/open-source/MyApp/app/src/main/cpp/native-lib.cpp:158:10
    #01 0x000000000013f350 /apex/com.android.runtime/lib64/libart.so (art_quick_generic_jni_trampoline+144) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #02 0x0000000000136334 /apex/com.android.runtime/lib64/libart.so (art_quick_invoke_stub+548) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #03 0x000000000014506c /apex/com.android.runtime/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+244) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #04 0x00000000002df720 /apex/com.android.runtime/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+384) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #05 0x00000000002daa00 /apex/com.android.runtime/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+912) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #06 0x0000000000597d6c /apex/com.android.runtime/lib64/libart.so (MterpInvokeVirtual+648) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #07 0x0000000000130814 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_virtual+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #08 0x0000000000010c34 [anon:dalvik-classes2.dex extracted in memory from /data/app/com.qxt.myapp-mpm2LPzx1fA48I99gUSq-A==/base.apk!classes2.dex] (com.qxt.myapp.MainActivity$1.onClick+4)
    #09 0x0000000000599870 /apex/com.android.runtime/lib64/libart.so (MterpInvokeInterface+1740) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #10 0x0000000000130a14 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_interface+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #11 0x00000000001a7a0e /system/framework/framework.jar (android.view.View.performClick+34)
    #12 0x000000000059807c /apex/com.android.runtime/lib64/libart.so (MterpInvokeVirtual+1432) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #13 0x0000000000130814 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_virtual+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #14 0x00000000001a7a86 /system/framework/framework.jar (android.view.View.performClickInternal+6)
    #15 0x000000000059a40c /apex/com.android.runtime/lib64/libart.so (MterpInvokeDirect+1168) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #16 0x0000000000130914 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_direct+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #17 0x00000000001a3304 /system/framework/framework.jar (android.view.View.access$3500)
    #18 0x000000000059ac18 /apex/com.android.runtime/lib64/libart.so (MterpInvokeStatic+1136) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #19 0x0000000000130994 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_static+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #20 0x0000000000182b28 /system/framework/framework.jar (android.view.View$PerformClick.run+16)
    #21 0x0000000000599870 /apex/com.android.runtime/lib64/libart.so (MterpInvokeInterface+1740) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #22 0x0000000000130a14 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_interface+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #23 0x000000000030435c /system/framework/framework.jar (android.os.Handler.handleCallback+4)
    #24 0x000000000059ac18 /apex/com.android.runtime/lib64/libart.so (MterpInvokeStatic+1136) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #25 0x0000000000130994 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_static+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #26 0x00000000003041c8 /system/framework/framework.jar (android.os.Handler.dispatchMessage+8)
    #27 0x000000000059807c /apex/com.android.runtime/lib64/libart.so (MterpInvokeVirtual+1432) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #28 0x0000000000130814 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_virtual+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #29 0x000000000032a672 /system/framework/framework.jar (android.os.Looper.loop+466)
    #30 0x000000000059ac18 /apex/com.android.runtime/lib64/libart.so (MterpInvokeStatic+1136) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #31 0x0000000000130994 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_static+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #32 0x0000000000193346 /system/framework/framework.jar (android.app.ActivityThread.main+430)
    #33 0x00000000002b036c /apex/com.android.runtime/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEbb.llvm.6052660250618262909+240) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #34 0x0000000000589374 /apex/com.android.runtime/lib64/libart.so (artQuickToInterpreterBridge+1012) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #35 0x000000000013f468 /apex/com.android.runtime/lib64/libart.so (art_quick_to_interpreter_bridge+88) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #36 0x00000000001365b8 /apex/com.android.runtime/lib64/libart.so (art_quick_invoke_static_stub+568) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #37 0x000000000014508c /apex/com.android.runtime/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+276) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #38 0x00000000004a9674 /apex/com.android.runtime/lib64/libart.so (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+104) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #39 0x00000000004ab09c /apex/com.android.runtime/lib64/libart.so (art::InvokeMethod(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned long)+1476) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #40 0x0000000000437ab0 /apex/com.android.runtime/lib64/libart.so (art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobjectArray*)+52) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #41 0x00000000006d3374 /system/framework/arm64/boot.oat (art_jni_trampoline+180) (BuildId: 7e6536fb26a76f1b84b0c56847c93a5238a88664)
    #42 0x0000000000136334 /apex/com.android.runtime/lib64/libart.so (art_quick_invoke_stub+548) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #43 0x000000000014506c /apex/com.android.runtime/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+244) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #44 0x00000000002df720 /apex/com.android.runtime/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+384) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #45 0x00000000002daa00 /apex/com.android.runtime/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+912) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #46 0x0000000000597d6c /apex/com.android.runtime/lib64/libart.so (MterpInvokeVirtual+648) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #47 0x0000000000130814 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_virtual+20) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #48 0x0000000000356f36 /system/framework/framework.jar (com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run+22)
    #49 0x00000000002b036c /apex/com.android.runtime/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEbb.llvm.6052660250618262909+240) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #50 0x0000000000589374 /apex/com.android.runtime/lib64/libart.so (artQuickToInterpreterBridge+1012) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #51 0x000000000013f468 /apex/com.android.runtime/lib64/libart.so (art_quick_to_interpreter_bridge+88) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #52 0x0000000002116c6c /system/framework/arm64/boot-framework.oat (com.android.internal.os.ZygoteInit.main+2076) (BuildId: aa37c86acfca1958ca3d1f1423214af04ae501f8)
    #53 0x00000000001365b8 /apex/com.android.runtime/lib64/libart.so (art_quick_invoke_static_stub+568) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #54 0x000000000014508c /apex/com.android.runtime/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+276) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #55 0x00000000004a9674 /apex/com.android.runtime/lib64/libart.so (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+104) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #56 0x00000000004a92e0 /apex/com.android.runtime/lib64/libart.so (art::InvokeWithVarArgs(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, std::__va_list)+408) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #57 0x00000000003b67b4 /apex/com.android.runtime/lib64/libart.so (art::JNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, std::__va_list)+628) (BuildId: 3202c08af4daa021ee265eb0c1cc0a00)
    #58 0x00000000000bf560 /system/lib64/libandroid_runtime.so (_JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...)+116) (BuildId: 68ffb68d2f18afa0e7728e1e0e6d81c3)
    #59 0x00000000000c23e8 /system/lib64/libandroid_runtime.so (android::AndroidRuntime::start(char const*, android::Vector<android::String8> const&, bool)+780) (BuildId: 68ffb68d2f18afa0e7728e1e0e6d81c3)
    #60 0x00000000000034e0 /system/bin/app_process64 (main+1168) (BuildId: 17c28587f58ba3244a8f195cab83135f)
    #61 0x000000000007d798 /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+108) (BuildId: 676a709a0ee633ec9cf6ab05ec6410ae)
    Crash dump is completed
    

    可以看到,还原后能明确看到出错的行号为158行:
    /mnt/sdb/home/qxt/code/open-source/MyApp/app/src/main/cpp/native-lib.cpp:158:10

    5. addr2line

    addr2line也是NDK中的一个工具,它可以通过指定保留符号链接的so和出错的内存地址来还原出错代码的行号。我们从之前日志中可以找出错的内存地址:00000000000107e0。
    还原指令:

    qxt@ubuntu:~/dev/sdk/ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin$ ./aarch64-linux-android-addr2line -f -e ~/code/open-source/MyApp/app/build/intermediates/cmake/debug/obj/arm64-v8a/libnative-lib.so 00000000000107e0
    Java_com_qxt_myapp_MainActivity_testCrash
    /mnt/sdb/home/qxt/code/open-source/MyApp/app/src/main/cpp/native-lib.cpp:158
    

    可以看到,还原后也能明确看到出错的行号为158行。
    为什么是 00000000000107e0 这个地址呢?可以回到我们之前的出错日志,这个地址是对应我们加的libnative-lib.so的。当然,如果你拥有出错堆栈信息中所有的保留符号链接的so,堆栈的每一个地址对应一个保留符号链接的so,你都可以将它们还原成对应的行号。
    看到这里的童鞋大概都会发现点什么,是的,为了准确还原JNI异常或错误的行号,我们每发一个版本,都需要保存保留符号链接的so或者符号表文件。这个和Java混淆后每发一个版本都需要保留mapping.txt文件用来还原堆栈是类似的。

    6. 第三方工具

    除了NDK提供的工具以外,我们还可以接入第三方的工具包来处理native的崩溃和异常问题,比较优秀的有爱奇艺的xCrash和腾讯的Bugly。本质上它们都是通过ndk-stack或者addr2line类似的方法来实现的还原的。利用它们进行还原so错误时也需要指定保留符号链接的so或者符号表文件,java错误则需要指定mapping.txt 文件。例如,你可以利用Bugly的插件,它会扫描保留符号链接的so生成符号表文件(zip),然后自动将符号表文件(zip)及mapping.txt文件上传。除此之外,Bugly还能记录APP的各类异常或错误信息、运营信息等等,功能非常强大。爱奇艺的xCrash和腾讯的Bugly都有详细的接入文档,这里就不再赘述了。

    6.1 xCrash

    爱奇艺 xCrash: https://github.com/iqiyi/xCrash

    6.2 Bugly

    腾讯Bugly: https://bugly.qq.com/docs/utility-tools/plugin-gradle-bugly/

    7. 结语

    JNI的开发系列的两篇写到这里就写完了,都是很基础的JNI知识。尽管实际开发中需求千变万化,Bug千奇百怪,但只要掌握了基本的三板斧,日常的JNI开发工作就应该没有问题了。衷心祝愿耐心看完了我这两篇文章的童鞋们都能掌握JNI开发。

    8. 本文参考

    https://developer.android.google.cn/studio/debug
    https://developer.android.google.cn/ndk/guides/ndk-stack
    JNI Crash:异常定位与捕获处理

    欢迎交流、点赞、转载,码字不易,转载请注明出处。

    相关文章

      网友评论

        本文标题:Android JNI开发(二)

        本文链接:https://www.haomeiwen.com/subject/knzbdktx.html