mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-13 19:08:34 +00:00
Set the system battery state and level on the FuContext shared state
This allows plugins to set the battery power state of the *machine* which means we can automatically inhibit devices with FWUPD_DEVICE_FLAG_REQUIRE_AC set. It also allows to set the BatteryThreshold to 25% for Lenovo hardware, and we can override other vendors with further quirks as required. Fixes https://github.com/fwupd/fwupd/issues/3084
This commit is contained in:
parent
0f50a3186c
commit
4d76d18d35
@ -3280,6 +3280,32 @@ fu_common_align_up (gsize value, guint8 alignment)
|
||||
return value_new;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_battery_state_to_string:
|
||||
* @battery_state: a #FuBatteryState, e.g. %FU_BATTERY_STATE_FULLY_CHARGED
|
||||
*
|
||||
* Converts an enumerated type to a string.
|
||||
*
|
||||
* Returns: a string, or %NULL for invalid
|
||||
*
|
||||
* Since: 1.6.0
|
||||
**/
|
||||
const gchar *
|
||||
fu_battery_state_to_string (FuBatteryState battery_state)
|
||||
{
|
||||
if (battery_state == FU_BATTERY_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";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_xmlb_builder_insert_kv:
|
||||
* @bn: #JsonBuilder
|
||||
|
@ -101,6 +101,34 @@ typedef enum {
|
||||
FU_CPU_VENDOR_LAST
|
||||
} FuCpuVendor;
|
||||
|
||||
/**
|
||||
* FU_BATTERY_VALUE_INVALID:
|
||||
*
|
||||
* This value signifies the battery level is either unset, or the value cannot
|
||||
* be discovered.
|
||||
*/
|
||||
#define FU_BATTERY_VALUE_INVALID 101
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* The device battery state.
|
||||
**/
|
||||
typedef enum {
|
||||
FU_BATTERY_STATE_UNKNOWN,
|
||||
FU_BATTERY_STATE_CHARGING,
|
||||
FU_BATTERY_STATE_DISCHARGING,
|
||||
FU_BATTERY_STATE_EMPTY,
|
||||
FU_BATTERY_STATE_FULLY_CHARGED,
|
||||
/*< private >*/
|
||||
FU_BATTERY_STATE_LAST
|
||||
} FuBatteryState;
|
||||
|
||||
typedef void (*FuOutputHandler) (const gchar *line,
|
||||
gpointer user_data);
|
||||
|
||||
@ -364,6 +392,7 @@ guint32 fu_common_crc32_full (const guint8 *buf,
|
||||
gchar *fu_common_uri_get_scheme (const gchar *uri);
|
||||
gsize fu_common_align_up (gsize value,
|
||||
guint8 alignment);
|
||||
const gchar *fu_battery_state_to_string (FuBatteryState battery_state);
|
||||
|
||||
void fu_xmlb_builder_insert_kv (XbBuilderNode *bn,
|
||||
const gchar *key,
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "fu-common.h"
|
||||
#include "fu-context-private.h"
|
||||
#include "fu-hwids.h"
|
||||
#include "fu-smbios-private.h"
|
||||
@ -29,6 +28,9 @@ typedef struct {
|
||||
GHashTable *compile_versions;
|
||||
GPtrArray *udev_subsystems;
|
||||
GHashTable *firmware_gtypes;
|
||||
FuBatteryState battery_state;
|
||||
guint battery_level;
|
||||
guint battery_threshold;
|
||||
} FuContextPrivate;
|
||||
|
||||
enum {
|
||||
@ -36,6 +38,14 @@ enum {
|
||||
SIGNAL_LAST
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_BATTERY_STATE,
|
||||
PROP_BATTERY_LEVEL,
|
||||
PROP_BATTERY_THRESHOLD,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
static guint signals[SIGNAL_LAST] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (FuContext, fu_context, G_TYPE_OBJECT)
|
||||
@ -546,6 +556,169 @@ fu_context_load_quirks (FuContext *self, FuQuirksLoadFlags flags, GError **error
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_context_get_battery_state:
|
||||
* @self: A #FuContext
|
||||
*
|
||||
* Gets if the system is on battery power, e.g. UPS or laptop battery.
|
||||
*
|
||||
* Returns: a #FuBatteryState, e.g. %FU_BATTERY_STATE_DISCHARGING
|
||||
*
|
||||
* Since: 1.6.0
|
||||
**/
|
||||
FuBatteryState
|
||||
fu_context_get_battery_state (FuContext *self)
|
||||
{
|
||||
FuContextPrivate *priv = GET_PRIVATE (self);
|
||||
g_return_val_if_fail (FU_IS_CONTEXT (self), FALSE);
|
||||
return priv->battery_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_context_set_battery_state:
|
||||
* @self: A #FuContext
|
||||
* @battery_state: a #FuBatteryState, e.g. %FU_BATTERY_STATE_DISCHARGING
|
||||
*
|
||||
* Sets if the system is on battery power, e.g. UPS or laptop battery.
|
||||
*
|
||||
* Since: 1.6.0
|
||||
**/
|
||||
void
|
||||
fu_context_set_battery_state (FuContext *self, FuBatteryState battery_state)
|
||||
{
|
||||
FuContextPrivate *priv = GET_PRIVATE (self);
|
||||
g_return_if_fail (FU_IS_CONTEXT (self));
|
||||
if (priv->battery_state == battery_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");
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_context_get_battery_level:
|
||||
* @self: A #FuContext
|
||||
*
|
||||
* Gets the system battery level in percent.
|
||||
*
|
||||
* Returns: percentage value, or %FU_BATTERY_VALUE_INVALID for unknown
|
||||
*
|
||||
* Since: 1.6.0
|
||||
**/
|
||||
guint
|
||||
fu_context_get_battery_level (FuContext *self)
|
||||
{
|
||||
FuContextPrivate *priv = GET_PRIVATE (self);
|
||||
g_return_val_if_fail (FU_IS_CONTEXT (self), G_MAXUINT);
|
||||
return priv->battery_level;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_context_set_battery_level:
|
||||
* @self: A #FuContext
|
||||
* @battery_level: value
|
||||
*
|
||||
* Sets the system battery level in percent.
|
||||
*
|
||||
* Since: 1.6.0
|
||||
**/
|
||||
void
|
||||
fu_context_set_battery_level (FuContext *self, guint battery_level)
|
||||
{
|
||||
FuContextPrivate *priv = GET_PRIVATE (self);
|
||||
g_return_if_fail (FU_IS_CONTEXT (self));
|
||||
g_return_if_fail (battery_level <= FU_BATTERY_VALUE_INVALID);
|
||||
if (priv->battery_level == battery_level)
|
||||
return;
|
||||
priv->battery_level = battery_level;
|
||||
g_debug ("battery level now %u", battery_level);
|
||||
g_object_notify (G_OBJECT (self), "battery-level");
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_context_get_battery_threshold:
|
||||
* @self: A #FuContext
|
||||
*
|
||||
* Gets the system battery threshold in percent.
|
||||
*
|
||||
* Returns: percentage value, or %FU_BATTERY_VALUE_INVALID for unknown
|
||||
*
|
||||
* Since: 1.6.0
|
||||
**/
|
||||
guint
|
||||
fu_context_get_battery_threshold (FuContext *self)
|
||||
{
|
||||
FuContextPrivate *priv = GET_PRIVATE (self);
|
||||
g_return_val_if_fail (FU_IS_CONTEXT (self), G_MAXUINT);
|
||||
return priv->battery_threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* fu_context_set_battery_threshold:
|
||||
* @self: A #FuContext
|
||||
* @battery_threshold: value
|
||||
*
|
||||
* Sets the system battery threshold in percent.
|
||||
*
|
||||
* Since: 1.6.0
|
||||
**/
|
||||
void
|
||||
fu_context_set_battery_threshold (FuContext *self, guint battery_threshold)
|
||||
{
|
||||
FuContextPrivate *priv = GET_PRIVATE (self);
|
||||
g_return_if_fail (FU_IS_CONTEXT (self));
|
||||
g_return_if_fail (battery_threshold <= FU_BATTERY_VALUE_INVALID);
|
||||
if (priv->battery_threshold == battery_threshold)
|
||||
return;
|
||||
priv->battery_threshold = battery_threshold;
|
||||
g_debug ("battery threshold now %u", battery_threshold);
|
||||
g_object_notify (G_OBJECT (self), "battery-threshold");
|
||||
}
|
||||
|
||||
static void
|
||||
fu_context_get_property (GObject *object, guint prop_id,
|
||||
GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
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);
|
||||
break;
|
||||
case PROP_BATTERY_LEVEL:
|
||||
g_value_set_uint (value, priv->battery_level);
|
||||
break;
|
||||
case PROP_BATTERY_THRESHOLD:
|
||||
g_value_set_uint (value, priv->battery_threshold);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fu_context_set_property (GObject *object, guint prop_id,
|
||||
const GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
FuContext *self = FU_CONTEXT (object);
|
||||
switch (prop_id) {
|
||||
case PROP_BATTERY_STATE:
|
||||
fu_context_set_battery_state (self, g_value_get_uint (value));
|
||||
break;
|
||||
case PROP_BATTERY_LEVEL:
|
||||
fu_context_set_battery_level (self, g_value_get_uint (value));
|
||||
break;
|
||||
case PROP_BATTERY_THRESHOLD:
|
||||
fu_context_set_battery_threshold (self, g_value_get_uint (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fu_context_finalize (GObject *object)
|
||||
{
|
||||
@ -565,6 +738,34 @@ static void
|
||||
fu_context_class_init (FuContextClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GParamSpec *pspec;
|
||||
|
||||
object_class->get_property = fu_context_get_property;
|
||||
object_class->set_property = fu_context_set_property;
|
||||
|
||||
pspec = g_param_spec_uint ("battery-state", NULL, NULL,
|
||||
FU_BATTERY_STATE_UNKNOWN,
|
||||
FU_BATTERY_STATE_LAST,
|
||||
FU_BATTERY_STATE_UNKNOWN,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_NAME);
|
||||
g_object_class_install_property (object_class, PROP_BATTERY_STATE, pspec);
|
||||
|
||||
pspec = g_param_spec_uint ("battery-level", NULL, NULL,
|
||||
0,
|
||||
FU_BATTERY_VALUE_INVALID,
|
||||
FU_BATTERY_VALUE_INVALID,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_NAME);
|
||||
g_object_class_install_property (object_class, PROP_BATTERY_LEVEL, pspec);
|
||||
|
||||
pspec = g_param_spec_uint ("battery-threshold", NULL, NULL,
|
||||
0,
|
||||
FU_BATTERY_VALUE_INVALID,
|
||||
FU_BATTERY_VALUE_INVALID,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_NAME);
|
||||
g_object_class_install_property (object_class, PROP_BATTERY_THRESHOLD, pspec);
|
||||
|
||||
signals[SIGNAL_SECURITY_CHANGED] =
|
||||
g_signal_new ("security-changed",
|
||||
@ -580,6 +781,8 @@ static void
|
||||
fu_context_init (FuContext *self)
|
||||
{
|
||||
FuContextPrivate *priv = GET_PRIVATE (self);
|
||||
priv->battery_level = FU_BATTERY_VALUE_INVALID;
|
||||
priv->battery_threshold = FU_BATTERY_VALUE_INVALID;
|
||||
priv->smbios = fu_smbios_new ();
|
||||
priv->hwids = fu_hwids_new ();
|
||||
priv->udev_subsystems = g_ptr_array_new_with_free_func (g_free);
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "fu-common.h"
|
||||
|
||||
#define FU_TYPE_CONTEXT (fu_context_get_type ())
|
||||
G_DECLARE_DERIVABLE_TYPE (FuContext, fu_context, FU, CONTEXT, GObject)
|
||||
|
||||
@ -59,3 +61,13 @@ gboolean fu_context_lookup_quirk_by_id_iter (FuContext *self,
|
||||
void 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);
|
||||
void fu_context_set_battery_state (FuContext *self,
|
||||
FuBatteryState battery_state);
|
||||
guint fu_context_get_battery_level (FuContext *self);
|
||||
void fu_context_set_battery_level (FuContext *self,
|
||||
guint battery_level);
|
||||
guint fu_context_get_battery_threshold (FuContext *self);
|
||||
void fu_context_set_battery_threshold (FuContext *self,
|
||||
guint battery_threshold);
|
||||
|
@ -2665,9 +2665,8 @@ static void
|
||||
fu_device_ensure_battery_inhibit (FuDevice *self)
|
||||
{
|
||||
FuDevicePrivate *priv = GET_PRIVATE (self);
|
||||
if (priv->battery_level == 0)
|
||||
return;
|
||||
if (priv->battery_level >= fu_device_get_battery_threshold (self)) {
|
||||
if (priv->battery_level == FU_BATTERY_VALUE_INVALID ||
|
||||
priv->battery_level >= fu_device_get_battery_threshold (self)) {
|
||||
fu_device_uninhibit (self, "battery");
|
||||
return;
|
||||
}
|
||||
@ -2688,7 +2687,7 @@ guint
|
||||
fu_device_get_battery_level (FuDevice *self)
|
||||
{
|
||||
FuDevicePrivate *priv = GET_PRIVATE (self);
|
||||
g_return_val_if_fail (FU_IS_DEVICE (self), 0);
|
||||
g_return_val_if_fail (FU_IS_DEVICE (self), FU_BATTERY_VALUE_INVALID);
|
||||
return priv->battery_level;
|
||||
}
|
||||
|
||||
@ -2697,8 +2696,10 @@ fu_device_get_battery_level (FuDevice *self)
|
||||
* @self: A #FuDevice
|
||||
* @battery_level: the percentage value
|
||||
*
|
||||
* Sets the battery level, or 0 for invalid. Setting this allows fwupd to show
|
||||
* a warning if the device change is too low to perform the update.
|
||||
* Sets the battery level, or %FU_BATTERY_VALUE_INVALID.
|
||||
*
|
||||
* Setting this allows fwupd to show a warning if the device change is too low
|
||||
* to perform the update.
|
||||
*
|
||||
* Since: 1.5.8
|
||||
**/
|
||||
@ -2707,7 +2708,7 @@ fu_device_set_battery_level (FuDevice *self, guint battery_level)
|
||||
{
|
||||
FuDevicePrivate *priv = GET_PRIVATE (self);
|
||||
g_return_if_fail (FU_IS_DEVICE (self));
|
||||
g_return_if_fail (battery_level <= 100);
|
||||
g_return_if_fail (battery_level <= FU_BATTERY_VALUE_INVALID);
|
||||
if (priv->battery_level == battery_level)
|
||||
return;
|
||||
priv->battery_level = battery_level;
|
||||
@ -2733,10 +2734,10 @@ guint
|
||||
fu_device_get_battery_threshold (FuDevice *self)
|
||||
{
|
||||
FuDevicePrivate *priv = GET_PRIVATE (self);
|
||||
g_return_val_if_fail (FU_IS_DEVICE (self), 0);
|
||||
g_return_val_if_fail (FU_IS_DEVICE (self), FU_BATTERY_VALUE_INVALID);
|
||||
|
||||
/* default value */
|
||||
if (priv->battery_threshold == 0)
|
||||
if (priv->battery_threshold == FU_BATTERY_VALUE_INVALID)
|
||||
return FU_DEVICE_DEFAULT_BATTERY_THRESHOLD;
|
||||
|
||||
return priv->battery_threshold;
|
||||
@ -2747,8 +2748,10 @@ fu_device_get_battery_threshold (FuDevice *self)
|
||||
* @self: A #FuDevice
|
||||
* @battery_threshold: the percentage value
|
||||
*
|
||||
* Sets the battery level, or 0 for the default. Setting this allows fwupd to
|
||||
* show a warning if the device change is too low to perform the update.
|
||||
* Sets the battery level, or %FU_BATTERY_VALUE_INVALID for the default.
|
||||
*
|
||||
* Setting this allows fwupd to show a warning if the device change is too low
|
||||
* to perform the update.
|
||||
*
|
||||
* Since: 1.6.0
|
||||
**/
|
||||
@ -2757,7 +2760,7 @@ fu_device_set_battery_threshold (FuDevice *self, guint battery_threshold)
|
||||
{
|
||||
FuDevicePrivate *priv = GET_PRIVATE (self);
|
||||
g_return_if_fail (FU_IS_DEVICE (self));
|
||||
g_return_if_fail (battery_threshold <= 100);
|
||||
g_return_if_fail (battery_threshold <= FU_BATTERY_VALUE_INVALID);
|
||||
if (priv->battery_threshold == battery_threshold)
|
||||
return;
|
||||
priv->battery_threshold = battery_threshold;
|
||||
@ -2796,9 +2799,9 @@ fu_device_add_string (FuDevice *self, guint idt, GString *str)
|
||||
fu_common_string_append_kv (str, idt + 1, "ProxyId", fu_device_get_id (priv->proxy));
|
||||
if (priv->proxy_guid != NULL)
|
||||
fu_common_string_append_kv (str, idt + 1, "ProxyGuid", priv->proxy_guid);
|
||||
if (priv->battery_level != 0)
|
||||
if (priv->battery_level != FU_BATTERY_VALUE_INVALID)
|
||||
fu_common_string_append_ku (str, idt + 1, "BatteryLevel", priv->battery_level);
|
||||
if (priv->battery_threshold != 0)
|
||||
if (priv->battery_threshold != FU_BATTERY_VALUE_INVALID)
|
||||
fu_common_string_append_ku (str, idt + 1, "BatteryThreshold", priv->battery_threshold);
|
||||
if (priv->size_min > 0) {
|
||||
g_autofree gchar *sz = g_strdup_printf ("%" G_GUINT64_FORMAT, priv->size_min);
|
||||
@ -3891,13 +3894,17 @@ fu_device_class_init (FuDeviceClass *klass)
|
||||
g_object_class_install_property (object_class, PROP_PROGRESS, pspec);
|
||||
|
||||
pspec = g_param_spec_uint ("battery-level", NULL, NULL,
|
||||
0, 100, 0,
|
||||
0,
|
||||
FU_BATTERY_VALUE_INVALID,
|
||||
FU_BATTERY_VALUE_INVALID,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_NAME);
|
||||
g_object_class_install_property (object_class, PROP_BATTERY_LEVEL, pspec);
|
||||
|
||||
pspec = g_param_spec_uint ("battery-threshold", NULL, NULL,
|
||||
0, 100, 0,
|
||||
0,
|
||||
FU_BATTERY_VALUE_INVALID,
|
||||
FU_BATTERY_VALUE_INVALID,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_NAME);
|
||||
g_object_class_install_property (object_class, PROP_BATTERY_THRESHOLD, pspec);
|
||||
@ -3921,6 +3928,8 @@ fu_device_init (FuDevice *self)
|
||||
{
|
||||
FuDevicePrivate *priv = GET_PRIVATE (self);
|
||||
priv->order = G_MAXINT;
|
||||
priv->battery_level = FU_BATTERY_VALUE_INVALID;
|
||||
priv->battery_threshold = FU_BATTERY_VALUE_INVALID;
|
||||
priv->parent_guids = g_ptr_array_new_with_free_func (g_free);
|
||||
priv->possible_plugins = g_ptr_array_new_with_free_func (g_free);
|
||||
priv->retry_recs = g_ptr_array_new_with_free_func (g_free);
|
||||
|
@ -713,6 +713,7 @@ LIBFWUPDPLUGIN_1.5.8 {
|
||||
|
||||
LIBFWUPDPLUGIN_1.6.0 {
|
||||
global:
|
||||
fu_battery_state_to_string;
|
||||
fu_byte_array_align_up;
|
||||
fu_byte_array_set_size_full;
|
||||
fu_common_align_up;
|
||||
@ -721,6 +722,9 @@ LIBFWUPDPLUGIN_1.6.0 {
|
||||
fu_context_add_quirk_key;
|
||||
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;
|
||||
fu_context_get_hwid_guids;
|
||||
@ -738,6 +742,9 @@ LIBFWUPDPLUGIN_1.6.0 {
|
||||
fu_context_lookup_quirk_by_id_iter;
|
||||
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;
|
||||
fu_device_add_security_attrs;
|
||||
|
@ -11,9 +11,7 @@
|
||||
#define MINIMUM_BATTERY_PERCENTAGE_FALLBACK 10
|
||||
|
||||
struct FuPluginData {
|
||||
GDBusProxy *upower_proxy;
|
||||
GDBusProxy *display_proxy;
|
||||
guint64 minimum_battery;
|
||||
GDBusProxy *proxy; /* nullable */
|
||||
};
|
||||
|
||||
void
|
||||
@ -27,113 +25,112 @@ void
|
||||
fu_plugin_destroy (FuPlugin *plugin)
|
||||
{
|
||||
FuPluginData *data = fu_plugin_get_data (plugin);
|
||||
if (data->upower_proxy != NULL)
|
||||
g_object_unref (data->upower_proxy);
|
||||
if (data->display_proxy != NULL)
|
||||
g_object_unref (data->display_proxy);
|
||||
if (data->proxy != NULL)
|
||||
g_object_unref (data->proxy);
|
||||
}
|
||||
|
||||
static void
|
||||
fu_plugin_upower_rescan (FuPlugin *plugin)
|
||||
{
|
||||
FuContext *ctx = fu_plugin_get_context (plugin);
|
||||
FuPluginData *data = fu_plugin_get_data (plugin);
|
||||
g_autoptr(GVariant) percentage_val = NULL;
|
||||
g_autoptr(GVariant) type_val = NULL;
|
||||
g_autoptr(GVariant) state_val = NULL;
|
||||
|
||||
/* check that we "have" a battery */
|
||||
type_val = g_dbus_proxy_get_cached_property (data->proxy, "Type");
|
||||
if (type_val == NULL) {
|
||||
g_warning ("failed to query power type");
|
||||
fu_context_set_battery_state (ctx, FU_BATTERY_STATE_UNKNOWN);
|
||||
fu_context_set_battery_level (ctx, FU_BATTERY_VALUE_INVALID);
|
||||
return;
|
||||
}
|
||||
state_val = g_dbus_proxy_get_cached_property (data->proxy, "State");
|
||||
if (state_val == NULL) {
|
||||
g_warning ("failed to query power state");
|
||||
fu_context_set_battery_state (ctx, FU_BATTERY_STATE_UNKNOWN);
|
||||
fu_context_set_battery_level (ctx, FU_BATTERY_VALUE_INVALID);
|
||||
return;
|
||||
}
|
||||
fu_context_set_battery_state (ctx, g_variant_get_uint32 (state_val));
|
||||
|
||||
/* get percentage */
|
||||
percentage_val = g_dbus_proxy_get_cached_property (data->proxy, "Percentage");
|
||||
if (percentage_val == NULL) {
|
||||
g_warning ("failed to query power percentage level");
|
||||
fu_context_set_battery_level (ctx, FU_BATTERY_VALUE_INVALID);
|
||||
return;
|
||||
}
|
||||
fu_context_set_battery_level (ctx, g_variant_get_double (percentage_val));
|
||||
}
|
||||
|
||||
static void
|
||||
fu_plugin_upower_proxy_changed_cb (GDBusProxy *proxy,
|
||||
GVariant *changed_properties,
|
||||
GStrv invalidated_properties,
|
||||
FuPlugin *plugin)
|
||||
{
|
||||
fu_plugin_upower_rescan (plugin);
|
||||
}
|
||||
|
||||
gboolean
|
||||
fu_plugin_startup (FuPlugin *plugin, GError **error)
|
||||
{
|
||||
FuContext *ctx = fu_plugin_get_context (plugin);
|
||||
FuPluginData *data = fu_plugin_get_data (plugin);
|
||||
guint64 minimum_battery;
|
||||
g_autofree gchar *name_owner = NULL;
|
||||
g_autofree gchar *battery_str = NULL;
|
||||
data->upower_proxy =
|
||||
|
||||
data->proxy =
|
||||
g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
|
||||
NULL,
|
||||
"org.freedesktop.UPower",
|
||||
"/org/freedesktop/UPower",
|
||||
"org.freedesktop.UPower",
|
||||
NULL,
|
||||
error);
|
||||
if (data->upower_proxy == NULL) {
|
||||
g_prefix_error (error, "failed to connect to upower: ");
|
||||
return FALSE;
|
||||
}
|
||||
name_owner = g_dbus_proxy_get_name_owner (data->upower_proxy);
|
||||
if (name_owner == NULL) {
|
||||
g_set_error (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_NOT_SUPPORTED,
|
||||
"no owner for %s",
|
||||
g_dbus_proxy_get_name (data->upower_proxy));
|
||||
return FALSE;
|
||||
}
|
||||
data->display_proxy =
|
||||
g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
NULL,
|
||||
"org.freedesktop.UPower",
|
||||
"/org/freedesktop/UPower/devices/DisplayDevice",
|
||||
"org.freedesktop.UPower.Device",
|
||||
NULL,
|
||||
error);
|
||||
if (data->display_proxy == NULL) {
|
||||
if (data->proxy == NULL) {
|
||||
g_prefix_error (error, "failed to connect to upower: ");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
battery_str = fu_plugin_get_config_value (plugin, "BatteryThreshold");
|
||||
if (battery_str == NULL)
|
||||
data->minimum_battery = MINIMUM_BATTERY_PERCENTAGE_FALLBACK;
|
||||
else
|
||||
data->minimum_battery = fu_common_strtoull (battery_str);
|
||||
if (data->minimum_battery > 100) {
|
||||
g_warning ("Invalid minimum battery level specified: %" G_GUINT64_FORMAT,
|
||||
data->minimum_battery);
|
||||
data->minimum_battery = MINIMUM_BATTERY_PERCENTAGE_FALLBACK;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_plugin_upower_check_percentage_level (FuPlugin *plugin)
|
||||
{
|
||||
FuPluginData *data = fu_plugin_get_data (plugin);
|
||||
gdouble level;
|
||||
guint power_type;
|
||||
g_autoptr(GVariant) percentage_val = NULL;
|
||||
g_autoptr(GVariant) type_val = NULL;
|
||||
|
||||
/* check that we "have" a battery */
|
||||
type_val = g_dbus_proxy_get_cached_property (data->display_proxy, "Type");
|
||||
if (type_val == NULL) {
|
||||
g_warning ("Failed to query power type, assume AC power");
|
||||
return TRUE;
|
||||
}
|
||||
power_type = g_variant_get_uint32 (type_val);
|
||||
if (power_type != 2) {
|
||||
g_debug ("Not running on battery (Type: %u)", power_type);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* check percentage high enough */
|
||||
percentage_val = g_dbus_proxy_get_cached_property (data->display_proxy, "Percentage");
|
||||
if (percentage_val == NULL) {
|
||||
g_warning ("Failed to query power percentage level, assume enough charge");
|
||||
return TRUE;
|
||||
}
|
||||
level = g_variant_get_double (percentage_val);
|
||||
g_debug ("System power source is %.1f%%", level);
|
||||
|
||||
return level >= data->minimum_battery;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_plugin_upower_check_on_battery (FuPlugin *plugin)
|
||||
{
|
||||
FuPluginData *data = fu_plugin_get_data (plugin);
|
||||
g_autoptr(GVariant) value = NULL;
|
||||
|
||||
value = g_dbus_proxy_get_cached_property (data->upower_proxy, "OnBattery");
|
||||
if (value == NULL) {
|
||||
g_warning ("failed to get OnBattery value, assume on AC power");
|
||||
name_owner = g_dbus_proxy_get_name_owner (data->proxy);
|
||||
if (name_owner == NULL) {
|
||||
g_set_error (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_NOT_SUPPORTED,
|
||||
"no owner for %s",
|
||||
g_dbus_proxy_get_name (data->proxy));
|
||||
return FALSE;
|
||||
}
|
||||
return g_variant_get_boolean (value);
|
||||
g_signal_connect (data->proxy, "g-properties-changed",
|
||||
G_CALLBACK (fu_plugin_upower_proxy_changed_cb), plugin);
|
||||
|
||||
battery_str = fu_plugin_get_config_value (plugin, "BatteryThreshold");
|
||||
if (battery_str == NULL) {
|
||||
const gchar *vendor = fu_context_get_hwid_replace_value (ctx,
|
||||
FU_HWIDS_KEY_MANUFACTURER,
|
||||
NULL);
|
||||
battery_str = g_strdup (fu_context_lookup_quirk_by_id (ctx,
|
||||
vendor,
|
||||
FU_QUIRKS_BATTERY_THRESHOLD));
|
||||
}
|
||||
if (battery_str == NULL)
|
||||
minimum_battery = MINIMUM_BATTERY_PERCENTAGE_FALLBACK;
|
||||
else
|
||||
minimum_battery = fu_common_strtoull (battery_str);
|
||||
if (minimum_battery > 100) {
|
||||
g_warning ("invalid minimum battery level specified: %" G_GUINT64_FORMAT,
|
||||
minimum_battery);
|
||||
minimum_battery = MINIMUM_BATTERY_PERCENTAGE_FALLBACK;
|
||||
}
|
||||
fu_context_set_battery_threshold (ctx, minimum_battery);
|
||||
fu_plugin_upower_rescan (plugin);
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
@ -142,13 +139,17 @@ fu_plugin_update_prepare (FuPlugin *plugin,
|
||||
FuDevice *device,
|
||||
GError **error)
|
||||
{
|
||||
FuContext *ctx = fu_plugin_get_context (plugin);
|
||||
|
||||
/* not all devices need this */
|
||||
if (!fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC))
|
||||
return TRUE;
|
||||
if (flags & FWUPD_INSTALL_FLAG_IGNORE_POWER)
|
||||
return TRUE;
|
||||
|
||||
/* determine if operating on AC or battery */
|
||||
if (fu_plugin_upower_check_on_battery (plugin) &&
|
||||
(flags & FWUPD_INSTALL_FLAG_IGNORE_POWER) == 0) {
|
||||
/* not charging */
|
||||
if (fu_context_get_battery_state (ctx) == FU_BATTERY_STATE_DISCHARGING ||
|
||||
fu_context_get_battery_state (ctx) == FU_BATTERY_STATE_EMPTY) {
|
||||
g_set_error_literal (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_AC_POWER_REQUIRED,
|
||||
@ -157,17 +158,17 @@ fu_plugin_update_prepare (FuPlugin *plugin,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* determine if battery high enough */
|
||||
if (!fu_plugin_upower_check_percentage_level (plugin) &&
|
||||
(flags & FWUPD_INSTALL_FLAG_IGNORE_POWER) == 0) {
|
||||
FuPluginData *data = fu_plugin_get_data (plugin);
|
||||
/* not enough just in case */
|
||||
if (fu_context_get_battery_level (ctx) < fu_context_get_battery_threshold (ctx)) {
|
||||
g_set_error (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_BATTERY_LEVEL_TOO_LOW,
|
||||
"Cannot install update when system battery "
|
||||
"is not at least %" G_GUINT64_FORMAT "%% unless forced",
|
||||
data->minimum_battery);
|
||||
"is not at least %u%% unless forced",
|
||||
fu_context_get_battery_threshold (ctx));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* success */
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
if host_machine.system() == 'linux'
|
||||
cargs = ['-DG_LOG_DOMAIN="FuPluginUpower"']
|
||||
|
||||
install_data(['upower.quirk'],
|
||||
install_dir: join_paths(datadir, 'fwupd', 'quirks.d'))
|
||||
|
||||
shared_module('fu_plugin_upower',
|
||||
fu_hash,
|
||||
sources : [
|
||||
|
@ -2,4 +2,4 @@
|
||||
|
||||
# The threshold to to require battery be at or above to allow updates
|
||||
# Measure in percent
|
||||
BatteryThreshold=10
|
||||
#BatteryThreshold=10
|
||||
|
2
plugins/upower/upower.quirk
Normal file
2
plugins/upower/upower.quirk
Normal file
@ -0,0 +1,2 @@
|
||||
[LENOVO]
|
||||
BatteryThreshold = 25
|
@ -225,10 +225,34 @@ fu_engine_watch_device (FuEngine *self, FuDevice *device)
|
||||
G_CALLBACK (fu_engine_status_notify_cb), self);
|
||||
}
|
||||
|
||||
static void
|
||||
fu_engine_ensure_device_battery_inhibit (FuEngine *self, FuDevice *device)
|
||||
{
|
||||
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_device_inhibit (device, "battery-system",
|
||||
"Cannot install update when not on AC power");
|
||||
return;
|
||||
}
|
||||
if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC) &&
|
||||
fu_context_get_battery_level (self->ctx) != FU_BATTERY_VALUE_INVALID &&
|
||||
fu_context_get_battery_threshold (self->ctx) != FU_BATTERY_VALUE_INVALID &&
|
||||
fu_context_get_battery_level (self->ctx) < fu_context_get_battery_threshold (self->ctx)) {
|
||||
g_autofree gchar *reason = NULL;
|
||||
reason = g_strdup_printf ("Cannot install update when system battery is not at least %u%%",
|
||||
fu_context_get_battery_threshold (self->ctx));
|
||||
fu_device_inhibit (device, "battery-system", reason);
|
||||
return;
|
||||
}
|
||||
fu_device_uninhibit (device, "battery-system");
|
||||
}
|
||||
|
||||
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);
|
||||
g_signal_emit (self, signals[SIGNAL_DEVICE_ADDED], 0, device);
|
||||
}
|
||||
|
||||
@ -6470,6 +6494,18 @@ fu_engine_add_app_flag (FuEngine *self, FuAppFlags app_flags)
|
||||
self->app_flags |= app_flags;
|
||||
}
|
||||
|
||||
static void
|
||||
fu_engine_context_battery_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);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fu_engine_idle_status_notify_cb (FuIdle *idle, GParamSpec *pspec, FuEngine *self)
|
||||
{
|
||||
@ -6509,6 +6545,15 @@ fu_engine_init (FuEngine *self)
|
||||
g_signal_connect (self->ctx, "security-changed",
|
||||
G_CALLBACK (fu_engine_context_security_changed_cb),
|
||||
self);
|
||||
g_signal_connect (self->ctx, "notify::battery-state",
|
||||
G_CALLBACK (fu_engine_context_battery_changed_cb),
|
||||
self);
|
||||
g_signal_connect (self->ctx, "notify::battery-level",
|
||||
G_CALLBACK (fu_engine_context_battery_changed_cb),
|
||||
self);
|
||||
g_signal_connect (self->ctx, "notify::battery-threshold",
|
||||
G_CALLBACK (fu_engine_context_battery_changed_cb),
|
||||
self);
|
||||
|
||||
g_signal_connect (self->config, "changed",
|
||||
G_CALLBACK (fu_engine_config_changed_cb),
|
||||
|
Loading…
Reference in New Issue
Block a user