[Test feedback] Laptop power states when on or off battery
Tofloor
poster avatar
w***f@pozinski.ru
deepin
8 hours ago
Author

upower says you are on mains while you are running on battery

Summary

On Deepin 25, unplugging the charger left upower reporting
on-battery: no indefinitely. The kernel knew the truth, the desktop did not.

This is not a cosmetic reporting bug. dde-daemon drives power policy from
that flag, so nothing battery-related ever engaged: no screen dimming, no
battery power profile, no low-battery warning. The machine ran on cells with
desktop-on-mains settings, which is worse for runtime than any tuning you can
do afterwards.

Symptom

With the cable out:

$ cat /sys/class/power_supply/AC/online          -> 0
$ cat /sys/class/power_supply/BAT0/status        -> Discharging
$ cat /sys/class/power_supply/BAT0/capacity      -> 76

$ upower -d | grep on-battery
  on-battery:      no        <- wrong

Everything downstream believes upower: the battery applet shows no
discharge, brightness does not drop, the power profile stays balance,
and upower's own "time to empty" is never computed.

Diagnosis

The AC adapter on this machine is a platform device, not a USB or ACPI AC
device that emits change events:

$ udevadm info -q property -p /sys/class/power_supply/AC
DEVPATH=/devices/LNXSYSTM:00/.../AC
POWER_SUPPLY_ONLINE=0

upower reads the line-power state when its device is added (coldplug at
boot) and relies on udev change events afterwards. Because this adapter
never emits one, a state change goes unnoticed and the cached value survives
until something pokes it.

The giveaway: upower can be corrected instantly by hand.

$ sudo udevadm trigger --action=change --subsystem-match=power_supply
$ upower -d | grep on-battery
  on-battery:      yes

That proves the plumbing works and only the notification is missing.

Permanent fix

Poll the AC line and fire the udev change yourself when it flips. Three
seconds of latency, negligible cost, no kernel modules, nothing to break.

/usr/local/bin/power-supply-watch.sh:

#!/bin/bash
# Keep upower's AC state in sync with sysfs.
# Fires once at startup, then again on every plug/unplug.

AC=/sys/class/power_supply/AC/online

trigger() { udevadm trigger --action=change --subsystem-match=power_supply; }

trigger                      # startup
sleep 1
last=$(cat "$AC" 2>/dev/null || echo "")

while true; do
    cur=$(cat "$AC" 2>/dev/null || echo "")
    if [ -n "$cur" ] && [ "$cur" != "$last" ]; then
        trigger
        last="$cur"
    fi
    sleep 3
done

/etc/systemd/system/power-supply-watch.service:

[Unit]
Description=Keep upower's AC state in sync with sysfs
After=upower.service

[Service]
ExecStart=/usr/local/bin/power-supply-watch.sh
Restart=always
RestartSec=5
Nice=10

[Install]
WantedBy=multi-user.target

Install:

sudo install -Dm755 power-supply-watch.sh /usr/local/bin/power-supply-watch.sh
sudo install -Dm644 power-supply-watch.service /etc/systemd/system/power-supply-watch.service
sudo systemctl daemon-reload
sudo systemctl enable --now power-supply-watch.service

Verification

Unplug, wait a few seconds, then:

upower -d | grep on-battery        # expect: yes

Plug back in:

upower -d | grep on-battery        # expect: no

Measured, not assumed

Verified on the affected machine (Deepin 25, i3-2330M, WD2500BEKX) with a
one-second poll watching both values:

01:42  ac=1  on-battery=no     (cable in)
       ac=0  on-battery=yes    (pulled)   <- within ~3 s
       ac=1  on-battery=no     (replaced) <- within ~3 s

Both transitions landed inside the three-second window, in both directions,
with no manual udevadm call. upower's "time to empty" then reported
about 3 h at 100%, which matches the 47.52 Wh pack at the ~17 W measured
resting draw - two independent methods agreeing.

Then confirm the policy followed, not just the flag - the screen should
dim on battery and return to full brightness when the cable goes back in.

Notes and caveats

  • No udev rule can fix this. A rule needs an event to fire on, and the
    absence of that event is the bug. Polling is the honest workaround.
  • Three seconds is a compromise between responsiveness and pointless
    wakeups. One second is fine too; ten is noticeable when you plug in.
  • The startup trigger matters. Without it the service only corrects
    itself on the next plug event, which can be hours away. A separate
    boot-time unit is then unnecessary.
  • If your hardware does emit AC change events, none of this is needed -
    check udevadm monitor --subsystem-match=power_supply while unplugging.

Why it is worth writing up

The visible symptom looks like a broken battery gauge, and the tempting
response is to distrust the battery. The actual fault is one stale boolean,
and it silently disables every power policy the desktop has.

Reply Favorite View the author
All Replies

No replies yet