TurboADB
One pip package for driving Android over ADB + scrcpy — a Python API, a full CLI, and a desktop GUI. Built for Android Automotive / IVI head units and regular phones alike.
New in 4.0.0: a release of fixes and hardening. The terminal draws plain output about four times as fast and no longer stalls on a flood or a line that never ends; Stop leaves a
pythonornodeprompt running; device Delete and Rename in Files can no longer land in another folder; keys on a multi-display head unit go to the display they are meant for, and Clear data on Android Automotive acts on the driver's app; closing TurboADB waits for a recording that is still being saved; shortcuts work on installs without PyQt5; and adb, scrcpy, ffmpeg and Windows' own tools are never picked up from the current folder. It is a major version because some commands now report failures they used to pass over (turboadb deviceswithout adb exits 3). Full notes in the changelog.
TurboADB wraps adb and scrcpy so you don't have to remember their flags. The
same engine powers all three front-ends, so every feature below works three
ways — click it in the GUI, run it as a one-line CLI command, or call it from
Python. It bundles its own adb/scrcpy (downloaded on first run), drives
devices on another machine's adb server (handy over RDP / in a lab), and knows
the quirks of Android Automotive head units.
The rest of this README is a hands-on guide: for each feature you get the GUI steps, the CLI command, and the Python call.
Contents
- Install
- First, target a device — the
-s/ config every command needs - The app at a glance — top bar, sidebar, device tabs, themes
- Feature guide
- Interactive shell · Logcat · Files · Apps
- Device controls: keys · media & connectivity · screen & launchers · keyboard
- Mirroring (scrcpy) · Screenshots & recording · Webcam (host camera)
- Telephony · Root & mount · Reboot · Device info
- Remote devices · Share devices (serve) · Deploy serve over WinRM
- Keep things up to date
- CLI cheatsheet — full CLI reference
- Python API notes
- Android Automotive / IVI tips
- Build from source
- License
Install
Pick whichever fits — both give you the full GUI.
A · Windows app — no Python needed
- Download
TurboADB-4.0.0-win64.exefrom the latest GitHub Release (also linked from the website). - Double-click it. On first launch it downloads
adb+scrcpyautomatically (about 20 seconds) and adds a desktop shortcut.
B · With pip — CLI, Python API, and GUI
pip install turboadb
On Windows this already includes the app: the package carries the same
executable (which is why the download is about 59 MB), so turboadb-gui starts
it even without PyQt5 (from a copy in ~/.turboadb/gui, so an upgrade can
replace the packaged file). To run the GUI from the Python code instead — on
Linux or macOS, for example — add the GUI extra:
pip install "turboadb[gui]"
Then use any of: turboadb-gui (the app), turboadb <command> (the CLI), or
import turboadb (the API). Other optional extras are:
pip install "turboadb[winrm]" # remote 'serve' deploy over WinRM
pip install "turboadb[all]" # GUI + WinRM support
Upgrade any time with pip install --upgrade turboadb.
adb and scrcpy download themselves into ~/.turboadb/tools on first use, so
they never need to be on your PATH: adb on Windows, macOS and x86-64 Linux,
scrcpy on Windows. Elsewhere install them with the system's package manager;
TurboADB finds them on PATH.
First, target a device
Everything operates on one device. How you point at it is the only thing that changes between local, network, and remote.
In the GUI — click Connect ▾ → Connect to a device… and choose how it is connected: USB, Network (IP and port) or Remote (a device on another PC's adb server). Attached devices also show live under Connected in the left sidebar; double-click one to open it in a tab. Connect ▾ also has Discover Wi-Fi devices and Pair device (Android 11+), and a USB device can switch itself to Wi-Fi with More ▾ → Go wireless (USB → Wi-Fi).
CLI — list first, then pass -s:
turboadb devices # what's attached here
turboadb -s 10BE330KG9000AF info # a USB serial
turboadb -s 192.168.1.50:5555 info # a network device
turboadb connect 192.168.1.50:5555 # adb connect first if needed
turboadb -s SERIAL wireless # USB device -> Wi-Fi adb in one step
turboadb discover # find wireless-debugging devices
turboadb --adb-host lab-pc-01 devices # devices on ANOTHER pc's server
turboadb --adb-host lab-pc-01 -s DEVICE info # …and drive one of them
Python — build an ADBConfig, then connect():
from turboadb import ADBHandler, ADBConfig
# USB (omit serial if it's the only device)
dev = ADBHandler(ADBConfig(serial="10BE330KG9000AF"))
# network device
dev = ADBHandler(ADBConfig(host="192.168.1.50", port=5555))
# a device on a remote machine's adb server
dev = ADBHandler(ADBConfig(adb_server_host="lab-pc-01", adb_server_port=5037,
serial="DEVICE"))
dev.connect()
Pass safe=True to the handler (the GUI does) to get an OperationResult back
instead of an exception on failure — handy when you don't want one bad call to
abort a run.
The app at a glance
- Top bar — Connect ▾ (connect, save a target, discover Wi-Fi devices, pair, restart ADB), ADB server ▾ (deploy to remote machines, share this PC's devices, stop sharing), Tools ▾ (check for updates, reinstall ADB and scrcpy, open the host webcam, create shortcuts), then icons for the theme, the log panel, settings and help.
- Closing TurboADB closes ADB and scrcpy — any mirror window it opened is
closed and the adb server it started is stopped, so nothing keeps the device
busy after you quit. A server it did not start (Android Studio's, a
script's) or one shared with other machines (
turboadb serve) is left alone, and Settings → Startup turns this off (separate mirror windows then stay open too). - Devices sidebar — Connected devices and Saved targets. Every device you connect is saved as a target automatically (named after the device, never twice; turn this off in Settings → Startup). Type in the search box to filter or quick-connect to a host; hide the sidebar with ‹ or Ctrl+B.
- Device tabs — every device gets Terminal, Logcat, Files, Device Control, Apps, Phone and Webcam (plus IVI Displays on cars and multi-display devices). Screen ▾, Screenshot, Reboot ▾ and More ▾ sit at the right end of that row. More ▾ holds Split view (Terminal, Device Control, Files and Logcat side by side, stacked or in a grid), Device health…, Build details…, Root and mount, Go wireless (USB → Wi-Fi) and Capture bugreport….
- Device type — TurboADB detects Android Automotive, an infotainment head unit, TV, watch, tablet or phone and shows it in the terminal's welcome banner. Cars get the IVI-compatible screen profile and the IVI Displays tab.
- Themes — Graphite (dark) and Porcelain (light) by default, plus Ocean / Sky (navy and crisp blue-white), Dusk / Lavender (violet), Evergreen / Meadow (green), Black / White, Slate / Mist (cool blue-grey), Night / Paper (a warm reading pair), Mocha / Latte and High contrast (dark and light, the most readable) — never pure black or glaring white. The top-bar sun or moon switches between your last dark and your last light theme (pick Slate, and it toggles Slate ↔ Porcelain); its arrow, the Themes menu and Settings → Themes pick any theme directly.
- Notifications — every action shows in the status bar and a small toast; errors show a red popup with a sound and a Copy button. The status bar is coloured by state: a green Connected, a red Error or amber Warning banner, and chips for the ADB server, the devices and the version (click one for its menu). The log panel (its top-bar icon) filters Normal, Verbose, Warnings + Errors or Errors only.
- Settings — Appearance (terminal font, Android shell on a device terminal), Tools (adb / scrcpy / ffmpeg paths), scrcpy (video and audio), Logcat, Themes and Startup.
- Menu bar — File (new target, save output, export / import saved targets), View, Themes, Device (including Run a command on ALL devices…), Tools and Help.
Feature guide
Interactive shell
A real terminal, not a one-shot: history, Tab completion, copy/paste, and a
Stop button that actually stops a runaway command like logcat. The Android
shell runs on a device terminal (adb shell -t -t), so the device prints its own
prompt, output such as ping, logcat | grep or a sed pipeline shows as it
comes, programs that ask for input (read, su) work, and ls fits its columns
to the window. Stop (or Ctrl+C) sends a real Ctrl+C: ping prints its
summary and you stay in the same shell (a program that answers it, such as
sqlite3, keeps running). A command that ignores it is ended by reopening the
shell in the same folder after 3 s, or at once when you press Stop again;
Restart shell always opens a fresh one. Full-screen programs such as
top, vi and less redraw in place and get every key.
If the device or adb gives no terminal (an old adb, a locked-down build), TurboADB falls back to plain pipes and draws the prompt itself; there Stop always reopens the shell, keeping your folder. Settings → Appearance → Android shell turns the device terminal off.
In the GUI — open a device → Terminal tab → start typing. A boxed two-line banner at the top shows the connection, device type, Android version, CPU and serial. Right-click for Copy / Paste / Send key / Save full output to file…; Stop (or Ctrl+C) halts whatever is running. A− / A+ (or Ctrl + mouse wheel) resize every terminal together (12 pt by default).
The Android / PowerShell / CMD switcher at the left of the toolbar opens
PowerShell or Command Prompt on this PC, with TurboADB's adb first on PATH and
ANDROID_SERIAL set to the device. They behave like a normal console: Python,
Node, Git, where and programs in the current folder all work, and output such
as ping or a Python script shows as it comes (adb logcat | findstr word
too). Stop (or Ctrl+C) presses a real Ctrl+C in the shell: ping prints
its summary, a script or batch file stops as in a console window, and the shell
keeps its folder and variables. A program that answers the Ctrl+C (a python
or node prompt showing KeyboardInterrupt) keeps running. A command that
ignores Ctrl+C has its processes ended, and the shell stays; only one that
still won't end, or a shell that is still waiting for an answer three seconds
later (pause, Read-Host, a -Confirm question — Stop never answers for
you), gets a fresh shell in the same folder, at once when you press Stop
again. Stop also drops the lines of a paste that have not run yet. At an idle
prompt Ctrl+C just starts a new line. Inside an adb shell typed there, Stop
sends Ctrl+C to the device instead: only the device command stops and you stay
in adb shell. If that command ignores it, Stop again reopens adb shell in the
same device folder.
Need a second terminal on the same device? More ▾ → New terminal session, or right-click the Terminal tab, opens another terminal tab with its own Android shell, PowerShell and Command Prompt.
CLI — one-shot commands (everything after -- goes to the device):
turboadb -s SERIAL shell -- getprop ro.build.version.release
turboadb -s SERIAL shell --su -- "cat /data/misc/file" # as root, through su
Python — shell() for one-shots, open_shell() for an interactive session:
import time
r = dev.shell("getprop ro.product.model")
print(r.stdout, r.exit_code, r.ok)
sess = dev.open_shell() # persistent ShellSession
sess.send("ls /sdcard\n")
time.sleep(0.5) # read() never waits: it returns what has arrived
print(sess.read())
sess.close()
Logcat
Filter by level, tag, app, or live regex; pause/clear; save the complete log
(even under a flood, or while the tab is hidden, the on-screen view trims to stay
responsive, but every line is kept on disk). So that an unattended capture can't
fill the disk, each capture's history file (and each terminal's) is kept under
1 GB: once it is full its oldest half goes (sooner while the disk is nearly
full), and a save starts with a line saying what was dropped.
"history_limit_mb" in ~/.turboadb/settings.json changes the limit (0:
none).
In the GUI — Logcat tab → pick the level and how much history to include
(Live from now, Last 1,000 + live, …), optionally Tag(s) (exact,
comma-separated), an App (package name or PID, Android 7+), a live Filter
regex or a Highlight pattern such as error|anr → Start. The Filter
ignores case unless Aa is on, matches text that isn't a valid regex (or a
pattern that would take too long to search a long line) as plain text, and
searches the whole capture, not just what is on screen. Changing Tag,
Level or App restarts a running capture where it left off, and a live capture
resumes by itself after a reboot, an ADB restart or a reconnect. Crashes is
a one-click preset, Pause / Clear do what they say, and Save… writes
everything captured.
CLI:
turboadb -s SERIAL logcat --tag ActivityManager --priority W
turboadb -s SERIAL logcat --match "ANR|FATAL" --save crash.log
turboadb -s SERIAL logcat --dump # dump current buffer and exit
turboadb -s SERIAL logcat-clear # clear the buffers
Python — logcat() streams via an on_line callback (and tees to a file);
iter_lines() is a plain generator if you'd rather loop:
dev.logcat(tag="ActivityManager", match="ANR", on_line=print, save_to="crash.log")
for line in dev.iter_lines(["logcat", "-v", "threadtime"]):
if "FATAL" in line:
break
Files (push/pull)
In the GUI — Files tab: This PC on one side, Device on the other.
Select files and press Push or Pull, or drag and drop between the panes
(also from Explorer). Both panes have New folder, New file, Open,
Edit (F4, a built-in editor), Copy / Paste, Rename (F2) and
Delete, plus quick folders such as Downloads and /sdcard.
Double-click a file (or press Enter) to open it in its app on this PC: pictures in Photos, videos in Media Player, text in Notepad, or any app you pick with Open with…. A device file opens as a copy, and each time you save it in that app it goes back to the device, keeping its permissions (TurboADB asks first if the device file changed meanwhile). Programs are never started from here; scripts and text files no app opens go to the built-in editor, which asks the same before it saves over a device file that changed since you opened it.
Selecting works like a file manager: drag beside the names for a block of files, Ctrl+A for all of them, Enter to open, Backspace to go up, Ctrl+Shift+N for a new folder. On Windows Delete moves local files to the Recycle Bin and Shift+Delete deletes them for good; device files always go for good. Each pane shows what it holds and what is selected. A PC file or folder whose name ends in a dot or a space (made by WSL, Git Bash or a Linux drive) is left alone, with a message saying why: Windows cannot address it by its path. When the device refuses a change, TurboADB offers adb root, adb disable-verity and adb remount and retries afterwards (see Root & mount).
The Transfers panel under the panes follows every copy: an overall bar with the files and bytes done, the speed and the time left, and under Details a row per file with its size, progress, speed and adb's exact error if it failed. Retry failed, Clear finished and Copy / Save report… are in its menu; right-click a row to retry it or open its folder.
To browse two folders at once, press New tab (or Ctrl+Shift+T). The new Files tab starts in the same folders and has its own selection and transfers. You can open up to eight, and split view shows two side by side. Rows show the system's own file icons.
CLI:
turboadb -s SERIAL push app.apk /data/local/tmp/
turboadb -s SERIAL pull /sdcard/Download/log.txt .
Python:
dev.push("app.apk", "/data/local/tmp/")
dev.pull("/sdcard/Download/log.txt", "log.txt")
Apps
List, install (single or split APKs), uninstall, clear data, start/stop.
In the GUI — Apps tab: Install APK(s)…, or filter the package list (Third-party only) and select one for Start, Stop, Clear data or Uninstall.
CLI:
turboadb -s SERIAL packages --third-party
turboadb -s SERIAL install app.apk --grant # grant all permissions
turboadb -s SERIAL install base.apk split_config.apk # split install
turboadb -s SERIAL uninstall com.example.app
turboadb -s SERIAL clear com.example.app # wipe app data
turboadb -s SERIAL start com.example.app
turboadb -s SERIAL stop com.example.app
Python:
for pkg in dev.list_packages(third_party=True):
print(pkg)
dev.install("app.apk", grant_perms=True)
dev.install_multiple(["base.apk", "split_config.apk"])
dev.uninstall("com.example.app")
dev.clear_app("com.example.app")
dev.start_app("com.example.app")
dev.stop_app("com.example.app")
Device controls
The Device Control tab has a Device controls panel beside the screen with one-click actions. Each is also a CLI command and an API call.
Keys & input
GUI — Device controls → Navigation (Back, Home, Recents, Power, Notifications, Settings).
turboadb -s SERIAL key home # back, home, recents, power, notifications…
turboadb -s SERIAL scroll down # up | down | left | right
turboadb -s SERIAL tap # tap the centre of the screen
dev.keyevent("home")
dev.scroll("down")
dev.tap_center()
Rapid taps (soak and stress testing)
Thousands of taps on one point, as one loop on the device — no tap waits for
the PC. With --method events (what auto picks when the adb shell may write to
the touchscreen) the taps go straight to the touch device and run several times
faster than input tap, which starts a JVM per tap. --rate caps taps per
second, and --duration taps for a while instead of counting.
GUI — not in the GUI: this is a command-line and API tool.
turboadb -s SERIAL tap-burst 540 1200 --count 5000
turboadb -s SERIAL tap-burst 540 1200 --rate 20 --duration 60
turboadb -s SERIAL touch-device # which touchscreen, and may the shell write to it?
report = dev.tap_burst(540, 1200, count=5000) # {'method': 'events', 'taps': 5000, …}
dev.tap_burst(540, 1200, rate=20, duration=60, on_progress=print)
dev.touch_device()
Media & connectivity
GUI — Device controls → Media & volume and Quick settings (Wi-Fi, Bluetooth, Mobile data, Airplane mode, Hotspot, each with On and Off).
turboadb -s SERIAL media play-pause # previous | next | play-pause
turboadb -s SERIAL wifi on # on | off
turboadb -s SERIAL bluetooth off
turboadb -s SERIAL airplane on
turboadb -s SERIAL hotspot on # best-effort (see IVI tips)
dev.media("play-pause")
dev.set_wifi(True)
dev.set_bluetooth(False)
dev.set_airplane(True)
dev.set_hotspot(True)
Screen & app launchers
GUI — Device controls → Screen & power and Apps & web (a URL or search box plus Browser, YouTube, Spotify, Maps, Play Store, Gallery, Calculator and Camera tiles).
turboadb -s SERIAL screen off # on | off
turboadb -s SERIAL settings # open the Settings app
turboadb -s SERIAL open https://maps.google.com
turboadb -s SERIAL search "nearest charger"
turboadb -s SERIAL camera # also: gallery, calculator
dev.screen_off()
dev.open_settings()
dev.open_url("https://maps.google.com")
dev.web_search("nearest charger")
dev.open_camera() # open_gallery(), open_calculator()
On-screen keyboard
Type into the focused field (useful when the unit has no soft keyboard).
GUI — Device controls → Keyboard: type, then Send (Enter, Backspace, Space, Tab, Esc and Search keys are next to it). While the screen is showing you can also click it and type on your PC keyboard, or use Options → Type or paste text….
turboadb -s SERIAL text "hello world"
turboadb -s SERIAL key enter
dev.input_text("hello world")
dev.keyevent("enter")
Mirroring (scrcpy)
Mirror in its own window or embedded in the tab. A compatibility mode (software decode, forced tunnel host/port, UHID keyboard) handles IVI units that choke on the defaults, and it works through a remote adb server.
GUI — open Device Control, pick a display, then press Start screen to show it in the tab or Separate window (Screen ▾ beside the section tabs does the same from any tab). Click the screen and type on your PC keyboard. The toolbar also has Stop, a screenshot icon, Record…, Audio on / off, Options, Maximize view and Hide controls (hides the controls without stopping the screen; it works while maximized too). The controls sit beside the screen or in a strip below it, whichever shows the screen larger for your window and the screen's shape.
The display picker lists every display by number, name and size (for example
Display 2 · Instrument cluster · 1920x720) as soon as the device connects.
TurboADB asks Android over adb for them, so connecting never starts scrcpy.
Options holds audio forwarding and its source, Compatibility mode (IVI /
automotive), software rendering, the keyboard mode (Standard SDK or UHID
hardware keyboard), Device camera with Back / Front — the device's own camera
instead of its screen, needing scrcpy 2.2+ and Android 12+ — Manage
displays… and All displays. Audio needs Android 11+; tune codec, bitrate
and latency in Settings → scrcpy.
All displays at once — cars, and any device with several displays, get an IVI Displays tab (Displays on other devices) that shows every display side by side, each controllable with its own Start / Stop, Separate window, screenshot and Record. Every display starts stopped: opening the tab (or Options → All displays), a rescan and a newly found display never start one, and a display you stopped stays stopped. Start the ones you need, or press Start all to start them one after another (it keeps going if you switch to another tab; Stop all ends it). Start all, Stop all and Rescan are at the top, and Maximize on a display shows only that one (Restore or Esc brings the grid back). Each display has its own Back, Home, Recents, volume, mute, power and screenshot buttons, sent to that display.
When scrcpy won't run — some builds can't run scrcpy at all. Settings →
scrcpy → Screen renderer → ADB screencap (or Options → Renderer on one
screen) shows the device through adb screencap instead: it finds the display
through dumpsys display, streams frames over one adb connection (a few frames a
second), and still supports tap, drag, long-press, scrolling and typing.
Record records on the device with screenrecord instead, so it works without scrcpy too.
CLI:
turboadb -s SERIAL scrcpy --max-size 1280 --bit-rate 8M
turboadb -s SERIAL scrcpy --bit-rate 16M --audio-source playback --audio-dup
turboadb -s SERIAL scrcpy --no-control --turn-screen-off
turboadb -s SERIAL scrcpy --video-source camera --camera-facing front
Python:
from turboadb import ScrcpyOptions
sess = dev.mirror(ScrcpyOptions(max_size=1280, bit_rate="8M"))
sess.wait() # blocks until the scrcpy window closes
Screenshots & recording
GUI — Screenshot at the right end of the section tabs (or the screenshot icon in Device Control); Record… in the Device Control screen toolbar. If the screen is already live, a second, windowless recorder runs beside it, so the view never restarts, and stopping saves a playable MP4. Closing TurboADB while a recording runs or is still being saved waits for it: a dialog names the file, and Close without saving is the way out.
CLI:
turboadb -s SERIAL screenshot shot.png
turboadb -s SERIAL record clip.mp4 --time-limit 20 --size 1280x720
Python:
dev.screenshot("shot.png")
dev.screen_record("clip.mp4", time_limit=20, size="1280x720")
The CLI
recordcommand andscreen_record()use device-sidescreenrecordand pull the file back, so they work over RDP without a video tunnel. Given a folder instead of a file, they saverecording-DATE-TIME.mp4there.
Webcam (host camera)
Different from the device camera (scrcpy --video-source camera): the 📹 Webcam
tab views a host webcam — a USB or laptop camera on the machine running TurboADB.
Point one at the physical head unit / bench and watch it beside the scrcpy mirror.
GUI — choose Tools ▾ → Open host webcam (or View → Open webcam (host camera), or the Host webcam tile on the start page) to open it as a standalone tab — no device needed. Every device also has its own Webcam tab, handy beside the screen. Pick a Source:
- Local — this PC — Scan cameras → pick a camera, resolution and frame rate → Start camera.
- Remote — Windows PC — enter the RDP host, User, Domain and
Password → Scan cameras → Start camera. No SSH: TurboADB uses the
same WinRM/NTLM path as
deploy-serveto run ffmpeg on the remote and stream its camera back over a direct TCP socket. Each stream uses a port of its own (28100–28115): open that range in a firewall between the PCs to view more than one.
Then Snapshot, Record (clean H.264 MP4), Pause, Rotate, Flip, and View: Fit, Fill or Stretch. Right-click the video to copy the image.
Local works over RDP too. Capture is local DirectShow, so when TurboADB runs inside an RDP session it sees whatever camera that session exposes. If none shows up: enable camera redirection in the RDP client (Local Resources → More… → Cameras), turn on Windows camera privacy ("Let desktop apps access your camera"), and make sure nothing else is using it.
Remote needs WinRM on the target (
Enable-PSRemoting -Force) and the account a local admin. ffmpeg is provisioned automatically: TurboADB first copies your localffmpeg.exeto the remote over its admin share (\\host\C$, fast on a LAN and no internet needed there — like TurboSSH's push); if the share isn't reachable it falls back to the remote downloading ffmpeg itself, and failing that you can putffmpeg.exeinC:\Program Files\TurboADB\ffmpeg\over RDP, as an administrator (ffmpeg runs with the admin's rights, so it is only ever taken from folders only administrators can write to). The host / user / domain are remembered and the password is saved in the Windows Credential vault (keyring), never in a file. A physical USB camera works headlessly; a camera redirected into someone's RDP session is only visible inside that session.ffmpeg powers the capture; locally it's downloaded once (~160 MB, cached under
~/.turboadb/ffmpeg) or set Settings → ffmpeg path to your own. A remote camera is watched without it; Record on one encodes on this PC, and offers that download when this PC has no ffmpeg yet.
Telephony
GUI — open a device and pick its Phone tab. Calls and messages load the first time you open the tab, never while connecting.
- Dialler — type or paste a number, or use the keypad (hold 0 for +). Call places the call, End hangs up or rejects (while the pill shows Idle it sends nothing: with no call Android takes the End key for the power button), Answer picks up a ringing call, and Open in dialler (or Enter in the number field) only opens the device dialler pre-filled. The toolbar pill shows Idle, Ringing or In call, No telephony on devices without it (e.g. IVI head units), or Checking… while the device does not answer (it is rebooting or unplugged): the page keeps asking and loads again once the device is back. Refresh reloads the call state, calls and messages.
- Recent calls — incoming, outgoing, missed and rejected calls with their time and duration. Double-click a call or press Call back to put its number in the dialler (it never calls by itself); Message starts a message to it.
- Messages — received and sent SMS with a one-line preview. Select one to address a reply, type under New message and press Compose in Messages: the device's Messages app opens with the draft, and you press Send there.
If the device refuses access to its call log or messages, the list says so in place of the rows and the log gets one warning.
Head units and other devices without a phone — the tab first checks what the device has, so nothing shows as an error. Without telephony the pill shows a grey No telephony; without a call log or SMS store the lists say so; and when no standard phone app exists, Call, Open in dialler and Compose are disabled. If the device has its own phone app (a customised head unit's Bluetooth phone, for example), an Open … button starts it.
CLI:
turboadb -s SERIAL dial 1800123456 # open dialer pre-filled
turboadb -s SERIAL call 1800123456 # place the call
turboadb -s SERIAL answer
turboadb -s SERIAL end-call
turboadb -s SERIAL call-log --limit 20
turboadb -s SERIAL sms --limit 20
turboadb -s SERIAL send-sms 1800123456 "on my way"
turboadb -s SERIAL phone-support # telephony + dialler / call / SMS apps
Python:
dev.dial("1800123456"); dev.call("1800123456")
dev.answer_call(); dev.end_call()
for c in dev.call_log(20): print(c)
for m in dev.sms_list(20): print(m)
dev.send_sms("1800123456", "on my way")
print(dev.phone_support()) # which dialler / SMS / phone apps exist (calls no one)
Root & mount
For rooted / engineering builds.
GUI — More ▾ → Root and mount (at the right end of the section tabs).
After adb root or adb unroot (from that menu, or typed in PowerShell or
Command Prompt) every terminal follows: the Android shell reconnects with the new
prompt (# as root), and a PowerShell or CMD tab that was inside adb shell
opens it again in the same folder.
When the Files tab can't change a device file (permission denied or a read-only file system), it asks which of adb root, adb disable-verity and adb remount to run, runs them with any reboot they need, and then retries. More ▾ → Root and mount → Make files writable… opens the same choices at any time.
CLI:
turboadb -s SERIAL root # restart adbd as root (unroot to undo)
turboadb -s SERIAL remount # adb remount
turboadb -s SERIAL mount-rw # mount -o remount,rw /
turboadb -s SERIAL disable-verity # syncs and offers the required reboot
turboadb -s SERIAL access # root, build type, verity, bootloader
turboadb -s SERIAL make-writable # root + remount, rebooting when needed
Python:
dev.root(); dev.unroot()
dev.remount(); dev.mount_rw()
dev.disable_verity(); dev.enable_verity()
dev.access_status() # {'root': True, 'verity': 'enforcing', …}
dev.make_writable(disable_verity=True) # root, disable-verity, reboot, root, remount
Reboot
GUI — Reboot ▾ (System / Recovery / Bootloader / Sideload — the risky ones warn first, doubly so on automotive).
turboadb -s SERIAL reboot
turboadb -s SERIAL reboot recovery # recovery | bootloader | sideload
dev.reboot()
dev.reboot("recovery")
Device info
GUI — the Android terminal's welcome banner shows the connection, device type, Android version, CPU and serial on connect. More ▾ → Device health… and Build details… show the rest, and Battery is in Device controls → Screen & power.
turboadb -s SERIAL info --json # includes kind, kind_label, display_size, telephony
turboadb -s SERIAL build-info
turboadb -s SERIAL battery
turboadb -s SERIAL health # battery, temperature, memory, CPU, uptime
turboadb -s SERIAL bugreport # save a full bug report zip
d = dev.device_info() # dict: manufacturer, model, android_version, sdk, abi, automotive, kind…
print(d["model"], d["android_version"], d["kind_label"])
kind = dev.device_kind() # {"kind": "phone" | "tablet" | "tv" | "watch" | "automotive" | "headunit", …}
print(kind["label"], "because", kind["reason"])
print(dev.battery()) # raw dumpsys battery text
print(dev.health()) # dict: battery, temperature, memory, CPU, uptime
The device type comes from the device itself: Android Automotive OS reports the
android.hardware.type.automotive feature (or automotive in
ro.build.characteristics); an infotainment head unit running ordinary Android
has no telephony feature and a natively landscape display; TVs, watches and
tablets report their own feature or characteristic. Both car kinds set
automotive, which selects the IVI-compatible screen profile in the GUI.
Remote devices
Drive a device that's plugged into a different machine, over its adb server —
exactly what you want for a lab unit reached by RDP. Add --adb-host to any CLI
command, or set adb_server_host in the config. (The host machine has to be
sharing its adb server — see the next two sections.)
turboadb --adb-host lab-pc-01 devices
turboadb --adb-host lab-pc-01 -s DEVICE shell -- pm list packages
turboadb --adb-host lab-pc-01 -s DEVICE scrcpy --max-size 1280
dev = ADBHandler(ADBConfig(adb_server_host="lab-pc-01", serial="DEVICE"))
dev.connect()
Share devices (serve)
Turn the machine a device is plugged into a host others can reach.
GUI — ADB server ▾ → Share THIS PC's devices… (Start once or **Start
- run at login**; opening the firewall needs Administrator, and sharing ends on a warning when the firewall may keep other machines out). ADB server ▾ → Stop sharing & remove auto-start undoes it; removing the SYSTEM startup task needs Administrator too, and TurboADB says so when that task is still installed.
CLI:
turboadb serve # start the shared server + open the firewall
turboadb serve --startup-task # …and keep it running headless across reboots
turboadb serve --uninstall-startup
Python:
from turboadb.devices import start_shared_server, open_firewall, install_serve_task
print(start_shared_server())
print(open_firewall((5037, "27184-27199")))
install_serve_task() # SYSTEM startup task, headless
The shared adb server has no password: anyone who can reach the port can control
the devices. The firewall rules therefore apply on Domain and Private networks
only: on a network Windows calls Public (a café or hotel Wi-Fi) nobody can
connect until you make that network Private (the status line names it).
open_firewall(..., remote_ip="localsubnet") narrows the rules further;
profiles="any" opens them everywhere. Stopping sharing deletes the rules again.
The startup task signs in to devices with your own adb key too, so devices you
already use need no new authorization. It runs as SYSTEM, so an adb that other
accounts could change (the downloaded one in ~/.turboadb/tools) is copied to
Program Files\TurboADB\adb, where only administrators can change it, and the
task runs that copy; serve --startup-task warns when the Python it runs can
be changed without administrator rights.
Deploy serve over WinRM
Push serve onto remote Windows hosts from your machine — one host or a whole
fleet — without logging into each. Uses pywinrm/NTLM, so domain credentials work
over plain WinRM.
GUI — ADB server ▾ → Deploy to remote machine(s) (RDP / WinRM)…: enter the host(s) + admin credentials, Test connection, then Deploy.
CLI:
turboadb deploy-serve lab-pc-01 lab-pc-02 -u "DOMAIN\user"
turboadb deploy-serve lab-pc-01 -u "DOMAIN\user" --test # just check WinRM first
turboadb deploy-serve lab-pc-01 -u "DOMAIN\user" --password-stdin < pw.txt # never in argv
Python:
from turboadb.remote_deploy import deploy_serve
deploy_serve(["lab-pc-01", "lab-pc-02"], "DOMAIN\\user", "password",
on_status=print)
Each target needs WinRM enabled (
Enable-PSRemoting -Forceonce), your account a local admin, and Python + turboadb installed there. adb is downloaded there when the host has none.
Keep things up to date
GUI — Tools ▾ → Check for updates… checks PyPI for a newer TurboADB,
updates it, refreshes adb/scrcpy, and restarts (with no newer TurboADB it
still checks the tools). The standalone Windows app and a source checkout,
which pip cannot update, are told when a newer version is out (at launch, on
the version chip and by this check) and how to get it. The device tabs pause
only while an update replaces adb or scrcpy. Tools ▾ → Download and reinstall
ADB and scrcpy… refreshes only the tools.
turboadb self-update # upgrade TurboADB itself, then adb/scrcpy
turboadb upgrade-tools # only refresh adb/scrcpy
turboadb doctor # report what's installed / missing
CLI cheatsheet
Every command with all its options and examples is in the
CLI reference (also
on the website, with search).
turboadb -h lists everything; turboadb <command> -h details one. Every
command takes --json. Target with -s SERIAL (or -s @NAME for a saved
target); add --adb-host HOST for a remote server.
devices info state serialno ip wait targets connect disconnect pair
tcpip wireless discover restart-server stop-server
shell adb logcat logcat-clear bugreport
push pull ls mkdir touch rm mv cp stat edit
packages install uninstall clear start start-activity activity stop
grant revoke close-apps
displays screenshot record scrcpy screen
key text tap tap-burst touch-device swipe scroll media brightness notifications
wifi bluetooth airplane hotspot mobile-data
settings open search camera gallery calculator
battery health build-info getprop
dial call answer end-call call-state call-log sms send-sms phone-support
root unroot remount access make-writable mount-rw disable-verity enable-verity reboot
forward reverse serve deploy-serve
doctor fetch-tools upgrade-tools self-update shortcut gui
Python API notes
import turboadb exposes the engine and its types. Calls return small
dataclasses — CommandResult (.stdout, .stderr, .exit_code, .ok),
TransferResult, StreamResult. Construct a handler with safe=True for
non-raising OperationResults, or leave it default to get exceptions you can
catch (ADBError and friends). See examples/examples.py
and ARCHITECTURE.md.
from turboadb import ADBHandler, ADBConfig, ScrcpyOptions
dev = ADBHandler(ADBConfig(serial="SERIAL"))
dev.connect()
assert dev.shell("getprop ro.build.version.release").ok
dev.install("app.apk", grant_perms=True)
dev.screenshot("after_install.png")
Android Automotive / IVI tips
device_info()flagsautomotivefor Android Automotive OS and for head units running ordinary Android (seedevice_kind()in Device info); the GUI then uses the IVI-compatible screen profile and adds the IVI Displays tab, which shows every display (centre stack, cluster, passenger) side by side, each stopped until you start it (or Start all).list_displays()names each display (Instrument cluster,Passenger) and asks Android over adb; passmethod="scrcpy"for scrcpy's own list.- If the default mirror fails, use compatibility mode (software decode).
bootloader/sideloadreboots warn hard — many head units have no on-screen recovery UI and can get stuck.- Calculator / Camera / Play Store are often absent; launchers fall back and the log says when nothing happened.
- Hotspot can't always be toggled purely over adb (uid permissions) — TurboADB
tries
cmd wifi, then falls back to opening the tethering settings. - On Android Automotive the driver is a secondary user: Clear data,
grantandrevokeact on the driver's copy of an app, not on the hidden system user's.
Build from source
git clone https://github.com/NVNKENNEDY/turboadb && cd turboadb
pip install -r requirements.txt
python -m turboadb.gui # run the GUI from source
python scripts/build_exe.py # build the versioned Windows exe in dist/
python tests/test_offline.py # offline checks
See ARCHITECTURE.md and CHANGELOG.md.
License
MIT.
Metadata
Release files for turboadb 4.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| turboadb-4.0.0.tar.gz | 61.8 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| turboadb-4.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 122.9 MB
Release files / turboadb-4.0.0.tar.gz
| Download URL | turboadb-4.0.0.tar.gz |
|---|---|
| Size | 61.8 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8df699b43bf45f3b49dff78c2ebc945522c8d9f99262c5c5683dc8552c336538
|
|
BLAKE2b-256 checksum How to use checksums |
5b23ddb028bf0566ee789fb080ed13cf11b131a82c5824f3d0e0285b591be818
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.9
|
Release files / turboadb-4.0.0-py3-none-any.whl
| Download URL | turboadb-4.0.0-py3-none-any.whl |
|---|---|
| Size | 61.1 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e5b2430f4321e09cf80fd2f33ace8127835033dcd0f19befd4e1ec1eeb7cf12c
|
|
BLAKE2b-256 checksum How to use checksums |
290951e85ae34743e8ec9ab62c25b3b16290c8f49e346c1a3112a2e9c9287934
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.9
|