Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Cómo depurar tu app

Android Studio proporciona un depurador que te permite realizar las siguientes acciones y más:

  • Seleccionar un dispositivo en el cual depurarás tu app
  • Establecer interrupciones en tu código Java, Kotlin y C/C++
  • Examinar variables y evaluar expresiones en el tiempo de ejecución

En esta página, se incluyen instrucciones para las operaciones básicas del depurador. Para obtener más documentación, también puedes consultar los documentos de depuración de IDEA de IntelliJ.

Cómo habilitar la depuración

Antes de comenzar a depurar, debes prepararte de la siguiente manera:

  • Habilita la depuración en tu dispositivo:

    Si estás usando el emulador, esta opción estará activada de forma predeterminada. Sin embargo, en el caso de un dispositivo conectado, deberás habilitar la depuración en las opciones para desarrolladores del dispositivo.

  • Ejecuta una variante de compilación depurable:

    Debes usar una variante de compilación que incluya debuggable true en la configuración de compilación. Por lo general, simplemente puedes seleccionar la variante "debug" predeterminada que se incluye en cada proyecto de Android Studio (aunque no esté visible en el archivo build.gradle). Sin embargo, si defines nuevos tipos de compilación que deberían ser depurables, debes agregar "debuggable true" al tipo de compilación de la siguiente manera

    android {
        buildTypes {
            customDebugType {
                debuggable true
                ...
            }
        }
    }
    

    Esta propiedad también se aplica a los módulos con código C o C++ (ya no se usa la propiedad jniDebuggable).

    Si tu app depende de un módulo de biblioteca que también quieres depurar, se debe empaquetar esa biblioteca con debuggable true de manera que conserve sus símbolos de depuración. Para garantizar que las variantes depurables del proyecto de tu app reciban la variante depurable de un módulo de biblioteca, asegúrate de publicar versiones no predeterminadas de tu biblioteca.

Cómo iniciar la depuración

Puedes iniciar una sesión de depuración de la siguiente manera:

  1. Establece algunas interrupciones en el código de la app.
  2. En la barra de herramientas, selecciona el dispositivo en el que depurarás la app en el menú desplegable del dispositivo de destino.

    Menú desplegable del dispositivo de destino.

    Si no tienes ningún dispositivo configurado, debes conectar uno mediante USB o crear un AVD para usar Android Emulator.

  3. En la barra de herramientas, haz clic en Debug .

    Si se muestra el diálogo "switch from Run to Debug" (cambiar del modo de ejecución al de depuración), significa que tu app ya se está ejecutando en el dispositivo y se reiniciará para comenzar con la depuración. Si prefieres conservar la misma instancia de la app en ejecución, haz clic en Cancel Debug y, en su lugar, adjunta el depurador a la app en ejecución.

    Android Studio compila un APK, lo firma con una clave de depuración, lo instala en el dispositivo seleccionado y lo ejecuta. Si agregas código C y C++ a tu proyecto, Android Studio también ejecutará el depurador LLDB en la ventana Debug para depurar tu código nativo.

  4. Si la ventana Debug no está abierta, selecciona View > Tool Windows > Debug (o haz clic en Debug  en la barra de ventanas de herramientas) y, luego, haz clic en la pestaña Debugger, como se muestra en la Figura 1.

    Figura 1: La ventana "Debugger", en la que se muestra el subproceso actual y el árbol de objetos para una variable

Cómo adjuntar el depurador a una app en ejecución

Si tu app ya se está ejecutando en el dispositivo, puedes comenzar con la depuración sin reiniciarla de la siguiente manera:

  1. Haz clic en Attach debugger to Android process .
  2. En el diálogo Choose Process, selecciona el proceso al que desees adjuntar el depurador.

    Si estás usando un emulador o un dispositivo con derechos de administrador, puedes marcar la opción Show all processes para ver todos los procesos.

    En el menú desplegable Use Android Debugger Settings, puedes seleccionar una configuración de ejecución y depuración existente. (En proyectos con código C y C++, esto te permite reutilizar los directorios de símbolos y los comandos de arranque y posconexión de LLDB de una configuración existente.) Si no tienes una configuración de ejecución y depuración, selecciona Create New. De esta forma, se habilita el menú desplegable Debug Type, donde puedes seleccionar un tipo de depuración diferente. De forma predeterminada, Android Studio usa el tipo de depuración Auto para seleccionar la mejor opción de depuración en función de si tus proyectos incluyen código Java o C/C++.

  3. Haz clic en OK.

    Aparecerá la ventana Debug.

