diff --git a/plugins/powerd/README.md b/plugins/powerd/README.md index 626b0238c..8d4015bd0 100644 --- a/plugins/powerd/README.md +++ b/plugins/powerd/README.md @@ -15,4 +15,4 @@ This protocol does not create a device and thus requires no vendor ID set. External interface access ------------------------- -This plugin requires access to a dbus interface that is to be discussed. +This plugin requires access to the `org.chromium.PowerManager` DBus interface. diff --git a/plugins/powerd/fu-plugin-powerd.c b/plugins/powerd/fu-plugin-powerd.c index 63ff621a0..16d893265 100644 --- a/plugins/powerd/fu-plugin-powerd.c +++ b/plugins/powerd/fu-plugin-powerd.c @@ -9,6 +9,8 @@ #include +#define MINIMUM_BATTERY_PERCENTAGE_FALLBACK 10 + struct FuPluginData { GDBusProxy *proxy; /* nullable */ }; @@ -17,14 +19,59 @@ void fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); +} + +void +fu_plugin_destroy (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + if (data->proxy != NULL) + g_object_unref (data->proxy); } gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) { - g_set_error ( - error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "not supported yet"); - return FALSE; + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(GDBusConnection) connection = NULL; + g_autofree gchar *name_owner = NULL; + + /* establishing DBus connection and proxy for method call to powerd */ + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); + + if (connection == NULL) { + g_prefix_error (error, + "Connection with system was not established: "); + return FALSE; + } + + data->proxy = g_dbus_proxy_new_sync (connection, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.chromium.PowerManager", + "/org/chromium/PowerManager", + "org.chromium.PowerManager", + NULL, + error); + + if (data->proxy == NULL) { + g_prefix_error ( + error, + "Failed to establish proxy for power manager server: "); + return FALSE; + } + + 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 service that owns the name for %s", + g_dbus_proxy_get_name (data->proxy)); + return FALSE; + } + return TRUE; } gboolean @@ -33,5 +80,58 @@ fu_plugin_update_prepare (FuPlugin *plugin, FuDevice *device, GError **error) { + FuPluginData *data = fu_plugin_get_data (plugin); + guint32 power_type = 0; + guint32 current_status = 0; + gdouble current_percentage = 0; + g_autoptr(GVariant) powerd_response = NULL; + + /* making method call to "GetBatteryState" through the proxy */ + powerd_response = g_dbus_proxy_call_sync (data->proxy, + "GetBatteryState", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + error); + + if (powerd_response == NULL) { + g_prefix_error ( + error, + "Battery information from powerd was not loaded " + "successfully: "); + return FALSE; + } + + /* parsing data in powerd_response and inputting it into battery-check + * conditions */ + g_variant_get (powerd_response, + "(uud)", + &power_type, + ¤t_status, + ¤t_percentage); + + /* blocking updates if there is no AC power or if battery + * percentage is too low + */ + if (fu_device_has_flag (device, FWUPD_DEVICE_FLAG_REQUIRE_AC) && + current_status == FU_BATTERY_STATE_DISCHARGING) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_AC_POWER_REQUIRED, + "Cannot install update without external power " + "unless forced "); + return FALSE; + } + + if (current_percentage < MINIMUM_BATTERY_PERCENTAGE_FALLBACK) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_BATTERY_LEVEL_TOO_LOW, + "Cannot install update when system battery " + "is not at least %i%% unless forced", + MINIMUM_BATTERY_PERCENTAGE_FALLBACK); + return FALSE; + } return TRUE; }