supply: Use new polling infrastructure

This means we do the fast-repoll and normal polling with the same method
(no timeout registrations within the supply code anymore).
This commit is contained in:
Benjamin Berg 2022-05-09 11:43:12 +02:00
parent ce15fa1507
commit 3243ff2a56
3 changed files with 42 additions and 126 deletions

View file

@ -945,14 +945,14 @@ class Tests(dbusmock.DBusTestCase):
self.start_daemon()
self.logind_obj.EmitSignal('', 'PrepareForSleep', 'b', [True])
self.assertEventually(lambda: self.have_text_in_log("Poll paused"), timeout=10)
self.assertEventually(lambda: self.have_text_in_log("Polling will be paused"), timeout=10)
# simulate some battery drain during sleep for which we then
# can check after we 'woke up'
self.testbed.set_attribute(bat0, 'energy_now', '40000000')
self.logind_obj.EmitSignal('', 'PrepareForSleep', 'b', [False])
self.assertEventually(lambda: self.have_text_in_log("Poll resumed"), timeout=10)
self.assertEventually(lambda: self.have_text_in_log("Polling will be resumed"), timeout=10)
devs = self.proxy.EnumerateDevices()
self.assertEqual(len(devs), 1)
@ -1107,44 +1107,6 @@ class Tests(dbusmock.DBusTestCase):
self.stop_daemon()
def test_no_poll_batteries(self):
''' setting NoPollBatteries option should disable polling'''
self.testbed.add_device('power_supply', 'BAT0', None,
['type', 'Battery',
'present', '1',
'status', 'Discharging',
'energy_full', '60000000',
'energy_full_design', '80000000',
'energy_now', '48000000',
'voltage_now', '12000000'], [])
config = tempfile.NamedTemporaryFile(delete=False, mode='w')
config.write("[UPower]\n")
config.write("NoPollBatteries=true\n")
config.close()
self.start_logind()
self.start_daemon(cfgfile=config.name)
devs = self.proxy.EnumerateDevices()
self.assertEqual(len(devs), 1)
self.logind_obj.EmitSignal('', 'PrepareForSleep', 'b', [True])
self.assertEventually(lambda: self.have_text_in_log("Polling will be paused"), timeout=10)
self.logind_obj.EmitSignal('', 'PrepareForSleep', 'b', [False])
self.assertEventually(lambda: self.have_text_in_log("Polling will be resumed"), timeout=10)
self.stop_daemon()
# Now make sure we don't have any actual polling setup for the battery
self.assertFalse(self.have_text_in_log("Setup poll for"))
self.assertFalse(self.have_text_in_log("Poll paused for"))
self.assertFalse(self.have_text_in_log("Poll resumed for"))
os.unlink(config.name)
def test_percentage_low_icon_set(self):
'''Without battery level, PercentageLow is limit for icon change'''

View file