Nota: El depurador y el recolector de elementos no utilizados de Android Studio se vinculan de forma flexible. La máquina virtual de Android garantiza que cualquier objeto que el depurador identifique no se recolecte como elemento no utilizado hasta que se desconecte el depurador, lo cual puede generar una acumulación de objetos con el tiempo mientras el depurador esté conectado. Por ejemplo, si el depurador ve un subproceso en ejecución, no se recolecta el objeto Thread asociado como elemento no utilizado hasta que se desconecta el depurador, aunque haya finalizado el subproceso.

Cómo cambiar el tipo de depurador

Debido a que se requieren diferentes herramientas de depuración para depurar el código Java o Kotlin y el código C/C ++, el depurador de Android Studio te permite seleccionar qué tipo de depurador usar. De forma predeterminada, Android Studio decide qué depurador usar según los idiomas que detecta en tu proyecto (con el tipo de depurador Auto). Sin embargo, puedes seleccionar manualmente el depurador en la configuración de depuración (haz clic en Run > Edit > Configurations) o en el diálogo que aparece cuando haces clic en Run > Attach debugger to Android process.

Entre los tipos de depuración disponibles, se incluyen los siguientes:

Auto
Selecciona este tipo de depuración si quieres que Android Studio elija automáticamente la mejor opción para el código que estás depurando. Por ejemplo, si tienes código C o C++ en tu proyecto, Android Studio usa automáticamente el tipo de depuración Dual. De lo contrario, usa el tipo de depuración Java.
Java
Selecciona este tipo de depuración si solo quieres depurar código escrito en Java o Kotlin. El depurador de Java ignora las interrupciones o los análisis que hayas establecido en tu código nativo.
Native (disponible solo con el código C/C++)
Selecciona este tipo de depuración si solo quieres usar LLDB para depurar tu código. Cuando usas este tipo de depuración, no está disponible la vista de la sesión del depurador de Java. De manera predeterminada, LLDB inspecciona solo tu código nativo y omite las interrupciones en tu código Java. Si también deseas depurar tu código Java, debes cambiar al tipo de depuración Auto o Dual.

La depuración nativa solo funciona en dispositivos que cumplen los siguientes requisitos:

  • El dispositivo admite run-as.

    Para verificar si el dispositivo admite run-as, ejecuta el siguiente comando en el shell de ADB que está conectado a tu dispositivo:

    run-as your-package-name pwd
    

    Reemplaza your-package-name por el nombre del paquete de tu app. Si el dispositivo admite run-as, el comando se debería mostrar sin errores.

  • El dispositivo tiene ptrace habilitado.

    Para verificar si ptrace está habilitado, ejecuta el siguiente comando en el shell de ADB que está conectado a tu dispositivo:

    sysctl kernel.yama.ptrace_scope
    

    Si ptrace está habilitado, el comando imprimirá el valor 0 o un error unknown key. Si ptrace no está habilitado, imprimirá un valor distinto de 0.

Dual (disponible solo con código C/C ++)
Selecciona este tipo de depuración si deseas realizar un cambio entre la depuración de Java y código nativo. Android Studio adjunta el depurador de Java y LLDB al proceso de tu app, uno para el depurador de Java y uno para LLDB, a fin de que puedas inspeccionar las interrupciones tanto en tu código Java como en tu código nativo sin reiniciar tu app ni cambiar la configuración de depuración.

En la Figura 2, observa las dos pestañas a la derecha del título de la ventana Debug. Como la app tiene códigos Java y C++, una pestaña es para depurar el código nativo y la otra para el código Java, como lo indica -java.

Figura 2: La pestaña para depurar código nativo y la pestaña para depurar código Java

Nota: Si estás depurando código nativo optimizado por el compilador, es posible que veas el siguiente mensaje de advertencia: This function was compiled with optimizations enabled. Some debugger features may not be available. Cuando se usan marcas de optimización, como las -O, el compilador realiza cambios en el código compilado para que se ejecute de manera más eficiente. Esta acción puede provocar que el depurador registre información incorrecta o inesperada porque le resulta difícil volver a asignar el código compilado y optimizado al código fuente original. Por este motivo, debes inhabilitar las optimizaciones del compilador mientras depuras tu código nativo.

Cómo usar el registro del sistema

El registro del sistema muestra mensajes mientras depuras tu app, que incluyen información sobre apps que se ejecutan en el dispositivo. Si deseas usar el registro del sistema para depurar tu app, asegúrate de que tu código escriba mensajes de registro y también imprima el seguimiento de pila para las excepciones mientras tu app se encuentre en etapa de desarrollo.

Cómo escribir mensajes de registro en tu código

Para escribir mensajes de registro en tu código, usa la clase Log. Estos mensajes te ayudan a comprender el flujo de ejecución mediante la recopilación de los resultados de depuración del sistema mientras interactúas con tu app. Además, pueden indicarte cuál es la parte de tu app que falló. Para obtener más información sobre el registro, consulta Cómo escribir y ver registros.

En el siguiente ejemplo, se muestra cómo puedes agregar mensajes de registro para determinar si hay información disponible sobre el estado anterior cuando inicias tu actividad:

Kotlin

import android.util.Log
...
private val TAG: String = MyActivity::class.java.simpleName
...
class MyActivity : Activity() {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        if (savedInstanceState != null) {
            Log.d(TAG, "onCreate() Restoring previous state")
            /* restore state */
        } else {
            Log.d(TAG, "onCreate() No saved state available")
            /* initialize app */
        }
    }
}

Java

import android.util.Log;
...
public class MyActivity extends Activity {
    private static final String TAG = MyActivity.class.getSimpleName();
    ...
    @Override
    public void onCreate(Bundle savedInstanceState) {
       ...
       if (savedInstanceState != null) {
            Log.d(TAG, "onCreate() Restoring previous state");
            /* restore state */
        } else {
            Log.d(TAG, "onCreate() No saved state available");
            /* initialize app */
        }
    }
}

Durante el desarrollo, tu código también puede detectar excepciones y escribir el seguimiento de pila en el registro del sistema:

Kotlin

fun someOtherMethod() {
    try {
        ...
    } catch (e : SomeException) {
        Log.d(TAG, "someOtherMethod()", e)
    }
}

Java

void someOtherMethod() {
    try {
        ...
    } catch (SomeException e) {
        Log.d(TAG, "someOtherMethod()", e);
    }
}

Nota: Cuando estés listo para publicar tu app, quita los mensajes del registro de depuración y las llamadas de impresión de seguimiento de pila de tu código. Para ello, configura una marca DEBUG y coloca mensajes del registro de depuración en las declaraciones condicionales.

Cómo ver el registro del sistema

Puedes ver y filtrar la depuración y otros mensajes del sistema en la ventana Logcat. Por ejemplo, puedes ver mensajes cuando se produce la recolección de elementos no utilizados, o bien, mensajes que agregas a tu app con la clase Log.

Para usar Logcat, debes iniciar la depuración y seleccionar la pestaña Logcat en la barra de herramientas inferior, como se muestra en la Figura 3.

Figura 3: La ventana "Logcat" con configuración de filtros

Para obtener una descripción de Logcat y sus opciones de filtrado, consulta Cómo escribir y ver registros con Logcat.

Cómo trabajar con interrupciones

Android Studio admite varios tipos de interrupciones que activan diferentes acciones de depuración. El tipo más común es una interrupción de línea que detiene la ejecución de tu app en una línea de código especificada. Mientras la app está detenida, puedes examinar variables, evaluar expresiones y, luego, continuar la ejecución línea por línea para determinar las causas de los errores en el tiempo de ejecución.

Para agregar una interrupción de línea, haz lo siguiente:

  1. Localiza la línea de código en la que desees detener la ejecución, luego haz clic en el margen izquierdo de esta o coloca el símbolo de intercalación en la línea y presiona Control + F8 (en Mac, Command + F8).
  2. Si tu app ya se está ejecutando, no necesitas actualizarla para agregar la interrupción. Simplemente, haz clic en Attach debugger to Android process . De lo contrario, inicia la depuración haciendo clic en Debug .

