Captura y análisis de Android NativeCrash

En el desarrollo de Android, NE siempre ha sido un problema que no se puede ignorar, pero es extremadamente difícil de resolver. La razón es que implica el desarrollo y el análisis de terminales cruzados. Debe estar familiarizado con el desarrollo de Java, C & C ++ y NDK, y La solución no es como las excepciones de Java, así que, claramente, para resolver algunas de las dudas, este artículo explorará los tres aspectos de la captura, análisis y restauración de NE.

1. Introducción a NE

El nombre completo de NE es NativeCrash, que es un error generado durante la ejecución de C o C ++. NE es diferente de los errores comunes de Java. El logcat ordinario no se puede restaurar directamente a una pila legible y, en general, no se puede depurar sin código fuente.

Por lo tanto, los ingenieros en la capa de aplicación diaria, incluso si tenemos registros de diagnóstico internos en la nube, generalmente ignorarán los errores de NE. Si se encuentran estos problemas, ¿un ingeniero que es una capa de aplicación y no comprende C ++ puede resolver la pila de restauración rápidamente? para localizar o solucionar los problemas de NE?

Lo siguiente se centrará en:

1.1 Entonces composición

Primero comprendamos la composición de so. Un so completo se compone de código C más información de depuración. Esta información de depuración registrará la tabla de comparación de todos los métodos en so, que es la tabla de correspondencia entre el nombre del método y su dirección barata, también llamada tabla de símbolos, que también se llama destripar y suele ser de mayor tamaño.

Por lo general, el bloque liberado debe pasar por una operación de eliminación, por lo que se eliminará la información de depuración de la sección posterior a la eliminación y se reducirá el tamaño de todo el bloque.

Como se muestra abajo:

Captura y análisis de Android NativeCrash

Puede ver la comparación de tamaño antes y después de la tira de la siguiente manera.

Captura y análisis de Android NativeCrash

Si no conoce NE o algo así, simplemente puede entender esta información de depuración como un archivo de mapeo en la ofuscación de código Java, y el análisis de pila solo se puede realizar si tiene este archivo de mapeo.

Si se pierde la información de la pila, básicamente la pila no se puede restaurar y el problema no se puede resolver.

Por lo tanto, esta información de depuración es particularmente importante, y es la información clave para que analicemos los problemas de NE, por lo que cuando la compilemos, debemos guardar una copia de la información de la tabla de símbolos para que no se haya eliminado o eliminado para un análisis posterior del problema. y cada vez que compilamos es necesario guardar All, una vez modificado y recompilado el código, la información de la tabla de símbolos antes y después de la modificación no podrá corresponder y analizar.

1.2 Ver el estado

De hecho, también puede ver el estado de so a través de la línea de comando, simplemente use el comando de archivo en Mac, y se puede ver información básica en el valor de retorno del comando.

Como se muestra en la figura siguiente, stripped representa el so sin información de depuración, y con debug_info, not stripped representa el so con información de depuración.

file libbreakpad-core-s.so
libbreakpad-core-s.so: *******, BuildID[sha1]=54ad86d708f4dc0926ad220b098d2a9e71da235a, stripped
file libbreakpad-core.so
libbreakpad-core.so: ******, BuildID[sha1]=54ad86d708f4dc0926ad220b098d2a9e71da235a, with debug_info, not stripped

Si es un sistema Windows, le aconsejo que instale un subsistema Linux y luego ejecute el mismo comando en Linux, también puede obtener la información.

A continuación, veamos cómo obtenemos el so en los dos estados.

1.3 Obtener la tira y destrabar para

En la actualidad, Android Studio generará strip y unstriped al mismo tiempo si está compilado con mk o Cmake. La siguiente figura muestra los dos correspondientes generados por Cmake compilados de esta manera.

Entonces, ruta antes de la tira: build / intermediates / transforms / mergeJniLibs

Entonces, ruta tras tira: build / intermediates / transforms / stripDebugSymbol

Captura y análisis de Android NativeCrash

