Chapters

Hide chapters

Android Debugging by Tutorials

First Edition · Android 12 · Kotlin 1.6 · Android Studio Chipmunk (2021.2.1)

Section I: Debugging Basics

Section 1: 8 chapters
Show chapters Hide chapters

1. Getting Started
Written by Zac Lippard

Imagine you finish an important feature for your Android application and you attempt to run it on your device. The app seems to launch, hooray! But, to your dismay the app crashes not a moment later! What do you do now?

Debugging is the core of every development process, and there is no exception with Android. That doesn’t mean it has to be a scary feat to undertake.

In this chapter, you’ll set up your debugging environment using the built-in tools Android Studio provides. You’ll also learn about some of the basics of the Android Debug Bridge (ADB) that powers these debugging tools. By the end of the chapter, you’ll be able to connect the debugger to the sample app running on either a device or emulator.

Throughout this book, you’ll use the PodPlay sample app to learn about the debugging tools available to you.

Note: This book requires knowledge of the fundamentals of Android development. If you’re new to Android, please check out our Android Apprentice book for a complete guide to Android development.

Debugging

So, what exactly is debugging anyway? Well, debugging is the process of finding and resolving bugs. A bug can be any defect in the software that causes unexpected errors and crashes.

Fun fact, while the engineering term “bug” was used as early as the 1870s by Thomas Edison, it became a more popular term in the 20th century. In the late 1940s, Admiral Grace Hopper had a team working on the Mark II computer when they noticed a moth trapped in one of the relays. The team had to literally “debug” the system to fix the error!

A debugger is a tool that helps software engineers track and monitor a program and change values in memory. Android Studio offers a built-in debugger tool that can help accomplish these tasks. The debugger allows you to add breakpoints to suspend execution of the Android application, monitor memory and CPU usage and provides a whole bunch of other tracking tools. You’ll learn more about breakpoints in Chapter 2, “Navigating Your Code With Breakpoints”.

Next, you’ll learn how to connect the Android Studio debugger to an Android application.

Connecting the Debugger

Begin by opening this chapter’s Podplay starter project in Android Studio. After the project loads, click the Debug icon in the toolbar of Android Studio.

Similar to running the application, Android Studio will build the app if necessary. Then, it will install and run the app on the connected device. The additional step after the app starts is that the debugger is immediately attached to the running application.

If you see a Waiting For Debugger alert dialog on the screen, you’ve successfully connected the debugger!

After the debugger is attached, you’ll see the main app screen stating that you haven’t subscribed to any podcasts yet.

Once the application is running in debug mode, you can stop the application by clicking on the Stop icon in the AS toolbar.

Attaching the Debugger

If you already have PodPlay running, you can attach the debugger to the currently running app so you don’t have to restart it completely. To do this, simply click the Attach Debugger to Android Process icon in the AS toolbar.

A popup will appear, and you can select the running app to connect to.

Select the com.yourcompany.podplay process and click OK. Now you’re connected and debugging your previously running app!

Debugging Wirelessly

Android Studio also allows connecting and debugging physical devices over WiFi. The main benefit of wireless debugging is the ability to avoid USB connectivity problems, such as driver installation or accidentally disconnecting your device if you have a damaged cable.

To start, ensure that your workstation and your device are on the same network. The device you’re using will need to have Developer options enabled.

To enable Developer options go to the Settings app and choose About phone. Scroll to the bottom where the Build number option is; if you don’t see it, look for Software information. Tap the option seven times. Congrats! You now have access to the Developer options on the device.

Once you enable the Developer options, go and find that menu, typically under Settings ▸ Developer options or Settings ▸ System ▸ Developer Options, and look for the Debugging section.

Turn on the Wireless debugging option. You’ll be prompted with the following dialog to accept wireless debugging on the device’s currently connected network:

Once your device has enabled wireless debugging, you’re ready to connect it to Android Studio! To do so, click the devices dropdown in the toolbar in Android Studio and select the Pair Devices Using Wi-Fi option.

For Android 11+ devices, you can scan the QR code to pair. Open the Wireless Debugging option and choose Pair device with QR code. Scan the QR code from the Android Studio dialog, and it should automatically pair.

You can pair the device with a pairing code for devices lower than Android 11. To do this, open the Pair using pairing code tab in the dialog. On your device, tap Wireless Debugging and choose the Pair device with pairing code option. A dialog on the device will appear with a code, and the device will appear on the Android Studio pairing devices dialog. Click Pair to be able to enter the code.

Enter in the code from your device and select Pair.

The device should pair, and you’ll now be able to run or debug your app wirelessly!

Debugging Multiple Devices

You can also simultaneously connect to multiple devices and debug them in Android Studio. This can be helpful if you need to run a side-by-side comparison of the same app but on different devices.

