- Shell 100%
| claude-code | ||
| scripts | ||
| README.md | ||
adb-scripts
Small POSIX shell tools for driving an Android device over adb, written for a Pixel running GrapheneOS but not tied to it.
The scripts
adbappsreads and changes app permissions, and can export the lot to JSON to put back after a factory resetadbtexttypes into whatever field has focus on the deviceadbwconnects over wireless debugging, finding the port over mDNS because it changes every time debugging is switched on
Requirements
adb(Arch:android-tools)- USB debugging enabled on the device
jq, where a script produces or reads JSONavahiandyq, foradbw
Conventions
Every script here follows the same shape:
--helpprints its own usage; subcommands have their own page where they exist--device <serial>picks the device when more than one is connected; without a serial it lists what is connected and exits- Flags have both a short and a long form (
-j/--json), except--device, which is long only so that-dstays free for the subcommands - Flags may appear anywhere on the command line, before or after the arguments
- Errors go to stderr, data to stdout, so output can be piped
- Nothing on the device needs root: only what the system exposes to the
shelluser.adbwdoes ask for sudo here, and only to open the firewall
Run any script with --help to see what it does.
Permissions and groups
Settings shows permission groups — Camera, Contacts, Nearby devices — and applies a decision to every permission a group holds. adb works one permission at a time, and the two use different names for the same thing.
Where a name is expected, either form is accepted: CONTACTS acts on the whole
group, READ_CONTACTS on that permission alone. A bare name is only ambiguous
when it is both a permission and a group of several, and then the fully
qualified android.permission.X or android.permission-group.X settles it.
Acting on a single permission leaves its group in a state Settings cannot produce, which is either what you wanted — an app running on the bare minimum — or something left half done.
Wireless debugging
The port changes every time wireless debugging is switched on, and again after
pairing, so there is nothing to remember: adbw reads it from the mDNS
announcement the device makes. The same goes for the pairing port, which is
only announced while the pairing window is open.
Pairing belongs to the machine's adb key, not to the network. It lives in
~/.android/adbkey and adbkey.pub, so copying those two files to another
machine carries the pairing with it — and losing them means pairing again.
The six-digit code is never anywhere but the screen: Android delivers it by broadcast to the settings UI and keeps it out of every log and dump. Nor can that screen be opened from adb, since it lives in an activity Settings does not export. So pairing always takes a few taps on the device.
Discovery needs mDNS through the firewall. Where fwctl manages one, adbw
opens mdns for the search and takes it back out once connected, keeping the adb
port. fw.yaml itself is always put back, so nothing outlives the run and a
reboot closes what is left. Any other firewall is left alone: if a search turns
up nothing at all, that is the first place to look.
Installing
They live in scripts/ and are self-contained files with no build step:
call them from there, or drop them somewhere on $PATH.
The name shown in help messages follows the file, so renaming a script is safe.
Notes
Anything an app keeps in /data/data stays out of reach without root, which
is the point of the sandbox. These scripts work with what adb exposes and
stop there.