Además, también puede eliminar manualmente a través de la herramienta aarch64-linux-android-strip proporcionada por el SDK de Android. La herramienta aarch64-linux-android-strip se encuentra en / Users / njvivo / Library / Android / sdk / ndk / 21.3.6528147 / directorio toolchains.

Hay varias versiones de esta herramienta, principalmente para diferentes arquitecturas de CPU de teléfonos móviles. Si no conoce la arquitectura de la CPU del teléfono, puede conectarse al teléfono y usar el siguiente comando para ver:

adb shell cat /proc/cpuinfo
Processor   : AArch64 Processor rev 12 (aarch64)

Como puede ver en la imagen de arriba, mi teléfono usa aarch64 para CPU, así que uso aarch64-linux-android-strip, la herramienta correspondiente a aarch64. Dado que NDK proporciona muchas herramientas, siga este principio para usar en el futuro:

aarch64架构
/Users/njvivo/Library/Android/sdk/ndk/21.3.6528147/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-strip
arm架构
/Users/njvivo/Library/Android/sdk/ndk/21.3.6528147/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-android-strip

Utilice el siguiente comando para eliminar directamente la depuración

aarch64-linux-android-strip --strip-all libbreakpad-core.so

Al usar Cmake para compilar, puede agregar los siguientes comandos para compilar directamente los strip

#set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s")
#set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s")

Cuando use archivos mk para compilar, puede agregar los siguientes comandos, o puede compilar directamente strip para

-fvisibility=hidden

En segundo lugar, captura y análisis de NE

El análisis de NE, como su nombre indica, es el análisis de pila. Por supuesto, todos los requisitos previos son guardar una tabla firmada, es decir, el as sin rayas. Si solo tiene el as después de la tira, no hay nada que pueda hacer, y la pila básicamente no se puede restaurar.

Generalmente, hay tres formas de capturar y restaurar la pila.

2.1 Captura de Logcat

Como sugiere el nombre, se captura a través de logcat. Abrimos logcat a través de Android Studio y creamos un NE. Solo podemos ver muchos símbolos como # 00 pc 00000000000161a0, y no hay ningún registro que se pueda leer directamente. Queremos generar directamente la salida una copia a través de logcat. Lee el registro directamente.

Puede utilizar una herramienta ndk-stack proporcionada en Android / SDK / NDK, que puede analizar directamente la salida del registro por NE en un registro legible.

ndk-stack generalmente se encuentra debajo de las herramientas de ndk, la dirección en Mac es

/Users/XXXX/Library/Android/sdk/ndk/21.3.6528147/ndk-stack

Luego ejecute el comando de la consola en este directorio, o ejecútelo en la terminal de Android Studio.

adb shell logcat | androidsdk绝对路径/ndk-stack -sym so所在目录

De esta manera, la consola generará el siguiente registro cuando se produzca NE en la aplicación. Desde el registro, se puede ver que el correspondiente so y el nombre del método correspondiente del bloqueo. fácil de localizar el problema.

promote:~ njvivo$ adb shell logcat | ndk-stack -sym libbreakpad-core.so
********** Crash dump: **********
Build fingerprint: 'vivo/PD1809/PD1809:8.1.0/OPM1.171019.026/compil04252203:user/release-keys'
#00 0x00000000000161a0 /data/app/com.android.necase-lEp0warh8FqicyY1YqGXXA==/lib/arm64/libbreakpad-core.so (Java_com_online_breakpad_BreakpadInit_nUpdateLaunchInfo+16)
#01 0x00000000000090cc /data/app/com.android.necase-lEp0warh8FqicyY1YqGXXA==/oat/arm64/base.odex (offset 0x9000)
Crash dump is completed

De hecho, el principio de la herramienta ndk-stack es que la integración interna usa addr2line para analizar la pila en tiempo real y mostrarla en la consola.

Al ver a algunos amigos aquí, siento que esto no es muy simple, pero la escena real del accidente no es fácil de reproducir, y la escena del usuario a veces es difícil de simular Entonces, cómo monitorear y localizar el accidente NE en línea Hay dos formas.

2.2 Análisis a través de registros de DropBox: adecuado para aplicaciones del sistema

