Merge branch 'wip/percentage-greater-100' into 'master'

up-daemon: Fix DisplayDevice percentage calculation for invalid battery data

Closes #336

See merge request upower/upower!302
This commit is contained in:
Kate Hsuan 2026-05-05 11:28:25 +08:00
commit 99eb00d645

View file

@ -169,6 +169,8 @@ up_daemon_update_display_battery (UpDaemon *daemon)
gdouble percentage = 0.0;
gdouble energy = 0.0;
gdouble energy_full = 0.0;
gdouble energy_full_design = 0.0;
gdouble effective_energy_full = 0.0;
gdouble energy_rate = 0.0;
gint64 time_to_empty = 0;
gint64 time_to_full = 0;
@ -183,6 +185,7 @@ up_daemon_update_display_battery (UpDaemon *daemon)
"percentage", &percentage,
"energy", &energy,
"energy-full", &energy_full,
"energy-full-design", &energy_full_design,
"energy-rate", &energy_rate,
"time-to-empty", &time_to_empty,
"time-to-full", &time_to_full,
@ -253,11 +256,39 @@ up_daemon_update_display_battery (UpDaemon *daemon)
/* If at least one battery has charge thresholds enabled, propagate that. */
charge_threshold_enabled_total = charge_threshold_enabled_total || charge_threshold_enabled;
/* sum up composite */
/* Validate battery capacity data before aggregation.
* Some firmware/ACPI implementations report energy_full=0 due to bugs,
* which breaks the weighted percentage calculation. We fall back to
* energy_full_design if available, or skip the battery from capacity-based
* calculation (will use percentage averaging instead).
*/
if (energy_full >= 0.01) {
/* Primary: Use reported full capacity */
effective_energy_full = energy_full;
} else if (energy_full_design >= 0.01) {
/* Fallback: Use design capacity */
effective_energy_full = energy_full_design;
g_debug ("Battery reports invalid energy_full (%.4f Wh), "
"using energy_full_design=%.2f Wh as fallback",
energy_full, energy_full_design);
} else {
/* No valid capacity data - skip from energy-based calculation.
* The percentage averaging fallback will be used instead.
*/
g_warning ("Battery reports energy=%.2f Wh but both energy_full and "
"energy_full_design are invalid; excluding from composite "
"capacity calculation", energy);
percentage_total += percentage;
num_batteries++;
continue;
}
/* Sum up composite using validated capacity data */
kind_total = UP_DEVICE_KIND_BATTERY;
is_present_total = TRUE;
energy_total += energy;
energy_full_total += energy_full;
energy_full_total += effective_energy_full;
energy_rate_total += energy_rate;
time_to_empty_total += time_to_empty;
time_to_full_total += time_to_full;
@ -273,8 +304,9 @@ up_daemon_update_display_battery (UpDaemon *daemon)
g_debug ("Calculating percentage and time to full/to empty for %i batteries", num_batteries);
/* use percentage weighted for each battery capacity
* fall back to averaging the batteries.
* ASSUMPTION: If one battery has energy data, then all batteries do
* Fall back to averaging the batteries if capacity data is unavailable.
* NOTE: We now validate capacity data per-battery, as some firmware/ACPI
* implementations incorrectly report energy_full=0.
*/
if (energy_full_total > 0.0)
percentage_total = 100.0 * energy_total / energy_full_total;