Firstly, in Android Studio, click the Select Run/Debug Configuration dropdown and choose Edit Configurations….

In the Run/Debug Configurations window:

  1. Select the + icon at the top-right of the dialog to add a new configuration.
  2. Choose Android App in the left column.
  3. Enter in app 2 for the configuration name.
  4. Select starter.app for the module.
  5. Confirm with OK.

Note: If you plan on debugging more than two devices at once, you’ll need to add additional configurations for each additional emulator/device that you’ve connected.

Open PodcastActivity.kt and add a breakpoint inside onCreate():

Now, click app in the Run/Debug Configurations in the AS toolbar dropdown, and then choose the first device you want to debug. Next, press the Debug icon to launch the app in debug mode.

When the application first launches, the breakpoint will hit!

Next, while the app configuration is still debugging and paused on the breakpoint, switch to the app 2 configuration in the toolbar dropdown. Select your second device, and then click the Debug icon.

Now, the breakpoint will hit again, but notice that this time in the debug window, there is now an app 2 tab that is active.

This represents the configuration and device pair that you ran the second time. You can toggle between the tabs to continue running the app on each device and set other breakpoints as necessary.

When you’re done, press the Stop icon in the toolbar and select the option to Stop All processes. This will disconnect the debugger from both devices.

Now that you have devices connected for debugging, you’re ready to start capturing data from them.

Capturing Device Data

Being able to see what’s happening on the device at a given time is a critical debugging technique. Knowing what is happening on the device will give you a better clue as to what may be going wrong in your app in the event of a bug or crash. Some common ways to capture device data are screenshots, recordings and bug reports.

First, you’ll learn about screenshots.

Screenshots

One of the most common capturing tasks you’ll need to perform is taking a screenshot of the device. There are a few different ways to take a screenshot of an Android device:

  1. From the device itself.
  2. In Android Studio.
  3. Via the emulator.

You’ll need to simultaneously press and hold power and volume-up buttons to take a screenshot from most Android devices. A “snap” will occur when you do this, and a shutter sound will play, indicating that you took a screenshot.

Run the application on the device by pressing the Play icon in the AS toolbar. Go to the Logcat window by selecting View ▸ Tool Windows ▸ Logcat.

Once the Logcat window appears, do the following:

  1. Choose the device in the top-left dropdown.
  2. Select the com.yourcompany.podplay process.
  3. Click the Screen Capture camera icon in the left column of the window.

A new dialog window will appear with the screenshot from the device, and you can save the image to your workstation.

If you’re running an emulator, there’s another way to grab a screenshot. In the emulator window, tap the Take a screenshot icon.

Similar to the Logcat screenshot approach, a dialog will appear where you can save the screenshot to your workstation.

Recording Videos

Within the Logcat window, you can also record videos of your device. Press the Screen Record video recorder icon in the left column of the Logcat window.

In the Screen Recorder Options dialog, you can choose the bit rate and resolution you prefer for the recording or use the defaults provided. The dialog also contains options to show screen taps and set the video format if you’re using an emulator.

Click Start Recording to start the recording. You’ll see a new dialog showing that the recording is in progress.

At this point, you can perform the necessary actions you want to have recorded on your running device or emulator. When you’re done, just use the Stop Recording button to stop the video. You’ll then be prompted to save the recording to your workstation file system.

Note: There is a lot more to the Logcat tool than just screenshots and videos! You’ll learn more about all the features that Logcat has to provide in Chapter 3, “Logcat Navigation & Customization”.

Generating a Bug Report

Bug reports are another crucial feature to have in your debugging arsenal. These reports can include things such as stack traces of thrown exceptions or crashes, logs, and other diagnostic information. You can generate bug reports on the device directly or in the emulator menu.

To generate the report on the device itself, you’ll need to have enabled Developer Options. Go to Settings ▸ System ▸ Developer Options, or Settings ▸ Developer Options on some devices, and tap Bug Report.

In the Bug report dialog, select the type of report you want.

Tap Report when you’re ready to have the system generate the bug report. While the report is generating, you’ll see a notification appear in the status bar. This notification provides information about the progress of the report. When the report completes, you’ll see another notification appear with the option to share the bug report.

While sharing bug reports from devices is extremely useful, if you don’t yet have a bug report but can reproduce a specific error or crash you can generate a bug report directly from an emulator and save it to your workstation.

To generate a report from an emulator, click the More option in the emulator window.

In the Extended Controls dialog, click Bug Report in the left column. Here, you have the option to add a screenshot, provide steps to reproduce the bug and include the bug report itself.

Select Save Report, and you’ll be prompted to save the bug report folder on your workstation.

Find the associated bugreport-DEVICE_ID-DATETIME-HASH folder and open it. The following files will be in the folder:

  • avd_details.txt: This file provides detailed information about the emulator, such as name, target type, Android OS, AVD file path, and configuration parameters for the emulator.
  • bugreport.zip: This zip contains the actual bug report details, including logs, stack traces, and other diagnostic data. The following section — Reading the Bug Report will cover this in greater detail.
  • repro_steps.txt: The steps to reproduce that were entered in the previous Bug Report dialog.
  • screenshot.png: The emulator screenshot when you generated the report.

Now that you have a bug report, it’s time to inspect it!

Inspecting the Bug Report Folder

Depending on the method of generating and receiving the bug report, you’ll typically receive a zip file named either bugreport.zip or bugreport-{BUILD-DATETIME}.zip. Extract the associated zip file and open up the associated bugreport folder. There are several files and folders within, but here are some of the prominent ones:

  • bugreport-{BUILD-DATETIME}.txt: This is the main file that you’ll want to reference when you’re attempting to debug your app. It contains error/system logs, system service output and diagnostic information like stack traces.
  • FS/: This folder contains a copy of the device’s filesystem.
  • version.txt: This is the version associated with the Android release letter.

Next, you’ll take a look at the first file mentioned, the actual bug report.

Reading the Bug Report

As previously mentioned, the bug report text file contains a ton of useful information about what happened in your app and the Android OS during the time the bug report covered. Here you can view things like Android Not Responding (ANR) scenarios, view stack traces for crashes, logs from Logcat and much more!

With ANRs, you can typically associate the logs with the specific ANR stack trace text files typically found in FS/data/anr/. These stack trace files can help you better understand what caused the ANR depending on the thread associated with the stack trace file itself. For example:

"main" prio=5 tid=1 Waiting
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x7257ad48 self=0xe1006210
  | sysTid=10231 nice=-10 cgrp=top-app sched=0/0 handle=0xef514478
  | state=S schedstat=( 2160085204 978028843 3198 ) utm=89 stm=126 core=3 HZ=100
  | stack=0xff5e8000-0xff5ea000 stackSize=8192KB
  | held mutexes=
  at sun.misc.Unsafe.park(Native method)
  - waiting on an unknown object
  at java.util.concurrent.locks.LockSupport.park(LockSupport.java:190)
  at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:450)
  at java.util.concurrent.FutureTask.get(FutureTask.java:192)
  at com.android.settings.dashboard.DashboardFragment.updatePreferenceStatesInParallel(DashboardFragment.java:407)
  at com.android.settings.dashboard.DashboardFragment.updatePreferenceStates(DashboardFragment.java:356)
  at com.android.settings.dashboard.DashboardFragment.onResume(DashboardFragment.java:212)
  at com.android.settings.dashboard.RestrictedDashboardFragment.onResume(RestrictedDashboardFragment.java:138)

This stack trace shows that there was an ANR that occurred on the main thread, specifically in DashboardFragment of the Settings app.

Android Debug Bridge

The Android Debug Bridge (ADB) is a command-line tool that, at its core, allows you to communicate with your connected device. Most of the debugging tools mentioned in this chapter utilize ADB under the hood. In this paragraph, you’ll look at some of ADB’s key commands.

Installing ADB

adb commands should work out-of-the-box as long as you have Android Studio installed. Android Studio comes bundled with adb as part of the platform-tools package in the bundled Android SDK. If you receive a “command not found: adb” error when attempting to run adb, then you can either download the platform-tools package directly or install it via Android Studio.

To download the platform-tools in Android Studio click the SDK Manager icon in the toolbar:

In the SDK Manager dialog, select the SDK Tools tab:

Now check the Android SDK Platform-Tools checkbox and click OK.

Once you download the package, set your PATH environment variable to include <android_sdk_location>/platform-tools. Now you’re ready to use adb!

Starting and Stopping the ADB Server

The first step to using ADB is ensuring the server process is running. The process is typically started when Android Studio is launched. However, it’s useful in certain situations to know how to manually start and stop the process.

First, open the Terminal in Android Studio and try out the following commands:

  • Start ADB:
$ adb start-server
  • Stop ADB:
$ adb kill-server

Pretty straightforward, right? :]

If there are any ADB connectivity issues, it is best to try to stop and restart the ADB server process first to see if that fixes things.

Common ADB Commands

While you may not necessarily be using or interacting with ADB directly, it’s good to have a handful of commands at your disposal. Many of these commands correlate to the tasks and features that you covered earlier in this chapter:

  • Previewing the list of connected devices (either via USB or wirelessly):
$ adb devices
List of devices attached
adb-R58MA3DJGKP-nC7KH1._adb-tls-connect._tcp.   device
emulator-5556   device
  • Launching a specific emulator:
$ adb kill-server
$ emulator -avd Pixel_5_API_30 -port 5557
$ adb start-server
$ adb devices
List of devices attached
emulator-5557 device

The code above launches the emulator named Pixel_5_API_30 on the 5557 port.

  • Installing an app:
$ adb install MyApp.apk

The code above takes the path to the APK as an argument.

  • To target commands to a specific device use the -s option:
$ adb -s DEVICE SOME_COMMAND
...
$ adb -s emulator-5557 install MyApp.apk
  • Downloading files from device:
$ adb pull /file/path/on/device /file/path/on/workstation
  • Sending files to device:
$ adb push /file/path/on/workstation /file/path/on/device
  • Taking a screenshot, yep, there’s even a way to do that in ADB:
$ adb shell screencap /sdcard/screen.png
$ adb pull /sdcard/screen.png ~/Downloads/screen.png

You can now view the screenshot at ~/Downloads/screen.png on your workstation.

  • Recording a screen capture video:
$ adb shell screenrecord /sdcard/recording.mp4

Notice the shell option used in some of the previous adb commands?

You can use shell by itself too, and run shell commands directly on the device:

$ adb shell
generic_x86:/ $ pwd
/
generic_x86:/ $ cd /sdcard
generic_x86:/sdcard $ screencap /sdcard/screen.png
generic_x86:/sdcard $ exit
$ adb pull /sdcard/screen.png ~/Downloads/screen.png

Challenges

Challenge 1: Reading your own bug report

To start reading through the bug report, open a Terminal window pointed at your associated bugreport folder.

Here are some great commands for getting information from a bug report:

  • To see if there were any associated ANRs occurred:
$ grep "am_anr" bugreport-sdk_gphone_x86-RSR1.201013.001-2022-05-08-12-20-27.txt
05-08 11:30:10.864  1000   510 10422 I am_anr  : [0,10231,com.android.settings,952745541,Input dispatching timed out (37c381c com.android.settings/com.android.settings.SubSettings (server) is not responding. Waited 5001ms for FocusEvent(hasFocus=false))]
05-08 11:31:57.648  1000   510 10554 I am_anr  : [0,10231,com.android.settings,952745541,Input dispatching timed out (ActivityRecord{58a944b u0 com.android.settings/.Settings t13} does not have a focused window)]
05-08 12:09:19.723  1000   510 13036 I am_anr  : [0,12519,com.google.android.setupwizard,684211717,executing service com.google.android.setupwizard/.predeferred.PreDeferredServiceScheduler]
05-08 12:13:32.705  1000   510 13872 I am_anr  : [0,12519,com.google.android.setupwizard,684211717,executing service com.google.android.setupwizard/.predeferred.PreDeferredServiceScheduler]
  • To view activities that were in focus to the user and that the user interacted with:
$ grep "am_focused_activity" bugreport-sdk_gphone_x86-RSR1.201013.001-2022-05-08-12-20-27.txt
05-08 11:30:59.125  1000   510 10422 I am_focused_activity  : [0,com.google.android.GoogleCamera/com.android.camera.CameraActivity]
  • Instances of low memory on the device or emulator can be searched with:
$ grep "am_low_memory" bugreport-sdk_gphone_x86-RSR1.201013.001-2022-05-08-12-20-27.txt
05-06 23:48:00.192  1000   510   587 I am_low_memory: 4

To make these commands work, you need to modify them a bit by changing the bug-report file name. Good luck!

Note: grep is a command-line utility used to search for patterns in plain-text files. You can learn more about grep on the GNU Manual.

You can do a lot more with just the bug report text file. The commands mentioned just scratch the surface on unlocking your full debug potential.

Challenge 2: Throwing an exception

Now that you have some of the basics of debugging an Android application under your belt, it’s time to try it out!

Try throwing an exception in the Podplay starter or final project and see if you can generate a bug report and find the stack trace within it.

Key Points

  • Run an app in debug mode to investigate issues in your app.
  • Attach the debugger to an already running app without restarting it.
  • Android Studio allows debugging the app by wireless connection to your device.
  • There is an option to debug multiple devices simultaneously.
  • Capture device data via screenshots, video recordings and bug reports.
  • Android Debug Bridge is command-line tool to run low-level debug commands.

Where to Go From Here?

Congrats on starting your debug journey. There’s more to come in the following chapters, and you’ll dive deeper into the different aspects of debugging Android apps. As you work through the chapters in this book, you’ll become well equipped to handle almost any error or crash that comes your way.

ADB is a powerful tool to use, and this chapter only demonstrates the tip of the iceberg. Read the Android Developers ADB user guide to learn more about all the commands provided by ADB.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.