Esto es muy simple. DropBox registrará varios registros de JE, NE y ANR. Solo necesita cargar los registros en DropBox para su análisis y resolución. A continuación se muestra un registro de muestra.

Captura y análisis de Android NativeCrash

Esquema de resolución 1:

Con la ayuda de la herramienta ndk-stack mencionada anteriormente, el registro de DropBox se puede analizar directamente en una pila, y se puede ver que el bloqueo está en el método Crash () en la línea 111 de breakpad.cpp.

ndk-stack -sym /Users/njvivo/Desktop/NE -dump [email protected]
********** Crash dump: **********
Build fingerprint: 'vivo/PD1809/PD1809:8.1.0/OPM1.171019.026/compil04252203:user/release-keys'
#00 0x00000000000161a0 /data/app/com.android.necase-lEp0warh8FqicyY1YqGXXA==/lib/arm64/libbreakpad-core.so (Java_com_online_breakpad_BreakpadInit_nUpdateLaunchInfo+16)
Crash()
/Users/njvivo/Documents/project/Breakpad/breakpad-build/src/main/cpp/breakpad.cpp:111:8
Java_com_online_breakpad_BreakpadInit_nUpdateLaunchInfo
/Users/njvivo/Documents/project/Breakpad/breakpad-build/src/main/cpp/breakpad.cpp:122:0
#01 0x00000000000090cc /data/app/com.android.necase-lEp0warh8FqicyY1YqGXXA==/oat/arm64/base.odex (offset 0x9000)
Crash dump is completed

Plan de análisis 2:

Todavía use la herramienta linux-android-addr2line proporcionada por Android / SDK / NDK. Esta herramienta se encuentra en el directorio / Users / njvivo / Library / Android / sdk / ndk y tiene dos versiones.

aarch64架构
/Users/njvivo/Library/Android/sdk/ndk/21.3.6528147/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-addr2line
arm架构
/Users/njvivo/Library/Android/sdk/ndk/21.3.6528147/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-addr2line

El método de uso del comando es el siguiente, combinado con el so sin rayas y el símbolo de pila 00000000000161a0 que aparece en el registro, la dirección y el método del bloqueo también se pueden analizar.

aarch64-linux-android-addr2line -f -C -e libbreakpad-core.so 00000000000161a0

Crash()
/Users/njvivo/Documents/project/Breakpad/breakpad-build/src/main/cpp/breakpad.cpp:111

En base a lo anterior, parece muy simple, pero hay un problema fatal que es que solo las aplicaciones del sistema pueden acceder a DropBox, y las aplicaciones que no son del sistema no pueden obtener registros en absoluto. Entonces, ¿qué deberían hacer las aplicaciones que no son del sistema?

2.3 Capturar análisis a través de BreakPad aplicable a todas las aplicaciones

Las aplicaciones que no pertenecen al sistema se pueden monitorear y analizar a través de la herramienta de código abierto BreakPad proporcionada por Google. CrashSDK también usa este método. Puede monitorear la ocurrencia de NE en tiempo real y registrar archivos relacionados, de modo que el bloqueo y el bloqueo de la aplicación correspondiente puedan comenzar, las escenas se combinan y se informa.

Aquí hay una breve introducción a cómo usar BreakPad.

2.3.1 La función de realización de BreakPad

BreakPad proporciona principalmente dos funciones, monitoreo de NE y devolución de llamada, generando archivos de minivolcado, que son archivos que terminan en dmp, y también proporciona dos herramientas, la herramienta de tabla de símbolos y la herramienta de restauración de pila.

Captura y análisis de Android NativeCrash

  • Herramienta de tabla de símbolos: se utiliza para extraer información de depuración y obtener la tabla de símbolos correspondiente a la pila.

  • Herramienta de restauración de pila: se utiliza para restaurar el archivo de volcado generado por BreakPad a un símbolo, que es el valor de compensación de pila.

Estas dos herramientas se generarán cuando se compile el código fuente de BreakPad.

