Skip to content

Service Connection

thejaustin edited this page Sep 19, 2026 · 4 revisions

Service Connection & Start Flow

This page documents how Shizuku+ starts its privileged service, how connection errors are handled, and what the background auto-start system does on your behalf.


Starting via Wireless ADB

Tapping Start on the home screen opens the connection terminal. The flow has four phases:

1. Port Resolution

Shizuku+ resolves a port in priority order:

Priority Source Notes
1 System property (adb_tcp_port) Set when Wireless Debugging is already active
2 Loopback probe (127.0.0.1:5555, then last/custom port) AdbPortProber opens a fast TCP socket (150 ms timeout) — works with no Wi-Fi, over 5G/LTE, or fully offline
3 mDNS discovery Broadcast by the device when Wireless Debugging is on
4 Last saved port Remembered from the most recent successful connection

If none are available, the discovery dialog opens and waits for the system to advertise a port.

Starting without Wi-Fi (5G / LTE / offline)

Android disables mDNS advertisement on cellular data, which historically made Wireless Debugging look "broken" whenever you weren't on Wi-Fi. Shizuku+ works around this by probing the loopback interface directly:

  • AdbPortProber opens a TCP socket to 127.0.0.1 on candidate ports (standard 5555 first, then your last-used and custom TCP ports). If ADB's TCP/IP mode is already listening, the connection is instant — no Wi-Fi and no mDNS required. This enables a 1-tap start on cellular or with the network fully off.
  • The connection dialog polls loopback live, so it connects the moment port 5555 (or a Mobile Hotspot) starts listening.
  • When mDNS genuinely is the only option, the dialog surfaces a diagnostic banner and a Mobile Hotspot launcher, explaining that enabling the hotspot lets Wireless Debugging work over 5G.

2. TCP Connection

AdbClient connects to 127.0.0.1:<port> using TLS. Up to 8 attempts with exponential back-off (200 ms → 3 s cap) are made before giving up, handling transient readiness delays after the port is advertised.

If TCP Mode is enabled and the active port differs from the stored TCP port, Shizuku+ first connects on the current port and issues tcpip:<stored_port> to switch ADB into persistent TCP mode before the main connection.

3. Service Launch

Once connected, Shizuku+ runs libshizuku.so --apk=<path> over the ADB shell channel. This starts the privileged shizuku_server process.

4. Binder Wait

After the launch command returns, Shizuku+ waits up to 15 seconds for the server binder to register. If the binder does not arrive in time, it silently retries once (another 15 s window) before surfacing the timeout error dialog.

On success, the elapsed wait time is shown (Connected in 1.3s) and the terminal closes immediately with haptic feedback.


The Connection Terminal

Element Behaviour
Progress bar Indeterminate; visible during connection, hidden on error
Cancel Dismisses the terminal immediately at any point
Elapsed time "Connected in X.Xs" logged just before auto-close
Retry Appears in every error dialog; clears the terminal and restarts from phase 2
Auto-close Terminal closes the moment the binder is confirmed — no artificial delay

Error Reference

Error Meaning Recovery
Can't connect to port ADB port not reachable — often blocked by a firewall, VPN, or ad-blocker Whitelist Shizuku+ in any network filtering app
Service did not start in time Server started but binder not received within 30 s total (2 × 15 s) Check Wireless Debugging is still enabled; tap Retry
Please pair first Device requires pairing before connecting Go through the pairing flow in Developer Options
Unable to generate key Device KeyStore is broken May require a factory reset or OEM-specific repair
SSL handshake failed ADB keys are corrupted Tap "Go to Developer Options" in the dialog and reset ADB keys
Root not granted Root shell is unavailable Grant root to Shizuku+ in your root manager
Unexpected error Unclassified exception See the terminal log for details; tap Retry

Starting via PC ADB

For devices that can't use Wireless ADB (older Android, or you'd rather use a computer), Shizuku+ can be started with a one-time adb command run from a PC. This has to be repeated after every device restart — there's no persistent pairing like Wireless ADB has.

  1. Install platform-tools on your computer if you don't have adb already (Google's official download).
  2. Enable USB debugging: Settings → About phone → tap "Build number" 7 times to unlock Developer Options, then Settings → Developer options → enable USB debugging.
  3. Connect your device: plug in via USB (accept the "Allow USB debugging?" prompt on the phone), or use adb connect <device-ip>:<port> if you've already got the device reachable over Wi-Fi.
  4. Get the exact command for your install: open Shizuku+ → the "Start via ADB" card → View command. The path is specific to your device/install, so copy it from there rather than typing it by hand.
  5. Run it in a terminal on your computer: adb shell <the path you copied>.

