Skip to content

Logcat and crashes ​

When an app crashes, freezes or does something odd, the reason is almost always written in the phone's log. This lesson shows how to read that log, cut it down to the one app you care about, and find the line in a crash that points at the bug.

What the log is ​

Android keeps a running log in memory. The system and every app write short messages to it as they work. Logcat is the tool that reads it, and you run it through ADB:

bash
adb logcat

Lines pour in, newest at the bottom, until you press Ctrl + C. A quiet phone writes many lines a second; that is normal.

Read one line ​

text
11-09 14:03:20.871  6120  6120 I ActivityManager: Start proc 6120:com.example.notes/u0a190 for …
└──── time ──────┘  PID   TID  │ └──── tag ────┘  └──────────────── message ─────────────────┘
                               priority
PartIn the exampleWhat it is
Date and time11-09 14:03:20.871When the line was written, on the phone's clock
PID6120The process ID: a number for the running program that wrote it
TID6120The thread ID: which thread inside that process. Equal to the PID for the app's main thread
PriorityIHow important the line is
TagActivityManagerA short name for the part of the code that wrote it, chosen by its developer
MessageStart proc …The text itself

This layout is called threadtime, and it is what adb logcat prints by default on current Android. DroidDeck asks for it by name with adb logcat -v threadtime.

Each app gets a new PID every time it starts. Note it: you will filter on it later.

Priorities ​

Every line has one of six priorities, from chattiest to most serious:

LetterPriorityTypical use
VVerboseEverything, in detail. Usually only in development builds
DDebugInformation for the developer
IInfoNormal events: an app started, a connection opened
WWarningSomething unexpected that the code recovered from
EErrorSomething failed
FFatalSomething failed so badly the process is ending

A priority filter means "this and everything more serious". Filter at W and you see W, E and F.

Buffers ​

The log is kept in several separate memory areas, called buffers:

BufferWhat goes in it
mainMost app and system messages
systemMessages from the Android system itself
crashCrash reports only
eventsShort coded system events, mostly for tools
radioMobile network and telephony messages

Plain adb logcat shows main, system and crash together. Pick others with -b, for example adb logcat -b crash for only crashes, or -b all.

Buffers are a fixed size. On a busy phone, old lines are pushed out within minutes, so save a log soon after something goes wrong.

Filter the log ​

On the command line, a filter is tag:priority. * means every tag, and S (silent) hides it:

bash
adb logcat "*:E"                              # errors and fatal lines only
adb logcat ActivityManager:I "*:S"            # only ActivityManager, Info and up
adb logcat -s NotesSync                       # only the tag NotesSync, everything

Put *:E in quotes. Without them, your shell may treat * as a file name pattern: a file in the current folder called x:E would quietly replace it.

One app only ​

Tags are chosen by developers and are not unique, so filtering on a tag often misses lines. The reliable way is the process ID. pidof on the phone finds it, and --pid keeps only that process's lines:

bash
adb shell pidof com.example.notes
adb logcat --pid=6120

Or both at once, in a Bash shell:

bash
adb logcat --pid=$(adb shell pidof -s com.example.notes)

The catch: when the app restarts, it gets a new PID, and you have to run it again.

The same in DroidDeck ​

The Logcat tab starts the stream as soon as a device is selected. Its toolbar holds the filters, and they combine: a line must pass all of them.

FilterWhat it does
V D I W E FShows the chosen priority and everything more serious
TagKeeps lines whose tag contains your text, ignoring case
ContainsKeeps lines whose message contains your text
PackageKeeps lines from one app, given its exact package name

Type com.example.notes into Package and a chip shows the app's pid, or not running. DroidDeck checks again every three seconds, so when the app restarts with a new PID, the filter follows it. That solves the catch above. The details are in Read the device log.

Read a crash ​

When an app crashes on an uncaught Java or Kotlin error, Android writes the report at priority E under the tag AndroidRuntime, starting with FATAL EXCEPTION. Here is a typical one, trimmed:

text
E AndroidRuntime: FATAL EXCEPTION: main
E AndroidRuntime: Process: com.example.notes, PID: 6120
E AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.notes/com.example.notes.EditorActivity}: java.lang.NullPointerException: …
E AndroidRuntime:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:…)
E AndroidRuntime:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:…)
E AndroidRuntime:     …
E AndroidRuntime: Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference
E AndroidRuntime:     at com.example.notes.EditorActivity.updateCounter(EditorActivity.java:42)
E AndroidRuntime:     at com.example.notes.EditorActivity.onCreate(EditorActivity.java:18)
E AndroidRuntime:     at android.app.Activity.performCreate(Activity.java:…)
E AndroidRuntime:     …

The block is a stack trace: the chain of method calls that was running when the error happened, most recent call first. Read it in four steps:

  1. Which app and thread. FATAL EXCEPTION: main and Process: com.example.notes say the app's main thread crashed. The main thread draws the screen, so the app closes.

  2. Find the last Caused by:. The first exception is often a wrapper. Here the system says it could not start a screen, Unable to start activity. The real cause is further down: a NullPointerException, with a message saying code called length() on a text value that was null, meaning empty, not set.

  3. Find the first line in the app's own code under that Caused by:. Skip lines that start with android., java. or androidx.; they belong to the system and libraries. The first line in com.example.notes is EditorActivity.updateCounter(EditorActivity.java:42): the file EditorActivity.java, line 42, inside updateCounter.

  4. Read the line below it to see how the code got there: onCreate called updateCounter while the screen was opening. So a text value was still null when the screen first appeared.

That is what a developer needs, and what a tester should paste into a bug report: the whole block from FATAL EXCEPTION to the end of the trace, plus the steps that caused it.

Two other kinds of failure look different:

  • App not responding. An app that freezes for several seconds gets an ANR in com.example.notes error from the tag ActivityManager. ANR means Application Not Responding: the main thread was busy and the screen stopped answering.
  • Native crashes, in code written in C or C++, show F lines such as Fatal signal 11 (SIGSEGV) from the tag libc, followed by a block of F DEBUG lines.

Save a log ​

bash
adb logcat -d > notes-crash.txt          # what is in the buffers now, then stop
adb logcat -b crash -d                   # recent crashes only
adb logcat > notes-live.txt              # keep saving until Ctrl+C
adb logcat -c                            # erase the buffers on the phone

-d dumps what is there and exits, so it is the one to run straight after a crash. In DroidDeck, Export current view to ~/Downloads saves the lines your filters show, to a droiddeck-logcat-…log file. Set the priority to V and empty the filters first to save everything.

WARNING

adb logcat -c, and DroidDeck's Clear (logcat -c), erase the log on the phone itself, not only on your screen. Lines from before that moment are gone for every tool. Save first.

A clean start helps when you reproduce a bug: save, clear, reproduce, save again. The second file then holds only what matters.

Stay safe ​

  • Logs can hold personal data. Apps sometimes log email addresses, account names, file names, locations, even tokens. Read a log before you attach it to a public bug report, and trim it to the app and the minutes that matter.
  • Never log secrets in your own apps. Anything an app writes to logcat can be read by anyone with ADB access to the phone.
  • Save before you clear. Clearing cannot be undone.

Check yourself ​

QuizLogcat and crashes

Question 1 of 6

In logcat you select the priority W. Which lines do you see?

Score: 0

What you learned ​

  • Each logcat line has a time, PID, TID, priority, tag and message.
  • Priorities run V D I W E F; a filter shows that level and above. Buffers keep different kinds of message, and old lines roll out.
  • Filter one app by its process ID; DroidDeck's Package filter follows the app across restarts.
  • In a crash, find the last Caused by:, then the first line in the app's own code: file and line number.
  • Save with adb logcat -d; clearing erases the phone's log for good.

Next steps ​