Skip to content

The overnight resume hang is a touch on a wake-gesture-armed suspended screen, not a suspend regression

scope: device:google-taimen · severity: finding · confidence: proven · subsystem: power

The question — a phone left overnight, cabled and at 99 %, idle-suspended at 03:01:20 and never wrote another line. The owner pressed power eight hours later and it came up with androidboot.bootreason=watchdog. What hung, and was suspend/resume regressing?

The answer — nothing about the duration mattered, and suspend was not regressing. The phone had the ftm4 wake gesture armed, and a touch on an armed, suspended screen hangs the resume. Picking the phone up to press the power key is a touch.

ftm4_suspend() arms the gesture and deliberately leaves the interrupt live so the controller can raise it on a double tap. A tap therefore runs ftm4_irq() while the system is still suspended, and i2c is unreachable there – runtime PM is disabled for the duration of a system sleep – so ftm4_read_event() fails instead of draining the event FIFO. The line is level triggered and the part holds it asserted until that FIFO is empty, so IRQF_ONESHOT unmasks and the handler is called straight back. The spin never lets the resume finish and the 30 s watchdog ends it.

The measurements —

condition result
armed + a tap 4 resets out of 4, bootreason=watchdog, 12-68 s after the tap
armed, untouched, RTC wake resumed, 301 s
not armed, 300 s RTC resumed
not armed, 900 s RTC resumed, exactly 900 s
not armed, power-key wake resumed, wakeirq=38 pm8941_pwrkey
pm_test freezer / devices / platform all clean, slowest callback ftm4_resume 86 ms

What this rules out —

  • “Suspend/resume is broken on 7.2.” Seven cycles resumed cleanly the same day.
  • “The hang is duration dependent.” 900 s unarmed resumed; 12 s after a tap did not. Duration is not the variable, the tap is.
  • “Arming the wake gesture is enough to hang it.” An armed cycle woken by its RTC alarm resumed normally. The gesture must actually fire.
  • “Double-tap is not the cause, because kernel #71 carried it and resumed 2/2.” #71 resumed because nobody touched the glass during those two cycles.
  • It also rules out the instruments people reach for first: see no-log-channel-survives-s2idle-on-this-device.

The fix — do not read the controller from the handler while a gesture is armed: mask the line, leave the event in the FIFO, and let ftm4_resume() drain it once i2c is back. That is also the only place the event can be decoded, so KEY_WAKEUP is reported for FTM4_EV_GESTURE carrying FTM4_GESTURE_DOUBLE_TAP and for nothing else. Kernel commit “Input: ftm4 - do not read the controller from the wake gesture’s interrupt”, aport patch 0254. After it a double tap wakes the phone: 3 cycles out of 3, wakeirq=141 (msmgpio 125 Level ftm4), and the resume logs double tap: 22 01 31 65 48 46 00 00. Ordinary touch still works afterwards – the interrupt counter went 1 to 1897 across twenty seconds of touching, which is the check that the disable_irq() depth stayed balanced.

How it was established — tools/ph-suspend-cycle.sh with a prep hook setting 0-0049/power/wakeup=enabled, an RTC alarm as the backstop, and an operator tapping at an announced wall-clock time. The oracle is binary and needs no log: either the boot_id changed or it did not. What would overturn it is a reset in an armed, genuinely untouched cycle – so record whether anything touched the glass, because that is the whole variable.