Figura 3: Cuando estableces una interrupción, aparece un punto rojo junto a la línea

Cuando la ejecución del código llega a la interrupción, Android Studio detiene la ejecución de tu app. Luego, puedes usar las herramientas de la pestaña Debugger para identificar el estado de la app:

  • Para examinar el árbol de objetos de una variable, expándelo en la vista Variables. Si no ves la vista Variables, haz clic en Restore Variables View .

  • Para evaluar una expresión en el punto de ejecución actual, haz clic en Evaluate Expression .

  • Para avanzar a la siguiente línea del código (sin ingresar a un método), haz clic en Step Over .

  • Para avanzar a la primera línea dentro de una llamada a un método, haz clic en Step Into .

  • Para avanzar a la siguiente línea fuera del método actual, haz clic en Step Out .

  • Para continuar ejecutando la app normalmente, haz clic en Resume Program .

Si tu proyecto usa código nativo, de forma predeterminada, el tipo de depuración Auto adjunta el depurador Java y LLDB a tu app como dos procesos independientes, de manera que puedas realizar el cambio entre la inspección de interrupciones de Java y C/C++ sin tener que reiniciar tu app ni cambiar la configuración.

Nota: Para que Android Studio detecte las interrupciones en tu código C o C++, debes usar un tipo de depuración que sea compatible con LLDB, como Auto, Native o Dual. Para cambiar el tipo de depuración que usa Android Studio, edita tu configuración de depuración. Para obtener más información sobre el tema, consulta la sección sobre cómo usar otros tipos de depuración.

Cuando Android Studio implementa tu app en el dispositivo de destino, se abre la ventana "Debug" con una pestaña o la vista de la sesión de depuración para cada proceso del depurador, como se muestra en la Figura 4.

Figura 4: Depuración de código nativo mediante LLDB

  1. Android Studio realiza un cambio a la pestaña <your-module> cuando el depurador LLDB encuentra una interrupción en tu código C y C++. También se encuentran disponibles los paneles Frames, Variables y Watches, que funcionan exactamente como lo harían si depuraras código Java. Si bien el panel Threads no está disponible en la vista de la sesión de LLDB, puedes acceder a los procesos de tu app por medio de la lista desplegable del panel Frames. Para obtener más información sobre estos paneles, consulta las secciones sobre cómo depurar marcos de ventanas y cómo inspeccionar variables.

    Nota: Mientras inspeccionas una interrupción en tu código nativo, el sistema de Android suspende la máquina virtual que ejecuta el código de bytes Java de tu app, lo que implica que no podrás interactuar con el depurador de Java ni recuperar información sobre el estado de tu sesión de depuración de Java mientras inspeccionas una interrupción en tu código nativo.

  2. Android Studio realiza un cambio automático a la pestaña <your-module>-java cuando el depurador de Java encuentra una interrupción en tu código Java.
  3. Durante la depuración con LLDB, puedes usar la terminal LLDB en la vista de la sesión de LLDB para pasar opciones de línea de comandos a LLDB. Si tienes comandos específicos que quisieras que LLDB ejecute cada vez que comiences a depurar tu app (ya sea justo antes o después de que el depurador se adjunte al proceso de tu app), puedes agregarlos a la configuración de depuración.

Durante la depuración de código C o C++, también puedes configurar tipos especiales de interrupciones, llamados puntos de análisis, que pueden suspender el proceso de tu app cuando esta interactúa con un bloque de memoria específico. Para obtener más información, consulta la sección sobre cómo agregar puntos de análisis.

Cómo ver y configurar interrupciones

Para ver todas las interrupciones y configurarlas, haz clic en View Breakpoints  en la parte izquierda de la ventana Debug. Aparecerá la ventana Breakpoints, como se muestra en la Figura 5.

Figura 5: En la ventana "Breakpoints", se enumeran todas las interrupciones actuales y se incluye la configuración de comportamiento para cada una

La ventana Breakpoints te permite habilitar o inhabilitar cada interrupción desde la lista de la izquierda. Si se inhabilita una interrupción, Android Studio no pausa tu app cuando la alcanza. Selecciona una interrupción de la lista para configurarla. Puedes inhabilitar una y hacer que el sistema la habilite luego de que se alcance otra interrupción. También puedes configurar una interrupción para que se inhabilite una vez que se alcance. Para configurar una interrupción en cualquier excepción, selecciona Exception Breakpoints en la lista de interrupciones.

Cómo depurar marcos de una ventana

En la ventana Debugger, el panel Frames te permite inspeccionar el marco de pila que provocó que se alcanzara la interrupción actual. De esta manera, podrás navegar y examinar el marco de pila y, además, inspeccionar la lista de subprocesos en tu app para Android. Para seleccionar una subproceso, usa el selector y observa su marco de pila. Cuando hagas clic en los elementos del marco, se abrirá el origen en el editor. También puedes personalizar la presentación de subprocesos y exportar el marco de pila como se explica en la Guía de marcos de ventanas.

Cómo inspeccionar variables

En la ventana Debugger, el panel Variables te permite inspeccionar variables cuando el sistema detiene tu app en una interrupción y seleccionas un marco del panel Frames. El panel Variables también te permite evaluar expresiones ad hoc por medio de métodos estáticos o variables disponibles en el marco seleccionado.

En el panel Watches, se proporciona una funcionalidad similar, con la excepción de que las expresiones agregadas al panel Watches se conservan entre sesiones de depuración. Debes agregar controles para variables y campos a los que accedas con frecuencia o que proporcionen un estado útil para la sesión de depuración actual. Los paneles Variables y Watches aparecen como se muestra en la Figura 6.

Para agregar una variable o expresión a la lista de Watches, sigue estos pasos:

  1. Inicia la depuración.
  2. En el panel Watches, haz clic en Add .
  3. En el cuadro de texto que aparece, escribe el nombre de la variable o la expresión que desees controlar y presiona Intro.

Para quitar un elemento de la lista Watches, selecciónalo y haz clic en Remove .

Puedes volver a ordenar los elementos en la lista Watches; para ello, selecciona un elemento y haz clic en Up  o Down .

Figura 6: Subpaneles Variables y Watches de la ventana Debugger

Cómo agregar puntos de análisis

Durante la depuración de código C y C++, puedes configurar tipos especiales de interrupciones, llamados puntos de análisis, que pueden suspender el proceso de tu app cuando esta interactúa con un bloque de memoria específico. Por ejemplo, si estableces dos punteros para un bloque de memoria y le asignas un punto de análisis, y usas cualquiera de los punteros para acceder al bloque de memoria que activa el punto de análisis.

En Android Studio, puedes crear un punto de análisis durante el tiempo de ejecución al seleccionar una variable específica, pero LLDB asigna el punto de análisis solo al bloque de memoria que el sistema asigna a esa variable, no a la variable en sí. Es distinto a agregar una variable al panel Watches, que te permite observar el valor de una variable, pero no suspender el proceso de tu app cuando el sistema lee o cambia su valor en la memoria.

Nota: Cuando el proceso de tu app sale de una función y el sistema desasigna sus variables locales de la memoria, tendrás que volver a asignar los puntos de análisis que creaste para esas variables.

Para establecer un punto de análisis, debes cumplir con los siguientes requisitos:

  • El dispositivo físico o el emulador de destino deben usar una CPU x86 o x86_64. Si tu dispositivo usa una CPU ARM, debes alinear el límite de la dirección de tu variable en la memoria a 4 bytes para procesadores de 32 bits o a 8 bytes para procesadores de 64 bits. Para alinear una variable en tu código nativo, especifica __attribute__((aligned(num_bytes))) en la desaceleración variable, como se muestra a continuación:
    // For a 64-bit ARM processor
    int my_counter __attribute__((aligned(8)));
    
  • Ya asignaste tres puntos de análisis o menos. Android Studio solo admite hasta cuatro puntos de análisis en dispositivos de destino x86 o x86_64. Es posible que otros dispositivos admitan menos puntos de análisis.

Nota: Cuando depuras tu app con ABI de ARM de 32 bits, agregar un punto de análisis o colocar el cursor sobre otras variables dentro del código para investigar sus valores podría ocasionar una falla. Como solución alternativa, utiliza ARM de 64 bits u objetos binarios x86 o x86_64 para la depuración. Este error se corregirá en una versión futura de Android Studio.