If adb devices doesn't show your phone, the USB debugging prompt wasn't accepted, or you're on the wrong USB cable/port (some cables are charge-only). If the command runs but nothing happens in the app, see Error Reference above — the same failure modes apply.


Starting via Root

When root is the last-used launch method, Shizuku+ skips ADB entirely:

  1. Acquires a root shell via libsu.
  2. Runs libshizuku.so --apk=<path> as root.
  3. Waits for the binder (same 15 s × 2 logic as the ADB path).

The root path has the same progress indicator, cancel, and retry behaviour as the ADB path.


Background Auto-Start (Boot & Watchdog)

On Boot

BootCompleteReceiver fires on BOOT_COMPLETED, LOCKED_BOOT_COMPLETED, MY_PACKAGE_REPLACED, and HTC/Xiaomi quick-boot broadcasts.

It reads the last launch method and dispatches accordingly:

  • ADB: Enqueues AdbStartWorker via WorkManager with optional Wi-Fi constraint.
  • Root: Runs ShizukuReceiverStarter.rootStart() directly.

AdbStartWorker Port Resolution

The worker resolves a port using the same priority order as interactive starts, with one addition: the saved last port is tried as a fast-path before launching mDNS discovery. On devices where the port is stable across reboots, this makes background starts significantly faster.

1. System property port → connect immediately
2. Loopback probe       → connect immediately  (127.0.0.1:5555 / last / custom port)
3. Last saved port      → connect immediately  (fast-path, no discovery needed)
4. mDNS discovery       → wait up to 15 s for the device to advertise a port

Cellular / 5G auto-reconnect: background reconnection previously refused to run whenever Wi-Fi was off, because the worker's Wi-Fi constraint (EnvironmentUtils.isWifiRequired()) was unconditional. It now returns false — i.e. Wi-Fi is not required — when TCP mode is on, when adb_tcp_port is set, or when a loopback probe finds 5555/the last port already listening. So if ADB TCP/IP is active, the service auto-reconnects after a reboot even on cellular data with no Wi-Fi in range.

Watchdog

When enabled in Settings, WatchdogService runs as a foreground service and monitors the ShizukuStateMachine state flow. On a CRASHED state:

  • Waits for the exponential back-off cooldown (5 s → 10 s → 20 s … → 5 min cap).
  • Calls ShizukuReceiverStarter.start() to relaunch the service.
  • Resets the crash counter once the service is confirmed running.
  • Shows a crash notification with links to learn more or disable alerts.

Two independent layers exist purely because they fail differently, and each covers a gap the other can't:

Layer Interval What it catches
WatchdogService Continuous (state-flow listener) Fast, in-process recovery from a normal Shizuku crash
WatchdogWorker (WorkManager) Every 2 hours Restarts WatchdogService if the OS killed just that service but left the app process alive
WatchdogAlarmReceiver (AlarmManager) Every 15 minutes Restarts everything if the entire app process was killed — the case neither of the above can self-detect, because both run inside the process that got killed

That third layer exists because some OEM battery managers (most notably Samsung One UI's "Sleeping apps" freezer) don't just kill a service — they freeze or kill the whole process, watchdog included, on screen lock (#415, #417). A dead or frozen process can't notice its own death. AlarmManager alarms are dispatched by the system itself (system_server), so the alarm can cold-start a fresh process to check on Shizuku even if the previous one never got the chance to. This needs the SCHEDULE_EXACT_ALARM permission for tight timing; if you decline it (or your OEM restricts it), Shizuku+ falls back to an inexact wake automatically — see Permissions.

This is a mitigation, not a full fix — if your OEM's freezer is aggressive enough, the app being fully asleep can still delay recovery by up to the alarm interval. If you're on a Samsung device, exempting Shizuku+ from Settings → Battery → Background usage limits → Sleeping apps manually still gives the most reliable result.


Activity Log

Every service start and watchdog restart is logged to the Activity Log (Settings → Activity Log):

Event Log entry
Interactive ADB start Service started via ADB on port <N>
Interactive root start Service started via root
Background worker start Service started via background ADB worker on port <N>
Watchdog restart Watchdog: restarting after crash #<N>

Last Port Memory

After every successful ADB connection, Shizuku+ saves the port to SharedPreferences (last_adb_port). This port is used as a fallback in three places:

  • Interactive start (home screen Start button)
  • AdbStartWorker background start
  • mDNS discovery dialog (if the saved port is still valid, the dialog resolves immediately)

The saved port is updated on every successful connection, so it always reflects the most recent working configuration.

Clone this wiki locally