Skip to content

Using the lsof command

David Griffiths edited this page Apr 18, 2015 · 2 revisions

If you’re running Mac or Linux, you will already have this command installed. lsof tells you what a process is currently talking to. It will list the process’ network connections and which files it’s reading. That’s really useful if, say, you want to see exactly what the adb server process is doing.

But the cool thing is that the Android designers helpfully included a copy of lsof inside every Android device.

Running lsof on your dev machine

Let’s begin by running lsof on a development machine. Let’s take a look at a machine that has an AVD running:

$ adb devices
List of devices attached
emulator-5554	device
$

The adb command finds out which devices are connected by running a background copy of itself called the adb daemon. You can find the daemon using the ps command:

$ ps -ef | grep adb
  501 42769     1   0  7:16pm ??         0:00.31 adb -P 5037 fork-server server
  501 42869 42797   0  7:19pm ttys000    0:00.00 grep adb
$

Here we can see the daemon running as process number 42769, and it was started with adb -P 5037 fork-server server. We’ll see in a moment that the -P 5037 option tells the server to listen on port 5037.

Now we can use the lsof command to look in a little more detail at what the adb server is doing:

$ lsof -p 42769
COMMAND   PID   USER   FD     TYPE             DEVICE  SIZE/OFF     NODE NAME
adb     42769 davidg  cwd      DIR                1,4       442  3815029 /Applications/Android Studio.app/Contents/bin
adb     42769 davidg  txt      REG                1,4   1324340  3828228 /Users/davidg/Library/Android/sdk/platform-tools/adb
adb     42769 davidg  txt      REG                1,4    622896 14974080 /usr/lib/dyld
...
adb     42769 davidg    9u    IPv4 0x27ac4f6f27541281       0t0      TCP localhost:5037->localhost:51686 (ESTABLISHED)
adb     42769 davidg   10u    IPv4 0x27ac4f6f2749b9b1       0t0      TCP localhost:5037->localhost:51691 (ESTABLISHED)
...
$

The lsof command shows a lot more output than you can see here. Each line in the output represents something that the server process is reading from or writing to. The lines with a NODE value of TCP represent network connections. One of the examples above shows a connection going from port 5037 on the server to some other process on port 51686. We can find what that other process is like this:

$ lsof | grep 51686
studio    42696 davidg  487u    IPv4 0x27ac4f6f2a7709b1       0t0      TCP localhost:51686->localhost:5037 (ESTABLISHED)
adb       42769 davidg    9u    IPv4 0x27ac4f6f27541281       0t0      TCP localhost:5037->localhost:51686 (ESTABLISHED)
$

Running lsof without any options, will output every connection made by every process. By searching through all of that and looking for 51686, we find that the network connection is to a copy of Android Studio. So we know that our IDE is communicating with the adb server over a network socket.

Running lsof on an Android device

You can also run lsof on an Android device. If you’re investigating how Android works, it’s actually easier to do it by running a Android Virtual Device than by connecting a physical device. Why? Because the virtual device will give you permission to do just about anything.

You can run a command on an Android device by either:

  • Starting a shell on the device with adb shell and then typing the command in direct, or
  • Passing the command as an additional string on the end of the adb shell command.

We’re going to use the second option. This is how we’ll run lsof on the Android device:

$ adb shell lsof
COMMAND     PID       USER   FD      TYPE             DEVICE  SIZE/OFF       NODE NAME
init          1       root  exe       ???                ???       ???        ??? /init
init          1       root    0       ???                ???       ???        ??? /dev/__null__ (deleted)
init          1       root    1       ???                ???       ???        ??? /dev/__null__ (deleted)
init          1       root    2       ???                ???       ???        ??? /dev/__null__ (deleted)
init          1       root    3       ???                ???       ???        ??? /dev/__kmsg__ (deleted)
init          1       root    4       ???                ???       ???        ??? /dev/__properties__
init          1       root    5       ???                ???       ???        ??? socket:[2438]
init          1       root    6       ???                ???       ???        ??? socket:[2440]
...
lsof       2727       root  mem       ???              1f:00      4096        848 /system/lib/libnetd_client.so
lsof       2727       root  mem       ???              1f:00      8192        848 /system/lib/libnetd_client.so
lsof       2727       root  mem       ???              00:0d         0       2216 /dev/__properties__
lsof       2727       root  mem       ???              1f:00         0        867 /system/lib/libselinux.so
lsof       2727       root  mem       ???              1f:00     94208        867 /system/lib/libselinux.so
lsof       2727       root  mem       ???              1f:00     98304        867 /system/lib/libselinux.so
lsof       2727       root  mem       ???              1f:00         0        787 /system/lib/libcutils.so

This output is a lot longer than we’re showing here. The lsof command within the device does not take any additional options, so it always outputs every connection on every process. But again, we can use other command line tools to cut the data down a little.

$ adb shell lsof | grep adb
adbd        943       root  exe       ???                ???       ???        ??? /sbin/adbd
adbd        943       root    0       ???                ???       ???        ??? /dev/null
adbd        943       root    1       ???                ???       ???        ??? /dev/null
adbd        943       root    2       ???                ???       ???        ??? /dev/null
adbd        943       root    3       ???                ???       ???        ??? /dev/qemu_pipe
adbd        943       root    4       ???                ???       ???        ??? socket:[2503]
adbd        943       root    5       ???                ???       ???        ??? socket:[2504]
...
adbd        943       root   73       ???                ???       ???        ??? socket:[7880]
adbd        943       root   74       ???                ???       ???        ??? socket:[7888]
adbd        943       root   75       ???                ???       ???        ??? socket:[7936]
adbd        943       root   77       ???                ???       ???        ??? socket:[7963]
adbd        943       root  mem       ???              00:01         0       2101 /sbin/adbd
adbd        943       root  mem       ???              00:01    589824       2101 /sbin/adbd
adbd        943       root  mem       ???              00:01    598016       2101 /sbin/adbd
$

Here we can see that there’s another adb-like process running inside the Android device. This one is called adbd, and in fact it’s the other end of the communication channel from the adb server process on the development machine. See that /dev/qemu_pipe line? That’ll be a virtual device in the QEMU emulator that’s communicating with the adb process on the development machine.

In this way, you can use lsof to track down the private communication channels between processes, and unveiling exactly how things talk to each other.