Si cumples con los requisitos anteriores, puedes agregar un punto de análisis de la siguiente manera:

  1. Mientras tu app esté suspendida en una interrupción, navega al panel Variables en la vista de la sesión de LLDB.
  2. Haz clic con el botón derecho en una variable que ocupe el bloque de memoria del cual desees realizar un seguimiento y selecciona Add Watchpoint. Aparecerá un diálogo para configurar tu punto de análisis, como se muestra en la Figura 7.

    Figura 7: Inclusión de un punto de análisis en una variable en la memoria

  3. Configura tu punto de análisis con las siguientes opciones:
    • Enabled: Puedes anular la selección de esta opción si deseas indicarle a Android Studio que ignore el punto de análisis por el momento. Android Studio guarda tu punto de análisis para que puedas acceder a él más adelante en tu sesión de depuración.
    • Suspend: De forma predeterminada, el sistema Android suspenderá el proceso de tu app cuando esta acceda a un bloque de memoria que asignaste a un punto de análisis. Puedes anular la selección de esta opción si no deseas este comportamiento (esta acción revela opciones adicionales que puedes usar para personalizar el comportamiento cuando el sistema interactúa con tu punto de análisis): Log message to console y Remove [the watchpoint] when hit.
    • Access type: Permite determinar si tu app debe activar el punto de análisis cuando intenta realizar operaciones de tipo Read (lectura) o Write (escritura) en el bloque de memoria que el sistema asigna a la variable. Para activar tu punto de análisis en lectura o escritura, selecciona Any.
  4. Haz clic en Done.

Para ver todos los puntos de análisis y configurarlos, haz clic en View Breakpoints  en la parte izquierda de la ventana Debug. Aparecerá el diálogo Breakpoints, como se muestra en la Figura 8.

Figura 8: En el diálogo "Breakpoints", se enumeran tus puntos de análisis actuales y se incluye la configuración de comportamiento para cada uno

Una vez que agregues tu punto de análisis, haz clic en Resume Program , en la parte izquierda de la ventana Debug, para reanudar el proceso de tu app. De forma predeterminada, si tu app intenta acceder a un bloque de memoria en el que configuraste un punto de análisis, el sistema Android suspende el proceso de la app y aparece un ícono de punto de análisis  junto a la última línea de código que ejecutó tu app, como se muestra en la Figura 9.

Figura 9: Android Studio indica la línea de código que tu app ejecuta justo antes de activar un punto de análisis.

Cómo ver y cambiar el formato de visualización de valores de los recursos

En el modo de depuración, puedes ver los valores de los recursos y seleccionar un formato de visualización diferente para las variables en tu código Java. Con la pestaña Variables visible en un marco seleccionado, haz lo siguiente:

  1. En la lista Variables, haz clic con el botón derecho en cualquier parte de una línea de recursos para mostrar la lista desplegable.
  2. En la lista desplegable, selecciona View as y elige el formato que quieres usar.

    Los formatos disponibles dependen del tipo de datos del recurso que selecciones. Es posible que veas una o más de las siguientes opciones:

    • Class: Se muestra la definición de la clase.
    • toString: Se muestra el formato de la string.
    • Object: Se muestra la definición del objeto (una instancia de una clase).
    • Array: Se muestra un formato de arreglo.
    • Timestamp: Se muestra la fecha y la hora en el siguiente formato: aaaa-mm-dd hh:mm:ss.
    • Auto: Android Studio elige el mejor formato en función del tipo de datos.
    • Binary: Se muestra un valor binario con ceros y unos.
    • MeasureSpec: Se muestra el valor que se pasa del elemento principal al elemento secundario seleccionado. Consulta MeasureSpec.
    • Hex: Se muestra un valor hexadecimal.
    • Primitive: Se muestra un valor numérico con un tipo de datos primitivo.
    • Integer: Se muestra un valor numérico del tipo Integer.

Puedes crear un formato personalizado (procesador del tipo de datos) de la siguiente manera:

  1. Haz clic con el botón derecho en el valor del recurso.
  2. Selecciona View as.
  3. Selecciona Create. Aparecerá el diálogo Java Data Type Renderers.
  4. Sigue las instrucciones de Procesadores de tipos de datos de Java.