The Hidden Cost of `adb shell input`
For years, automated test runners have relied on `adb shell input tap X Y` or `adb shell input swipe` to interact with Android devices. What most developers don't realize is what happens inside the Android OS every time that command is invoked.
Every single call to `adb shell input` forks an entirely new Linux process, spins up an instance of the Android runtime (`app_process`), initializes Java classpath bindings, and only then dispatches the MotionEvent before immediately exiting. This process initialization takes anywhere from 80ms to 140ms on modern Android hardware.
Direct Compositor Injection via Custom Server Jar
To eliminate this overhead, Gravity QA takes inspiration from the brilliant engineering of Scrcpy. Instead of repeatedly invoking the shell binary, we deploy a lightweight headless Java server directly into the Android zygote process upon initial USB connection.
This server holds an open Unix domain socket and interacts directly with internal `android.hardware.input.IInputManager` and `SurfaceControl` APIs:
// Gravity QA Native Input Dispatcher (Snippet)
public final class TouchDispatcher {
private final IInputManager inputManager;
public boolean injectTouch(int action, float x, float y, long downTime) {
MotionEvent event = MotionEvent.obtain(
downTime,
SystemClock.uptimeMillis(),
action,
x,
y,
1.0f, 1.0f, 0, 1.0f, 1.0f, 0, 0
);
event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
// Direct binder IPC call - zero process fork overhead
return inputManager.injectInputEvent(event, INJECT_MODE_ASYNC);
}
}By communicating over binary protobuf streams through the persistent socket, touch events are registered by the Android display pipeline within 1.2ms—making tests literally 80x faster to interact than legacy Appium suites.