Be more nuanced when considering if the system is on AC power

This should be no beahviour change, but it allows the powerd and upower plugins
to provide more information in the future.

Fixes https://github.com/fwupd/fwupd/issues/3386
This commit is contained in:
Richard Hughes 2023-02-20 16:59:29 +00:00
parent 322cd2e03b
commit b24d14ebde
8 changed files with 148 additions and 89 deletions

View File

@ -219,34 +219,58 @@ fu_common_align_up(gsize value, guint8 alignment)
}
/**
* fu_battery_state_to_string:
* @battery_state: a battery state, e.g. %FU_BATTERY_STATE_FULLY_CHARGED
* fu_power_state_to_string:
* @power_state: a power state, e.g. %FU_POWER_STATE_AC_FULLY_CHARGED
*
* Converts an enumerated type to a string.
*
* Returns: a string, or %NULL for invalid
*
* Since: 1.6.0
* Since: 1.8.11
**/
const gchar *
fu_battery_state_to_string(FuBatteryState battery_state)
fu_power_state_to_string(FuPowerState power_state)
{
if (battery_state == FU_BATTERY_STATE_UNKNOWN)
if (power_state == FU_POWER_STATE_UNKNOWN)
return "unknown";
if (battery_state == FU_BATTERY_STATE_CHARGING)
return "charging";
if (battery_state == FU_BATTERY_STATE_DISCHARGING)
return "discharging";
if (battery_state == FU_BATTERY_STATE_EMPTY)
return "empty";
if (battery_state == FU_BATTERY_STATE_FULLY_CHARGED)
return "fully-charged";
if (power_state == FU_POWER_STATE_BATTERY)
return "battery";
if (power_state == FU_POWER_STATE_BATTERY_DISCHARGING)
return "battery-discharging";
if (power_state == FU_POWER_STATE_BATTERY_EMPTY)
return "battery-empty";
if (power_state == FU_POWER_STATE_AC)
return "ac";
if (power_state == FU_POWER_STATE_AC_CHARGING)
return "ac-charging";
if (power_state == FU_POWER_STATE_AC_FULLY_CHARGED)
return "ac-fully-charged";
return NULL;
}
/**
* fu_power_state_is_ac:
* @power_state: a power state, e.g. %FU_POWER_STATE_AC_FULLY_CHARGED
*
* Determines if the power state can be considered "on AC power".
*
* Returns: %TRUE for success
*
* Since: 1.8.11
**/
gboolean
fu_power_state_is_ac(FuPowerState power_state)
{
if (power_state == FU_POWER_STATE_UNKNOWN || power_state == FU_POWER_STATE_AC ||
power_state == FU_POWER_STATE_AC_CHARGING ||
power_state == FU_POWER_STATE_AC_FULLY_CHARGED)
return TRUE;
return FALSE;
}
/**
* fu_lid_state_to_string:
* @lid_state: a battery state, e.g. %FU_LID_STATE_CLOSED
* @lid_state: a lid state, e.g. %FU_LID_STATE_CLOSED
*
* Converts an enumerated type to a string.
*

View File

@ -32,24 +32,34 @@ typedef enum {
} FuCpuVendor;
/**
* FuBatteryState:
* @FU_BATTERY_STATE_UNKNOWN: Unknown
* @FU_BATTERY_STATE_CHARGING: Charging
* @FU_BATTERY_STATE_DISCHARGING: Discharging
* @FU_BATTERY_STATE_EMPTY: Empty
* @FU_BATTERY_STATE_FULLY_CHARGED: Fully charged
* FuPowerState:
* @FU_POWER_STATE_UNKNOWN: Unknown
* @FU_POWER_STATE_AC: On AC power
* @FU_POWER_STATE_AC_CHARGING: Charging on AC
* @FU_POWER_STATE_AC_FULLY_CHARGED: Fully charged on AC
* @FU_POWER_STATE_BATTERY: On system battery
* @FU_POWER_STATE_BATTERY_DISCHARGING: System battery discharging
* @FU_POWER_STATE_BATTERY_EMPTY: System battery empty
*
* The device battery state.
* The system power state.
*
* This does not have to be exactly what the battery is doing, but is supposed to represent the
* 40,000ft view of the system power state.
*
* For example, it is perfectly correct to set %FU_POWER_STATE_AC if the system is connected to
* AC power, but the battery cells are discharging for health or for other performance reasons.
**/
typedef enum {
FU_BATTERY_STATE_UNKNOWN,
FU_BATTERY_STATE_CHARGING,
FU_BATTERY_STATE_DISCHARGING,
FU_BATTERY_STATE_EMPTY,
FU_BATTERY_STATE_FULLY_CHARGED,
FU_POWER_STATE_UNKNOWN,
FU_POWER_STATE_AC,
FU_POWER_STATE_AC_CHARGING,
FU_POWER_STATE_AC_FULLY_CHARGED,
FU_POWER_STATE_BATTERY,
FU_POWER_STATE_BATTERY_DISCHARGING,
FU_POWER_STATE_BATTERY_EMPTY,
/*< private >*/
FU_BATTERY_STATE_LAST
} FuBatteryState;
FU_POWER_STATE_LAST
} FuPowerState;
/**
* FuLidState:
@ -82,7 +92,9 @@ fu_common_check_full_disk_encryption(GError **error);
gsize
fu_common_align_up(gsize value, guint8 alignment);
const gchar *
fu_battery_state_to_string(FuBatteryState battery_state);
fu_power_state_to_string(FuPowerState power_state);
gboolean
fu_power_state_is_ac(FuPowerState power_state);
const gchar *
fu_lid_state_to_string(FuLidState lid_state);

View File

@ -35,7 +35,7 @@ typedef struct {
GPtrArray *esp_volumes;
GHashTable *firmware_gtypes;
GHashTable *hwid_flags; /* str: */
FuBatteryState battery_state;
FuPowerState power_state;
FuLidState lid_state;
guint battery_level;
guint battery_threshold;
@ -48,7 +48,7 @@ enum { SIGNAL_SECURITY_CHANGED, SIGNAL_LAST };
enum {
PROP_0,
PROP_BATTERY_STATE,
PROP_POWER_STATE,
PROP_LID_STATE,
PROP_BATTERY_LEVEL,
PROP_BATTERY_THRESHOLD,
@ -907,42 +907,42 @@ fu_context_load_quirks(FuContext *self, FuQuirksLoadFlags flags, GError **error)
}
/**
* fu_context_get_battery_state:
* fu_context_get_power_state:
* @self: a #FuContext
*
* Gets if the system is on battery power, e.g. UPS or laptop battery.
*
* Returns: a battery state, e.g. %FU_BATTERY_STATE_DISCHARGING
* Returns: a power state, e.g. %FU_POWER_STATE_BATTERY_DISCHARGING
*
* Since: 1.6.0
* Since: 1.8.11
**/
FuBatteryState
fu_context_get_battery_state(FuContext *self)
FuPowerState
fu_context_get_power_state(FuContext *self)
{
FuContextPrivate *priv = GET_PRIVATE(self);
g_return_val_if_fail(FU_IS_CONTEXT(self), FALSE);
return priv->battery_state;
return priv->power_state;
}
/**
* fu_context_set_battery_state:
* fu_context_set_power_state:
* @self: a #FuContext
* @battery_state: a battery state, e.g. %FU_BATTERY_STATE_DISCHARGING
* @power_state: a power state, e.g. %FU_POWER_STATE_BATTERY_DISCHARGING
*
* Sets if the system is on battery power, e.g. UPS or laptop battery.
*
* Since: 1.6.0
* Since: 1.8.11
**/
void
fu_context_set_battery_state(FuContext *self, FuBatteryState battery_state)
fu_context_set_power_state(FuContext *self, FuPowerState power_state)
{
FuContextPrivate *priv = GET_PRIVATE(self);
g_return_if_fail(FU_IS_CONTEXT(self));
if (priv->battery_state == battery_state)
if (priv->power_state == power_state)
return;
priv->battery_state = battery_state;
g_debug("battery state now %s", fu_battery_state_to_string(battery_state));
g_object_notify(G_OBJECT(self), "battery-state");
priv->power_state = power_state;
g_debug("power state now %s", fu_power_state_to_string(power_state));
g_object_notify(G_OBJECT(self), "power-state");
}
/**
@ -951,7 +951,7 @@ fu_context_set_battery_state(FuContext *self, FuBatteryState battery_state)
*
* Gets the laptop lid state, if applicable.
*
* Returns: a battery state, e.g. %FU_LID_STATE_CLOSED
* Returns: a lid state, e.g. %FU_LID_STATE_CLOSED
*
* Since: 1.7.4
**/
@ -966,7 +966,7 @@ fu_context_get_lid_state(FuContext *self)
/**
* fu_context_set_lid_state:
* @self: a #FuContext
* @lid_state: a battery state, e.g. %FU_LID_STATE_CLOSED
* @lid_state: a lid state, e.g. %FU_LID_STATE_CLOSED
*
* Sets the laptop lid state, if applicable.
*
@ -1237,8 +1237,8 @@ fu_context_get_property(GObject *object, guint prop_id, GValue *value, GParamSpe
FuContext *self = FU_CONTEXT(object);
FuContextPrivate *priv = GET_PRIVATE(self);
switch (prop_id) {
case PROP_BATTERY_STATE:
g_value_set_uint(value, priv->battery_state);
case PROP_POWER_STATE:
g_value_set_uint(value, priv->power_state);
break;
case PROP_LID_STATE:
g_value_set_uint(value, priv->lid_state);
@ -1264,8 +1264,8 @@ fu_context_set_property(GObject *object, guint prop_id, const GValue *value, GPa
FuContext *self = FU_CONTEXT(object);
FuContextPrivate *priv = GET_PRIVATE(self);
switch (prop_id) {
case PROP_BATTERY_STATE:
fu_context_set_battery_state(self, g_value_get_uint(value));
case PROP_POWER_STATE:
fu_context_set_power_state(self, g_value_get_uint(value));
break;
case PROP_LID_STATE:
fu_context_set_lid_state(self, g_value_get_uint(value));
@ -1319,20 +1319,20 @@ fu_context_class_init(FuContextClass *klass)
object_class->set_property = fu_context_set_property;
/**
* FuContext:battery-state:
* FuContext:power-state:
*
* The system battery state.
* The system power state.
*
* Since: 1.6.0
* Since: 1.8.11
*/
pspec = g_param_spec_uint("battery-state",
pspec = g_param_spec_uint("power-state",
NULL,
NULL,
FU_BATTERY_STATE_UNKNOWN,
FU_BATTERY_STATE_LAST,
FU_BATTERY_STATE_UNKNOWN,
FU_POWER_STATE_UNKNOWN,
FU_POWER_STATE_LAST,
FU_POWER_STATE_UNKNOWN,
G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
g_object_class_install_property(object_class, PROP_BATTERY_STATE, pspec);
g_object_class_install_property(object_class, PROP_POWER_STATE, pspec);
/**
* FuContext:lid-state:

View File

@ -111,10 +111,10 @@ fu_context_add_quirk_key(FuContext *self, const gchar *key);
void
fu_context_security_changed(FuContext *self);
FuBatteryState
fu_context_get_battery_state(FuContext *self);
FuPowerState
fu_context_get_power_state(FuContext *self);
void
fu_context_set_battery_state(FuContext *self, FuBatteryState battery_state);
fu_context_set_power_state(FuContext *self, FuPowerState power_state);
FuLidState
fu_context_get_lid_state(FuContext *self);
void

View File

@ -573,7 +573,6 @@ LIBFWUPDPLUGIN_1.5.8 {
LIBFWUPDPLUGIN_1.6.0 {
global:
fu_battery_state_to_string;
fu_byte_array_align_up;
fu_bytes_get_data_safe;
fu_cabinet_add_file;
@ -587,7 +586,6 @@ LIBFWUPDPLUGIN_1.6.0 {
fu_context_add_runtime_version;
fu_context_add_udev_subsystem;
fu_context_get_battery_level;
fu_context_get_battery_state;
fu_context_get_battery_threshold;
fu_context_get_firmware_gtype_by_id;
fu_context_get_firmware_gtype_ids;
@ -606,7 +604,6 @@ LIBFWUPDPLUGIN_1.6.0 {
fu_context_new;
fu_context_security_changed;
fu_context_set_battery_level;
fu_context_set_battery_state;
fu_context_set_battery_threshold;
fu_context_set_compile_versions;
fu_context_set_runtime_versions;
@ -1168,11 +1165,15 @@ LIBFWUPDPLUGIN_1.8.11 {
fu_acpi_table_get_revision;
fu_acpi_table_get_type;
fu_acpi_table_new;
fu_context_get_power_state;
fu_context_set_power_state;
fu_device_has_problem;
fu_device_progress_get_type;
fu_device_progress_new;
fu_device_sleep;
fu_device_sleep_full;
fu_power_state_is_ac;
fu_power_state_to_string;
fu_strdup;
fu_udev_device_get_cls;
fu_udev_device_is_pci_base_cls;

View File

@ -16,6 +16,14 @@ struct _FuPowerdPlugin {
G_DEFINE_TYPE(FuPowerdPlugin, fu_powerd_plugin, FU_TYPE_PLUGIN)
typedef enum {
FU_POWERD_BATTERY_STATE_UNKNOWN,
FU_POWERD_BATTERY_STATE_CHARGING,
FU_POWERD_BATTERY_STATE_DISCHARGING,
FU_POWERD_BATTERY_STATE_EMPTY,
FU_POWERD_BATTERY_STATE_FULLY_CHARGED,
} FuPowerdBatteryState;
static gboolean
fu_powerd_plugin_create_suspend_file(GError **error)
{
@ -66,9 +74,25 @@ fu_powerd_plugin_rescan(FuPlugin *plugin, GVariant *parameters)
/* checking if percentage is invalid */
if (current_level < 1 || current_level > 100)
current_level = FWUPD_BATTERY_LEVEL_INVALID;
fu_context_set_battery_state(ctx, current_state);
fu_context_set_battery_level(ctx, current_level);
switch (current_state) {
case FU_POWERD_BATTERY_STATE_CHARGING:
fu_context_set_power_state(ctx, FU_POWER_STATE_AC_CHARGING);
break;
case FU_POWERD_BATTERY_STATE_DISCHARGING:
fu_context_set_power_state(ctx, FU_POWER_STATE_BATTERY_DISCHARGING);
break;
case FU_POWERD_BATTERY_STATE_EMPTY:
fu_context_set_power_state(ctx, FU_POWER_STATE_BATTERY_EMPTY);
break;
case FU_POWERD_BATTERY_STATE_FULLY_CHARGED:
fu_context_set_power_state(ctx, FU_POWER_STATE_AC_FULLY_CHARGED);
break;
default:
fu_context_set_power_state(ctx, FU_POWER_STATE_UNKNOWN);
break;
}
}
static void

View File

@ -39,36 +39,36 @@ fu_upower_plugin_rescan_devices(FuPlugin *plugin)
/* check that we "have" a battery */
type_val = g_dbus_proxy_get_cached_property(self->proxy, "Type");
if (type_val == NULL || g_variant_get_uint32(type_val) == 0) {
fu_context_set_battery_state(ctx, FU_BATTERY_STATE_UNKNOWN);
fu_context_set_power_state(ctx, FU_POWER_STATE_UNKNOWN);
fu_context_set_battery_level(ctx, FWUPD_BATTERY_LEVEL_INVALID);
return;
}
state_val = g_dbus_proxy_get_cached_property(self->proxy, "State");
if (state_val == NULL || g_variant_get_uint32(state_val) == 0) {
g_warning("failed to query power state");
fu_context_set_battery_state(ctx, FU_BATTERY_STATE_UNKNOWN);
fu_context_set_power_state(ctx, FU_POWER_STATE_UNKNOWN);
fu_context_set_battery_level(ctx, FWUPD_BATTERY_LEVEL_INVALID);
return;
}
/* map from UpDeviceState to FuBatteryState */
/* map from UpDeviceState to FuPowerState */
switch (g_variant_get_uint32(state_val)) {
case UP_DEVICE_STATE_CHARGING:
case UP_DEVICE_STATE_PENDING_CHARGE:
fu_context_set_battery_state(ctx, FU_BATTERY_STATE_CHARGING);
fu_context_set_power_state(ctx, FU_POWER_STATE_AC_CHARGING);
break;
case UP_DEVICE_STATE_DISCHARGING:
case UP_DEVICE_STATE_PENDING_DISCHARGE:
fu_context_set_battery_state(ctx, FU_BATTERY_STATE_DISCHARGING);
fu_context_set_power_state(ctx, FU_POWER_STATE_BATTERY_DISCHARGING);
break;
case UP_DEVICE_STATE_EMPTY:
fu_context_set_battery_state(ctx, FU_BATTERY_STATE_EMPTY);
fu_context_set_power_state(ctx, FU_POWER_STATE_BATTERY_EMPTY);
break;
case UP_DEVICE_STATE_FULLY_CHARGED:
fu_context_set_battery_state(ctx, FU_BATTERY_STATE_FULLY_CHARGED);
fu_context_set_power_state(ctx, FU_POWER_STATE_AC_FULLY_CHARGED);
break;
default:
fu_context_set_battery_state(ctx, FU_BATTERY_STATE_UNKNOWN);
fu_context_set_power_state(ctx, FU_POWER_STATE_UNKNOWN);
break;
}

View File

@ -443,14 +443,13 @@ fu_engine_watch_device(FuEngine *self, FuDevice *device)
}
static void
fu_engine_ensure_device_battery_inhibit(FuEngine *self, FuDevice *device)
fu_engine_ensure_device_power_inhibit(FuEngine *self, FuDevice *device)
{
if (fu_config_get_ignore_power(self->config))
return;
if (fu_device_has_flag(device, FWUPD_DEVICE_FLAG_REQUIRE_AC) &&
(fu_context_get_battery_state(self->ctx) == FU_BATTERY_STATE_DISCHARGING ||
fu_context_get_battery_state(self->ctx) == FU_BATTERY_STATE_EMPTY)) {
!fu_power_state_is_ac(fu_context_get_power_state(self->ctx))) {
fu_device_add_problem(device, FWUPD_DEVICE_PROBLEM_REQUIRE_AC_POWER);
} else {
fu_device_remove_problem(device, FWUPD_DEVICE_PROBLEM_REQUIRE_AC_POWER);
@ -522,7 +521,7 @@ static void
fu_engine_device_added_cb(FuDeviceList *device_list, FuDevice *device, FuEngine *self)
{
fu_engine_watch_device(self, device);
fu_engine_ensure_device_battery_inhibit(self, device);
fu_engine_ensure_device_power_inhibit(self, device);
fu_engine_ensure_device_lid_inhibit(self, device);
fu_engine_ensure_device_system_inhibit(self, device);
fu_engine_acquiesce_reset(self);
@ -3487,8 +3486,7 @@ fu_engine_device_check_power(FuEngine *self,
/* not charging */
if (fu_device_has_flag(device, FWUPD_DEVICE_FLAG_REQUIRE_AC) &&
(fu_context_get_battery_state(self->ctx) == FU_BATTERY_STATE_DISCHARGING ||
fu_context_get_battery_state(self->ctx) == FU_BATTERY_STATE_EMPTY)) {
!fu_power_state_is_ac(fu_context_get_power_state(self->ctx))) {
g_set_error_literal(error,
FWUPD_ERROR,
FWUPD_ERROR_AC_POWER_REQUIRED,
@ -8871,14 +8869,14 @@ fu_engine_add_runtime_version(FuEngine *self, const gchar *component_id, const g
}
static void
fu_engine_context_battery_changed_cb(FuContext *ctx, GParamSpec *pspec, FuEngine *self)
fu_engine_context_power_changed_cb(FuContext *ctx, GParamSpec *pspec, FuEngine *self)
{
g_autoptr(GPtrArray) devices = fu_device_list_get_all(self->device_list);
/* apply policy on any existing devices */
for (guint i = 0; i < devices->len; i++) {
FuDevice *device = g_ptr_array_index(devices, i);
fu_engine_ensure_device_battery_inhibit(self, device);
fu_engine_ensure_device_power_inhibit(self, device);
fu_engine_ensure_device_lid_inhibit(self, device);
fu_engine_ensure_device_system_inhibit(self, device);
}
@ -8928,24 +8926,24 @@ fu_engine_init(FuEngine *self)
G_CALLBACK(fu_engine_context_security_changed_cb),
self);
g_signal_connect(FU_CONTEXT(self->ctx),
"notify::battery-state",
G_CALLBACK(fu_engine_context_battery_changed_cb),
"notify::power-state",
G_CALLBACK(fu_engine_context_power_changed_cb),
self);
g_signal_connect(FU_CONTEXT(self->ctx),
"notify::lid-state",
G_CALLBACK(fu_engine_context_battery_changed_cb),
G_CALLBACK(fu_engine_context_power_changed_cb),
self);
g_signal_connect(FU_CONTEXT(self->ctx),
"notify::battery-level",
G_CALLBACK(fu_engine_context_battery_changed_cb),
G_CALLBACK(fu_engine_context_power_changed_cb),
self);
g_signal_connect(FU_CONTEXT(self->ctx),
"notify::battery-threshold",
G_CALLBACK(fu_engine_context_battery_changed_cb),
G_CALLBACK(fu_engine_context_power_changed_cb),
self);
g_signal_connect(FU_CONTEXT(self->ctx),
"notify::flags",
G_CALLBACK(fu_engine_context_battery_changed_cb),
G_CALLBACK(fu_engine_context_power_changed_cb),
self);
g_signal_connect(FU_CONFIG(self->config),