@ -52,15 +52,13 @@ enum {
struct UpDeviceSupplyPrivate
{
guint poll_timer_id;
gboolean has_coldplug_values;
gboolean coldplug_units;
gdouble *energy_old;
GTimeVal *energy_old_timespec;
guint energy_old_first;
gdouble rate_old;
guint unknown_retries;
gint64 last_unknown_retry;
gint64 fast_repoll_until;
gboolean disable_battery_poll; /* from configuration */
gboolean is_power_supply;
gboolean shown_invalid_voltage_warning;
@ -71,13 +69,15 @@ G_DEFINE_TYPE_WITH_PRIVATE (UpDeviceSupply, up_device_supply, UP_TYPE_DEVICE)
static gboolean up_device_supply_refresh (UpDevice *device,
UpRefreshReason reason);
static void up_device_supply_setup_unknown_poll (UpDevice *device,
UpDeviceState state);
static void up_device_supply_update_poll_frequency (UpDevice *device,
UpDeviceState state,
UpRefreshReason reason);
static UpDeviceKind up_device_supply_guess_type (GUdevDevice *native,
const char *native_path);
static gboolean
up_device_supply_refresh_line_power (UpDeviceSupply *supply)
up_device_supply_refresh_line_power (UpDeviceSupply *supply,
UpRefreshReason reason)
{
UpDevice *device = UP_DEVICE (supply);
GUdevDevice *native;
@ -542,7 +542,7 @@ sysfs_get_capacity_level (GUdevDevice *native,
static gboolean
up_device_supply_refresh_battery (UpDeviceSupply *supply,
UpDeviceState *out_state)
UpRefreshReason reason)
{
gchar *technology_native = NULL;
gdouble voltage_design;
@ -585,7 +585,6 @@ up_device_supply_refresh_battery (UpDeviceSupply *supply,
g_object_set (device, "is-present", is_present, NULL);
if (!is_present) {
up_device_supply_reset_values (supply);
g_object_get (device, "state", out_state, NULL);
goto out;
}
@ -856,8 +855,6 @@ up_device_supply_refresh_battery (UpDeviceSupply *supply,
supply->priv->energy_old_first = 0;
}
*out_state = state;
g_object_set (device,
"energy", energy,
"energy-full", energy_full,
@ -873,7 +870,7 @@ up_device_supply_refresh_battery (UpDeviceSupply *supply,
NULL);
/* Setup unknown poll again if needed */
up_device_supply_setup_unknown_poll (device, state);
up_device_supply_update_poll_frequency (device, state, reason);
out:
g_free (technology_native);
@ -936,7 +933,7 @@ up_device_supply_get_sibling_with_subsystem (GUdevDevice *device,
static gboolean
up_device_supply_refresh_device (UpDeviceSupply *supply,
UpDeviceState *out_state)
UpRefreshReason reason)
{
UpDeviceState state;
UpDevice *device = UP_DEVICE (supply);
@ -1005,7 +1002,6 @@ up_device_supply_refresh_device (UpDeviceSupply *supply,
/* Probably talking to the device over Bluetooth */
state = UP_DEVICE_STATE_UNKNOWN;
g_object_set (device, "state", state, NULL);
*out_state = state;
return FALSE;
}
@ -1016,37 +1012,15 @@ up_device_supply_refresh_device (UpDeviceSupply *supply,
if (percentage == 100.0)
state = UP_DEVICE_STATE_FULLY_CHARGED;
/* reset unknown counter */
if (state != UP_DEVICE_STATE_UNKNOWN) {
g_debug ("resetting unknown timeout after %i retries", supply->priv->unknown_retries);
supply->priv->unknown_retries = 0;
}
g_object_set (device,
"percentage", percentage,
"battery-level", level,
"state", state,
NULL);
*out_state = state;
return TRUE;
}
static gboolean
up_device_supply_poll_unknown_battery (UpDevice *device)
{
UpDeviceSupply *supply = UP_DEVICE_SUPPLY (device);
g_debug ("Unknown state on supply %s; forcing update after %i seconds",
up_device_get_object_path (device), UP_DAEMON_UNKNOWN_TIMEOUT);
supply->priv->poll_timer_id = 0;
up_device_supply_refresh (device, UP_REFRESH_POLL);
return FALSE;
}
static UpDeviceKind
up_device_supply_guess_type (GUdevDevice *native,
const char *native_path)
@ -1167,10 +1141,10 @@ up_device_supply_coldplug (UpDevice *device)
if (type != UP_DEVICE_KIND_LINE_POWER &&
type != UP_DEVICE_KIND_BATTERY)
up_daemon_start_poll (G_OBJECT (device));
g_object_set (device, "poll-timeout", UP_DAEMON_SHORT_TIMEOUT, NULL);
else if (type == UP_DEVICE_KIND_BATTERY &&
(!supply->priv->disable_battery_poll || !supply->priv->is_power_supply))
up_daemon_start_poll (G_OBJECT (device));
g_object_set (device, "poll-timeout", UP_DAEMON_SHORT_TIMEOUT, NULL);
/* coldplug values */
up_device_supply_refresh (device, UP_REFRESH_INIT);
@ -1178,46 +1152,42 @@ up_device_supply_coldplug (UpDevice *device)
return TRUE;
}
/**
* up_device_supply_setup_unknown_poll:
**/
static void
up_device_supply_setup_unknown_poll (UpDevice *device,
UpDeviceState state)
up_device_supply_update_poll_frequency (UpDevice *device,
UpDeviceState state,
UpRefreshReason reason)
{
UpDeviceSupply *supply = UP_DEVICE_SUPPLY (device);
if (supply->priv->disable_battery_poll)
return;
/* if it's unknown, poll faster than we would normally */
if (supply->priv->unknown_retries < UP_DAEMON_UNKNOWN_RETRIES &&
/* We start fast-polling if the reason to update was not a normal POLL
* and the state is either unknown or we are in quirk mode and expect
* the battery to return unstable values for a while.
*
* We stop again when:
* 1. The state is known and we are NOT in quirk mode
* 2. The timeout elapsed
*/
if (reason != UP_REFRESH_POLL &&
(state == UP_DEVICE_STATE_UNKNOWN || up_backend_needs_poll_after_uevent ())) {
gint64 now;
supply->priv->poll_timer_id =
g_timeout_add_seconds (UP_DAEMON_UNKNOWN_TIMEOUT,
(GSourceFunc) up_device_supply_poll_unknown_battery, supply);
g_source_set_name_by_id (supply->priv->poll_timer_id, "[upower] up_device_supply_poll_unknown_battery (linux)");
g_debug ("unknown_poll: setting up fast re-poll");
g_object_set (device, "poll-timeout", UP_DAEMON_UNKNOWN_TIMEOUT, NULL);
supply->priv->fast_repoll_until = g_get_monotonic_time () + UP_DAEMON_UNKNOWN_POLL_TIME * G_USEC_PER_SEC;
/* increase count, we don't want to poll at 0.5Hz forever */
now = g_get_monotonic_time ();
if (now - supply->priv->last_unknown_retry > G_USEC_PER_SEC)
supply->priv->unknown_retries++;
supply->priv->last_unknown_retry = now;
} else {
/* reset unknown counter */
supply->priv->unknown_retries = 0;
}
}
} else if (supply->priv->fast_repoll_until == 0) {
/* Not fast-repolling, no need to check whether to stop */
static void
up_device_supply_disable_unknown_poll (UpDevice *device)
{
UpDeviceSupply *supply = UP_DEVICE_SUPPLY (device);
} else if (state != UP_DEVICE_STATE_UNKNOWN && !up_backend_needs_poll_after_uevent ()) {
g_debug ("unknown_poll: stopping fast repoll (not needed anymore)");
supply->priv->fast_repoll_until = 0;
g_object_set (device, "poll-timeout", UP_DAEMON_SHORT_TIMEOUT, NULL);
if (supply->priv->poll_timer_id > 0) {
g_source_remove (supply->priv->poll_timer_id);
supply->priv->poll_timer_id = 0;
} else if (supply->priv->fast_repoll_until < g_get_monotonic_time ()) {
g_debug ("unknown_poll: stopping fast repoll (giving up)");
supply->priv->fast_repoll_until = 0;
g_object_set (device, "poll-timeout", UP_DAEMON_SHORT_TIMEOUT, NULL);
}
}
@ -1227,17 +1197,15 @@ up_device_supply_refresh (UpDevice *device, UpRefreshReason reason)
gboolean updated;
UpDeviceSupply *supply = UP_DEVICE_SUPPLY (device);
UpDeviceKind type;
UpDeviceState state;
g_object_get (device, "type", &type, NULL);
if (type == UP_DEVICE_KIND_LINE_POWER) {
updated = up_device_supply_refresh_line_power (supply);
updated = up_device_supply_refresh_line_power (supply, reason);
} else if (type == UP_DEVICE_KIND_BATTERY &&
supply->priv->is_power_supply) {
up_device_supply_disable_unknown_poll (device);
updated = up_device_supply_refresh_battery (supply, &state);
updated = up_device_supply_refresh_battery (supply, reason);
} else {
updated = up_device_supply_refresh_device (supply, &state);
updated = up_device_supply_refresh_device (supply, reason);
}
/* reset time if we got new data */
@ -1291,19 +1259,6 @@ up_device_supply_finalize (GObject *object)
G_OBJECT_CLASS (up_device_supply_parent_class)->finalize (object);
}
static void
up_device_supply_dispose (GObject *object)
{
UpDeviceSupply *supply = UP_DEVICE_SUPPLY (object);
up_daemon_stop_poll (object);
if (supply->priv->poll_timer_id > 0)
g_source_remove (supply->priv->poll_timer_id);
G_OBJECT_CLASS (up_device_supply_parent_class)->dispose (object);
}
static void
up_device_supply_set_property (GObject *object,
guint property_id,
@ -1348,7 +1303,6 @@ up_device_supply_class_init (UpDeviceSupplyClass *klass)
UpDeviceClass *device_class = UP_DEVICE_CLASS (klass);
object_class->finalize = up_device_supply_finalize;
object_class->dispose = up_device_supply_dispose;
object_class->set_property = up_device_supply_set_property;
object_class->get_property = up_device_supply_get_property;
device_class->get_on_battery = up_device_supply_get_on_battery;

View file

@ -27,7 +27,7 @@
G_BEGIN_DECLS
#define UP_DAEMON_UNKNOWN_TIMEOUT 1 /* second */
#define UP_DAEMON_UNKNOWN_RETRIES 5
#define UP_DAEMON_UNKNOWN_POLL_TIME 5 /* second */
#define UP_DAEMON_SHORT_TIMEOUT 30 /* seconds */
#define UP_DAEMON_LONG_TIMEOUT 120 /* seconds */