From 357bfd07dae27dc8e88a73f8dcaff2cf13843472 Mon Sep 17 00:00:00 2001 From: George Popoola Date: Wed, 7 Jul 2021 17:56:27 +0000 Subject: [PATCH] powerd: DBus Connection and Parsing A series of changes are made to the powerd skeleton plugin in order to reach two goals: ensuring that it handles cases correctly, given certain information about the battery and/or certain return types and that it successfully retrieves battery information from powerd to be used later. Logic is then added to ensure updates are only performed when that battery level is at or above the minimum threshold. Then logic is added that checks if the device being updating requires AC power. Along with this, specific error statements are added for each scenario where an update is blocked. To address the next goal, within fu_plugin_startup(), a GDBus connection is established. However, instead of a direct connection to powerd, the connection is changed to link to the general system bus with g_bus_get_sync(). From there, a proxy is created to represent the connection to powerd. A test call is made for the name of the service that the proxy represents to check for successful communication. Then, in fu_plugin_update_prepare(), the existing proxy is called and in the call, the "GetBatteryState" is passed to make a method call method. The response is filled into a GVariant, whose entries are initialized in new variables to use for battery checks. And checks are added to make sure every step was successful. --- plugins/powerd/README.md | 2 +- plugins/powerd/fu-plugin-powerd.c | 106 +++++++++++++++++++++++++++++- 2 files changed, 104 insertions(+), 4 deletions(-) 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; }