ADB is one of the most useful tools for understanding what is happening inside an Android device. It lets us communicate with a phone from your computer, inspect running processes, install apps, read logs, explore files, debug applications, and investigate parts of Android's operating system.
ADB has its own commands, while adb shell gives you access to a separate set of commands provided by Android's shell environment.
What is ADB?
ADB stands for Android Debug Bridge. It is a command-line tool included in Google's Android SDK Platform-Tools. It allows your computer to communicate with an Android device or emulator.
For example, you can run these commands from a computer terminal:
adb devices
adb install app.apk
adb logcat
adb shellADB Commands versus shell commands
There are two different command environments.
Environment A – Your computer's terminal
Commands start with `adb`.
These are ADB client commands executed on your computer.Environment B - Android's shell
Commands execute on the device.
After the shell opens:
These are commands available inside Android's shell environment.You don't need to enter the interactive shell for every command.
Set up ADB and connect your phone
Step 1: Install Platform-Tools
Download from the Google's official page. The package contains adb and is available separately from the full Android Studio installation.
Open a terminal in the directory containing the executable, or add that directory to your system's PATH.
Check that ADB works:
Step 2: Enable USB debugging
On your Android phone:
- Open Settings and find
About phone. - Tap
Build numberrepeatedly, commonly seven times, to enable Developer options. - Open Developer options and enable
USB Debugging. - Connect the phone to the computer using USB.
- Unlock your phone and approve the debugging authorization prompt, checking the computer's identity before trusting it.
Menu names can vary by manufacturer.
Step 3: Verify the connection
For more details:
Example:
The status matters:
Status | Meaning |
|---|---|
device | ADB has an active connection. |
unauthorized | The phone has not authorized this computer. |
offline | ADB cannot currently communicate properly with the device. |
No device listed | No device was discovered by the ADB server. |
A device status means the ADB connection is established; it doesn't guarantee that Android has completely finished booting.
Connection and Device Management
These commands manage the server, find devices, and target the right one. They are the first things you run every session.
Seeing devices & the server:
| Command | What it does |
| adb devices | List connected devices and their state (device, unauthorized, offline) |
| adb devices -l | Same, with more detail (model, transport id, usb path |
| adb start-server | Start the background server explicitly (usually automatic) |
| adb kill-server | Stop the server – the universal first fix for weird states |
| adb reconnect | Reset the connection to a device |
| adb reconnect offline | Reset only devices stuck in offline |
| adb get-state | Print one device's state |
| adb get-serialno | Print the device's serial number |
Targeting a specific device (when more than one is connected, or over network):
2 File Transfer & app install
Moving files – push and pull. These copy between laptop and device:
adb push localfile.txt /sdcard/ # laptop -> device
adb push ./myfolder /sdcard/myfolder # a whole directory
adb pull /sdcard/photo.jpg . # device -> laptop (to current dir)
adb pull /sdcard/DCIM ./backup # pull a directoryInstalling apps – adb install. This pushes an APK and runs PackageManager's install:
adb install app.apk # install
adb install -r app.apk # reinstall, keeping data (-r = replace)
adb install -d app.apk # allow version downgrade
adb install -g app.apk # grant all runtime permissions at install
adb install -t app.apk # allow a 'test' APK (debug-built)
adb install -i com.android.vending app.apk # set the installer package nameadb install-multiple base.apk split_config.arm64_v8a.apk split_config.en.apk
adb install-multiple -r *.apk # all splits, reinstallThere's also install-multi-package for installing several different apps automatically in one transaction.
Uninstalling:
adb uninstall com.example.app # remove app + its data
adb uninstall -k com.example.app # -k = keep the data/cache directoriesThe install flow, under the hood. adb install really does: push the APK to a staging area on the device, then invoke pm install (PackageManagerService), which verifies the signature, parses the manifest, assigns the app a UID, sets up its data dir, and registers its components/permissions. You can do the two steps by hand — adb push app.apk /data/local/tmp/ then adb shell pm install /data/local/tmp/app.apk — which is sometimes needed for edge cases, and shows that install is just a convenience wrapper over pm.
Related install/package host commands:
| Command | What it does |
| adb shell pm path <pkg> | Find where an installed APK lives (to pull it) |
| adb pull $(adb shell pm path <pkg> | sed ‘s/package://’) | One-liner to pull an installed app's base APK |
| adb shell pm clear <pkgadb> | Wipe an app's data to factory-fresh (keeps the app) |
| adb shell pm list packages | List installed packages |
A common recipe – extract an installed app:
adb shell pm path com.example.app # e.g. prints: package:/data/app/.../base.apk
adb pull /data/app/.../base.apk . # copy it to the laptop3 Logging, debugging & bug capture
adb logcat the live system log, your single most-used diagnostic. Everything the OS and apps log streams here.
Core usage:
adb logcat # live stream (Ctrl-C to stop)
adb logcat -d # dump the current buffer and exit (no streaming)
adb logcat -c # CLEAR the buffer (run before a test)
adb logcat -t 100 # show the last 100 lines and exit
adb logcat -t '01-01 10:00:00.000' # show lines since a time
adb logcat > log.txt # save to a file on the laptopThe reset-reproduce-read loop is the professional workflow: adb logcat -c (clear) -> do one action on the device -> adb logcat -d (read only what that action produced). Without clearing first you drown in backlog.
Output formats (-v) change how each line looks:
| -v format | Shows |
| brief | default-ish: priority/tag/pid + message |
| time | adds a timestamp |
| threadtime | timestamp + PID + TID (the most useful; often the default now) |
| color | colorizes by priority |
| long | each field on its own lines (verbose) |
Combine: adb logcat -v threadtime -v color.
Filtering by tag and priority: The syntax is TAG:PRIORITY pairs ending with *:S (silence the rest). Priorities: Verbose < Debug < Info < Warn < Error < Fatal.
adb logcat *:E # errors and worse only
adb logcat ActivityManager:I *:S # only ActivityManager at Info and above
adb logcat -s ActivityManager # -s is shorthand for a single-tag filter
adb logcat -e "token|password" # -e = only lines matching this regexFiltering by process:
adb logcat --pid=$(adb shell pidof -s com.example.app) # one app's logs onlyBuffers (-b) – logcat reads several separate ring buffers:
| Buffer | Contents |
| main | app logs (default) |
| system | framework/system logs |
| crash | crash logs only – adb logcat -b crash for just fatals |
| events | structured system events (am_proc_start, launch times) |
| radio | telephony/modem |
| all | every buffer |
Example: adb logcat -b crash -d grabs the latest crash stack; adb logcat -b events shows the Activity Manager's structured record of what it did.
4 Running commands & lifecycle control
adb shell – two modes. This is how you run commands on the device:
adb shell # INTERACTIVE: drops into a device shell prompt ($)
adb shell ls /sdcard # ONE-SHOT: runs one command and returns immediatelyInteractive mode is for exploring (you type command after command, exit to leave). One-shot mode is for scripting and quick checks. It's the form you will use in the most examples and in scripts.
Getting root in the shell. On your Magisk-rooted retails device:
adb shell # prompt is $ (shell user, uid 2000)
su # prompt becomes # (root) - Magisk may prompt to grant
# .... root commands
exit # drop root
exit # leave the shellOr run a single root command from the laptop without going interactive:
adb shell su -c 'ls /data/data' # run one command as root, come straight backThe quoting trap – the #1 source of confusion. When you run adb shell ‘something’, there are two shells involved: your laptop's shell and the device's shell. Both try to interpret quotes, $, *, >, ;, etc. Rules of thumb:
- Wrap the whole remote comand in single quotes so your laptop shell passes it through untouched:
adb shell ‘echo $RANDOM’– the$RANDOMis expanded on the device, not your laptop. - A redirect like
adb shell ‘ps > /sdcard/ps.txt’(quoted) writes the file on the device; unquotedadb shell ps >ps.txtwrites it on the laptop. The quotes decide where the redirect happens. - Globs (
*) similarly: quoted = expanded on device, unquoted = expanded on laptop (usually wrong). - When in doubt, single-quote the entire remote command and reason about “this runs on the device”.
Forwarding ports (handy for debugging device-side servers, or Frida):
adb forward tcp:8080 tcp:8080 # laptop:8080 -> device:8080
adb reverse tcp:3000 tcp:3000 # device:3000 -> laptop:3000 (device reaches your laptop)
adb forward --list # list active forwards
adb forward --remove-all # clear themadb reverse is especially useful: it lets an app on the device reach a server running on your laptop – common in development and instrumentation.
5 The on-device shell toolbox (Linux side)
Once inside adb shell, you are in a Linux-like environment. Most standard Unix commands exist, but provided by toybox (a compact single-binary implementation), not the GNU coreutils you know from desktop Linux. That means flags are a subset – some option you expect are missing. When one isn't recognized, check toybox or <command> --help.
Navigation & file operations:
| Command | Use |
| ls / ls -l / ls -la / ls -Z | List files: -l = long -a = hidden - Z = SELinux context |
| cd / pwd | Change / print working directory |
| cat / head / tail | Print file / first lines / last lines (tail -f to follow) |
| cp / mv / rm / mkdir / rmdir | Copy / move / remove / make dir |
| find <path> -name ‘*.db’ | Search for files |
| stat <file> | Detailed file metadata (size, perms, times, inode) |
| file <file> | Identify a file's type (if present) |
| ln -s target link | Symlink |
| touch | Create/update a file timestamp |
Text processing (greate for carving signal out of dumpsys / logcat):
| Command | Use |
| grep / grep -i / grep -E / grep -R | Search text; -i = ignore case, -E = regex, -R = recursive |
| sed ‘s/a/b/’ | Stream edit (substitute) |
| awk ‘{print $2}’ | Field extraction ($2 = 2nd column) |
| cut -d: -f1 | Cut by delimiter |
| sort / uniq / wc -l | Sort / dedupe / count lines |
| tr / xargs | Translate chars / build commands from input |
System & process inspection:
| Command | Use |
| ps -A / ps -A -o PID,USER,NAME | List processes; custom columns with -o |
| top / top -m 10 - n 1 | Live resource use; -n 1 one snapshot |
| kill <pid> / kill -9 <pid> | Terminate a process (root for other's processes) |
| pidof <pkg> | Get a process's PID by name |
| id / whoami | Current UID/GID / username |
| uname -a | Kernel version/arch |
| uptime / date | Uptime / current time |
| dmesg | Kernel ring buffer (root; where avc: SELinux denials appear) |
| getevent / sendevent | Read / inject raw input events (low-level) |
Storage & memory:
| Command | Use |
| df -h | Free space per file system |
| du -sh <dir> | Size of a directory |
| mount | Lists mounts + flags (see ro/rw) |
| free -h | RAM usage (if present) |
| cat / proc/meminfo | Detailed memory info |
| lsof | Open files (if present; else ls -l /proc/<pid>/fd) |
Permissions & ownership (mostly root-only to change):
| Command | Use |
| chmod 644 <file> | Change permission bits |
| chown user:group <file> | Change owner |
| ls -Z / chcon | View / change SELinuz context (root) |
Networking:
| Command | Use |
| ip addr / ip route | Interfaces & routing (replaces ifconfig) |
| netstat -tunp / ss -tunp | Active sockets + owning process (root shows PID) |
| ping <host> | Connectivity test |
| cat /proc/net/… | Raw network tables |
What's different from desktop Linux.
6 Android-specific shell commands
These are the commands that make it Android, not just Linux – front-ends to the framework services. They have no desktop equivalent and are where most of your real work happens. (All run inside adb shell, or via adb shell <cmd> from the laptop.)
pm – Package Manager (talks to PackageManagerService):
| Command | Use |
| pm list packages | List all packages |
| pm list packages -3 / -s | Third-party only / system only |
| pm list packages -f | Show the APK path with each package |
| pm path <pkg> | Print an installed app's APK path(s) |
| pm install / pm uninstall <pkg> | Install / uninstall (what adb install wraps) |
| pm clear <pkg> | Wipe an app's data to factory-fresh |
| pm grant <pkg> <perm> / pm revoke … | Grant / revoke a runtime permission |
| pm list permissions -d -g | List dangerous permission, grouped |
| pm disable-user <pkg> / pm enable <pkg> | Disable / re-enable an app |
| pm dump <pkg> | Everything PMS knows (like dumpsys package <pkg>) |
am – Activity Manager (talks to ActivityManagerService):
| Command | Use |
| am start -n <pkg>/<activity> | Launch a specific activity (explicit intent) |
| am start -a <ACTION> -d <uri> | Fire an implicit intent (e.g., open a URL) |
| am start … --es key val | Add a string extra (--ez bool, --ei int, --el long) |
| am startservice / am start-foreground-service | Start a service |
| am broadcast -a <ACTION> | Send a broadcast |
| am force-stop <pkg> | Kill an app completely |
| am kill <pkg> | Kill background processes of an app |
| am instrument | Run instrumentation/tests |
settings – read/write the system settings database:
settings lists global # all global settings
settings get system screen_brightness
settings put global http_proxy 192.168.1.50.8080 # set a system-wide proxy
settings put global http_proxy :0 # clear it
settings delete secure <key>getprop/setprop – system properties
getprop # dump ALL properties
getprop ro.build.version.sdk # read one (ro.* = read-only, set at boot)
setprop debug.myflag 1 # set a writable property (root for most)
watch -n1 getprop sys.boot_completed # watch a property change



Join the discussion
Sign in with your account to post comments, reply to others, and participate in the conversation.
Login to Comment