up-device-battery: Enable and preserve the battery charging threshold config

It sets the battery start and end charging threshold to the kernel and also
saves the configuration in a file. If upower is restarted, upower
can recover the charging threshold setting through the configuration file.

The configuration file is based on the model name and serial number of the
battery so the battery can be configured individually.

Signed-off-by: Kate Hsuan <hpa@redhat.com>
This commit is contained in:
Jelle van der Waa 2024-07-23 14:46:36 +08:00 committed by Kate Hsuan
parent dc28eccd1c
commit 16e373add0
4 changed files with 113 additions and 0 deletions

View file

@ -100,6 +100,11 @@ if historydir == ''
historydir = get_option('prefix') / get_option('localstatedir') / 'lib' / 'upower'
endif
statedir = get_option('statedir')
if statedir == ''
statedir = get_option('prefix') / get_option('localstatedir') / 'lib' / 'upower'
endif
dbusdir = get_option('datadir') / 'dbus-1'
systemdsystemunitdir = get_option('systemdsystemunitdir')
if systemdsystemunitdir == ''

View file

@ -21,6 +21,9 @@ option('udevhwdbdir',
option('historydir',
type : 'string',
description : 'Directory for upower history files will be stored')
option('statedir',
type : 'string',
description : 'Directory for upower status files will be stored')
option('systemdsystemunitdir',
type : 'string',
description : 'Directory for systemd service files ("no" to disable)')

View file

@ -11,6 +11,7 @@ upowerd_deps = declare_dependency(
compile_args: [
'-DUP_COMPILATION',
'-DHISTORY_DIR="@0@"'.format(historydir),
'-DSTATE_DIR="@0@"'.format(statedir),
],
)

View file

@ -52,6 +52,9 @@ typedef struct {
/* dynamic values */
gint64 fast_repoll_until;
gboolean repoll_needed;
/* state path */
const char *state_dir;
} UpDeviceBatteryPrivate;
G_DEFINE_TYPE_EXTENDED (UpDeviceBattery, up_device_battery, UP_TYPE_DEVICE, 0,
@ -395,6 +398,16 @@ up_device_battery_report (UpDeviceBattery *self,
up_device_battery_update_poll_frequency (self, values->state, reason);
}
static gboolean
up_device_battery_set_charge_thresholds(UpDeviceBattery *self, gdouble start, gdouble end, GError **error)
{
UpDeviceBatteryClass *klass = UP_DEVICE_BATTERY_GET_CLASS (self);
if (klass->set_battery_charge_thresholds == NULL)
return FALSE;
return klass->set_battery_charge_thresholds(&self->parent_instance, start, end, error);
}
void
up_device_battery_update_info (UpDeviceBattery *self, UpBatteryInfo *info)
{
@ -445,6 +458,8 @@ up_device_battery_update_info (UpDeviceBattery *self, UpBatteryInfo *info)
"technology", info->technology,
"has-history", TRUE,
"has-statistics", TRUE,
"charge-start-threshold", info->charge_control_start_threshold,
"charge-end-threshold", info->charge_control_end_threshold,
"charge-threshold-supported", info->charge_control_supported,
NULL);
@ -513,20 +528,109 @@ up_device_battery_update_info (UpDeviceBattery *self, UpBatteryInfo *info)
"has-history", FALSE,
"has-statistics", FALSE,
"update-time", (guint64) g_get_real_time () / G_USEC_PER_SEC,
"charge-start-threshold", 0,
"charge-end-threshold", 100,
"charge-threshold-enabled", FALSE,
"charge-threshold-supported", FALSE,
NULL);
}
}
static gboolean
up_device_battery_charge_threshold_state_write(UpDeviceBattery *self, gboolean enabled, const gchar *state_file) {
g_autofree gchar *filename = NULL;
GError *error = NULL;
UpDeviceBatteryPrivate *priv = up_device_battery_get_instance_private (self);
filename = g_build_filename (priv->state_dir, state_file, NULL);
if (!g_file_set_contents (filename, enabled ? "1": "0" , -1, &error)) {
g_error ("failed to save battery charge threshold: %s", error->message);
return FALSE;
}
return TRUE;
}
/**
* up_device_battery_set_charge_threshold:
**/
static gboolean
up_device_battery_set_charge_threshold (UpExportedDevice *skeleton,
GDBusMethodInvocation *invocation,
gboolean enabled,
UpDeviceBattery *self)
{
gboolean ret = FALSE;
gboolean charge_threshold_enabled;
gboolean charge_threshold_supported;
guint charge_start_threshold = 0;
guint charge_end_threshold = 100;
g_autofree gchar *state_file = NULL;
g_autoptr(GError) error = NULL;
g_object_get (self,
"charge-threshold-enabled", &charge_threshold_enabled,
"charge-threshold-supported", &charge_threshold_supported,
"charge-start-threshold", &charge_start_threshold,
"charge-end-threshold", &charge_end_threshold,
NULL);
if (!charge_threshold_supported) {
g_dbus_method_invocation_return_error (invocation,
UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL,
"setting battery charge thresholds is unsupported");
return TRUE;
}
state_file = g_strdup_printf("charging-threshold-status");
if (!up_device_battery_charge_threshold_state_write (self, enabled, state_file)) {
g_dbus_method_invocation_return_error (invocation,
UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL,
"writing charge limits state file '%s' failed", state_file);
return TRUE;
}
if (enabled)
ret = up_device_battery_set_charge_thresholds (self, charge_start_threshold, charge_end_threshold, &error);
else
ret = up_device_battery_set_charge_thresholds (self, 0, 100, &error);
if (!ret) {
g_dbus_method_invocation_return_error (invocation,
UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL,
"failed on setting charging threshold: %s", error->message);
return TRUE;
}
g_object_set(self,
"charge-threshold-enabled", enabled,
NULL);
up_exported_device_complete_enable_charge_threshold (skeleton, invocation);
return TRUE;
}
static void
up_device_battery_init (UpDeviceBattery *self)
{
UpDeviceBatteryPrivate *priv = up_device_battery_get_instance_private (self);
g_object_set (self,
"type", UP_DEVICE_KIND_BATTERY,
"power-supply", TRUE,
"is-rechargeable", TRUE,
NULL);
g_signal_connect (self, "handle-enable-charge-threshold",
G_CALLBACK (up_device_battery_set_charge_threshold), self);
if (g_getenv ("UPOWER_STATE_DIR")) {
priv->state_dir = g_getenv ("UPOWER_STATE_DIR");
} else {
priv->state_dir = STATE_DIR;
}
}
static void