Después de compilar, se generará la herramienta minidump_stackwalk. Si algunos estudiantes no quieren compilar, Android Studio también proporciona esta herramienta.

Este programa minidump_stackwalk también existe en el directorio de Android Studio, puedes sacarlo y usarlo directamente. Si no quieres compilar, simplemente ve al directorio y tómalo directamente. La ruta de Mac es:

/Applications/Android Studio.app/Contents/bin/lldb/bin/minidump_stackwalk

2.3.2 Principio de captura de BreakPad

Se puede saber por lo anterior que cuando la aplicación falla con NE, BreakPad puede escribir el archivo de minivolcado correspondiente a NE en el local, y volverá a llamar a la capa de aplicación al mismo tiempo. La capa de aplicación puede hacer algún procesamiento para esto crash para lograr el efecto de capturar estadísticas. Después de cargar el archivo minidump, las herramientas minidump_stackwalk y addr2line se pueden usar para restaurar la pila real. El diagrama esquemático es el siguiente:

Captura y análisis de Android NativeCrash

Cuando ocurre NE en la aplicación, BreakPad generará un archivo de volcado localmente en el teléfono, como se muestra en la figura:

Captura y análisis de Android NativeCrash

Con los archivos anteriores, solo podemos saber que se ha producido NE en la aplicación, pero estos archivos son en realidad ilegibles y deben analizarse.

Lo siguiente se centra en cómo analizar el NE generado anteriormente:

2.3.3 Analizando el archivo de volcado

1. Obtenga el archivo de volcado de NE crash, coloque minidump_stackwalk y el archivo de volcado que acaba de obtener en el mismo directorio, o déjelo solo, simplemente complete la ruta absoluta al completar la ruta.

Luego ejecute el siguiente comando en la ventana de terminal debajo de este directorio, lo que significa usar minidump_stackwalk para analizar el archivo de volcado y generar la información analizada en el archivo crashLog.txt en el directorio actual.

./minidump_stackwalk xxxxxxxx.dmp >crashLog.txt

2. Después de la ejecución, minidump_stackwalk escribirá información relacionada con NE en crashLog.txt. La información detallada se muestra en la figura:

Captura y análisis de Android NativeCrash

3. De acuerdo con la información de NE analizada, preste atención al cuadro rojo en la figura, puede saber que en libbreakpad-core.so donde ocurrió el bloqueo   , 0x161a0 representa que el bloqueo ocurrió en una posición desplazada desde la posición raíz de 161a0

2.3.4 Obtener la pila de fallos

1. Con la herramienta addr2line mencionada anteriormente, el método, el número de líneas y la relación de la pila de llamadas del bloqueo se pueden obtener de acuerdo con el archivo so donde ocurrió el bloqueo y la dirección de compensación (0x161a0).

2. Ejecute el siguiente comando en la ventana de terminal de su directorio raíz.

arm-linux-androideabi-addr2line -C -f -e ${SOPATH} ${Address}
-C -f           //打印错误行数所在的函数名称
-e                //打印错误地址的对应路径及行数
${SOPATH}         //so库路径
${Address}        //需要转换的堆栈错误信息地址,可以添加多个,但是中间要用空格隔开,例如:0x161a0

3. La siguiente figura es un ejemplo de funcionamiento real.

aarch64-linux-android-addr2line -f -C -e libbreakpad-core.so 0x161a0
Crash()
/Users/njvivo/Documents/project/Breakpad/breakpad-build/src/main/cpp/breakpad.cpp:111

Como se puede ver en la figura anterior, el bloqueo ocurrió en la línea 111 del archivo breakpad.cpp. El nombre de la función es Crash (), que es consistente con el archivo real. El código de bloqueo es el siguiente:

void Crash() {
    volatile int *a = (int *) (NULL);
    *a = 1; //此处在代码里是111行
}

extern "C"
JNIEXPORT void JNICALL
Java_com_online_breakpad_BreakpadInit_nUpdateLaunchInfo(JNIEnv *env, jobject instance,
                                                        jstring mLaunchInfoStr_) {

    DO_TRY
    {
        Crash();
        const char *mLaunchInfoStr = env->GetStringUTFChars(mLaunchInfoStr_, 0);
        launch_info = (char *) mLaunchInfoStr;
//        env->ReleaseStringUTFChars(mLaunchInfoStr_, mLaunchInfoStr);
    }
    DO_CATCH("updateLaunchInfo");

}

En base a lo anterior, la información detallada de la pila de NE se puede analizar a través del archivo de volcado recopilado por la aplicación.

 3. Extracción de la tabla de símbolos so

3.1 Extraiga la tabla de símbolos de

A través del contenido anterior, sabemos que contiene alguna información de depuración, también llamada tabla de símbolos, entonces, ¿cómo separamos esta información de depuración por separado? Ndk también nos proporciona herramientas relacionadas.

aarch64架构
/Users/njvivo/Library/Android/sdk/ndk/21.3.6528147/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-objdump
arm架构
/Users/njvivo/Library/Android/sdk/ndk/21.3.6528147/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-android-objdump

A continuación se muestra cómo se ejecuta el comando. Con este comando, la información de depuración en so se puede extraer a un archivo.

promote:~ njvivo$ aarch64-linux-android-objdump -S libbreakpad-core.so > breakpad.asm

3.2 Análisis de la tabla de símbolos

3.2.1 Análisis directo

La siguiente figura muestra el archivo de la tabla de símbolos de salida. Combinando el registro anterior y el archivo de la tabla de símbolos a continuación, también podemos analizar la pila.

Como se muestra en el registro, se ha demostrado que la dirección del bloqueo es 161a0, y el código correspondiente a 161a0 es * a = 1. Del análisis anterior, ya sabemos que el bloqueo está en la línea 111 de breakpad.cpp, que es * a = 1. La ubicación es exactamente la esperada.

backtrace:
#00 pc 00000000000161a0 /data/app/com.android.necase-lEp0warh8FqicyY1YqGXXA==/lib/arm64/libbreakpad-core.so (Java_com_online_breakpad_BreakpadInit_nUpdateLaunchInfo+16)
#01 pc 00000000000090cc /data/app/com.android.necase-lEp0warh8FqicyY1YqGXXA==/oat/arm64/base.odex (offset 0x9000)

Captura y análisis de Android NativeCrash

3.2.2 Análisis de herramientas

Google proporciona una herramienta Python, que puede analizar directamente la pila combinando la tabla de símbolos y el registro. Acceso a la herramienta Pythonhttps://code.google.com/archive/p/android-ndk-stacktrace-analyzer/  se puede descargar.

Al ejecutar el comando, se puede analizar la pila correspondiente. Esta herramienta se puede utilizar para el análisis de lotes en el lado del servidor, y no se describirá en detalle aquí.

python parse_stack.py <asm-file> <logcat-file>

3.2.3 Breve análisis de la posición de compensación

El artículo anterior mencionó un concepto de posición de compensación, no sé mucho al respecto, pero hay más o menos un concepto, el código C tiene un código de posición raíz y cada línea de código tiene una posición de compensación relativa al código raíz.

Como se muestra en el ejemplo anterior, hay una línea de declaración en el registro (Java_com_online_breakpad_BreakpadInit_nUpdateLaunchInfo + 16), +16 significa que la posición relativa al método nUpdateLaunchInfo está compensada por 16.

Como se puede ver en la figura anterior, la posición del método nUpdateLaunchInfo es 16190, desplazamiento 16, que es 16190 + 10 (10 después de que el decimal 16 se convierte a hexadecimal) = 161a0, que es lo mismo que la salida del registro.

 Cuatro, resumen

Lo anterior es todo el contenido de este artículo. Principalmente describe brevemente algunos conocimientos básicos de eso, así como el bloqueo de NE en Android, y la solución de captura y análisis. Espero que este documento ayude a los pequeños socios relacionados con NE, y el CrashSDK de seguimiento también apoyará la función de análisis del NE relevante.

Autor: vivo-MaLian

Supongo que te gusta

Origin blog.51cto.com/14291117/2635609
Recomendado
Clasificación