Skip to content

Readiness gate waits on UHID_OPEN, which the kernel does not guarantee (START is tracked but unused) #49

Description

@guaje

Follow-up from the 1.4.2 review (#44, current behavior introduced in ec43809, verified at 53308c9). Posted per the review on #44.

UhidChannel.awaitReady() (app/src/main/java/com/inputleaf/android/shizuku/uhid/UhidChannel.kt:163-178) gates readiness on UHID_OPEN alone:

while (readinessConfig.nanoTime() < openDeadline && !wait.sawOpen.get()) { ... }
if (!wait.sawOpen.get()) return

Kernel mechanics (drivers/hid/uhid.c) — the two events have different guarantees:

  • UHID_START is queued from uhid_hid_start() (the ll-driver .start callback), invoked by hid_hw_start() during probe, before any userspace node is used. It is guaranteed whenever the device bound.
  • UHID_OPEN is queued only when a userspace process opens the HID device through the kernel open path:
static int uhid_hid_open(struct hid_device *hid)
{
	struct uhid_device *uhid = hid->driver_data;

	return uhid_queue_event(uhid, UHID_OPEN);
}

Stock Android's InputReader does open scanned devices, so on AOSP the OPEN arrives — but nothing in the kernel guarantees an opener exists, and the device matrix for this app is precisely OEM ROMs, where input-device open policy is customized (input filters, HID/OTG security toggles, vendor SELinux label variants). An OPEN-less device is a whole-class possibility, not one documented family. (The repo's prior "ColorOS never emits OPEN" rationale does not establish an OPEN-less device: under the corrected constants from #44's first review round, the event that code observed was the real OPEN — mislabeled "START" — and the event it never observed was value 6, UHID_OUTPUT, which never arrives on any device because it is host→device.)

Current behavior regresses attach latency on both device classes:

  1. OPEN-less devices burn the full openTimeoutMs on every createDevice() — even though the reader already tracks START (UhidChannel.kt:220) and a log branch exists for it (:127), because the loop condition at :169 checks only sawOpen.
  2. OPEN-present devices additionally pay the sysfs presence confirmation after OPEN (:173-178, up to presenceTimeoutMs), where the pre-1.4.2 loop treated presence as an alternative exit, so whichever signal came first won.

Functional impact is bounded: createDevice() logs and proceeds either way, and allowInputLocked() still runs — but every attach eats the timeout(s).

Suggested fix: exit the readiness window on wait.sawStart.get() || wait.sawOpen.get() (START is the kernel-guaranteed readiness signal; OPEN becomes an optional confirmation), demote the sysfs presence check to a logged confirmation or an alternative exit as before, and add virtual-clock tests for both exits through the existing UhidReadinessConfig seams.

Sources: drivers/hid/uhid.c (master): https://raw.githubusercontent.com/torvalds/linux/master/drivers/hid/uhid.c ; ll-driver start-before-connect ordering: hid_hw_start() invokes ll_driver->start prior to hid_connect() in drivers/hid/hid-core.c.

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions