Skip to content

Dual AIDL Dispatch Thread

NanoMindExplores edited this page Jul 14, 2026 · 1 revision

Dual AIDL Dispatch Thread (v2)

This page documents the dual-thread AIDL dispatch architecture introduced in v2, which fixed the combo delay bug where the player pauses briefly when any button is pressed while moving.

The Bug (v1)

Before v2, NativeGamepadMapper used a single aidlThread for ALL touch calls (analog move + button down/up). Since Binder calls are 5-15ms each and the queue is strict FIFO, a burst of button events would pile up in front of pending touchMove calls. The stick appeared frozen for 50-100ms every time a button was tapped during movement.

v2 Solution: Two Separate Threads

  • stickAidlHandler (Thread.MAX_PRIORITY) — analog stick touchDown/touchMove/touchUp
  • buttonAidlHandler (Thread.NORM_PRIORITY) — button touchDown/touchUp/injectTap

Both threads can execute Binder calls in parallel — Android InputManager accepts concurrent injectInputEvent calls for different pointer IDs without serialization.

Why Two Priorities?

  • Stick (MAX_PRIORITY): A 10-20ms delay on stick movement is VERY perceptible. Stick move events fire at 100-200Hz from getevent.
  • Button (NORM_PRIORITY): A 10-20ms delay on a button press is imperceptible. Buttons fire at most a few times per second.

Coalescing Stick Moves (v2)

Even with a dedicated stick thread, rapid touchMove events (100-200Hz) can pile up. v2 adds coalescing: only the LATEST move per pointer ID is actually sent to the daemon.

If 10 touchMove events arrive in 5ms (while a previous move is still being processed), only the LAST one is actually sent. The 9 intermediate positions are dropped — which is fine, because a fast-moving stick only cares about the final position per frame.

This caps stick move latency at one Binder call (~10ms) regardless of input rate.

Dispatch Routing

  • processStick touchDown/touchUp: dispatchStickCall (analog, high priority)
  • processStick touchMove: dispatchStickMove (analog, coalesced)
  • handleHoldInteraction touchDown/touchUp: dispatchButtonCall (button, normal priority)
  • handleTap/handleTurbo/handleToggle/handleCharge/handleMacro: dispatchButtonCall

Backward Compatibility

The legacy dispatchTouchCall function still exists and routes to dispatchButtonCall by default (since most existing call sites are button touchDown/touchUp).

See Also

  • Injection-Architecture — 3-path injection overview
  • Multi-Pointer-MotionEvent — How v3 builds correct multi-touch MotionEvents

Clone this wiki locally