From 2261f9327d57f7216c412985cb80a600ad7f9162 Mon Sep 17 00:00:00 2001 From: Simo Piiroinen Date: Thu, 11 Jun 2020 15:09:32 +0300 Subject: [PATCH] [battery-udev] Refresh all udev properties on heartbeat. Fixes JB#48324 There might not be udev notification about every battery capacity percent value change. While this is usually harmless when battery is sufficiently full, it can cause issues like missed battery low notifications and/or delay battery empty shutdown so much that battery gets too depleted for regular bootup. Poll power supply device properties in process watchdog heartbeat pace i.e. about every 36 seconds of uptime not spent in suspend. Periodic udev polling is enabled by default, but can be disabled via mce configuration. Signed-off-by: Simo Piiroinen --- inifiles/battery-udev-settings.ini | 19 ++++++++ modules/battery-udev.c | 76 ++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/inifiles/battery-udev-settings.ini b/inifiles/battery-udev-settings.ini index 3f426d89..f9adb80b 100644 --- a/inifiles/battery-udev-settings.ini +++ b/inifiles/battery-udev-settings.ini @@ -26,3 +26,22 @@ # Default is: # # RefreshOnNotify = false + +# Many/most of devices do not send udev notifications +# on every battery capacity percent change. Most of the +# times this is harmless. However it can also cause +# battery empty shutdown to be delayed so much that +# battery is too depleted for regular bootup. +# +# To avoid this udev battery plugin polls all power +# supply devices in process watchdog heartbeat pace +# i.e. about every 36 seconds of uptime not spent in +# suspend. +# +# To disable this periodic polling: +# +# RefreshOnHeartbeat = false +# +# Default is: +# +# RefreshOnHeartbeat = true diff --git a/modules/battery-udev.c b/modules/battery-udev.c index dafb585b..0c2d2803 100644 --- a/modules/battery-udev.c +++ b/modules/battery-udev.c @@ -82,6 +82,10 @@ #define MCE_CONF_BATTERY_UDEV_REFRESH_ON_NOTIFY "RefreshOnNotify" #define DEFAULT_BATTERY_UDEV_REFRESH_ON_NOTIFY false +/** Setting for forced refresh on system heartbeat */ +#define MCE_CONF_BATTERY_UDEV_REFRESH_ON_HEARTBEAT "RefreshOnHeartbeat" +#define DEFAULT_BATTERY_UDEV_REFRESH_ON_HEARTBEAT true + /** Delay between udev notifications and battery state evaluation * * The purpose is to increase chances of getting battery and @@ -311,6 +315,14 @@ static gboolean udevtracker_refresh_cb (gpointer aptr); static void udevtracker_schedule_refresh(void); static void udevtracker_cancel_refresh (void); +/* ------------------------------------------------------------------------- * + * DATAPIPE_HANDLERS + * ------------------------------------------------------------------------- */ + +static void mcebat_datapipe_heartbeat_event_cb(gconstpointer data); +static void mcebat_datapipe_init (void); +static void mcebat_datapipe_quit (void); + /* ------------------------------------------------------------------------- * * G_MODULE * ------------------------------------------------------------------------- */ @@ -418,6 +430,9 @@ static const char * const udevproperty_used_keys[] = { /** Cached MCE_CONF_BATTERY_UDEV_REFRESH_ON_NOTIFY value */ static bool mcebat_refresh_on_notify = DEFAULT_BATTERY_UDEV_REFRESH_ON_NOTIFY; +/** Cached MCE_CONF_BATTERY_UDEV_REFRESH_ON_HEARTBEAT value */ +static bool mcebat_refresh_on_heartbeat = DEFAULT_BATTERY_UDEV_REFRESH_ON_HEARTBEAT; + /* ========================================================================= * * CLIENT * ========================================================================= */ @@ -2138,6 +2153,60 @@ static void udevtracker_cancel_refresh(void) } } +/* ========================================================================= * + * DATAPIPE_HANDLERS + * ========================================================================= */ + +/** Change notifications for heartbeat_event_pipe + * + * @param data (unused dummy parameter) + */ +static void mcebat_datapipe_heartbeat_event_cb(gconstpointer data) +{ + (void)data; + + mce_log(LL_DEBUG, "ENTER - refresh on heartbeat"); + + if( mcebat_refresh_on_heartbeat && udevtracker_object ) + udevtracker_refresh_all(udevtracker_object); + + mce_log(LL_DEBUG, "LEAVE - refresh on heartbeat"); +} + +/** Array of datapipe handlers */ +static datapipe_handler_t mcebat_datapipe_handlers[] = +{ + // output triggers + { + .datapipe = &heartbeat_event_pipe, + .output_cb = mcebat_datapipe_heartbeat_event_cb, + }, + // sentinel + { + .datapipe = 0, + } +}; + +static datapipe_bindings_t mcebat_datapipe_bindings = +{ + .module = "battery_udev", + .handlers = mcebat_datapipe_handlers, +}; + +/** Append triggers/filters to datapipes + */ +static void mcebat_datapipe_init(void) +{ + mce_datapipe_init_bindings(&mcebat_datapipe_bindings); +} + +/** Remove triggers/filters from datapipes + */ +static void mcebat_datapipe_quit(void) +{ + mce_datapipe_quit_bindings(&mcebat_datapipe_bindings); +} + /* ========================================================================= * * G_MODULE * ========================================================================= */ @@ -2166,6 +2235,11 @@ mcebat_init_settings(void) mce_conf_get_bool(MCE_CONF_BATTERY_UDEV_SETTINGS_GROUP, MCE_CONF_BATTERY_UDEV_REFRESH_ON_NOTIFY, DEFAULT_BATTERY_UDEV_REFRESH_ON_NOTIFY); + + mcebat_refresh_on_heartbeat = + mce_conf_get_bool(MCE_CONF_BATTERY_UDEV_SETTINGS_GROUP, + MCE_CONF_BATTERY_UDEV_REFRESH_ON_HEARTBEAT, + DEFAULT_BATTERY_UDEV_REFRESH_ON_HEARTBEAT); } /** Init function for the battery and charger module @@ -2184,6 +2258,7 @@ G_MODULE_EXPORT const gchar *g_module_check_init(GModule *module) udevproperty_init_types(); mcebat_dbus_init(); + mcebat_datapipe_init(); /* Initial udev probing can take a long time. * Do it from idle callback in order not to delay @@ -2206,6 +2281,7 @@ G_MODULE_EXPORT void g_module_unload(GModule *module) if( mcebat_init_tracker_id ) g_source_remove(mcebat_init_tracker_id), mcebat_init_tracker_id = 0; + mcebat_datapipe_quit(); mcebat_dbus_quit(); udevtracker_delete(udevtracker_object), udevtracker_object = 0;