From 139188a5b0216fc8ce05e7f77cfc3b58162ca3f1 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 12 Sep 2022 19:40:41 +0100 Subject: [PATCH] Allow adding backend tags to devices This allows the backend to identify the specific device for a specific phase. For instance, there might be a pre-update runtime, a bootloader and a post-update runtime and allowing tags to be saved to the backend object allows us to identify each version of the same physical device. This takes us one step closer to emulating a complete byte-perfect end-to-end update without actual hardware installed. --- libfwupdplugin/fu-device.c | 89 ++++++++++++++++++++++++++++++++++ libfwupdplugin/fu-device.h | 6 +++ libfwupdplugin/fu-plugin.c | 8 +++ libfwupdplugin/fu-self-test.c | 7 +++ libfwupdplugin/fwupdplugin.map | 3 ++ 5 files changed, 113 insertions(+) diff --git a/libfwupdplugin/fu-device.c b/libfwupdplugin/fu-device.c index e4d6fb913..13c0b4d1c 100644 --- a/libfwupdplugin/fu-device.c +++ b/libfwupdplugin/fu-device.c @@ -81,6 +81,7 @@ typedef struct { gchar *custom_flags; gulong notify_flags_handler_id; GHashTable *instance_hash; + GPtrArray *backend_tags; /* of utf-8 */ } FuDevicePrivate; typedef struct { @@ -103,6 +104,7 @@ enum { PROP_CONTEXT, PROP_PROXY, PROP_PARENT, + PROP_BACKEND_TAGS, PROP_LAST }; @@ -137,6 +139,9 @@ fu_device_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec case PROP_PARENT: g_value_set_object(value, fu_device_get_parent(self)); break; + case PROP_BACKEND_TAGS: + g_value_set_boxed(value, priv->backend_tags); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -1244,6 +1249,74 @@ fu_device_get_children(FuDevice *self) return fwupd_device_get_children(FWUPD_DEVICE(self)); } +/** + * fu_device_get_backend_tags: + * @self: a #FuDevice + * @backend_tag: a tag, for example `bootloader` or `runtime-reload` + * + * Gets any backend tags. + * + * Returns: (transfer none) (element-type utf-8): string tags + * + * Since: 1.8.5 + **/ +GPtrArray * +fu_device_get_backend_tags(FuDevice *self) +{ + FuDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(FU_IS_DEVICE(self), NULL); + return priv->backend_tags; +} + +/** + * fu_device_add_backend_tag: + * @self: a #FuDevice + * @backend_tag: a tag, for example `bootloader` or `runtime-reload` + * + * Adds a backend tag, which allows the backend to identify the specific device for a specific + * phase. For instance, there might be a pre-update runtime, a bootloader and a post-update runtime + * and allowing tags to be saved to the backend object allows us to identify each version of + * the same physical device. + * + * Since: 1.8.5 + **/ +void +fu_device_add_backend_tag(FuDevice *self, const gchar *backend_tag) +{ + FuDevicePrivate *priv = GET_PRIVATE(self); + g_return_if_fail(FU_IS_DEVICE(self)); + g_return_if_fail(backend_tag != NULL); + if (fu_device_has_backend_tag(self, backend_tag)) + return; + g_ptr_array_add(priv->backend_tags, g_strdup(backend_tag)); + g_object_notify(G_OBJECT(self), "backend-tags"); +} + +/** + * fu_device_has_backend_tag: + * @self: a #FuDevice + * @backend_tag: a tag, for example `bootloader` or `runtime-reload` + * + * Finds if the backend tag already exists. + * + * Returns: %TRUE if the backend tag exists + * + * Since: 1.8.5 + **/ +gboolean +fu_device_has_backend_tag(FuDevice *self, const gchar *backend_tag) +{ + FuDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(FU_IS_DEVICE(self), FALSE); + g_return_val_if_fail(backend_tag != NULL, FALSE); + for (guint i = 0; i < priv->backend_tags->len; i++) { + const gchar *backend_tag_tmp = g_ptr_array_index(priv->backend_tags, i); + if (g_strcmp0(backend_tag_tmp, backend_tag) == 0) + return TRUE; + } + return FALSE; +} + /** * fu_device_add_child: * @self: a #FuDevice @@ -5584,6 +5657,20 @@ fu_device_class_init(FuDeviceClass *klass) FU_TYPE_DEVICE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_NAME); g_object_class_install_property(object_class, PROP_PARENT, pspec); + + /** + * FuDevice:backend-tags: + * + * The device tags used for backend identification. + * + * Since: 1.5.8 + */ + pspec = g_param_spec_boxed("backend-tags", + NULL, + NULL, + G_TYPE_PTR_ARRAY, + G_PARAM_READABLE | G_PARAM_STATIC_NAME); + g_object_class_install_property(object_class, PROP_BACKEND_TAGS, pspec); } static void @@ -5595,6 +5682,7 @@ fu_device_init(FuDevice *self) priv->possible_plugins = g_ptr_array_new_with_free_func(g_free); priv->retry_recs = g_ptr_array_new_with_free_func(g_free); priv->instance_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + priv->backend_tags = g_ptr_array_new_with_free_func(g_free); priv->acquiesce_delay = 50; /* ms */ g_rw_lock_init(&priv->parent_guids_mutex); g_rw_lock_init(&priv->metadata_mutex); @@ -5632,6 +5720,7 @@ fu_device_finalize(GObject *object) g_ptr_array_unref(priv->parent_guids); g_ptr_array_unref(priv->possible_plugins); g_ptr_array_unref(priv->retry_recs); + g_ptr_array_unref(priv->backend_tags); g_free(priv->alternate_id); g_free(priv->equivalent_id); g_free(priv->physical_id); diff --git a/libfwupdplugin/fu-device.h b/libfwupdplugin/fu-device.h index 753af3869..b0cae55e5 100644 --- a/libfwupdplugin/fu-device.h +++ b/libfwupdplugin/fu-device.h @@ -540,6 +540,12 @@ fu_device_set_version_lowest(FuDevice *self, const gchar *version); void fu_device_set_version_bootloader(FuDevice *self, const gchar *version); void +fu_device_add_backend_tag(FuDevice *self, const gchar *backend_tag); +gboolean +fu_device_has_backend_tag(FuDevice *self, const gchar *backend_tag); +GPtrArray * +fu_device_get_backend_tags(FuDevice *self); +void fu_device_inhibit(FuDevice *self, const gchar *inhibit_id, const gchar *reason); void fu_device_uninhibit(FuDevice *self, const gchar *inhibit_id); diff --git a/libfwupdplugin/fu-plugin.c b/libfwupdplugin/fu-plugin.c index 61cefdd25..9744af9d6 100644 --- a/libfwupdplugin/fu-plugin.c +++ b/libfwupdplugin/fu-plugin.c @@ -1226,6 +1226,7 @@ fu_plugin_runner_prepare(FuPlugin *self, GError **error) { FuPluginVfuncs *vfuncs = fu_plugin_get_vfuncs(self); + fu_device_add_backend_tag(device, "prepare"); return fu_plugin_runner_flagged_device_generic(self, device, progress, @@ -1257,6 +1258,7 @@ fu_plugin_runner_cleanup(FuPlugin *self, GError **error) { FuPluginVfuncs *vfuncs = fu_plugin_get_vfuncs(self); + fu_device_add_backend_tag(device, "cleanup"); return fu_plugin_runner_flagged_device_generic(self, device, progress, @@ -1283,6 +1285,7 @@ gboolean fu_plugin_runner_attach(FuPlugin *self, FuDevice *device, FuProgress *progress, GError **error) { FuPluginVfuncs *vfuncs = fu_plugin_get_vfuncs(self); + fu_device_add_backend_tag(device, "attach"); return fu_plugin_runner_device_generic_progress( self, device, @@ -1309,6 +1312,7 @@ gboolean fu_plugin_runner_detach(FuPlugin *self, FuDevice *device, FuProgress *progress, GError **error) { FuPluginVfuncs *vfuncs = fu_plugin_get_vfuncs(self); + fu_device_add_backend_tag(device, "detach"); return fu_plugin_runner_device_generic_progress( self, device, @@ -1344,6 +1348,7 @@ fu_plugin_runner_reload(FuPlugin *self, FuDevice *device, GError **error) locker = fu_device_locker_new(proxy, error); if (locker == NULL) return FALSE; + fu_device_add_backend_tag(device, "reload"); return fu_device_reload(device, error); } @@ -1917,6 +1922,7 @@ fu_plugin_runner_activate(FuPlugin *self, FuDevice *device, FuProgress *progress } /* run vfunc */ + fu_device_add_backend_tag(device, "activate"); if (!fu_plugin_runner_device_generic_progress( self, device, @@ -1966,6 +1972,7 @@ fu_plugin_runner_unlock(FuPlugin *self, FuDevice *device, GError **error) } /* run vfunc */ + fu_device_add_backend_tag(device, "unlock"); if (!fu_plugin_runner_device_generic(self, device, "fu_plugin_unlock", @@ -2015,6 +2022,7 @@ fu_plugin_runner_write_firmware(FuPlugin *self, g_debug("plugin not enabled, skipping"); return TRUE; } + fu_device_add_backend_tag(device, "write-firmware"); /* optional */ if (vfuncs->write_firmware == NULL) { diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index 3d052e034..2dbc9c94f 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -1103,6 +1103,13 @@ fu_device_func(void) fu_device_add_possible_plugin(device, "test"); possible_plugins = fu_device_get_possible_plugins(device); g_assert_cmpint(possible_plugins->len, ==, 1); + + g_assert_cmpint(fu_device_get_backend_tags(device)->len, ==, 0); + fu_device_add_backend_tag(device, "foo"); + fu_device_add_backend_tag(device, "bar"); + g_assert_cmpint(fu_device_get_backend_tags(device)->len, ==, 2); + g_assert_true(fu_device_has_backend_tag(device, "foo")); + g_assert_false(fu_device_has_backend_tag(device, "bazbazbazbazbaz")); } static void diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 6875d4c81..79ae1e9d6 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -1102,6 +1102,9 @@ LIBFWUPDPLUGIN_1.8.5 { fu_backend_save; fu_context_add_flag; fu_context_has_flag; + fu_device_add_backend_tag; + fu_device_get_backend_tags; + fu_device_has_backend_tag; fu_device_set_quirk_kv; fu_intel_thunderbolt_firmware_get_type; fu_intel_thunderbolt_firmware_new;